@@ -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,206 @@ 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+
197+ func unmarshalMig6Session (ctx context.Context , db * sqlcmig6.Queries ,
198+ dbSess sqlcmig6.Session ) (* Session , error ) {
199+
200+ var legacyGroupID ID
201+ if dbSess .GroupID .Valid {
202+ groupID , err := db .GetAliasBySessionID (
203+ ctx , dbSess .GroupID .Int64 ,
204+ )
205+ if err != nil {
206+ return nil , fmt .Errorf ("unable to get legacy group " +
207+ "Alias: %v" , err )
208+ }
209+
210+ legacyGroupID , err = IDFromBytes (groupID )
211+ if err != nil {
212+ return nil , fmt .Errorf ("unable to get legacy Alias: %v" ,
213+ err )
214+ }
215+ }
216+
217+ var acctAlias fn.Option [accounts.AccountID ]
218+ if dbSess .AccountID .Valid {
219+ account , err := db .GetAccount (ctx , dbSess .AccountID .Int64 )
220+ if err != nil {
221+ return nil , fmt .Errorf ("unable to get account: %v" , err )
222+ }
223+
224+ accountAlias , err := accounts .AccountIDFromInt64 (account .Alias )
225+ if err != nil {
226+ return nil , fmt .Errorf ("unable to get account ID: %v" , err )
227+ }
228+ acctAlias = fn .Some (accountAlias )
229+ }
230+
231+ legacyID , err := IDFromBytes (dbSess .Alias )
232+ if err != nil {
233+ return nil , fmt .Errorf ("unable to get legacy Alias: %v" , err )
234+ }
235+
236+ var revokedAt time.Time
237+ if dbSess .RevokedAt .Valid {
238+ revokedAt = dbSess .RevokedAt .Time
239+ }
240+
241+ localPriv , localPub := btcec .PrivKeyFromBytes (dbSess .LocalPrivateKey )
242+
243+ var remotePub * btcec.PublicKey
244+ if len (dbSess .RemotePublicKey ) != 0 {
245+ remotePub , err = btcec .ParsePubKey (dbSess .RemotePublicKey )
246+ if err != nil {
247+ return nil , fmt .Errorf ("unable to parse remote " +
248+ "public key: %v" , err )
249+ }
250+ }
251+
252+ // Get the macaroon permissions if they exist.
253+ perms , err := db .GetSessionMacaroonPermissions (ctx , dbSess .ID )
254+ if err != nil {
255+ return nil , fmt .Errorf ("unable to get macaroon " +
256+ "permissions: %v" , err )
257+ }
258+
259+ // Get the macaroon caveats if they exist.
260+ caveats , err := db .GetSessionMacaroonCaveats (ctx , dbSess .ID )
261+ if err != nil {
262+ return nil , fmt .Errorf ("unable to get macaroon " +
263+ "caveats: %v" , err )
264+ }
265+
266+ var macRecipe * MacaroonRecipe
267+ if perms != nil || caveats != nil {
268+ macRecipe = & MacaroonRecipe {
269+ Permissions : unmarshalMig6MacPerms (perms ),
270+ Caveats : unmarshalMig6MacCaveats (caveats ),
271+ }
272+ }
273+
274+ // Get the feature configs if they exist.
275+ featureConfigs , err := db .GetSessionFeatureConfigs (ctx , dbSess .ID )
276+ if err != nil {
277+ return nil , fmt .Errorf ("unable to get feature configs: %v" , err )
278+ }
279+
280+ var featureCfgs * FeaturesConfig
281+ if featureConfigs != nil {
282+ featureCfgs = unmarshalMig6FeatureConfigs (featureConfigs )
283+ }
284+
285+ // Get the privacy flags if they exist.
286+ privacyFlags , err := db .GetSessionPrivacyFlags (ctx , dbSess .ID )
287+ if err != nil {
288+ return nil , fmt .Errorf ("unable to get privacy flags: %v" , err )
289+ }
290+
291+ var privFlags PrivacyFlags
292+ if privacyFlags != nil {
293+ privFlags = unmarshalMig6PrivacyFlags (privacyFlags )
294+ }
295+
296+ var pairingSecret [mailbox .NumPassphraseEntropyBytes ]byte
297+ copy (pairingSecret [:], dbSess .PairingSecret )
298+
299+ return & Session {
300+ ID : legacyID ,
301+ Label : dbSess .Label ,
302+ State : State (dbSess .State ),
303+ Type : Type (dbSess .Type ),
304+ Expiry : dbSess .Expiry ,
305+ CreatedAt : dbSess .CreatedAt ,
306+ RevokedAt : revokedAt ,
307+ ServerAddr : dbSess .ServerAddress ,
308+ DevServer : dbSess .DevServer ,
309+ MacaroonRootKey : uint64 (dbSess .MacaroonRootKey ),
310+ PairingSecret : pairingSecret ,
311+ LocalPrivateKey : localPriv ,
312+ LocalPublicKey : localPub ,
313+ RemotePublicKey : remotePub ,
314+ WithPrivacyMapper : dbSess .Privacy ,
315+ GroupID : legacyGroupID ,
316+ PrivacyFlags : privFlags ,
317+ MacaroonRecipe : macRecipe ,
318+ FeatureConfig : featureCfgs ,
319+ AccountID : acctAlias ,
320+ }, nil
321+ }
322+
323+ func unmarshalMig6MacPerms (dbPerms []sqlcmig6.SessionMacaroonPermission ) []bakery.Op {
324+ ops := make ([]bakery.Op , len (dbPerms ))
325+ for i , dbPerm := range dbPerms {
326+ ops [i ] = bakery.Op {
327+ Entity : dbPerm .Entity ,
328+ Action : dbPerm .Action ,
329+ }
330+ }
331+
332+ return ops
333+ }
334+
335+ func unmarshalMig6MacCaveats (dbCaveats []sqlcmig6.SessionMacaroonCaveat ) []macaroon.Caveat {
336+ caveats := make ([]macaroon.Caveat , len (dbCaveats ))
337+ for i , dbCaveat := range dbCaveats {
338+ caveats [i ] = macaroon.Caveat {
339+ Id : dbCaveat .CaveatID ,
340+ VerificationId : dbCaveat .VerificationID ,
341+ Location : dbCaveat .Location .String ,
342+ }
343+ }
344+
345+ return caveats
346+ }
347+
348+ func unmarshalMig6FeatureConfigs (dbConfigs []sqlcmig6.SessionFeatureConfig ) * FeaturesConfig {
349+ configs := make (FeaturesConfig , len (dbConfigs ))
350+ for _ , dbConfig := range dbConfigs {
351+ configs [dbConfig .FeatureName ] = dbConfig .Config
352+ }
353+
354+ return & configs
355+ }
356+
357+ func unmarshalMig6PrivacyFlags (dbFlags []sqlcmig6.SessionPrivacyFlag ) PrivacyFlags {
358+ flags := make (PrivacyFlags , len (dbFlags ))
359+ for i , dbFlag := range dbFlags {
360+ flags [i ] = PrivacyFlag (dbFlag .Flag )
361+ }
362+
363+ return flags
364+ }
365+
176366// migrateSingleSessionToSQL runs the migration for a single session from the
177367// KV database to the SQL database. Note that if the session links to an
178368// account, the linked accounts store MUST have been migrated before that
179369// session is migrated.
180370func migrateSingleSessionToSQL (ctx context.Context ,
181- tx SQLQueries , session * Session ) error {
371+ tx * sqlcmig6. Queries , session * Session ) error {
182372
183373 var (
184374 acctID sql.NullInt64
@@ -214,7 +404,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
214404 }
215405
216406 // Proceed to insert the session into the sql db.
217- sqlId , err := tx .InsertSession (ctx , sqlc .InsertSessionParams {
407+ sqlId , err := tx .InsertSession (ctx , sqlcmig6 .InsertSessionParams {
218408 Alias : session .ID [:],
219409 Label : session .Label ,
220410 State : int16 (session .State ),
@@ -240,7 +430,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
240430 // has been created.
241431 if ! session .RevokedAt .IsZero () {
242432 err = tx .SetSessionRevokedAt (
243- ctx , sqlc .SetSessionRevokedAtParams {
433+ ctx , sqlcmig6 .SetSessionRevokedAtParams {
244434 ID : sqlId ,
245435 RevokedAt : sqldb .SQLTime (
246436 session .RevokedAt .UTC (),
@@ -266,7 +456,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
266456 }
267457
268458 // Now lets set the group ID for the session.
269- err = tx .SetSessionGroupID (ctx , sqlc .SetSessionGroupIDParams {
459+ err = tx .SetSessionGroupID (ctx , sqlcmig6 .SetSessionGroupIDParams {
270460 ID : sqlId ,
271461 GroupID : sqldb .SQLInt64 (groupID ),
272462 })
@@ -280,7 +470,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
280470 // We start by inserting the macaroon permissions.
281471 for _ , sessionPerm := range session .MacaroonRecipe .Permissions {
282472 err = tx .InsertSessionMacaroonPermission (
283- ctx , sqlc .InsertSessionMacaroonPermissionParams {
473+ ctx , sqlcmig6 .InsertSessionMacaroonPermissionParams {
284474 SessionID : sqlId ,
285475 Entity : sessionPerm .Entity ,
286476 Action : sessionPerm .Action ,
@@ -294,7 +484,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
294484 // Next we insert the macaroon caveats.
295485 for _ , caveat := range session .MacaroonRecipe .Caveats {
296486 err = tx .InsertSessionMacaroonCaveat (
297- ctx , sqlc .InsertSessionMacaroonCaveatParams {
487+ ctx , sqlcmig6 .InsertSessionMacaroonCaveatParams {
298488 SessionID : sqlId ,
299489 CaveatID : caveat .Id ,
300490 VerificationID : caveat .VerificationId ,
@@ -313,7 +503,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
313503 if session .FeatureConfig != nil {
314504 for featureName , config := range * session .FeatureConfig {
315505 err = tx .InsertSessionFeatureConfig (
316- ctx , sqlc .InsertSessionFeatureConfigParams {
506+ ctx , sqlcmig6 .InsertSessionFeatureConfigParams {
317507 SessionID : sqlId ,
318508 FeatureName : featureName ,
319509 Config : config ,
@@ -328,7 +518,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
328518 // Finally we insert the privacy flags.
329519 for _ , privacyFlag := range session .PrivacyFlags {
330520 err = tx .InsertSessionPrivacyFlag (
331- ctx , sqlc .InsertSessionPrivacyFlagParams {
521+ ctx , sqlcmig6 .InsertSessionPrivacyFlagParams {
332522 SessionID : sqlId ,
333523 Flag : int32 (privacyFlag ),
334524 },
0 commit comments