Files
AutistMask/tests/rpcErrorLog.test.js
T
sneak d7f0e241ff
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
fix: Blockscout and Etherscan lookups are off until the user turns them on (closes #668)
Out of the box the wallet sent the user's addresses to Blockscout for history
and token lookups, and each recipient to Etherscan for its label. Two settings,
"Use Blockscout" and "Check recipients on Etherscan", now gate those requests
where they are made. Both are off in a new profile and offered unticked on
Welcome and in Settings. While one is off, the screens that relied on it say so
in a plain line naming the setting; after either changes in Settings, Back
draws the screen it lands on again. ENS lookups ask only the RPC endpoint, so a
name resolved off-chain does not resolve. README and the user guide say what is
contacted by default and what each setting adds.

Model: opus-5-5
2026-10-21 16:11:02 +00:00

107 lines
3.8 KiB
JavaScript

// What reaches the console when the RPC endpoint answers with an HTTP error.
//
// RPC providers put the API key in the endpoint URL's path or query string.
// When the endpoint answers with an HTTP error (a wrong or expired key, a rate
// limit, a server error), the error ethers throws carries the full request URL
// in its message, so a line logging that message printed the key
// (https://git.eeqj.de/sneak/AutistMask/issues/410). Those lines log the
// error's short message, which names the HTTP status and not the URL.
//
// The real ethers provider runs; only its HTTP transport is replaced, by one
// that answers every request with 401 Unauthorized. Debug mode is on, so
// every log level is printed.
const { FetchRequest } = require("ethers");
const {
getProvider,
lookupTokenInfo,
refreshBalances,
} = require("../src/shared/balances");
const { getFullWarnings } = require("../src/shared/addressWarnings");
const { resolveEnsName } = require("../src/shared/ens");
const { setRuntimeDebug } = require("../src/shared/log");
const RPC_URL = "https://rpc.example.invalid/v3/PATHKEY123?token=QUERYTOKEN456";
const ADDRESS = "0x1111111111111111111111111111111111111111";
const realFetch = globalThis.fetch;
let printed;
beforeEach(() => {
setRuntimeDebug(true);
printed = [];
for (const method of ["log", "warn", "error"]) {
jest.spyOn(console, method).mockImplementation((...args) => {
printed.push(args.map(String).join(" "));
});
}
FetchRequest.registerGetUrl(async () => ({
statusCode: 401,
statusMessage: "Unauthorized",
headers: {},
body: new Uint8Array(),
}));
// The explorer requests the balance refresh makes go nowhere.
globalThis.fetch = jest.fn(async () => {
throw new Error("tests must not perform network requests");
});
});
afterEach(() => {
FetchRequest.registerGetUrl(FetchRequest.createGetUrlFunc());
globalThis.fetch = realFetch;
setRuntimeDebug(false);
jest.restoreAllMocks();
});
// The line carrying `label` was printed and names the HTTP status, and nothing
// printed carries the key.
function expectFailureLoggedWithoutKey(label) {
const line = printed.find((text) => text.includes(label));
expect(line).toContain("401");
const all = printed.join("\n");
expect(all).not.toContain("PATHKEY123");
expect(all).not.toContain("QUERYTOKEN456");
}
test("ethers puts the URL in the error message, not in the short message", async () => {
const provider = getProvider(RPC_URL, "mainnet");
const error = await provider.getCode(ADDRESS).catch((e) => e);
expect(error.message).toContain("PATHKEY123");
expect(error.shortMessage).not.toContain("PATHKEY123");
});
test("the recipient checks before a send", async () => {
await getFullWarnings(ADDRESS, getProvider(RPC_URL, "mainnet"));
expectFailureLoggedWithoutKey("contract check failed");
expectFailureLoggedWithoutKey("tx count or balance check failed");
});
test("the ENS reverse lookup", async () => {
expect(await resolveEnsName(ADDRESS, RPC_URL, "mainnet")).toBeNull();
expectFailureLoggedWithoutKey("ENS reverse lookup failed");
});
test("the balance refresh", async () => {
const wallets = [{ addresses: [{ address: ADDRESS }] }];
await refreshBalances(
wallets,
RPC_URL,
"https://explorer.example.invalid/api/v2",
true,
[],
"mainnet",
);
expectFailureLoggedWithoutKey("ETH balance failed");
expectFailureLoggedWithoutKey("ENS reverse failed");
});
// The lookup's first line, at debug level, names the RPC endpoint; the check
// of everything printed covers it too.
test("the token lookup", async () => {
await expect(lookupTokenInfo(ADDRESS, RPC_URL, "mainnet")).rejects.toThrow(
"Not a valid ERC-20 token",
);
expectFailureLoggedWithoutKey("symbol() failed:");
});