-
Notifications
You must be signed in to change notification settings - Fork 110
sessions: delete session after registration failure #1174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -442,7 +442,10 @@ func (db *BoltStore) DeleteReservedSessions(_ context.Context) error { | |
| return err | ||
| } | ||
|
|
||
| return sessionBucket.ForEach(func(k, v []byte) error { | ||
| // We create a copy of the sessions to delete so that we are | ||
| // not iterating and modifying the bucket at the same time. | ||
| var sessionsToDelete []*Session | ||
| err = sessionBucket.ForEach(func(k, v []byte) error { | ||
| // We'll also get buckets here, skip those (identified | ||
| // by nil value). | ||
| if v == nil { | ||
|
|
@@ -458,69 +461,120 @@ func (db *BoltStore) DeleteReservedSessions(_ context.Context) error { | |
| return nil | ||
| } | ||
|
|
||
| err = sessionBucket.Delete(k) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| sessionsToDelete = append(sessionsToDelete, session) | ||
|
|
||
| idIndexBkt := sessionBucket.Bucket(idIndexKey) | ||
| if idIndexBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
| return nil | ||
| }) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Delete the entire session ID bucket. | ||
| err = idIndexBkt.DeleteBucket(session.ID[:]) | ||
| if err != nil { | ||
| for _, session := range sessionsToDelete { | ||
| if err := deleteSession(sessionBucket, | ||
| session); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| groupIdIndexBkt := sessionBucket.Bucket(groupIDIndexKey) | ||
| if groupIdIndexBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
| return nil | ||
| }) | ||
| } | ||
|
|
||
| groupBkt := groupIdIndexBkt.Bucket(session.GroupID[:]) | ||
| if groupBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
| // deleteSession deletes all the parts of a session from the database. This | ||
| // assumes that the session has already been fetched from the db. | ||
| func deleteSession(sessionBucket *bbolt.Bucket, session *Session) error { | ||
| sessionKey := getSessionKey(session) | ||
| err := sessionBucket.Delete(sessionKey) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| sessionIDsBkt := groupBkt.Bucket(sessionIDKey) | ||
| if sessionIDsBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
| idIndexBkt := sessionBucket.Bucket(idIndexKey) | ||
| if idIndexBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
|
|
||
| var ( | ||
| seqKey []byte | ||
| numSessions int | ||
| ) | ||
| err = sessionIDsBkt.ForEach(func(k, v []byte) error { | ||
| numSessions++ | ||
| // Delete the entire session ID bucket. | ||
| err = idIndexBkt.DeleteBucket(session.ID[:]) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if !bytes.Equal(v, session.ID[:]) { | ||
| return nil | ||
| } | ||
| groupIdIndexBkt := sessionBucket.Bucket(groupIDIndexKey) | ||
| if groupIdIndexBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
|
|
||
| seqKey = k | ||
| groupBkt := groupIdIndexBkt.Bucket(session.GroupID[:]) | ||
| if groupBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
|
|
||
| return nil | ||
| }) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| sessionIDsBkt := groupBkt.Bucket(sessionIDKey) | ||
| if sessionIDsBkt == nil { | ||
| return ErrDBInitErr | ||
| } | ||
|
|
||
| if numSessions == 0 { | ||
| return fmt.Errorf("no sessions found for "+ | ||
| "group ID %x", session.GroupID) | ||
| } | ||
| var ( | ||
| seqKey []byte | ||
| numSessions int | ||
| ) | ||
| err = sessionIDsBkt.ForEach(func(k, v []byte) error { | ||
| numSessions++ | ||
|
|
||
| if numSessions == 1 { | ||
| // Delete the whole group bucket. | ||
| return groupBkt.DeleteBucket(sessionIDKey) | ||
| } | ||
| if !bytes.Equal(v, session.ID[:]) { | ||
| return nil | ||
| } | ||
|
|
||
| // Else, delete just the session ID entry. | ||
| return sessionIDsBkt.Delete(seqKey) | ||
| }) | ||
| seqKey = k | ||
|
|
||
| return nil | ||
| }) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if numSessions == 0 { | ||
| return fmt.Errorf("no sessions found for "+ | ||
| "group ID %x", session.GroupID) | ||
| } | ||
|
|
||
| if numSessions == 1 { | ||
| // If this is the last session in the group, we can delete the | ||
| // whole group bucket. | ||
| return groupIdIndexBkt.DeleteBucket(session.GroupID[:]) | ||
| } | ||
|
|
||
| // Else, delete just the session ID entry from the group. | ||
| return sessionIDsBkt.Delete(seqKey) | ||
| } | ||
|
|
||
| // DeleteReservedSession removes a given session that is in the reserved state | ||
| // from the database. | ||
| // | ||
| // NOTE: This is part of the Store interface. | ||
| func (db *BoltStore) DeleteReservedSession(_ context.Context, id ID) error { | ||
| return db.Update(func(tx *bbolt.Tx) error { | ||
| sessionBucket, err := getBucket(tx, sessionBucketKey) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // We'll first get the session to make sure it's actually in the | ||
| // reserved state before deleting. This gives us a slightly | ||
| // better error message than just trying to delete and getting a | ||
| // "not found" if the session was in another state. | ||
| session, err := getSessionByID(sessionBucket, id) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if session.State != StateReserved { | ||
| return fmt.Errorf("session not in reserved state, is "+ | ||
| "%v", session.State) | ||
| } | ||
|
|
||
| return deleteSession(sessionBucket, session) | ||
|
Comment on lines
+572
to
+577
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as mentioned above, could just make the db query enforce this constraint |
||
| }) | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could maybe in future make things more defensive (both here and above by restricting this to only allowing it for "where status=reserved" - but i guess it's ok for now since your store interface does this protection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, I see your point enforcing that on the db layer would be safer, one downside of this is that we'd need to hard code an integer here for the type (i.e.
4), so we'd lose some type safety, right? for this reason I kept the current approach, but I'll definitely consider that approach in future work 🙏