@@ -9,12 +9,17 @@ import (
99 "reflect"
1010 "time"
1111
12+ "github.com/btcsuite/btcd/btcec/v2"
1213 "github.com/davecgh/go-spew/spew"
14+ "github.com/lightninglabs/lightning-node-connect/mailbox"
1315 "github.com/lightninglabs/lightning-terminal/accounts"
14- "github.com/lightninglabs/lightning-terminal/db/sqlc"
16+ "github.com/lightninglabs/lightning-terminal/db/sqlcmig6"
17+ "github.com/lightningnetwork/lnd/fn"
1518 "github.com/lightningnetwork/lnd/sqldb"
1619 "github.com/pmezard/go-difflib/difflib"
1720 "go.etcd.io/bbolt"
21+ "gopkg.in/macaroon-bakery.v2/bakery"
22+ "gopkg.in/macaroon.v2"
1823)
1924
2025var (
3136// NOTE: As sessions may contain linked accounts, the accounts sql migration
3237// MUST be run prior to this migration.
3338func MigrateSessionStoreToSQL (ctx context.Context , kvStore * bbolt.DB ,
34- tx SQLQueries ) error {
39+ tx SQLMig6Queries ) error {
3540
3641 log .Infof ("Starting migration of the KV sessions store to SQL" )
3742
@@ -118,7 +123,7 @@ func getBBoltSessions(db *bbolt.DB) ([]*Session, error) {
118123// from the KV database to the SQL database, and validates that the migrated
119124// sessions match the original sessions.
120125func migrateSessionsToSQLAndValidate (ctx context.Context ,
121- tx SQLQueries , kvSessions []* Session ) error {
126+ tx SQLMig6Queries , kvSessions []* Session ) error {
122127
123128 for _ , kvSession := range kvSessions {
124129 err := migrateSingleSessionToSQL (ctx , tx , kvSession )
@@ -127,18 +132,9 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
127132 kvSession .ID , err )
128133 }
129134
130- // Validate that the session was correctly migrated and matches
131- // the original session in the kv store.
132- sqlSess , err := tx .GetSessionByAlias (ctx , kvSession .ID [:])
133- if err != nil {
134- if errors .Is (err , sql .ErrNoRows ) {
135- err = ErrSessionNotFound
136- }
137- return fmt .Errorf ("unable to get migrated session " +
138- "from sql store: %w" , err )
139- }
140-
141- migratedSession , err := unmarshalSession (ctx , tx , sqlSess )
135+ migratedSession , err := getAndUnmarshalSession (
136+ ctx , tx , kvSession .ID [:],
137+ )
142138 if err != nil {
143139 return fmt .Errorf ("unable to unmarshal migrated " +
144140 "session: %w" , err )
@@ -172,12 +168,206 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
172168 return nil
173169}
174170
171+ func getAndUnmarshalSession (ctx context.Context ,
172+ tx SQLMig6Queries , legacyID []byte ) (* Session , error ) {
173+
174+ // Validate that the session was correctly migrated and matches
175+ // the original session in the kv store.
176+ sqlSess , err := tx .GetSessionByAlias (ctx , legacyID )
177+ if err != nil {
178+ if errors .Is (err , sql .ErrNoRows ) {
179+ err = ErrSessionNotFound
180+ }
181+
182+ return nil , fmt .Errorf ("unable to get migrated session " +
183+ "from sql store: %w" , err )
184+ }
185+
186+ migratedSession , err := unmarshalMig6Session (ctx , tx , sqlSess )
187+ if err != nil {
188+ return nil , fmt .Errorf ("unable to unmarshal migrated " +
189+ "session: %w" , err )
190+ }
191+
192+ return migratedSession , nil
193+
194+ }
195+
196+ func unmarshalMig6Session (ctx context.Context , db SQLMig6Queries ,
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+
175365// migrateSingleSessionToSQL runs the migration for a single session from the
176366// KV database to the SQL database. Note that if the session links to an
177367// account, the linked accounts store MUST have been migrated before that
178368// session is migrated.
179369func migrateSingleSessionToSQL (ctx context.Context ,
180- tx SQLQueries , session * Session ) error {
370+ tx SQLMig6Queries , session * Session ) error {
181371
182372 var (
183373 acctID sql.NullInt64
@@ -213,7 +403,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
213403 }
214404
215405 // Proceed to insert the session into the sql db.
216- sqlId , err := tx .InsertSession (ctx , sqlc .InsertSessionParams {
406+ sqlId , err := tx .InsertSession (ctx , sqlcmig6 .InsertSessionParams {
217407 Alias : session .ID [:],
218408 Label : session .Label ,
219409 State : int16 (session .State ),
@@ -239,7 +429,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
239429 // has been created.
240430 if ! session .RevokedAt .IsZero () {
241431 err = tx .SetSessionRevokedAt (
242- ctx , sqlc .SetSessionRevokedAtParams {
432+ ctx , sqlcmig6 .SetSessionRevokedAtParams {
243433 ID : sqlId ,
244434 RevokedAt : sqldb .SQLTime (
245435 session .RevokedAt .UTC (),
@@ -265,7 +455,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
265455 }
266456
267457 // Now lets set the group ID for the session.
268- err = tx .SetSessionGroupID (ctx , sqlc .SetSessionGroupIDParams {
458+ err = tx .SetSessionGroupID (ctx , sqlcmig6 .SetSessionGroupIDParams {
269459 ID : sqlId ,
270460 GroupID : sqldb .SQLInt64 (groupID ),
271461 })
@@ -279,7 +469,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
279469 // We start by inserting the macaroon permissions.
280470 for _ , sessionPerm := range session .MacaroonRecipe .Permissions {
281471 err = tx .InsertSessionMacaroonPermission (
282- ctx , sqlc .InsertSessionMacaroonPermissionParams {
472+ ctx , sqlcmig6 .InsertSessionMacaroonPermissionParams {
283473 SessionID : sqlId ,
284474 Entity : sessionPerm .Entity ,
285475 Action : sessionPerm .Action ,
@@ -293,7 +483,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
293483 // Next we insert the macaroon caveats.
294484 for _ , caveat := range session .MacaroonRecipe .Caveats {
295485 err = tx .InsertSessionMacaroonCaveat (
296- ctx , sqlc .InsertSessionMacaroonCaveatParams {
486+ ctx , sqlcmig6 .InsertSessionMacaroonCaveatParams {
297487 SessionID : sqlId ,
298488 CaveatID : caveat .Id ,
299489 VerificationID : caveat .VerificationId ,
@@ -312,7 +502,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
312502 if session .FeatureConfig != nil {
313503 for featureName , config := range * session .FeatureConfig {
314504 err = tx .InsertSessionFeatureConfig (
315- ctx , sqlc .InsertSessionFeatureConfigParams {
505+ ctx , sqlcmig6 .InsertSessionFeatureConfigParams {
316506 SessionID : sqlId ,
317507 FeatureName : featureName ,
318508 Config : config ,
@@ -327,7 +517,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
327517 // Finally we insert the privacy flags.
328518 for _ , privacyFlag := range session .PrivacyFlags {
329519 err = tx .InsertSessionPrivacyFlag (
330- ctx , sqlc .InsertSessionPrivacyFlagParams {
520+ ctx , sqlcmig6 .InsertSessionPrivacyFlagParams {
331521 SessionID : sqlId ,
332522 Flag : int32 (privacyFlag ),
333523 },
0 commit comments