Skip to content

Commit 3864ebb

Browse files
committed
session_rpcserver: allow sessions with custom permissions
1 parent 1736857 commit 3864ebb

File tree

1 file changed

+86
-13
lines changed

1 file changed

+86
-13
lines changed

session_rpcserver.go

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"github.com/lightninglabs/lightning-node-connect/mailbox"
1212
"github.com/lightninglabs/lightning-terminal/litrpc"
1313
"github.com/lightninglabs/lightning-terminal/session"
14+
"github.com/lightningnetwork/lnd/macaroons"
1415
"google.golang.org/grpc"
16+
"gopkg.in/macaroon-bakery.v2/bakery"
1517
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
1618
"gopkg.in/macaroon.v2"
1719
)
@@ -123,16 +125,46 @@ func (s *sessionRpcServer) AddSession(_ context.Context,
123125
return nil, err
124126
}
125127

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+
}
128143

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")
131163
}
132164

133165
sess, err := session.NewSession(
134166
req.Label, typ, expiry, req.MailboxServerAddr, req.DevServer,
135-
nil, nil,
167+
permissions, nil,
136168
)
137169
if err != nil {
138170
return nil, fmt.Errorf("error creating new session: %v", err)
@@ -184,19 +216,29 @@ func (s *sessionRpcServer) resumeSession(sess *session.Session) error {
184216
return nil
185217
}
186218

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
189234

235+
// No other types are currently supported.
236+
default:
190237
log.Debugf("Not resuming session %x with type %d", pubKeyBytes,
191238
sess.Type)
192239
return nil
193240
}
194241

195-
var (
196-
caveats []macaroon.Caveat
197-
readOnly = sess.Type == session.TypeMacaroonReadonly
198-
)
199-
200242
// Add the session expiry as a macaroon caveat.
201243
macExpiry := checkers.TimeBeforeCaveat(sess.Expiry)
202244
caveats = append(caveats, macaroon.Caveat{
@@ -206,7 +248,7 @@ func (s *sessionRpcServer) resumeSession(sess *session.Session) error {
206248
mac, err := s.cfg.superMacBaker(
207249
context.Background(), sess.MacaroonRootKey,
208250
&session.MacaroonRecipe{
209-
Permissions: s.cfg.permMgr.ActivePermissions(readOnly),
251+
Permissions: permissions,
210252
Caveats: caveats,
211253
},
212254
)
@@ -380,6 +422,8 @@ func marshalRPCSession(sess *session.Session) (*litrpc.Session, error) {
380422
return nil, err
381423
}
382424

425+
macRecipe := marshalRPCMacaroonRecipe(sess.MacaroonRecipe)
426+
383427
return &litrpc.Session{
384428
Label: sess.Label,
385429
SessionState: rpcState,
@@ -392,9 +436,38 @@ func marshalRPCSession(sess *session.Session) (*litrpc.Session, error) {
392436
LocalPublicKey: sess.LocalPublicKey.SerializeCompressed(),
393437
RemotePublicKey: remotePubKey,
394438
CreatedAt: uint64(sess.CreatedAt.Unix()),
439+
MacaroonRecipe: macRecipe,
395440
}, nil
396441
}
397442

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+
398471
// marshalRPCState converts a session state to its RPC counterpart.
399472
func marshalRPCState(state session.State) (litrpc.SessionState, error) {
400473
switch state {

0 commit comments

Comments
 (0)