Skip to content

[sql-15] sessions: various functional options for NewSession #984

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

Merged
merged 2 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 101 additions & 20 deletions session/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,13 @@ type Session struct {

// buildSession creates a new session with the given user-defined parameters.
func buildSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
created, expiry time.Time, serverAddr string, devServer bool,
perms []bakery.Op, caveats []macaroon.Caveat,
featureConfig FeaturesConfig, privacy bool, linkedGroupID *ID,
flags PrivacyFlags) (*Session, error) {
created, expiry time.Time, serverAddr string,
options ...Option) (*Session, error) {

opts := defaultSessionOptions()
for _, o := range options {
o(opts)
}

_, pairingSecret, err := mailbox.NewPassphraseEntropy()
if err != nil {
Expand All @@ -135,10 +138,10 @@ func buildSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
// The group ID will by default be the same as the Session ID
// unless this session links to a previous session.
groupID := id
if linkedGroupID != nil {
if opts.linkedGroupID != nil {
// If this session is linked to a previous session, then the
// group ID is the same as the linked session's group ID.
groupID = *linkedGroupID
groupID = *opts.linkedGroupID
}

sess := &Session{
Expand All @@ -149,29 +152,109 @@ func buildSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
Expiry: expiry.UTC(),
CreatedAt: created.UTC(),
ServerAddr: serverAddr,
DevServer: devServer,
DevServer: opts.devServer,
MacaroonRootKey: macRootKey,
PairingSecret: pairingSecret,
LocalPrivateKey: localPrivKey,
LocalPublicKey: localPrivKey.PubKey(),
RemotePublicKey: nil,
WithPrivacyMapper: privacy,
PrivacyFlags: flags,
WithPrivacyMapper: opts.privacy,
PrivacyFlags: opts.privacyFlags,
GroupID: groupID,
MacaroonRecipe: opts.macaroonRecipe,
}

if perms != nil || caveats != nil {
sess.MacaroonRecipe = &MacaroonRecipe{
Permissions: perms,
Caveats: caveats,
}
if len(opts.featureConfig) != 0 {
sess.FeatureConfig = &opts.featureConfig
}

if len(featureConfig) != 0 {
sess.FeatureConfig = &featureConfig
return sess, nil
}

// sessionOptions defines various options that can be tweaked via functional
// parameters for session creation.
type sessionOptions struct {
// privacy indicates if a privacy map should be used with this session.
privacy bool

// privacyFlags to use in combination with the session's privacy mapper.
privacyFlags PrivacyFlags

// featureConfig holds any feature configuration bytes to use for this
// session.
featureConfig FeaturesConfig

// linkedGroupID is the ID of the group that this session is linked
// to. By default, a session is not linked to another group.
linkedGroupID *ID

// devServer is true if TLS should be skipped when connecting to the
// mailbox server.
devServer bool

// macaroonRecipe holds the permissions and caveats that should be used
// to bake the macaroon to be used with this session.
macaroonRecipe *MacaroonRecipe
}

// defaultSessionOptions returns a new sessionOptions struct with default
// values set.
func defaultSessionOptions() *sessionOptions {
return &sessionOptions{
privacy: false,
privacyFlags: PrivacyFlags{},
featureConfig: FeaturesConfig{},
linkedGroupID: nil,
devServer: false,
}
}

return sess, nil
// Option defines the signature of a functional option that can be used to
// tweak various session creation options.
type Option func(*sessionOptions)

// WithPrivacy can be used to enable the privacy mapper for this session.
// An optional set of privacy flags can be provided to further customize the
// privacy mapper.
func WithPrivacy(flags PrivacyFlags) Option {
return func(o *sessionOptions) {
o.privacy = true
o.privacyFlags = flags
}
}

// WithFeatureConfig can be used to set the feature configuration bytes for
// this session.
func WithFeatureConfig(config FeaturesConfig) Option {
return func(o *sessionOptions) {
o.featureConfig = config
}
}

// WithLinkedGroupID can be used to link this session to a previous session.
func WithLinkedGroupID(groupID *ID) Option {
return func(o *sessionOptions) {
o.linkedGroupID = groupID
}
}

// WithDevServer can be used to set if TLS verification should be skipped when
// connecting to the mailbox server.
func WithDevServer() Option {
return func(o *sessionOptions) {
o.devServer = true
}
}

// WithMacaroonRecipe can be used to set the permissions and caveats that
// should be used to bake the macaroon for a session.
func WithMacaroonRecipe(caveats []macaroon.Caveat, perms []bakery.Op) Option {
return func(o *sessionOptions) {
o.macaroonRecipe = &MacaroonRecipe{
Permissions: perms,
Caveats: caveats,
}
}
}

// IDToGroupIndex defines an interface for the session ID to group ID index.
Expand All @@ -191,9 +274,7 @@ type Store interface {
// parameters. The session will remain in the StateReserved state until
// ShiftState is called to update the state.
NewSession(label string, typ Type, expiry time.Time, serverAddr string,
devServer bool, perms []bakery.Op, caveats []macaroon.Caveat,
featureConfig FeaturesConfig, privacy bool, linkedGroupID *ID,
flags PrivacyFlags) (*Session, error)
opts ...Option) (*Session, error)

// GetSession fetches the session with the given key.
GetSession(key *btcec.PublicKey) (*Session, error)
Expand Down
9 changes: 2 additions & 7 deletions session/kvdb_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/clock"
"go.etcd.io/bbolt"
"gopkg.in/macaroon-bakery.v2/bakery"
"gopkg.in/macaroon.v2"
)

var (
Expand Down Expand Up @@ -188,9 +186,7 @@ func getSessionKey(session *Session) []byte {
//
// NOTE: this is part of the Store interface.
func (db *BoltStore) NewSession(label string, typ Type, expiry time.Time,
serverAddr string, devServer bool, perms []bakery.Op,
caveats []macaroon.Caveat, featureConfig FeaturesConfig, privacy bool,
linkedGroupID *ID, flags PrivacyFlags) (*Session, error) {
serverAddr string, opts ...Option) (*Session, error) {

var session *Session
err := db.Update(func(tx *bbolt.Tx) error {
Expand All @@ -206,8 +202,7 @@ func (db *BoltStore) NewSession(label string, typ Type, expiry time.Time,

session, err = buildSession(
id, localPrivKey, label, typ, db.clock.Now(), expiry,
serverAddr, devServer, perms, caveats, featureConfig,
privacy, linkedGroupID, flags,
serverAddr, opts...,
)
if err != nil {
return err
Expand Down
6 changes: 4 additions & 2 deletions session/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,10 @@ func reserveSession(db Store, label string,

return db.NewSession(label, opts.sessType,
time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC),
"foo.bar.baz:1234", true, nil, nil, nil, true, opts.groupID,
[]PrivacyFlag{ClearPubkeys},
"foo.bar.baz:1234",
WithDevServer(),
WithPrivacy(PrivacyFlags{ClearPubkeys}),
WithLinkedGroupID(opts.groupID),
)
}

Expand Down
23 changes: 13 additions & 10 deletions session/tlv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,12 @@ func TestSerializeDeserializeSession(t *testing.T) {
id, priv, test.name, test.sessType,
time.Now(),
time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC),
"foo.bar.baz:1234", true, test.perms,
test.caveats, test.featureConfig, true,
test.linkedGroupID,
[]PrivacyFlag{ClearPubkeys},
"foo.bar.baz:1234",
WithDevServer(),
WithPrivacy(PrivacyFlags{ClearPubkeys}),
WithMacaroonRecipe(test.caveats, test.perms),
WithFeatureConfig(test.featureConfig),
WithLinkedGroupID(test.linkedGroupID),
)
require.NoError(t, err)

Expand Down Expand Up @@ -188,8 +190,8 @@ func TestGroupIDForOlderSessions(t *testing.T) {
id, priv, "test-session", TypeMacaroonAdmin,
time.Now(),
time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC),
"foo.bar.baz:1234", true, nil, nil, nil, false, nil,
PrivacyFlags{},
"foo.bar.baz:1234",
WithDevServer(),
)
require.NoError(t, err)

Expand Down Expand Up @@ -224,8 +226,8 @@ func TestGroupID(t *testing.T) {
id, priv, "test-session", TypeMacaroonAdmin,
time.Now(),
time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC),
"foo.bar.baz:1234", true, nil, nil, nil, false, nil,
PrivacyFlags{},
"foo.bar.baz:1234",
WithDevServer(),
)
require.NoError(t, err)

Expand All @@ -239,8 +241,9 @@ func TestGroupID(t *testing.T) {
id, priv, "test-session", TypeMacaroonAdmin,
time.Now(),
time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC),
"foo.bar.baz:1234", true, nil, nil, nil, false,
&session1.GroupID, PrivacyFlags{},
"foo.bar.baz:1234",
WithLinkedGroupID(&session1.ID),
WithDevServer(),
)
require.NoError(t, err)

Expand Down
38 changes: 32 additions & 6 deletions session_rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,16 @@ func (s *sessionRpcServer) AddSession(ctx context.Context,
}
}

sessOpts := []session.Option{
session.WithMacaroonRecipe(caveats, uniquePermissions),
}

if req.DevServer {
sessOpts = append(sessOpts, session.WithDevServer())
}

sess, err := s.cfg.db.NewSession(
req.Label, typ, expiry, req.MailboxServerAddr,
req.DevServer, uniquePermissions, caveats, nil, false, nil,
session.PrivacyFlags{},
req.Label, typ, expiry, req.MailboxServerAddr, sessOpts...,
)
if err != nil {
return nil, fmt.Errorf("error creating new session: %v", err)
Expand Down Expand Up @@ -911,6 +917,11 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
// Determine privacy flags to use for session registration.
var privacyFlags session.PrivacyFlags
if req.PrivacyFlagsSet {
if !privacy {
return nil, fmt.Errorf("privacy flags can only be " +
"set when the privacy mapper is enabled")
}

// We apply privacy flags from the session request in order to
// to be able to set flags resulting from non-standard feature
// configurations.
Expand Down Expand Up @@ -1120,10 +1131,25 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
caveats = append(caveats, firewall.MetaPrivacyCaveat)
}

// Construct the functional options that will be used to create the
// session.
sessOpts := []session.Option{
session.WithMacaroonRecipe(caveats, perms),
session.WithFeatureConfig(clientConfig),
session.WithLinkedGroupID(linkedGroupID),
}

if req.DevServer {
sessOpts = append(sessOpts, session.WithDevServer())
}

if privacy {
sessOpts = append(sessOpts, session.WithPrivacy(privacyFlags))
}

sess, err := s.cfg.db.NewSession(
req.Label, session.TypeAutopilot, expiry,
req.MailboxServerAddr, req.DevServer, perms, caveats,
clientConfig, privacy, linkedGroupID, privacyFlags,
req.Label, session.TypeAutopilot, expiry, req.MailboxServerAddr,
sessOpts...,
)
if err != nil {
return nil, fmt.Errorf("error creating new session: %v", err)
Expand Down
Loading