Skip to content

Commit

Permalink
Merge pull request #5285 from WalletConnect/fix/verify-v3
Browse files Browse the repository at this point in the history
fix: Verify V3
  • Loading branch information
ganchoradkov authored Aug 27, 2024
2 parents 1a7dc28 + bc41e19 commit dd255e8
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 66 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/constants/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ export const VERIFY_CONTEXT = "verify-api";
const VERIFY_SERVER_COM = "https://verify.walletconnect.com";
const VERIFY_SERVER_ORG = "https://verify.walletconnect.org";
export const VERIFY_SERVER = VERIFY_SERVER_ORG;
export const VERIFY_SERVER_V2 = `${VERIFY_SERVER}/v2`;
export const VERIFY_SERVER_V3 = `${VERIFY_SERVER}/v3`;

export const TRUSTED_VERIFY_URLS = [VERIFY_SERVER_COM, VERIFY_SERVER_ORG];
46 changes: 19 additions & 27 deletions packages/core/src/controllers/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { ICore, IVerify } from "@walletconnect/types";
import { isBrowser, isNode, P256KeyDataType, verifyP256Jwt } from "@walletconnect/utils";
import { FIVE_SECONDS, ONE_SECOND, toMiliseconds } from "@walletconnect/time";
import { getDocument } from "@walletconnect/window-getters";
import { decodeJWT } from "@walletconnect/relay-auth";

import {
CORE_STORAGE_PREFIX,
CORE_VERSION,
TRUSTED_VERIFY_URLS,
VERIFY_CONTEXT,
VERIFY_SERVER,
VERIFY_SERVER_V2,
VERIFY_SERVER_V3,
} from "../constants";
import { IKeyValueStorage } from "@walletconnect/keyvaluestorage";

Expand All @@ -29,7 +30,7 @@ export class Verify extends IVerify {
public name = VERIFY_CONTEXT;
private abortController: AbortController;
private isDevEnv;
private verifyUrlV2 = VERIFY_SERVER_V2;
private verifyUrlV3 = VERIFY_SERVER_V3;
private storagePrefix = CORE_STORAGE_PREFIX;
private version = CORE_VERSION;
private publicKey?: Jwk;
Expand Down Expand Up @@ -62,40 +63,30 @@ export class Verify extends IVerify {

public register: IVerify["register"] = async (params) => {
if (!isBrowser()) return;
const origin = window.location.origin;
const { id, decryptedId } = params;
const url = `${this.verifyUrlV2}/attestation?projectId=${this.core.projectId}`;
let src = "";
try {
const response = await fetch(url, {
method: "POST",
body: JSON.stringify({ id, decryptedId }),
});
const { srcdoc } = await response.json();
src = srcdoc;
this.logger.debug("srcdoc fetched", src);
} catch (e) {
this.logger.warn(e);
return;
}
const src = `${this.verifyUrlV3}/attestation?projectId=${this.core.projectId}&origin=${origin}&id=${id}&decryptedId=${decryptedId}`;
try {
const document = getDocument() as Document;
const abortTimeout = this.startAbortTimer(ONE_SECOND * 3);
const attestationJwt = await new Promise((resolve) => {
const abortTimeout = this.startAbortTimer(ONE_SECOND * 5);
const attestationJwt = await new Promise((resolve, reject) => {
const abortListener = () => {
window.removeEventListener("message", listener);
document.body.removeChild(iframe);
throw new Error("attestation aborted");
reject("attestation aborted");
};
this.abortController.signal.addEventListener("abort", abortListener, {
signal: this.abortController.signal,
});
this.abortController.signal.addEventListener("abort", abortListener);
const iframe = document.createElement("iframe");
iframe.srcdoc = src;
iframe.src = src;
iframe.style.display = "none";
iframe.addEventListener("error", abortListener, { signal: this.abortController.signal });
const listener = (event: MessageEvent) => {
if (!event.data) return;
const data = JSON.parse(event.data);
if (data.type === "verify_attestation") {
const decoded = decodeJWT(data.attestation) as unknown as { payload: JwkPayload };
if (decoded.payload.id !== id) return;

clearInterval(abortTimeout);
document.body.removeChild(iframe);
this.abortController.signal.removeEventListener("abort", abortListener);
Expand All @@ -116,14 +107,15 @@ export class Verify extends IVerify {

public resolve: IVerify["resolve"] = async (params) => {
if (this.isDevEnv) return "";
const { attestationId, hash } = params;

const { attestationId, hash, encryptedId } = params;
if (attestationId === "") {
this.logger.debug("resolve: attestationId is empty, skipping");
return;
}

if (attestationId) {
const decoded = decodeJWT(attestationId) as unknown as { payload: JwkPayload };
if (decoded.payload.id !== encryptedId) return;
const validation = await this.isValidJwtAttestation(attestationId);
if (validation) return validation;
}
Expand Down Expand Up @@ -165,9 +157,9 @@ export class Verify extends IVerify {

private fetchPublicKey = async () => {
try {
this.logger.debug(`fetching public key from: ${this.verifyUrlV2}`);
this.logger.debug(`fetching public key from: ${this.verifyUrlV3}`);
const timeout = this.startAbortTimer(FIVE_SECONDS);
const result = await fetch(`${this.verifyUrlV2}/public-key`, {
const result = await fetch(`${this.verifyUrlV3}/public-key`, {
signal: this.abortController.signal,
});
clearTimeout(timeout);
Expand Down
54 changes: 31 additions & 23 deletions packages/sign-client/src/controllers/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,12 @@ export class Engine extends IEngine {
try {
if (isJsonRpcRequest(payload)) {
this.client.core.history.set(topic, payload);
this.onRelayEventRequest({ topic, payload, attestation });
this.onRelayEventRequest({
topic,
payload,
attestation,
encryptedId: hashMessage(message),
});
} else if (isJsonRpcResponse(payload)) {
await this.client.core.history.resolve(payload);
await this.onRelayEventResponse({ topic, payload });
Expand Down Expand Up @@ -1370,7 +1375,7 @@ export class Engine extends IEngine {
};

private processRequest: EnginePrivate["onRelayEventRequest"] = async (event) => {
const { topic, payload, attestation } = event;
const { topic, payload, attestation, encryptedId } = event;
const reqMethod = payload.method as JsonRpcTypes.WcMethod;

if (this.shouldIgnorePairingRequest({ topic, requestMethod: reqMethod })) {
Expand All @@ -1379,7 +1384,7 @@ export class Engine extends IEngine {

switch (reqMethod) {
case "wc_sessionPropose":
return await this.onSessionProposeRequest(topic, payload, attestation);
return await this.onSessionProposeRequest({ topic, payload, attestation, encryptedId });
case "wc_sessionSettle":
return await this.onSessionSettleRequest(topic, payload);
case "wc_sessionUpdate":
Expand All @@ -1391,11 +1396,16 @@ export class Engine extends IEngine {
case "wc_sessionDelete":
return await this.onSessionDeleteRequest(topic, payload);
case "wc_sessionRequest":
return await this.onSessionRequest(topic, payload, attestation);
return await this.onSessionRequest({ topic, payload, attestation, encryptedId });
case "wc_sessionEvent":
return await this.onSessionEventRequest(topic, payload);
case "wc_sessionAuthenticate":
return await this.onSessionAuthenticateRequest(topic, payload, attestation);
return await this.onSessionAuthenticateRequest({
topic,
payload,
attestation,
encryptedId,
});
default:
return this.client.logger.info(`Unsupported request method ${reqMethod}`);
}
Expand Down Expand Up @@ -1455,11 +1465,8 @@ export class Engine extends IEngine {

// ---------- Relay Events Handlers --------------------------------- //

private onSessionProposeRequest: EnginePrivate["onSessionProposeRequest"] = async (
topic,
payload,
attestation,
) => {
private onSessionProposeRequest: EnginePrivate["onSessionProposeRequest"] = async (args) => {
const { topic, payload, attestation, encryptedId } = args;
const { params, id } = payload;
try {
this.isValidConnect({ ...payload.params });
Expand All @@ -1470,6 +1477,7 @@ export class Engine extends IEngine {
const verifyContext = await this.getVerifyContext({
attestationId: attestation,
hash: hashMessage(JSON.stringify(payload)),
encryptedId,
metadata: proposal.proposer.metadata,
});
this.client.events.emit("session_proposal", { id, params: proposal, verifyContext });
Expand Down Expand Up @@ -1766,18 +1774,16 @@ export class Engine extends IEngine {
}
};

private onSessionRequest: EnginePrivate["onSessionRequest"] = async (
topic,
payload,
attestation,
) => {
private onSessionRequest: EnginePrivate["onSessionRequest"] = async (args) => {
const { topic, payload, attestation, encryptedId } = args;
const { id, params } = payload;
try {
await this.isValidRequest({ topic, ...params });
const session = this.client.session.get(topic);
const verifyContext = await this.getVerifyContext({
attestationId: attestation,
hash: hashMessage(JSON.stringify(formatJsonRpcRequest("wc_sessionRequest", params, id))),
encryptedId,
metadata: session.peer.metadata,
});
const request = {
Expand Down Expand Up @@ -1869,15 +1875,15 @@ export class Engine extends IEngine {
};

private onSessionAuthenticateRequest: EnginePrivate["onSessionAuthenticateRequest"] = async (
topic,
payload,
attestation,
args,
) => {
const { topic, payload, attestation, encryptedId } = args;
try {
const { requester, authPayload, expiryTimestamp } = payload.params;
const verifyContext = await this.getVerifyContext({
attestationId: attestation,
hash: hashMessage(JSON.stringify(payload)),
encryptedId,
metadata: this.client.metadata,
});
const pendingRequest = {
Expand Down Expand Up @@ -2028,9 +2034,9 @@ export class Engine extends IEngine {
const proposals = this.client.proposal.getAll();
const proposal = proposals.find((p) => p.pairingTopic === pairing.topic);
if (!proposal) return;
this.onSessionProposeRequest(
pairing.topic,
formatJsonRpcRequest(
this.onSessionProposeRequest({
topic: pairing.topic,
payload: formatJsonRpcRequest(
"wc_sessionPropose",
{
requiredNamespaces: proposal.requiredNamespaces,
Expand All @@ -2041,7 +2047,7 @@ export class Engine extends IEngine {
},
proposal.id,
),
);
});
};

// ---------- Validation Helpers ------------------------------------ //
Expand Down Expand Up @@ -2428,9 +2434,10 @@ export class Engine extends IEngine {
private getVerifyContext = async (params: {
attestationId?: string;
hash?: string;
encryptedId?: string;
metadata: CoreTypes.Metadata;
}) => {
const { attestationId, hash, metadata } = params;
const { attestationId, hash, encryptedId, metadata } = params;
const context: Verify.Context = {
verified: {
verifyUrl: metadata.verifyUrl || VERIFY_SERVER,
Expand All @@ -2443,6 +2450,7 @@ export class Engine extends IEngine {
const result = await this.client.core.verify.resolve({
attestationId,
hash,
encryptedId,
verifyUrl: metadata.verifyUrl,
});
if (result) {
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/core/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export abstract class IVerify {
public abstract resolve(params: {
attestationId?: string;
hash?: string;
encryptedId?: string;
verifyUrl?: string;
}): Promise<{ origin: string; isScam?: boolean }>;
}
34 changes: 19 additions & 15 deletions packages/types/src/sign-client/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export declare namespace EngineTypes {
topic: string;
payload: T;
attestation?: string;
encryptedId?: string;
}

interface ConnectParams {
Expand Down Expand Up @@ -248,11 +249,12 @@ export interface EnginePrivate {

cleanup(): Promise<void>;

onSessionProposeRequest(
topic: string,
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionPropose"]>,
attestation?: string,
): Promise<void>;
onSessionProposeRequest(params: {
topic: string;
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionPropose"]>;
attestation?: string;
encryptedId?: string;
}): Promise<void>;

onSessionProposeResponse(
topic: string,
Expand Down Expand Up @@ -304,11 +306,12 @@ export interface EnginePrivate {
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionDelete"]>,
): Promise<void>;

onSessionRequest(
topic: string,
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionRequest"]>,
attestation?: string,
): Promise<void>;
onSessionRequest(params: {
topic: string;
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionRequest"]>;
attestation?: string;
encryptedId?: string;
}): Promise<void>;

onSessionRequestResponse(
topic: string,
Expand All @@ -320,11 +323,12 @@ export interface EnginePrivate {
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionEvent"]>,
): Promise<void>;

onSessionAuthenticateRequest(
topic: string,
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionAuthenticate"]>,
attestation?: string,
): Promise<void>;
onSessionAuthenticateRequest(params: {
topic: string;
payload: JsonRpcRequest<JsonRpcTypes.RequestParams["wc_sessionAuthenticate"]>;
attestation?: string;
encryptedId?: string;
}): Promise<void>;

onSessionAuthenticateResponse(
topic: string,
Expand Down

0 comments on commit dd255e8

Please sign in to comment.