@imtbl/auth 2.10.7-alpha.3 → 2.10.7-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.js +31 -37
- package/dist/node/index.cjs +45 -50
- package/dist/node/index.js +32 -37
- package/dist/types/Auth.d.ts +136 -0
- package/dist/types/authManager.d.ts +3 -4
- package/dist/types/index.d.ts +4 -5
- package/dist/types/{confirmation → login}/embeddedLoginPrompt.d.ts +1 -1
- package/dist/types/overlay/{confirmationOverlay.d.ts → loginPopupOverlay.d.ts} +1 -1
- package/dist/types/types.d.ts +27 -0
- package/dist/types/utils/typedEventEmitter.d.ts +6 -0
- package/package.json +4 -4
- package/src/Auth.ts +252 -0
- package/src/authManager.ts +10 -12
- package/src/index.ts +9 -6
- package/src/{confirmation → login}/embeddedLoginPrompt.ts +6 -10
- package/src/overlay/{confirmationOverlay.ts → loginPopupOverlay.ts} +1 -1
- package/src/types.ts +30 -0
- package/src/utils/typedEventEmitter.ts +26 -0
- package/dist/types/confirmation/confirmation.d.ts +0 -28
- package/dist/types/confirmation/index.d.ts +0 -3
- package/dist/types/confirmation/popup.d.ts +0 -8
- package/src/confirmation/confirmation.ts +0 -275
- package/src/confirmation/index.ts +0 -3
- package/src/confirmation/popup.ts +0 -41
- /package/dist/types/{confirmation → login}/types.d.ts +0 -0
- /package/src/{confirmation → login}/types.ts +0 -0
|
@@ -2,7 +2,7 @@ import { PopupOverlayOptions } from '../types';
|
|
|
2
2
|
import { PASSPORT_OVERLAY_CLOSE_ID, PASSPORT_OVERLAY_TRY_AGAIN_ID } from './constants';
|
|
3
3
|
import { addLink, getBlockedOverlay, getGenericOverlay } from './elements';
|
|
4
4
|
|
|
5
|
-
export default class
|
|
5
|
+
export default class LoginPopupOverlay {
|
|
6
6
|
private disableGenericPopupOverlay: boolean;
|
|
7
7
|
|
|
8
8
|
private disableBlockedPopupOverlay: boolean;
|
package/src/types.ts
CHANGED
|
@@ -126,3 +126,33 @@ export type DirectLoginOptions = {
|
|
|
126
126
|
marketingConsentStatus?: MarketingConsentStatus;
|
|
127
127
|
email?: string;
|
|
128
128
|
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Extended login options with caching and silent login support
|
|
132
|
+
*/
|
|
133
|
+
export type LoginOptions = {
|
|
134
|
+
/** If true, attempts to use cached session without user interaction */
|
|
135
|
+
useCachedSession?: boolean;
|
|
136
|
+
/** If true, attempts silent authentication (force token refresh) */
|
|
137
|
+
useSilentLogin?: boolean;
|
|
138
|
+
/** If true, uses redirect flow instead of popup flow */
|
|
139
|
+
useRedirectFlow?: boolean;
|
|
140
|
+
/** Direct login options (social provider, email, etc.) */
|
|
141
|
+
directLoginOptions?: DirectLoginOptions;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Authentication events emitted by the Auth class
|
|
146
|
+
*/
|
|
147
|
+
export enum AuthEvents {
|
|
148
|
+
LOGGED_OUT = 'loggedOut',
|
|
149
|
+
LOGGED_IN = 'loggedIn',
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Event map for typed event emitter
|
|
154
|
+
*/
|
|
155
|
+
export interface AuthEventMap extends Record<string, any> {
|
|
156
|
+
[AuthEvents.LOGGED_OUT]: [];
|
|
157
|
+
[AuthEvents.LOGGED_IN]: [User];
|
|
158
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
|
|
3
|
+
export default class TypedEventEmitter<TEvents extends Record<string, any>> {
|
|
4
|
+
private emitter = new EventEmitter();
|
|
5
|
+
|
|
6
|
+
emit<TEventName extends keyof TEvents & string>(
|
|
7
|
+
eventName: TEventName,
|
|
8
|
+
...eventArg: TEvents[TEventName]
|
|
9
|
+
) {
|
|
10
|
+
this.emitter.emit(eventName, ...(eventArg as []));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
on<TEventName extends keyof TEvents & string>(
|
|
14
|
+
eventName: TEventName,
|
|
15
|
+
handler: (...eventArg: TEvents[TEventName]) => void,
|
|
16
|
+
) {
|
|
17
|
+
this.emitter.on(eventName, handler as any);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
removeListener<TEventName extends keyof TEvents & string>(
|
|
21
|
+
eventName: TEventName,
|
|
22
|
+
handler: (...eventArg: TEvents[TEventName]) => void,
|
|
23
|
+
) {
|
|
24
|
+
this.emitter.removeListener(eventName, handler as any);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as GeneratedClients from '@imtbl/generated-clients';
|
|
2
|
-
import { ConfirmationResult } from './types';
|
|
3
|
-
import { IAuthConfiguration } from '../config';
|
|
4
|
-
export declare const CONFIRMATION_IFRAME_ID = "passport-confirm";
|
|
5
|
-
export declare const CONFIRMATION_IFRAME_STYLE = "display: none; position: absolute;width:0px;height:0px;border:0;";
|
|
6
|
-
type MessageHandler = (arg0: MessageEvent) => void;
|
|
7
|
-
type MessageType = 'erc191' | 'eip712';
|
|
8
|
-
export default class ConfirmationScreen {
|
|
9
|
-
private config;
|
|
10
|
-
private confirmationWindow;
|
|
11
|
-
private popupOptions;
|
|
12
|
-
private overlay;
|
|
13
|
-
private overlayClosed;
|
|
14
|
-
private timer;
|
|
15
|
-
constructor(config: IAuthConfiguration);
|
|
16
|
-
private getHref;
|
|
17
|
-
requestConfirmation(transactionId: string, etherAddress: string, chainType: GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum, chainId?: string): Promise<ConfirmationResult>;
|
|
18
|
-
requestMessageConfirmation(messageID: string, etherAddress: string, messageType?: MessageType): Promise<ConfirmationResult>;
|
|
19
|
-
showServiceUnavailable(): Promise<void>;
|
|
20
|
-
loading(popupOptions?: {
|
|
21
|
-
width: number;
|
|
22
|
-
height: number;
|
|
23
|
-
}): void;
|
|
24
|
-
closeWindow(): void;
|
|
25
|
-
showConfirmationScreen(href: string, messageHandler: MessageHandler, resolve: Function): void;
|
|
26
|
-
private recreateConfirmationWindow;
|
|
27
|
-
}
|
|
28
|
-
export {};
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import * as GeneratedClients from '@imtbl/generated-clients';
|
|
2
|
-
import { trackError } from '@imtbl/metrics';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
ConfirmationResult,
|
|
6
|
-
PASSPORT_CONFIRMATION_EVENT_TYPE,
|
|
7
|
-
ConfirmationReceiveMessage,
|
|
8
|
-
ConfirmationSendMessage,
|
|
9
|
-
} from './types';
|
|
10
|
-
import { openPopupCenter } from './popup';
|
|
11
|
-
import { IAuthConfiguration } from '../config';
|
|
12
|
-
import ConfirmationOverlay from '../overlay/confirmationOverlay';
|
|
13
|
-
|
|
14
|
-
const CONFIRMATION_WINDOW_TITLE = 'Confirm this transaction';
|
|
15
|
-
const CONFIRMATION_WINDOW_HEIGHT = 720;
|
|
16
|
-
const CONFIRMATION_WINDOW_WIDTH = 480;
|
|
17
|
-
const CONFIRMATION_WINDOW_CLOSED_POLLING_DURATION = 1000;
|
|
18
|
-
|
|
19
|
-
export const CONFIRMATION_IFRAME_ID = 'passport-confirm';
|
|
20
|
-
export const CONFIRMATION_IFRAME_STYLE = 'display: none; position: absolute;width:0px;height:0px;border:0;';
|
|
21
|
-
|
|
22
|
-
type MessageHandler = (arg0: MessageEvent) => void;
|
|
23
|
-
|
|
24
|
-
type MessageType = 'erc191' | 'eip712';
|
|
25
|
-
|
|
26
|
-
export default class ConfirmationScreen {
|
|
27
|
-
private config: IAuthConfiguration;
|
|
28
|
-
|
|
29
|
-
private confirmationWindow: Window | undefined;
|
|
30
|
-
|
|
31
|
-
private popupOptions: { width: number; height: number } | undefined;
|
|
32
|
-
|
|
33
|
-
private overlay: ConfirmationOverlay | undefined;
|
|
34
|
-
|
|
35
|
-
private overlayClosed: boolean;
|
|
36
|
-
|
|
37
|
-
private timer: NodeJS.Timeout | undefined;
|
|
38
|
-
|
|
39
|
-
constructor(config: IAuthConfiguration) {
|
|
40
|
-
this.config = config;
|
|
41
|
-
this.overlayClosed = false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
private getHref(relativePath: string, queryStringParams?: { [key: string]: any }) {
|
|
45
|
-
let href = `${this.config.passportDomain}/transaction-confirmation/${relativePath}`;
|
|
46
|
-
|
|
47
|
-
if (queryStringParams) {
|
|
48
|
-
const queryString = queryStringParams
|
|
49
|
-
? Object.keys(queryStringParams)
|
|
50
|
-
.map((key) => `${key}=${queryStringParams[key]}`)
|
|
51
|
-
.join('&')
|
|
52
|
-
: '';
|
|
53
|
-
|
|
54
|
-
href = `${href}?${queryString}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return href;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
requestConfirmation(
|
|
61
|
-
transactionId: string,
|
|
62
|
-
etherAddress: string,
|
|
63
|
-
chainType: GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum,
|
|
64
|
-
chainId?: string,
|
|
65
|
-
): Promise<ConfirmationResult> {
|
|
66
|
-
return new Promise((resolve, reject) => {
|
|
67
|
-
const messageHandler = ({ data, origin }: MessageEvent) => {
|
|
68
|
-
if (
|
|
69
|
-
origin !== this.config.passportDomain
|
|
70
|
-
|| data.eventType !== PASSPORT_CONFIRMATION_EVENT_TYPE
|
|
71
|
-
) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
switch (data.messageType as ConfirmationReceiveMessage) {
|
|
76
|
-
case ConfirmationReceiveMessage.CONFIRMATION_WINDOW_READY: {
|
|
77
|
-
this.confirmationWindow?.postMessage({
|
|
78
|
-
eventType: PASSPORT_CONFIRMATION_EVENT_TYPE,
|
|
79
|
-
messageType: ConfirmationSendMessage.CONFIRMATION_START,
|
|
80
|
-
}, this.config.passportDomain);
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
case ConfirmationReceiveMessage.TRANSACTION_CONFIRMED: {
|
|
84
|
-
this.closeWindow();
|
|
85
|
-
resolve({ confirmed: true });
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
case ConfirmationReceiveMessage.TRANSACTION_REJECTED: {
|
|
89
|
-
this.closeWindow();
|
|
90
|
-
resolve({ confirmed: false });
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
case ConfirmationReceiveMessage.TRANSACTION_ERROR: {
|
|
94
|
-
this.closeWindow();
|
|
95
|
-
reject(new Error('Error during transaction confirmation'));
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
default:
|
|
99
|
-
this.closeWindow();
|
|
100
|
-
reject(new Error('Unsupported message type'));
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
let href = '';
|
|
105
|
-
if (chainType === GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum.Starkex) {
|
|
106
|
-
href = this.getHref('transaction', { transactionId, etherAddress, chainType });
|
|
107
|
-
} else {
|
|
108
|
-
href = this.getHref('zkevm/transaction', {
|
|
109
|
-
transactionID: transactionId, etherAddress, chainType, chainID: chainId,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
window.addEventListener('message', messageHandler);
|
|
113
|
-
this.showConfirmationScreen(href, messageHandler, resolve);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
requestMessageConfirmation(
|
|
118
|
-
messageID: string,
|
|
119
|
-
etherAddress: string,
|
|
120
|
-
messageType?: MessageType,
|
|
121
|
-
): Promise<ConfirmationResult> {
|
|
122
|
-
return new Promise((resolve, reject) => {
|
|
123
|
-
const messageHandler = ({ data, origin }: MessageEvent) => {
|
|
124
|
-
if (
|
|
125
|
-
origin !== this.config.passportDomain
|
|
126
|
-
|| data.eventType !== PASSPORT_CONFIRMATION_EVENT_TYPE
|
|
127
|
-
) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
switch (data.messageType as ConfirmationReceiveMessage) {
|
|
131
|
-
case ConfirmationReceiveMessage.CONFIRMATION_WINDOW_READY: {
|
|
132
|
-
this.confirmationWindow?.postMessage({
|
|
133
|
-
eventType: PASSPORT_CONFIRMATION_EVENT_TYPE,
|
|
134
|
-
messageType: ConfirmationSendMessage.CONFIRMATION_START,
|
|
135
|
-
}, this.config.passportDomain);
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
case ConfirmationReceiveMessage.MESSAGE_CONFIRMED: {
|
|
139
|
-
this.closeWindow();
|
|
140
|
-
resolve({ confirmed: true });
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
143
|
-
case ConfirmationReceiveMessage.MESSAGE_REJECTED: {
|
|
144
|
-
this.closeWindow();
|
|
145
|
-
resolve({ confirmed: false });
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
case ConfirmationReceiveMessage.MESSAGE_ERROR: {
|
|
149
|
-
this.closeWindow();
|
|
150
|
-
reject(new Error('Error during message confirmation'));
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
default:
|
|
154
|
-
this.closeWindow();
|
|
155
|
-
reject(new Error('Unsupported message type'));
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
window.addEventListener('message', messageHandler);
|
|
160
|
-
const href = this.getHref('zkevm/message', {
|
|
161
|
-
messageID,
|
|
162
|
-
etherAddress,
|
|
163
|
-
...(messageType ? { messageType } : {}),
|
|
164
|
-
});
|
|
165
|
-
this.showConfirmationScreen(href, messageHandler, resolve);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
showServiceUnavailable(): Promise<void> {
|
|
170
|
-
return new Promise((_, reject) => {
|
|
171
|
-
this.showConfirmationScreen(
|
|
172
|
-
this.getHref('unavailable'),
|
|
173
|
-
() => {},
|
|
174
|
-
() => {
|
|
175
|
-
this.closeWindow();
|
|
176
|
-
reject(new Error('Service unavailable'));
|
|
177
|
-
},
|
|
178
|
-
);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
loading(popupOptions?: { width: number; height: number }) {
|
|
183
|
-
if (this.config.crossSdkBridgeEnabled) {
|
|
184
|
-
// There is no need to open a confirmation window if cross-sdk bridge is enabled
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
this.popupOptions = popupOptions;
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
this.confirmationWindow = openPopupCenter({
|
|
192
|
-
url: this.getHref('loading'),
|
|
193
|
-
title: CONFIRMATION_WINDOW_TITLE,
|
|
194
|
-
width: popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
|
|
195
|
-
height: popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
|
|
196
|
-
});
|
|
197
|
-
this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {});
|
|
198
|
-
} catch (error) {
|
|
199
|
-
// If an error is thrown here then the popup is blocked
|
|
200
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
201
|
-
trackError('passport', 'confirmationPopupDenied', new Error(errorMessage));
|
|
202
|
-
this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {}, true);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
this.overlay.append(
|
|
206
|
-
() => {
|
|
207
|
-
try {
|
|
208
|
-
this.confirmationWindow?.close();
|
|
209
|
-
this.confirmationWindow = openPopupCenter({
|
|
210
|
-
url: this.getHref('loading'),
|
|
211
|
-
title: CONFIRMATION_WINDOW_TITLE,
|
|
212
|
-
width: this.popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
|
|
213
|
-
height: this.popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
|
|
214
|
-
});
|
|
215
|
-
} catch { /* Empty */ }
|
|
216
|
-
},
|
|
217
|
-
() => {
|
|
218
|
-
this.overlayClosed = true;
|
|
219
|
-
this.closeWindow();
|
|
220
|
-
},
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
closeWindow() {
|
|
225
|
-
this.confirmationWindow?.close();
|
|
226
|
-
this.overlay?.remove();
|
|
227
|
-
this.overlay = undefined;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
showConfirmationScreen(href: string, messageHandler: MessageHandler, resolve: Function) {
|
|
231
|
-
// If popup blocked, the confirmation window will not exist
|
|
232
|
-
if (this.confirmationWindow) {
|
|
233
|
-
this.confirmationWindow.location.href = href;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// This indicates the user closed the overlay so the transaction should be rejected
|
|
237
|
-
if (!this.overlay) {
|
|
238
|
-
this.overlayClosed = false;
|
|
239
|
-
resolve({ confirmed: false });
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// https://stackoverflow.com/questions/9388380/capture-the-close-event-of-popup-window-in-javascript/48240128#48240128
|
|
244
|
-
const timerCallback = () => {
|
|
245
|
-
if (this.confirmationWindow?.closed || this.overlayClosed) {
|
|
246
|
-
clearInterval(this.timer);
|
|
247
|
-
window.removeEventListener('message', messageHandler);
|
|
248
|
-
resolve({ confirmed: false });
|
|
249
|
-
this.overlayClosed = false;
|
|
250
|
-
this.confirmationWindow = undefined;
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
this.timer = setInterval(
|
|
254
|
-
timerCallback,
|
|
255
|
-
CONFIRMATION_WINDOW_CLOSED_POLLING_DURATION,
|
|
256
|
-
);
|
|
257
|
-
this.overlay.update(() => this.recreateConfirmationWindow(href, timerCallback));
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
private recreateConfirmationWindow(href: string, timerCallback: () => void) {
|
|
261
|
-
try {
|
|
262
|
-
// Clears and recreates the timer to ensure when the confirmation window
|
|
263
|
-
// is closed and recreated the transaction is not rejected.
|
|
264
|
-
clearInterval(this.timer);
|
|
265
|
-
this.confirmationWindow?.close();
|
|
266
|
-
this.confirmationWindow = openPopupCenter({
|
|
267
|
-
url: href,
|
|
268
|
-
title: CONFIRMATION_WINDOW_TITLE,
|
|
269
|
-
width: this.popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
|
|
270
|
-
height: this.popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
|
|
271
|
-
});
|
|
272
|
-
this.timer = setInterval(timerCallback, CONFIRMATION_WINDOW_CLOSED_POLLING_DURATION);
|
|
273
|
-
} catch { /* Empty */ }
|
|
274
|
-
}
|
|
275
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export type PopUpProps = {
|
|
2
|
-
url: string;
|
|
3
|
-
title: string;
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
query?: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const openPopupCenter = ({
|
|
10
|
-
url,
|
|
11
|
-
title,
|
|
12
|
-
width,
|
|
13
|
-
height,
|
|
14
|
-
}: PopUpProps): Window => {
|
|
15
|
-
const left = Math.max(
|
|
16
|
-
0,
|
|
17
|
-
Math.round(window.screenX + (window.outerWidth - width) / 2),
|
|
18
|
-
);
|
|
19
|
-
const top = Math.max(
|
|
20
|
-
0,
|
|
21
|
-
Math.round(window.screenY + (window.outerHeight - height) / 2),
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
const newWindow = window.open(
|
|
25
|
-
url,
|
|
26
|
-
title,
|
|
27
|
-
`
|
|
28
|
-
scrollbars=yes,
|
|
29
|
-
width=${width},
|
|
30
|
-
height=${height},
|
|
31
|
-
top=${top},
|
|
32
|
-
left=${left}
|
|
33
|
-
`,
|
|
34
|
-
);
|
|
35
|
-
if (!newWindow) {
|
|
36
|
-
throw new Error('Failed to open confirmation screen');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
newWindow.focus();
|
|
40
|
-
return newWindow;
|
|
41
|
-
};
|
|
File without changes
|
|
File without changes
|