lightning-terminal/db/sqlcmig6/models.go
Viktor Torstensson b61f62d7d9
multi: preserve macaroon recipe order in SQL
Store explicit positions for session macaroon caveats and permissions
in the SQL schema and read them back in position order. Also remove the
migration-time sorting workaround in session comparison, so migration
validation now checks the actual persisted order instead of masking it.

This is needed because session caveat order is not just presentation
data. LiT adds caveats to the baked macaroon in slice order, and the
macaroon library updates the signature hash chain for each added caveat.
Reordering caveats can therefore change the resulting macaroon bytes and
signature.

The previous schema split caveats and permissions into child tables
without any position column, and the SQL reads had no ORDER BY. The KV
store preserves slice order, but SQL had no explicit way to reproduce
that order after migration or on later reads. The migration code’s old
sorting step was only making validation deterministic; it did not
preserve the original recipe order.

Permissions are canonicalized by lnd when baking, so their order is less
semantically important for the final macaroon. They still get positions
here so the stored recipe remains faithful to the original session data
and both child tables behave consistently.

Why it was needed:

- caveats needed explicit order preservation because they are appended
  and signed in order.
- The old SQL schema did not store order, and the read queries did not
  request one.
- Adding position makes the SQL representation faithful to the KV/TLV
  recipe instead of relying on incidental row order.

- Adding it to permissions too keeps the stored recipe lossless and
  consistent, even though lnd. canonicalizes permissions before baking.

NOTE: This commit explicitly edits the previous migration instead of
adding a new one. This is ok as SQL dbs are not yet supported in
production, so there are no live deployments to worry about.
2026-06-08 17:21:03 +02:00

126 lines
2.2 KiB
Go

package sqlcmig6
import (
"database/sql"
"time"
)
type Account struct {
ID int64
Alias int64
Label sql.NullString
Type int16
InitialBalanceMsat int64
CurrentBalanceMsat int64
LastUpdated time.Time
Expiration time.Time
}
type AccountIndex struct {
Name string
Value int64
}
type AccountInvoice struct {
AccountID int64
Hash []byte
}
type AccountPayment struct {
AccountID int64
Hash []byte
Status int16
FullAmountMsat int64
}
type Action struct {
ID int64
SessionID sql.NullInt64
AccountID sql.NullInt64
MacaroonIdentifier []byte
ActorName sql.NullString
FeatureName sql.NullString
ActionTrigger sql.NullString
Intent sql.NullString
StructuredJsonData []byte
RpcMethod string
RpcParamsJson []byte
CreatedAt time.Time
ActionState int16
ErrorReason sql.NullString
}
type Feature struct {
ID int64
Name string
}
type Kvstore struct {
ID int64
Perm bool
RuleID int64
GroupID sql.NullInt64
FeatureID sql.NullInt64
EntryKey string
Value []byte
}
type PrivacyPair struct {
GroupID int64
RealVal string
PseudoVal string
}
type Rule struct {
ID int64
Name string
}
type Session struct {
ID int64
Alias []byte
Label string
State int16
Type int16
Expiry time.Time
CreatedAt time.Time
RevokedAt sql.NullTime
ServerAddress string
DevServer bool
MacaroonRootKey int64
PairingSecret []byte
LocalPrivateKey []byte
LocalPublicKey []byte
RemotePublicKey []byte
Privacy bool
AccountID sql.NullInt64
GroupID sql.NullInt64
}
type SessionFeatureConfig struct {
SessionID int64
FeatureName string
Config []byte
}
type SessionMacaroonCaveat struct {
ID int64
SessionID int64
CaveatID []byte
VerificationID []byte
Location sql.NullString
Position int64
}
type SessionMacaroonPermission struct {
ID int64
SessionID int64
Entity string
Action string
Position int64
}
type SessionPrivacyFlag struct {
SessionID int64
Flag int32
}