Merge pull request #3783 from halseth/mobile-macaroons
[mobile] mobile macaroons support
This commit is contained in:
commit
773212bdf8
@ -109,6 +109,10 @@ func GenCertPair(org, certFile, keyFile string, tlsExtraIPs,
|
|||||||
// verification will fail in the client.
|
// verification will fail in the client.
|
||||||
dnsNames = append(dnsNames, "unix", "unixpacket")
|
dnsNames = append(dnsNames, "unix", "unixpacket")
|
||||||
|
|
||||||
|
// Also add hostnames for 'bufconn' which is the hostname used for the
|
||||||
|
// in-memory connections used on mobile.
|
||||||
|
dnsNames = append(dnsNames, "bufconn")
|
||||||
|
|
||||||
// Generate a private key for the certificate.
|
// Generate a private key for the certificate.
|
||||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
97
lnd.go
97
lnd.go
@ -22,6 +22,7 @@ import (
|
|||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
|
|
||||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||||
|
"gopkg.in/macaroon.v2"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
@ -59,6 +60,45 @@ var (
|
|||||||
networkDir string
|
networkDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AdminAuthOptions returns a list of DialOptions that can be used to
|
||||||
|
// authenticate with the RPC server with admin capabilities.
|
||||||
|
//
|
||||||
|
// NOTE: This should only be called after the RPCListener has signaled it is
|
||||||
|
// ready.
|
||||||
|
func AdminAuthOptions() ([]grpc.DialOption, error) {
|
||||||
|
creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read TLS cert: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a dial options array.
|
||||||
|
opts := []grpc.DialOption{
|
||||||
|
grpc.WithTransportCredentials(creds),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the admin macaroon if macaroons are active.
|
||||||
|
if !cfg.NoMacaroons {
|
||||||
|
// Load the adming macaroon file.
|
||||||
|
macBytes, err := ioutil.ReadFile(cfg.AdminMacPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read macaroon "+
|
||||||
|
"path (check the network setting!): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mac := &macaroon.Macaroon{}
|
||||||
|
if err = mac.UnmarshalBinary(macBytes); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to decode macaroon: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we append the macaroon credentials to the dial options.
|
||||||
|
cred := macaroons.NewMacaroonCredential(mac)
|
||||||
|
opts = append(opts, grpc.WithPerRPCCredentials(cred))
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ListnerWithSignal is a net.Listner that has an additional Ready channel that
|
// ListnerWithSignal is a net.Listner that has an additional Ready channel that
|
||||||
// will be closed when a server starts listening.
|
// will be closed when a server starts listening.
|
||||||
type ListenerWithSignal struct {
|
type ListenerWithSignal struct {
|
||||||
@ -81,12 +121,11 @@ type ListenerCfg struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rpcListeners is a function type used for closures that fetches a set of RPC
|
// rpcListeners is a function type used for closures that fetches a set of RPC
|
||||||
// listeners for the current configuration, and the GRPC server options to use
|
// listeners for the current configuration. If no custom listeners are present,
|
||||||
// with these listeners. If no custom listeners are present, this should return
|
// this should return normal listeners from the RPC endpoints defined in the
|
||||||
// normal listeners from the RPC endpoints defined in the config, and server
|
// config. The second return value us a closure that will close the fetched
|
||||||
// options specifying TLS.
|
// listeners.
|
||||||
type rpcListeners func() ([]*ListenerWithSignal, func(), []grpc.ServerOption,
|
type rpcListeners func() ([]*ListenerWithSignal, func(), error)
|
||||||
error)
|
|
||||||
|
|
||||||
// Main is the true entry point for lnd. This function is required since defers
|
// Main is the true entry point for lnd. This function is required since defers
|
||||||
// created in the top-level scope of a main method aren't executed if os.Exit()
|
// created in the top-level scope of a main method aren't executed if os.Exit()
|
||||||
@ -245,9 +284,7 @@ func Main(lisCfg ListenerCfg) error {
|
|||||||
// getListeners is a closure that creates listeners from the
|
// getListeners is a closure that creates listeners from the
|
||||||
// RPCListeners defined in the config. It also returns a cleanup
|
// RPCListeners defined in the config. It also returns a cleanup
|
||||||
// closure and the server options to use for the GRPC server.
|
// closure and the server options to use for the GRPC server.
|
||||||
getListeners := func() ([]*ListenerWithSignal, func(),
|
getListeners := func() ([]*ListenerWithSignal, func(), error) {
|
||||||
[]grpc.ServerOption, error) {
|
|
||||||
|
|
||||||
var grpcListeners []*ListenerWithSignal
|
var grpcListeners []*ListenerWithSignal
|
||||||
for _, grpcEndpoint := range cfg.RPCListeners {
|
for _, grpcEndpoint := range cfg.RPCListeners {
|
||||||
// Start a gRPC server listening for HTTP/2
|
// Start a gRPC server listening for HTTP/2
|
||||||
@ -256,7 +293,7 @@ func Main(lisCfg ListenerCfg) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
ltndLog.Errorf("unable to listen on %s",
|
ltndLog.Errorf("unable to listen on %s",
|
||||||
grpcEndpoint)
|
grpcEndpoint)
|
||||||
return nil, nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
grpcListeners = append(
|
grpcListeners = append(
|
||||||
grpcListeners, &ListenerWithSignal{
|
grpcListeners, &ListenerWithSignal{
|
||||||
@ -270,23 +307,20 @@ func Main(lisCfg ListenerCfg) error {
|
|||||||
lis.Close()
|
lis.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return grpcListeners, cleanup, serverOpts, nil
|
return grpcListeners, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// walletUnlockerListeners is a closure we'll hand to the wallet
|
// walletUnlockerListeners is a closure we'll hand to the wallet
|
||||||
// unlocker, that will be called when it needs listeners for its GPRC
|
// unlocker, that will be called when it needs listeners for its GPRC
|
||||||
// server.
|
// server.
|
||||||
walletUnlockerListeners := func() ([]*ListenerWithSignal, func(),
|
walletUnlockerListeners := func() ([]*ListenerWithSignal, func(),
|
||||||
[]grpc.ServerOption, error) {
|
error) {
|
||||||
|
|
||||||
// If we have chosen to start with a dedicated listener for the
|
// If we have chosen to start with a dedicated listener for the
|
||||||
// wallet unlocker, we return it directly, and empty server
|
// wallet unlocker, we return it directly.
|
||||||
// options to deactivate TLS.
|
|
||||||
// TODO(halseth): any point in adding TLS support for custom
|
|
||||||
// listeners?
|
|
||||||
if lisCfg.WalletUnlocker != nil {
|
if lisCfg.WalletUnlocker != nil {
|
||||||
return []*ListenerWithSignal{lisCfg.WalletUnlocker},
|
return []*ListenerWithSignal{lisCfg.WalletUnlocker},
|
||||||
func() {}, []grpc.ServerOption{}, nil
|
func() {}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we'll return the regular listeners.
|
// Otherwise we'll return the regular listeners.
|
||||||
@ -298,8 +332,8 @@ func Main(lisCfg ListenerCfg) error {
|
|||||||
// for wallet encryption.
|
// for wallet encryption.
|
||||||
if !cfg.NoSeedBackup {
|
if !cfg.NoSeedBackup {
|
||||||
params, err := waitForWalletPassword(
|
params, err := waitForWalletPassword(
|
||||||
cfg.RESTListeners, restDialOpts, restProxyDest, tlsCfg,
|
cfg.RESTListeners, serverOpts, restDialOpts,
|
||||||
walletUnlockerListeners,
|
restProxyDest, tlsCfg, walletUnlockerListeners,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Unable to set up wallet password "+
|
err := fmt.Errorf("Unable to set up wallet password "+
|
||||||
@ -515,17 +549,12 @@ func Main(lisCfg ListenerCfg) error {
|
|||||||
|
|
||||||
// rpcListeners is a closure we'll hand to the rpc server, that will be
|
// rpcListeners is a closure we'll hand to the rpc server, that will be
|
||||||
// called when it needs listeners for its GPRC server.
|
// called when it needs listeners for its GPRC server.
|
||||||
rpcListeners := func() ([]*ListenerWithSignal, func(),
|
rpcListeners := func() ([]*ListenerWithSignal, func(), error) {
|
||||||
[]grpc.ServerOption, error) {
|
|
||||||
|
|
||||||
// If we have chosen to start with a dedicated listener for the
|
// If we have chosen to start with a dedicated listener for the
|
||||||
// rpc server, we return it directly, and empty server options
|
// rpc server, we return it directly.
|
||||||
// to deactivate TLS.
|
|
||||||
// TODO(halseth): any point in adding TLS support for custom
|
|
||||||
// listeners?
|
|
||||||
if lisCfg.RPCListener != nil {
|
if lisCfg.RPCListener != nil {
|
||||||
return []*ListenerWithSignal{lisCfg.RPCListener},
|
return []*ListenerWithSignal{lisCfg.RPCListener},
|
||||||
func() {}, []grpc.ServerOption{}, nil
|
func() {}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we'll return the regular listeners.
|
// Otherwise we'll return the regular listeners.
|
||||||
@ -535,9 +564,9 @@ func Main(lisCfg ListenerCfg) error {
|
|||||||
// Initialize, and register our implementation of the gRPC interface
|
// Initialize, and register our implementation of the gRPC interface
|
||||||
// exported by the rpcServer.
|
// exported by the rpcServer.
|
||||||
rpcServer, err := newRPCServer(
|
rpcServer, err := newRPCServer(
|
||||||
server, macaroonService, cfg.SubRPCServers, restDialOpts,
|
server, macaroonService, cfg.SubRPCServers, serverOpts,
|
||||||
restProxyDest, atplManager, server.invoices, tower, tlsCfg,
|
restDialOpts, restProxyDest, atplManager, server.invoices,
|
||||||
rpcListeners, chainedAcceptor,
|
tower, tlsCfg, rpcListeners, chainedAcceptor,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Unable to create RPC server: %v", err)
|
err := fmt.Errorf("Unable to create RPC server: %v", err)
|
||||||
@ -813,13 +842,13 @@ type WalletUnlockParams struct {
|
|||||||
// WalletUnlocker server, and block until a password is provided by
|
// WalletUnlocker server, and block until a password is provided by
|
||||||
// the user to this RPC server.
|
// the user to this RPC server.
|
||||||
func waitForWalletPassword(restEndpoints []net.Addr,
|
func waitForWalletPassword(restEndpoints []net.Addr,
|
||||||
restDialOpts []grpc.DialOption, restProxyDest string,
|
serverOpts []grpc.ServerOption, restDialOpts []grpc.DialOption,
|
||||||
tlsConf *tls.Config, getListeners rpcListeners) (
|
restProxyDest string, tlsConf *tls.Config,
|
||||||
*WalletUnlockParams, error) {
|
getListeners rpcListeners) (*WalletUnlockParams, error) {
|
||||||
|
|
||||||
// Start a gRPC server listening for HTTP/2 connections, solely used
|
// Start a gRPC server listening for HTTP/2 connections, solely used
|
||||||
// for getting the encryption password from the client.
|
// for getting the encryption password from the client.
|
||||||
listeners, cleanup, serverOpts, err := getListeners()
|
listeners, cleanup, err := getListeners()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,19 @@ func Start(extraArgs string, unlockerReady, rpcReady Callback) {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-rpcListening
|
<-rpcListening
|
||||||
|
|
||||||
|
// Now that the RPC server is ready, we can get the needed
|
||||||
|
// authentication options, and add them to the global dial
|
||||||
|
// options.
|
||||||
|
auth, err := lnd.AdminAuthOptions()
|
||||||
|
if err != nil {
|
||||||
|
rpcReady.OnError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the auth options to the listener's dial options.
|
||||||
|
addLightningLisDialOption(auth...)
|
||||||
|
|
||||||
rpcReady.OnResponse([]byte{})
|
rpcReady.OnResponse([]byte{})
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
mkdir -p build
|
mkdir -p build
|
||||||
|
|
||||||
# Check falafel version.
|
# Check falafel version.
|
||||||
falafelVersion="0.5"
|
falafelVersion="0.6"
|
||||||
falafel=$(which falafel)
|
falafel=$(which falafel)
|
||||||
if [ $falafel ]
|
if [ $falafel ]
|
||||||
then
|
then
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
[Application Options]
|
[Application Options]
|
||||||
debuglevel=info
|
debuglevel=info
|
||||||
no-macaroons=1
|
|
||||||
maxbackoff=2s
|
maxbackoff=2s
|
||||||
nolisten=1
|
nolisten=1
|
||||||
norest=1
|
norest=1
|
||||||
|
11
rpcserver.go
11
rpcserver.go
@ -508,10 +508,11 @@ var _ lnrpc.LightningServer = (*rpcServer)(nil)
|
|||||||
// base level options passed to the grPC server. This typically includes things
|
// base level options passed to the grPC server. This typically includes things
|
||||||
// like requiring TLS, etc.
|
// like requiring TLS, etc.
|
||||||
func newRPCServer(s *server, macService *macaroons.Service,
|
func newRPCServer(s *server, macService *macaroons.Service,
|
||||||
subServerCgs *subRPCServerConfigs, restDialOpts []grpc.DialOption,
|
subServerCgs *subRPCServerConfigs, serverOpts []grpc.ServerOption,
|
||||||
restProxyDest string, atpl *autopilot.Manager,
|
restDialOpts []grpc.DialOption, restProxyDest string,
|
||||||
invoiceRegistry *invoices.InvoiceRegistry, tower *watchtower.Standalone,
|
atpl *autopilot.Manager, invoiceRegistry *invoices.InvoiceRegistry,
|
||||||
tlsCfg *tls.Config, getListeners rpcListeners,
|
tower *watchtower.Standalone, tlsCfg *tls.Config,
|
||||||
|
getListeners rpcListeners,
|
||||||
chanPredicate *chanacceptor.ChainedAcceptor) (*rpcServer, error) {
|
chanPredicate *chanacceptor.ChainedAcceptor) (*rpcServer, error) {
|
||||||
|
|
||||||
// Set up router rpc backend.
|
// Set up router rpc backend.
|
||||||
@ -643,7 +644,7 @@ func newRPCServer(s *server, macService *macaroons.Service,
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Get the listeners and server options to use for this rpc server.
|
// Get the listeners and server options to use for this rpc server.
|
||||||
listeners, cleanup, serverOpts, err := getListeners()
|
listeners, cleanup, err := getListeners()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user