@@ -10,12 +10,17 @@ import (
1010 "sort"
1111 "time"
1212
13+ "github.com/btcsuite/btcd/btcec/v2"
1314 "github.com/davecgh/go-spew/spew"
15+ "github.com/lightninglabs/lightning-node-connect/mailbox"
1416 "github.com/lightninglabs/lightning-terminal/accounts"
15- "github.com/lightninglabs/lightning-terminal/db/sqlc"
17+ "github.com/lightninglabs/lightning-terminal/db/sqlcmig6"
18+ "github.com/lightningnetwork/lnd/fn"
1619 "github.com/lightningnetwork/lnd/sqldb"
1720 "github.com/pmezard/go-difflib/difflib"
1821 "go.etcd.io/bbolt"
22+ "gopkg.in/macaroon-bakery.v2/bakery"
23+ "gopkg.in/macaroon.v2"
1924)
2025
2126var (
3237// NOTE: As sessions may contain linked accounts, the accounts sql migration
3338// MUST be run prior to this migration.
3439func MigrateSessionStoreToSQL (ctx context.Context , kvStore * bbolt.DB ,
35- tx SQLQueries ) error {
40+ tx * sqlcmig6. Queries ) error {
3641
3742 log .Infof ("Starting migration of the KV sessions store to SQL" )
3843
@@ -119,7 +124,7 @@ func getBBoltSessions(db *bbolt.DB) ([]*Session, error) {
119124// from the KV database to the SQL database, and validates that the migrated
120125// sessions match the original sessions.
121126func migrateSessionsToSQLAndValidate (ctx context.Context ,
122- tx SQLQueries , kvSessions []* Session ) error {
127+ tx * sqlcmig6. Queries , kvSessions []* Session ) error {
123128
124129 for _ , kvSession := range kvSessions {
125130 err := migrateSingleSessionToSQL (ctx , tx , kvSession )
@@ -128,18 +133,9 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
128133 kvSession .ID , err )
129134 }
130135
131- // Validate that the session was correctly migrated and matches
132- // the original session in the kv store.
133- sqlSess , err := tx .GetSessionByAlias (ctx , kvSession .ID [:])
134- if err != nil {
135- if errors .Is (err , sql .ErrNoRows ) {
136- err = ErrSessionNotFound
137- }
138- return fmt .Errorf ("unable to get migrated session " +
139- "from sql store: %w" , err )
140- }
141-
142- migratedSession , err := unmarshalSession (ctx , tx , sqlSess )
136+ migratedSession , err := getAndUnmarshalSession (
137+ ctx , tx , kvSession .ID [:],
138+ )
143139 if err != nil {
144140 return fmt .Errorf ("unable to unmarshal migrated " +
145141 "session: %w" , err )
@@ -173,12 +169,205 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
173169 return nil
174170}
175171
172+ func getAndUnmarshalSession (ctx context.Context ,
173+ tx * sqlcmig6.Queries , legacyID []byte ) (* Session , error ) {
174+
175+ // Validate that the session was correctly migrated and matches
176+ // the original session in the kv store.
177+ sqlSess , err := tx .GetSessionByAlias (ctx , legacyID )
178+ if err != nil {
179+ if errors .Is (err , sql .ErrNoRows ) {
180+ err = ErrSessionNotFound
181+ }
182+
183+ return nil , fmt .Errorf ("unable to get migrated session " +
184+ "from sql store: %w" , err )
185+ }
186+
187+ migratedSession , err := unmarshalMig6Session (ctx , tx , sqlSess )
188+ if err != nil {
189+ return nil , fmt .Errorf ("unable to unmarshal migrated " +
190+ "session: %w" , err )
191+ }
192+
193+ return migratedSession , nil
194+ }
195+
196+ func unmarshalMig6Session (ctx context.Context , db * sqlcmig6.Queries ,
197+ dbSess sqlcmig6.Session ) (* Session , error ) {
198+
199+ var legacyGroupID ID
200+ if dbSess .GroupID .Valid {
201+ groupID , err := db .GetAliasBySessionID (
202+ ctx , dbSess .GroupID .Int64 ,
203+ )
204+ if err != nil {
205+ return nil , fmt .Errorf ("unable to get legacy group " +
206+ "Alias: %v" , err )
207+ }
208+
209+ legacyGroupID , err = IDFromBytes (groupID )
210+ if err != nil {
211+ return nil , fmt .Errorf ("unable to get legacy Alias: %v" ,
212+ err )
213+ }
214+ }
215+
216+ var acctAlias fn.Option [accounts.AccountID ]
217+ if dbSess .AccountID .Valid {
218+ account , err := db .GetAccount (ctx , dbSess .AccountID .Int64 )
219+ if err != nil {
220+ return nil , fmt .Errorf ("unable to get account: %v" , err )
221+ }
222+
223+ accountAlias , err := accounts .AccountIDFromInt64 (account .Alias )
224+ if err != nil {
225+ return nil , fmt .Errorf ("unable to get account ID: %v" , err )
226+ }
227+ acctAlias = fn .Some (accountAlias )
228+ }
229+
230+ legacyID , err := IDFromBytes (dbSess .Alias )
231+ if err != nil {
232+ return nil , fmt .Errorf ("unable to get legacy Alias: %v" , err )
233+ }
234+
235+ var revokedAt time.Time
236+ if dbSess .RevokedAt .Valid {
237+ revokedAt = dbSess .RevokedAt .Time
238+ }
239+
240+ localPriv , localPub := btcec .PrivKeyFromBytes (dbSess .LocalPrivateKey )
241+
242+ var remotePub * btcec.PublicKey
243+ if len (dbSess .RemotePublicKey ) != 0 {
244+ remotePub , err = btcec .ParsePubKey (dbSess .RemotePublicKey )
245+ if err != nil {
246+ return nil , fmt .Errorf ("unable to parse remote " +
247+ "public key: %v" , err )
248+ }
249+ }
250+
251+ // Get the macaroon permissions if they exist.
252+ perms , err := db .GetSessionMacaroonPermissions (ctx , dbSess .ID )
253+ if err != nil {
254+ return nil , fmt .Errorf ("unable to get macaroon " +
255+ "permissions: %v" , err )
256+ }
257+
258+ // Get the macaroon caveats if they exist.
259+ caveats , err := db .GetSessionMacaroonCaveats (ctx , dbSess .ID )
260+ if err != nil {
261+ return nil , fmt .Errorf ("unable to get macaroon " +
262+ "caveats: %v" , err )
263+ }
264+
265+ var macRecipe * MacaroonRecipe
266+ if perms != nil || caveats != nil {
267+ macRecipe = & MacaroonRecipe {
268+ Permissions : unmarshalMig6MacPerms (perms ),
269+ Caveats : unmarshalMig6MacCaveats (caveats ),
270+ }
271+ }
272+
273+ // Get the feature configs if they exist.
274+ featureConfigs , err := db .GetSessionFeatureConfigs (ctx , dbSess .ID )
275+ if err != nil {
276+ return nil , fmt .Errorf ("unable to get feature configs: %v" , err )
277+ }
278+
279+ var featureCfgs * FeaturesConfig
280+ if featureConfigs != nil {
281+ featureCfgs = unmarshalMig6FeatureConfigs (featureConfigs )
282+ }
283+
284+ // Get the privacy flags if they exist.
285+ privacyFlags , err := db .GetSessionPrivacyFlags (ctx , dbSess .ID )
286+ if err != nil {
287+ return nil , fmt .Errorf ("unable to get privacy flags: %v" , err )
288+ }
289+
290+ var privFlags PrivacyFlags
291+ if privacyFlags != nil {
292+ privFlags = unmarshalMig6PrivacyFlags (privacyFlags )
293+ }
294+
295+ var pairingSecret [mailbox .NumPassphraseEntropyBytes ]byte
296+ copy (pairingSecret [:], dbSess .PairingSecret )
297+
298+ return & Session {
299+ ID : legacyID ,
300+ Label : dbSess .Label ,
301+ State : State (dbSess .State ),
302+ Type : Type (dbSess .Type ),
303+ Expiry : dbSess .Expiry ,
304+ CreatedAt : dbSess .CreatedAt ,
305+ RevokedAt : revokedAt ,
306+ ServerAddr : dbSess .ServerAddress ,
307+ DevServer : dbSess .DevServer ,
308+ MacaroonRootKey : uint64 (dbSess .MacaroonRootKey ),
309+ PairingSecret : pairingSecret ,
310+ LocalPrivateKey : localPriv ,
311+ LocalPublicKey : localPub ,
312+ RemotePublicKey : remotePub ,
313+ WithPrivacyMapper : dbSess .Privacy ,
314+ GroupID : legacyGroupID ,
315+ PrivacyFlags : privFlags ,
316+ MacaroonRecipe : macRecipe ,
317+ FeatureConfig : featureCfgs ,
318+ AccountID : acctAlias ,
319+ }, nil
320+ }
321+
322+ func unmarshalMig6MacPerms (dbPerms []sqlcmig6.SessionMacaroonPermission ) []bakery.Op {
323+ ops := make ([]bakery.Op , len (dbPerms ))
324+ for i , dbPerm := range dbPerms {
325+ ops [i ] = bakery.Op {
326+ Entity : dbPerm .Entity ,
327+ Action : dbPerm .Action ,
328+ }
329+ }
330+
331+ return ops
332+ }
333+
334+ func unmarshalMig6MacCaveats (dbCaveats []sqlcmig6.SessionMacaroonCaveat ) []macaroon.Caveat {
335+ caveats := make ([]macaroon.Caveat , len (dbCaveats ))
336+ for i , dbCaveat := range dbCaveats {
337+ caveats [i ] = macaroon.Caveat {
338+ Id : dbCaveat .CaveatID ,
339+ VerificationId : dbCaveat .VerificationID ,
340+ Location : dbCaveat .Location .String ,
341+ }
342+ }
343+
344+ return caveats
345+ }
346+
347+ func unmarshalMig6FeatureConfigs (dbConfigs []sqlcmig6.SessionFeatureConfig ) * FeaturesConfig {
348+ configs := make (FeaturesConfig , len (dbConfigs ))
349+ for _ , dbConfig := range dbConfigs {
350+ configs [dbConfig .FeatureName ] = dbConfig .Config
351+ }
352+
353+ return & configs
354+ }
355+
356+ func unmarshalMig6PrivacyFlags (dbFlags []sqlcmig6.SessionPrivacyFlag ) PrivacyFlags {
357+ flags := make (PrivacyFlags , len (dbFlags ))
358+ for i , dbFlag := range dbFlags {
359+ flags [i ] = PrivacyFlag (dbFlag .Flag )
360+ }
361+
362+ return flags
363+ }
364+
176365// migrateSingleSessionToSQL runs the migration for a single session from the
177366// KV database to the SQL database. Note that if the session links to an
178367// account, the linked accounts store MUST have been migrated before that
179368// session is migrated.
180369func migrateSingleSessionToSQL (ctx context.Context ,
181- tx SQLQueries , session * Session ) error {
370+ tx * sqlcmig6. Queries , session * Session ) error {
182371
183372 var (
184373 acctID sql.NullInt64
@@ -214,7 +403,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
214403 }
215404
216405 // Proceed to insert the session into the sql db.
217- sqlId , err := tx .InsertSession (ctx , sqlc .InsertSessionParams {
406+ sqlId , err := tx .InsertSession (ctx , sqlcmig6 .InsertSessionParams {
218407 Alias : session .ID [:],
219408 Label : session .Label ,
220409 State : int16 (session .State ),
@@ -240,7 +429,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
240429 // has been created.
241430 if ! session .RevokedAt .IsZero () {
242431 err = tx .SetSessionRevokedAt (
243- ctx , sqlc .SetSessionRevokedAtParams {
432+ ctx , sqlcmig6 .SetSessionRevokedAtParams {
244433 ID : sqlId ,
245434 RevokedAt : sqldb .SQLTime (
246435 session .RevokedAt .UTC (),
@@ -266,7 +455,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
266455 }
267456
268457 // Now lets set the group ID for the session.
269- err = tx .SetSessionGroupID (ctx , sqlc .SetSessionGroupIDParams {
458+ err = tx .SetSessionGroupID (ctx , sqlcmig6 .SetSessionGroupIDParams {
270459 ID : sqlId ,
271460 GroupID : sqldb .SQLInt64 (groupID ),
272461 })
@@ -280,7 +469,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
280469 // We start by inserting the macaroon permissions.
281470 for _ , sessionPerm := range session .MacaroonRecipe .Permissions {
282471 err = tx .InsertSessionMacaroonPermission (
283- ctx , sqlc .InsertSessionMacaroonPermissionParams {
472+ ctx , sqlcmig6 .InsertSessionMacaroonPermissionParams {
284473 SessionID : sqlId ,
285474 Entity : sessionPerm .Entity ,
286475 Action : sessionPerm .Action ,
@@ -294,7 +483,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
294483 // Next we insert the macaroon caveats.
295484 for _ , caveat := range session .MacaroonRecipe .Caveats {
296485 err = tx .InsertSessionMacaroonCaveat (
297- ctx , sqlc .InsertSessionMacaroonCaveatParams {
486+ ctx , sqlcmig6 .InsertSessionMacaroonCaveatParams {
298487 SessionID : sqlId ,
299488 CaveatID : caveat .Id ,
300489 VerificationID : caveat .VerificationId ,
@@ -313,7 +502,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
313502 if session .FeatureConfig != nil {
314503 for featureName , config := range * session .FeatureConfig {
315504 err = tx .InsertSessionFeatureConfig (
316- ctx , sqlc .InsertSessionFeatureConfigParams {
505+ ctx , sqlcmig6 .InsertSessionFeatureConfigParams {
317506 SessionID : sqlId ,
318507 FeatureName : featureName ,
319508 Config : config ,
@@ -328,7 +517,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
328517 // Finally we insert the privacy flags.
329518 for _ , privacyFlag := range session .PrivacyFlags {
330519 err = tx .InsertSessionPrivacyFlag (
331- ctx , sqlc .InsertSessionPrivacyFlagParams {
520+ ctx , sqlcmig6 .InsertSessionPrivacyFlagParams {
332521 SessionID : sqlId ,
333522 Flag : int32 (privacyFlag ),
334523 },
0 commit comments