2017-10-12 12:13:58 +03:00
|
|
|
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"
|
2018-01-16 19:18:41 +03:00
|
|
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
2017-10-12 12:13:58 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
2017-10-20 05:46:42 +03:00
|
|
|
// client to be used to initially create and encrypt a wallet will be
|
|
|
|
// sent.
|
2017-10-12 12:13:58 +03:00
|
|
|
CreatePasswords chan []byte
|
|
|
|
|
|
|
|
// UnlockPasswords is a channel where passwords provided by the rpc
|
2017-10-20 05:46:42 +03:00
|
|
|
// client to be used to unlock and decrypt an existing wallet will be
|
|
|
|
// sent.
|
2017-10-12 12:13:58 +03:00
|
|
|
UnlockPasswords chan []byte
|
|
|
|
|
|
|
|
chainDir string
|
|
|
|
netParams *chaincfg.Params
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates and returns a new UnlockerService.
|
2018-01-16 19:18:41 +03:00
|
|
|
func New(authSvc *bakery.Bakery, chainDir string,
|
2017-10-12 12:13:58 +03:00
|
|
|
params *chaincfg.Params) *UnlockerService {
|
|
|
|
return &UnlockerService{
|
|
|
|
CreatePasswords: make(chan []byte, 1),
|
|
|
|
UnlockPasswords: make(chan []byte, 1),
|
|
|
|
chainDir: chainDir,
|
|
|
|
netParams: params,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-20 05:46:42 +03:00
|
|
|
// 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.
|
2017-10-12 12:13:58 +03:00
|
|
|
func (u *UnlockerService) CreateWallet(ctx context.Context,
|
|
|
|
in *lnrpc.CreateWalletRequest) (*lnrpc.CreateWalletResponse, error) {
|
|
|
|
|
2017-11-14 07:12:49 +03:00
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
|
2017-10-12 12:13:58 +03:00
|
|
|
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.
|
2017-11-14 07:12:49 +03:00
|
|
|
u.CreatePasswords <- password
|
2017-10-12 12:13:58 +03:00
|
|
|
|
|
|
|
return &lnrpc.CreateWalletResponse{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnlockWallet sends the password provided by the incoming UnlockWalletRequest
|
2017-10-20 05:46:42 +03:00
|
|
|
// over the UnlockPasswords channel in case it successfully decrypts an
|
|
|
|
// existing wallet found in the chain's wallet database directory.
|
2017-10-12 12:13:58 +03:00
|
|
|
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
|
|
|
|
}
|