Skip to content

Commit 8010e62

Browse files
committed
feat: tighten controller security, error handling
- rewrite scan.xql to generate.xqm - adhere to naming conventions - explicitly allow routes and deny evertying else - route modules/reindex.xql moved to /regenerate - add routes fro markdown and static resources - call to /regenerate is a GET request
1 parent af087c1 commit 8010e62

File tree

8 files changed

+222
-201
lines changed

8 files changed

+222
-201
lines changed

src/main/xar-resources/controller.xql renamed to src/main/xar-resources/controller.xq

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,36 @@ declare variable $exist:controller external;
1010
declare variable $exist:path external;
1111
declare variable $exist:resource external;
1212

13-
if ($exist:path eq '') then
13+
if ($exist:path eq '') then (
1414
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
1515
<redirect url="{concat(request:get-uri(), '/')}"/>
1616
</dispatch>
17-
else if ($exist:path eq "/") then
17+
) else if ($exist:path eq "/") then (
1818
(: forward root path to index.xql :)
1919
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
2020
<redirect url="index.html"/>
2121
</dispatch>
22-
23-
else if ($exist:resource eq "login") then
22+
) else if (ends-with($exist:resource, ".html")) then (
23+
let $loggedIn := login:set-user("org.exist.login", (), true())
24+
return
25+
(: the html page is run through view.xql to expand templates :)
26+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
27+
<view>
28+
<forward url="{$exist:controller}/modules/view.xq">
29+
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
30+
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
31+
</forward>
32+
</view>
33+
</dispatch>
34+
) else if (ends-with($exist:resource, ".md")) then (
35+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
36+
<forward url="{$exist:controller}{$exist:path}" />
37+
</dispatch>
38+
) else if (matches($exist:path, "/resources/(css|fonts|images|scripts|svg|css)/.+")) then (
39+
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
40+
<forward url="{$exist:controller}{$exist:path}" />
41+
</dispatch>
42+
) else if ($exist:resource eq "login") then (
2443
let $loggedIn := login:set-user("org.exist.login", (), true())
2544
return
2645
try {
@@ -33,27 +52,13 @@ else if ($exist:resource eq "login") then
3352
response:set-status-code(401),
3453
<status>{$err:description}</status>
3554
}
36-
37-
else if (ends-with($exist:resource, ".html")) then
38-
let $loggedIn := login:set-user("org.exist.login", (), true())
55+
) else if ($exist:path = "/regenerate") then (
56+
let $loggedIn := login:set-user("org.exist.login", (), false())
3957
return
40-
(: the html page is run through view.xql to expand templates :)
4158
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
42-
<view>
43-
<forward url="{$exist:controller}/modules/view.xql">
44-
<set-attribute name="$exist:prefix" value="{$exist:prefix}"/>
45-
<set-attribute name="$exist:controller" value="{$exist:controller}"/>
46-
</forward>
47-
</view>
59+
<forward url="{$exist:controller}/modules/regenerate.xq" />
4860
</dispatch>
49-
50-
else if ($exist:resource = "reindex.xql") then
51-
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
52-
{login:set-user("org.exist.login", (), false())}
53-
</dispatch>
54-
55-
else
56-
(: everything else is passed through :)
57-
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
58-
<cache-control cache="yes"/>
59-
</dispatch>
61+
) else (
62+
response:set-status-code(404),
63+
<data>Not Found</data>
64+
)
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
xquery version "3.1";
2+
3+
4+
(:~
5+
: This module scans the database instance for library modules and
6+
: generates XQDoc for each one that is found.
7+
: This collection of XQDoc definitions is then used to render
8+
: the function documentation.
9+
:)
10+
module namespace generate="http://exist-db.org/apps/fundocs/generate";
11+
12+
13+
import module namespace xmldb="http://exist-db.org/xquery/xmldb";
14+
import module namespace inspect="http://exist-db.org/xquery/inspection" at "java:org.exist.xquery.functions.inspect.InspectionModule";
15+
import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm";
16+
import module namespace dbutil="http://exist-db.org/xquery/dbutil" at "dbutil.xqm";
17+
18+
19+
declare namespace xqdoc="http://www.xqdoc.org/1.0";
20+
21+
22+
declare variable $generate:doc-collection := $config:app-root || "/data";
23+
24+
25+
declare function generate:fundocs() {
26+
(
27+
generate:load-mapped-modules(),
28+
generate:load-internal-modules(),
29+
generate:load-stored-modules()
30+
)
31+
=> filter(generate:has-definition#1)
32+
=> for-each(generate:generate-and-store-xqdoc#1)
33+
};
34+
35+
declare %private function generate:load-mapped-modules() as array(*)* {
36+
for $path in util:mapped-modules()
37+
let $uri := xs:anyURI($path)
38+
return generate:safe-inspect($uri, inspect:inspect-module-uri#1)
39+
};
40+
41+
declare %private function generate:load-internal-modules() as array(*)* {
42+
for $path in util:registered-modules()
43+
let $uri := xs:anyURI($path)
44+
return generate:safe-inspect($uri, inspect:inspect-module-uri#1)
45+
};
46+
47+
declare %private function generate:load-stored-modules() as array(*)* {
48+
for $uri in dbutil:find-by-mimetype(xs:anyURI("/db"), "application/xquery")
49+
return generate:safe-inspect($uri, inspect:inspect-module#1)
50+
};
51+
52+
declare %private function generate:safe-inspect ($moduleUri as xs:anyURI, $inspect as function(xs:anyURI) as element(module)?) as array(*)? {
53+
try {
54+
[$moduleUri, $inspect($moduleUri)]
55+
} catch * {
56+
(:
57+
: Expected to fail if XQuery file is not a library module
58+
: Will also guard against malformed and missing modules
59+
:)
60+
util:log("WARN", (
61+
"Could not compile function documentation for: ",
62+
$moduleUri, " (", $err:code, ")", $err:description
63+
))
64+
}
65+
};
66+
67+
declare %private function generate:has-definition($module-info as array(*)) as xs:boolean {
68+
exists($module-info?2)
69+
};
70+
71+
declare %private function generate:generate-and-store-xqdoc ($module-info as array(*)) {
72+
let $filename := concat(util:hash($module-info?1, "md5"), ".xml"),
73+
$xqdoc := generate:module-to-xqdoc($module-info?2)
74+
return
75+
xmldb:store($generate:doc-collection, $filename, $xqdoc)
76+
=> xs:anyURI()
77+
=> sm:chmod("rw-rw-r--")
78+
};
79+
80+
declare %private function generate:module-to-xqdoc($module as element(module)) as element(xqdoc:xqdoc) {
81+
<xqdoc:xqdoc xmlns:xqdoc="http://www.xqdoc.org/1.0">
82+
<xqdoc:control>
83+
<xqdoc:date>{current-dateTime()}</xqdoc:date>
84+
<xqdoc:location>{$module/@location/string()}</xqdoc:location>
85+
</xqdoc:control>
86+
<xqdoc:module type="library">
87+
<xqdoc:uri>{$module/@uri/string()}</xqdoc:uri>
88+
<xqdoc:name>{$module/@prefix/string()}</xqdoc:name>
89+
<xqdoc:comment>
90+
<xqdoc:description>{$module/description/string()}</xqdoc:description>
91+
{
92+
if (empty($module/version)) then ()
93+
else
94+
<xqdoc:version>{$module/version/string()}</xqdoc:version>
95+
}
96+
{
97+
if (empty($module/author)) then ()
98+
else
99+
<xqdoc:author>{$module/author/string()}</xqdoc:author>
100+
}
101+
</xqdoc:comment>
102+
</xqdoc:module>
103+
<xqdoc:functions>
104+
{
105+
for $function in $module/function
106+
return generate:function-to-xqdoc($function)
107+
}
108+
</xqdoc:functions>
109+
</xqdoc:xqdoc>
110+
};
111+
112+
declare %private function generate:function-to-xqdoc($function as element(function)) as element(xqdoc:function) {
113+
<xqdoc:function>
114+
<xqdoc:name>{$function/@name/string()}</xqdoc:name>
115+
<xqdoc:signature>{generate:signature($function)}</xqdoc:signature>
116+
<xqdoc:comment>
117+
<xqdoc:description>{$function/description/string()}</xqdoc:description>
118+
{
119+
for $argument in $function/argument
120+
return
121+
<xqdoc:param>{
122+
"$" || $argument/@var || generate:cardinality($argument/@cardinality) ||
123+
" " || $argument/text()
124+
}</xqdoc:param>
125+
}
126+
<xqdoc:return>
127+
{
128+
$function/returns/@type/string() || generate:cardinality($function/returns/@cardinality)
129+
}{
130+
if (empty($function/returns/text())) then ()
131+
else " : " || $function/returns/text()
132+
}
133+
</xqdoc:return>
134+
{
135+
if (empty($function/deprecated)) then ()
136+
else
137+
<xqdoc:deprecated>{$function/deprecated/string()}</xqdoc:deprecated>
138+
}
139+
</xqdoc:comment>
140+
</xqdoc:function>
141+
};
142+
143+
declare %private function generate:cardinality($cardinality as xs:string) as xs:string? {
144+
switch ($cardinality)
145+
case "zero or one" return "?"
146+
case "zero or more" return "*"
147+
case "one or more" return "+"
148+
default return ()
149+
};
150+
151+
declare %private function generate:signature($function as element(function)) as xs:string {
152+
let $arguments :=
153+
for $argument in $function/argument
154+
return
155+
"$" || $argument/@var || " as " || $argument/@type || generate:cardinality($argument/@cardinality)
156+
157+
return
158+
$function/@name/string() || "(" || string-join($arguments, ", ") || ")" ||
159+
" as " || $function/returns/@type || generate:cardinality($function/returns/@cardinality)
160+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
xquery version "3.1";
2+
3+
import module namespace sm="http://exist-db.org/xquery/securitymanager";
4+
import module namespace generate="http://exist-db.org/apps/fundocs/generate" at "generate.xqm";
5+
6+
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
7+
8+
declare option output:method "json";
9+
declare option output:media-type "application/json";
10+
11+
try {
12+
let $user := sm:id()/sm:id/(sm:effective|sm:real)[1]/sm:username
13+
return if (sm:is-dba($user)) then (
14+
let $result := generate:fundocs()
15+
return
16+
<response status="ok">
17+
<message>Scan completed! {$result}</message>
18+
</response>
19+
) else (
20+
response:set-status-code(403),
21+
<response status="failed">
22+
<message>You have to be a member of the dba group. Please log in using the dashboard and retry.</message>
23+
</response>
24+
)
25+
} catch * {
26+
response:set-status-code(500),
27+
<response status="failed">
28+
<message>{$err:description}</message>
29+
</response>
30+
}

src/main/xar-resources/modules/reindex.xql

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)