···
9
+
"tangled.sh/tangled.sh/core/appview/cache"
12
+
type OAuthSession struct {
18
+
AuthServerIss string
20
+
DpopAuthserverNonce string
21
+
DpopPrivateJwk string
25
+
type OAuthRequest struct {
26
+
AuthserverIss string
32
+
DpopAuthserverNonce string
33
+
DpopPrivateJwk string
36
+
type SessionStore struct {
40
+
func New(cache *cache.Cache) *SessionStore {
41
+
return &SessionStore{cache: cache}
44
+
func (s *SessionStore) SaveSession(ctx context.Context, session OAuthSession) error {
45
+
key := fmt.Sprintf("oauthsession:%s", session.Did)
46
+
data, err := json.Marshal(session)
51
+
// Set with TTL = expires in + buffer
52
+
expiry, _ := time.Parse(time.RFC3339, session.Expiry)
53
+
ttl := time.Until(expiry) + time.Minute
55
+
return s.cache.Set(ctx, key, data, ttl).Err()
58
+
// SaveRequest stores the OAuth request to be later fetched in the callback. Since
59
+
// the fetching happens by comparing the state we get in the callback params, we
60
+
// store an additional state->did mapping which then lets us fetch the whole OAuth request.
61
+
func (s *SessionStore) SaveRequest(ctx context.Context, request OAuthRequest) error {
62
+
key := fmt.Sprintf("oauthrequest:%s", request.Did)
63
+
data, err := json.Marshal(request)
68
+
// oauth flow must complete within 30 minutes
69
+
err = s.cache.Set(ctx, key, data, 30*time.Minute).Err()
71
+
return fmt.Errorf("error saving request: %w", err)
74
+
stateKey := fmt.Sprintf("oauthstate:%s", request.State)
75
+
err = s.cache.Set(ctx, stateKey, request.Did, 30*time.Minute).Err()
77
+
return fmt.Errorf("error saving state->did mapping: %w", err)
83
+
func (s *SessionStore) GetSession(ctx context.Context, did string) (*OAuthSession, error) {
84
+
key := fmt.Sprintf("oauthsession:%s", did)
85
+
val, err := s.cache.Get(ctx, key).Result()
90
+
var session OAuthSession
91
+
err = json.Unmarshal([]byte(val), &session)
95
+
return &session, nil
98
+
func (s *SessionStore) GetRequestByState(ctx context.Context, state string) (*OAuthRequest, error) {
99
+
didKey, err := s.getRequestKey(ctx, state)
104
+
val, err := s.cache.Get(ctx, didKey).Result()
109
+
var request OAuthRequest
110
+
err = json.Unmarshal([]byte(val), &request)
115
+
return &request, nil
118
+
func (s *SessionStore) DeleteSession(ctx context.Context, did string) error {
119
+
key := fmt.Sprintf("oauthsession:%s", did)
120
+
return s.cache.Del(ctx, key).Err()
123
+
func (s *SessionStore) DeleteRequestByState(ctx context.Context, state string) error {
124
+
key := fmt.Sprintf("oauthstate:%s", state)
125
+
did, err := s.cache.Get(ctx, key).Result()
130
+
didKey := fmt.Sprintf("oauthrequest:%s", did)
131
+
return s.cache.Del(ctx, didKey).Err()
134
+
func (s *SessionStore) RefreshSession(ctx context.Context, did, access, refresh, expiry string) error {
135
+
session, err := s.GetSession(ctx, did)
139
+
session.AccessJwt = access
140
+
session.RefreshJwt = refresh
141
+
session.Expiry = expiry
142
+
return s.SaveSession(ctx, *session)
145
+
func (s *SessionStore) UpdateNonce(ctx context.Context, did, nonce string) error {
146
+
session, err := s.GetSession(ctx, did)
150
+
session.DpopAuthserverNonce = nonce
151
+
return s.SaveSession(ctx, *session)
154
+
func (s *SessionStore) getRequestKey(ctx context.Context, state string) (string, error) {
155
+
key := fmt.Sprintf("oauthstate:%s", state)
156
+
did, err := s.cache.Get(ctx, key).Result()
161
+
didKey := fmt.Sprintf("oauthrequest:%s", did)