a bunch of misc changes
alex wennerberg alex@alexwennerberg.com
Sat, 24 Oct 2020 01:13:39 -0700
9 files changed,
91 insertions(+),
47 deletions(-)
M
flounder.toml
→
flounder.toml
@@ -1,3 +1,4 @@
+# Used in HTML templates and titles SiteTitle="🐟flounder" RootDomain="localhost" FilesDirectory="./files"@@ -5,3 +6,5 @@ # handles templates and static files
# everything in the static subfolder will be served at root TemplatesDirectory="./templates" DBFile="./flounder.db" + +# Log file
M
gemini.go
→
gemini.go
@@ -12,6 +12,7 @@ "io/ioutil"
"log" "os" "path" + "path/filepath" "text/template" "time" )@@ -24,21 +25,24 @@ }
files, _ := getIndexFiles() users, _ := getUsers() data := struct { - Domain string - Files []*File - Users []string + Domain string + SiteTitle string + Files []*File + Users []string }{ - Domain: "flounder.online", - Files: files, - Users: users, + Domain: c.RootDomain, + SiteTitle: c.SiteTitle, + Files: files, + Users: users, } t.Execute(w, data) } func gmiPage(w *gmi.ResponseWriter, r *gmi.Request) { userName := strings.Split(r.URL.Host, ".")[0] - fileName := path.Join(c.FilesDirectory, userName, r.URL.Path) + fileName := path.Join(c.FilesDirectory, userName, filepath.Clean(r.URL.Path)) data, err := ioutil.ReadFile(fileName) + // serve file? // TODO write mimetype if err != nil { // TODO return 404 equivalent@@ -91,6 +95,8 @@ server.HandleFunc("*."+c.RootDomain, gmiPage)
server.ListenAndServe() } + +// TODO log request // writeCertificate writes the provided certificate and private key // to path.crt and path.key respectively.
M
go.sum
→
go.sum
@@ -2,6 +2,10 @@ git.sr.ht/~adnano/gmi v0.1.0-alpha.2 h1:5/wzImYT3mJmZ27lazJ8YAdpiVN3QNJruLX7PXOITeo=
git.sr.ht/~adnano/gmi v0.1.0-alpha.2/go.mod h1:t/m2KtH+7lXIF7jjVN+bNvwPbE0nxHOpvlA/WZ/KeLQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d h1:2+ZP7EfsZV7Vvmx3TIqSlSzATMkTAKqM14YGFPoSKjI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=@@ -9,3 +13,5 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
M
http.go
→
http.go
@@ -2,12 +2,15 @@ package main
import ( "git.sr.ht/~adnano/gmi" + "github.com/gorilla/handlers" "html/template" "log" "net/http" "os" "path" + "path/filepath" "strings" + "time" ) var t *template.Template@@ -26,7 +29,7 @@
func rootHandler(w http.ResponseWriter, r *http.Request) { // serve everything inside static directory if r.URL.Path != "/" { - fileName := path.Join(c.TemplatesDirectory, "static", r.URL.Path) + fileName := path.Join(c.TemplatesDirectory, "static", filepath.Clean(r.URL.Path)) http.ServeFile(w, r, fileName) return }@@ -154,25 +157,19 @@
// Server a user's file func userFile(w http.ResponseWriter, r *http.Request) { userName := strings.Split(r.Host, ".")[0] - fileName := path.Join(c.FilesDirectory, userName, r.URL.Path) + fileName := path.Join(c.FilesDirectory, userName, filepath.Clean(r.URL.Path)) extension := path.Ext(fileName) if r.URL.Path == "/static/style.css" { http.ServeFile(w, r, path.Join(c.TemplatesDirectory, "static/style.css")) } if extension == ".gmi" || extension == ".gemini" { - if strings.Contains(fileName, "..") { - // prevent directory traversal TODO verify - http.Error(w, "invalid URL path", http.StatusBadRequest) - } else { - // covert to html - stat, _ := os.Stat(fileName) - file, _ := os.Open(fileName) - htmlString := gmi.Parse(file).HTML() - reader := strings.NewReader(htmlString) - w.Header().Set("Content-Type", "text/html") - http.ServeContent(w, r, fileName, stat.ModTime(), reader) - } - // TODO clean + // covert to html + stat, _ := os.Stat(fileName) + file, _ := os.Open(fileName) + htmlString := gmi.Parse(file).HTML() + reader := strings.NewReader(htmlString) + w.Header().Set("Content-Type", "text/html") + http.ServeContent(w, r, fileName, stat.ModTime(), reader) } else { http.ServeFile(w, r, fileName) }@@ -185,22 +182,27 @@ t, err = template.ParseGlob("./templates/*.html") // TODO make template dir configruable
if err != nil { log.Fatal(err) } - http.HandleFunc(c.RootDomain+"/", rootHandler) - http.HandleFunc(c.RootDomain+"/my_site", mySiteHandler) - http.HandleFunc(c.RootDomain+"/edit/", editFileHandler) - http.HandleFunc(c.RootDomain+"/login", loginHandler) - http.HandleFunc(c.RootDomain+"/register", registerHandler) - http.HandleFunc(c.RootDomain+"/delete/", deleteFileHandler) - // login+register functions + serveMux := http.NewServeMux() + + serveMux.HandleFunc(c.RootDomain+"/", rootHandler) + serveMux.HandleFunc(c.RootDomain+"/my_site", mySiteHandler) + serveMux.HandleFunc(c.RootDomain+"/edit/", editFileHandler) + serveMux.HandleFunc(c.RootDomain+"/login", loginHandler) + serveMux.HandleFunc(c.RootDomain+"/register", registerHandler) + serveMux.HandleFunc(c.RootDomain+"/delete/", deleteFileHandler) + + wrapped := handlers.LoggingHandler(os.Stdout, serveMux) // handle user files based on subdomain - http.HandleFunc("/", userFile) - log.Fatal(http.ListenAndServe(":8080", logRequest(http.DefaultServeMux))) -} - -func logRequest(handler http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) - handler.ServeHTTP(w, r) - }) + serveMux.HandleFunc("/", userFile) + // login+register functions + srv := &http.Server{ + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 120 * time.Second, + Addr: ":8080", + // TLSConfig: tlsConfig, + Handler: wrapped, + } + log.Fatal(srv.ListenAndServe()) }
M
main.go
→
main.go
@@ -7,6 +7,7 @@ "log"
"os" "path" "path/filepath" + "sync" ) var c Config // global var to hold static configuration@@ -71,7 +72,16 @@ c, err = getConfig(*configPath)
if err != nil { log.Fatal(err) } - runHTTPServer() - // runGeminiServer() - // go log.Fatal(gmi.ListenAndServe(":8080", nil)) + + wg := new(sync.WaitGroup) + wg.Add(2) + go func() { + runHTTPServer() + wg.Done() + }() + go func() { + runGeminiServer() + wg.Done() + }() + wg.Wait() }
M
templates/index.gmi
→
templates/index.gmi
@@ -1,5 +1,5 @@
{{$domain := .Domain}} -# 🐟Flounder! +# {{.SiteTitle}}! Welcome to flounder, a home for Gemini sites. Flounder hosts small Gemini web pages over https and Gemini. Right now, the only way to make an account is via the https portal, but I'm working on adding alternatives. Feel free to make an account and join if you'd like!
M
templates/static/style.css
→
templates/static/style.css
@@ -4,12 +4,7 @@ padding: 2ch;
margin: auto; font-family: Helvetica, Arial, monospace; word-wrap: break-word; - border: 1px solid black; background-color: white; -} - -body { - background-color: #cfe6fc; } .inline {
A
templates/user_page.html
@@ -0,0 +1,20 @@
+{{$domain := .Domain}} +{{template "header" .}} +<h1>{{.PageTitle}}!</h1> +{{template "nav.html" .}} +<h2>All users:</h2> +{{ range .Users}} +<a href="https://{{.}}.{{$domain}}" class='person-link'>{{.}}</a> +{{end}} +<h2>Recently updated files:</h2> +{{ range .Files }} +<div> + <a href="https://{{.Creator}}.{{$domain}}" class='person-link'> + {{ .Creator }}</a> + <em>{{.UpdatedTime}}</em> + <a href="https://{{.Creator}}.{{$domain}}/{{.Name}}"> + {{ .Name}} + </a> +</div> +{{end}} +{{template "footer" .}}