Files
gocommon/session/common.go

163 lines
3.8 KiB
Go

package session
import (
"context"
"encoding/binary"
"encoding/hex"
"errors"
"math/rand"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type Authorization struct {
Account primitive.ObjectID `bson:"a" json:"a"`
invalidated string
// by authorization provider
Platform string `bson:"p" json:"p"`
Uid string `bson:"u" json:"u"`
Alias string `bson:"al" json:"al"`
CreatedTime primitive.DateTime `bson:"ct" json:"ct"`
}
func (auth *Authorization) ToStrings() []string {
return []string{
"a", auth.Account.Hex(),
"p", auth.Platform,
"u", auth.Uid,
"al", auth.Alias,
"inv", auth.invalidated,
}
}
func (auth *Authorization) Valid() bool {
return len(auth.invalidated) == 0 && !auth.Account.IsZero()
}
func MakeAuthrizationFromStringMap(src map[string]string) Authorization {
accid, _ := primitive.ObjectIDFromHex(src["a"])
return Authorization{
Account: accid,
Platform: src["p"],
Uid: src["u"],
Alias: src["al"],
invalidated: src["inv"],
}
}
type Provider interface {
New(*Authorization) (string, error)
RevokeAll(primitive.ObjectID) error
Query(string) (Authorization, error)
Touch(string) (bool, error)
}
type Consumer interface {
Query(string) Authorization
Touch(string) (Authorization, error)
IsRevoked(primitive.ObjectID) bool
Revoke(string)
RegisterOnSessionInvalidated(func(primitive.ObjectID))
}
type storagekey string
type publickey string
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
func make_storagekey(acc primitive.ObjectID) storagekey {
bs := [4]byte{}
binary.LittleEndian.PutUint32(bs[:], r.Uint32())
return storagekey(acc.Hex() + hex.EncodeToString(bs[2:]))
}
func storagekey_to_publickey(sk storagekey) publickey {
bs, _ := hex.DecodeString(string(sk))
acc := bs[:12]
cs := bs[12:]
encoded := [14]byte{}
for i, v := range acc[:] {
encoded[i] = (v ^ cs[0]) ^ cs[1]
}
encoded[12] = cs[0]
encoded[13] = cs[1]
return publickey(hex.EncodeToString(encoded[:]))
}
func publickey_to_storagekey(pk publickey) storagekey {
bs, _ := hex.DecodeString(string(pk))
acc := bs[:12]
cs := bs[12:]
decoded := [14]byte{}
for i, v := range acc[:] {
decoded[i] = (v ^ cs[1]) ^ cs[0]
}
decoded[12] = cs[0]
decoded[13] = cs[1]
return storagekey(hex.EncodeToString(decoded[:]))
}
type SessionConfig struct {
SessionTTL int64 `json:"session_ttl"`
SessionStorage string `json:"session_storage"`
}
var errInvalidScheme = errors.New("storageAddr is not valid scheme")
var errSessionStorageMissing = errors.New("session_storageis missing")
func NewConsumer(ctx context.Context, storageAddr string, ttl time.Duration) (Consumer, error) {
if strings.HasPrefix(storageAddr, "mongodb") {
return newConsumerWithMongo(ctx, storageAddr, ttl)
}
if strings.HasPrefix(storageAddr, "redis") {
return newConsumerWithRedis(ctx, storageAddr, ttl)
}
return nil, errInvalidScheme
}
func NewConsumerWithConfig(ctx context.Context, cfg SessionConfig) (Consumer, error) {
if len(cfg.SessionStorage) == 0 {
return nil, errSessionStorageMissing
}
if cfg.SessionTTL == 0 {
cfg.SessionTTL = 3600
}
return NewConsumer(ctx, cfg.SessionStorage, time.Duration(cfg.SessionTTL)*time.Second)
}
func NewProvider(ctx context.Context, storageAddr string, ttl time.Duration) (Provider, error) {
if strings.HasPrefix(storageAddr, "mongodb") {
return newProviderWithMongo(ctx, storageAddr, ttl)
}
if strings.HasPrefix(storageAddr, "redis") {
return newProviderWithRedis(ctx, storageAddr, ttl)
}
return nil, errInvalidScheme
}
func NewProviderWithConfig(ctx context.Context, cfg SessionConfig) (Provider, error) {
if len(cfg.SessionStorage) == 0 {
return nil, errSessionStorageMissing
}
if cfg.SessionTTL == 0 {
cfg.SessionTTL = 3600
}
return NewProvider(ctx, cfg.SessionStorage, time.Duration(cfg.SessionTTL)*time.Second)
}