sr-71/routes.go

69 lines
1.4 KiB
Go

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
}
}