auth.go (1928B)
1 package internal 2 3 import ( 4 "crypto/hmac" 5 "crypto/sha256" 6 "encoding/base64" 7 "net/http" 8 "os" 9 "strconv" 10 "strings" 11 "time" 12 ) 13 14 var secretKey []byte 15 16 func init() { 17 if k := os.Getenv("MARKY_SECRET"); k != "" { 18 secretKey = []byte(k) 19 } else { 20 secretKey = []byte("dev-secret-change-me") 21 } 22 } 23 24 // SetSession sets a signed cookie identifying the user ID. 25 func SetSession(w http.ResponseWriter, userID int64) { 26 exp := time.Now().Add(30 * 24 * time.Hour).Unix() 27 payload := strconv.FormatInt(userID, 10) + ":" + strconv.FormatInt(exp, 10) 28 sig := sign(payload) 29 val := payload + ":" + sig 30 http.SetCookie(w, &http.Cookie{ 31 Name: "marky_session", 32 Value: base64.StdEncoding.EncodeToString([]byte(val)), 33 Path: "/", 34 HttpOnly: true, 35 SameSite: http.SameSiteLaxMode, 36 MaxAge: int(30 * 24 * time.Hour / time.Second), 37 }) 38 } 39 40 // ClearSession removes the session cookie. 41 func ClearSession(w http.ResponseWriter) { 42 http.SetCookie(w, &http.Cookie{Name: "marky_session", Value: "", Path: "/", MaxAge: -1}) 43 } 44 45 // CurrentUserID extracts the user ID from the signed cookie, if valid. 46 func CurrentUserID(r *http.Request) (int64, bool) { 47 c, err := r.Cookie("marky_session") 48 if err != nil || c.Value == "" { 49 return 0, false 50 } 51 raw, err := base64.StdEncoding.DecodeString(c.Value) 52 if err != nil { 53 return 0, false 54 } 55 parts := strings.Split(string(raw), ":") 56 if len(parts) != 3 { 57 return 0, false 58 } 59 payload := parts[0] + ":" + parts[1] 60 if !hmac.Equal([]byte(sign(payload)), []byte(parts[2])) { 61 return 0, false 62 } 63 exp, err := strconv.ParseInt(parts[1], 10, 64) 64 if err != nil || exp < time.Now().Unix() { 65 return 0, false 66 } 67 uid, err := strconv.ParseInt(parts[0], 10, 64) 68 if err != nil || uid <= 0 { 69 return 0, false 70 } 71 return uid, true 72 } 73 74 func sign(s string) string { 75 mac := hmac.New(sha256.New, secretKey) 76 mac.Write([]byte(s)) 77 sum := mac.Sum(nil) 78 return base64.StdEncoding.EncodeToString(sum[:16]) 79 }