@@ -9,12 +9,17 @@ import (
9
9
"reflect"
10
10
"time"
11
11
12
+ "github.com/btcsuite/btcd/btcec/v2"
12
13
"github.com/davecgh/go-spew/spew"
14
+ "github.com/lightninglabs/lightning-node-connect/mailbox"
13
15
"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"
15
18
"github.com/lightningnetwork/lnd/sqldb"
16
19
"github.com/pmezard/go-difflib/difflib"
17
20
"go.etcd.io/bbolt"
21
+ "gopkg.in/macaroon-bakery.v2/bakery"
22
+ "gopkg.in/macaroon.v2"
18
23
)
19
24
20
25
var (
31
36
// NOTE: As sessions may contain linked accounts, the accounts sql migration
32
37
// MUST be run prior to this migration.
33
38
func MigrateSessionStoreToSQL (ctx context.Context , kvStore * bbolt.DB ,
34
- tx SQLQueries ) error {
39
+ tx SQLMig6Queries ) error {
35
40
36
41
log .Infof ("Starting migration of the KV sessions store to SQL" )
37
42
@@ -118,7 +123,7 @@ func getBBoltSessions(db *bbolt.DB) ([]*Session, error) {
118
123
// from the KV database to the SQL database, and validates that the migrated
119
124
// sessions match the original sessions.
120
125
func migrateSessionsToSQLAndValidate (ctx context.Context ,
121
- tx SQLQueries , kvSessions []* Session ) error {
126
+ tx SQLMig6Queries , kvSessions []* Session ) error {
122
127
123
128
for _ , kvSession := range kvSessions {
124
129
err := migrateSingleSessionToSQL (ctx , tx , kvSession )
@@ -127,18 +132,9 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
127
132
kvSession .ID , err )
128
133
}
129
134
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
+ )
142
138
if err != nil {
143
139
return fmt .Errorf ("unable to unmarshal migrated " +
144
140
"session: %w" , err )
@@ -172,12 +168,206 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
172
168
return nil
173
169
}
174
170
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
+
175
365
// migrateSingleSessionToSQL runs the migration for a single session from the
176
366
// KV database to the SQL database. Note that if the session links to an
177
367
// account, the linked accounts store MUST have been migrated before that
178
368
// session is migrated.
179
369
func migrateSingleSessionToSQL (ctx context.Context ,
180
- tx SQLQueries , session * Session ) error {
370
+ tx SQLMig6Queries , session * Session ) error {
181
371
182
372
var (
183
373
acctID sql.NullInt64
@@ -213,7 +403,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
213
403
}
214
404
215
405
// 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 {
217
407
Alias : session .ID [:],
218
408
Label : session .Label ,
219
409
State : int16 (session .State ),
@@ -239,7 +429,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
239
429
// has been created.
240
430
if ! session .RevokedAt .IsZero () {
241
431
err = tx .SetSessionRevokedAt (
242
- ctx , sqlc .SetSessionRevokedAtParams {
432
+ ctx , sqlcmig6 .SetSessionRevokedAtParams {
243
433
ID : sqlId ,
244
434
RevokedAt : sqldb .SQLTime (
245
435
session .RevokedAt .UTC (),
@@ -265,7 +455,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
265
455
}
266
456
267
457
// Now lets set the group ID for the session.
268
- err = tx .SetSessionGroupID (ctx , sqlc .SetSessionGroupIDParams {
458
+ err = tx .SetSessionGroupID (ctx , sqlcmig6 .SetSessionGroupIDParams {
269
459
ID : sqlId ,
270
460
GroupID : sqldb .SQLInt64 (groupID ),
271
461
})
@@ -279,7 +469,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
279
469
// We start by inserting the macaroon permissions.
280
470
for _ , sessionPerm := range session .MacaroonRecipe .Permissions {
281
471
err = tx .InsertSessionMacaroonPermission (
282
- ctx , sqlc .InsertSessionMacaroonPermissionParams {
472
+ ctx , sqlcmig6 .InsertSessionMacaroonPermissionParams {
283
473
SessionID : sqlId ,
284
474
Entity : sessionPerm .Entity ,
285
475
Action : sessionPerm .Action ,
@@ -293,7 +483,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
293
483
// Next we insert the macaroon caveats.
294
484
for _ , caveat := range session .MacaroonRecipe .Caveats {
295
485
err = tx .InsertSessionMacaroonCaveat (
296
- ctx , sqlc .InsertSessionMacaroonCaveatParams {
486
+ ctx , sqlcmig6 .InsertSessionMacaroonCaveatParams {
297
487
SessionID : sqlId ,
298
488
CaveatID : caveat .Id ,
299
489
VerificationID : caveat .VerificationId ,
@@ -312,7 +502,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
312
502
if session .FeatureConfig != nil {
313
503
for featureName , config := range * session .FeatureConfig {
314
504
err = tx .InsertSessionFeatureConfig (
315
- ctx , sqlc .InsertSessionFeatureConfigParams {
505
+ ctx , sqlcmig6 .InsertSessionFeatureConfigParams {
316
506
SessionID : sqlId ,
317
507
FeatureName : featureName ,
318
508
Config : config ,
@@ -327,7 +517,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
327
517
// Finally we insert the privacy flags.
328
518
for _ , privacyFlag := range session .PrivacyFlags {
329
519
err = tx .InsertSessionPrivacyFlag (
330
- ctx , sqlc .InsertSessionPrivacyFlagParams {
520
+ ctx , sqlcmig6 .InsertSessionPrivacyFlagParams {
331
521
SessionID : sqlId ,
332
522
Flag : int32 (privacyFlag ),
333
523
},
0 commit comments