Skip to content

Commit b051ac2

Browse files
committed
sec: tighten controller security
closes #639 - only allow get requests - add route for page assets (scripts, styles, images, fonts) - add route for article assets (screenshots, diagrams, ...) - add cache header for all assets - everything else will return with status 404
1 parent 22937e4 commit b051ac2

File tree

1 file changed

+79
-64
lines changed

1 file changed

+79
-64
lines changed

src/main/xar-resources/controller.xql

Lines changed: 79 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ xquery version "1.0";
88
(:== SETUP: ==:)
99

1010
import module namespace request = "http://exist-db.org/xquery/request";
11-
import module namespace xdb = "http://exist-db.org/xquery/xmldb";
12-
1311
import module namespace config = "http://exist-db.org/xquery/apps/config" at "modules/config.xqm";
1412

1513
declare variable $exist:path external;
@@ -18,87 +16,104 @@ declare variable $exist:controller external;
1816
declare variable $exist:prefix external;
1917
declare variable $exist:root external;
2018

19+
declare variable $local:method := lower-case(request:get-method());
20+
declare variable $local:is-get := $local:method eq 'get';
21+
2122
(: Make sure we have a correct resource name. If this thing has no extension, amend it with .xml: :)
22-
declare variable $resource-name as xs:string := if (contains($exist:resource, '.')) then
23-
$exist:resource
24-
else
25-
concat($exist:resource, '.xml');
23+
declare variable $resource-name as xs:string :=
24+
if (contains($exist:resource, '.')) then (
25+
$exist:resource
26+
) else (
27+
concat($exist:resource, '.xml')
28+
)
29+
;
2630

2731
(: Find out whether the resource has a path component: :)
2832
declare variable $has-path as xs:boolean :=
29-
let $path-no-leading-slash := if (starts-with($exist:path, '/')) then
30-
substring($exist:path, 2)
31-
else
32-
$exist:path
33-
return
34-
contains($path-no-leading-slash, '/');
33+
let $path-no-leading-slash :=
34+
if (starts-with($exist:path, '/')) then (
35+
substring($exist:path, 2)
36+
) else (
37+
$exist:path
38+
)
39+
40+
return
41+
contains($path-no-leading-slash, '/')
42+
;
3543

3644
(:============================================================================:)
3745
(:== MAIN: ==:)
3846

39-
(: No path at all? End it with a /: :)
40-
if ($exist:path eq '') then
41-
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
42-
<redirect url="{concat(request:get-uri(), '/')}"/>
43-
</dispatch>
44-
45-
(: A path that simply ends with a / goes to the main documentation page: :)
46-
else
47-
if ($exist:path eq "/") then
47+
if ($exist:path eq '') then (
48+
(: No path at all? Append a slash :)
4849
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
49-
<forward url="{$exist:controller}/templates/content.html"/>
50-
<view>
51-
<!-- pass the results through view.xql -->
52-
<forward url="{$exist:controller}/modules/view.xql">
53-
<add-parameter name="doc" value="{config:get-resource-path($config:data-root, 'documentation.xml')}"/>
54-
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
55-
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
56-
</forward>
57-
</view>
58-
<error-handler>
59-
<forward url="{$exist:controller}/error-page.html" method="get"/>
60-
<forward url="{$exist:controller}/modules/view.xql"/>
61-
</error-handler>
50+
<redirect url="{concat(request:get-uri(), '/')}"/>
6251
</dispatch>
63-
52+
) else if ($local:is-get and $exist:path eq "/") then (
53+
(: A path that simply ends with a / goes to the main documentation page: :)
54+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
55+
<forward url="{$exist:controller}/templates/content.html"/>
56+
<view>
57+
<!-- pass the results through view.xql -->
58+
<forward url="{$exist:controller}/modules/view.xql">
59+
<add-parameter name="doc" value="{config:get-resource-path($config:data-root, 'documentation.xml')}"/>
60+
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
61+
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
62+
</forward>
63+
</view>
64+
<error-handler>
65+
<forward url="{$exist:controller}/error-page.html" method="get"/>
66+
<forward url="{$exist:controller}/modules/view.xql"/>
67+
</error-handler>
68+
</dispatch>
69+
) else if ($local:is-get and ends-with($resource-name, ".xml") and not($has-path)) then (
6470
(: Pass all requests to XML files through to view.xql, which handles HTML templating
6571
Request that contain a path are supposed to be resources and not handled here.
6672
:)
67-
else
68-
if (ends-with($resource-name, ".xml") and not($has-path)) then
69-
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
73+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
7074
<forward url="{$exist:controller}/templates/content.html"/>
7175
<view>
72-
<!-- pass the results through view.xql -->
73-
<forward url="{$exist:controller}/modules/view.xql">
74-
<add-parameter name="doc" value="{config:get-resource-path($config:data-root, $resource-name)}"/>
75-
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
76-
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
77-
</forward>
76+
<!-- pass the results through view.xql -->
77+
<forward url="{$exist:controller}/modules/view.xql">
78+
<add-parameter name="doc" value="{config:get-resource-path($config:data-root, $resource-name)}"/>
79+
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
80+
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
81+
</forward>
7882
</view>
7983
<error-handler>
80-
<forward url="{$exist:controller}/error-page.html" method="get"/>
81-
<forward url="{$exist:controller}/modules/view.xql"/>
84+
<forward url="{$exist:controller}/error-page.html" method="get"/>
85+
<forward url="{$exist:controller}/modules/view.xql"/>
8286
</error-handler>
83-
</dispatch>
84-
85-
(: Pass all requests to HTML files through view.xql, which handles HTML templating :)
86-
else
87-
if (ends-with($resource-name, ".html")) then
88-
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
89-
<view>
87+
</dispatch>
88+
) else if ($local:is-get and ends-with($resource-name, ".html")) then (
89+
(: Pass all requests to HTML files through view.xql, which handles HTML templating :)
90+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
91+
<view>
9092
<forward url="{$exist:controller}/modules/view.xql">
91-
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
92-
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
93+
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
94+
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
9395
</forward>
94-
</view>
95-
<error-handler>
96+
</view>
97+
<error-handler>
9698
<forward url="{$exist:controller}/error-page.html" method="get"/>
9799
<forward url="{$exist:controller}/modules/view.xql"/>
98-
</error-handler>
99-
</dispatch>
100-
(: Final catch-all: :)
101-
else
102-
<ignore xmlns="http://exist.sourceforge.net/NS/exist">
103-
<cache-control cache="yes"/>
104-
</ignore>
100+
</error-handler>
101+
</dispatch>
102+
) else if ($local:is-get and matches($exist:path, "^/data/.+\.(png|jpg|jpeg|gif|svg)$")) then (
103+
(: article assets like screenshots and diagrams :)
104+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
105+
<forward url="{$exist:controller}{$exist:path}">
106+
<set-header name="Cache-Control" value="max-age=73600; must-revalidate;"/>
107+
</forward>
108+
</dispatch>
109+
) else if ($local:is-get and matches($exist:path, "/resources/(styles|fonts|images|scripts|svg)/.+")) then (
110+
(: static page assets like images, fonts, styles and scripts :)
111+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
112+
<forward url="{$exist:controller}{$exist:path}">
113+
<set-header name="Cache-Control" value="max-age=73600; must-revalidate;"/>
114+
</forward>
115+
</dispatch>
116+
) else (
117+
response:set-status-code(404),
118+
<data>Not Found</data>
119+
)

0 commit comments

Comments
 (0)