From 5f74bbc9705a68643623fb7b48d394a7c09d2b10 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 30 Aug 2022 09:09:36 +0200 Subject: [PATCH] subserver_perms: add Lnd's registered subserver perms --- README.md | 2 +- itest/litd_mode_integrated_test.go | 7 +- rpc_proxy.go | 43 ++-- session_rpcserver.go | 3 +- subserver_permissions.go | 316 ++++++++++++++++++++++++----- terminal.go | 34 +++- 6 files changed, 316 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index afac59f4d..5baf695a7 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ To use LiT with a remote `lnd` instance please [follow these instructions](./doc Note that LiT requires `lnd` to be built with **all of its subservers** and requires running at least v0.11.0. Download the latest [official release binary](https://github.com/lightningnetwork/lnd/releases/latest) or build `lnd` from source by following the [installation instructions](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md). If you choose to build `lnd` from source, use the following command to enable all the relevant subservers: ```shell -⛰ make install tags="signrpc walletrpc chainrpc invoicesrpc" +⛰ make install tags="signrpc walletrpc chainrpc invoicesrpc verrpc" ``` ## Interaction diff --git a/itest/litd_mode_integrated_test.go b/itest/litd_mode_integrated_test.go index 0bb0594e7..62c886092 100644 --- a/itest/litd_mode_integrated_test.go +++ b/itest/litd_mode_integrated_test.go @@ -834,7 +834,12 @@ func bakeSuperMacaroon(cfg *LitNodeConfig, readOnly bool) (string, error) { lndAdminCtx := macaroonContext(ctxt, lndAdminMacBytes) lndConn := lnrpc.NewLightningClient(rawConn) - superMacPermissions := terminal.GetAllPermissions(readOnly) + permsMgr, err := terminal.NewPermissionsManager() + if err != nil { + return "", err + } + + superMacPermissions := permsMgr.GetPermissionsList(readOnly) nullID := [4]byte{} superMacHex, err := terminal.BakeSuperMacaroon( lndAdminCtx, lndConn, session.NewSuperMacaroonRootKeyID(nullID), diff --git a/rpc_proxy.go b/rpc_proxy.go index 1662da772..0d8df2119 100644 --- a/rpc_proxy.go +++ b/rpc_proxy.go @@ -24,7 +24,6 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" - "gopkg.in/macaroon-bakery.v2/bakery" "gopkg.in/macaroon.v2" ) @@ -59,8 +58,7 @@ func (e *proxyErr) Unwrap() error { // component. func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator, superMacValidator session.SuperMacaroonValidator, - permissionMap map[string][]bakery.Op, - bufListener *bufconn.Listener) *rpcProxy { + permsMgr *PermissionsManager, bufListener *bufconn.Listener) *rpcProxy { // The gRPC web calls are protected by HTTP basic auth which is defined // by base64(username:password). Because we only have a password, we @@ -77,7 +75,7 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator, p := &rpcProxy{ cfg: cfg, basicAuth: basicAuth, - permissionMap: permissionMap, + permsMgr: permsMgr, macValidator: validator, superMacValidator: superMacValidator, bufListener: bufListener, @@ -146,9 +144,10 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator, // +---------------------+ // type rpcProxy struct { - cfg *Config - basicAuth string - permissionMap map[string][]bakery.Op + cfg *Config + basicAuth string + + permsMgr *PermissionsManager macValidator macaroons.MacaroonValidator superMacValidator session.SuperMacaroonValidator @@ -345,17 +344,17 @@ func (p *rpcProxy) makeDirector(allowLitRPC bool) func(ctx context.Context, // handled by the integrated daemons that are hooking into lnd's // gRPC server. switch { - case isFaradayURI(requestURI) && p.cfg.faradayRemote: + case p.permsMgr.IsFaradayURI(requestURI) && p.cfg.faradayRemote: return outCtx, p.faradayConn, nil - case isLoopURI(requestURI) && p.cfg.loopRemote: + case p.permsMgr.IsLoopURI(requestURI) && p.cfg.loopRemote: return outCtx, p.loopConn, nil - case isPoolURI(requestURI) && p.cfg.poolRemote: + case p.permsMgr.IsPoolURI(requestURI) && p.cfg.poolRemote: return outCtx, p.poolConn, nil // Calls to LiT session RPC aren't allowed in some cases. - case isLitURI(requestURI) && !allowLitRPC: + case p.permsMgr.IsLitURI(requestURI) && !allowLitRPC: return outCtx, nil, status.Errorf( codes.Unimplemented, "unknown service %s", requestURI, @@ -373,7 +372,7 @@ func (p *rpcProxy) UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - uriPermissions, ok := p.permissionMap[info.FullMethod] + uriPermissions, ok := p.permsMgr.GetPermOps(info.FullMethod) if !ok { return nil, fmt.Errorf("%s: unknown permissions "+ "required for method", info.FullMethod) @@ -414,7 +413,7 @@ func (p *rpcProxy) StreamServerInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - uriPermissions, ok := p.permissionMap[info.FullMethod] + uriPermissions, ok := p.permsMgr.GetPermOps(info.FullMethod) if !ok { return fmt.Errorf("%s: unknown permissions required "+ "for method", info.FullMethod) @@ -503,31 +502,31 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string, macData []byte ) switch { - case isLndURI(requestURI): + case p.permsMgr.IsLndURI(requestURI): _, _, _, macPath, macData = p.cfg.lndConnectParams() - case isFaradayURI(requestURI): + case p.permsMgr.IsFaradayURI(requestURI): if p.cfg.faradayRemote { macPath = p.cfg.Remote.Faraday.MacaroonPath } else { macPath = p.cfg.Faraday.MacaroonPath } - case isLoopURI(requestURI): + case p.permsMgr.IsLoopURI(requestURI): if p.cfg.loopRemote { macPath = p.cfg.Remote.Loop.MacaroonPath } else { macPath = p.cfg.Loop.MacaroonPath } - case isPoolURI(requestURI): + case p.permsMgr.IsPoolURI(requestURI): if p.cfg.poolRemote { macPath = p.cfg.Remote.Pool.MacaroonPath } else { macPath = p.cfg.Pool.MacaroonPath } - case isLitURI(requestURI): + case p.permsMgr.IsLitURI(requestURI): macPath = p.cfg.MacaroonPath default: @@ -580,7 +579,7 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string, func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string, fullMethod string) ([]byte, error) { - requiredPermissions, ok := p.permissionMap[fullMethod] + requiredPermissions, ok := p.permsMgr.GetPermOps(fullMethod) if !ok { return nil, fmt.Errorf("%s: unknown permissions required for "+ "method", fullMethod) @@ -605,17 +604,17 @@ func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string, // Is this actually a request that goes to a daemon that is running // remotely? switch { - case isFaradayURI(fullMethod) && p.cfg.faradayRemote: + case p.permsMgr.IsFaradayURI(fullMethod) && p.cfg.faradayRemote: return readMacaroon(lncfg.CleanAndExpandPath( p.cfg.Remote.Faraday.MacaroonPath, )) - case isLoopURI(fullMethod) && p.cfg.loopRemote: + case p.permsMgr.IsLoopURI(fullMethod) && p.cfg.loopRemote: return readMacaroon(lncfg.CleanAndExpandPath( p.cfg.Remote.Loop.MacaroonPath, )) - case isPoolURI(fullMethod) && p.cfg.poolRemote: + case p.permsMgr.IsPoolURI(fullMethod) && p.cfg.poolRemote: return readMacaroon(lncfg.CleanAndExpandPath( p.cfg.Remote.Pool.MacaroonPath, )) diff --git a/session_rpcserver.go b/session_rpcserver.go index ed4032157..e458806d9 100644 --- a/session_rpcserver.go +++ b/session_rpcserver.go @@ -39,6 +39,7 @@ type sessionRpcServerConfig struct { superMacBaker func(ctx context.Context, rootKeyID uint64, recipe *session.MacaroonRecipe) (string, error) firstConnectionDeadline time.Duration + permMgr *PermissionsManager } // newSessionRPCServer creates a new sessionRpcServer using the passed config. @@ -205,7 +206,7 @@ func (s *sessionRpcServer) resumeSession(sess *session.Session) error { mac, err := s.cfg.superMacBaker( context.Background(), sess.MacaroonRootKey, &session.MacaroonRecipe{ - Permissions: GetAllPermissions(readOnly), + Permissions: s.cfg.permMgr.GetPermissionsList(readOnly), Caveats: caveats, }, ) diff --git a/subserver_permissions.go b/subserver_permissions.go index f350f5e66..d6d537b1c 100644 --- a/subserver_permissions.go +++ b/subserver_permissions.go @@ -1,10 +1,31 @@ package terminal import ( + "net" + "strings" + "sync" + faraday "github.com/lightninglabs/faraday/frdrpcserver/perms" loop "github.com/lightninglabs/loop/loopd/perms" pool "github.com/lightninglabs/pool/perms" "github.com/lightningnetwork/lnd" + "github.com/lightningnetwork/lnd/autopilot" + "github.com/lightningnetwork/lnd/chainreg" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnrpc/autopilotrpc" + "github.com/lightningnetwork/lnd/lnrpc/chainrpc" + "github.com/lightningnetwork/lnd/lnrpc/devrpc" + "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" + "github.com/lightningnetwork/lnd/lnrpc/neutrinorpc" + "github.com/lightningnetwork/lnd/lnrpc/peersrpc" + "github.com/lightningnetwork/lnd/lnrpc/routerrpc" + "github.com/lightningnetwork/lnd/lnrpc/signrpc" + "github.com/lightningnetwork/lnd/lnrpc/walletrpc" + "github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc" + "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" + "github.com/lightningnetwork/lnd/lntest/mock" + "github.com/lightningnetwork/lnd/routing" + "github.com/lightningnetwork/lnd/sweep" "gopkg.in/macaroon-bakery.v2/bakery" ) @@ -26,9 +47,9 @@ var ( }}, } - // whiteListedMethods is a map of all lnd RPC methods that don't require - // any macaroon authentication. - whiteListedMethods = map[string][]bakery.Op{ + // whiteListedLNDMethods is a map of all lnd RPC methods that don't + // require any macaroon authentication. + whiteListedLNDMethods = map[string][]bakery.Op{ "/lnrpc.WalletUnlocker/GenSeed": {}, "/lnrpc.WalletUnlocker/InitWallet": {}, "/lnrpc.WalletUnlocker/UnlockWallet": {}, @@ -39,55 +60,151 @@ var ( "/lnrpc.State/SubscribeState": {}, "/lnrpc.State/GetState": {}, } -) -// getSubserverPermissions returns a merged map of all subserver macaroon -// permissions. -func getSubserverPermissions() map[string][]bakery.Op { - mapSize := len(faraday.RequiredPermissions) + - len(loop.RequiredPermissions) + len(pool.RequiredPermissions) - result := make(map[string][]bakery.Op, mapSize) - for key, value := range faraday.RequiredPermissions { - result[key] = value + // lndSubServerNameToTag is a map from the name of an LND subserver to + // the name of the LND tag that corresponds to the subserver. This map + // only contains the subserver-to-tag pairs for the pairs where the + // names differ. + lndSubServerNameToTag = map[string]string{ + "WalletKitRPC": "walletrpc", + "DevRPC": "dev", + "NeutrinoKitRPC": "neutrinorpc", + "VersionRPC": "verrpc", + "WatchtowerClientRPC": "wtclientrpc", } - for key, value := range loop.RequiredPermissions { - result[key] = value +) + +// subServerName is a name used to identify a particular Lit sub-server. +type subServerName string + +const ( + poolPerms subServerName = "pool" + loopPerms subServerName = "loop" + faradayPerms subServerName = "faraday" + litPerms subServerName = "lit" + lndPerms subServerName = "lnd" +) + +// PermissionsManager manages the permission lists that Lit requires. +type PermissionsManager struct { + // lndSubServerPerms is a map from LND subserver name to permissions + // map. This is used once the manager receives a list of build tags + // that LND has been compiled with so that the correct permissions can + // be extracted based on subservers that LND has been compiled with. + lndSubServerPerms map[string]map[string][]bakery.Op + + // fixedPerms is constructed once on creation of the PermissionsManager. + // It contains all the permissions that will not change throughout the + // lifetime of the manager. It maps sub-server name to uri to permission + // operations. + fixedPerms map[subServerName]map[string][]bakery.Op + + // perms is a map containing all permissions that the manager knows + // are available for use. This map will start out not including any of + // lnd's sub-server permissions. Only when the LND build tags are + // obtained and OnLNDBuildTags is called will this map include the + // available LND sub-server permissions. This map must only be accessed + // once the permsMu mutex is held. + perms map[string][]bakery.Op + permsMu sync.RWMutex +} + +// NewPermissionsManager constructs a new PermissionsManager instance and +// collects any of the fixed permissions. +func NewPermissionsManager() (*PermissionsManager, error) { + // Collect all LND sub-server permissions along with the name of the + // sub-server that each permission is associated with. + lndSubServerPerms := make(map[string]map[string][]bakery.Op) + ss := lnrpc.RegisteredSubServers() + for _, subServer := range ss { + _, perms, err := subServer.NewGrpcHandler().CreateSubServer( + &mockConfig{}, + ) + if err != nil { + return nil, err + } + + name := subServer.SubServerName + lndSubServerPerms[name] = make(map[string][]bakery.Op) + for key, value := range perms { + lndSubServerPerms[name][key] = value + } } - for key, value := range pool.RequiredPermissions { - result[key] = value + + permissions := make(map[subServerName]map[string][]bakery.Op) + permissions[faradayPerms] = faraday.RequiredPermissions + permissions[loopPerms] = loop.RequiredPermissions + permissions[poolPerms] = pool.RequiredPermissions + permissions[litPerms] = litPermissions + permissions[lndPerms] = lnd.MainRPCServerPermissions() + for k, v := range whiteListedLNDMethods { + permissions[lndPerms][k] = v } - for key, value := range litPermissions { - result[key] = value + + allPerms := make(map[string][]bakery.Op) + for _, perms := range permissions { + for k, v := range perms { + allPerms[k] = v + } } - return result + + return &PermissionsManager{ + lndSubServerPerms: lndSubServerPerms, + fixedPerms: permissions, + perms: allPerms, + }, nil } -// getAllMethodPermissions returns a merged map of lnd's and all subservers' -// method macaroon permissions. -func getAllMethodPermissions() map[string][]bakery.Op { - subserverPermissions := getSubserverPermissions() - lndPermissions := lnd.MainRPCServerPermissions() - mapSize := len(subserverPermissions) + len(lndPermissions) + - len(whiteListedMethods) - result := make(map[string][]bakery.Op, mapSize) - for key, value := range lndPermissions { - result[key] = value - } - for key, value := range subserverPermissions { - result[key] = value +// OnLNDBuildTags should be called once a list of LND build tags has been +// obtained. It then uses those build tags to decide which of the LND sub-server +// permissions to add to the main permissions list. This method should only +// be called once. +func (pm *PermissionsManager) OnLNDBuildTags(lndBuildTags []string) { + pm.permsMu.Lock() + defer pm.permsMu.Unlock() + + tagLookup := make(map[string]bool) + for _, t := range lndBuildTags { + tagLookup[strings.ToLower(t)] = true } - for key, value := range whiteListedMethods { - result[key] = value + + for subServerName, perms := range pm.lndSubServerPerms { + name := subServerName + if tagName, ok := lndSubServerNameToTag[name]; ok { + name = tagName + } + + if !tagLookup[strings.ToLower(name)] { + continue + } + + for key, value := range perms { + pm.perms[key] = value + } } - return result } -// GetAllPermissions retrieves all the permissions needed to bake a super -// macaroon. -func GetAllPermissions(readOnly bool) []bakery.Op { - dedupMap := make(map[string]map[string]bool) +// GetPermOps returns a list of permission operations for the given URI if the +// uri is known to the manager. The second return parameter will be false if +// the URI is unknown to the manager. +func (pm *PermissionsManager) GetPermOps(uri string) ([]bakery.Op, bool) { + pm.permsMu.RLock() + defer pm.permsMu.RUnlock() - for _, methodPerms := range getAllMethodPermissions() { + ops, ok := pm.perms[uri] + return ops, ok +} + +// GetPermissionsList returns all the available active permissions that the +// manager is aware of. Optionally, readOnly can be set to true if only the +// read-only permissions should be returned. +func (pm *PermissionsManager) GetPermissionsList(readOnly bool) []bakery.Op { + pm.permsMu.RLock() + defer pm.permsMu.RUnlock() + + // De-dup the permissions and optionally apply the read-only filter. + dedupMap := make(map[string]map[string]bool) + for _, methodPerms := range pm.perms { for _, methodPerm := range methodPerms { if methodPerm.Action == "" || methodPerm.Entity == "" { continue @@ -119,32 +236,119 @@ func GetAllPermissions(readOnly bool) []bakery.Op { return result } -// isLndURI returns true if the given URI belongs to an RPC of lnd. -func isLndURI(uri string) bool { - _, ok := lnd.MainRPCServerPermissions()[uri] - return ok +// GetLitPerms returns a map of all permissions that the manager is aware of +// _except_ for any LND permissions. In other words, this returns permissions +// for which the external validator of Lit is responsible. +func (pm *PermissionsManager) GetLitPerms() map[string][]bakery.Op { + mapSize := len(pm.fixedPerms[litPerms]) + + len(pm.fixedPerms[faradayPerms]) + + len(pm.fixedPerms[loopPerms]) + len(pm.fixedPerms[poolPerms]) + + result := make(map[string][]bakery.Op, mapSize) + for key, value := range pm.fixedPerms[faradayPerms] { + result[key] = value + } + for key, value := range pm.fixedPerms[loopPerms] { + result[key] = value + } + for key, value := range pm.fixedPerms[poolPerms] { + result[key] = value + } + for key, value := range pm.fixedPerms[litPerms] { + result[key] = value + } + return result } -// isLoopURI returns true if the given URI belongs to an RPC of loopd. -func isLoopURI(uri string) bool { - _, ok := loop.RequiredPermissions[uri] +// IsLndURI returns true if the given URI belongs to an RPC of lnd. +func (pm *PermissionsManager) IsLndURI(uri string) bool { + _, lndSubServerCall := pm.lndSubServerPerms[uri] + _, lndCall := pm.fixedPerms[lndPerms][uri] + return lndCall || lndSubServerCall +} + +// IsLoopURI returns true if the given URI belongs to an RPC of loopd. +func (pm *PermissionsManager) IsLoopURI(uri string) bool { + _, ok := pm.fixedPerms[loopPerms][uri] return ok } -// isFaradayURI returns true if the given URI belongs to an RPC of faraday. -func isFaradayURI(uri string) bool { - _, ok := faraday.RequiredPermissions[uri] +// IsFaradayURI returns true if the given URI belongs to an RPC of faraday. +func (pm *PermissionsManager) IsFaradayURI(uri string) bool { + _, ok := pm.fixedPerms[faradayPerms][uri] return ok } -// isPoolURI returns true if the given URI belongs to an RPC of poold. -func isPoolURI(uri string) bool { - _, ok := pool.RequiredPermissions[uri] +// IsPoolURI returns true if the given URI belongs to an RPC of poold. +func (pm *PermissionsManager) IsPoolURI(uri string) bool { + _, ok := pm.fixedPerms[poolPerms][uri] return ok } -// isLitURI returns true if the given URI belongs to an RPC of LiT. -func isLitURI(uri string) bool { - _, ok := litPermissions[uri] +// IsLitURI returns true if the given URI belongs to an RPC of LiT. +func (pm *PermissionsManager) IsLitURI(uri string) bool { + _, ok := pm.fixedPerms[litPerms][uri] return ok } + +// mockConfig implements lnrpc.SubServerConfigDispatcher. It provides th +// functionality required so that the lnrpc.GrpcHandler.CreateSubServer +// function can be called without panicking. +type mockConfig struct{} + +var _ lnrpc.SubServerConfigDispatcher = (*mockConfig)(nil) + +// FetchConfig is a mock implementation of lnrpc.SubServerConfigDispatcher. It +// is used as a parameter to lnrpc.GrpcHandler.CreateSubServer and allows the +// function to be called without panicking. This is useful because +// CreateSubServer can be used to extract the permissions required by each +// registered subserver. +// +// TODO(elle): remove this once the sub-server permission lists in LND have been +// exported +func (t *mockConfig) FetchConfig(subServerName string) (interface{}, bool) { + switch subServerName { + case "InvoicesRPC": + return &invoicesrpc.Config{}, true + case "WatchtowerClientRPC": + return &wtclientrpc.Config{ + Resolver: func(_, _ string) (*net.TCPAddr, error) { + return nil, nil + }, + }, true + case "AutopilotRPC": + return &autopilotrpc.Config{ + Manager: &autopilot.Manager{}, + }, true + case "ChainRPC": + return &chainrpc.Config{ + ChainNotifier: &chainreg.NoChainBackend{}, + }, true + case "DevRPC": + return &devrpc.Config{}, true + case "NeutrinoKitRPC": + return &neutrinorpc.Config{}, true + case "PeersRPC": + return &peersrpc.Config{}, true + case "RouterRPC": + return &routerrpc.Config{ + Router: &routing.ChannelRouter{}, + }, true + case "SignRPC": + return &signrpc.Config{ + Signer: &mock.DummySigner{}, + }, true + case "WalletKitRPC": + return &walletrpc.Config{ + FeeEstimator: &chainreg.NoChainBackend{}, + Wallet: &mock.WalletController{}, + KeyRing: &mock.SecretKeyRing{}, + Sweeper: &sweep.UtxoSweeper{}, + Chain: &mock.ChainIO{}, + }, true + case "WatchtowerRPC": + return &watchtowerrpc.Config{}, true + default: + return nil, false + } +} diff --git a/terminal.go b/terminal.go index 710266db5..3678d8cbc 100644 --- a/terminal.go +++ b/terminal.go @@ -145,6 +145,8 @@ type LightningTerminal struct { lndClient *lndclient.GrpcLndServices basicClient lnrpc.LightningClient + permsMgr *PermissionsManager + faradayServer *frdrpcserver.RPCServer faradayStarted bool @@ -193,6 +195,12 @@ func (g *LightningTerminal) Run() error { // Show version at startup. log.Infof("LiT version: %s", Version()) + // Construct a new PermissionsManager + g.permsMgr, err = NewPermissionsManager() + if err != nil { + return fmt.Errorf("could not create permissions manager") + } + // Create the instances of our subservers now so we can hook them up to // lnd once it's fully started. bufRpcListener := bufconn.Listen(100) @@ -200,8 +208,7 @@ func (g *LightningTerminal) Run() error { g.loopServer = loopd.New(g.cfg.Loop, nil) g.poolServer = pool.NewServer(g.cfg.Pool) g.rpcProxy = newRpcProxy( - g.cfg, g, g.validateSuperMacaroon, getAllMethodPermissions(), - bufRpcListener, + g.cfg, g, g.validateSuperMacaroon, g.permsMgr, bufRpcListener, ) g.sessionRpcServer, err = newSessionRPCServer(&sessionRpcServerConfig{ basicAuth: g.rpcProxy.basicAuth, @@ -233,6 +240,7 @@ func (g *LightningTerminal) Run() error { ) }, firstConnectionDeadline: g.cfg.FirstLNCConnDeadline, + permMgr: g.permsMgr, }) if err != nil { return fmt.Errorf("could not create new session rpc "+ @@ -486,6 +494,16 @@ func (g *LightningTerminal) startSubservers() error { return err } + // Collect the tags that LND was built with. + version, err := g.lndClient.Versioner.GetVersion(ctxc) + if err != nil { + return err + } + + // Pass LND's build tags to the permission manager so that it can + // filter the available permissions accordingly. + g.permsMgr.OnLNDBuildTags(version.BuildTags) + // In the integrated mode, we received an admin macaroon once lnd was // ready. We can now bake a "super macaroon" that contains all // permissions of all daemons that we can use for any internal calls. @@ -497,7 +515,7 @@ func (g *LightningTerminal) startSubservers() error { ctx, g.basicClient, session.NewSuperMacaroonRootKeyID( [4]byte{}, ), - GetAllPermissions(false), nil, + g.permsMgr.GetPermissionsList(false), nil, ) if err != nil { return err @@ -704,7 +722,7 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context, // process. Calls that we proxy to a remote host don't need to be // checked as they'll have their own interceptor. switch { - case isFaradayURI(fullMethod): + case g.permsMgr.IsFaradayURI(fullMethod): // In remote mode we just pass through the request, the remote // daemon will check the macaroon. if g.cfg.faradayRemote { @@ -728,7 +746,7 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context, } } - case isLoopURI(fullMethod): + case g.permsMgr.IsLoopURI(fullMethod): // In remote mode we just pass through the request, the remote // daemon will check the macaroon. if g.cfg.loopRemote { @@ -752,7 +770,7 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context, } } - case isPoolURI(fullMethod): + case g.permsMgr.IsPoolURI(fullMethod): // In remote mode we just pass through the request, the remote // daemon will check the macaroon. if g.cfg.poolRemote { @@ -776,7 +794,7 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context, } } - case isLitURI(fullMethod): + case g.permsMgr.IsLitURI(fullMethod): if !g.macaroonServiceStarted { return fmt.Errorf("the macaroon service has not " + "started yet") @@ -806,7 +824,7 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context, // // NOTE: This is part of the lnd.ExternalValidator interface. func (g *LightningTerminal) Permissions() map[string][]bakery.Op { - return getSubserverPermissions() + return g.permsMgr.GetLitPerms() } // BuildWalletConfig is responsible for creating or unlocking and then