Skip to content

Commit c0e85e0

Browse files
authored
Merge pull request #968 from ellemouton/sql10Sessions2
[sql-10] sessions: decouple super macaroon helpers from `sessions` package
2 parents 290344f + 402373c commit c0e85e0

File tree

11 files changed

+199
-175
lines changed

11 files changed

+199
-175
lines changed

accounts/rpcserver.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
"github.com/btcsuite/btcd/btcutil"
1010
"github.com/lightninglabs/lightning-terminal/litrpc"
11-
"github.com/lightninglabs/lightning-terminal/session"
11+
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
1212
"github.com/lightningnetwork/lnd/lntypes"
1313
"github.com/lightningnetwork/lnd/lnwire"
1414
"github.com/lightningnetwork/lnd/macaroons"
@@ -22,12 +22,12 @@ type RPCServer struct {
2222

2323
service *InterceptorService
2424

25-
superMacBaker session.MacaroonBaker
25+
superMacBaker litmac.Baker
2626
}
2727

2828
// NewRPCServer returns a new RPC server for the given service.
2929
func NewRPCServer(service *InterceptorService,
30-
superMacBaker session.MacaroonBaker) *RPCServer {
30+
superMacBaker litmac.Baker) *RPCServer {
3131

3232
return &RPCServer{
3333
service: service,
@@ -79,19 +79,17 @@ func (s *RPCServer) CreateAccount(ctx context.Context,
7979

8080
var rootKeyIdSuffix [4]byte
8181
copy(rootKeyIdSuffix[:], account.ID[0:4])
82-
macRootKey := session.NewSuperMacaroonRootKeyID(rootKeyIdSuffix)
82+
macRootKey := litmac.NewSuperMacaroonRootKeyID(rootKeyIdSuffix)
8383

8484
accountCaveat := checkers.Condition(
8585
macaroons.CondLndCustom,
8686
fmt.Sprintf("%s %x", CondAccount, account.ID[:]),
8787
)
8888

89-
macHex, err := s.superMacBaker(ctx, macRootKey, &session.MacaroonRecipe{
90-
Permissions: MacaroonPermissions,
91-
Caveats: []macaroon.Caveat{{
92-
Id: []byte(accountCaveat),
93-
}},
94-
})
89+
macHex, err := s.superMacBaker(
90+
ctx, macRootKey, MacaroonPermissions,
91+
[]macaroon.Caveat{{Id: []byte(accountCaveat)}},
92+
)
9593
if err != nil {
9694
return nil, fmt.Errorf("error baking account macaroon: %w", err)
9795
}

cmd/litcli/helpers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"encoding/json"
88
"os"
99

10-
"github.com/lightninglabs/lightning-terminal/session"
10+
"github.com/lightninglabs/lightning-terminal/macaroons"
1111
"github.com/urfave/cli"
1212
)
1313

@@ -66,7 +66,7 @@ func superMacRootKey(ctx *cli.Context) error {
6666
}
6767
}
6868

69-
id := session.NewSuperMacaroonRootKeyID(suffix)
69+
id := macaroons.NewSuperMacaroonRootKeyID(suffix)
7070

7171
printJSON(struct {
7272
RootKeyID uint64 `json:"root_key_id"`
@@ -97,7 +97,7 @@ var isSuperMacaroonCmd = cli.Command{
9797
// isSuperMacaroon checks if the users given macaroon is considered a super
9898
// macaroon.
9999
func isSuperMacaroon(ctx *cli.Context) error {
100-
isSuperMac := session.IsSuperMacaroon(ctx.String("mac"))
100+
isSuperMac := macaroons.IsSuperMacaroon(ctx.String("mac"))
101101

102102
printJSON(struct {
103103
IsSuperMacaroon bool `json:"is_super_macaroon"`

itest/litd_firewall_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/lightninglabs/lightning-terminal/firewall"
2323
"github.com/lightninglabs/lightning-terminal/firewalldb"
2424
"github.com/lightninglabs/lightning-terminal/litrpc"
25+
"github.com/lightninglabs/lightning-terminal/macaroons"
2526
"github.com/lightninglabs/lightning-terminal/rules"
2627
"github.com/lightninglabs/lightning-terminal/session"
2728
"github.com/lightningnetwork/lnd"
@@ -2566,7 +2567,7 @@ func (c *caveatCredentials) GetRequestMetadata(ctx context.Context,
25662567
return metadata, nil
25672568
}
25682569

2569-
mac, err := session.ParseMacaroon(macHex)
2570+
mac, err := macaroons.ParseMacaroon(macHex)
25702571
if err != nil {
25712572
return nil, err
25722573
}

macaroons/macaroons.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package macaroons
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
8+
"github.com/lightningnetwork/lnd/lnrpc"
9+
"google.golang.org/protobuf/proto"
10+
"gopkg.in/macaroon-bakery.v2/bakery"
11+
"gopkg.in/macaroon.v2"
12+
)
13+
14+
// Baker is a function type for baking a super macaroon.
15+
type Baker func(ctx context.Context, rootKeyID uint64,
16+
perms []bakery.Op, caveats []macaroon.Caveat) (string, error)
17+
18+
// RootKeyIDFromMacaroon extracts the root key ID of the passed macaroon.
19+
func RootKeyIDFromMacaroon(mac *macaroon.Macaroon) (uint64, error) {
20+
rawID := mac.Id()
21+
if rawID[0] != byte(bakery.LatestVersion) {
22+
return 0, fmt.Errorf("mac id is not on the latest version")
23+
}
24+
25+
decodedID := &lnrpc.MacaroonId{}
26+
idProto := rawID[1:]
27+
err := proto.Unmarshal(idProto, decodedID)
28+
if err != nil {
29+
return 0, err
30+
}
31+
32+
// The storage ID is a string representation of a 64-bit unsigned
33+
// number.
34+
return strconv.ParseUint(string(decodedID.StorageId), 10, 64)
35+
}

macaroons/super_mac.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package macaroons
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/binary"
7+
"encoding/hex"
8+
"errors"
9+
10+
"github.com/lightningnetwork/lnd/lnrpc"
11+
"gopkg.in/macaroon-bakery.v2/bakery"
12+
"gopkg.in/macaroon.v2"
13+
)
14+
15+
// SuperMacaroonRootKeyPrefix is the prefix we set on a super macaroon's root
16+
// key to clearly mark it as such.
17+
var SuperMacaroonRootKeyPrefix = [4]byte{0xFF, 0xEE, 0xDD, 0xCC}
18+
19+
// SuperMacaroonValidator is a function type for validating a super macaroon.
20+
type SuperMacaroonValidator func(ctx context.Context,
21+
superMacaroon []byte, requiredPermissions []bakery.Op,
22+
fullMethod string) error
23+
24+
// NewSuperMacaroonRootKeyID returns a new macaroon root key ID that has the
25+
// prefix to mark it as a super macaroon root key.
26+
func NewSuperMacaroonRootKeyID(id [4]byte) uint64 {
27+
rootKeyBytes := make([]byte, 8)
28+
copy(rootKeyBytes[:], SuperMacaroonRootKeyPrefix[:])
29+
copy(rootKeyBytes[4:], id[:])
30+
31+
return binary.BigEndian.Uint64(rootKeyBytes)
32+
}
33+
34+
// ParseMacaroon parses a hex encoded macaroon into its native struct.
35+
func ParseMacaroon(macHex string) (*macaroon.Macaroon, error) {
36+
macBytes, err := hex.DecodeString(macHex)
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
mac := &macaroon.Macaroon{}
42+
if err := mac.UnmarshalBinary(macBytes); err != nil {
43+
return nil, err
44+
}
45+
46+
return mac, nil
47+
}
48+
49+
// IsSuperMacaroon returns true if the given hex encoded macaroon is a super
50+
// macaroon baked by LiT which can be identified by its root key ID.
51+
func IsSuperMacaroon(macHex string) bool {
52+
mac, err := ParseMacaroon(macHex)
53+
if err != nil {
54+
return false
55+
}
56+
57+
rootKeyID, err := RootKeyIDFromMacaroon(mac)
58+
if err != nil {
59+
return false
60+
}
61+
62+
return isSuperMacaroonRootKeyID(rootKeyID)
63+
}
64+
65+
// isSuperMacaroonRootKeyID returns true if the given macaroon root key ID (also
66+
// known as storage ID) is a super macaroon, which can be identified by its
67+
// first 4 bytes.
68+
func isSuperMacaroonRootKeyID(rootKeyID uint64) bool {
69+
rootKeyBytes := make([]byte, 8)
70+
binary.BigEndian.PutUint64(rootKeyBytes, rootKeyID)
71+
return bytes.HasPrefix(rootKeyBytes, SuperMacaroonRootKeyPrefix[:])
72+
}
73+
74+
// BakeSuperMacaroon uses the lnd client to bake a macaroon that can include
75+
// permissions for multiple daemons.
76+
func BakeSuperMacaroon(ctx context.Context, lnd lnrpc.LightningClient,
77+
rootKeyID uint64, perms []bakery.Op, caveats []macaroon.Caveat) (string,
78+
error) {
79+
80+
if lnd == nil {
81+
return "", errors.New("lnd not yet connected")
82+
}
83+
84+
req := &lnrpc.BakeMacaroonRequest{
85+
Permissions: make(
86+
[]*lnrpc.MacaroonPermission, len(perms),
87+
),
88+
AllowExternalPermissions: true,
89+
RootKeyId: rootKeyID,
90+
}
91+
for idx, perm := range perms {
92+
req.Permissions[idx] = &lnrpc.MacaroonPermission{
93+
Entity: perm.Entity,
94+
Action: perm.Action,
95+
}
96+
}
97+
98+
res, err := lnd.BakeMacaroon(ctx, req)
99+
if err != nil {
100+
return "", err
101+
}
102+
103+
mac, err := ParseMacaroon(res.Macaroon)
104+
if err != nil {
105+
return "", err
106+
}
107+
108+
for _, caveat := range caveats {
109+
if err := mac.AddFirstPartyCaveat(caveat.Id); err != nil {
110+
return "", err
111+
}
112+
}
113+
114+
macBytes, err := mac.MarshalBinary()
115+
if err != nil {
116+
return "", err
117+
}
118+
119+
return hex.EncodeToString(macBytes), err
120+
}

session/macaroon_test.go renamed to macaroons/super_mac_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package session
1+
package macaroons
22

33
import (
44
"testing"
@@ -25,13 +25,21 @@ var (
2525
"60a6caf"
2626
)
2727

28+
// TestSuperMacaroonRootKeyID tests that adding the super macaroon prefix to
29+
// a root key ID results in a valid super macaroon root key ID.
2830
func TestSuperMacaroonRootKeyID(t *testing.T) {
31+
t.Parallel()
32+
2933
someBytes := [4]byte{02, 03, 44, 88}
3034
rootKeyID := NewSuperMacaroonRootKeyID(someBytes)
3135
require.True(t, isSuperMacaroonRootKeyID(rootKeyID))
3236
require.False(t, isSuperMacaroonRootKeyID(123))
3337
}
3438

39+
// TestIsSuperMacaroon tests that we can correctly identify an example super
40+
// macaroon.
3541
func TestIsSuperMacaroon(t *testing.T) {
42+
t.Parallel()
43+
3644
require.True(t, IsSuperMacaroon(testMacHex))
3745
}

rpc_proxy.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313

1414
"github.com/improbable-eng/grpc-web/go/grpcweb"
1515
"github.com/lightninglabs/lightning-terminal/litrpc"
16+
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
1617
"github.com/lightninglabs/lightning-terminal/perms"
17-
"github.com/lightninglabs/lightning-terminal/session"
1818
litstatus "github.com/lightninglabs/lightning-terminal/status"
1919
"github.com/lightninglabs/lightning-terminal/subservers"
2020
"github.com/lightningnetwork/lnd/lncfg"
@@ -71,7 +71,7 @@ func (e *proxyErr) Unwrap() error {
7171
// or REST request and delegate (and convert if necessary) it to the correct
7272
// component.
7373
func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
74-
superMacValidator session.SuperMacaroonValidator,
74+
superMacValidator litmac.SuperMacaroonValidator,
7575
permsMgr *perms.Manager, subServerMgr *subservers.Manager,
7676
statusMgr *litstatus.Manager, getLNDClient lndBasicClientFn) *rpcProxy {
7777

@@ -176,7 +176,7 @@ type rpcProxy struct {
176176
bakeSuperMac bakeSuperMac
177177

178178
macValidator macaroons.MacaroonValidator
179-
superMacValidator session.SuperMacaroonValidator
179+
superMacValidator litmac.SuperMacaroonValidator
180180

181181
superMacaroon string
182182

@@ -331,7 +331,9 @@ func (p *rpcProxy) makeDirector(allowLitRPC bool) func(ctx context.Context,
331331
))
332332
}
333333

334-
case len(macHeader) == 1 && session.IsSuperMacaroon(macHeader[0]):
334+
case len(macHeader) == 1 &&
335+
litmac.IsSuperMacaroon(macHeader[0]):
336+
335337
// If we have a macaroon, and it's a super macaroon,
336338
// then we need to convert it into the actual daemon
337339
// macaroon if they're running in remote mode.

session/interface.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package session
22

33
import (
4-
"context"
54
"fmt"
65
"time"
76

87
"github.com/btcsuite/btcd/btcec/v2"
98
"github.com/lightninglabs/lightning-node-connect/mailbox"
9+
"github.com/lightninglabs/lightning-terminal/macaroons"
1010
"gopkg.in/macaroon-bakery.v2/bakery"
1111
"gopkg.in/macaroon.v2"
1212
)
@@ -71,10 +71,6 @@ type Session struct {
7171
GroupID ID
7272
}
7373

74-
// MacaroonBaker is a function type for baking a super macaroon.
75-
type MacaroonBaker func(ctx context.Context, rootKeyID uint64,
76-
recipe *MacaroonRecipe) (string, error)
77-
7874
// NewSession creates a new session with the given user-defined parameters.
7975
func NewSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
8076
expiry time.Time, serverAddr string, devServer bool, perms []bakery.Op,
@@ -86,7 +82,7 @@ func NewSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
8682
return nil, fmt.Errorf("error deriving pairing secret: %v", err)
8783
}
8884

89-
macRootKey := NewSuperMacaroonRootKeyID(id)
85+
macRootKey := macaroons.NewSuperMacaroonRootKeyID(id)
9086

9187
// The group ID will by default be the same as the Session ID
9288
// unless this session links to a previous session.

0 commit comments

Comments
 (0)