cmd/litcli: add litcli for session functions

This commit is contained in:
Elle Mouton 2021-10-29 14:50:32 +02:00 committed by jamaljsr
parent 13429b8fc0
commit 9b84dbc7c9
No known key found for this signature in database
GPG key ID: 8680860C961AD657
9 changed files with 523 additions and 31 deletions

1
.gitignore vendored
View file

@ -2,6 +2,7 @@
.env*.local
litd-debug
litcli-debug
/lightning-terminal-*
# MacOS junk

View file

@ -64,6 +64,7 @@ EXPOSE 8443 10009 9735
# Copy the binaries and entrypoint from the builder image.
COPY --from=golangbuilder /go/bin/litd /bin/
COPY --from=golangbuilder /go/bin/litcli /bin/
COPY --from=golangbuilder /go/bin/lncli /bin/
COPY --from=golangbuilder /go/bin/frcli /bin/
COPY --from=golangbuilder /go/bin/loop /bin/

View file

@ -108,10 +108,12 @@ install: app-build go-install
go-build:
@$(call print, "Building lightning-terminal.")
$(GOBUILD) -tags="$(LND_RELEASE_TAGS)" -ldflags "$(LDFLAGS)" -o litd-debug $(PKG)/cmd/litd
$(GOBUILD) -tags="$(LND_RELEASE_TAGS)" -ldflags "$(LDFLAGS)" -o litcli-debug $(PKG)/cmd/litcli
go-install:
@$(call print, "Installing lightning-terminal.")
$(GOINSTALL) -tags="$(LND_RELEASE_TAGS)" -ldflags "$(LDFLAGS)" $(PKG)/cmd/litd
$(GOINSTALL) -tags="$(LND_RELEASE_TAGS)" -ldflags "$(LDFLAGS)" $(PKG)/cmd/litcli
go-install-cli:
@$(call print, "Installing all CLI binaries.")

251
cmd/litcli/main.go Normal file
View file

@ -0,0 +1,251 @@
package main
import (
"context"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
terminal "github.com/lightninglabs/lightning-terminal"
"github.com/lightninglabs/lightning-terminal/litrpc"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/protobuf-hex-display/jsonpb"
"github.com/lightninglabs/protobuf-hex-display/proto"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/urfave/cli"
"golang.org/x/term"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
const (
// uiPasswordEnvName is the name of the environment variable under which
// we look for the UI password for litcli.
uiPasswordEnvName = "UI_PASSWORD"
)
var (
// maxMsgRecvSize is the largest message our client will receive. We
// set this to 200MiB atm.
maxMsgRecvSize = grpc.MaxCallRecvMsgSize(1 * 1024 * 1024 * 200)
baseDirFlag = cli.StringFlag{
Name: "basedir",
Value: terminal.DefaultLitDir,
Usage: "path to lit's base directory",
}
networkFlag = cli.StringFlag{
Name: "network, n",
Usage: "the network litd is running on e.g. mainnet, " +
"testnet, etc.",
Value: terminal.DefaultNetwork,
}
tlsCertFlag = cli.StringFlag{
Name: "tlscertpath",
Usage: "path to lit's TLS certificate",
Value: terminal.DefaultTLSCertPath,
}
lndMode = cli.StringFlag{
Name: "lndmode",
Usage: "the mode that lnd is running in: remote or integrated",
Value: terminal.ModeIntegrated,
}
lndTlsCertFlag = cli.StringFlag{
Name: "lndtlscertpath",
Usage: "path to lnd's TLS certificate",
Value: lnd.DefaultConfig().TLSCertPath,
}
uiPasswordFlag = cli.StringFlag{
Name: "uipassword",
Usage: "the UI password for authenticating against LiT; if " +
"not specified will read from environment variable " +
uiPasswordEnvName + " or prompt on terminal if both " +
"values are empty",
}
)
func main() {
app := cli.NewApp()
app.Name = "litcli"
app.Usage = "control plane for your Lightning Terminal (lit) daemon"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "rpcserver",
Value: "localhost:8443",
Usage: "lit daemon address host:port",
},
networkFlag,
baseDirFlag,
lndMode,
tlsCertFlag,
lndTlsCertFlag,
uiPasswordFlag,
}
app.Commands = append(app.Commands, sessionCommands...)
err := app.Run(os.Args)
if err != nil {
fatal(err)
}
}
func fatal(err error) {
fmt.Fprintf(os.Stderr, "[litcli] %v\n", err)
os.Exit(1)
}
func getClient(ctx *cli.Context) (litrpc.SessionsClient, func(), error) {
rpcServer := ctx.GlobalString("rpcserver")
tlsCertPath, err := extractPathArgs(ctx)
if err != nil {
return nil, nil, err
}
conn, err := getClientConn(rpcServer, tlsCertPath)
if err != nil {
return nil, nil, err
}
cleanup := func() { _ = conn.Close() }
sessionsClient := litrpc.NewSessionsClient(conn)
return sessionsClient, cleanup, nil
}
func getClientConn(address, tlsCertPath string) (*grpc.ClientConn, error) {
opts := []grpc.DialOption{
grpc.WithDefaultCallOptions(maxMsgRecvSize),
}
// TLS cannot be disabled, we'll always have a cert file to read.
creds, err := credentials.NewClientTLSFromFile(tlsCertPath, "")
if err != nil {
fatal(err)
}
opts = append(opts, grpc.WithTransportCredentials(creds))
conn, err := grpc.Dial(address, opts...)
if err != nil {
return nil, fmt.Errorf("unable to connect to RPC server: %v",
err)
}
return conn, nil
}
// extractPathArgs parses the TLS certificate from the command.
func extractPathArgs(ctx *cli.Context) (string, error) {
// We'll start off by parsing the network. This is needed to determine
// the correct path to the TLS certificate and macaroon when not
// specified.
networkStr := strings.ToLower(ctx.GlobalString("network"))
_, err := lndclient.Network(networkStr).ChainParams()
if err != nil {
return "", err
}
// We'll now fetch the basedir so we can make a decision on how to
// properly read the cert. This will either be the default,
// or will have been overwritten by the end user.
baseDir := lncfg.CleanAndExpandPath(ctx.GlobalString(baseDirFlag.Name))
lndmode := strings.ToLower(ctx.GlobalString(lndMode.Name))
if lndmode == terminal.ModeIntegrated {
tlsCertPath := lncfg.CleanAndExpandPath(ctx.GlobalString(
lndTlsCertFlag.Name,
))
return tlsCertPath, nil
}
tlsCertPath := lncfg.CleanAndExpandPath(ctx.GlobalString(
tlsCertFlag.Name,
))
// If a custom base directory was set, we'll also check if custom paths
// for the TLS cert file was set as well. If not, we'll override the
// paths so they can be found within the custom base directory set.
// This allows us to set a custom base directory, along with custom
// paths to the TLS cert file.
if baseDir != terminal.DefaultLitDir || networkStr != terminal.DefaultNetwork {
tlsCertPath = filepath.Join(
baseDir, networkStr, terminal.DefaultTLSCertFilename,
)
}
return tlsCertPath, nil
}
func printRespJSON(resp proto.Message) { // nolint
jsonMarshaler := &jsonpb.Marshaler{
EmitDefaults: true,
OrigName: true,
Indent: "\t", // Matches indentation of printJSON.
}
jsonStr, err := jsonMarshaler.MarshalToString(resp)
if err != nil {
fmt.Println("unable to decode response: ", err)
return
}
fmt.Println(jsonStr)
}
func getAuthContext(cliCtx *cli.Context) context.Context {
uiPassword, err := getUIPassword(cliCtx)
if err != nil {
fatal(err)
}
basicAuth := base64.StdEncoding.EncodeToString(
[]byte(fmt.Sprintf("%s:%s", uiPassword, uiPassword)),
)
ctxb := context.Background()
md := metadata.MD{}
md.Set("macaroon", "no-macaroons-for-litcli")
md.Set("authorization", fmt.Sprintf("Basic %s", basicAuth))
return metadata.NewOutgoingContext(ctxb, md)
}
func getUIPassword(ctx *cli.Context) (string, error) {
// The command line flag has precedence.
uiPassword := strings.TrimSpace(ctx.GlobalString(uiPasswordFlag.Name))
// To automate things with litcli, we also offer reading the password
// from environment variables if the flag wasn't specified.
if uiPassword == "" {
uiPassword = strings.TrimSpace(os.Getenv(uiPasswordEnvName))
}
if uiPassword == "" {
// If there's no value in the environment, we'll now prompt the
// user to enter their password on the terminal.
fmt.Printf("Input your LiT UI password: ")
// The variable syscall.Stdin is of a different type in the
// Windows API that's why we need the explicit cast. And of
// course the linter doesn't like it either.
pw, err := term.ReadPassword(int(syscall.Stdin)) // nolint:unconvert
fmt.Println()
if err != nil {
return "", err
}
uiPassword = strings.TrimSpace(string(pw))
}
if uiPassword == "" {
return "", fmt.Errorf("no UI password provided")
}
return uiPassword, nil
}

232
cmd/litcli/sessions.go Normal file
View file

@ -0,0 +1,232 @@
package main
import (
"encoding/hex"
"fmt"
"time"
"github.com/lightninglabs/lightning-terminal/litrpc"
"github.com/urfave/cli"
)
var sessionCommands = []cli.Command{
{
Name: "sessions",
ShortName: "s",
Usage: "manage Terminal Web sessions",
Category: "Sessions",
Subcommands: []cli.Command{
addSessionCommand,
listSessionCommand,
revokeSessionCommand,
},
},
}
var addSessionCommand = cli.Command{
Name: "add",
ShortName: "a",
Usage: "create a new Terminal Web session",
Description: "Add a new active session.",
Action: addSession,
Flags: []cli.Flag{
cli.StringFlag{
Name: "label",
Usage: "session label",
},
cli.Uint64Flag{
Name: "expiry",
Usage: "number of seconds that the session should " +
"remain active",
Value: uint64(time.Hour.Seconds()),
},
cli.StringFlag{
Name: "mailboxserveraddr",
Usage: "the host:port of the mailbox server to be used",
Value: "mailbox.staging.lightningcluster.com:443",
},
cli.BoolFlag{
Name: "devserver",
Usage: "set to true to skip verification of the " +
"server's tls cert.",
},
},
}
func addSession(ctx *cli.Context) error {
client, cleanup, err := getClient(ctx)
if err != nil {
return err
}
defer cleanup()
label := ctx.String("label")
if label == "" {
return fmt.Errorf("must set a label for the session")
}
sessionLength := time.Second * time.Duration(ctx.Uint64("expiry"))
sessionExpiry := time.Now().Add(sessionLength).Unix()
resp, err := client.AddSession(
getAuthContext(ctx), &litrpc.AddSessionRequest{
Label: label,
SessionType: litrpc.SessionType_TYPE_UI_PASSWORD,
ExpiryTimestampSeconds: uint64(sessionExpiry),
MailboxServerAddr: ctx.String("mailboxserveraddr"),
DevServer: ctx.Bool("devserver"),
},
)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var listSessionCommand = cli.Command{
Name: "list",
ShortName: "l",
Usage: "list Terminal Web sessions",
Description: "List sessions.",
Subcommands: []cli.Command{
listAllSessionsCommand,
listRevokedSessions,
listInUseSessions,
listExpiredSessions,
listCreatedSessions,
},
}
var listAllSessionsCommand = cli.Command{
Name: "all",
ShortName: "a",
Usage: "list all Terminal Web sessions",
Description: "List all sessions.",
Action: listSessions(sessionFilterAll),
}
var listRevokedSessions = cli.Command{
Name: "revoked",
ShortName: "r",
Usage: "list revoked Terminal Web sessions",
Description: "List revoked sessions.",
Action: listSessions(sessionFilterRevoked),
}
var listInUseSessions = cli.Command{
Name: "inuse",
ShortName: "u",
Usage: "list in-use Terminal Web sessions",
Description: "List in-use sessions.",
Action: listSessions(sessionFilterInUse),
}
var listExpiredSessions = cli.Command{
Name: "expired",
ShortName: "e",
Usage: "list expired Terminal Web sessions",
Description: "List expired sessions.",
Action: listSessions(sessionFilterExpired),
}
var listCreatedSessions = cli.Command{
Name: "created",
ShortName: "c",
Usage: "list created Terminal Web sessions",
Description: "List created sessions.",
Action: listSessions(sessionFilterCreated),
}
type sessionFilter uint32
const (
sessionFilterAll sessionFilter = iota
sessionFilterExpired
sessionFilterInUse
sessionFilterRevoked
sessionFilterCreated
)
var sessionStateMap = map[litrpc.SessionState]sessionFilter{
litrpc.SessionState_STATE_CREATED: sessionFilterCreated,
litrpc.SessionState_STATE_EXPIRED: sessionFilterExpired,
litrpc.SessionState_STATE_IN_USE: sessionFilterInUse,
litrpc.SessionState_STATE_REVOKED: sessionFilterRevoked,
}
func listSessions(filter sessionFilter) func(ctx *cli.Context) error {
return func(ctx *cli.Context) error {
client, cleanup, err := getClient(ctx)
if err != nil {
return err
}
defer cleanup()
resp, err := client.ListSessions(
getAuthContext(ctx), &litrpc.ListSessionsRequest{},
)
if err != nil {
return err
}
if filter == sessionFilterAll {
printRespJSON(resp)
return nil
}
var sessions []*litrpc.Session
for _, session := range resp.Sessions {
if sessionStateMap[session.SessionState] != filter {
continue
}
sessions = append(sessions, session)
}
printRespJSON(&litrpc.ListSessionsResponse{Sessions: sessions})
return nil
}
}
var revokeSessionCommand = cli.Command{
Name: "revoke",
ShortName: "r",
Usage: "revoke a Terminal Web session",
Description: "Revoke an active session",
Action: revokeSession,
Flags: []cli.Flag{
cli.StringFlag{
Name: "localpubkey",
Usage: "local pubkey of the session to revoke",
},
},
}
func revokeSession(ctx *cli.Context) error {
client, cleanup, err := getClient(ctx)
if err != nil {
return err
}
defer cleanup()
pubkey, err := hex.DecodeString(ctx.String("localpubkey"))
if err != nil {
return err
}
resp, err := client.RevokeSession(
getAuthContext(ctx), &litrpc.RevokeSessionRequest{
LocalPublicKey: pubkey,
},
)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}

View file

@ -39,7 +39,7 @@ const (
ModeIntegrated = "integrated"
ModeRemote = "remote"
defaultLndMode = ModeRemote
DefaultLndMode = ModeRemote
defaultFaradayMode = ModeIntegrated
defaultLoopMode = ModeIntegrated
defaultPoolMode = ModeIntegrated
@ -57,10 +57,10 @@ const (
defaultLogDirname = "logs"
defaultLogFilename = "litd.log"
defaultTLSCertFilename = "tls.cert"
defaultTLSKeyFilename = "tls.key"
DefaultTLSCertFilename = "tls.cert"
DefaultTLSKeyFilename = "tls.key"
defaultNetwork = "mainnet"
DefaultNetwork = "mainnet"
defaultRemoteLndRpcServer = "localhost:10009"
defaultRemoteFaradayRpcServer = "localhost:8465"
defaultRemoteLoopRpcServer = "localhost:11010"
@ -81,43 +81,43 @@ var (
loopDefaultConfig = loopd.DefaultConfig()
poolDefaultConfig = pool.DefaultConfig()
// defaultLitDir is the default directory where LiT tries to find its
// DefaultLitDir is the default directory where LiT tries to find its
// configuration file and store its data (in remote lnd node). This is a
// directory in the user's application data, for example:
// C:\Users\<username>\AppData\Local\Lit on Windows
// ~/.lit on Linux
// ~/Library/Application Support/Lit on MacOS
defaultLitDir = btcutil.AppDataDir("lit", false)
DefaultLitDir = btcutil.AppDataDir("lit", false)
// defaultTLSCertPath is the default full path of the autogenerated TLS
// DefaultTLSCertPath is the default full path of the autogenerated TLS
// certificate that is created in remote lnd mode.
defaultTLSCertPath = filepath.Join(
defaultLitDir, defaultTLSCertFilename,
DefaultTLSCertPath = filepath.Join(
DefaultLitDir, DefaultTLSCertFilename,
)
// defaultTLSKeyPath is the default full path of the autogenerated TLS
// key that is created in remote lnd mode.
defaultTLSKeyPath = filepath.Join(defaultLitDir, defaultTLSKeyFilename)
defaultTLSKeyPath = filepath.Join(DefaultLitDir, DefaultTLSKeyFilename)
// defaultConfigFile is the default path for the LiT configuration file
// that is always attempted to be loaded.
defaultConfigFile = filepath.Join(defaultLitDir, defaultConfigFilename)
defaultConfigFile = filepath.Join(DefaultLitDir, defaultConfigFilename)
// defaultLogDir is the default directory in which LiT writes its log
// files in remote lnd mode.
defaultLogDir = filepath.Join(defaultLitDir, defaultLogDirname)
defaultLogDir = filepath.Join(DefaultLitDir, defaultLogDirname)
// defaultLetsEncryptDir is the default directory in which LiT writes
// its Let's Encrypt files.
defaultLetsEncryptDir = filepath.Join(
defaultLitDir, defaultLetsEncryptSubDir,
DefaultLitDir, defaultLetsEncryptSubDir,
)
// defaultRemoteLndMacaroonPath is the default path we assume for a
// DefaultRemoteLndMacaroonPath is the default path we assume for a
// local lnd node to store its admin.macaroon file at.
defaultRemoteLndMacaroonPath = filepath.Join(
DefaultRemoteLndMacaroonPath = filepath.Join(
lndDefaultConfig.DataDir, defaultLndChainSubDir,
defaultLndChain, defaultNetwork, defaultLndMacaroon,
defaultLndChain, DefaultNetwork, defaultLndMacaroon,
)
)
@ -263,7 +263,7 @@ func defaultConfig() *Config {
return &Config{
HTTPSListen: defaultHTTPSListen,
Remote: &RemoteConfig{
LitTLSCertPath: defaultTLSCertPath,
LitTLSCertPath: DefaultTLSCertPath,
LitTLSKeyPath: defaultTLSKeyPath,
LitDebugLevel: defaultLogLevel,
LitLogDir: defaultLogDir,
@ -271,7 +271,7 @@ func defaultConfig() *Config {
LitMaxLogFileSize: defaultMaxLogFileSize,
Lnd: &RemoteDaemonConfig{
RPCServer: defaultRemoteLndRpcServer,
MacaroonPath: defaultRemoteLndMacaroonPath,
MacaroonPath: DefaultRemoteLndMacaroonPath,
TLSCertPath: lndDefaultConfig.TLSCertPath,
},
Faraday: &RemoteDaemonConfig{
@ -290,10 +290,10 @@ func defaultConfig() *Config {
TLSCertPath: poolDefaultConfig.TLSCertPath,
},
},
Network: defaultNetwork,
LndMode: defaultLndMode,
Network: DefaultNetwork,
LndMode: DefaultLndMode,
Lnd: &lndDefaultConfig,
LitDir: defaultLitDir,
LitDir: DefaultLitDir,
LetsEncryptListen: defaultLetsEncryptListen,
LetsEncryptDir: defaultLetsEncryptDir,
ConfigFile: defaultConfigFile,
@ -367,7 +367,7 @@ func loadAndValidateConfig(interceptor signal.Interceptor) (*Config, error) {
// Validate the lightning-terminal config options.
litDir := lnd.CleanAndExpandPath(preCfg.LitDir)
cfg.LetsEncryptDir = lncfg.CleanAndExpandPath(cfg.LetsEncryptDir)
if litDir != defaultLitDir {
if litDir != DefaultLitDir {
if cfg.LetsEncryptDir == defaultLetsEncryptDir {
cfg.LetsEncryptDir = filepath.Join(
litDir, defaultLetsEncryptSubDir,
@ -427,7 +427,7 @@ func loadAndValidateConfig(interceptor signal.Interceptor) (*Config, error) {
// remote mode and not mainnet, we want to update our default paths for
// the remote connection as well.
defaultFaradayCfg := faraday.DefaultConfig()
if cfg.faradayRemote && cfg.Network != defaultNetwork {
if cfg.faradayRemote && cfg.Network != DefaultNetwork {
if cfg.Remote.Faraday.MacaroonPath == defaultFaradayCfg.MacaroonPath {
cfg.Remote.Faraday.MacaroonPath = cfg.Faraday.MacaroonPath
}
@ -451,7 +451,7 @@ func loadAndValidateConfig(interceptor signal.Interceptor) (*Config, error) {
}
}
if cfg.loopRemote && cfg.Network != defaultNetwork {
if cfg.loopRemote && cfg.Network != DefaultNetwork {
if cfg.Remote.Loop.MacaroonPath == defaultLoopCfg.MacaroonPath {
cfg.Remote.Loop.MacaroonPath = cfg.Loop.MacaroonPath
}
@ -461,7 +461,7 @@ func loadAndValidateConfig(interceptor signal.Interceptor) (*Config, error) {
}
defaultPoolCfg := pool.DefaultConfig()
if cfg.poolRemote && cfg.Network != defaultNetwork {
if cfg.poolRemote && cfg.Network != DefaultNetwork {
if cfg.Remote.Pool.MacaroonPath == defaultPoolCfg.MacaroonPath {
cfg.Remote.Pool.MacaroonPath = cfg.Pool.MacaroonPath
}
@ -484,7 +484,7 @@ func loadConfigFile(preCfg *Config, interceptor signal.Interceptor) (*Config,
// file within it.
litDir := lnd.CleanAndExpandPath(preCfg.LitDir)
configFilePath := lnd.CleanAndExpandPath(preCfg.ConfigFile)
if litDir != defaultLitDir {
if litDir != DefaultLitDir {
if configFilePath == defaultConfigFile {
configFilePath = filepath.Join(
litDir, defaultConfigFilename,
@ -576,8 +576,8 @@ func validateRemoteModeConfig(cfg *Config) error {
// need to adjust the default macaroon directory so the user can only
// specify --network=testnet for example if everything else is using
// the defaults.
if cfg.Network != defaultNetwork &&
r.Lnd.MacaroonPath == defaultRemoteLndMacaroonPath {
if cfg.Network != DefaultNetwork &&
r.Lnd.MacaroonPath == DefaultRemoteLndMacaroonPath {
r.Lnd.MacaroonPath = filepath.Join(
defaultLndCfg.DataDir, defaultLndChainSubDir,
@ -589,9 +589,9 @@ func validateRemoteModeConfig(cfg *Config) error {
// If the provided lit directory is not the default, we'll modify the
// path to all of the files and directories that will live within it.
litDir := lnd.CleanAndExpandPath(cfg.LitDir)
if litDir != defaultLitDir {
r.LitTLSCertPath = filepath.Join(litDir, defaultTLSCertFilename)
r.LitTLSKeyPath = filepath.Join(litDir, defaultTLSKeyFilename)
if litDir != DefaultLitDir {
r.LitTLSCertPath = filepath.Join(litDir, DefaultTLSCertFilename)
r.LitTLSKeyPath = filepath.Join(litDir, DefaultTLSKeyFilename)
r.LitLogDir = filepath.Join(litDir, defaultLogDirname)
}

View file

@ -41,6 +41,7 @@ EXPOSE 8443 10009 9735
# Copy the binaries and entrypoint from the builder image.
COPY --from=golangbuilder /go/bin/litd /bin/
COPY --from=golangbuilder /go/bin/litcli /bin/
COPY --from=golangbuilder /go/bin/lncli /bin/
COPY --from=golangbuilder /go/bin/frcli /bin/
COPY --from=golangbuilder /go/bin/loop /bin/

3
go.mod
View file

@ -13,14 +13,17 @@ require (
github.com/lightninglabs/lndclient v0.14.0-5
github.com/lightninglabs/loop v0.15.1-beta
github.com/lightninglabs/pool v0.5.2-alpha
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
github.com/lightningnetwork/lnd v0.14.0-beta
github.com/lightningnetwork/lnd/cert v1.1.0
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76
github.com/rs/cors v1.7.0 // indirect
github.com/stretchr/testify v1.7.0
github.com/urfave/cli v1.20.0
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
google.golang.org/grpc v1.39.0
google.golang.org/protobuf v1.27.1
gopkg.in/macaroon-bakery.v2 v2.1.0

View file

@ -70,6 +70,7 @@ function build_release() {
green " - Building: ${os} ${arch} ${arm} with build tags '${buildtags}'"
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=$arm go build -v -trimpath -ldflags="${ldflags}" -tags="${buildtags}" ${PKG}/cmd/litd
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=$arm go build -v -trimpath -ldflags="${ldflags}" -tags="${buildtags}" ${PKG}/cmd/litcli
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=$arm go build -v -trimpath -ldflags="${ldflags}" -tags="${buildtags}" ${LND_PKG}/cmd/lncli
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=$arm go build -v -trimpath -ldflags="${ldflags}" -tags="${buildtags}" ${FARADAY_PKG}/cmd/frcli
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=$arm go build -v -trimpath -ldflags="${ldflags}" -tags="${buildtags}" ${LOOP_PKG}/cmd/loop