Skip to content

Commit

Permalink
feat: add disconnect account approval step (#1101)
Browse files Browse the repository at this point in the history
  • Loading branch information
euharrison authored Sep 13, 2024
1 parent 008da89 commit 026b971
Show file tree
Hide file tree
Showing 16 changed files with 473 additions and 232 deletions.
5 changes: 5 additions & 0 deletions apps/extension/src/Approvals/Approvals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AccountType, TxDetails } from "@namada/types";
import { AppHeader } from "App/Common/AppHeader";
import { TopLevelRoute } from "Approvals/types";
import { ApproveConnection } from "./ApproveConnection";
import { ApproveDisconnection } from "./ApproveDisconnection";
import { ApproveSignArbitrary } from "./ApproveSignArbitrary";
import { ApproveSignTx } from "./ApproveSignTx";
import { ConfirmSignature } from "./ConfirmSignArbitrary";
Expand Down Expand Up @@ -65,6 +66,10 @@ export const Approvals: React.FC = () => {
path={TopLevelRoute.ApproveConnection}
element={<ApproveConnection />}
/>
<Route
path={TopLevelRoute.ApproveDisconnection}
element={<ApproveDisconnection />}
/>
<Route
path={`${TopLevelRoute.ApproveSignArbitrary}/:signer`}
element={
Expand Down
9 changes: 2 additions & 7 deletions apps/extension/src/Approvals/ApproveConnection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,12 @@ export const ApproveConnection: React.FC = () => {
const requester = useRequester();
const params = useQuery();
const interfaceOrigin = params.get("interfaceOrigin");
const interfaceTabId = params.get("interfaceTabId");

const handleResponse = async (allowConnection: boolean): Promise<void> => {
if (interfaceTabId && interfaceOrigin) {
if (interfaceOrigin) {
await requester.sendMessage(
Ports.Background,
new ConnectInterfaceResponseMsg(
parseInt(interfaceTabId),
interfaceOrigin,
allowConnection
)
new ConnectInterfaceResponseMsg(interfaceOrigin, allowConnection)
);
await closeCurrentTab();
}
Expand Down
45 changes: 45 additions & 0 deletions apps/extension/src/Approvals/ApproveDisconnection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ActionButton, Alert, GapPatterns, Stack } from "@namada/components";
import { PageHeader } from "App/Common";
import { DisconnectInterfaceResponseMsg } from "background/approvals";
import { useQuery } from "hooks";
import { useRequester } from "hooks/useRequester";
import { Ports } from "router";
import { closeCurrentTab } from "utils";

export const ApproveDisconnection: React.FC = () => {
const requester = useRequester();
const params = useQuery();
const interfaceOrigin = params.get("interfaceOrigin");

const handleResponse = async (revokeConnection: boolean): Promise<void> => {
if (interfaceOrigin) {
await requester.sendMessage(
Ports.Background,
new DisconnectInterfaceResponseMsg(interfaceOrigin, revokeConnection)
);
await closeCurrentTab();
}
};

return (
<Stack full gap={GapPatterns.TitleContent} className="pt-4 pb-8">
<PageHeader title="Approve Request" />
<Stack full className="justify-between" gap={12}>
<Alert type="warning">
Approve disconnect for <strong>{interfaceOrigin}</strong>?
</Alert>
<Stack gap={2}>
<ActionButton onClick={() => handleResponse(true)}>
Approve
</ActionButton>
<ActionButton
outlineColor="yellow"
onClick={() => handleResponse(false)}
>
Reject
</ActionButton>
</Stack>
</Stack>
</Stack>
);
};
1 change: 1 addition & 0 deletions apps/extension/src/Approvals/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum TopLevelRoute {

// Connection approval
ApproveConnection = "/approve-connection",
ApproveDisconnection = "/approve-disconnection",

// Sign Tx approval
ApproveSignTx = "/approve-sign-tx",
Expand Down
9 changes: 8 additions & 1 deletion apps/extension/src/background/approvals/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Message } from "router";
import { getHandler } from "./handler";
import {
ConnectInterfaceResponseMsg,
DisconnectInterfaceResponseMsg,
RejectSignArbitraryMsg,
RejectSignTxMsg,
RevokeConnectionMsg,
Expand Down Expand Up @@ -80,13 +81,19 @@ describe("approvals handler", () => {
expect(service.approveConnection).toBeCalled();

const connectInterfaceResponseMsg = new ConnectInterfaceResponseMsg(
0,
"",
true
);
handler(env, connectInterfaceResponseMsg);
expect(service.approveConnectionResponse).toBeCalled();

const disconnectInterfaceResponseMsg = new DisconnectInterfaceResponseMsg(
"",
true
);
handler(env, disconnectInterfaceResponseMsg);
expect(service.approveDisconnectionResponse).toBeCalled();

const revokeConnectionMsg = new RevokeConnectionMsg("");
handler(env, revokeConnectionMsg);
expect(service.revokeConnection).toBeCalled();
Expand Down
46 changes: 40 additions & 6 deletions apps/extension/src/background/approvals/handler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
ApproveConnectInterfaceMsg,
ApproveDisconnectInterfaceMsg,
ApproveSignArbitraryMsg,
ApproveSignTxMsg,
IsConnectionApprovedMsg,
} from "provider";
import { Env, Handler, InternalHandler, Message } from "router";
import {
ConnectInterfaceResponseMsg,
DisconnectInterfaceResponseMsg,
QueryPendingTxBytesMsg,
QuerySignArbitraryDataMsg,
QueryTxDetailsMsg,
Expand Down Expand Up @@ -37,6 +39,16 @@ export const getHandler: (service: ApprovalsService) => Handler = (service) => {
env,
msg as ConnectInterfaceResponseMsg
);
case ApproveDisconnectInterfaceMsg:
return handleApproveDisconnectInterfaceMsg(service)(
env,
msg as ApproveDisconnectInterfaceMsg
);
case DisconnectInterfaceResponseMsg:
return handleDisconnectInterfaceResponseMsg(service)(
env,
msg as DisconnectInterfaceResponseMsg
);
case RevokeConnectionMsg:
return handleRevokeConnectionMsg(service)(
env,
Expand Down Expand Up @@ -101,8 +113,8 @@ const handleIsConnectionApprovedMsg: (
const handleApproveConnectInterfaceMsg: (
service: ApprovalsService
) => InternalHandler<ApproveConnectInterfaceMsg> = (service) => {
return async ({ senderTabId: interfaceTabId }, { origin }) => {
return await service.approveConnection(interfaceTabId, origin);
return async (_, { origin }) => {
return await service.approveConnection(origin);
};
};

Expand All @@ -111,13 +123,35 @@ const handleConnectInterfaceResponseMsg: (
) => InternalHandler<ConnectInterfaceResponseMsg> = (service) => {
return async (
{ senderTabId: popupTabId },
{ interfaceTabId, interfaceOrigin, allowConnection }
{ interfaceOrigin, allowConnection }
) => {
return await service.approveConnectionResponse(
interfaceTabId,
popupTabId,
interfaceOrigin,
allowConnection
);
};
};

const handleApproveDisconnectInterfaceMsg: (
service: ApprovalsService
) => InternalHandler<ApproveDisconnectInterfaceMsg> = (service) => {
return async (_, { origin }) => {
return await service.approveDisconnection(origin);
};
};

const handleDisconnectInterfaceResponseMsg: (
service: ApprovalsService
) => InternalHandler<DisconnectInterfaceResponseMsg> = (service) => {
return async (
{ senderTabId: popupTabId },
{ interfaceOrigin, revokeConnection }
) => {
return await service.approveDisconnectionResponse(
popupTabId,
interfaceOrigin,
allowConnection,
popupTabId
revokeConnection
);
};
};
Expand Down
4 changes: 4 additions & 0 deletions apps/extension/src/background/approvals/init.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
ApproveConnectInterfaceMsg,
ApproveDisconnectInterfaceMsg,
ApproveSignArbitraryMsg,
ApproveSignTxMsg,
IsConnectionApprovedMsg,
} from "provider";
import { Router } from "router";
import {
ConnectInterfaceResponseMsg,
DisconnectInterfaceResponseMsg,
QueryPendingTxBytesMsg,
QuerySignArbitraryDataMsg,
QueryTxDetailsMsg,
Expand All @@ -33,6 +35,8 @@ export function init(router: Router, service: ApprovalsService): void {
router.registerMessage(IsConnectionApprovedMsg);
router.registerMessage(ApproveConnectInterfaceMsg);
router.registerMessage(ConnectInterfaceResponseMsg);
router.registerMessage(ApproveDisconnectInterfaceMsg);
router.registerMessage(DisconnectInterfaceResponseMsg);
router.registerMessage(RevokeConnectionMsg);
router.registerMessage(QueryTxDetailsMsg);
router.registerMessage(QuerySignArbitraryDataMsg);
Expand Down
16 changes: 5 additions & 11 deletions apps/extension/src/background/approvals/messages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,29 +63,23 @@ describe("approvals messages", () => {
});

test("valid ConnectInterfaceResponseMsg", () => {
const msg = new ConnectInterfaceResponseMsg(0, "interface", true);
const msg = new ConnectInterfaceResponseMsg("interface", true);

expect(msg.type()).toBe(MessageType.ConnectInterfaceResponse);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid ConnectInterfaceResponseMsg", () => {
const msg = new ConnectInterfaceResponseMsg(0, "interface", true);

(msg as any).interfaceTabId = undefined;
const msg = new ConnectInterfaceResponseMsg("interface", true);
(msg as any).interfaceOrigin = undefined;

expect(() => msg.validate()).toThrow();

const msg2 = new ConnectInterfaceResponseMsg(0, "interface", true);
(msg2 as any).interfaceOrigin = undefined;
const msg2 = new ConnectInterfaceResponseMsg("interface", true);
(msg2 as any).allowConnection = undefined;

expect(() => msg2.validate()).toThrow();

const msg3 = new ConnectInterfaceResponseMsg(0, "interface", true);
(msg3 as any).allowConnection = undefined;

expect(() => msg3.validate()).toThrow();
});

test("valid RevokeConnectionMsg", () => {
Expand Down
33 changes: 27 additions & 6 deletions apps/extension/src/background/approvals/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export enum MessageType {
SubmitApprovedSignLedgerTx = "submit-approved-sign-ledger-tx",
RejectSignArbitrary = "reject-sign-arbitrary",
ConnectInterfaceResponse = "connect-interface-response",
DisconnectInterfaceResponse = "disconnect-interface-response",
RevokeConnection = "revoke-connection",
QueryTxDetails = "query-tx-details",
QuerySignArbitraryData = "query-sign-arbitrary-data",
Expand Down Expand Up @@ -144,19 +145,14 @@ export class ConnectInterfaceResponseMsg extends Message<void> {
}

constructor(
public readonly interfaceTabId: number,
public readonly interfaceOrigin: string,
public readonly allowConnection: boolean
) {
super();
}

validate(): void {
validateProps(this, [
"interfaceTabId",
"interfaceOrigin",
"allowConnection",
]);
validateProps(this, ["interfaceOrigin", "allowConnection"]);
}

route(): string {
Expand All @@ -168,6 +164,31 @@ export class ConnectInterfaceResponseMsg extends Message<void> {
}
}

export class DisconnectInterfaceResponseMsg extends Message<void> {
public static type(): MessageType {
return MessageType.DisconnectInterfaceResponse;
}

constructor(
public readonly interfaceOrigin: string,
public readonly revokeConnection: boolean
) {
super();
}

validate(): void {
validateProps(this, ["interfaceOrigin", "revokeConnection"]);
}

route(): string {
return ROUTE;
}

type(): string {
return DisconnectInterfaceResponseMsg.type();
}
}

export class RevokeConnectionMsg extends Message<void> {
public static type(): MessageType {
return MessageType.RevokeConnection;
Expand Down
Loading

1 comment on commit 026b971

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.