diff --git a/lnd.go b/lnd.go index 4fbe291d..62e8c6c2 100644 --- a/lnd.go +++ b/lnd.go @@ -22,6 +22,7 @@ import ( _ "net/http/pprof" "gopkg.in/macaroon-bakery.v2/bakery" + "gopkg.in/macaroon.v2" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -59,6 +60,45 @@ var ( 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 // will be closed when a server starts listening. type ListenerWithSignal struct {