multi: rename Action.SessionID to MacaroonIdentifier

To make it very clear what the data is actually derived from. Then also
add an optional Session.ID. Our bbolt db wont store this real session ID
and will populate it in a best effort manner by casting the persisted
MacaroonIdentifier.
This commit is contained in:
Elle Mouton 2025-05-12 13:59:58 +02:00
parent b60dc29c69
commit 3e963c04b4
No known key found for this signature in database
GPG key ID: D7D916376026F177
5 changed files with 42 additions and 23 deletions

View file

@ -182,19 +182,20 @@ func (r *RequestLogger) addNewAction(ctx context.Context, ri *RequestInfo,
withPayloadData bool) error {
// If no macaroon is provided, then an empty 4-byte array is used as the
// session ID. Otherwise, the macaroon is used to derive a session ID.
var sessionID [4]byte
// macaroon ID. Otherwise, the last 4 bytes of the macaroon's root key
// ID are used.
var macaroonID [4]byte
if ri.Macaroon != nil {
var err error
sessionID, err = session.IDFromMacaroon(ri.Macaroon)
macaroonID, err = session.IDFromMacaroon(ri.Macaroon)
if err != nil {
return fmt.Errorf("could not extract ID from macaroon")
}
}
actionReq := &firewalldb.AddActionReq{
SessionID: sessionID,
RPCMethod: ri.URI,
MacaroonIdentifier: macaroonID,
RPCMethod: ri.URI,
}
if withPayloadData {

View file

@ -5,6 +5,7 @@ import (
"time"
"github.com/lightninglabs/lightning-terminal/session"
"github.com/lightningnetwork/lnd/fn"
)
// ActionState represents the state of an action.
@ -32,10 +33,17 @@ const (
// It contains all the information that is needed to create a new Action in the
// ActionStateInit State.
type AddActionReq struct {
// SessionID is the ID of the session that this action belongs to.
// Note that this is not serialized on persistence since the action is
// already stored under a bucket identified by the session ID.
SessionID session.ID
// MacaroonIdentifier is a 4 byte identifier created from the last 4
// bytes of the root key ID of the macaroon used to perform the action.
MacaroonIdentifier [4]byte
// SessionID holds the optional session ID of the session that this
// action was performed with.
//
// NOTE: for our BoltDB impl, this is not persisted in any way, and we
// populate it by casting the macaroon ID to a session.ID and so is not
// guaranteed to be linked to an existing session.
SessionID fn.Option[session.ID]
// ActorName is the name of the entity who performed the Action.
ActorName string

View file

@ -10,6 +10,7 @@ import (
"time"
"github.com/lightninglabs/lightning-terminal/session"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/tlv"
"go.etcd.io/bbolt"
)
@ -80,7 +81,7 @@ func (db *BoltDB) AddAction(_ context.Context,
}
sessBucket, err := actionsBucket.CreateBucketIfNotExists(
action.SessionID[:],
action.MacaroonIdentifier[:],
)
if err != nil {
return err
@ -109,7 +110,7 @@ func (db *BoltDB) AddAction(_ context.Context,
}
locator = kvdbActionLocator{
sessionID: action.SessionID,
sessionID: action.MacaroonIdentifier,
actionID: nextActionIndex,
}
@ -549,7 +550,8 @@ func DeserializeAction(r io.Reader, sessionID session.ID) (*Action, error) {
return nil, err
}
action.SessionID = sessionID
action.MacaroonIdentifier = sessionID
action.SessionID = fn.Some(sessionID)
action.ActorName = string(actor)
action.FeatureName = string(featureName)
action.Trigger = string(trigger)

View file

@ -7,6 +7,7 @@ import (
"time"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/fn"
"github.com/stretchr/testify/require"
)
@ -18,7 +19,8 @@ var (
sessionID2 = intToSessionID(2)
action1Req = &AddActionReq{
SessionID: sessionID1,
SessionID: fn.Some(sessionID1),
MacaroonIdentifier: sessionID1,
ActorName: "Autopilot",
FeatureName: "auto-fees",
Trigger: "fee too low",
@ -35,13 +37,14 @@ var (
}
action2Req = &AddActionReq{
SessionID: sessionID2,
ActorName: "Autopilot",
FeatureName: "rebalancer",
Trigger: "channels not balanced",
Intent: "balance",
RPCMethod: "SendToRoute",
RPCParamsJson: []byte("hops, amount"),
SessionID: fn.Some(sessionID2),
MacaroonIdentifier: sessionID2,
ActorName: "Autopilot",
FeatureName: "rebalancer",
Trigger: "channels not balanced",
Intent: "balance",
RPCMethod: "SendToRoute",
RPCParamsJson: []byte("hops, amount"),
}
action2 = &Action{
@ -171,7 +174,7 @@ func TestListActions(t *testing.T) {
actionIds++
actionReq := &AddActionReq{
SessionID: sessionID,
MacaroonIdentifier: sessionID,
ActorName: "Autopilot",
FeatureName: fmt.Sprintf("%d", actionIds),
Trigger: "fee too low",
@ -194,7 +197,7 @@ func TestListActions(t *testing.T) {
require.Len(t, dbActions, len(al))
for i, a := range al {
require.EqualValues(
t, a.sessionID, dbActions[i].SessionID,
t, a.sessionID, dbActions[i].MacaroonIdentifier,
)
require.Equal(t, a.actionID, dbActions[i].FeatureName)
}

View file

@ -731,8 +731,13 @@ func (s *sessionRpcServer) ListActions(ctx context.Context,
return nil, err
}
var sessionID session.ID
a.SessionID.WhenSome(func(id session.ID) {
sessionID = id
})
resp[i] = &litrpc.Action{
SessionId: a.SessionID[:],
SessionId: sessionID[:],
ActorName: a.ActorName,
FeatureName: a.FeatureName,
Trigger: a.Trigger,