Skip to content

Commit d65d04c

Browse files
committed
session: introduce Reserve->Create pattern
TODO: flesh out commit message
1 parent 6fa7a4a commit d65d04c

File tree

4 files changed

+208
-211
lines changed

4 files changed

+208
-211
lines changed

session/interface.go

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ const (
2727
type State uint8
2828

2929
/*
30-
/---> StateExpired
31-
StateCreated ---
32-
\---> StateRevoked
30+
/---> StateExpired
31+
StateReserved ---> StateCreated ---
32+
\---> StateRevoked
3333
*/
3434

3535
const (
3636
// StateCreated is the state of a session once it has been fully
37-
// committed to the Store and is ready to be used. This is the first
38-
// state of a session.
37+
// committed to the BoltStore and is ready to be used. This is the
38+
// first state after StateReserved.
3939
StateCreated State = 0
4040

4141
// StateInUse is the state of a session that is currently being used.
@@ -52,10 +52,10 @@ const (
5252
// date.
5353
StateExpired State = 3
5454

55-
// StateReserved is a temporary initial state of a session. On start-up,
56-
// any sessions in this state should be cleaned up.
57-
//
58-
// NOTE: this isn't used yet.
55+
// StateReserved is a temporary initial state of a session. This is used
56+
// to reserve a unique ID and private key pair for a session before it
57+
// is fully created. On start-up, any sessions in this state should be
58+
// cleaned up.
5959
StateReserved State = 4
6060
)
6161

@@ -123,7 +123,7 @@ func buildSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
123123
sess := &Session{
124124
ID: id,
125125
Label: label,
126-
State: StateCreated,
126+
State: StateReserved,
127127
Type: typ,
128128
Expiry: expiry.UTC(),
129129
CreatedAt: created.UTC(),
@@ -167,22 +167,16 @@ type IDToGroupIndex interface {
167167
// retrieving Terminal Connect sessions.
168168
type Store interface {
169169
// NewSession creates a new session with the given user-defined
170-
// parameters.
171-
//
172-
// NOTE: currently this purely a constructor of the Session type and
173-
// does not make any database calls. This will be changed in a future
174-
// commit.
175-
NewSession(id ID, localPrivKey *btcec.PrivateKey, label string,
176-
typ Type, expiry time.Time, serverAddr string, devServer bool,
177-
perms []bakery.Op, caveats []macaroon.Caveat,
170+
// parameters. The session will remain in the StateReserved state until
171+
// CreateSession is called for the session.
172+
NewSession(label string, typ Type, expiry time.Time, serverAddr string,
173+
devServer bool, perms []bakery.Op, caveats []macaroon.Caveat,
178174
featureConfig FeaturesConfig, privacy bool, linkedGroupID *ID,
179175
flags PrivacyFlags) (*Session, error)
180176

181-
// CreateSession adds a new session to the store. If a session with the
182-
// same local public key already exists an error is returned. This
183-
// can only be called with a Session with an ID that the Store has
184-
// reserved.
185-
CreateSession(*Session) error
177+
// CreateSession moves the given session from the StateReserved state to
178+
// the StateCreated state.
179+
CreateSession(ID) (*Session, error)
186180

187181
// GetSession fetches the session with the given key.
188182
GetSession(key *btcec.PublicKey) (*Session, error)
@@ -204,12 +198,6 @@ type Store interface {
204198
UpdateSessionRemotePubKey(localPubKey,
205199
remotePubKey *btcec.PublicKey) error
206200

207-
// GetUnusedIDAndKeyPair can be used to generate a new, unused, local
208-
// private key and session ID pair. Care must be taken to ensure that no
209-
// other thread calls this before the returned ID and key pair from this
210-
// method are either used or discarded.
211-
GetUnusedIDAndKeyPair() (ID, *btcec.PrivateKey, error)
212-
213201
// GetSessionByID fetches the session with the given ID.
214202
GetSessionByID(id ID) (*Session, error)
215203

session/kvdb_store.go

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -182,41 +182,39 @@ func getSessionKey(session *Session) []byte {
182182
return session.LocalPublicKey.SerializeCompressed()
183183
}
184184

185-
// NewSession creates a new session with the given user-defined parameters.
186-
//
187-
// NOTE: currently this purely a constructor of the Session type and does not
188-
// make any database calls. This will be changed in a future commit.
185+
// NewSession creates and persists a new session with the given user-defined
186+
// parameters. The initial state of the session will be Reserved until
187+
// CreateSession is called.
189188
//
190189
// NOTE: this is part of the Store interface.
191-
func (db *BoltStore) NewSession(id ID, localPrivKey *btcec.PrivateKey,
192-
label string, typ Type, expiry time.Time, serverAddr string,
193-
devServer bool, perms []bakery.Op, caveats []macaroon.Caveat,
194-
featureConfig FeaturesConfig, privacy bool, linkedGroupID *ID,
195-
flags PrivacyFlags) (*Session, error) {
196-
197-
return buildSession(
198-
id, localPrivKey, label, typ, db.clock.Now(), expiry,
199-
serverAddr, devServer, perms, caveats, featureConfig, privacy,
200-
linkedGroupID, flags,
201-
)
202-
}
190+
func (db *BoltStore) NewSession(label string, typ Type, expiry time.Time,
191+
serverAddr string, devServer bool, perms []bakery.Op,
192+
caveats []macaroon.Caveat, featureConfig FeaturesConfig, privacy bool,
193+
linkedGroupID *ID, flags PrivacyFlags) (*Session, error) {
203194

204-
// CreateSession adds a new session to the store. If a session with the same
205-
// local public key already exists an error is returned.
206-
//
207-
// NOTE: this is part of the Store interface.
208-
func (db *BoltStore) CreateSession(session *Session) error {
209-
sessionKey := getSessionKey(session)
210-
211-
return db.Update(func(tx *bbolt.Tx) error {
195+
var session *Session
196+
err := db.Update(func(tx *bbolt.Tx) error {
212197
sessionBucket, err := getBucket(tx, sessionBucketKey)
213198
if err != nil {
214199
return err
215200
}
216201

202+
id, localPrivKey, err := getUnusedIDAndKeyPair(sessionBucket)
203+
if err != nil {
204+
return err
205+
}
206+
207+
session, err = buildSession(
208+
id, localPrivKey, label, typ, db.clock.Now(), expiry,
209+
serverAddr, devServer, perms, caveats, featureConfig,
210+
privacy, linkedGroupID, flags,
211+
)
212+
213+
sessionKey := getSessionKey(session)
214+
217215
if len(sessionBucket.Get(sessionKey)) != 0 {
218-
return fmt.Errorf("session with local public "+
219-
"key(%x) already exists",
216+
return fmt.Errorf("session with local public key(%x) "+
217+
"already exists",
220218
session.LocalPublicKey.SerializeCompressed())
221219
}
222220

@@ -275,6 +273,46 @@ func (db *BoltStore) CreateSession(session *Session) error {
275273

276274
return putSession(sessionBucket, session)
277275
})
276+
if err != nil {
277+
return nil, err
278+
}
279+
280+
return session, nil
281+
}
282+
283+
// CreateSession moves the session with the given ID from the Reserved state to
284+
// the Created state.
285+
//
286+
// NOTE: this is part of the Store interface.
287+
func (db *BoltStore) CreateSession(id ID) (*Session, error) {
288+
var session *Session
289+
err := db.Update(func(tx *bbolt.Tx) error {
290+
sessionBucket, err := getBucket(tx, sessionBucketKey)
291+
if err != nil {
292+
return err
293+
}
294+
295+
session, err = getSessionByID(sessionBucket, id)
296+
if err != nil {
297+
return err
298+
}
299+
300+
// The session MUST be in the Reserved state.
301+
if session.State != StateReserved {
302+
return fmt.Errorf("session must be in the Reserved " +
303+
"state for it to move to the Created state")
304+
}
305+
306+
// Move the session to the CreatedState.
307+
session.State = StateCreated
308+
309+
return putSession(sessionBucket, session)
310+
})
311+
if err != nil {
312+
return nil, err
313+
}
314+
315+
return session, nil
278316
}
279317

280318
// UpdateSessionRemotePubKey can be used to add the given remote pub key
@@ -558,53 +596,35 @@ func (db *BoltStore) GetSessionByID(id ID) (*Session, error) {
558596
return session, nil
559597
}
560598

561-
// GetUnusedIDAndKeyPair can be used to generate a new, unused, local private
599+
// getUnusedIDAndKeyPair can be used to generate a new, unused, local private
562600
// key and session ID pair. Care must be taken to ensure that no other thread
563601
// calls this before the returned ID and key pair from this method are either
564602
// used or discarded.
565-
//
566-
// NOTE: this is part of the Store interface.
567-
func (db *BoltStore) GetUnusedIDAndKeyPair() (ID, *btcec.PrivateKey, error) {
568-
var (
569-
id ID
570-
privKey *btcec.PrivateKey
571-
)
572-
err := db.Update(func(tx *bbolt.Tx) error {
573-
sessionBucket, err := getBucket(tx, sessionBucketKey)
574-
if err != nil {
575-
return err
576-
}
577-
578-
idIndexBkt := sessionBucket.Bucket(idIndexKey)
579-
if idIndexBkt == nil {
580-
return ErrDBInitErr
581-
}
603+
func getUnusedIDAndKeyPair(bucket *bbolt.Bucket) (ID, *btcec.PrivateKey,
604+
error) {
582605

583-
// Spin until we find a key with an ID that does not collide
584-
// with any of our existing IDs.
585-
for {
586-
// Generate a new private key and ID pair.
587-
privKey, id, err = NewSessionPrivKeyAndID()
588-
if err != nil {
589-
return err
590-
}
606+
idIndexBkt := bucket.Bucket(idIndexKey)
607+
if idIndexBkt == nil {
608+
return ID{}, nil, ErrDBInitErr
609+
}
591610

592-
// Check that no such ID exits in our id-to-key index.
593-
idBkt := idIndexBkt.Bucket(id[:])
594-
if idBkt != nil {
595-
continue
596-
}
611+
// Spin until we find a key with an ID that does not collide with any of
612+
// our existing IDs.
613+
for {
614+
// Generate a new private key and ID pair.
615+
privKey, id, err := NewSessionPrivKeyAndID()
616+
if err != nil {
617+
return ID{}, nil, err
618+
}
597619

598-
break
620+
// Check that no such ID exits in our id-to-key index.
621+
idBkt := idIndexBkt.Bucket(id[:])
622+
if idBkt != nil {
623+
continue
599624
}
600625

601-
return nil
602-
})
603-
if err != nil {
604-
return id, nil, err
626+
return id, privKey, nil
605627
}
606-
607-
return id, privKey, nil
608628
}
609629

610630
// GetGroupID will return the group ID for the given session ID.

0 commit comments

Comments
 (0)