21c29c33d7
This commit reworks the macaroon authentication framework to use the v2 macaroon format and bakery API. It also replaces the code in each RPC method which calls the macaroon verifier with interceptors which call the macaroon verifier instead. In addition, the operation permissions are reworked to fit the new format of "allow" commands (specifically, entity/operation permissions instead of method permissions).
119 lines
3.6 KiB
Go
119 lines
3.6 KiB
Go
package walletunlocker
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
|
"github.com/roasbeef/btcd/chaincfg"
|
|
"github.com/roasbeef/btcwallet/wallet"
|
|
"golang.org/x/net/context"
|
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
|
)
|
|
|
|
// UnlockerService implements the WalletUnlocker service used to provide lnd
|
|
// with a password for wallet encryption at startup.
|
|
type UnlockerService struct {
|
|
// CreatePasswords is a channel where passwords provided by the rpc
|
|
// client to be used to initially create and encrypt a wallet will be
|
|
// sent.
|
|
CreatePasswords chan []byte
|
|
|
|
// UnlockPasswords is a channel where passwords provided by the rpc
|
|
// client to be used to unlock and decrypt an existing wallet will be
|
|
// sent.
|
|
UnlockPasswords chan []byte
|
|
|
|
chainDir string
|
|
netParams *chaincfg.Params
|
|
}
|
|
|
|
// New creates and returns a new UnlockerService.
|
|
func New(authSvc *bakery.Bakery, chainDir string,
|
|
params *chaincfg.Params) *UnlockerService {
|
|
return &UnlockerService{
|
|
CreatePasswords: make(chan []byte, 1),
|
|
UnlockPasswords: make(chan []byte, 1),
|
|
chainDir: chainDir,
|
|
netParams: params,
|
|
}
|
|
}
|
|
|
|
// CreateWallet will read the password provided in the CreateWalletRequest and
|
|
// send it over the CreatePasswords channel in case no wallet already exist in
|
|
// the chain's wallet database directory.
|
|
func (u *UnlockerService) CreateWallet(ctx context.Context,
|
|
in *lnrpc.CreateWalletRequest) (*lnrpc.CreateWalletResponse, error) {
|
|
|
|
// Require the provided password to have a length of at
|
|
// least 8 characters.
|
|
password := in.Password
|
|
if len(password) < 8 {
|
|
return nil, fmt.Errorf("password must have " +
|
|
"at least 8 characters")
|
|
}
|
|
|
|
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
|
loader := wallet.NewLoader(u.netParams, netDir)
|
|
|
|
// Check if wallet already exists.
|
|
walletExists, err := loader.WalletExists()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if walletExists {
|
|
// Cannot create wallet if it already exists!
|
|
return nil, fmt.Errorf("wallet already exists")
|
|
}
|
|
|
|
// We send the password over the CreatePasswords channel, such that it
|
|
// can be used by lnd to open or create the wallet.
|
|
u.CreatePasswords <- password
|
|
|
|
return &lnrpc.CreateWalletResponse{}, nil
|
|
}
|
|
|
|
// UnlockWallet sends the password provided by the incoming UnlockWalletRequest
|
|
// over the UnlockPasswords channel in case it successfully decrypts an
|
|
// existing wallet found in the chain's wallet database directory.
|
|
func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
|
in *lnrpc.UnlockWalletRequest) (*lnrpc.UnlockWalletResponse, error) {
|
|
|
|
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
|
loader := wallet.NewLoader(u.netParams, netDir)
|
|
|
|
// Check if wallet already exists.
|
|
walletExists, err := loader.WalletExists()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !walletExists {
|
|
// Cannot unlock a wallet that does not exist!
|
|
return nil, fmt.Errorf("wallet not found")
|
|
}
|
|
|
|
// Try opening the existing wallet with the provided password.
|
|
_, err = loader.OpenExistingWallet(in.Password, false)
|
|
if err != nil {
|
|
// Could not open wallet, most likely this means that
|
|
// provided password was incorrect.
|
|
return nil, err
|
|
}
|
|
|
|
// We successfully opened the wallet, but we'll need to unload
|
|
// it to make sure lnd can open it later.
|
|
if err := loader.UnloadWallet(); err != nil {
|
|
// TODO: not return error here?
|
|
return nil, err
|
|
}
|
|
|
|
// At this point we was able to open the existing wallet with the
|
|
// provided password. We send the password over the UnlockPasswords
|
|
// channel, such that it can be used by lnd to open the wallet.
|
|
u.UnlockPasswords <- in.Password
|
|
|
|
return &lnrpc.UnlockWalletResponse{}, nil
|
|
}
|