14 Commits

Author SHA1 Message Date
bel
eaa8debb73 no binary 2022-07-09 16:36:57 -06:00
bel
3727e2ee5e support for basic auth 2022-07-09 16:27:49 -06:00
bel
7fabfcd14d got md ok 2022-07-09 16:18:11 -06:00
bel
19c13c43f6 log 2022-07-09 15:56:21 -06:00
bel
fc7451ab40 add https only forwarding 2022-07-09 15:49:14 -06:00
bel
c8e09a989d add -ro for read-only tag 2022-07-09 15:21:11 -06:00
bel
7b04c49f4a change default bundle.css 2022-06-26 21:33:25 -06:00
bel
de57779200 whoops 2022-06-26 21:30:02 -06:00
bel
d706a2c4a3 Merge branch 'master' of https://gogs.inhome.blapointe.com/local/simpleserve 2022-06-26 21:29:26 -06:00
bel
90252d971f sub gomod 2022-06-26 21:27:15 -06:00
Bel LaPointe
16c4ade51b up go mod 2021-11-29 12:44:02 -07:00
Bel LaPointe
58e8a594eb go mod 2021-09-17 08:24:09 -06:00
bel
66a35fcf10 More types 2020-04-13 20:47:42 +00:00
bel
05ef683334 More content types 2020-04-13 13:00:30 +00:00
5 changed files with 123 additions and 11 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
*.key *.key
/exec-*
*.crt *.crt
*.pem *.pem
*.swp *.swp

25
go.mod Normal file
View File

@@ -0,0 +1,25 @@
module local/simpleserve
go 1.16
replace local/args => ../args
replace local/gziphttp => ../gziphttp
replace local/notes-server/notes/md => ../notes-server/notes/md
replace local/oauth2 => ../oauth2
replace local/router => ../router
replace local/simpleserve => ../simpleserve
replace local/storage => ../storage
replace local/logb => ../logb
require (
local/args v0.0.0-00010101000000-000000000000
local/gziphttp v0.0.0-00010101000000-000000000000
local/notes-server/notes/md v0.0.0-00010101000000-000000000000
)

6
go.sum Normal file
View File

@@ -0,0 +1,6 @@
github.com/gomarkdown/markdown v0.0.0-20220607163217-45f7c050e2d1 h1:wAupuFkZ/yq219/mSbqDtMfUZQY0gTYEtoz3/LKtppU=
github.com/gomarkdown/markdown v0.0.0-20220607163217-45f7c050e2d1/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

101
main.go
View File

@@ -31,8 +31,11 @@ var (
func main() { func main() {
fs = args.NewArgSet() fs = args.NewArgSet()
fs.Append(args.STRING, "p", "port to serve", "8100") fs.Append(args.STRING, "p", "port to serve", "8100")
fs.Append(args.STRING, "u", "user:pass for basic auth", "")
fs.Append(args.BOOL, "md", "whether to render markdown as html", true) fs.Append(args.BOOL, "md", "whether to render markdown as html", true)
fs.Append(args.STRING, "md-css", "css to load for md", "./public/bundle.css") fs.Append(args.BOOL, "ro", "read only mode", false)
fs.Append(args.BOOL, "https", "https only", false)
fs.Append(args.STRING, "md-css", "css to load for md", "/dev/null")
fs.Append(args.STRING, "md-class", "class to wrap md", "phb") fs.Append(args.STRING, "md-class", "class to wrap md", "phb")
fs.Append(args.STRING, "d", "static path to serve", "./public") fs.Append(args.STRING, "d", "static path to serve", "./public")
if err := fs.Parse(); err != nil { if err := fs.Parse(); err != nil {
@@ -40,7 +43,10 @@ func main() {
} }
d := fs.Get("d").GetString() d := fs.Get("d").GetString()
userPass := fs.Get("u").GetString()
md := fs.Get("md").GetBool() md := fs.Get("md").GetBool()
ro := fs.Get("ro").GetBool()
https := fs.Get("https").GetBool()
mdCss := fs.Get("md-css").GetString() mdCss := fs.Get("md-css").GetString()
mdClass := fs.Get("md-class").GetString() mdClass := fs.Get("md-class").GetString()
if mdCss != "" { if mdCss != "" {
@@ -89,15 +95,15 @@ func main() {
} }
p := strings.TrimPrefix(fs.Get("p").GetString(), ":") p := strings.TrimPrefix(fs.Get("p").GetString(), ":")
http.Handle("/", http.HandlerFunc(handler(d, md, mdCss, mdClass))) http.Handle("/", http.HandlerFunc(handler(userPass, https, ro, d, md, mdCss, mdClass)))
log.Printf("Serving %s on HTTP port: %s\n", d, p) log.Printf("Serving %s on HTTP port: %s\n", d, p)
log.Fatal(http.ListenAndServe(":"+p, nil)) log.Fatal(http.ListenAndServe(":"+p, nil))
} }
func handler(d string, md bool, mdCss, mdClass string) http.HandlerFunc { func handler(userPass string, https, ro bool, d string, md bool, mdCss, mdClass string) http.HandlerFunc {
return gzip(endpoints(withDel(withMD(d, md, mdCss, mdClass, fserve(d))))) return httpsOnly(https, gzip(basicAuth(userPass, endpoints(ro, withDel(ro, withMD(d, md, mdCss, mdClass, fserve(d)))))))
} }
func writeMeta(w http.ResponseWriter) { func writeMeta(w http.ResponseWriter) {
@@ -118,6 +124,32 @@ func writeForm(w http.ResponseWriter) {
`, ENDPOINT_UPLOAD) `, ENDPOINT_UPLOAD)
} }
func basicAuth(userPass string, foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if userPass != "" {
u, p, ok := r.BasicAuth()
if !ok || u+":"+p != userPass {
w.Header().Set("WWW-Authenticate", "Basic")
w.WriteHeader(401)
return
}
}
foo(w, r)
}
}
func httpsOnly(https bool, foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if https && r.URL.Scheme != "https" {
log.Printf("redirecting: %+v", r.URL)
r.URL.Scheme = "https"
http.Redirect(w, r, r.URL.String(), http.StatusSeeOther)
return
}
foo(w, r)
}
}
func gzip(foo http.HandlerFunc) http.HandlerFunc { func gzip(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if gziphttp.Can(r) { if gziphttp.Can(r) {
@@ -129,17 +161,19 @@ func gzip(foo http.HandlerFunc) http.HandlerFunc {
} }
} }
func endpoints(foo http.HandlerFunc) http.HandlerFunc { func endpoints(ro bool, foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if isDir(r) { if isDir(r) {
writeMeta(w) writeMeta(w)
writeForm(w) if !ro {
writeForm(w)
}
} }
if isUploaded(r) { if !ro && isUploaded(r) {
if err := upload(w, r); err != nil { if err := upload(w, r); err != nil {
fmt.Fprintln(w, err.Error()) fmt.Fprintln(w, err.Error())
} }
} else if isDeleted(r) { } else if !ro && isDeleted(r) {
if err := del(w, r); err != nil { if err := del(w, r); err != nil {
fmt.Fprintln(w, err.Error()) fmt.Fprintln(w, err.Error())
} }
@@ -198,19 +232,19 @@ func withMD(dir string, enabled bool, mdCss, mdClass string, foo http.HandlerFun
} }
} }
func withDel(foo http.HandlerFunc) http.HandlerFunc { func withDel(ro bool, foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if !isDir(r) { if !isDir(r) {
foo(w, r) foo(w, r)
return return
} }
fmt.Fprintln(w, `<a href=".."><input type="button" style="padding: .15em 4em .35em 4em" value=".."/></a>`+"\n") fmt.Fprintln(w, `<a href=".."><input type="button" style="padding: .15em 4em .35em 4em" value=".."/></a>`)
w2 := httptest.NewRecorder() w2 := httptest.NewRecorder()
foo(w2, r) foo(w2, r)
b := bytes.Split(w2.Body.Bytes(), []byte("\n")) b := bytes.Split(w2.Body.Bytes(), []byte("\n"))
buff := bytes.NewBuffer(nil) buff := bytes.NewBuffer(nil)
for i := range b { for i := range b {
if bytes.Contains(b[i], []byte("<a href=")) { if !ro && bytes.Contains(b[i], []byte("<a href=")) {
re := regexp.MustCompile(`href="[^"]*"`) re := regexp.MustCompile(`href="[^"]*"`)
match := re.Find(b[i]) match := re.Find(b[i])
if len(match) > 0 { if len(match) > 0 {
@@ -272,3 +306,48 @@ func toRealPath(p string) string {
d := path.Join(fs.Get("d").GetString()) d := path.Join(fs.Get("d").GetString())
return path.Join(d, p) return path.Join(d, p)
} }
func setContentTypeIfMedia(w http.ResponseWriter, r *http.Request) {
switch strings.ToLower(path.Ext(r.URL.Path)) {
case ".mp4":
w.Header().Set("Content-Type", "video/mp4")
case ".mkv":
w.Header().Set("Content-Type", "video/x-matroska")
case ".mp3":
w.Header().Set("Content-Type", "audio/mpeg3")
case ".epub", ".mobi":
w.Header().Set("Content-Disposition", "attachment")
case ".jpg", ".jpeg":
w.Header().Set("Content-Type", "image/jpeg")
case ".gif":
w.Header().Set("Content-Type", "image/gif")
case ".png":
w.Header().Set("Content-Type", "image/png")
case ".ico":
w.Header().Set("Content-Type", "image/x-icon")
case ".svg":
w.Header().Set("Content-Type", "image/svg+xml")
case ".css":
w.Header().Set("Content-Type", "text/css")
case ".js":
w.Header().Set("Content-Type", "text/javascript")
case ".json":
w.Header().Set("Content-Type", "application/json")
case ".html", ".htm":
w.Header().Set("Content-Type", "text/html")
case ".pdf":
w.Header().Set("Content-Type", "application/pdf")
case ".webm":
w.Header().Set("Content-Type", "video/webm")
case ".weba":
w.Header().Set("Content-Type", "audio/webm")
case ".webp":
w.Header().Set("Content-Type", "image/webp")
case ".zip":
w.Header().Set("Content-Type", "application/zip")
case ".7z":
w.Header().Set("Content-Type", "application/x-7z-compressed")
case ".tar":
w.Header().Set("Content-Type", "application/x-tar")
}
}

View File

@@ -28,6 +28,7 @@ func SetContentTypeIfMedia(w http.ResponseWriter, r *http.Request) {
v = "image/jpeg" v = "image/jpeg"
case ".md": case ".md":
v = "text/markdown" v = "text/markdown"
v = "text/html"
case ".gif": case ".gif":
v = "image/gif" v = "image/gif"
case ".png": case ".png":