diff --git a/.changeset/cool-ladybugs-admire.md b/.changeset/cool-ladybugs-admire.md new file mode 100644 index 00000000..31f1c881 --- /dev/null +++ b/.changeset/cool-ladybugs-admire.md @@ -0,0 +1,5 @@ +--- +'@gnosis.pm/safe-apps-sdk': patch +--- + +fix missing context on signature checks diff --git a/packages/safe-apps-sdk/dist/package.json b/packages/safe-apps-sdk/dist/package.json index 55b5db33..a61a3584 100644 --- a/packages/safe-apps-sdk/dist/package.json +++ b/packages/safe-apps-sdk/dist/package.json @@ -1,6 +1,6 @@ { "name": "@gnosis.pm/safe-apps-sdk", - "version": "4.2.0", + "version": "4.3.0-next.0", "description": "SDK developed to integrate third-party apps with Safe-Multisig app.", "main": "dist/src/index.js", "typings": "dist/src/index.d.ts", diff --git a/packages/safe-apps-sdk/dist/src/index.d.ts b/packages/safe-apps-sdk/dist/src/index.d.ts index ce815bba..8dfa1c9a 100644 --- a/packages/safe-apps-sdk/dist/src/index.d.ts +++ b/packages/safe-apps-sdk/dist/src/index.d.ts @@ -4,4 +4,5 @@ export * from './sdk'; export * from './types'; export * from './communication/methods'; export * from './communication/messageFormatter'; +export { calculateMessageHash } from './safe/signatures'; export { getSDKVersion } from './utils'; diff --git a/packages/safe-apps-sdk/dist/src/index.js b/packages/safe-apps-sdk/dist/src/index.js index 84dbd287..10138a2d 100644 --- a/packages/safe-apps-sdk/dist/src/index.js +++ b/packages/safe-apps-sdk/dist/src/index.js @@ -13,13 +13,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getSDKVersion = void 0; +exports.getSDKVersion = exports.calculateMessageHash = void 0; const sdk_1 = __importDefault(require("./sdk")); exports.default = sdk_1.default; __exportStar(require("./sdk"), exports); __exportStar(require("./types"), exports); __exportStar(require("./communication/methods"), exports); __exportStar(require("./communication/messageFormatter"), exports); +var signatures_1 = require("./safe/signatures"); +Object.defineProperty(exports, "calculateMessageHash", { enumerable: true, get: function () { return signatures_1.calculateMessageHash; } }); var utils_1 = require("./utils"); Object.defineProperty(exports, "getSDKVersion", { enumerable: true, get: function () { return utils_1.getSDKVersion; } }); //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/safe-apps-sdk/dist/src/index.js.map b/packages/safe-apps-sdk/dist/src/index.js.map index c204a1a7..62b88489 100644 --- a/packages/safe-apps-sdk/dist/src/index.js.map +++ b/packages/safe-apps-sdk/dist/src/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAAwB;AAExB,kBAAe,aAAG,CAAC;AACnB,wCAAsB;AACtB,0CAAwB;AACxB,0DAAwC;AACxC,mEAAiD;AACjD,iCAAwC;AAA/B,sGAAA,aAAa,OAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAAwB;AAExB,kBAAe,aAAG,CAAC;AACnB,wCAAsB;AACtB,0CAAwB;AACxB,0DAAwC;AACxC,mEAAiD;AACjD,gDAAyD;AAAhD,kHAAA,oBAAoB,OAAA;AAC7B,iCAAwC;AAA/B,sGAAA,aAAa,OAAA"} \ No newline at end of file diff --git a/packages/safe-apps-sdk/dist/src/safe/index.d.ts b/packages/safe-apps-sdk/dist/src/safe/index.d.ts index 84e82568..f71e3a91 100644 --- a/packages/safe-apps-sdk/dist/src/safe/index.d.ts +++ b/packages/safe-apps-sdk/dist/src/safe/index.d.ts @@ -4,9 +4,9 @@ declare class Safe { constructor(communicator: Communicator); getInfo(): Promise; experimental_getBalances({ currency }?: GetBalanceParams): Promise; - calculateMessageHash(message: BytesLike): string; private check1271Signature; private check1271SignatureBytes; isMessageSigned(message: BytesLike, signature?: string): Promise; + isMessageHashSigned(messageHash: string, signature?: string): Promise; } export { Safe }; diff --git a/packages/safe-apps-sdk/dist/src/safe/index.js b/packages/safe-apps-sdk/dist/src/safe/index.js index 17d0852e..b0c76ae6 100644 --- a/packages/safe-apps-sdk/dist/src/safe/index.js +++ b/packages/safe-apps-sdk/dist/src/safe/index.js @@ -20,12 +20,6 @@ class Safe { }); return response.data; } - calculateMessageHash(message) { - if (typeof message === 'string') { - message = ethers_1.ethers.utils.toUtf8Bytes(message); - } - return ethers_1.ethers.utils.keccak256(message); - } async check1271Signature(messageHash, signature = '0x') { const safeInfo = await this.getInfo(); const encodedIsValidSignatureCall = signatures_1.EIP_1271_INTERFACE.encodeFunctionData('isValidSignature', [ @@ -52,8 +46,9 @@ class Safe { } async check1271SignatureBytes(messageHash, signature = '0x') { const safeInfo = await this.getInfo(); + const msgBytes = ethers_1.ethers.utils.arrayify(messageHash); const encodedIsValidSignatureCall = signatures_1.EIP_1271_BYTES_INTERFACE.encodeFunctionData('isValidSignature', [ - messageHash, + msgBytes, signature, ]); const payload = { @@ -75,23 +70,14 @@ class Safe { } } async isMessageSigned(message, signature = '0x') { - const checks = [this.check1271Signature, this.check1271SignatureBytes]; - let msgBytes = Buffer.from([]); - // Set msgBytes as Buffer type - if (Buffer.isBuffer(message)) { - msgBytes = message; - } - else if (typeof message === 'string') { - if (ethers_1.ethers.utils.isHexString(message)) { - msgBytes = Buffer.from(message.substring(2), 'hex'); - } - else { - msgBytes = Buffer.from(message); - } - } - msgBytes = ethers_1.ethers.utils.arrayify(msgBytes); + const messageHash = (0, signatures_1.calculateMessageHash)(message); + const messageHashSigned = await this.isMessageHashSigned(messageHash, signature); + return messageHashSigned; + } + async isMessageHashSigned(messageHash, signature = '0x') { + const checks = [this.check1271Signature.bind(this), this.check1271SignatureBytes.bind(this)]; for (const check of checks) { - const isValid = await check(msgBytes, signature); + const isValid = await check(messageHash, signature); if (isValid) { return true; } diff --git a/packages/safe-apps-sdk/dist/src/safe/index.js.map b/packages/safe-apps-sdk/dist/src/safe/index.js.map index bf680e42..45b8dbee 100644 --- a/packages/safe-apps-sdk/dist/src/safe/index.js.map +++ b/packages/safe-apps-sdk/dist/src/safe/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/safe/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/safe/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/safe-apps-sdk/dist/src/safe/signatures.d.ts b/packages/safe-apps-sdk/dist/src/safe/signatures.d.ts index e3bbc2d1..5eb39a23 100644 --- a/packages/safe-apps-sdk/dist/src/safe/signatures.d.ts +++ b/packages/safe-apps-sdk/dist/src/safe/signatures.d.ts @@ -1,6 +1,8 @@ import { ethers } from 'ethers'; +import { BytesLike } from '../types'; declare const MAGIC_VALUE = "0x1626ba7e"; declare const MAGIC_VALUE_BYTES = "0x20c13b0b"; declare const EIP_1271_INTERFACE: ethers.utils.Interface; declare const EIP_1271_BYTES_INTERFACE: ethers.utils.Interface; -export { EIP_1271_INTERFACE, EIP_1271_BYTES_INTERFACE, MAGIC_VALUE, MAGIC_VALUE_BYTES }; +declare const calculateMessageHash: (message: BytesLike) => string; +export { EIP_1271_INTERFACE, EIP_1271_BYTES_INTERFACE, MAGIC_VALUE, MAGIC_VALUE_BYTES, calculateMessageHash }; diff --git a/packages/safe-apps-sdk/dist/src/safe/signatures.js b/packages/safe-apps-sdk/dist/src/safe/signatures.js index 8e6c208d..eaa8bc86 100644 --- a/packages/safe-apps-sdk/dist/src/safe/signatures.js +++ b/packages/safe-apps-sdk/dist/src/safe/signatures.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.MAGIC_VALUE_BYTES = exports.MAGIC_VALUE = exports.EIP_1271_BYTES_INTERFACE = exports.EIP_1271_INTERFACE = void 0; +exports.calculateMessageHash = exports.MAGIC_VALUE_BYTES = exports.MAGIC_VALUE = exports.EIP_1271_BYTES_INTERFACE = exports.EIP_1271_INTERFACE = void 0; const ethers_1 = require("ethers"); const MAGIC_VALUE = '0x1626ba7e'; exports.MAGIC_VALUE = MAGIC_VALUE; @@ -14,4 +14,11 @@ const EIP_1271_BYTES_INTERFACE = new ethers_1.ethers.utils.Interface([ 'function isValidSignature(bytes calldata _data, bytes calldata _signature) public view', ]); exports.EIP_1271_BYTES_INTERFACE = EIP_1271_BYTES_INTERFACE; +const calculateMessageHash = (message) => { + if (typeof message === 'string') { + message = ethers_1.ethers.utils.toUtf8Bytes(message); + } + return ethers_1.ethers.utils.keccak256(message); +}; +exports.calculateMessageHash = calculateMessageHash; //# sourceMappingURL=signatures.js.map \ No newline at end of file diff --git a/packages/safe-apps-sdk/dist/src/safe/signatures.js.map b/packages/safe-apps-sdk/dist/src/safe/signatures.js.map index 80dcc306..7b343009 100644 --- a/packages/safe-apps-sdk/dist/src/safe/signatures.js.map +++ b/packages/safe-apps-sdk/dist/src/safe/signatures.js.map @@ -1 +1 @@ -{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../../../src/safe/signatures.ts"],"names":[],"mappings":";;;AAAA,mCAAgC;AAEhC,MAAM,WAAW,GAAG,YAAY,CAAC;AAUsB,kCAAW;AATlE,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAS6B,8CAAiB;AAPrF,MAAM,kBAAkB,GAAG,IAAI,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC;IACpD,uFAAuF;CACxF,CAAC,CAAC;AAKM,gDAAkB;AAJ3B,MAAM,wBAAwB,GAAG,IAAI,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC;IAC1D,wFAAwF;CACzF,CAAC,CAAC;AAE0B,4DAAwB"} \ No newline at end of file +{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../../../src/safe/signatures.ts"],"names":[],"mappings":";;;AAAA,mCAAgC;AAGhC,MAAM,WAAW,GAAG,YAAY,CAAC;AAkBsB,kCAAW;AAjBlE,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAiB6B,8CAAiB;AAfrF,MAAM,kBAAkB,GAAG,IAAI,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC;IACpD,uFAAuF;CACxF,CAAC,CAAC;AAaM,gDAAkB;AAZ3B,MAAM,wBAAwB,GAAG,IAAI,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC;IAC1D,wFAAwF;CACzF,CAAC,CAAC;AAU0B,4DAAwB;AARrD,MAAM,oBAAoB,GAAG,CAAC,OAAkB,EAAU,EAAE;IAC1D,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;QAC/B,OAAO,GAAG,eAAM,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;KAC7C;IAED,OAAO,eAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC,CAAC;AAEqF,oDAAoB"} \ No newline at end of file diff --git a/packages/safe-apps-sdk/package.json b/packages/safe-apps-sdk/package.json index f6d989ba..399493bf 100644 --- a/packages/safe-apps-sdk/package.json +++ b/packages/safe-apps-sdk/package.json @@ -15,7 +15,7 @@ ], "scripts": { "test": "jest", - "format-dist": "sed -i 's/\"files\":/\"_files\":/' dist/package.json", + "format-dist": "sed -i '' 's/\"files\":/\"_files\":/' dist/package.json", "build": "yarn rimraf dist && tsc && yarn format-dist", "lint": "tslint -p tsconfig.json" }, diff --git a/packages/safe-apps-sdk/src/index.ts b/packages/safe-apps-sdk/src/index.ts index ffa8dbfb..84296482 100644 --- a/packages/safe-apps-sdk/src/index.ts +++ b/packages/safe-apps-sdk/src/index.ts @@ -5,4 +5,5 @@ export * from './sdk'; export * from './types'; export * from './communication/methods'; export * from './communication/messageFormatter'; +export { calculateMessageHash } from './safe/signatures'; export { getSDKVersion } from './utils'; diff --git a/packages/safe-apps-sdk/src/safe/index.ts b/packages/safe-apps-sdk/src/safe/index.ts index 25e68a52..377d1977 100644 --- a/packages/safe-apps-sdk/src/safe/index.ts +++ b/packages/safe-apps-sdk/src/safe/index.ts @@ -1,5 +1,11 @@ import { ethers } from 'ethers'; -import { EIP_1271_INTERFACE, EIP_1271_BYTES_INTERFACE, MAGIC_VALUE_BYTES, MAGIC_VALUE } from './signatures'; +import { + EIP_1271_INTERFACE, + EIP_1271_BYTES_INTERFACE, + MAGIC_VALUE_BYTES, + MAGIC_VALUE, + calculateMessageHash, +} from './signatures'; import { Methods } from '../communication/methods'; import { RPC_CALLS } from '../eth/constants'; import { @@ -40,15 +46,7 @@ class Safe { return response.data; } - calculateMessageHash(message: BytesLike): string { - if (typeof message === 'string') { - message = ethers.utils.toUtf8Bytes(message); - } - - return ethers.utils.keccak256(message); - } - - private async check1271Signature(messageHash: Uint8Array, signature = '0x'): Promise { + private async check1271Signature(messageHash: string, signature = '0x'): Promise { const safeInfo = await this.getInfo(); const encodedIsValidSignatureCall = EIP_1271_INTERFACE.encodeFunctionData('isValidSignature', [ @@ -78,11 +76,12 @@ class Safe { } } - private async check1271SignatureBytes(messageHash: Uint8Array, signature = '0x'): Promise { + private async check1271SignatureBytes(messageHash: string, signature = '0x'): Promise { const safeInfo = await this.getInfo(); + const msgBytes = ethers.utils.arrayify(messageHash); const encodedIsValidSignatureCall = EIP_1271_BYTES_INTERFACE.encodeFunctionData('isValidSignature', [ - messageHash, + msgBytes, signature, ]); @@ -110,18 +109,17 @@ class Safe { } async isMessageSigned(message: BytesLike, signature = '0x'): Promise { - const messageHash = this.calculateMessageHash(message); + const messageHash = calculateMessageHash(message); const messageHashSigned = await this.isMessageHashSigned(messageHash, signature); return messageHashSigned; } async isMessageHashSigned(messageHash: string, signature = '0x'): Promise { - const checks = [this.check1271Signature, this.check1271SignatureBytes]; + const checks = [this.check1271Signature.bind(this), this.check1271SignatureBytes.bind(this)]; - const msgBytes = ethers.utils.arrayify(messageHash); for (const check of checks) { - const isValid = await check(msgBytes, signature); + const isValid = await check(messageHash, signature); if (isValid) { return true; } diff --git a/packages/safe-apps-sdk/src/safe/safe.test.ts b/packages/safe-apps-sdk/src/safe/safe.test.ts index 189a22fd..47e3394a 100644 --- a/packages/safe-apps-sdk/src/safe/safe.test.ts +++ b/packages/safe-apps-sdk/src/safe/safe.test.ts @@ -1,6 +1,7 @@ import SDK from '../sdk'; import { SafeInfo } from '../types'; import { Methods } from '../communication/methods'; +import { calculateMessageHash } from './signatures'; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -28,7 +29,7 @@ describe('Safe Apps SDK safe methods', () => { }); }); - describe('SDK.safe.calculateMessageHash', () => { + describe('calculateMessageHash', () => { test('Should generate a valid message hash', () => { const safeInfoSpy = jest.spyOn(sdkInstance.safe, 'getInfo'); safeInfoSpy.mockImplementationOnce( @@ -44,7 +45,7 @@ describe('Safe Apps SDK safe methods', () => { // https://dashboard.tenderly.co/tx/rinkeby/0x9308fb61d9f4282080334e3f35b357fc689e06808b8ad2817536813948e3720d const message = 'approve rugpull'; const expectedHash = '0xb4fd0d8fd75eea963cec570dd58d8c3f5f93569f5c112e227fa64f275623b4db'; - const hash = sdkInstance.safe.calculateMessageHash(message); + const hash = calculateMessageHash(message); expect(hash).toEqual(expectedHash); }); @@ -226,6 +227,41 @@ describe('Safe Apps SDK safe methods', () => { }); describe('SDK.safe.isMessageHashSigned', () => { + test('Should send call messages to check the message the interface', async () => { + const safeInfoSpy = jest.spyOn(sdkInstance.safe, 'getInfo'); + safeInfoSpy.mockImplementation( + (): Promise => + Promise.resolve({ + chainId: 4, + safeAddress: '0x9C6FEA0B2eAc5b6D8bBB6C30401D42aA95398190', + owners: [], + threshold: 1, + }), + ); + + const message = '0x617070726f76652072756770756c6c0000000000000000000000000000000000'; // ethers.utils.formatBytes32String('approve rugpull') + + sdkInstance.safe.isMessageHashSigned(message); + await sleep(200); + // calling first check1271Signature method + expect(postMessageSpy).toHaveBeenCalledWith( + expect.objectContaining({ + method: Methods.rpcCall, + params: { + call: 'eth_call', + params: [ + { + to: '0x9C6FEA0B2eAc5b6D8bBB6C30401D42aA95398190', + data: '0x1626ba7e617070726f76652072756770756c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000', + }, + 'latest', + ], + }, + }), + '*', + ); + }); + test('Should return true if check1271Signature return true', async () => { const safeInfoSpy = jest.spyOn(sdkInstance.safe, 'getInfo'); // @ts-expect-error method is private but we are testing it @@ -243,9 +279,7 @@ describe('Safe Apps SDK safe methods', () => { check1271SignatureSpy.mockImplementationOnce(() => Promise.resolve(true)); // ethers.utils.formatBytes32String('approve rugpull') - const message = sdkInstance.safe.calculateMessageHash( - '0x617070726f76652072756770756c6c0000000000000000000000000000000000', - ); + const message = calculateMessageHash('0x617070726f76652072756770756c6c0000000000000000000000000000000000'); const signed = await sdkInstance.safe.isMessageHashSigned(message); expect(signed).toEqual(true); @@ -272,9 +306,7 @@ describe('Safe Apps SDK safe methods', () => { check1271SignatureBytesSpy.mockImplementationOnce(() => Promise.resolve(true)); // ethers.utils.formatBytes32String('approve rugpull') - const message = sdkInstance.safe.calculateMessageHash( - '0x617070726f76652072756770756c6c0000000000000000000000000000000000', - ); + const message = calculateMessageHash('0x617070726f76652072756770756c6c0000000000000000000000000000000000'); const signed = await sdkInstance.safe.isMessageHashSigned(message); expect(signed).toEqual(true); @@ -301,9 +333,7 @@ describe('Safe Apps SDK safe methods', () => { check1271SignatureBytesSpy.mockImplementationOnce(() => Promise.resolve(false)); // ethers.utils.formatBytes32String('approve rugpull') - const message = sdkInstance.safe.calculateMessageHash( - '0x617070726f76652072756770756c6c0000000000000000000000000000000000', - ); + const message = calculateMessageHash('0x617070726f76652072756770756c6c0000000000000000000000000000000000'); const signed = await sdkInstance.safe.isMessageHashSigned(message); expect(signed).toEqual(false); diff --git a/packages/safe-apps-sdk/src/safe/signatures.ts b/packages/safe-apps-sdk/src/safe/signatures.ts index 6773122c..40080888 100644 --- a/packages/safe-apps-sdk/src/safe/signatures.ts +++ b/packages/safe-apps-sdk/src/safe/signatures.ts @@ -1,4 +1,5 @@ import { ethers } from 'ethers'; +import { BytesLike } from '../types'; const MAGIC_VALUE = '0x1626ba7e'; const MAGIC_VALUE_BYTES = '0x20c13b0b'; @@ -10,4 +11,12 @@ const EIP_1271_BYTES_INTERFACE = new ethers.utils.Interface([ 'function isValidSignature(bytes calldata _data, bytes calldata _signature) public view', ]); -export { EIP_1271_INTERFACE, EIP_1271_BYTES_INTERFACE, MAGIC_VALUE, MAGIC_VALUE_BYTES }; +const calculateMessageHash = (message: BytesLike): string => { + if (typeof message === 'string') { + message = ethers.utils.toUtf8Bytes(message); + } + + return ethers.utils.keccak256(message); +}; + +export { EIP_1271_INTERFACE, EIP_1271_BYTES_INTERFACE, MAGIC_VALUE, MAGIC_VALUE_BYTES, calculateMessageHash };