Bootstrap copied BFF and local accounts with public Sendico contracts (#34)

This commit is contained in:
Stephan D committed 2026-09-12 13:37:48 +02:00
1 parent 67dc5b5b1e
commit 7062672a87
556 files changed
+42291 -777

No files matched your search

@@ -0,0 +1,140 @@
package model
import (
"fmt"
"time"
"git.sendico.io/tech/sxchnge/bff/edge/shared/interface/middleware"
"git.sendico.io/tech/sxchnge/bff/pkg/merrors"
"git.sendico.io/tech/sxchnge/bff/pkg/model"
mduration "git.sendico.io/tech/sxchnge/bff/pkg/mutil/duration"
"go.mongodb.org/mongo-driver/v2/bson"
)
type AccountToken struct {
AccountRef bson.ObjectID
Login string
Name string
Locale string
model.SessionIdentifier
Expiration time.Time
Pending bool
}
func createAccountToken(a *model.Account, expiration int, session model.SessionIdentifier) AccountToken {
return AccountToken{
AccountRef: *a.GetID(),
Login: a.Login,
Name: a.Name,
Locale: a.Locale,
SessionIdentifier: session,
Expiration: time.Now().Add(mduration.Param2Duration(expiration, time.Hour)),
Pending: false,
}
}
func getTokenParam(claims middleware.MapClaims, param string) (string, error) {
id, ok := claims[param].(string)
if !ok {
return "", merrors.NoData(fmt.Sprintf("param '%s' not found", param))
}
return id, nil
}
const (
paramNameID = "id"
paramNameName = "name"
paramNameLocale = "locale"
paramNameLogin = "login"
paramNameClientID = "clientId"
paramNameDeviceID = "deviceId"
paramNameSessionVersion = "sessionVersion"
paramNameExpiration = "exp"
paramNamePending = "pending"
)
func Claims2Token(claims middleware.MapClaims) (*AccountToken, error) {
var at AccountToken
var err error
var account string
if account, err = getTokenParam(claims, paramNameID); err != nil {
return nil, err
}
if at.AccountRef, err = bson.ObjectIDFromHex(account); err != nil {
return nil, err
}
if at.Login, err = getTokenParam(claims, paramNameLogin); err != nil {
return nil, err
}
if at.Name, err = getTokenParam(claims, paramNameName); err != nil {
return nil, err
}
if at.Locale, err = getTokenParam(claims, paramNameLocale); err != nil {
return nil, err
}
if clientID, ok := claims[paramNameClientID]; ok {
if clientIDText, ok := clientID.(string); ok {
at.ClientID = clientIDText
}
}
if deviceID, ok := claims[paramNameDeviceID]; ok {
if deviceIDText, ok := deviceID.(string); ok {
at.DeviceID = deviceIDText
}
}
if version, ok := claims[paramNameSessionVersion]; ok {
if versionText, ok := version.(string); ok {
at.SessionVersion = versionText
}
}
if pending, ok := claims[paramNamePending]; ok {
if pbool, ok := pending.(bool); ok {
at.Pending = pbool
}
}
if expValue, ok := claims[paramNameExpiration]; ok {
switch exp := expValue.(type) {
case time.Time:
at.Expiration = exp
case float64:
at.Expiration = time.Unix(int64(exp), 0)
case int64:
at.Expiration = time.Unix(exp, 0)
default:
return nil, merrors.InvalidDataType(fmt.Sprintf("expiration param is of invalid type: %T", expValue))
}
} else {
return nil, merrors.InvalidDataType(fmt.Sprintf("expiration param is of invalid type: %T", expValue))
}
return &at, nil
}
func Account2ClaimsForSession(a *model.Account, expiration int, session model.SessionIdentifier) middleware.MapClaims {
t := createAccountToken(a, expiration, session)
return middleware.MapClaims{
paramNameID: t.AccountRef.Hex(),
paramNameLogin: t.Login,
paramNameName: t.Name,
paramNameLocale: t.Locale,
paramNameClientID: t.ClientID,
paramNameDeviceID: t.DeviceID,
paramNameSessionVersion: t.SessionVersion,
paramNameExpiration: t.Expiration.Unix(),
paramNamePending: t.Pending,
}
}
func PendingAccount2Claims(a *model.Account, expirationMinutes int) middleware.MapClaims {
t := createAccountToken(a, expirationMinutes/60, model.SessionIdentifier{})
t.Expiration = time.Now().Add(time.Duration(expirationMinutes) * time.Minute)
t.Pending = true
return middleware.MapClaims{
paramNameID: t.AccountRef.Hex(),
paramNameLogin: t.Login,
paramNameName: t.Name,
paramNameLocale: t.Locale,
paramNameExpiration: t.Expiration.Unix(),
paramNamePending: t.Pending,
}
}
@@ -0,0 +1,32 @@
package model
import (
"testing"
basemodel "git.sendico.io/tech/sxchnge/bff/pkg/model"
"go.mongodb.org/mongo-driver/v2/bson"
)
func TestAccountTokenPreservesSessionIdentity(t *testing.T) {
account := &basemodel.Account{}
account.SetID(bson.NewObjectID())
account.Login = "security@example.com"
account.Name = "Security"
account.Locale = "en"
session := basemodel.SessionIdentifier{
ClientID: "web",
DeviceID: "device-a",
SessionVersion: "session-version-a",
}
token, err := Claims2Token(Account2ClaimsForSession(account, 1, session))
if err != nil {
t.Fatalf("decode account claims: %v", err)
}
if token.SessionIdentifier != session {
t.Fatalf("session identity = %#v, want %#v", token.SessionIdentifier, session)
}
if token.Expiration.IsZero() {
t.Fatal("access token expiration is missing")
}
}