11package lndclient
22
33import (
4+ "encoding/hex"
45 "fmt"
56 "io/ioutil"
67 "path/filepath"
@@ -13,23 +14,27 @@ import (
1314 macaroon "gopkg.in/macaroon.v2"
1415)
1516
16- // BasicClientOption is a functional option argument that allows adding arbitrary
17- // lnd basic client configuration overrides, without forcing existing users of
18- // NewBasicClient to update their invocation. These are always processed in
19- // order, with later options overriding earlier ones.
17+ // BasicClientOption is a functional option argument that allows adding
18+ // arbitrary lnd basic client configuration overrides, without forcing existing
19+ // users of NewBasicClient to update their invocation. These are always
20+ // processed in order, with later options overriding earlier ones.
2021type BasicClientOption func (* basicClientOptions )
2122
2223// basicClientOptions is a set of options that can configure the lnd client
2324// returned by NewBasicClient.
2425type basicClientOptions struct {
2526 macFilename string
27+ tlsData string
28+ macData string
29+ insecure bool
30+ systemCerts bool
2631}
2732
28- // defaultBasicClientOptions returns a basicClientOptions set to lnd basic client
29- // defaults.
33+ // defaultBasicClientOptions returns a basicClientOptions set to lnd basic
34+ // client defaults.
3035func defaultBasicClientOptions () * basicClientOptions {
3136 return & basicClientOptions {
32- macFilename : defaultAdminMacaroonFilename ,
37+ macFilename : adminMacFilename ,
3338 }
3439}
3540
@@ -41,9 +46,43 @@ func MacFilename(macFilename string) BasicClientOption {
4146 }
4247}
4348
49+ // TLSData is a basic client option that sets TLS data (encoded in PEM format)
50+ // directly instead of loading them from a file.
51+ func TLSData (tlsData string ) BasicClientOption {
52+ return func (bc * basicClientOptions ) {
53+ bc .tlsData = tlsData
54+ }
55+ }
56+
57+ // MacaroonData is a basic client option that sets macaroon data (encoded as hex
58+ // string) directly instead of loading it from a file.
59+ func MacaroonData (macData string ) BasicClientOption {
60+ return func (bc * basicClientOptions ) {
61+ bc .macData = macData
62+ }
63+ }
64+
65+ // Insecure allows the basic client to establish an insecure (non-TLS)
66+ // connection to the RPC server.
67+ func Insecure () BasicClientOption {
68+ return func (bc * basicClientOptions ) {
69+ bc .insecure = true
70+ }
71+ }
72+
73+ // SystemCerts instructs the basic client to use the system's certificate trust
74+ // store for verifying the TLS certificate of the RPC server.
75+ func SystemCerts () BasicClientOption {
76+ return func (bc * basicClientOptions ) {
77+ bc .systemCerts = true
78+ }
79+ }
80+
4481// applyBasicClientOptions updates a basicClientOptions set with functional
4582// options.
46- func (bc * basicClientOptions ) applyBasicClientOptions (options ... BasicClientOption ) {
83+ func (bc * basicClientOptions ) applyBasicClientOptions (
84+ options ... BasicClientOption ) {
85+
4786 for _ , option := range options {
4887 option (bc )
4988 }
@@ -53,9 +92,7 @@ func (bc *basicClientOptions) applyBasicClientOptions(options ...BasicClientOpti
5392// "basic" as it falls back to expected defaults if the arguments aren't
5493// provided.
5594func NewBasicClient (lndHost , tlsPath , macDir , network string ,
56- basicOptions ... BasicClientOption ) (
57-
58- lnrpc.LightningClient , error ) {
95+ basicOptions ... BasicClientOption ) (lnrpc.LightningClient , error ) {
5996
6097 conn , err := NewBasicConn (
6198 lndHost , tlsPath , macDir , network , basicOptions ... ,
@@ -70,67 +107,93 @@ func NewBasicClient(lndHost, tlsPath, macDir, network string,
70107// NewBasicConn creates a new basic gRPC connection to lnd. We call this
71108// connection "basic" as it falls back to expected defaults if the arguments
72109// aren't provided.
73- func NewBasicConn (lndHost , tlsPath , macDir , network string ,
74- basicOptions ... BasicClientOption ) (
75-
76- * grpc.ClientConn , error ) {
110+ func NewBasicConn (lndHost string , tlsPath , macDir , network string ,
111+ basicOptions ... BasicClientOption ) (* grpc.ClientConn , error ) {
77112
78- if tlsPath == "" {
79- tlsPath = defaultTLSCertPath
113+ creds , mac , err := parseTLSAndMacaroon (
114+ tlsPath , macDir , network , basicOptions ... ,
115+ )
116+ if err != nil {
117+ return nil , err
80118 }
81119
82- // Load the specified TLS certificate and build transport credentials
83- creds , err := credentials . NewClientTLSFromFile ( tlsPath , "" )
120+ // Now we append the macaroon credentials to the dial options.
121+ cred , err := macaroons . NewMacaroonCredential ( mac )
84122 if err != nil {
85- return nil , err
123+ return nil , fmt .Errorf ("error creating macaroon credential: %v" ,
124+ err )
86125 }
87126
88127 // Create a dial options array.
89128 opts := []grpc.DialOption {
90129 grpc .WithTransportCredentials (creds ),
130+ grpc .WithPerRPCCredentials (cred ),
131+ grpc .WithDefaultCallOptions (maxMsgRecvSize ),
91132 }
92133
93- if macDir == "" {
94- macDir = filepath .Join (
95- defaultLndDir , defaultDataDir , defaultChainSubDir ,
96- "bitcoin" , network ,
97- )
134+ // We need to use a custom dialer so we can also connect to unix sockets
135+ // and not just TCP addresses.
136+ opts = append (
137+ opts , grpc .WithContextDialer (
138+ lncfg .ClientAddressDialer (defaultRPCPort ),
139+ ),
140+ )
141+ conn , err := grpc .Dial (lndHost , opts ... )
142+ if err != nil {
143+ return nil , fmt .Errorf ("unable to connect to RPC server: %v" ,
144+ err )
98145 }
99146
147+ return conn , nil
148+ }
149+
150+ // parseTLSAndMacaroon looks to see if the TLS certificate and macaroon were
151+ // passed in as a path or as straight-up data, and processes it accordingly, so
152+ // it can be passed into grpc to establish a connection with LND.
153+ func parseTLSAndMacaroon (tlsPath , macDir , network string ,
154+ basicOptions ... BasicClientOption ) (credentials.TransportCredentials ,
155+ * macaroon.Macaroon , error ) {
156+
100157 // Starting with the set of default options, we'll apply any specified
101158 // functional options to the basic client.
102159 bco := defaultBasicClientOptions ()
103160 bco .applyBasicClientOptions (basicOptions ... )
104161
105- macPath := filepath .Join (macDir , bco .macFilename )
162+ creds , err := GetTLSCredentials (
163+ bco .tlsData , tlsPath , bco .insecure , bco .systemCerts ,
164+ )
165+ if err != nil {
166+ return nil , nil , err
167+ }
106168
107- // Load the specified macaroon file.
108- macBytes , err := ioutil .ReadFile (macPath )
109- if err == nil {
110- // Only if file is found
111- mac := & macaroon.Macaroon {}
112- if err = mac .UnmarshalBinary (macBytes ); err != nil {
113- return nil , fmt .Errorf ("unable to decode macaroon: %v" ,
114- err )
169+ var macBytes []byte
170+ mac := & macaroon.Macaroon {}
171+ if bco .macData != "" {
172+ macBytes , err = hex .DecodeString (bco .macData )
173+ if err != nil {
174+ return nil , nil , err
115175 }
176+ } else {
177+ if macDir == "" {
178+ macDir = filepath .Join (
179+ defaultLndDir , defaultDataDir , defaultChainSubDir ,
180+ "bitcoin" , network ,
181+ )
182+ }
183+
184+ macPath := filepath .Join (macDir , bco .macFilename )
116185
117- // Now we append the macaroon credentials to the dial options.
118- cred := macaroons .NewMacaroonCredential (mac )
119- opts = append (opts , grpc .WithPerRPCCredentials (cred ))
120- opts = append (opts , grpc .WithDefaultCallOptions (maxMsgRecvSize ))
186+ // Load the specified macaroon file.
187+ macBytes , err = ioutil .ReadFile (macPath )
188+ if err != nil {
189+ return nil , nil , err
190+ }
121191 }
122192
123- // We need to use a custom dialer so we can also connect to unix sockets
124- // and not just TCP addresses.
125- opts = append (
126- opts , grpc .WithContextDialer (
127- lncfg .ClientAddressDialer (defaultRPCPort ),
128- ),
129- )
130- conn , err := grpc .Dial (lndHost , opts ... )
131- if err != nil {
132- return nil , fmt .Errorf ("unable to connect to RPC server: %v" , err )
193+ if err = mac .UnmarshalBinary (macBytes ); err != nil {
194+ return nil , nil , fmt .Errorf ("unable to decode macaroon: %v" ,
195+ err )
133196 }
134197
135- return conn , nil
198+ return creds , mac , nil
136199}
0 commit comments