Skip to content

Commit 2ad2a06

Browse files
authored
WAL-5344: Harden transport for signers flow (#1282)
* harden transport for signers flow * changeset * extract to type
1 parent 86aea7f commit 2ad2a06

File tree

6 files changed

+58
-15
lines changed

6 files changed

+58
-15
lines changed

.changeset/thin-humans-sort.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@crossmint/client-sdk-window": patch
3+
"@crossmint/wallets-sdk": patch
4+
---
5+
6+
Fix Window Transport Error

packages/client/window/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from "./handshake";
33
export type { Transport, SimpleMessageEvent } from "./transport/Transport";
44
export type { EventMap } from "./EventEmitter";
55
export { generateRandomString } from "./utils/generateRandomString";
6+
export { SignersWindowTransport } from "./transport/SignersWindowTransport";
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { SimpleMessageEvent } from "./Transport";
2+
import { generateRandomString } from "../utils/generateRandomString";
3+
import { WindowTransport } from "./WindowTransport";
4+
5+
export class SignersWindowTransport extends WindowTransport {
6+
addMessageListener(listener: (event: SimpleMessageEvent) => void): string {
7+
const wrapped = (event: MessageEvent) => {
8+
const sameSource = event.source === this.otherWindow;
9+
const originMatches = this.isTargetOrigin(event.origin);
10+
if (sameSource && originMatches) {
11+
listener({
12+
type: event.type,
13+
data: event.data,
14+
} as SimpleMessageEvent);
15+
}
16+
};
17+
18+
const id = generateRandomString();
19+
window.addEventListener("message", wrapped);
20+
this.listeners.set(id, wrapped);
21+
return id;
22+
}
23+
}

packages/client/window/src/transport/WindowTransport.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import type { Transport, SimpleMessageEvent } from "./Transport";
44
import { generateRandomString } from "../utils/generateRandomString";
55

66
export class WindowTransport<OutgoingEvents extends EventMap = EventMap> implements Transport<OutgoingEvents> {
7-
private listeners = new Map<string, (event: MessageEvent) => void>();
7+
protected listeners = new Map<string, (event: MessageEvent) => void>();
88

99
constructor(
10-
private otherWindow: Window,
11-
private targetOrigin: string | string[]
10+
protected otherWindow: Window,
11+
protected targetOrigin: string | string[]
1212
) {}
1313

1414
send<K extends keyof OutgoingEvents>(message: { event: K; data: z.infer<OutgoingEvents[K]> }): void {

packages/client/window/src/windows/IFrame.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import type { EventMap } from "../EventEmitter";
44
import type { EventEmitterWithHandshakeOptions } from "../handshake";
55
import { HandshakeParent } from "../handshake/Parent";
66
import { WindowTransport } from "../transport/WindowTransport";
7+
import type { Transport } from "../transport/Transport";
8+
9+
type TransportClassConstructor<OutgoingEvents extends EventMap> = new (
10+
otherWindow: Window,
11+
targetOrigin: string | string[]
12+
) => Transport<OutgoingEvents>;
713

814
export class IFrameWindow<IncomingEvents extends EventMap, OutgoingEvents extends EventMap> extends HandshakeParent<
915
IncomingEvents,
@@ -12,32 +18,35 @@ export class IFrameWindow<IncomingEvents extends EventMap, OutgoingEvents extend
1218
private constructor(
1319
public iframe: HTMLIFrameElement,
1420
targetOrigin: string,
15-
options?: EventEmitterWithHandshakeOptions<IncomingEvents, OutgoingEvents>
21+
options?: EventEmitterWithHandshakeOptions<IncomingEvents, OutgoingEvents>,
22+
TransportClass: TransportClassConstructor<OutgoingEvents> = WindowTransport
1623
) {
1724
const contentWindow = iframe.contentWindow;
1825
if (!contentWindow) {
1926
throw new Error("IFrame must have a contentWindow");
2027
}
21-
const transport = new WindowTransport<OutgoingEvents>(contentWindow, targetOrigin);
28+
const transport = new TransportClass(contentWindow, targetOrigin);
2229
super(transport, options);
2330
}
2431

2532
static async init<IncomingEvents extends EventMap, OutgoingEvents extends EventMap>(
2633
urlOrExistingIframe: string | HTMLIFrameElement,
27-
options?: EventEmitterWithHandshakeOptions<IncomingEvents, OutgoingEvents>
34+
options?: EventEmitterWithHandshakeOptions<IncomingEvents, OutgoingEvents>,
35+
TransportClass: TransportClassConstructor<OutgoingEvents> = WindowTransport
2836
) {
2937
const iframe =
3038
typeof urlOrExistingIframe === "string" ? await createIFrame(urlOrExistingIframe) : urlOrExistingIframe;
3139
const targetOrigin = options?.targetOrigin || urlToOrigin(iframe.src);
32-
return new IFrameWindow<IncomingEvents, OutgoingEvents>(iframe, targetOrigin, options);
40+
return new IFrameWindow<IncomingEvents, OutgoingEvents>(iframe, targetOrigin, options, TransportClass);
3341
}
3442

3543
static initExistingIFrame<IncomingEvents extends EventMap, OutgoingEvents extends EventMap>(
3644
iframe: HTMLIFrameElement,
37-
options?: EventEmitterWithHandshakeOptions<IncomingEvents, OutgoingEvents>
45+
options?: EventEmitterWithHandshakeOptions<IncomingEvents, OutgoingEvents>,
46+
TransportClass: TransportClassConstructor<OutgoingEvents> = WindowTransport
3847
) {
3948
const targetOrigin = options?.targetOrigin || urlToOrigin(iframe.src);
40-
return new IFrameWindow<IncomingEvents, OutgoingEvents>(iframe, targetOrigin, options);
49+
return new IFrameWindow<IncomingEvents, OutgoingEvents>(iframe, targetOrigin, options, TransportClass);
4150
}
4251
}
4352

packages/wallets/src/signers/non-custodial/ncs-iframe-manager.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IFrameWindow, type HandshakeParent } from "@crossmint/client-sdk-window";
1+
import { IFrameWindow, SignersWindowTransport, type HandshakeParent } from "@crossmint/client-sdk-window";
22
import { environmentUrlConfig, signerInboundEvents, signerOutboundEvents } from "@crossmint/client-signers";
33
import type { APIKeyEnvironmentPrefix } from "@crossmint/common-sdk-base";
44

@@ -20,11 +20,15 @@ export class NcsIframeManager {
2020
iframeUrl.searchParams.set("targetOrigin", window.location.origin);
2121

2222
const iframeElement = await this.createInvisibleIFrame(iframeUrl.toString());
23-
this.handshakeParent = await IFrameWindow.init(iframeElement, {
24-
targetOrigin: iframeUrl.origin,
25-
incomingEvents: signerOutboundEvents,
26-
outgoingEvents: signerInboundEvents,
27-
});
23+
this.handshakeParent = await IFrameWindow.init(
24+
iframeElement,
25+
{
26+
targetOrigin: iframeUrl.origin,
27+
incomingEvents: signerOutboundEvents,
28+
outgoingEvents: signerInboundEvents,
29+
},
30+
SignersWindowTransport
31+
);
2832

2933
await this.handshakeParent.handshakeWithChild();
3034
return this.handshakeParent;

0 commit comments

Comments
 (0)