From fd37c6f90a99b32710a78070b2902b6c68df2037 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 9 Oct 2024 08:34:59 +0200 Subject: [PATCH] cmd/commands: add mac_root_key flag to unlock commands This commit adds a new --mac_root_key flag to both the lncli create and lncli createwatchonly commands that allows the user to specify the macaroon root key that should be used when creating the macaroon database on wallet initialization. This allows for deterministic wallet initialization and baking of macaroons before the wallet is initialized. --- cmd/commands/cmd_walletunlocker.go | 56 +++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/cmd/commands/cmd_walletunlocker.go b/cmd/commands/cmd_walletunlocker.go index a0a286047..49a14b0e6 100644 --- a/cmd/commands/cmd_walletunlocker.go +++ b/cmd/commands/cmd_walletunlocker.go @@ -12,6 +12,7 @@ import ( "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" + "github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/walletunlocker" "github.com/urfave/cli" ) @@ -26,6 +27,13 @@ var ( Name: "save_to", Usage: "save returned admin macaroon to this file", } + macRootKeyFlag = cli.StringFlag{ + Name: "mac_root_key", + Usage: "macaroon root key to use when initializing the " + + "macaroon store; allows for deterministic macaroon " + + "generation; if not set, a random one will be " + + "created", + } ) var createCommand = cli.Command{ @@ -81,6 +89,7 @@ var createCommand = cli.Command{ }, statelessInitFlag, saveToFlag, + macRootKeyFlag, }, Action: actionDecorator(create), } @@ -261,6 +270,7 @@ mnemonicCheck: extendedRootKey string extendedRootKeyBirthday uint64 recoveryWindow int32 + macRootKey []byte ) switch { // Use an existing cipher seed mnemonic in the aezeed format. @@ -366,6 +376,23 @@ mnemonicCheck: printCipherSeedWords(cipherSeedMnemonic) } + // Parse the macaroon root key if it was specified by the user. + if ctx.IsSet(macRootKeyFlag.Name) { + macRootKey, err = hex.DecodeString( + ctx.String(macRootKeyFlag.Name), + ) + if err != nil { + return fmt.Errorf("unable to parse macaroon root key: "+ + "%w", err) + } + + if len(macRootKey) != macaroons.RootKeyLen { + return fmt.Errorf("macaroon root key must be exactly "+ + "%v bytes, got %v", macaroons.RootKeyLen, + len(macRootKey)) + } + } + // With either the user's prior cipher seed, or a newly generated one, // we'll go ahead and initialize the wallet. req := &lnrpc.InitWalletRequest{ @@ -377,6 +404,7 @@ mnemonicCheck: RecoveryWindow: recoveryWindow, ChannelBackups: chanBackups, StatelessInit: statelessInit, + MacaroonRootKey: macRootKey, } response, err := client.InitWallet(ctxc, req) if err != nil { @@ -687,6 +715,7 @@ var createWatchOnlyCommand = cli.Command{ Flags: []cli.Flag{ statelessInitFlag, saveToFlag, + macRootKeyFlag, }, Action: actionDecorator(createWatchOnly), } @@ -764,11 +793,30 @@ func createWatchOnly(ctx *cli.Context) error { } } + // Parse the macaroon root key if it was specified by the user. + var macRootKey []byte + if ctx.IsSet(macRootKeyFlag.Name) { + macRootKey, err = hex.DecodeString( + ctx.String(macRootKeyFlag.Name), + ) + if err != nil { + return fmt.Errorf("unable to parse macaroon root key: "+ + "%w", err) + } + + if len(macRootKey) != macaroons.RootKeyLen { + return fmt.Errorf("macaroon root key must be exactly "+ + "%v bytes, got %v", macaroons.RootKeyLen, + len(macRootKey)) + } + } + initResp, err := client.InitWallet(ctxc, &lnrpc.InitWalletRequest{ - WalletPassword: walletPassword, - WatchOnly: rpcResp, - RecoveryWindow: recoveryWindow, - StatelessInit: statelessInit, + WalletPassword: walletPassword, + WatchOnly: rpcResp, + RecoveryWindow: recoveryWindow, + StatelessInit: statelessInit, + MacaroonRootKey: macRootKey, }) if err != nil { return err