Merge pull request #1373 from loin3/issue1367/escape_chars

fix fail amino sign verify with special chars
This commit is contained in:
Simon Warta 2023-03-09 12:24:08 +01:00 committed by GitHub
commit e2632994b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 4 deletions

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Random } from "@cosmjs/crypto";
import { toBech32 } from "@cosmjs/encoding";
import { fromUtf8, toBech32, toUtf8 } from "@cosmjs/encoding";
import { AminoMsg, makeSignDoc, sortedJsonStringify } from "./signdoc";
import { AminoMsg, escapeCharacters, makeSignDoc, sortedJsonStringify } from "./signdoc";
function makeRandomAddress(): string {
return toBech32("cosmos", Random.getBytes(20));
@ -132,4 +132,14 @@ describe("encoding", () => {
});
});
});
describe("escape characters after utf8 encoding", () => {
it("works", () => {
const test = JSON.stringify({ memo: "ampersand:&,lt:<,gt:>" });
const utf8Encoding = toUtf8(test);
const escapedEncoding = escapeCharacters(utf8Encoding);
expect(JSON.parse(fromUtf8(utf8Encoding))).toEqual(JSON.parse(fromUtf8(escapedEncoding)));
});
});
});

View File

@ -72,6 +72,35 @@ export function makeSignDoc(
};
}
export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array {
return toUtf8(sortedJsonStringify(signDoc));
export function escapeCharacters(encodedArray: Uint8Array): Uint8Array {
const AmpersandUnicode = new Uint8Array([92, 117, 48, 48, 50, 54]);
const LtSignUnicode = new Uint8Array([92, 117, 48, 48, 51, 99]);
const GtSignUnicode = new Uint8Array([92, 117, 48, 48, 51, 101]);
const AmpersandAscii = 38;
const LtSign = 60; // <
const GtSign = 62; // >
const filteredIndex: number[] = [];
encodedArray.forEach((value, index) => {
if (value === AmpersandAscii || value === LtSign || value === GtSign) filteredIndex.push(index);
});
let result = new Uint8Array([...encodedArray]);
const reversedFilteredIndex = filteredIndex.reverse();
reversedFilteredIndex.forEach((value) => {
let unicode = AmpersandUnicode;
if (result[value] === LtSign) {
unicode = LtSignUnicode;
} else if (result[value] === GtSign) {
unicode = GtSignUnicode;
}
result = new Uint8Array([...result.slice(0, value), ...unicode, ...result.slice(value + 1)]);
});
return result;
}
export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array {
return escapeCharacters(toUtf8(sortedJsonStringify(signDoc)));
}

View File

@ -455,6 +455,33 @@ describe("SigningStargateClient", () => {
});
describe("legacy Amino mode", () => {
it("works with special characters in memo", async () => {
pendingWithoutSimapp();
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const client = await SigningStargateClient.connectWithSigner(
simapp.tendermintUrl,
wallet,
defaultSigningClientOptions,
);
const msgSend: MsgSend = {
fromAddress: faucet.address0,
toAddress: makeRandomAddress(),
amount: coins(1234, "ucosm"),
};
const msgAny: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msgSend,
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "200000",
};
const memo = "ampersand:&,lt:<,gt:>";
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
assertIsDeliverTxSuccess(result);
});
it("works with bank MsgSend", async () => {
pendingWithoutSimapp();
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);