From e759651bd34ba2fb6d1b13a1dfd6a2bf1cfc10ec Mon Sep 17 00:00:00 2001 From: Juri Leino Date: Thu, 18 Sep 2025 13:23:23 +0200 Subject: [PATCH] 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 --- src/main/xar-resources/controller.xql | 143 ++++++++++++++------------ 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/src/main/xar-resources/controller.xql b/src/main/xar-resources/controller.xql index f4750229..cda488d3 100755 --- a/src/main/xar-resources/controller.xql +++ b/src/main/xar-resources/controller.xql @@ -8,8 +8,6 @@ xquery version "1.0"; (:== SETUP: ==:) import module namespace request = "http://exist-db.org/xquery/request"; -import module namespace xdb = "http://exist-db.org/xquery/xmldb"; - import module namespace config = "http://exist-db.org/xquery/apps/config" at "modules/config.xqm"; declare variable $exist:path external; @@ -18,87 +16,104 @@ declare variable $exist:controller external; declare variable $exist:prefix external; declare variable $exist:root external; +declare variable $local:method := lower-case(request:get-method()); +declare variable $local:is-get := $local:method eq 'get'; + (: Make sure we have a correct resource name. If this thing has no extension, amend it with .xml: :) -declare variable $resource-name as xs:string := if (contains($exist:resource, '.')) then - $exist:resource -else - concat($exist:resource, '.xml'); +declare variable $resource-name as xs:string := + if (contains($exist:resource, '.')) then ( + $exist:resource + ) else ( + concat($exist:resource, '.xml') + ) +; (: Find out whether the resource has a path component: :) declare variable $has-path as xs:boolean := -let $path-no-leading-slash := if (starts-with($exist:path, '/')) then - substring($exist:path, 2) -else - $exist:path -return - contains($path-no-leading-slash, '/'); + let $path-no-leading-slash := + if (starts-with($exist:path, '/')) then ( + substring($exist:path, 2) + ) else ( + $exist:path + ) + + return + contains($path-no-leading-slash, '/') +; (:============================================================================:) (:== MAIN: ==:) -(: No path at all? End it with a /: :) -if ($exist:path eq '') then - - - - - (: A path that simply ends with a / goes to the main documentation page: :) -else - if ($exist:path eq "/") then +if ($exist:path eq '') then ( + (: No path at all? Append a slash :) - - - - - - - - - - - - - + - +) else if ($local:is-get and $exist:path eq "/") then ( + (: A path that simply ends with a / goes to the main documentation page: :) + + + + + + + + + + + + + + + +) else if ($local:is-get and ends-with($resource-name, ".xml") and not($has-path)) then ( (: Pass all requests to XML files through to view.xql, which handles HTML templating Request that contain a path are supposed to be resources and not handled here. :) - else - if (ends-with($resource-name, ".xml") and not($has-path)) then - + - - - - - - + + + + + + - - + + - - - (: Pass all requests to HTML files through view.xql, which handles HTML templating :) - else - if (ends-with($resource-name, ".html")) then - - + +) else if ($local:is-get and ends-with($resource-name, ".html")) then ( + (: Pass all requests to HTML files through view.xql, which handles HTML templating :) + + - - + + - - + + - - - (: Final catch-all: :) - else - - - + + +) else if ($local:is-get and matches($exist:path, "^/data/.+\.(png|jpg|jpeg|gif|svg)$")) then ( + (: article assets like screenshots and diagrams :) + + + + + +) else if ($local:is-get and matches($exist:path, "/resources/(styles|fonts|images|scripts|svg)/.+")) then ( + (: static page assets like images, fonts, styles and scripts :) + + + + + +) else ( + response:set-status-code(404), + Not Found +)