Skip to content

Commit

Permalink
Merge branch 'v2.0' into fix/relay-socket-on-ping
Browse files Browse the repository at this point in the history
  • Loading branch information
paranormal authored Dec 11, 2024
2 parents bc08fe1 + 2464e53 commit 29665e9
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/pr_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ jobs:
env:
TEST_RELAY_URL: ${{ secrets.TEST_RELAY_URL }}
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
TEST_PROJECT_ID_MOBILE: ${{ vars.TEST_PROJECT_ID_MOBILE }}
TEST_MOBILE_APP_ID: ${{ vars.TEST_MOBILE_APP_ID }}
steps:
- name: checkout
uses: actions/checkout@v4
Expand Down
26 changes: 24 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@walletconnect/jsonrpc-provider": "1.0.14",
"@walletconnect/jsonrpc-types": "1.0.4",
"@walletconnect/jsonrpc-utils": "1.0.8",
"@walletconnect/jsonrpc-ws-connection": "1.0.14",
"@walletconnect/jsonrpc-ws-connection": "1.0.16",
"@walletconnect/keyvaluestorage": "1.1.1",
"@walletconnect/logger": "2.1.2",
"@walletconnect/relay-api": "1.0.11",
Expand Down
13 changes: 11 additions & 2 deletions packages/core/src/controllers/relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import {
formatRelayRpcUrl,
isOnline,
subscribeToNetworkChange,
getBundleId,
getAppId,
isAndroid,
isIos,
getInternalError,
isNode,
calcExpiry,
Expand Down Expand Up @@ -76,6 +78,7 @@ export class Relayer extends IRelayer {

private relayUrl: string;
private projectId: string | undefined;
private packageName: string | undefined;
private bundleId: string | undefined;
private hasExperiencedNetworkDisruption = false;
private pingTimeout: NodeJS.Timeout | undefined;
Expand All @@ -101,7 +104,12 @@ export class Relayer extends IRelayer {

this.relayUrl = opts?.relayUrl || RELAYER_DEFAULT_RELAY_URL;
this.projectId = opts.projectId;
this.bundleId = getBundleId();

if (isAndroid()) {
this.packageName = getAppId();
} else if (isIos()) {
this.bundleId = getAppId();
}

// re-assigned during init()
this.provider = {} as IJsonRpcProvider;
Expand Down Expand Up @@ -451,6 +459,7 @@ export class Relayer extends IRelayer {
auth,
useOnCloseEvent: true,
bundleId: this.bundleId,
packageName: this.packageName,
}),
),
);
Expand Down
166 changes: 165 additions & 1 deletion packages/core/test/relayer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@ import {
SUBSCRIBER_EVENTS,
TRANSPORT_TYPES,
} from "../src";
import { disconnectSocket, TEST_CORE_OPTIONS, throttle } from "./shared";
import {
disconnectSocket,
TEST_MOBILE_APP_ID,
TEST_CORE_OPTIONS,
TEST_PROJECT_ID_MOBILE,
throttle,
} from "./shared";
import { ICore, IRelayer, ISubscriber } from "@walletconnect/types";
import Sinon from "sinon";
import { JsonRpcRequest } from "@walletconnect/jsonrpc-utils";
import { createExpiringPromise, generateRandomBytes32, hashMessage } from "@walletconnect/utils";
import * as utils from "@walletconnect/utils";

describe("Relayer", () => {
const logger = pino(getDefaultLoggerOptions({ level: CORE_DEFAULT.logger }));
Expand Down Expand Up @@ -343,4 +350,161 @@ describe("Relayer", () => {
});
});
});
describe("packageName and bundleId validations", () => {
beforeEach(async () => {
core = new Core({ ...TEST_CORE_OPTIONS, projectId: TEST_PROJECT_ID_MOBILE });
relayer = core.relayer;
await core.start();
});

it("[Android] packageName included in Cloud Settings - should connect", async () => {
// Mock Android environment
vi.spyOn(utils, "isAndroid").mockReturnValue(true);
vi.spyOn(utils, "isIos").mockReturnValue(false);
vi.spyOn(utils, "getAppId").mockReturnValue(TEST_MOBILE_APP_ID);

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();

// @ts-expect-error - accessing private property for testing
const wsUrl = relayer.provider.connection.url;
expect(wsUrl).to.include(`packageName=${TEST_MOBILE_APP_ID}`);
expect(relayer.connected).to.be.true;
});

it("[Android] packageName undefined - should connect", async () => {
// Mock Android environment
vi.spyOn(utils, "isAndroid").mockReturnValue(true);
vi.spyOn(utils, "isIos").mockReturnValue(false);
vi.spyOn(utils, "getAppId").mockReturnValue(undefined);

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();

// @ts-expect-error - accessing private property for testing
const wsUrl = relayer.provider.connection.url;
expect(wsUrl).not.to.include("packageName=");
expect(relayer.connected).to.be.true;
});

it("[Android] packageName not included in Cloud Settings - should fail", async () => {
// Mock Android environment
vi.spyOn(utils, "isAndroid").mockReturnValue(true);
vi.spyOn(utils, "isIos").mockReturnValue(false);
vi.spyOn(utils, "getAppId").mockReturnValue("com.example.wrong");

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();
relayer.provider.on(RELAYER_PROVIDER_EVENTS.payload, (payload) => {
expect(payload.error.message).to.include("Unauthorized: origin not allowed");
});

await throttle(1000);
});

it("[iOS] bundleId included in Cloud Settings - should connect", async () => {
// Mock iOS environment
vi.spyOn(utils, "isAndroid").mockReturnValue(false);
vi.spyOn(utils, "isIos").mockReturnValue(true);
vi.spyOn(utils, "getAppId").mockReturnValue(TEST_MOBILE_APP_ID);

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();

// @ts-expect-error - accessing private property for testing
const wsUrl = relayer.provider.connection.url;
expect(wsUrl).to.include(`bundleId=${TEST_MOBILE_APP_ID}`);
});

it("[iOS] bundleId undefined - should connect", async () => {
// Mock iOS environment
vi.spyOn(utils, "isAndroid").mockReturnValue(false);
vi.spyOn(utils, "isIos").mockReturnValue(true);
vi.spyOn(utils, "getAppId").mockReturnValue(undefined);

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();

// @ts-expect-error - accessing private property for testing
const wsUrl = relayer.provider.connection.url;
expect(wsUrl).not.to.include("bundleId=");
expect(relayer.connected).to.be.true;
});

it("[iOS] bundleId not included in Cloud Settings - should fail", async () => {
// Mock iOS environment
vi.spyOn(utils, "isAndroid").mockReturnValue(false);
vi.spyOn(utils, "isIos").mockReturnValue(true);
vi.spyOn(utils, "getAppId").mockReturnValue("com.example.wrong");

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();
relayer.provider.on(RELAYER_PROVIDER_EVENTS.payload, (payload) => {
expect(payload.error.message).to.include("Unauthorized: origin not allowed");
});

await throttle(1000);
});

it("[Web] packageName and bundleId not set - should connect", async () => {
// Mock non-mobile environment
vi.spyOn(utils, "isAndroid").mockReturnValue(false);
vi.spyOn(utils, "isIos").mockReturnValue(false);
vi.spyOn(utils, "getAppId").mockReturnValue(TEST_MOBILE_APP_ID);

relayer = new Relayer({
core,
relayUrl: TEST_CORE_OPTIONS.relayUrl,
projectId: TEST_PROJECT_ID_MOBILE,
});

await relayer.init();
await relayer.transportOpen();

// @ts-expect-error - accessing private property for testing
const wsUrl = relayer.provider.connection.url;
expect(wsUrl).not.to.include("packageName=");
expect(wsUrl).not.to.include("bundleId=");
});

afterEach(() => {
vi.restoreAllMocks();
});
});
});
8 changes: 8 additions & 0 deletions packages/core/test/shared/values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export const TEST_PROJECT_ID = process.env.TEST_PROJECT_ID
? process.env.TEST_PROJECT_ID
: undefined;

export const TEST_PROJECT_ID_MOBILE = process.env.TEST_PROJECT_ID_MOBILE
? process.env.TEST_PROJECT_ID_MOBILE
: undefined;

export const TEST_CORE_OPTIONS: CoreTypes.Options = {
logger: "fatal",
relayUrl: TEST_RELAY_URL,
Expand All @@ -17,6 +21,10 @@ export const TEST_CORE_OPTIONS: CoreTypes.Options = {
},
};

export const TEST_MOBILE_APP_ID = process.env.TEST_MOBILE_APP_ID
? process.env.TEST_MOBILE_APP_ID
: undefined;

// default db name for persistent storage tests
export const DEFAULT_DB_NAME = "./test/tmp/persistent-test.db";

Expand Down
1 change: 1 addition & 0 deletions packages/types/src/core/relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export declare namespace RelayerTypes {
projectId?: string;
useOnCloseEvent?: boolean;
bundleId?: string;
packageName?: string;
}
}

Expand Down
24 changes: 22 additions & 2 deletions packages/utils/src/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ export function isReactNative(): boolean {
return !getDocument() && !!getNavigator() && navigator.product === REACT_NATIVE_PRODUCT;
}

export function isAndroid(): boolean {
return (
isReactNative() &&
typeof global !== "undefined" &&
typeof (global as any)?.Platform !== "undefined" &&
(global as any)?.Platform.OS === "android"
);
}

export function isIos(): boolean {
return (
isReactNative() &&
typeof global !== "undefined" &&
typeof (global as any)?.Platform !== "undefined" &&
(global as any)?.Platform.OS === "ios"
);
}

export function isBrowser(): boolean {
return !isNode() && !!getNavigator() && !!getDocument();
}
Expand All @@ -59,7 +77,7 @@ export function getEnvironment(): string {
return ENV_MAP.unknown;
}

export function getBundleId(): string | undefined {
export function getAppId(): string | undefined {
try {
if (
isReactNative() &&
Expand Down Expand Up @@ -153,6 +171,7 @@ export function formatRelayRpcUrl({
projectId,
useOnCloseEvent,
bundleId,
packageName,
}: RelayerTypes.RpcUrlParams) {
const splitUrl = relayUrl.split("?");
const ua = formatUA(protocol, version, sdkVersion);
Expand All @@ -161,7 +180,8 @@ export function formatRelayRpcUrl({
ua,
projectId,
useOnCloseEvent: useOnCloseEvent || undefined,
origin: bundleId || undefined,
packageName: packageName || undefined,
bundleId: bundleId || undefined,
};
const queryString = appendToQueryString(splitUrl[1] || "", params);
return splitUrl[0] + "?" + queryString;
Expand Down
Loading

0 comments on commit 29665e9

Please sign in to comment.