fix: typed data with a missing field or a bool that is not true or false is refused (closes #552)
ethers signs a bool field by whether its value is truthy, so the string "false" was shown as false and signed as true, and a bool field left out was shown as nothing and signed as false. The sign screen now refuses typed data whose message leaves out a declared field, at any level of nesting, or holds a bool that is not true or false: the error line names the field and Sign is disabled. The background refuses a signature for it too. Presence is an own-key test, so a field named like a built-in property such as constructor is not found by accident. signedPrimaryType() moves to the shared module so the background reads the message as the same type. Model: opus-5-5
This commit is contained in:
@@ -27,7 +27,6 @@ const {
|
||||
Interface,
|
||||
MaxUint256,
|
||||
toUtf8String,
|
||||
TypedDataEncoder,
|
||||
} = require("ethers");
|
||||
const { getPrice, formatUsd } = require("../../shared/prices");
|
||||
const { ERC20_ABI } = require("../../shared/constants");
|
||||
@@ -48,6 +47,8 @@ const { getSignerForAddress } = require("../../shared/wallet");
|
||||
const { walletDefect } = require("../../shared/walletDefects");
|
||||
const {
|
||||
describeSigningFailure,
|
||||
signedPrimaryType,
|
||||
typedDataMessageRefusal,
|
||||
typedDataChainRefusal,
|
||||
} = require("../../shared/approvalVerify");
|
||||
const txStatus = require("./txStatus");
|
||||
@@ -432,22 +433,12 @@ function markInvisibleCharacters(text) {
|
||||
);
|
||||
}
|
||||
|
||||
// The type ethers will sign typed data as. ethers does not read the page's
|
||||
// `primaryType`: it takes the one struct in `types` that no other struct
|
||||
// refers to. Throws when the types name no such single struct, which ethers
|
||||
// would refuse to sign as well.
|
||||
function signedPrimaryType(types) {
|
||||
const structs = { ...types };
|
||||
// ethers derives EIP712Domain itself and rejects it as an input.
|
||||
delete structs.EIP712Domain;
|
||||
return TypedDataEncoder.getPrimaryType(structs);
|
||||
}
|
||||
|
||||
// Why a signature request cannot be signed, as a sentence for the error line,
|
||||
// or null when it can. Only typed data is refused: the `primaryType` the page
|
||||
// states has to be the type ethers will sign, or this screen would name one
|
||||
// message while another is signed. Its domain may name no chain but the active
|
||||
// network's.
|
||||
// message while another is signed. Its message has to hold every declared
|
||||
// field, with each `bool` true or false, and its domain may name no chain but
|
||||
// the active network's.
|
||||
function typedDataRefusal(sp) {
|
||||
if (sp.method === "personal_sign" || sp.method === "eth_sign") return null;
|
||||
let data;
|
||||
@@ -470,7 +461,10 @@ function typedDataRefusal(sp) {
|
||||
", so it cannot be signed."
|
||||
);
|
||||
}
|
||||
return typedDataChainRefusal(data.domain, currentNetwork());
|
||||
return (
|
||||
typedDataMessageRefusal(data.types, signed, data.message, "") ||
|
||||
typedDataChainRefusal(data.domain, currentNetwork())
|
||||
);
|
||||
}
|
||||
|
||||
// The largest amount a Permit2 allowance can hold, a uint160. Permit2 treats
|
||||
|
||||
Reference in New Issue
Block a user