Initial commit.
A gemini server which drops privileges to the 'nobody' user, hosts files including directory listings (index.gmi or a default listing), and runs CGIs out of /cgi-bin/*.
This commit is contained in:
commit
1f519d05bf
|
@ -0,0 +1,7 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,31 @@
|
|||
# SR-71, a small web server
|
||||
|
||||
```ASCII art of an SR-71 Blackbird
|
||||
,
|
||||
dMb,
|
||||
,dMMMMb, ,,
|
||||
,dMMMMMMMMMb, eeee8888"
|
||||
,mMMm!!!!XXXXMMMMM"""
|
||||
,d!!XXMMXX88888888W"
|
||||
`MX88dMM8888WWWMMMMMMb,
|
||||
'""MMMMMMMMMMMMMMMMb
|
||||
MMMMMMMMMMMMMMMMMMb,
|
||||
dMMMMMMMMMMMMMMMMMMMMb,,
|
||||
_,dMMMMMMMMMMXXXX!!!!!!!!!!!!!!XXXXXMP
|
||||
_,dMMXX!!!!!!!!!!!!!!!!!!XXXXX888888888WWC
|
||||
_,dMMX!!!MMMM!!!!!!!!XXXXXX888888888888WWMMMMMb,
|
||||
dMMX!!!!!MMM!XXXXXX88888888888888888WWMMMMMMMMMMMb
|
||||
dMMXXXXXX8MMMM88888888888888888WWWMMMMMMMMMMMMMMMMMb ,d8
|
||||
MMMMWW888888MMMMM8888888WWMMMMMMMMMMMMMMMMMMMMMMMMMMM,d88P'
|
||||
YMMMMMWW888888WWMMMMMMMMMMP"""' `"YMMMMMMMMMMMXMMMMMP
|
||||
`""YMMMMMMMMMMMMMP""' mMMMm!XXXXX8888888e,
|
||||
,d!!XXMM888888888888WW
|
||||
"MX88dMM888888WWWMMMMMMb
|
||||
"""``'"YMMMMMMMYMMM
|
||||
`"YMMMMM
|
||||
`"YMP
|
||||
```
|
||||
|
||||
The SR-71 Blackbird was arguably the pinnacle of slide rule-based engineering.
|
||||
|
||||
The last airplane designed without the use of electronic calculators, it was developed from concept to first flight in just over 2 years. It few higher and faster than any jet of its time (holding the speed record to this day), and pioneered low-observability (stealth) characteristics.
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
# SR-71, a small web server
|
||||
|
||||
```
|
||||
,
|
||||
dMb,
|
||||
,dMMMMb, ,,
|
||||
,dMMMMMMMMMb, eeee8888"
|
||||
,mMMm!!!!XXXXMMMMM"""
|
||||
,d!!XXMMXX88888888W"
|
||||
`MX88dMM8888WWWMMMMMMb,
|
||||
'""MMMMMMMMMMMMMMMMb
|
||||
MMMMMMMMMMMMMMMMMMb,
|
||||
dMMMMMMMMMMMMMMMMMMMMb,,
|
||||
_,dMMMMMMMMMMXXXX!!!!!!!!!!!!!!XXXXXMP
|
||||
_,dMMXX!!!!!!!!!!!!!!!!!!XXXXX888888888WWC
|
||||
_,dMMX!!!MMMM!!!!!!!!XXXXXX888888888888WWMMMMMb,
|
||||
dMMX!!!!!MMM!XXXXXX88888888888888888WWMMMMMMMMMMMb
|
||||
dMMXXXXXX8MMMM88888888888888888WWWMMMMMMMMMMMMMMMMMb ,d8
|
||||
MMMMWW888888MMMMM8888888WWMMMMMMMMMMMMMMMMMMMMMMMMMMM,d88P'
|
||||
YMMMMMWW888888WWMMMMMMMMMMP"""' `"YMMMMMMMMMMMXMMMMMP
|
||||
`""YMMMMMMMMMMMMMP""' mMMMm!XXXXX8888888e,
|
||||
,d!!XXMM888888888888WW
|
||||
"MX88dMM888888WWWMMMMMMb
|
||||
"""``'"YMMMMMMMYMMM
|
||||
`"YMMMMM
|
||||
`"YMP
|
||||
```
|
||||
|
||||
The SR-71 Blackbird was arguably the pinnacle of slide rule-based engineering.
|
||||
|
||||
The last airplane designed without the use of electronic calculators, it was developed from concept to first flight in just over 2 years. It few higher and faster than any jet of its time (holding the speed record to this day), and pioneered low-observability (stealth) characteristics.
|
|
@ -0,0 +1,70 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"tildegit.org/tjp/sliderule/logging"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
hostname string
|
||||
|
||||
geminiRoot string
|
||||
|
||||
tlsKeyFile string
|
||||
tlsCertFile string
|
||||
}
|
||||
|
||||
func configure() config {
|
||||
return config{
|
||||
hostname: os.Getenv("HOST_NAME"),
|
||||
geminiRoot: os.Getenv("GEMINI_ROOT"),
|
||||
tlsKeyFile: os.Getenv("TLS_KEY_FILE"),
|
||||
tlsCertFile: os.Getenv("TLS_CERT_FILE"),
|
||||
}
|
||||
}
|
||||
|
||||
func dropPrivileges() (bool, error) {
|
||||
me, err := user.Current()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if me.Uid != "0" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
nobody, err := user.Lookup("nobody")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
uid, err := strconv.Atoi(nobody.Uid)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := syscall.Setuid(uid); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func serverContext() (context.Context, logging.Logger, logging.Logger, logging.Logger, logging.Logger) {
|
||||
debug, info, warn, err := logging.DefaultLoggers()
|
||||
ctx := signals(context.Background())
|
||||
ctx = context.WithValue(ctx, "debuglog", debug)
|
||||
ctx = context.WithValue(ctx, "infolog", info)
|
||||
ctx = context.WithValue(ctx, "warnlog", warn)
|
||||
ctx = context.WithValue(ctx, "errorlog", err)
|
||||
return ctx, debug, info, warn, err
|
||||
}
|
||||
|
||||
func signals(ctx context.Context) context.Context {
|
||||
ctx, _ = signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGHUP)
|
||||
return ctx
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
module tildegit.org/tjp/sr-71
|
||||
|
||||
go 1.19
|
||||
|
||||
require tildegit.org/tjp/sliderule v1.0.1-0.20230502145627-c7f8a1292544
|
||||
|
||||
require (
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
tildegit.org/tjp/sliderule v1.0.0 h1:DBXmzm5m3DXxzCE5kTHMulsBo9twd91n6fXR1ciXOoI=
|
||||
tildegit.org/tjp/sliderule v1.0.0/go.mod h1:opdo8E25iS9X9pNismM8U7pCH8XO0PdRIIhdADn8Uik=
|
||||
tildegit.org/tjp/sliderule v1.0.1-0.20230502041606-3d5acb3b68af h1:OWVyuBsOToP8cm0QWZutyxa5vLJAFvgX7uSzpWLq5RI=
|
||||
tildegit.org/tjp/sliderule v1.0.1-0.20230502041606-3d5acb3b68af/go.mod h1:opdo8E25iS9X9pNismM8U7pCH8XO0PdRIIhdADn8Uik=
|
||||
tildegit.org/tjp/sliderule v1.0.1-0.20230502144345-ace21031f98f h1:o4+wUZVYl6uPlzxcJ8gSwMz81enfHfMhAYCOnER8DOQ=
|
||||
tildegit.org/tjp/sliderule v1.0.1-0.20230502144345-ace21031f98f/go.mod h1:opdo8E25iS9X9pNismM8U7pCH8XO0PdRIIhdADn8Uik=
|
||||
tildegit.org/tjp/sliderule v1.0.1-0.20230502145627-c7f8a1292544 h1:5m8q5VZRt1RVJ8F6ti9WFPVkIgrJ1UmnGbxTry+GYIg=
|
||||
tildegit.org/tjp/sliderule v1.0.1-0.20230502145627-c7f8a1292544/go.mod h1:opdo8E25iS9X9pNismM8U7pCH8XO0PdRIIhdADn8Uik=
|
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"tildegit.org/tjp/sliderule/gemini"
|
||||
"tildegit.org/tjp/sliderule/logging"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conf := configure()
|
||||
gemTLS, err := gemini.FileTLS(conf.tlsCertFile, conf.tlsKeyFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
dropped, err := dropPrivileges()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctx, _, info, warn, errlog := serverContext()
|
||||
|
||||
if !dropped {
|
||||
warn.Log("msg", "dropping privileges to 'nobody' failed")
|
||||
}
|
||||
|
||||
handler := logging.LogRequests(info)(geminiRouter(conf))
|
||||
server, err := gemini.NewServer(
|
||||
ctx,
|
||||
conf.hostname,
|
||||
"tcp",
|
||||
"127.0.0.1:1965",
|
||||
handler,
|
||||
errlog,
|
||||
gemTLS,
|
||||
)
|
||||
if err != nil {
|
||||
errlog.Log("msg", "error building server", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := server.Serve(); err != nil {
|
||||
errlog.Log("msg", "error serving gemini", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
sr "tildegit.org/tjp/sliderule"
|
||||
"tildegit.org/tjp/sliderule/contrib/cgi"
|
||||
"tildegit.org/tjp/sliderule/contrib/fs"
|
||||
)
|
||||
|
||||
func geminiRouter(conf config) sr.Handler {
|
||||
fsys := os.DirFS(conf.geminiRoot)
|
||||
|
||||
router := &sr.Router{}
|
||||
|
||||
router.Route(
|
||||
"/*",
|
||||
sr.FallthroughHandler(
|
||||
fs.GeminiFileHandler(fsys),
|
||||
fs.GeminiDirectoryDefault(fsys, "index.gmi"),
|
||||
fs.GeminiDirectoryListing(fsys, nil),
|
||||
),
|
||||
)
|
||||
|
||||
router.Route(
|
||||
"/cgi-bin/*",
|
||||
cgi.GeminiCGIDirectory("/cgi-bin/", "./cgi-bin/"),
|
||||
)
|
||||
|
||||
return router.Handler()
|
||||
}
|
Loading…
Reference in New Issue