diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-06 21:08:45 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-06 21:08:45 -0700 |
| commit | c5a5b24cf6370ab549c033b20ad0389ec3ce8ec1 (patch) | |
| tree | dfd8b0914e2021fdd75e65c1db1beadbb51f74d9 /roseh.moe.go | |
| parent | d35bbbd54ed3de79d2a7d709013ff49d4a9413b8 (diff) | |
| download | roseh.moe-c5a5b24cf6370ab549c033b20ad0389ec3ce8ec1.tar.zst | |
Simplify simplify simplify
Diffstat (limited to 'roseh.moe.go')
| -rw-r--r-- | roseh.moe.go | 89 |
1 files changed, 38 insertions, 51 deletions
diff --git a/roseh.moe.go b/roseh.moe.go index 77c78c1..9b5c1a6 100644 --- a/roseh.moe.go +++ b/roseh.moe.go @@ -9,6 +9,7 @@ import ( "embed" "encoding/base64" "encoding/binary" + "encoding/hex" "flag" "fmt" "html/template" @@ -19,8 +20,6 @@ import ( "strings" "sync" "time" - - "gitlab.com/rhogenson/roseh.moe/internal/pwhash" ) var ( @@ -40,12 +39,12 @@ func loadSecrets() error { } for _, line := range bytes.Split(bytes.TrimSuffix(secrets, []byte("\n")), []byte("\n")) { if pw, ok := bytes.CutPrefix(line, []byte("notepad-password=")); ok { - notepadPassword, err = base64.RawURLEncoding.AppendDecode(nil, pw) + notepadPassword, err = hex.AppendDecode(nil, pw) if err != nil { return err } } else if key, ok := bytes.CutPrefix(line, []byte("secret-key=")); ok { - secretKey, err = base64.RawURLEncoding.AppendDecode(nil, key) + secretKey, err = hex.AppendDecode(nil, key) if err != nil { return err } @@ -135,9 +134,10 @@ type wormholeTemplateArgs struct { } func wormhole(w http.ResponseWriter, r *http.Request) { - buf := make([]byte, 20) + const nWords = 10 + buf := make([]byte, 2*nWords) rand.Read(buf) - words := make([]string, 10) + words := make([]string, nWords) for i := range words { words[i] = wordList[binary.NativeEndian.Uint16(buf[2*i:])&0x1fff] } @@ -247,24 +247,22 @@ func wormholeReady(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "event: ready\ndata:\n\n") } -func sign(msg []byte, info string) []byte { +func mac(msg []byte) []byte { mac := hmac.New(sha256.New, secretKey) - mac.Write(binary.AppendVarint(nil, int64(len(info)))) - io.WriteString(mac, info) mac.Write(msg) - return mac.Sum(msg) + return mac.Sum(nil) +} + +func sign(msg []byte) []byte { + return append(msg, mac(msg)...) } -func verify(msg []byte, info string) ([]byte, bool) { +func verify(msg []byte) ([]byte, bool) { if len(msg) < sha256.Size { return nil, false } msg, messageMAC := msg[:len(msg)-sha256.Size], msg[len(msg)-sha256.Size:] - mac := hmac.New(sha256.New, secretKey) - mac.Write(binary.AppendVarint(nil, int64(len(info)))) - io.WriteString(mac, info) - mac.Write(msg) - expectedMAC := mac.Sum(nil) + expectedMAC := mac(msg) if !hmac.Equal(messageMAC, expectedMAC) { return nil, false } @@ -276,27 +274,11 @@ func makeToken() (string, error) { if err != nil { return "", err } - return base64.RawURLEncoding.EncodeToString(sign(b, "auth")), nil + return base64.RawURLEncoding.EncodeToString(sign(b)), nil } const cookieExpiration = 180 * 24 * time.Hour -func checkToken(token string) bool { - authCookie, err := base64.RawURLEncoding.DecodeString(token) - if err != nil { - return false - } - msg, ok := verify(authCookie, "auth") - if !ok { - return false - } - var t time.Time - if err := t.UnmarshalBinary(msg); err != nil { - return false - } - return time.Since(t) < cookieExpiration -} - func attachCookie(w http.ResponseWriter) error { token, err := makeToken() if err != nil { @@ -339,10 +321,25 @@ func cookieAuth(w http.ResponseWriter, r *http.Request) (string, bool) { if err != nil { return csrfToken, false } - if !checkToken(cookie.Value) { + authCookie, err := base64.RawURLEncoding.DecodeString(cookie.Value) + if err != nil { return csrfToken, false } - attachCookie(w) + msg, ok := verify(authCookie) + if !ok { + return csrfToken, false + } + var t time.Time + if err := t.UnmarshalBinary(msg); err != nil { + return csrfToken, false + } + cookieAge := time.Since(t) + if cookieAge > cookieExpiration { + return csrfToken, false + } + if cookieAge > 24*time.Hour { + attachCookie(w) + } return csrfToken, true } @@ -367,15 +364,11 @@ var ( type loginTemplateArgs struct { CSRFToken string - Redirect string Error bool } -func executeLoginTemplate(w io.Writer, csrfToken, redirect string) { - if err := loginTemplate.Execute(w, loginTemplateArgs{ - Redirect: base64.RawURLEncoding.EncodeToString(sign([]byte(redirect), "redirect")), - CSRFToken: csrfToken, - }); err != nil { +func executeLoginTemplate(w io.Writer, csrfToken string) { + if err := loginTemplate.Execute(w, loginTemplateArgs{CSRFToken: csrfToken}); err != nil { log.Printf("Warning: login: %s", err) } } @@ -385,10 +378,10 @@ func login(w http.ResponseWriter, r *http.Request) { http.Error(w, "bad CSRF token", http.StatusBadRequest) return } - if err := pwhash.Check(notepadPassword, r.FormValue("password")); err != nil { + hash := sha256.Sum256([]byte(r.FormValue("password"))) + if subtle.ConstantTimeCompare(notepadPassword, hash[:]) == 0 { if err := loginTemplate.Execute(w, loginTemplateArgs{ Error: true, - Redirect: r.FormValue("redirect"), CSRFToken: r.FormValue("csrf-token"), }); err != nil { log.Printf("Warning: login: %s", err) @@ -396,13 +389,7 @@ func login(w http.ResponseWriter, r *http.Request) { return } attachCookie(w) - redirect := "/" - if b, err := base64.RawURLEncoding.DecodeString(r.FormValue("redirect")); err == nil { - if r, ok := verify(b, "redirect"); ok { - redirect = string(r) - } - } - http.Redirect(w, r, redirect, http.StatusSeeOther) + http.Redirect(w, r, "/notepad", http.StatusSeeOther) } var ( @@ -422,7 +409,7 @@ type notepadTemplateArgs struct { func notepad(w http.ResponseWriter, r *http.Request) { csrfToken, ok := cookieAuth(w, r) if !ok { - executeLoginTemplate(w, csrfToken, "/notepad") + executeLoginTemplate(w, csrfToken) return } notepadContentsMu.Lock() |
