package session import ( "context" "encoding/binary" "encoding/hex" "errors" "math/rand" "strings" "time" "go.mongodb.org/mongo-driver/bson/primitive" "repositories.action2quare.com/ayo/gocommon" ) const ( communication_channel_name_prefix = "_sess_comm_chan_name" session_collection_name = gocommon.CollectionName("session") ) type Authorization struct { Account primitive.ObjectID `bson:"a" json:"a"` // by authorization provider Platform string `bson:"p" json:"p"` Uid string `bson:"u" json:"u"` Email string `bson:"em" json:"em"` } type Provider interface { New(*Authorization) (string, error) Delete(primitive.ObjectID) error Query(string) (*Authorization, error) } type Consumer interface { Query(string) (*Authorization, error) Touch(string) (*Authorization, error) } 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") 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) { 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) { return NewProvider(ctx, cfg.SessionStorage, time.Duration(cfg.SessionTTL)*time.Second) }