diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index a2125c4ae1c..2ce1ef6463e 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -306,10 +306,14 @@ BOOST_AUTO_TEST_CASE(util_ReplaceAll) }}; test_replaceall(original, "", "foo", original); + test_replaceall(original, "missing", "foo", original); test_replaceall(original, original, "foo", "foo"); test_replaceall(original, "%s", "foo", "A test \"foo\" string 'foo'."); test_replaceall(original, "\"", "foo", "A test foo%sfoo string '%s'."); test_replaceall(original, "'", "foo", "A test \"%s\" string foo%sfoo."); + test_replaceall("a.b", ".", "x", "xxx"); // TODO: Search text must remain literal. + test_replaceall("%w and %w", "%w", "$&$`$'$1$$", "%w and %w$ and %w and $"); // TODO: Replacement bytes must remain literal. + test_replaceall("x", "x", "xx", "xx"); } BOOST_AUTO_TEST_CASE(util_TrimString) diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index e983d5a2b83..fb573d3af98 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -42,6 +42,7 @@ class NotificationsTest(BitcoinTestFramework): self.num_nodes = 2 self.setup_clean_chain = True self.uses_wallet = None + self.noban_tx_relay = True def setup_network(self): self.wallet = ''.join(chr(i) for i in range(FILE_CHAR_START, FILE_CHAR_END) if chr(i) not in FILE_CHARS_DISALLOWED) @@ -175,6 +176,19 @@ class NotificationsTest(BitcoinTestFramework): self.expect_wallet_notify([(bump2, blockheight2, blockhash2), (tx2, -1, UNCONFIRMED_HASH_STRING)]) assert_equal(self.nodes[1].gettransaction(bump2)["confirmations"], 1) + if platform.system() != 'Windows': + self.log.info("test -walletnotify replacement metacharacters in wallet name") + self.nodes[1].unloadwallet(self.wallet) + command_marker = os.path.join(self.options.tmpdir, "walletnotify_injected") + # The previous regex replacement expanded `$'` to the command suffix, breaking the shell-escaped wallet name's quote accounting + wallet_name = self.nodes[1].createwallet(f"$'$'; echo Pwned > {os.path.basename(command_marker)}; #")["name"] + txid = self.nodes[0].sendtoaddress(self.nodes[1].get_wallet_rpc(wallet_name).getnewaddress(), 1) + self.sync_mempools() + notify_path = os.path.join(self.walletnotify_dir, notify_outputname(wallet_name, txid)) + self.wait_until(lambda: os.path.exists(command_marker) or os.path.exists(notify_path), timeout=10) + assert os.path.exists(command_marker) # TODO: Wallet names must not inject shell commands. + assert not os.path.exists(notify_path) # TODO: Wallet names must remain literal in notification paths. + self.log.info("test -alertnotify with large work invalid chain") # create a bunch of invalid blocks tip = self.nodes[0].getbestblockhash()