harden: show a personal message's hex and its text in byte order, hidden characters marked (closes #403)
The signature screen showed only the text a personal message decodes to, with bidirectional, right-to-left and zero-width characters acting on it, so a site could make the message read differently from the bytes that are signed, and a message that was not hex was decoded into NUL characters. The screen now shows the hex as "Raw data" alongside the text, lays the text out left to right in byte order, and shows each control character and each character that paints nothing (the set src/shared/symbolSpoof.js already strips) as a U+XXXX mark. A message is hex when getBytes, which signing uses, reads it; one that is not cannot be signed, so it is shown as plain text with "Sign" disabled. Model: opus-5-5
This commit is contained in:
@@ -3232,6 +3232,47 @@ test("personal_sign rejected returns a rejection to the page (#183)", async (env
|
||||
);
|
||||
});
|
||||
|
||||
// A right-to-left character must not move the characters around it: U+05C3
|
||||
// between "5" and "00" would otherwise put "500" on screen before it
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/403).
|
||||
test("a personal message is laid out in the order of its bytes (#403)", async (env) => {
|
||||
const text = "Pay 5" + String.fromCodePoint(0x05c3) + "00 ETH";
|
||||
await startRequest(env.dapp, "sign-bidi", "personal_sign", [
|
||||
hexlify(toUtf8Bytes(text)),
|
||||
env.expectedAddress,
|
||||
]);
|
||||
const popup = await waitForApprovalWindow(env.ctx);
|
||||
await visible(popup, "#view-approve-sign");
|
||||
|
||||
// The left edge of each character on screen, in byte order. A character
|
||||
// the browser's fonts draw with no width shares its neighbour's edge.
|
||||
const lefts = await popup.evaluate(() => {
|
||||
const message = document.getElementById("approve-sign-message");
|
||||
const textNode = message.firstChild;
|
||||
const range = document.createRange();
|
||||
const out = [];
|
||||
for (let i = 0; i < textNode.length; i++) {
|
||||
range.setStart(textNode, i);
|
||||
range.setEnd(textNode, i + 1);
|
||||
out.push(range.getBoundingClientRect().left);
|
||||
}
|
||||
return out;
|
||||
});
|
||||
await clickAndClose(popup, "#btn-reject-sign");
|
||||
await assertUserRejection(
|
||||
env.dapp,
|
||||
"sign-bidi",
|
||||
"the byte-order personal_sign rejection",
|
||||
);
|
||||
|
||||
assert(
|
||||
lefts.length === text.length &&
|
||||
lefts.every((left, i) => i === 0 || left >= lefts[i - 1]),
|
||||
"the personal message is not laid out in byte order: " +
|
||||
JSON.stringify(lefts),
|
||||
);
|
||||
});
|
||||
|
||||
test("eth_signTypedData_v4 signs, and the signature recovers (#183)", async (env) => {
|
||||
await startRequest(env.dapp, "typed", "eth_signTypedData_v4", [
|
||||
env.expectedAddress,
|
||||
|
||||
Reference in New Issue
Block a user