@@ -6,15 +6,20 @@ import (
66 "fmt"
77 "io/ioutil"
88 "os"
9+ "path/filepath"
910 "strconv"
11+ "strings"
1012 "time"
1113
14+ "github.com/lightninglabs/lndclient"
1215 "github.com/lightninglabs/loop"
16+ "github.com/lightninglabs/loop/loopd"
1317 "github.com/lightninglabs/loop/looprpc"
1418 "github.com/lightninglabs/loop/swap"
1519 "github.com/lightninglabs/protobuf-hex-display/json"
1620 "github.com/lightninglabs/protobuf-hex-display/jsonpb"
1721 "github.com/lightninglabs/protobuf-hex-display/proto"
22+ "github.com/lightningnetwork/lnd/lncfg"
1823 "github.com/lightningnetwork/lnd/macaroons"
1924
2025 "github.com/btcsuite/btcutil"
@@ -43,10 +48,22 @@ var (
4348 // that we set when sending it over the line.
4449 defaultMacaroonTimeout int64 = 60
4550
51+ loopDirFlag = cli.StringFlag {
52+ Name : "loopdir" ,
53+ Value : loopd .LoopDirBase ,
54+ Usage : "path to loop's base directory" ,
55+ }
56+ networkFlag = cli.StringFlag {
57+ Name : "network, n" ,
58+ Usage : "the network loop is running on e.g. mainnet, " +
59+ "testnet, etc." ,
60+ Value : loopd .DefaultNetwork ,
61+ }
62+
4663 tlsCertFlag = cli.StringFlag {
47- Name : "tlscertpath" ,
48- Usage : "path to loop's TLS certificate, only needed if loop " +
49- "runs in the same process as lnd" ,
64+ Name : "tlscertpath" ,
65+ Usage : "path to loop's TLS certificate" ,
66+ Value : loopd . DefaultTLSCertPath ,
5067 }
5168 macaroonPathFlag = cli.StringFlag {
5269 Name : "macaroonpath" ,
@@ -103,6 +120,8 @@ func main() {
103120 Value : "localhost:11010" ,
104121 Usage : "loopd daemon address host:port" ,
105122 },
123+ networkFlag ,
124+ loopDirFlag ,
106125 tlsCertFlag ,
107126 macaroonPathFlag ,
108127 }
@@ -121,8 +140,10 @@ func main() {
121140
122141func getClient (ctx * cli.Context ) (looprpc.SwapClientClient , func (), error ) {
123142 rpcServer := ctx .GlobalString ("rpcserver" )
124- tlsCertPath := ctx .GlobalString (tlsCertFlag .Name )
125- macaroonPath := ctx .GlobalString (macaroonPathFlag .Name )
143+ tlsCertPath , macaroonPath , err := extractPathArgs (ctx )
144+ if err != nil {
145+ return nil , nil , err
146+ }
126147 conn , err := getClientConn (rpcServer , tlsCertPath , macaroonPath )
127148 if err != nil {
128149 return nil , nil , err
@@ -137,6 +158,40 @@ func getMaxRoutingFee(amt btcutil.Amount) btcutil.Amount {
137158 return swap .CalcFee (amt , maxRoutingFeeBase , maxRoutingFeeRate )
138159}
139160
161+ // extractPathArgs parses the TLS certificate and macaroon paths from the
162+ // command.
163+ func extractPathArgs (ctx * cli.Context ) (string , string , error ) {
164+ // We'll start off by parsing the network. This is needed to determine
165+ // the correct path to the TLS certificate and macaroon when not
166+ // specified.
167+ networkStr := strings .ToLower (ctx .GlobalString ("network" ))
168+ _ , err := lndclient .Network (networkStr ).ChainParams ()
169+ if err != nil {
170+ return "" , "" , err
171+ }
172+
173+ // We'll now fetch the loopdir so we can make a decision on how to
174+ // properly read the cert. This will either be the default, or will have
175+ // been overwritten by the end user.
176+ loopDir := lncfg .CleanAndExpandPath (ctx .GlobalString (loopDirFlag .Name ))
177+ tlsCertPath := lncfg .CleanAndExpandPath (ctx .GlobalString (
178+ tlsCertFlag .Name ,
179+ ))
180+
181+ // If a custom lnd directory was set, we'll also check if custom paths
182+ // for the TLS cert file were set as well. If not, we'll override their
183+ // paths so they can be found within the custom loop directory set. This
184+ // allows us to set a custom lnd directory, along with custom paths to
185+ // the TLS cert file.
186+ if loopDir != loopd .LoopDirBase || networkStr != loopd .DefaultNetwork {
187+ tlsCertPath = filepath .Join (
188+ loopDir , networkStr , loopd .DefaultTLSCertFilename ,
189+ )
190+ }
191+
192+ return tlsCertPath , ctx .GlobalString (macaroonPathFlag .Name ), nil
193+ }
194+
140195type inLimits struct {
141196 maxMinerFee btcutil.Amount
142197 maxSwapFee btcutil.Amount
@@ -322,49 +377,44 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn,
322377 grpc .WithDefaultCallOptions (maxMsgRecvSize ),
323378 }
324379
325- switch {
326- // If a TLS certificate file is specified, we need to load it and build
327- // transport credentials with it.
328- case tlsCertPath != "" :
329- creds , err := credentials .NewClientTLSFromFile (tlsCertPath , "" )
330- if err != nil {
331- fatal (err )
332- }
380+ // TLS cannot be disabled, we'll always have a cert file to read.
381+ creds , err := credentials .NewClientTLSFromFile (tlsCertPath , "" )
382+ if err != nil {
383+ return nil , err
384+ }
333385
334- // Macaroons are only allowed to be transmitted over a TLS
335- // enabled connection.
336- if macaroonPath != "" {
337- opts = append (opts , readMacaroon (macaroonPath ))
386+ // Macaroons are not yet enabled by default.
387+ if macaroonPath != "" {
388+ macOption , err := readMacaroon (macaroonPath )
389+ if err != nil {
390+ return nil , err
338391 }
339-
340- opts = append (opts , grpc .WithTransportCredentials (creds ))
341-
342- // By default, if no certificate is supplied, we assume the RPC server
343- // runs without TLS.
344- default :
345- opts = append (opts , grpc .WithInsecure ())
392+ opts = append (opts , macOption )
346393 }
347394
395+ opts = append (opts , grpc .WithTransportCredentials (creds ))
396+
348397 conn , err := grpc .Dial (address , opts ... )
349398 if err != nil {
350- return nil , fmt .Errorf ("unable to connect to RPC server: %v" , err )
399+ return nil , fmt .Errorf ("unable to connect to RPC server: %v" ,
400+ err )
351401 }
352402
353403 return conn , nil
354404}
355405
356406// readMacaroon tries to read the macaroon file at the specified path and create
357407// gRPC dial options from it.
358- func readMacaroon (macPath string ) grpc.DialOption {
408+ func readMacaroon (macPath string ) ( grpc.DialOption , error ) {
359409 // Load the specified macaroon file.
360410 macBytes , err := ioutil .ReadFile (macPath )
361411 if err != nil {
362- fatal ( fmt .Errorf ("unable to read macaroon path : %v" , err ) )
412+ return nil , fmt .Errorf ("unable to read macaroon path : %v" , err )
363413 }
364414
365415 mac := & macaroon.Macaroon {}
366416 if err = mac .UnmarshalBinary (macBytes ); err != nil {
367- fatal ( fmt .Errorf ("unable to decode macaroon: %v" , err ) )
417+ return nil , fmt .Errorf ("unable to decode macaroon: %v" , err )
368418 }
369419
370420 macConstraints := []macaroons.Constraint {
@@ -384,10 +434,10 @@ func readMacaroon(macPath string) grpc.DialOption {
384434 // Apply constraints to the macaroon.
385435 constrainedMac , err := macaroons .AddConstraints (mac , macConstraints ... )
386436 if err != nil {
387- fatal ( err )
437+ return nil , err
388438 }
389439
390440 // Now we append the macaroon credentials to the dial options.
391441 cred := macaroons .NewMacaroonCredential (constrainedMac )
392- return grpc .WithPerRPCCredentials (cred )
442+ return grpc .WithPerRPCCredentials (cred ), nil
393443}
0 commit comments