💾 Archived View for going-flying.com › ~mernisse › 34.gmi captured on 2024-07-08 at 23:46:59. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2024-06-16)
-=-=-=-=-=-=-
Rather quickly after I setup a Gemini capsule I settled on Solderpunk's The Unsinkable Molly Brown as server software. I created a Docker container as I'm not a fan of running untrusted code on my publicly accessible server infrastructure. The container mounts /var/gemini, and the TLS certificate and key file read-only which restricts its ability to be harmful in the event it is ever compromised. Until recently the /var/gemini directory contained just a checked out copy of a private(ish) git repository containing all the files served and all was well.
At some point libgit2 got upgraded and the ancient CGI script that I have serving the git repository broke because it refuses to open a repository that isn't owned by the process owner. My git hooks run as the git user but the container runs as a different UID which means that the checked-out copy of the repository isn't owned by the CGI script's EUID, causing it to fail.
I ended up fixing the permissions problem but in doing so I had to figure out how to keep the checked out copy in sync and the best way was to add the check out to the post commit hook. This means that there is now git metadata files stored in the /var/gemini directory that someone could read.
Obviously this is unacceptable and this is where the missing feature cropped up. There appears to be no ACLs in Molly Brown's configuration. You can control if the directory is list-able but you cannot actually control if Molly Brown will serve requests from within that directory.
The only reasonable way seems to be to create a PermRedirect and send the client somewhere acceptable. In the case of my git repository this is reasonable, an invalid path will kick you back to the root of the CGI, however I'd much rather be able to tell Molly Brown to return a 5x error code to the client instead.
In case someone needs it, below is an example. Note that if you don't specify the capture group ( "(.*)$" ) in the match portion, it will do a simple replace, so given a configuration of:
[PermRedirects] "^/bad/request/" = "/error/notallowed.gmi"
A request for "/bad/request/file" would rewrite to "/error/notallowed.gmifile".
So, to rewrite all requests under "/bad/requests" you would do something like the following.
[PermRedirects] "^/bad/request(.*)$" = "/error/notallowed.gmi"
The capture group should ensure the entire remainder of the request path is discarded. Note that if you can access the value of the capture group using $1...$n variables in the substitution.
🚀 © MMXX-MMXXIV matt@going-flying.com