package main import ( "context" "crypto/sha256" "crypto/x509" "encoding/hex" "os" "sort" "strings" sr "tildegit.org/tjp/sliderule" "tildegit.org/tjp/sliderule/contrib/cgi" "tildegit.org/tjp/sliderule/contrib/fs" "tildegit.org/tjp/sliderule/contrib/tlsauth" "tildegit.org/tjp/sliderule/gemini" ) func geminiRouter(conf config) sr.Handler { fsys := os.DirFS(conf.geminiRoot) router := &sr.Router{} router.Route( "/*", gemini.GeminiOnly(true)(sr.FallthroughHandler( fs.TitanUpload(tlsAuth(conf.uploaderFingerprints), conf.geminiRoot)(postUploadRedirect), fs.GeminiFileHandler(fsys), fs.GeminiDirectoryDefault(fsys, "index.gmi"), fs.GeminiDirectoryListing(fsys, nil), )), ) router.Route( "/cgi-bin/*", gemini.GeminiOnly(false)(cgi.GeminiCGIDirectory("/cgi-bin/", "./cgi-bin/")), ) return router.Handler() } var postUploadRedirect = sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response { u := *request.URL u.Path = strings.SplitN(u.Path, ";", 2)[0] u.Scheme = "gemini" return gemini.Redirect(u.String()) }) func tlsAuth(uploaders []string) tlsauth.Approver { sort.Strings(uploaders) return func(cert *x509.Certificate) bool { raw := sha256.Sum256(cert.Raw) user := hex.EncodeToString(raw[:]) _, found := sort.Find(len(uploaders), func(i int) int { switch { case uploaders[i] < user: return 1 case uploaders[i] == user: return 0 default: return -1 } }) return found } }