mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
multi: persist full mac root key in sql actions db
When migrating the actions store from kvdb to sql, we will update the existing actions to include the full mac root key, instead of just the last 4 bytes (currently called `MacaroonIdentifier`). In order to do so, we change the sql implementation of the `actions` store to persist the full mac root key, instead of just the last 4 bytes. As no production data in the sql actions store exists for users yet, it's fine for us to change this without having to address old sql actions which only stored the last 4 bytes. Note though that since old actions stored in the kvdb implementation only have the last 4 bytes of the mac root key persisted, we will only ever persist the last 4 byte of the mac root key ID for kvdb actions. When the actions are later read back from the kvdb store, the first 4 bytes of the mac root key ID will be padded with zeroes to make up the full 8 bytes. As no call site currently utilizes the full 8 bytes of the mac root key ID, this is okay for now. When we later deprecate and remove the kvdb implementation, we can then update the rest of `litd` to also use the full mac root key ID.
This commit is contained in:
parent
580ce701a2
commit
651cc678fc
6 changed files with 84 additions and 8 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/firewalldb"
|
||||
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
|
|
@ -182,14 +183,25 @@ func (r *RequestLogger) Intercept(ctx context.Context,
|
|||
func (r *RequestLogger) addNewAction(ctx context.Context, ri *RequestInfo,
|
||||
withPayloadData bool) error {
|
||||
|
||||
var macaroonID fn.Option[[4]byte]
|
||||
var (
|
||||
rootKeyID fn.Option[uint64]
|
||||
macaroonID fn.Option[[4]byte]
|
||||
)
|
||||
|
||||
if ri.Macaroon != nil {
|
||||
var err error
|
||||
macID, err := session.IDFromMacaroon(ri.Macaroon)
|
||||
|
||||
fullRootKeyID, err := litmac.RootKeyIDFromMacaroon(
|
||||
ri.Macaroon,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not extract ID from macaroon")
|
||||
return fmt.Errorf("could not extract root key ID from "+
|
||||
"macaroon: %w", err)
|
||||
}
|
||||
|
||||
macID := session.IDFromMacRootKeyID(fullRootKeyID)
|
||||
|
||||
rootKeyID = fn.Some(fullRootKeyID)
|
||||
macaroonID = fn.Some([4]byte(macID))
|
||||
}
|
||||
|
||||
|
|
@ -197,6 +209,7 @@ func (r *RequestLogger) addNewAction(ctx context.Context, ri *RequestInfo,
|
|||
SessionID: ri.SessionID,
|
||||
AccountID: ri.AccountID,
|
||||
MacaroonIdentifier: macaroonID,
|
||||
MacaroonRootKeyID: rootKeyID,
|
||||
RPCMethod: ri.URI,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ type AddActionReq struct {
|
|||
// If no macaroon was used for the action, then this will not be set.
|
||||
MacaroonIdentifier fn.Option[[4]byte]
|
||||
|
||||
// MacaroonRootKeyID is the uint64 / full 8 bytes of the root key ID of
|
||||
// the macaroon used to perform the action.
|
||||
// If no macaroon was used for the action, then this will not be set.
|
||||
//
|
||||
// NOTE: for our BoltDB impl, only the lower 32 bits / last 4 bytes of
|
||||
// this uint64 are stored. When read back, the upper 32 bits / first 4
|
||||
// bytes are zeroed.
|
||||
MacaroonRootKeyID fn.Option[uint64]
|
||||
|
||||
// SessionID holds the optional session ID of the session that this
|
||||
// action was performed with.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -596,7 +596,13 @@ func DeserializeAction(r io.Reader, sessionID session.ID) (*Action, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Since the kvdb only persists 4 bytes for the macaroon root key ID, we
|
||||
// first cast it to a uint32, and then to a uint64, effectively padding
|
||||
// the first 4 bytes with zeroes.
|
||||
rootKeyID := uint64(binary.BigEndian.Uint32(sessionID[:]))
|
||||
|
||||
action.MacaroonIdentifier = fn.Some([4]byte(sessionID))
|
||||
action.MacaroonRootKeyID = fn.Some(rootKeyID)
|
||||
action.SessionID = fn.Some(sessionID)
|
||||
action.ActorName = string(actor)
|
||||
action.FeatureName = string(featureName)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package firewalldb
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
|
@ -140,8 +141,11 @@ func (s *SQLDB) AddAction(ctx context.Context,
|
|||
}
|
||||
|
||||
var macID []byte
|
||||
req.MacaroonIdentifier.WhenSome(func(id [4]byte) {
|
||||
macID = id[:]
|
||||
req.MacaroonRootKeyID.WhenSome(func(rootKeyID uint64) {
|
||||
rootKeyBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(rootKeyBytes[:], rootKeyID)
|
||||
|
||||
macID = rootKeyBytes
|
||||
})
|
||||
|
||||
id, err := db.InsertAction(ctx, sqlc.InsertActionParams{
|
||||
|
|
@ -393,14 +397,24 @@ func unmarshalAction(ctx context.Context, db SQLActionQueries,
|
|||
legacyAcctID = fn.Some(acctID)
|
||||
}
|
||||
|
||||
// Note that we export the full 8 byte macaroon root key ID in the sql
|
||||
// actions DB, while the kvdb version persists and exports stored the
|
||||
// last 4 bytes only.
|
||||
var macID fn.Option[[4]byte]
|
||||
if len(dbAction.MacaroonIdentifier) > 0 {
|
||||
macID = fn.Some([4]byte(dbAction.MacaroonIdentifier))
|
||||
var macRootKeyID fn.Option[uint64]
|
||||
if len(dbAction.MacaroonIdentifier) >= 4 {
|
||||
dbMacID := dbAction.MacaroonIdentifier
|
||||
macID = fn.Some([4]byte(dbMacID[len(dbMacID)-4:]))
|
||||
|
||||
if len(dbAction.MacaroonIdentifier) >= 8 {
|
||||
macRootKeyID = fn.Some(binary.BigEndian.Uint64(dbMacID))
|
||||
}
|
||||
}
|
||||
|
||||
return &Action{
|
||||
AddActionReq: AddActionReq{
|
||||
MacaroonIdentifier: macID,
|
||||
MacaroonRootKeyID: macRootKeyID,
|
||||
AccountID: legacyAcctID,
|
||||
SessionID: legacySessID,
|
||||
ActorName: dbAction.ActorName.String,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/accounts"
|
||||
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
|
|
@ -60,10 +61,13 @@ func TestActionStorage(t *testing.T) {
|
|||
acct1, err := accountsDB.NewAccount(ctx, 0, time.Time{}, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
sess1RootKeyID := litmac.NewSuperMacaroonRootKeyID(sess1.ID)
|
||||
|
||||
action1Req := &AddActionReq{
|
||||
SessionID: fn.Some(sess1.ID),
|
||||
AccountID: fn.Some(acct1.ID),
|
||||
MacaroonIdentifier: fn.Some([4]byte(sess1.ID)),
|
||||
MacaroonRootKeyID: fn.Some(sess1RootKeyID),
|
||||
ActorName: "Autopilot",
|
||||
FeatureName: "auto-fees",
|
||||
Trigger: "fee too low",
|
||||
|
|
@ -79,9 +83,12 @@ func TestActionStorage(t *testing.T) {
|
|||
State: ActionStateDone,
|
||||
}
|
||||
|
||||
sess2RootKeyID := litmac.NewSuperMacaroonRootKeyID(sess2.ID)
|
||||
|
||||
action2Req := &AddActionReq{
|
||||
SessionID: fn.Some(sess2.ID),
|
||||
MacaroonIdentifier: fn.Some([4]byte(sess2.ID)),
|
||||
MacaroonRootKeyID: fn.Some(sess2RootKeyID),
|
||||
ActorName: "Autopilot",
|
||||
FeatureName: "rebalancer",
|
||||
Trigger: "channels not balanced",
|
||||
|
|
@ -213,8 +220,11 @@ func TestListActions(t *testing.T) {
|
|||
addAction := func(sessionID [4]byte) {
|
||||
actionIds++
|
||||
|
||||
sessRootKeyID := litmac.NewSuperMacaroonRootKeyID(sessionID)
|
||||
|
||||
actionReq := &AddActionReq{
|
||||
MacaroonIdentifier: fn.Some(sessionID),
|
||||
MacaroonRootKeyID: fn.Some(sessRootKeyID),
|
||||
ActorName: "Autopilot",
|
||||
FeatureName: fmt.Sprintf("%d", actionIds),
|
||||
Trigger: "fee too low",
|
||||
|
|
@ -424,9 +434,12 @@ func TestListGroupActions(t *testing.T) {
|
|||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
sess1RootKeyID := litmac.NewSuperMacaroonRootKeyID(sess1.ID)
|
||||
|
||||
action1Req := &AddActionReq{
|
||||
SessionID: fn.Some(sess1.ID),
|
||||
MacaroonIdentifier: fn.Some([4]byte(sess1.ID)),
|
||||
MacaroonRootKeyID: fn.Some(sess1RootKeyID),
|
||||
ActorName: "Autopilot",
|
||||
FeatureName: "auto-fees",
|
||||
Trigger: "fee too low",
|
||||
|
|
@ -442,9 +455,12 @@ func TestListGroupActions(t *testing.T) {
|
|||
State: ActionStateDone,
|
||||
}
|
||||
|
||||
sess2RootKeyID := litmac.NewSuperMacaroonRootKeyID(sess2.ID)
|
||||
|
||||
action2Req := &AddActionReq{
|
||||
SessionID: fn.Some(sess2.ID),
|
||||
MacaroonIdentifier: fn.Some([4]byte(sess2.ID)),
|
||||
MacaroonRootKeyID: fn.Some(sess2RootKeyID),
|
||||
ActorName: "Autopilot",
|
||||
FeatureName: "rebalancer",
|
||||
Trigger: "channels not balanced",
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
package firewalldb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -59,7 +61,23 @@ func assertEqualActions(t *testing.T, expected, got *Action) {
|
|||
// Accounts are not explicitly linked in our bbolt DB implementation.
|
||||
actualAccountID := got.AccountID
|
||||
got.AccountID = expected.AccountID
|
||||
require.Equal(t, expected, got)
|
||||
|
||||
// As the kvdb implementation only stores the last 4 bytes Macaroon Root
|
||||
// Key ID, we pad it with 4 zero bytes when comparing.
|
||||
expectedMacRootKey := expected.MacaroonRootKeyID
|
||||
|
||||
expectedMacRootKey.WhenSome(func(rootID uint64) {
|
||||
// Remove the 4 byte prefix of the actual Macaroon Root Key ID.
|
||||
sessID := session.IDFromMacRootKeyID(rootID)
|
||||
|
||||
// Recreate the full 8 byte Macaroon Root Key ID (represented as
|
||||
// a uint64) by padding the first 4 bytes with zeroes.
|
||||
expected.MacaroonRootKeyID = fn.Some(
|
||||
uint64(binary.BigEndian.Uint32(sessID[:])),
|
||||
)
|
||||
})
|
||||
|
||||
require.Equal(t, expected, got)
|
||||
got.AccountID = actualAccountID
|
||||
expected.MacaroonRootKeyID = expectedMacRootKey
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue