| 9 | |
| 10 | namespace wallet { |
| 11 | RPCHelpMan walletpassphrase() |
| 12 | { |
| 13 | return RPCHelpMan{"walletpassphrase", |
| 14 | "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" |
| 15 | "This is needed prior to performing transactions related to private keys such as sending bitcoins\n" |
| 16 | "\nNote:\n" |
| 17 | "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n" |
| 18 | "time that overrides the old one.\n", |
| 19 | { |
| 20 | {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"}, |
| 21 | {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."}, |
| 22 | }, |
| 23 | RPCResult{RPCResult::Type::NONE, "", ""}, |
| 24 | RPCExamples{ |
| 25 | "\nUnlock the wallet for 60 seconds\n" |
| 26 | + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") + |
| 27 | "\nLock the wallet again (before 60 seconds)\n" |
| 28 | + HelpExampleCli("walletlock", "") + |
| 29 | "\nAs a JSON-RPC call\n" |
| 30 | + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60") |
| 31 | }, |
| 32 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 33 | { |
| 34 | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); |
| 35 | if (!wallet) return NullUniValue; |
| 36 | CWallet* const pwallet = wallet.get(); |
| 37 | |
| 38 | int64_t nSleepTime; |
| 39 | int64_t relock_time; |
| 40 | // Prevent concurrent calls to walletpassphrase with the same wallet. |
| 41 | LOCK(pwallet->m_unlock_mutex); |
| 42 | { |
| 43 | LOCK(pwallet->cs_wallet); |
| 44 | |
| 45 | if (!pwallet->IsCrypted()) { |
| 46 | throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); |
| 47 | } |
| 48 | |
| 49 | // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed |
| 50 | SecureString strWalletPass; |
| 51 | strWalletPass.reserve(100); |
| 52 | // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) |
| 53 | // Alternately, find a way to make request.params[0] mlock()'d to begin with. |
| 54 | strWalletPass = request.params[0].get_str().c_str(); |
| 55 | |
| 56 | // Get the timeout |
| 57 | nSleepTime = request.params[1].get_int64(); |
| 58 | // Timeout cannot be negative, otherwise it will relock immediately |
| 59 | if (nSleepTime < 0) { |
| 60 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); |
| 61 | } |
| 62 | // Clamp timeout |
| 63 | constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug? |
| 64 | if (nSleepTime > MAX_SLEEP_TIME) { |
| 65 | nSleepTime = MAX_SLEEP_TIME; |
| 66 | } |
| 67 | |
| 68 | if (strWalletPass.empty()) { |
nothing calls this directly
no test coverage detected