@@ -11,7 +11,9 @@ import (
11
11
"github.com/lightninglabs/lightning-node-connect/mailbox"
12
12
"github.com/lightninglabs/lightning-terminal/litrpc"
13
13
"github.com/lightninglabs/lightning-terminal/session"
14
+ "github.com/lightningnetwork/lnd/macaroons"
14
15
"google.golang.org/grpc"
16
+ "gopkg.in/macaroon-bakery.v2/bakery"
15
17
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
16
18
"gopkg.in/macaroon.v2"
17
19
)
@@ -123,16 +125,46 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
123
125
return nil , err
124
126
}
125
127
126
- if typ != session .TypeMacaroonAdmin &&
127
- typ != session .TypeMacaroonReadonly {
128
+ var permissions []bakery.Op
129
+ switch typ {
130
+ // For the default session types we use empty caveats and permissions,
131
+ // the macaroons are baked correctly when creating the session.
132
+ case session .TypeMacaroonAdmin , session .TypeMacaroonReadonly :
133
+
134
+ // For the custom macaroon type, we use the custom permissions specified
135
+ // in the request. For the time being, the caveats list will be empty
136
+ // for this type.
137
+ case session .TypeMacaroonCustom :
138
+ if len (req .MacaroonCustomPermissions ) == 0 {
139
+ return nil , fmt .Errorf ("custom macaroon " +
140
+ "permissions must be specified for the " +
141
+ "custom macaroon session type" )
142
+ }
128
143
129
- return nil , fmt .Errorf ("invalid session type, only admin " +
130
- "and readonly macaroon types supported in LiT" )
144
+ for _ , op := range req .MacaroonCustomPermissions {
145
+ if op .Entity == macaroons .PermissionEntityCustomURI {
146
+ _ , ok := s .cfg .permMgr .URIPermissions (op .Action )
147
+ if ! ok {
148
+ return nil , fmt .Errorf ("URI %s is " +
149
+ "unknown to LiT" , op .Action )
150
+ }
151
+ }
152
+
153
+ permissions = append (permissions , bakery.Op {
154
+ Entity : op .Entity ,
155
+ Action : op .Action ,
156
+ })
157
+ }
158
+
159
+ // No other types are currently supported.
160
+ default :
161
+ return nil , fmt .Errorf ("invalid session type, only admin, " +
162
+ "readonly and custom macaroon types supported in LiT" )
131
163
}
132
164
133
165
sess , err := session .NewSession (
134
166
req .Label , typ , expiry , req .MailboxServerAddr , req .DevServer ,
135
- nil , nil ,
167
+ permissions , nil ,
136
168
)
137
169
if err != nil {
138
170
return nil , fmt .Errorf ("error creating new session: %v" , err )
@@ -184,19 +216,29 @@ func (s *sessionRpcServer) resumeSession(sess *session.Session) error {
184
216
return nil
185
217
}
186
218
187
- if sess .Type != session .TypeMacaroonAdmin &&
188
- sess .Type != session .TypeMacaroonReadonly {
219
+ var (
220
+ caveats []macaroon.Caveat
221
+ permissions []bakery.Op
222
+ readOnly = sess .Type == session .TypeMacaroonReadonly
223
+ )
224
+ switch sess .Type {
225
+ // For the default session types we use empty caveats and permissions,
226
+ // the macaroons are baked correctly when creating the session.
227
+ case session .TypeMacaroonAdmin , session .TypeMacaroonReadonly :
228
+ permissions = s .cfg .permMgr .ActivePermissions (readOnly )
229
+
230
+ // For custom session types, we use the caveats and permissions that
231
+ // were persisted on session creation.
232
+ case session .TypeMacaroonCustom :
233
+ permissions = sess .MacaroonRecipe .Permissions
189
234
235
+ // No other types are currently supported.
236
+ default :
190
237
log .Debugf ("Not resuming session %x with type %d" , pubKeyBytes ,
191
238
sess .Type )
192
239
return nil
193
240
}
194
241
195
- var (
196
- caveats []macaroon.Caveat
197
- readOnly = sess .Type == session .TypeMacaroonReadonly
198
- )
199
-
200
242
// Add the session expiry as a macaroon caveat.
201
243
macExpiry := checkers .TimeBeforeCaveat (sess .Expiry )
202
244
caveats = append (caveats , macaroon.Caveat {
@@ -206,7 +248,7 @@ func (s *sessionRpcServer) resumeSession(sess *session.Session) error {
206
248
mac , err := s .cfg .superMacBaker (
207
249
context .Background (), sess .MacaroonRootKey ,
208
250
& session.MacaroonRecipe {
209
- Permissions : s . cfg . permMgr . ActivePermissions ( readOnly ) ,
251
+ Permissions : permissions ,
210
252
Caveats : caveats ,
211
253
},
212
254
)
@@ -380,6 +422,8 @@ func marshalRPCSession(sess *session.Session) (*litrpc.Session, error) {
380
422
return nil , err
381
423
}
382
424
425
+ macRecipe := marshalRPCMacaroonRecipe (sess .MacaroonRecipe )
426
+
383
427
return & litrpc.Session {
384
428
Label : sess .Label ,
385
429
SessionState : rpcState ,
@@ -392,9 +436,38 @@ func marshalRPCSession(sess *session.Session) (*litrpc.Session, error) {
392
436
LocalPublicKey : sess .LocalPublicKey .SerializeCompressed (),
393
437
RemotePublicKey : remotePubKey ,
394
438
CreatedAt : uint64 (sess .CreatedAt .Unix ()),
439
+ MacaroonRecipe : macRecipe ,
395
440
}, nil
396
441
}
397
442
443
+ // marshalRPCMacaroonRecipe converts a macaroon recipe (permissions and caveats)
444
+ // into its RPC counterpart.
445
+ func marshalRPCMacaroonRecipe (
446
+ recipe * session.MacaroonRecipe ) * litrpc.MacaroonRecipe {
447
+
448
+ if recipe == nil {
449
+ return nil
450
+ }
451
+
452
+ perms := make ([]* litrpc.MacaroonPermission , len (recipe .Permissions ))
453
+ for i , op := range recipe .Permissions {
454
+ perms [i ] = & litrpc.MacaroonPermission {
455
+ Entity : op .Entity ,
456
+ Action : op .Action ,
457
+ }
458
+ }
459
+
460
+ caveats := make ([]string , len (recipe .Caveats ))
461
+ for i , cav := range recipe .Caveats {
462
+ caveats [i ] = string (cav .Id )
463
+ }
464
+
465
+ return & litrpc.MacaroonRecipe {
466
+ Permissions : perms ,
467
+ Caveats : caveats ,
468
+ }
469
+ }
470
+
398
471
// marshalRPCState converts a session state to its RPC counterpart.
399
472
func marshalRPCState (state session.State ) (litrpc.SessionState , error ) {
400
473
switch state {
0 commit comments