package session import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "strings" "time" "github.com/google/uuid" ) const cookieName = "vpn_panel_session" const maxAge = 7 * 24 * time.Hour type Data struct { UserID uuid.UUID `json:"uid"` Email string `json:"email"` Role string `json:"role"` Exp int64 `json:"exp"` } func CookieName() string { return cookieName } func Sign(secret string, d Data) (string, error) { d.Exp = time.Now().Add(maxAge).Unix() payload, err := json.Marshal(d) if err != nil { return "", err } b64 := base64.RawURLEncoding.EncodeToString(payload) sig := sign(secret, b64) return b64 + "." + sig, nil } func Verify(secret, token string) (*Data, error) { parts := strings.Split(token, ".") if len(parts) != 2 { return nil, errors.New("invalid token") } if sign(secret, parts[0]) != parts[1] { return nil, errors.New("bad signature") } raw, err := base64.RawURLEncoding.DecodeString(parts[0]) if err != nil { return nil, err } var d Data if err := json.Unmarshal(raw, &d); err != nil { return nil, err } if time.Now().Unix() > d.Exp { return nil, errors.New("expired") } return &d, nil } func sign(secret, payload string) string { m := hmac.New(sha256.New, []byte(secret)) m.Write([]byte(payload)) return base64.RawURLEncoding.EncodeToString(m.Sum(nil)) }