mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
multi: move macaroon helpers to macaroons dir
... and out of the `sessions` directory. This is to avoid import cycles when we start explicitly linking accounts to sessions.
This commit is contained in:
parent
df0e86781d
commit
949c0bf7e2
10 changed files with 131 additions and 102 deletions
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/lightninglabs/lightning-terminal/litrpc"
|
||||
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
|
|
@ -79,7 +80,7 @@ func (s *RPCServer) CreateAccount(ctx context.Context,
|
|||
|
||||
var rootKeyIdSuffix [4]byte
|
||||
copy(rootKeyIdSuffix[:], account.ID[0:4])
|
||||
macRootKey := session.NewSuperMacaroonRootKeyID(rootKeyIdSuffix)
|
||||
macRootKey := litmac.NewSuperMacaroonRootKeyID(rootKeyIdSuffix)
|
||||
|
||||
accountCaveat := checkers.Condition(
|
||||
macaroons.CondLndCustom,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ func superMacRootKey(ctx *cli.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
id := session.NewSuperMacaroonRootKeyID(suffix)
|
||||
id := macaroons.NewSuperMacaroonRootKeyID(suffix)
|
||||
|
||||
printJSON(struct {
|
||||
RootKeyID uint64 `json:"root_key_id"`
|
||||
|
|
@ -97,7 +97,7 @@ var isSuperMacaroonCmd = cli.Command{
|
|||
// isSuperMacaroon checks if the users given macaroon is considered a super
|
||||
// macaroon.
|
||||
func isSuperMacaroon(ctx *cli.Context) error {
|
||||
isSuperMac := session.IsSuperMacaroon(ctx.String("mac"))
|
||||
isSuperMac := macaroons.IsSuperMacaroon(ctx.String("mac"))
|
||||
|
||||
printJSON(struct {
|
||||
IsSuperMacaroon bool `json:"is_super_macaroon"`
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/lightninglabs/lightning-terminal/firewall"
|
||||
"github.com/lightninglabs/lightning-terminal/firewalldb"
|
||||
"github.com/lightninglabs/lightning-terminal/litrpc"
|
||||
"github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"github.com/lightninglabs/lightning-terminal/rules"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd"
|
||||
|
|
@ -2566,7 +2567,7 @@ func (c *caveatCredentials) GetRequestMetadata(ctx context.Context,
|
|||
return metadata, nil
|
||||
}
|
||||
|
||||
mac, err := session.ParseMacaroon(macHex)
|
||||
mac, err := macaroons.ParseMacaroon(macHex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
30
macaroons/macaroons.go
Normal file
30
macaroons/macaroons.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package macaroons
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
"gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
||||
// RootKeyIDFromMacaroon extracts the root key ID of the passed macaroon.
|
||||
func RootKeyIDFromMacaroon(mac *macaroon.Macaroon) (uint64, error) {
|
||||
rawID := mac.Id()
|
||||
if rawID[0] != byte(bakery.LatestVersion) {
|
||||
return 0, fmt.Errorf("mac id is not on the latest version")
|
||||
}
|
||||
|
||||
decodedID := &lnrpc.MacaroonId{}
|
||||
idProto := rawID[1:]
|
||||
err := proto.Unmarshal(idProto, decodedID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// The storage ID is a string representation of a 64-bit unsigned
|
||||
// number.
|
||||
return strconv.ParseUint(string(decodedID.StorageId), 10, 64)
|
||||
}
|
||||
70
macaroons/super_mac.go
Normal file
70
macaroons/super_mac.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package macaroons
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
"gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
||||
// SuperMacaroonRootKeyPrefix is the prefix we set on a super macaroon's root
|
||||
// key to clearly mark it as such.
|
||||
var SuperMacaroonRootKeyPrefix = [4]byte{0xFF, 0xEE, 0xDD, 0xCC}
|
||||
|
||||
// SuperMacaroonValidator is a function type for validating a super macaroon.
|
||||
type SuperMacaroonValidator func(ctx context.Context,
|
||||
superMacaroon []byte, requiredPermissions []bakery.Op,
|
||||
fullMethod string) error
|
||||
|
||||
// NewSuperMacaroonRootKeyID returns a new macaroon root key ID that has the
|
||||
// prefix to mark it as a super macaroon root key.
|
||||
func NewSuperMacaroonRootKeyID(id [4]byte) uint64 {
|
||||
rootKeyBytes := make([]byte, 8)
|
||||
copy(rootKeyBytes[:], SuperMacaroonRootKeyPrefix[:])
|
||||
copy(rootKeyBytes[4:], id[:])
|
||||
|
||||
return binary.BigEndian.Uint64(rootKeyBytes)
|
||||
}
|
||||
|
||||
// ParseMacaroon parses a hex encoded macaroon into its native struct.
|
||||
func ParseMacaroon(macHex string) (*macaroon.Macaroon, error) {
|
||||
macBytes, err := hex.DecodeString(macHex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mac := &macaroon.Macaroon{}
|
||||
if err := mac.UnmarshalBinary(macBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mac, nil
|
||||
}
|
||||
|
||||
// IsSuperMacaroon returns true if the given hex encoded macaroon is a super
|
||||
// macaroon baked by LiT which can be identified by its root key ID.
|
||||
func IsSuperMacaroon(macHex string) bool {
|
||||
mac, err := ParseMacaroon(macHex)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
rootKeyID, err := RootKeyIDFromMacaroon(mac)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return isSuperMacaroonRootKeyID(rootKeyID)
|
||||
}
|
||||
|
||||
// isSuperMacaroonRootKeyID returns true if the given macaroon root key ID (also
|
||||
// known as storage ID) is a super macaroon, which can be identified by its
|
||||
// first 4 bytes.
|
||||
func isSuperMacaroonRootKeyID(rootKeyID uint64) bool {
|
||||
rootKeyBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(rootKeyBytes, rootKeyID)
|
||||
return bytes.HasPrefix(rootKeyBytes, SuperMacaroonRootKeyPrefix[:])
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package session
|
||||
package macaroons
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -25,13 +25,21 @@ var (
|
|||
"60a6caf"
|
||||
)
|
||||
|
||||
// TestSuperMacaroonRootKeyID tests that adding the super macaroon prefix to
|
||||
// a root key ID results in a valid super macaroon root key ID.
|
||||
func TestSuperMacaroonRootKeyID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
someBytes := [4]byte{02, 03, 44, 88}
|
||||
rootKeyID := NewSuperMacaroonRootKeyID(someBytes)
|
||||
require.True(t, isSuperMacaroonRootKeyID(rootKeyID))
|
||||
require.False(t, isSuperMacaroonRootKeyID(123))
|
||||
}
|
||||
|
||||
// TestIsSuperMacaroon tests that we can correctly identify an example super
|
||||
// macaroon.
|
||||
func TestIsSuperMacaroon(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require.True(t, IsSuperMacaroon(testMacHex))
|
||||
}
|
||||
10
rpc_proxy.go
10
rpc_proxy.go
|
|
@ -13,8 +13,8 @@ import (
|
|||
|
||||
"github.com/improbable-eng/grpc-web/go/grpcweb"
|
||||
"github.com/lightninglabs/lightning-terminal/litrpc"
|
||||
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"github.com/lightninglabs/lightning-terminal/perms"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
litstatus "github.com/lightninglabs/lightning-terminal/status"
|
||||
"github.com/lightninglabs/lightning-terminal/subservers"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
|
|
@ -71,7 +71,7 @@ func (e *proxyErr) Unwrap() error {
|
|||
// or REST request and delegate (and convert if necessary) it to the correct
|
||||
// component.
|
||||
func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
|
||||
superMacValidator session.SuperMacaroonValidator,
|
||||
superMacValidator litmac.SuperMacaroonValidator,
|
||||
permsMgr *perms.Manager, subServerMgr *subservers.Manager,
|
||||
statusMgr *litstatus.Manager, getLNDClient lndBasicClientFn) *rpcProxy {
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ type rpcProxy struct {
|
|||
bakeSuperMac bakeSuperMac
|
||||
|
||||
macValidator macaroons.MacaroonValidator
|
||||
superMacValidator session.SuperMacaroonValidator
|
||||
superMacValidator litmac.SuperMacaroonValidator
|
||||
|
||||
superMacaroon string
|
||||
|
||||
|
|
@ -331,7 +331,9 @@ func (p *rpcProxy) makeDirector(allowLitRPC bool) func(ctx context.Context,
|
|||
))
|
||||
}
|
||||
|
||||
case len(macHeader) == 1 && session.IsSuperMacaroon(macHeader[0]):
|
||||
case len(macHeader) == 1 &&
|
||||
litmac.IsSuperMacaroon(macHeader[0]):
|
||||
|
||||
// If we have a macaroon, and it's a super macaroon,
|
||||
// then we need to convert it into the actual daemon
|
||||
// macaroon if they're running in remote mode.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/lightninglabs/lightning-node-connect/mailbox"
|
||||
"github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
"gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
|
@ -86,7 +87,7 @@ func NewSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type,
|
|||
return nil, fmt.Errorf("error deriving pairing secret: %v", err)
|
||||
}
|
||||
|
||||
macRootKey := NewSuperMacaroonRootKeyID(id)
|
||||
macRootKey := macaroons.NewSuperMacaroonRootKeyID(id)
|
||||
|
||||
// The group ID will by default be the same as the Session ID
|
||||
// unless this session links to a previous session.
|
||||
|
|
|
|||
|
|
@ -1,87 +1,21 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
"github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// SuperMacaroonRootKeyPrefix is the prefix we set on a super macaroon's
|
||||
// root key to clearly mark it as such.
|
||||
SuperMacaroonRootKeyPrefix = [4]byte{0xFF, 0xEE, 0xDD, 0xCC}
|
||||
)
|
||||
|
||||
// ID represents the id of a session.
|
||||
type ID [4]byte
|
||||
|
||||
// SuperMacaroonValidator is a function type for validating a super macaroon.
|
||||
type SuperMacaroonValidator func(ctx context.Context,
|
||||
superMacaroon []byte, requiredPermissions []bakery.Op,
|
||||
fullMethod string) error
|
||||
|
||||
// NewSuperMacaroonRootKeyID returns a new macaroon root key ID that has the
|
||||
// prefix to mark it as a super macaroon root key.
|
||||
func NewSuperMacaroonRootKeyID(id [4]byte) uint64 {
|
||||
rootKeyBytes := make([]byte, 8)
|
||||
copy(rootKeyBytes[:], SuperMacaroonRootKeyPrefix[:])
|
||||
copy(rootKeyBytes[4:], id[:])
|
||||
return binary.BigEndian.Uint64(rootKeyBytes)
|
||||
}
|
||||
|
||||
// ParseMacaroon parses a hex encoded macaroon into its native struct.
|
||||
func ParseMacaroon(macHex string) (*macaroon.Macaroon, error) {
|
||||
macBytes, err := hex.DecodeString(macHex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mac := &macaroon.Macaroon{}
|
||||
if err := mac.UnmarshalBinary(macBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mac, nil
|
||||
}
|
||||
|
||||
// IsSuperMacaroon returns true if the given hex encoded macaroon is a super
|
||||
// macaroon baked by LiT which can be identified by its root key ID.
|
||||
func IsSuperMacaroon(macHex string) bool {
|
||||
mac, err := ParseMacaroon(macHex)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
rootKeyID, err := RootKeyIDFromMacaroon(mac)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return isSuperMacaroonRootKeyID(rootKeyID)
|
||||
}
|
||||
|
||||
// isSuperMacaroonRootKeyID returns true if the given macaroon root key ID (also
|
||||
// known as storage ID) is a super macaroon, which can be identified by its
|
||||
// first 4 bytes.
|
||||
func isSuperMacaroonRootKeyID(rootKeyID uint64) bool {
|
||||
rootKeyBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(rootKeyBytes, rootKeyID)
|
||||
return bytes.HasPrefix(rootKeyBytes, SuperMacaroonRootKeyPrefix[:])
|
||||
}
|
||||
|
||||
// IDFromMacaroon is a helper function that creates a session ID from
|
||||
// a macaroon ID.
|
||||
func IDFromMacaroon(mac *macaroon.Macaroon) (ID, error) {
|
||||
rootKeyID, err := RootKeyIDFromMacaroon(mac)
|
||||
rootKeyID, err := macaroons.RootKeyIDFromMacaroon(mac)
|
||||
if err != nil {
|
||||
return ID{}, err
|
||||
}
|
||||
|
|
@ -110,25 +44,6 @@ func IDFromBytes(b []byte) (ID, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
// RootKeyIDFromMacaroon extracts the root key ID of the passed macaroon.
|
||||
func RootKeyIDFromMacaroon(mac *macaroon.Macaroon) (uint64, error) {
|
||||
rawID := mac.Id()
|
||||
if rawID[0] != byte(bakery.LatestVersion) {
|
||||
return 0, fmt.Errorf("mac id is not on the latest version")
|
||||
}
|
||||
|
||||
decodedID := &lnrpc.MacaroonId{}
|
||||
idProto := rawID[1:]
|
||||
err := proto.Unmarshal(idProto, decodedID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// The storage ID is a string representation of a 64-bit unsigned
|
||||
// number.
|
||||
return strconv.ParseUint(string(decodedID.StorageId), 10, 64)
|
||||
}
|
||||
|
||||
// NewSessionPrivKeyAndID randomly derives a new private key and session ID
|
||||
// pair.
|
||||
func NewSessionPrivKeyAndID() (*btcec.PrivateKey, ID, error) {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/lightninglabs/lightning-terminal/firewall"
|
||||
"github.com/lightninglabs/lightning-terminal/firewalldb"
|
||||
"github.com/lightninglabs/lightning-terminal/litrpc"
|
||||
litmac "github.com/lightninglabs/lightning-terminal/macaroons"
|
||||
"github.com/lightninglabs/lightning-terminal/perms"
|
||||
"github.com/lightninglabs/lightning-terminal/queue"
|
||||
mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware"
|
||||
|
|
@ -662,7 +663,7 @@ func (g *LightningTerminal) start(ctx context.Context) error {
|
|||
var suffixBytes [4]byte
|
||||
binary.BigEndian.PutUint32(suffixBytes[:], rootKeyIDSuffix)
|
||||
|
||||
rootKeyID := session.NewSuperMacaroonRootKeyID(suffixBytes)
|
||||
rootKeyID := litmac.NewSuperMacaroonRootKeyID(suffixBytes)
|
||||
|
||||
return BakeSuperMacaroon(
|
||||
ctx, g.basicClient, rootKeyID,
|
||||
|
|
@ -953,7 +954,7 @@ func (g *LightningTerminal) setUpLNDClients(ctx context.Context,
|
|||
// faraday, loop, and pool, all at the same time.
|
||||
log.Infof("Baking internal super macaroon")
|
||||
superMacaroon, err := BakeSuperMacaroon(
|
||||
ctx, g.basicClient, session.NewSuperMacaroonRootKeyID(
|
||||
ctx, g.basicClient, litmac.NewSuperMacaroonRootKeyID(
|
||||
[4]byte{},
|
||||
),
|
||||
g.permsMgr.ActivePermissions(false), nil,
|
||||
|
|
@ -1265,7 +1266,7 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
|
|||
// the proxy and its director and any super macaroon will be converted
|
||||
// to a daemon specific macaroon before directing the call to the remote
|
||||
// daemon. Those calls don't land here.
|
||||
if session.IsSuperMacaroon(macHex) {
|
||||
if litmac.IsSuperMacaroon(macHex) {
|
||||
macBytes, err := hex.DecodeString(macHex)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -1873,7 +1874,7 @@ func BakeSuperMacaroon(ctx context.Context, lnd lnrpc.LightningClient,
|
|||
return "", err
|
||||
}
|
||||
|
||||
mac, err := session.ParseMacaroon(res.Macaroon)
|
||||
mac, err := litmac.ParseMacaroon(res.Macaroon)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue