- Setup C++/Qt6 desktop application structure - Added initial Go proxy backend for TMDB/IGDB integration
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// appClaims is the payload of a desktop-app access token. These tokens are
|
|
// minted by this server after a successful Authentik login and are independent
|
|
// of the (short-lived) OIDC tokens, so a friend can paste one into the desktop
|
|
// app and keep using it until it expires.
|
|
type appClaims struct {
|
|
Subject string `json:"sub"`
|
|
Email string `json:"email"`
|
|
Expires int64 `json:"exp"` // unix seconds
|
|
}
|
|
|
|
// mintToken creates a stateless, HMAC-signed token of the form
|
|
// base64url(payload).base64url(sig). No server-side storage is needed.
|
|
func mintToken(secret []byte, sub, email string, ttl time.Duration) (string, error) {
|
|
payload := appClaims{
|
|
Subject: sub,
|
|
Email: email,
|
|
Expires: time.Now().Add(ttl).Unix(),
|
|
}
|
|
raw, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
body := base64.RawURLEncoding.EncodeToString(raw)
|
|
sig := sign(secret, body)
|
|
return body + "." + sig, nil
|
|
}
|
|
|
|
// verifyToken validates the signature and expiry, returning the claims.
|
|
func verifyToken(secret []byte, token string) (*appClaims, error) {
|
|
parts := strings.SplitN(strings.TrimSpace(token), ".", 2)
|
|
if len(parts) != 2 {
|
|
return nil, errors.New("malformed token")
|
|
}
|
|
expected := sign(secret, parts[0])
|
|
if !hmac.Equal([]byte(expected), []byte(parts[1])) {
|
|
return nil, errors.New("bad signature")
|
|
}
|
|
raw, err := base64.RawURLEncoding.DecodeString(parts[0])
|
|
if err != nil {
|
|
return nil, errors.New("bad payload encoding")
|
|
}
|
|
var claims appClaims
|
|
if err := json.Unmarshal(raw, &claims); err != nil {
|
|
return nil, errors.New("bad payload")
|
|
}
|
|
if time.Now().Unix() >= claims.Expires {
|
|
return nil, errors.New("token expired")
|
|
}
|
|
return &claims, nil
|
|
}
|
|
|
|
func sign(secret []byte, body string) string {
|
|
m := hmac.New(sha256.New, secret)
|
|
m.Write([]byte(body))
|
|
return base64.RawURLEncoding.EncodeToString(m.Sum(nil))
|
|
}
|