Allow createwallet to take empty passwords to make unencrypted wallets

Allow createwallet to take the empty string as a password and interpret that
as leaving the wallet unencrypted. Also warn when that happens.
This commit is contained in:
Andrew Chow 2019-07-15 15:33:56 -04:00
parent b21acab82f
commit c5d3787367
3 changed files with 27 additions and 7 deletions

View file

@ -0,0 +1,4 @@
RPC changes
-----------
`createwallet` now returns a warning if an empty string is used as an encryption password, and does not encrypt the wallet, instead of raising an error.
This makes it easier to disable encryption but also specify other options when using the `bitcoin-cli` tool.

View file

@ -2676,11 +2676,12 @@ static UniValue createwallet(const JSONRPCRequest& request)
} }
SecureString passphrase; SecureString passphrase;
passphrase.reserve(100); passphrase.reserve(100);
std::string warning;
if (!request.params[3].isNull()) { if (!request.params[3].isNull()) {
passphrase = request.params[3].get_str().c_str(); passphrase = request.params[3].get_str().c_str();
if (passphrase.empty()) { if (passphrase.empty()) {
// Empty string is invalid // Empty string means unencrypted
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); warning = "Empty string given as passphrase, wallet will not be encrypted.";
} }
} }
@ -2689,9 +2690,9 @@ static UniValue createwallet(const JSONRPCRequest& request)
} }
std::string error; std::string error;
std::string warning; std::string create_warning;
std::shared_ptr<CWallet> wallet; std::shared_ptr<CWallet> wallet;
WalletCreationStatus status = CreateWallet(*g_rpc_interfaces->chain, passphrase, flags, request.params[0].get_str(), error, warning, wallet); WalletCreationStatus status = CreateWallet(*g_rpc_interfaces->chain, passphrase, flags, request.params[0].get_str(), error, create_warning, wallet);
switch (status) { switch (status) {
case WalletCreationStatus::CREATION_FAILED: case WalletCreationStatus::CREATION_FAILED:
throw JSONRPCError(RPC_WALLET_ERROR, error); throw JSONRPCError(RPC_WALLET_ERROR, error);
@ -2702,6 +2703,12 @@ static UniValue createwallet(const JSONRPCRequest& request)
// no default case, so the compiler can warn about missing cases // no default case, so the compiler can warn about missing cases
} }
if (warning.empty()) {
warning = create_warning;
} else if (!warning.empty() && !create_warning.empty()){
warning += "; " + create_warning;
}
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName()); obj.pushKV("name", wallet->GetName());
obj.pushKV("warning", warning); obj.pushKV("warning", warning);

View file

@ -116,11 +116,20 @@ class CreateWalletTest(BitcoinTestFramework):
walletinfo = w6.getwalletinfo() walletinfo = w6.getwalletinfo()
assert_equal(walletinfo['keypoolsize'], 1) assert_equal(walletinfo['keypoolsize'], 1)
assert_equal(walletinfo['keypoolsize_hd_internal'], 1) assert_equal(walletinfo['keypoolsize_hd_internal'], 1)
# Empty passphrase, error # Allow empty passphrase, but there should be a warning
assert_raises_rpc_error(-16, 'Cannot encrypt a wallet with a blank password', self.nodes[0].createwallet, 'w7', False, False, '') resp = self.nodes[0].createwallet(wallet_name='w7', disable_private_keys=False, blank=False, passphrase='')
assert_equal(resp['warning'], 'Empty string given as passphrase, wallet will not be encrypted.')
w7 = node.get_wallet_rpc('w7')
assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 10)
self.log.info('Test making a wallet with avoid reuse flag')
self.nodes[0].createwallet('w8', False, False, '', True) # Use positional arguments to check for bug where avoid_reuse could not be set for wallets without needing them to be encrypted
w8 = node.get_wallet_rpc('w8')
assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 10)
assert_equal(w8.getwalletinfo()["avoid_reuse"], True)
self.log.info('Using a passphrase with private keys disabled returns error') self.log.info('Using a passphrase with private keys disabled returns error')
assert_raises_rpc_error(-4, 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', self.nodes[0].createwallet, wallet_name='w8', disable_private_keys=True, passphrase='thisisapassphrase') assert_raises_rpc_error(-4, 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', self.nodes[0].createwallet, wallet_name='w9', disable_private_keys=True, passphrase='thisisapassphrase')
if __name__ == '__main__': if __name__ == '__main__':
CreateWalletTest().main() CreateWalletTest().main()