Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data fetching fixes #641

Merged
merged 5 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions apps/extension/src/background/approvals/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ApproveConnectInterfaceMsg,
ApproveSignArbitraryMsg,
ApproveTxMsg,
IsConnectionApprovedMsg,
} from "provider";
import { Env, Handler, InternalHandler, Message } from "router";
import {
Expand All @@ -26,6 +27,11 @@ export const getHandler: (service: ApprovalsService) => Handler = (service) => {
env,
msg as SubmitApprovedTxMsg
);
case IsConnectionApprovedMsg:
return handleIsConnectionApprovedMsg(service)(
env,
msg as IsConnectionApprovedMsg
);
case ApproveConnectInterfaceMsg:
return handleApproveConnectInterfaceMsg(service)(
env,
Expand Down Expand Up @@ -87,6 +93,14 @@ const handleSubmitApprovedTxMsg: (
};
};

const handleIsConnectionApprovedMsg: (
service: ApprovalsService
) => InternalHandler<IsConnectionApprovedMsg> = (service) => {
return async (_, { origin }) => {
return await service.isConnectionApproved(origin);
};
};

const handleApproveConnectInterfaceMsg: (
service: ApprovalsService
) => InternalHandler<ApproveConnectInterfaceMsg> = (service) => {
Expand Down
2 changes: 2 additions & 0 deletions apps/extension/src/background/approvals/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ApproveConnectInterfaceMsg,
ApproveSignArbitraryMsg,
ApproveTxMsg,
IsConnectionApprovedMsg,
} from "provider";
import { Router } from "router";
import {
Expand All @@ -24,6 +25,7 @@ export function init(router: Router, service: ApprovalsService): void {
router.registerMessage(ApproveSignArbitraryMsg);
router.registerMessage(RejectSignatureMsg);
router.registerMessage(SubmitApprovedSignatureMsg);
router.registerMessage(IsConnectionApprovedMsg);
router.registerMessage(ApproveConnectInterfaceMsg);
router.registerMessage(ConnectInterfaceResponseMsg);
router.registerMessage(RevokeConnectionMsg);
Expand Down
6 changes: 5 additions & 1 deletion apps/extension/src/background/approvals/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { KeyRingService, TabStore } from "background/keyring";
import { LedgerService } from "background/ledger";
import { VaultService } from "background/vault";
import BigNumber from "bignumber.js";
import { ExtensionBroadcaster } from "extension";
import createMockInstance from "jest-create-mock-instance";
import { KVStoreMock } from "test/init";
import { ApprovalsService } from "./service";
Expand Down Expand Up @@ -55,6 +56,8 @@ describe.only("approvals service", () => {
const vaultService: jest.Mocked<VaultService> = createMockInstance(
VaultService as any
);
const broadcaster: jest.Mocked<ExtensionBroadcaster> =
createMockInstance(ExtensionBroadcaster);

service = new ApprovalsService(
txStore,
Expand All @@ -63,7 +66,8 @@ describe.only("approvals service", () => {
approvedOriginsStore,
keyRingService,
ledgerService,
vaultService
vaultService,
broadcaster
);
});

Expand Down
23 changes: 17 additions & 6 deletions apps/extension/src/background/approvals/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {
import { assertNever, paramsToUrl } from "@namada/utils";
import { KeyRingService, TabStore } from "background/keyring";
import { LedgerService } from "background/ledger";

import { VaultService } from "background/vault";
import { ExtensionBroadcaster } from "extension";
import { ApprovedOriginsStore, TxStore } from "./types";
import {
APPROVED_ORIGINS_KEY,
Expand Down Expand Up @@ -52,7 +52,8 @@ export class ApprovalsService {
protected readonly approvedOriginsStore: KVStore<ApprovedOriginsStore>,
protected readonly keyRingService: KeyRingService,
protected readonly ledgerService: LedgerService,
protected readonly vaultService: VaultService
protected readonly vaultService: VaultService,
protected readonly broadcaster: ExtensionBroadcaster
) {}

async approveSignature(
Expand Down Expand Up @@ -344,6 +345,13 @@ export class ApprovalsService {
return await this._clearPendingTx(msgId);
}

async isConnectionApproved(interfaceOrigin: string): Promise<boolean> {
const approvedOrigins =
(await this.approvedOriginsStore.get(APPROVED_ORIGINS_KEY)) || [];

return approvedOrigins.includes(interfaceOrigin);
}

async approveConnection(
interfaceTabId: number,
interfaceOrigin: string
Expand All @@ -357,10 +365,9 @@ export class ApprovalsService {
interfaceOrigin,
});

const approvedOrigins =
(await this.approvedOriginsStore.get(APPROVED_ORIGINS_KEY)) || [];
const alreadyApproved = await this.isConnectionApproved(interfaceOrigin);

if (!approvedOrigins.includes(interfaceOrigin)) {
if (!alreadyApproved) {
const approvalWindow = await this._launchApprovalWindow(url);
const popupTabId = approvalWindow.tabs?.[0]?.id;

Expand All @@ -376,6 +383,9 @@ export class ApprovalsService {
this.resolverMap[popupTabId] = { resolve, reject };
});
}

// A resolved promise is implicitly returned here if the origin had
// previously been approved.
}

async approveConnectionResponse(
Expand Down Expand Up @@ -403,7 +413,8 @@ export class ApprovalsService {
}

async revokeConnection(originToRevoke: string): Promise<void> {
return removeApprovedOrigin(this.approvedOriginsStore, originToRevoke);
await removeApprovedOrigin(this.approvedOriginsStore, originToRevoke);
await this.broadcaster.revokeConnection();
}

private async _clearPendingTx(msgId: string): Promise<void> {
Expand Down
3 changes: 2 additions & 1 deletion apps/extension/src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ const init = new Promise<void>(async (resolve) => {
approvedOriginsStore,
keyRingService,
ledgerService,
vaultService
vaultService,
broadcaster
);

// Initialize messages and handlers
Expand Down
24 changes: 24 additions & 0 deletions apps/extension/src/content/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,26 @@ export class VaultLockedEventMsg extends Message<void> {
}
}

export class ConnectionRevokedEventMsg extends Message<void> {
public static type(): Events {
return Events.ConnectionRevoked;
}

constructor() {
super();
}

validate(): void {}

route(): string {
return Routes.InteractionForeground;
}

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

export function initEvents(router: Router): void {
router.registerMessage(AccountChangedEventMsg);
router.registerMessage(NetworkChangedEventMsg);
Expand All @@ -210,6 +230,7 @@ export function initEvents(router: Router): void {
router.registerMessage(TxStartedEvent);
router.registerMessage(TxCompletedEvent);
router.registerMessage(VaultLockedEventMsg);
router.registerMessage(ConnectionRevokedEventMsg);

router.addHandler(Routes.InteractionForeground, (_, msg) => {
const clonedMsg =
Expand Down Expand Up @@ -248,6 +269,9 @@ export function initEvents(router: Router): void {
case VaultLockedEventMsg:
window.dispatchEvent(new CustomEvent(Events.ExtensionLocked));
break;
case ConnectionRevokedEventMsg:
window.dispatchEvent(new CustomEvent(Events.ConnectionRevoked));
break;
default:
throw new Error("Unknown msg type");
}
Expand Down
5 changes: 5 additions & 0 deletions apps/extension/src/extension/ExtensionBroadcaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { KVStore } from "@namada/storage";
import { TabStore, syncTabs } from "background/keyring";
import {
AccountChangedEventMsg,
ConnectionRevokedEventMsg,
NetworkChangedEventMsg,
ProposalsUpdatedEventMsg,
TxCompletedEvent,
Expand Down Expand Up @@ -59,6 +60,10 @@ export class ExtensionBroadcaster {
await this.sendMsgToTabs(new VaultLockedEventMsg());
}

async revokeConnection(): Promise<void> {
await this.sendMsgToTabs(new ConnectionRevokedEventMsg());
}

/**
* Query all existing tabs, and send provided message to each
*/
Expand Down
6 changes: 5 additions & 1 deletion apps/extension/src/provider/InjectedNamada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ import { InjectedProxy } from "./InjectedProxy";
import { Signer } from "./Signer";

export class InjectedNamada implements INamada {
constructor(private readonly _version: string) { }
constructor(private readonly _version: string) {}

public async connect(): Promise<void> {
return await InjectedProxy.requestMethod<string, void>("connect");
}

public async isConnected(): Promise<boolean> {
return await InjectedProxy.requestMethod<string, boolean>("isConnected");
}

public async accounts(): Promise<DerivedAccount[]> {
return await InjectedProxy.requestMethod<string, DerivedAccount[]>(
"accounts"
Expand Down
14 changes: 13 additions & 1 deletion apps/extension/src/provider/Namada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
FetchAndStoreMaspParamsMsg,
GetChainMsg,
HasMaspParamsMsg,
IsConnectionApprovedMsg,
QueryAccountsMsg,
QueryBalancesMsg,
QueryDefaultAccountMsg,
Expand All @@ -28,7 +29,7 @@ export class Namada implements INamada {
constructor(
private readonly _version: string,
protected readonly requester?: MessageRequester
) { }
) {}

public async connect(): Promise<void> {
return await this.requester?.sendMessage(
Expand All @@ -37,6 +38,17 @@ export class Namada implements INamada {
);
}

public async isConnected(): Promise<boolean> {
if (!this.requester) {
throw new Error("no requester");
}

return await this.requester.sendMessage(
Ports.Background,
new IsConnectionApprovedMsg()
);
}

public async accounts(
// TODO: This argument should be removed in the future!
_chainId?: string
Expand Down
12 changes: 8 additions & 4 deletions apps/extension/src/provider/Proxy.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { KVStore } from "@namada/storage";
import { ApprovedOriginsStore, APPROVED_ORIGINS_KEY } from "background/approvals";
import {
APPROVED_ORIGINS_KEY,
ApprovedOriginsStore,
} from "background/approvals";

import { Namada } from "./Namada";
import { ProxyRequest, ProxyRequestResponse, ProxyRequestTypes } from "./types";

export class Proxy {
static start(
namada: Namada,
approvedOriginsStore: KVStore<ApprovedOriginsStore>,
approvedOriginsStore: KVStore<ApprovedOriginsStore>
): void {
Proxy.addMessageListener(async (e) => {
const message = e.data;
Expand All @@ -18,8 +21,9 @@ export class Proxy {

const { method, args } = message;

if (method !== "connect") {
const approvedOrigins = await approvedOriginsStore.get(APPROVED_ORIGINS_KEY) || [];
if (method !== "connect" && method !== "isConnected") {
const approvedOrigins =
(await approvedOriginsStore.get(APPROVED_ORIGINS_KEY)) || [];
if (!approvedOrigins.includes(e.origin)) {
return;
}
Expand Down
24 changes: 23 additions & 1 deletion apps/extension/src/provider/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum Route {
}

enum MessageType {
IsConnectionApproved = "is-connection-approved",
ApproveConnectInterface = "approve-connect-interface",
QueryAccounts = "query-accounts",
QueryDefaultAccount = "query-default-account",
Expand All @@ -42,6 +43,27 @@ enum MessageType {
/**
* Messages routed from providers to Chains service
*/
export class IsConnectionApprovedMsg extends Message<boolean> {
public static type(): MessageType {
return MessageType.IsConnectionApproved;
}

constructor() {
super();
}

validate(): void {
return;
}

route(): string {
return Route.Approvals;
}

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

export class ApproveConnectInterfaceMsg extends Message<void> {
public static type(): MessageType {
Expand Down Expand Up @@ -74,7 +96,7 @@ export class GetChainMsg extends Message<Chain> {
super();
}

validate(): void { }
validate(): void {}

route(): string {
return Route.Chains;
Expand Down
5 changes: 3 additions & 2 deletions apps/extension/src/test/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const cryptoMemory = require("@namada/crypto").__wasm.memory;
export class KVStoreMock<T> implements KVStore<T> {
private storage: { [key: string]: T | null } = {};

constructor(readonly _prefix: string) { }
constructor(readonly _prefix: string) {}

get<U extends T>(key: string): Promise<U | undefined> {
return new Promise((resolve) => {
Expand Down Expand Up @@ -141,7 +141,8 @@ export const init = async (): Promise<{
approvedOriginsStore,
keyRingService,
ledgerService,
vaultService
vaultService,
broadcaster
);

const init = new Promise<void>(async (resolve) => {
Expand Down
Loading
Loading