diff options
| author | Mitchell Riedstra <mitch@riedstra.dev> | 2023-01-03 23:49:41 -0500 |
|---|---|---|
| committer | Mitchell Riedstra <mitch@riedstra.dev> | 2023-01-03 23:49:41 -0500 |
| commit | c71b37eb23d4c8af7ab983de34c6da5be9363f3a (patch) | |
| tree | fa699de5d31008b17529d799df00a9a3290c52bf | |
| parent | 61612c8e1861ac704bbe592a623a41f12ebc9c11 (diff) | |
| download | paste-c71b37eb23d4c8af7ab983de34c6da5be9363f3a.tar.gz paste-c71b37eb23d4c8af7ab983de34c6da5be9363f3a.tar.xz | |
Also add Nginx testing script, logging options and
some docs.
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | LICENSE | 2 | ||||
| -rw-r--r-- | main.go | 56 | ||||
| -rw-r--r-- | nginx.conf | 46 | ||||
| -rwxr-xr-x | nginx.sh | 10 |
5 files changed, 109 insertions, 8 deletions
@@ -1,3 +1,6 @@ bpaste paste .idea/* +*.pem +storage/* +ses.vim @@ -1,4 +1,4 @@ -Copyright (c) 2021 Mitchell Riedstra +Copyright (c) 2023 Mitchell Riedstra Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -73,6 +73,8 @@ func main() { var ( listen = ":6130" idBytes = "8" + logRequestsF = "false" + logRequests bool debugF = "false" debug bool genhash = false @@ -105,9 +107,13 @@ func main() { EnvFlagString(fl, &proxyURL, "sp", "STATIC_PROXY", "What server do we proxy to for static content?") EnvFlagString(fl, &jwtKey, "jwt", "JWT_KEY", - "If supplied use the value as the JWT key instead of a random value") + "If supplied use the value as the JWT key instead of a random value\n"+ + "Please understand this is not a good idea. Use a random key if "+ + "possible\n") EnvFlagString(fl, &sessionHours, "hours", "SESSION_HOURS", "How many hours should login sessions last?") + EnvFlagString(fl, &logRequestsF, "log", "LOG_REQUESTS", + "Do we do full request logs, or are we quiet?") fl.BoolVar(&genhash, "genhash", genhash, "Interactively prompt for a password and spit out a hash\n") version := fl.Bool("v", false, "Print version then exit") @@ -129,6 +135,11 @@ func main() { logger.Println("Warning invalid value for debug: ", debugF) } + logRequests, err = strconv.ParseBool(logRequestsF) + if err != nil { + logger.Println("Warning invalid value for logRequests: ", logRequestsF) + } + if debug { logger.SetFlags(log.LstdFlags | log.Llongfile) } @@ -184,8 +195,14 @@ func main() { logger.Println("listening on: ", listen) + handler := app.Handler() + + if logRequests { + handler = httpRequestLogger(handler) + } + srv := &http.Server{ - Handler: logRequests(app.Handler()), + Handler: handler, Addr: listen, WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, @@ -220,7 +237,7 @@ func getProxyHandler(proxyURL string) (http.Handler, error) { return rp, nil } -func logRequests(next http.Handler) http.Handler { +func httpRequestLogger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { logger.Printf("%s %s %s \"%s\" \"%s\"\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent(), r.Referer()) @@ -283,10 +300,12 @@ func (a *App) Handler() http.Handler { "/api/v1/login": loginHandler(a.users, a.jwtKey, a.sessionHours), "/api/v1/logout": logoutHandler(), - "/": http.FileServer(http.FS(a.static)), + "/_app/": http.FileServer(http.FS(a.static)), + "/": a.HandleIndex(a.static), } if a.staticHandler != nil { + delete(handlers, "/_app") handlers["/"] = a.staticHandler } @@ -317,6 +336,13 @@ func (a *App) Handler() http.Handler { return mux } +// LoadUsersFromEnviron lets you build a very basic user store from scraping +// the environment variables alone. Environment variables are in the form of +// `USER_<username>=<hash>` For example in a shell script: +// +// export USER_mitch='$2a$10$MdpHOxqyaxVwX7tBmch/MOnuq5jgcy7ciCUGwixVR43SchyDtxLVW' +// +// Will then be picked up and put into the map as mitch: <hash_above> func LoadUsersFromEnviron() UsersMap { users := map[string]string{} for _, entry := range os.Environ() { @@ -335,6 +361,22 @@ func LoadUsersFromEnviron() UsersMap { return users } +func (a *App) HandleIndex(f fs.FS) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + pth := filepath.Clean(r.URL.Path) + fh, err := f.Open(pth) + if err != nil { + fh, err = f.Open("index.html") + if err != nil { + sendPlain(Response{w, http.StatusInternalServerError, + "Internal server error", nil}, nil) + } + } + + _, _ = io.Copy(w, fh) + }) +} + func genTokenKey() string { r := make([]byte, 16) // 128 bits _, err := rand.Read(r) @@ -453,12 +495,11 @@ func (users UsersMap) HasValidPlainAuth(r *http.Request) bool { // it's invalid or there are any errors. func getCookie(r *http.Request, name string) string { c, err := r.Cookie(name) - // Normally I'd also check c.Valid()... Expires is optional, but - // apparently makes it invalid? + // Normally I'd also check c.Valid()... Expires is optional, but apparently + // makes it invalid? Either way duration is handled by the JWT if err != nil { return "" } - fmt.Printf("Cookie value: '%s'\n", c.Value) return c.Value } @@ -534,6 +575,7 @@ func loginHandler(users UsersMap, jwtKey string, sessionHours int, HttpOnly: true, SameSite: http.SameSiteStrictMode, Value: ss, + Secure: true, }) http.Redirect(w, r, "/", http.StatusFound) diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..07995ad --- /dev/null +++ b/nginx.conf @@ -0,0 +1,46 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + # include /etc/nginx/conf.d/*.conf; + + + server { + listen [::1]:8443 ssl http2; + listen 127.0.0.1:8443 ssl http2; + + ssl_certificate /crt.pem; + ssl_certificate_key /key.pem; + + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://localhost:6130/; + } + } +} diff --git a/nginx.sh b/nginx.sh new file mode 100755 index 0000000..31ff236 --- /dev/null +++ b/nginx.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -ex +# Testing script to run behind a local https proxy +# `mkcert` can be useful to generate valid certs +# for testing +podman run --rm --network=host \ + -v "$(pwd)/nginx.conf":/etc/nginx/nginx.conf \ + -v "$(pwd)/key.pem":/key.pem \ + -v "$(pwd)/crt.pem":/crt.pem \ + docker.io/nginx:alpine |
