1
1
package lndclient
2
2
3
3
import (
4
+ "encoding/hex"
4
5
"fmt"
5
6
"io/ioutil"
6
7
"path/filepath"
@@ -13,23 +14,27 @@ import (
13
14
macaroon "gopkg.in/macaroon.v2"
14
15
)
15
16
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.
20
21
type BasicClientOption func (* basicClientOptions )
21
22
22
23
// basicClientOptions is a set of options that can configure the lnd client
23
24
// returned by NewBasicClient.
24
25
type basicClientOptions struct {
25
26
macFilename string
27
+ tlsData string
28
+ macData string
29
+ insecure bool
30
+ systemCerts bool
26
31
}
27
32
28
- // defaultBasicClientOptions returns a basicClientOptions set to lnd basic client
29
- // defaults.
33
+ // defaultBasicClientOptions returns a basicClientOptions set to lnd basic
34
+ // client defaults.
30
35
func defaultBasicClientOptions () * basicClientOptions {
31
36
return & basicClientOptions {
32
- macFilename : defaultAdminMacaroonFilename ,
37
+ macFilename : adminMacFilename ,
33
38
}
34
39
}
35
40
@@ -41,9 +46,43 @@ func MacFilename(macFilename string) BasicClientOption {
41
46
}
42
47
}
43
48
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
+
44
81
// applyBasicClientOptions updates a basicClientOptions set with functional
45
82
// options.
46
- func (bc * basicClientOptions ) applyBasicClientOptions (options ... BasicClientOption ) {
83
+ func (bc * basicClientOptions ) applyBasicClientOptions (
84
+ options ... BasicClientOption ) {
85
+
47
86
for _ , option := range options {
48
87
option (bc )
49
88
}
@@ -53,9 +92,7 @@ func (bc *basicClientOptions) applyBasicClientOptions(options ...BasicClientOpti
53
92
// "basic" as it falls back to expected defaults if the arguments aren't
54
93
// provided.
55
94
func NewBasicClient (lndHost , tlsPath , macDir , network string ,
56
- basicOptions ... BasicClientOption ) (
57
-
58
- lnrpc.LightningClient , error ) {
95
+ basicOptions ... BasicClientOption ) (lnrpc.LightningClient , error ) {
59
96
60
97
conn , err := NewBasicConn (
61
98
lndHost , tlsPath , macDir , network , basicOptions ... ,
@@ -70,67 +107,93 @@ func NewBasicClient(lndHost, tlsPath, macDir, network string,
70
107
// NewBasicConn creates a new basic gRPC connection to lnd. We call this
71
108
// connection "basic" as it falls back to expected defaults if the arguments
72
109
// 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 ) {
77
112
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
80
118
}
81
119
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 )
84
122
if err != nil {
85
- return nil , err
123
+ return nil , fmt .Errorf ("error creating macaroon credential: %v" ,
124
+ err )
86
125
}
87
126
88
127
// Create a dial options array.
89
128
opts := []grpc.DialOption {
90
129
grpc .WithTransportCredentials (creds ),
130
+ grpc .WithPerRPCCredentials (cred ),
131
+ grpc .WithDefaultCallOptions (maxMsgRecvSize ),
91
132
}
92
133
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 )
98
145
}
99
146
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
+
100
157
// Starting with the set of default options, we'll apply any specified
101
158
// functional options to the basic client.
102
159
bco := defaultBasicClientOptions ()
103
160
bco .applyBasicClientOptions (basicOptions ... )
104
161
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
+ }
106
168
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
115
175
}
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 )
116
185
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
+ }
121
191
}
122
192
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 )
133
196
}
134
197
135
- return conn , nil
198
+ return creds , mac , nil
136
199
}
0 commit comments