From 3d04adbc356fd1f94da70acc0e671bd3ef32b91d Mon Sep 17 00:00:00 2001 From: "Justin R. Evans" Date: Thu, 24 Oct 2024 11:48:03 -0400 Subject: [PATCH] feat: specify permissions in approval --- .../src/Approvals/ApproveConnection.tsx | 22 ++++++++++++------- .../src/background/approvals/handler.test.ts | 2 +- .../src/background/approvals/handler.ts | 4 ++-- .../src/background/approvals/messages.test.ts | 15 ++++++++++--- .../src/background/approvals/messages.ts | 5 +++-- .../src/background/approvals/service.test.ts | 8 +++---- .../src/background/approvals/service.ts | 8 +++---- 7 files changed, 40 insertions(+), 24 deletions(-) diff --git a/apps/extension/src/Approvals/ApproveConnection.tsx b/apps/extension/src/Approvals/ApproveConnection.tsx index a091ecf41..cfba69ca8 100644 --- a/apps/extension/src/Approvals/ApproveConnection.tsx +++ b/apps/extension/src/Approvals/ApproveConnection.tsx @@ -4,6 +4,7 @@ import { ConnectInterfaceResponseMsg } from "background/approvals"; import { useQuery } from "hooks"; import { useRequester } from "hooks/useRequester"; import { Ports } from "router"; +import { AllowedPermissions } from "storage"; import { closeCurrentTab } from "utils"; export const ApproveConnection: React.FC = () => { @@ -12,15 +13,13 @@ export const ApproveConnection: React.FC = () => { const interfaceOrigin = params.get("interfaceOrigin"); const chainId = params.get("chainId")!; - const handleResponse = async (allowConnection: boolean): Promise => { + const handleResponse = async ( + permissions: AllowedPermissions + ): Promise => { if (interfaceOrigin) { await requester.sendMessage( Ports.Background, - new ConnectInterfaceResponseMsg( - interfaceOrigin, - chainId, - allowConnection - ) + new ConnectInterfaceResponseMsg(interfaceOrigin, chainId, permissions) ); await closeCurrentTab(); } @@ -35,12 +34,19 @@ export const ApproveConnection: React.FC = () => { signing for {chainId}? - handleResponse(true)}> + + // NOTE: In the future we may want the user to have + // granular control over what access the extension may + // have for any particular domain + handleResponse(["accounts", "proofGenKeys", "signing"]) + } + > Approve handleResponse(false)} + onClick={() => handleResponse([])} > Reject diff --git a/apps/extension/src/background/approvals/handler.test.ts b/apps/extension/src/background/approvals/handler.test.ts index d7fec2cf5..5b4a5d077 100644 --- a/apps/extension/src/background/approvals/handler.test.ts +++ b/apps/extension/src/background/approvals/handler.test.ts @@ -84,7 +84,7 @@ describe("approvals handler", () => { const connectInterfaceResponseMsg = new ConnectInterfaceResponseMsg( "", chainId, - true + ["accounts", "signing"] ); handler(env, connectInterfaceResponseMsg); expect(service.approveConnectionResponse).toBeCalled(); diff --git a/apps/extension/src/background/approvals/handler.ts b/apps/extension/src/background/approvals/handler.ts index d0f17aa45..ea714fc7f 100644 --- a/apps/extension/src/background/approvals/handler.ts +++ b/apps/extension/src/background/approvals/handler.ts @@ -135,13 +135,13 @@ const handleConnectInterfaceResponseMsg: ( ) => InternalHandler = (service) => { return async ( { senderTabId: popupTabId }, - { interfaceOrigin, chainId, allowConnection } + { interfaceOrigin, chainId, permissions } ) => { return await service.approveConnectionResponse( popupTabId, interfaceOrigin, chainId, - allowConnection + permissions ); }; }; diff --git a/apps/extension/src/background/approvals/messages.test.ts b/apps/extension/src/background/approvals/messages.test.ts index 919ffd13b..57b8c05e3 100644 --- a/apps/extension/src/background/approvals/messages.test.ts +++ b/apps/extension/src/background/approvals/messages.test.ts @@ -63,7 +63,10 @@ describe("approvals messages", () => { }); test("valid ConnectInterfaceResponseMsg", () => { - const msg = new ConnectInterfaceResponseMsg("interface", "chainId", true); + const msg = new ConnectInterfaceResponseMsg("interface", "chainId", [ + "accounts", + "signing", + ]); expect(msg.type()).toBe(MessageType.ConnectInterfaceResponse); expect(msg.route()).toBe(ROUTE); @@ -71,12 +74,18 @@ describe("approvals messages", () => { }); test("invalid ConnectInterfaceResponseMsg", () => { - const msg = new ConnectInterfaceResponseMsg("interface", "chainId", true); + const msg = new ConnectInterfaceResponseMsg("interface", "chainId", [ + "accounts", + "signing", + ]); (msg as any).interfaceOrigin = undefined; expect(() => msg.validate()).toThrow(); - const msg2 = new ConnectInterfaceResponseMsg("interface", "chainId", true); + const msg2 = new ConnectInterfaceResponseMsg("interface", "chainId", [ + "accounts", + "signing", + ]); (msg2 as any).allowConnection = undefined; expect(() => msg2.validate()).toThrow(); diff --git a/apps/extension/src/background/approvals/messages.ts b/apps/extension/src/background/approvals/messages.ts index 8e263e97b..4270fa86c 100644 --- a/apps/extension/src/background/approvals/messages.ts +++ b/apps/extension/src/background/approvals/messages.ts @@ -3,6 +3,7 @@ import { ROUTE } from "./constants"; import { TxDetails } from "@namada/types"; import { ResponseSign } from "@zondax/ledger-namada"; +import { AllowedPermissions } from "storage"; import { validateProps } from "utils"; export enum MessageType { @@ -148,13 +149,13 @@ export class ConnectInterfaceResponseMsg extends Message { constructor( public readonly interfaceOrigin: string, public readonly chainId: string, - public readonly allowConnection: boolean + public readonly permissions: AllowedPermissions ) { super(); } validate(): void { - validateProps(this, ["interfaceOrigin", "chainId", "allowConnection"]); + validateProps(this, ["interfaceOrigin", "chainId", "permissions"]); } route(): string { diff --git a/apps/extension/src/background/approvals/service.test.ts b/apps/extension/src/background/approvals/service.test.ts index 735ed35d5..321d2e057 100644 --- a/apps/extension/src/background/approvals/service.test.ts +++ b/apps/extension/src/background/approvals/service.test.ts @@ -323,7 +323,7 @@ describe("approvals service", () => { popupTabId, interfaceOrigin, chainId, - true + ["accounts", "signing"] ); expect(service["resolverMap"][popupTabId].resolve).toHaveBeenCalled(); @@ -343,7 +343,7 @@ describe("approvals service", () => { popupTabId, interfaceOrigin, chainId, - true + ["accounts", "signing"] ) ).rejects.toBeDefined(); }); @@ -363,7 +363,7 @@ describe("approvals service", () => { popupTabId, interfaceOrigin, chainId, - false + [] ); expect(service["resolverMap"][popupTabId].reject).toHaveBeenCalled(); @@ -449,7 +449,7 @@ describe("approvals service", () => { popupTabId, interfaceOrigin, chainId, - false + [] ); expect(service["resolverMap"][popupTabId].reject).toHaveBeenCalled(); diff --git a/apps/extension/src/background/approvals/service.ts b/apps/extension/src/background/approvals/service.ts index 9247a8e26..7e54ca0b8 100644 --- a/apps/extension/src/background/approvals/service.ts +++ b/apps/extension/src/background/approvals/service.ts @@ -14,7 +14,7 @@ import { PermissionsService } from "background/permissions"; import { SdkService } from "background/sdk"; import { VaultService } from "background/vault"; import { ExtensionBroadcaster } from "extension"; -import { LocalStorage } from "storage"; +import { AllowedPermissions, LocalStorage } from "storage"; import { fromEncodedTx } from "utils"; import { EncodedTxData, PendingTx } from "./types"; @@ -224,16 +224,16 @@ export class ApprovalsService { popupTabId: number, interfaceOrigin: string, chainId: string, - allowConnection: boolean + permissions: AllowedPermissions ): Promise { const resolvers = this.getResolver(popupTabId); - if (allowConnection) { + if (permissions.length) { try { await this.permissionsService.enablePermissions( interfaceOrigin, chainId, - ["accounts", "proofGenKeys", "signing"] + permissions ); // Enable signing for this chain await this.chainService.updateChain(chainId);