Skip to content

Commit

Permalink
multi: add Lnd's registered subserver perms
Browse files Browse the repository at this point in the history
In this commit, we let the PermissionsManager manage LND's subserver
permissions. Once Litd is connected to LND, it can get LND's build tags
and pass them to the PermissionsManager which will then adjust its list
of permissions accordingly.
  • Loading branch information
ellemouton committed Aug 31, 2022
1 parent 31f2f24 commit 37a657f
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
172 changes: 167 additions & 5 deletions subserver_permissions.go
Original file line number Diff line number Diff line change
@@ -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"
)

Expand Down Expand Up @@ -39,6 +60,18 @@ var (
"/lnrpc.State/SubscribeState": {},
"/lnrpc.State/GetState": {},
}

// 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",
}
)

// subServerName is a name used to identify a particular Lit sub-server.
Expand All @@ -54,20 +87,50 @@ const (

// 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.
perms map[string][]bakery.Op
// 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
}
}

permissions := make(map[subServerName]map[string][]bakery.Op)
permissions[faradayPerms] = faraday.RequiredPermissions
permissions[loopPerms] = loop.RequiredPermissions
Expand All @@ -86,15 +149,48 @@ func NewPermissionsManager() (*PermissionsManager, error) {
}

return &PermissionsManager{
fixedPerms: permissions,
perms: allPerms,
lndSubServerPerms: lndSubServerPerms,
fixedPerms: permissions,
perms: allPerms,
}, nil
}

// 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 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
}
}
}

// 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()

ops, ok := pm.perms[uri]
return ops, ok
}
Expand All @@ -103,6 +199,9 @@ func (pm *PermissionsManager) GetPermOps(uri string) ([]bakery.Op, bool) {
// 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 {
Expand Down Expand Up @@ -163,8 +262,9 @@ func (pm *PermissionsManager) GetLitPerms() map[string][]bakery.Op {

// 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
return lndCall || lndSubServerCall
}

// IsLoopURI returns true if the given URI belongs to an RPC of loopd.
Expand All @@ -190,3 +290,65 @@ 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
}
}
10 changes: 10 additions & 0 deletions terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,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.
Expand Down

0 comments on commit 37a657f

Please sign in to comment.