commit 44aeff5e7491093298a43348ee044cad2adc1b3b Author: Travis Shears Date: Wed Sep 24 20:47:44 2025 +0200 inital commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..20589ba --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module custom_pb + +go 1.25.0 + +require github.com/kulak/gemini v1.2.2 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..88ba58c --- /dev/null +++ b/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kulak/gemini v1.2.2 h1:wPFOAFFdOf9ZaHcpMwTq1xYUWxmyV3h0uQl0OXCGa+A= +github.com/kulak/gemini v1.2.2/go.mod h1:8yiD7yhLkUGvOpdvgd/0nKQD2I0ChIAKD3yHuT13R5k= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..f2e1eb1 --- /dev/null +++ b/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "log" + "strconv" + "strings" + "time" + + gemini "github.com/kulak/gemini" +) + +type ExampleHandler struct { +} + +func (h ExampleHandler) ServeGemini(w gemini.ResponseWriter, req *gemini.Request) { + log.Printf("request: %s, user: %v", req.URL.Path, strings.Join(userName(req), " ")) + switch req.URL.Path { + case "/": + err := w.WriteStatusMsg(gemini.StatusSuccess, "text/gemini") + requireNoError(err) + _, err = w.WriteBody([]byte("Hello, world!")) + requireNoError(err) + case "/user": + if req.Certificate() == nil { + w.WriteStatusMsg(gemini.StatusCertRequired, "Authentication Required") + return + } + w.WriteStatusMsg(gemini.StatusSuccess, "text/gemini") + w.WriteBody([]byte(req.Certificate().Subject.CommonName)) + case "/die": + requireNoError(errors.New("must die")) + case "/file": + gemini.ServeFileName("cmd/example/hello.gmi", "text/gemini")(w, req) + case "/post": + if req.URL.Scheme != gemini.SchemaTitan { + w.WriteStatusMsg(gemini.StatusSuccess, "text/gemini") + w.WriteBody([]byte("Use titan scheme to upload data")) + return + } + payload, err := req.ReadTitanPayload() + requireNoError(err) + w.WriteStatusMsg(gemini.StatusSuccess, "text/gemini") + w.WriteBody([]byte("Titan Upload Parameters\r\n")) + w.WriteBody([]byte(fmt.Sprintf("Upload MIME Type: %s\r\n", req.Titan.Mime))) + w.WriteBody([]byte(fmt.Sprintf("Token: %s\r\n", req.Titan.Token))) + w.WriteBody([]byte(fmt.Sprintf("Size: %v\r\n", req.Titan.Size))) + w.WriteBody([]byte("Payload:\r\n")) + w.WriteBody(payload) + + default: + w.WriteStatusMsg(gemini.StatusNotFound, req.URL.Path) + } + +} + +func requireNoError(err error) { + if err != nil { + panic(err) + } +} + +func dateToStr(t time.Time) string { + return strconv.FormatInt(t.Unix(), 36) +} + +func userName(r *gemini.Request) []string { + cert := r.Certificate() + if cert == nil { + return []string{""} + } + return []string{cert.Subject.CommonName, cert.SerialNumber.String(), dateToStr(cert.NotBefore), dateToStr(cert.NotAfter)} +} + +func main() { + var host, cert, key string + flag.StringVar(&host, "host", ":1965", "listen on host and port. Example: hostname:1965") + flag.StringVar(&cert, "cert", "server.crt.pem", "certificate file") + flag.StringVar(&key, "key", "server.key.pem", "private key associated with certificate file") + flag.Parse() + + handler := ExampleHandler{} + + err := gemini.ListenAndServe(host, cert, key, gemini.TrapPanic(handler.ServeGemini)) + if err != nil { + log.Fatal(err) + } +}