65 lines
1.3 KiB
Go
65 lines
1.3 KiB
Go
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))
|
|
}
|