From 7b400e7461c7166c347868e3d34b0ad785346494 Mon Sep 17 00:00:00 2001 From: Richard Liu Date: Tue, 21 Feb 2023 02:10:57 -0800 Subject: [PATCH 1/2] add eth_getPlumeSignature handler --- src/wallet.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/wallet.ts b/src/wallet.ts index 39d9f331..fe8ae698 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -62,6 +62,10 @@ export interface WalletMiddlewareOptions { req: JsonRpcRequest, version: string, ) => Promise; + processPlumeSignature?: ( + msgParams: MessageParams, + req: JsonRpcRequest, + ) => Promise; } export function createWalletMiddleware({ @@ -75,6 +79,7 @@ export function createWalletMiddleware({ processTypedMessage, processTypedMessageV3, processTypedMessageV4, + processPlumeSignature, }: WalletMiddlewareOptions): JsonRpcMiddleware { if (!getAccounts) { throw new Error('opts.getAccounts is required'); @@ -96,6 +101,7 @@ export function createWalletMiddleware({ eth_getEncryptionPublicKey: createAsyncMiddleware(encryptionPublicKey), eth_decrypt: createAsyncMiddleware(decryptMessage), personal_ecRecover: createAsyncMiddleware(personalRecover), + eth_getPlumeSignature: createAsyncMiddleware(plumeSignature), }); // @@ -356,6 +362,30 @@ export function createWalletMiddleware({ res.result = await processDecryptMessage(msgParams, req); } + async function plumeSignature( + req: JsonRpcRequest, + res: PendingJsonRpcResponse, + ): Promise { + if (!processPlumeSignature) { + throw ethErrors.rpc.methodNotSupported(); + } + + const message: string = (req.params as string[])[0]; + const address: string = await validateAndNormalizeKeyholder( + (req.params as string[])[1], + req, + ); + const extraParams: Record = + (req.params as Record[])[2] || {}; + const msgParams: MessageParams = { + ...extraParams, + from: address, + data: message, + }; + + res.result = await processPlumeSignature(msgParams, req); + } + // // utility // From e9bebeba56508b42ff3de4b0519c74f176e20da7 Mon Sep 17 00:00:00 2001 From: Richard Liu Date: Thu, 23 Feb 2023 01:47:47 -0800 Subject: [PATCH 2/2] add unit tests --- src/wallet.test.ts | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/wallet.test.ts b/src/wallet.test.ts index ac912f2e..25540147 100644 --- a/src/wallet.test.ts +++ b/src/wallet.test.ts @@ -412,3 +412,94 @@ describe('wallet', () => { }); }); }); + +describe('getPlumeSignature', () => { + it('should sign with a valid address', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(); + const witnessedMsgParams: MessageParams[] = []; + const processPlumeSignature = async (msgParams: MessageParams) => { + witnessedMsgParams.push(msgParams); + return testMsgSig; + }; + + engine.push(createWalletMiddleware({ getAccounts, processPlumeSignature })); + const message = [ + { + type: 'string', + name: 'message', + value: 'Hi, Alice!', + }, + ]; + + const payload = { + method: 'eth_getPlumeSignature', + params: [message, testAddresses[0]], + }; + const signMsgResponse = await pify(engine.handle).call(engine, payload); + const signMsgResult = signMsgResponse.result; + + expect(signMsgResult).toBeDefined(); + expect(signMsgResult).toStrictEqual(testMsgSig); + expect(witnessedMsgParams).toHaveLength(1); + expect(witnessedMsgParams[0]).toStrictEqual({ + from: testAddresses[0], + data: message, + }); + }); + + it('should throw with invalid address', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(); + const witnessedMsgParams: MessageParams[] = []; + const processPlumeSignature = async (msgParams: MessageParams) => { + witnessedMsgParams.push(msgParams); + return testMsgSig; + }; + + engine.push(createWalletMiddleware({ getAccounts, processPlumeSignature })); + const message = [ + { + type: 'string', + name: 'message', + value: 'Hi, Alice!', + }, + ]; + + const payload = { + method: 'eth_getPlumeSignature', + params: [message, '0x3d'], + }; + await expect(pify(engine.handle).call(engine, payload)).rejects.toThrow( + new Error('Invalid parameters: must provide an Ethereum address.'), + ); + }); + + it('should throw with unknown address', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(); + const witnessedMsgParams: MessageParams[] = []; + const processPlumeSignature = async (msgParams: MessageParams) => { + witnessedMsgParams.push(msgParams); + return testMsgSig; + }; + + engine.push(createWalletMiddleware({ getAccounts, processPlumeSignature })); + const message = [ + { + type: 'string', + name: 'message', + value: 'Hi, Alice!', + }, + ]; + + const payload = { + method: 'eth_getPlumeSignature', + params: [message, testUnkownAddress], + }; + const promise = pify(engine.handle).call(engine, payload); + await expect(promise).rejects.toThrow( + 'The requested account and/or method has not been authorized by the user.', + ); + }); +});