aboutsummaryrefslogtreecommitdiff
path: root/cmd/server/auth.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/server/auth.go')
-rw-r--r--cmd/server/auth.go108
1 files changed, 108 insertions, 0 deletions
diff --git a/cmd/server/auth.go b/cmd/server/auth.go
new file mode 100644
index 0000000..caade97
--- /dev/null
+++ b/cmd/server/auth.go
@@ -0,0 +1,108 @@
+package main
+
+import (
+ "crypto/rand"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "os"
+ "strings"
+
+ "riedstra.dev/mitch/go-website/users"
+)
+
+type Auth struct {
+ Users []*users.SiteUser `json:"Users"`
+ // How long are JWTs valid?
+ LoginHours int `json:"LoginHours"`
+ // JWT secret
+ TokenKey string `json:"TokenKey"`
+ // Are cookies HTTP only?
+ HTTPOnly bool `json:"HTTPOnly"`
+ // Do they require HTTPs?
+ Secure bool `json:"SecureCookie"`
+ // See https://pkg.go.dev/net/http#SameSite
+ // You probably want this set to 3
+ SameSiteStrict http.SameSite `json:"SameSiteStrict"`
+}
+
+func GenTokenKey() string {
+ r := make([]byte, 16) // 128 bits
+ _, err := rand.Read(r)
+
+ if err != nil {
+ // Not my favorite thing, but I consider this to be a
+ // critical issue
+ panic(fmt.Errorf("reading random bytes: %w", err))
+ }
+
+ return base64.RawURLEncoding.EncodeToString(r)
+}
+
+func (a *App) ReadAuth(fn string) error { //nolint
+ auth := &Auth{
+ Users: []*users.SiteUser{
+ {
+ Username: "admin",
+ Password: "admin",
+ },
+ },
+ LoginHours: 1,
+ TokenKey: GenTokenKey(),
+ HTTPOnly: true,
+ Secure: true,
+ SameSiteStrict: http.SameSiteStrictMode,
+ }
+
+ var dec *json.Decoder
+
+ fh, err := os.Open(fn)
+ if err != nil {
+ if strings.Contains(err.Error(), "no such file") {
+ goto write
+ }
+
+ return fmt.Errorf("opening %s: %w", fn, err)
+ }
+
+ dec = json.NewDecoder(fh)
+ dec.DisallowUnknownFields()
+
+ err = dec.Decode(auth)
+ if err != nil {
+ return fmt.Errorf("decoding file %s: %w", fn, err)
+ }
+
+ err = fh.Close()
+ if err != nil {
+ return fmt.Errorf("closing file %s: %w", fn, err)
+ }
+
+ for _, u := range auth.Users {
+ err = u.SetPasswordHashIfNecessary()
+ if err != nil {
+ return fmt.Errorf("setting password hash for: %s: %w",
+ u.Username, err)
+ }
+ }
+
+write:
+ fh, err = os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
+
+ if err != nil {
+ return fmt.Errorf("opening file %s: %w", fn, err)
+ }
+
+ enc := json.NewEncoder(fh)
+ enc.SetIndent("", " ")
+
+ err = enc.Encode(auth)
+ if err != nil {
+ return fmt.Errorf("encoding to file %s: %w", fn, err)
+ }
+
+ a.auth = auth
+
+ return nil
+}