mirror of
https://github.com/nais/wonderwall.git
synced 2026-05-07 00:46:56 +00:00
110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package session
|
|
|
|
import (
|
|
"context"
|
|
"encoding"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/nais/wonderwall/pkg/config"
|
|
"github.com/nais/wonderwall/pkg/crypto"
|
|
)
|
|
|
|
type Store interface {
|
|
Write(ctx context.Context, key string, value *EncryptedData, expiration time.Duration) error
|
|
Read(ctx context.Context, key string) (*EncryptedData, error)
|
|
Delete(ctx context.Context, keys ...string) error
|
|
}
|
|
|
|
func NewStore(cfg *config.Config) Store {
|
|
if len(cfg.Redis.Address) == 0 {
|
|
log.Warnf("Redis not configured, using in-memory session backing store; not suitable for multi-pod deployments!")
|
|
return NewMemory()
|
|
}
|
|
|
|
redisClient, err := cfg.Redis.Client()
|
|
if err != nil {
|
|
log.Fatalf("Failed to configure Redis: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
|
|
err = redisClient.Ping(ctx).Err()
|
|
if err != nil {
|
|
log.Warnf("Failed to connect to configured Redis, using cookie fallback: %v", err)
|
|
} else {
|
|
log.Infof("Using Redis as session backing store")
|
|
}
|
|
|
|
return NewRedis(redisClient)
|
|
}
|
|
|
|
type EncryptedData struct {
|
|
Data string `json:"data"`
|
|
}
|
|
|
|
var _ encoding.BinaryMarshaler = &EncryptedData{}
|
|
var _ encoding.BinaryUnmarshaler = &EncryptedData{}
|
|
|
|
func (in *EncryptedData) MarshalBinary() ([]byte, error) {
|
|
return json.Marshal(in)
|
|
}
|
|
|
|
func (in *EncryptedData) UnmarshalBinary(bytes []byte) error {
|
|
return json.Unmarshal(bytes, in)
|
|
}
|
|
|
|
func (in *EncryptedData) Decrypt(crypter crypto.Crypter) (*Data, error) {
|
|
ciphertext, err := base64.StdEncoding.DecodeString(in.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rawData, err := crypter.Decrypt(ciphertext)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var data Data
|
|
err = json.Unmarshal(rawData, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &data, nil
|
|
}
|
|
|
|
type Data struct {
|
|
ExternalSessionID string `json:"external_session_id"`
|
|
AccessToken string `json:"access_token"`
|
|
IDToken string `json:"id_token"`
|
|
}
|
|
|
|
func NewData(externalSessionID, accessToken, idToken string) *Data {
|
|
return &Data{
|
|
ExternalSessionID: externalSessionID,
|
|
AccessToken: accessToken,
|
|
IDToken: idToken,
|
|
}
|
|
}
|
|
|
|
func (in *Data) Encrypt(crypter crypto.Crypter) (*EncryptedData, error) {
|
|
bytes, err := json.Marshal(in)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ciphertext, err := crypter.Encrypt(bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &EncryptedData{
|
|
Data: base64.StdEncoding.EncodeToString(ciphertext),
|
|
}, nil
|
|
}
|