Files
cpone_dashboard/cpone-dashboard/menu/auth/session.go
2026-04-30 14:27:01 +07:00

125 lines
2.5 KiB
Go

package auth
import (
"context"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"net/http"
"strconv"
"strings"
"time"
)
const cookieName = "cpone_session"
const projectCookieName = "cpone_project_mcu_id"
type ctxKey string
const userCtxKey ctxKey = "username"
// Username returns the logged-in username from the request context.
func Username(r *http.Request) string {
v, _ := r.Context().Value(userCtxKey).(string)
return v
}
func setContext(r *http.Request, username string) *http.Request {
return r.WithContext(context.WithValue(r.Context(), userCtxKey, username))
}
func SetSession(w http.ResponseWriter, username, secret string) {
val := encode(username) + "." + sign(username, secret)
http.SetCookie(w, &http.Cookie{
Name: cookieName,
Value: val,
Path: "/",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(24 * time.Hour),
})
}
func ClearSession(w http.ResponseWriter) {
http.SetCookie(w, &http.Cookie{
Name: cookieName,
Value: "",
Path: "/",
MaxAge: -1,
})
}
func SetSelectedProject(w http.ResponseWriter, mcuID int) {
http.SetCookie(w, &http.Cookie{
Name: projectCookieName,
Value: strconv.Itoa(mcuID),
Path: "/",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(7 * 24 * time.Hour),
})
}
func ClearSelectedProject(w http.ResponseWriter) {
http.SetCookie(w, &http.Cookie{
Name: projectCookieName,
Value: "",
Path: "/",
MaxAge: -1,
})
}
func SelectedProjectID(r *http.Request) int {
c, err := r.Cookie(projectCookieName)
if err != nil {
return 0
}
id, err := strconv.Atoi(strings.TrimSpace(c.Value))
if err != nil {
return 0
}
return id
}
func getSession(r *http.Request, secret string) string {
c, err := r.Cookie(cookieName)
if err != nil {
return ""
}
parts := strings.SplitN(c.Value, ".", 2)
if len(parts) != 2 {
return ""
}
username, err := decode(parts[0])
if err != nil || username == "" {
return ""
}
if !hmac.Equal([]byte(sign(username, secret)), []byte(parts[1])) {
return ""
}
return username
}
func newUUID() string {
b := make([]byte, 16)
rand.Read(b)
return hex.EncodeToString(b)
}
func sign(username, secret string) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(username))
return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
}
func encode(s string) string {
return base64.RawURLEncoding.EncodeToString([]byte(s))
}
func decode(s string) (string, error) {
b, err := base64.RawURLEncoding.DecodeString(s)
return string(b), err
}