@okta/okta-signin-widget 7.15.0 → 7.15.1
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/README.md +5 -5
- package/dist/esm/src/config/config.json.js +1 -1
- package/dist/js/okta-sign-in.classic.js +1 -1
- package/dist/js/okta-sign-in.classic.min.js +1 -1
- package/dist/js/okta-sign-in.js +1 -1
- package/dist/js/okta-sign-in.min.js +1 -1
- package/dist/js/okta-sign-in.next.js +11 -11
- package/dist/js/okta-sign-in.next.js.map +1 -1
- package/dist/js/okta-sign-in.next.no-polyfill.js +2 -2
- package/dist/js/okta-sign-in.next.no-polyfill.js.map +1 -1
- package/dist/js/okta-sign-in.no-polyfill.min.js +1 -1
- package/dist/js/okta-sign-in.oie.js +1 -1
- package/dist/js/okta-sign-in.oie.min.js +1 -1
- package/package.json +3 -3
- package/src/config/config.json +1 -1
- package/src/v3/hooks/useOnSubmit.ts +12 -0
- package/src/v3/package.json +1 -1
- package/src/v3/src/hooks/useOnSubmit.ts +12 -0
- package/src/v3/src/util/browserUtils.ts +4 -0
- package/src/v3/src/util/deviceFingerprintingUtils.test.ts +130 -0
- package/src/v3/src/util/deviceFingerprintingUtils.ts +90 -0
- package/src/v3/util/browserUtils.ts +4 -0
- package/src/v3/util/deviceFingerprintingUtils.ts +90 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@okta/okta-signin-widget",
|
|
4
4
|
"description": "The Okta Sign-In Widget",
|
|
5
|
-
"version": "7.15.
|
|
5
|
+
"version": "7.15.1",
|
|
6
6
|
"homepage": "https://github.com/okta/okta-signin-widget",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"repository": {
|
|
@@ -291,7 +291,7 @@
|
|
|
291
291
|
"workerDirectory": "playground"
|
|
292
292
|
},
|
|
293
293
|
"okta": {
|
|
294
|
-
"commitSha": "
|
|
295
|
-
"fullVersion": "7.15.
|
|
294
|
+
"commitSha": "48be3a5bce89767aa556742410c72e54b646d122",
|
|
295
|
+
"fullVersion": "7.15.1-g48be3a5"
|
|
296
296
|
}
|
|
297
297
|
}
|
package/src/config/config.json
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '@okta/okta-auth-js';
|
|
21
21
|
import { cloneDeep, merge, omit } from 'lodash';
|
|
22
22
|
import { useCallback } from 'preact/hooks';
|
|
23
|
+
import { generateDeviceFingerprint } from 'src/util/deviceFingerprintingUtils';
|
|
23
24
|
|
|
24
25
|
import { IDX_STEP, ON_PREM_TOKEN_CHANGE_ERROR_KEY } from '../constants';
|
|
25
26
|
import { useWidgetContext } from '../contexts';
|
|
@@ -27,6 +28,7 @@ import { MessageType } from '../types';
|
|
|
27
28
|
import {
|
|
28
29
|
areTransactionsEqual,
|
|
29
30
|
containsMessageKey,
|
|
31
|
+
getBaseUrl,
|
|
30
32
|
getErrorEventContext,
|
|
31
33
|
getImmutableData,
|
|
32
34
|
isConfigRecoverFlow,
|
|
@@ -209,6 +211,16 @@ export const useOnSubmit = (): (options: OnSubmitHandlerOptions) => Promise<void
|
|
|
209
211
|
if (step === IDX_STEP.CANCEL_TRANSACTION) {
|
|
210
212
|
SessionStorage.removeStateHandle();
|
|
211
213
|
}
|
|
214
|
+
if (step === IDX_STEP.IDENTIFY && features?.deviceFingerprinting) {
|
|
215
|
+
const baseUrl = getBaseUrl(widgetProps);
|
|
216
|
+
if (baseUrl) {
|
|
217
|
+
// Proceeds with form submission even if device fingerprinting fails
|
|
218
|
+
const fingerprint = await generateDeviceFingerprint(baseUrl).catch(() => undefined);
|
|
219
|
+
if (fingerprint) {
|
|
220
|
+
authClient.http.setRequestHeader('X-Device-Fingerprint', fingerprint);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
212
224
|
setMessage(undefined);
|
|
213
225
|
try {
|
|
214
226
|
let newTransaction = await fn(payload);
|
package/src/v3/package.json
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '@okta/okta-auth-js';
|
|
21
21
|
import { cloneDeep, merge, omit } from 'lodash';
|
|
22
22
|
import { useCallback } from 'preact/hooks';
|
|
23
|
+
import { generateDeviceFingerprint } from 'src/util/deviceFingerprintingUtils';
|
|
23
24
|
|
|
24
25
|
import { IDX_STEP, ON_PREM_TOKEN_CHANGE_ERROR_KEY } from '../constants';
|
|
25
26
|
import { useWidgetContext } from '../contexts';
|
|
@@ -27,6 +28,7 @@ import { MessageType } from '../types';
|
|
|
27
28
|
import {
|
|
28
29
|
areTransactionsEqual,
|
|
29
30
|
containsMessageKey,
|
|
31
|
+
getBaseUrl,
|
|
30
32
|
getErrorEventContext,
|
|
31
33
|
getImmutableData,
|
|
32
34
|
isConfigRecoverFlow,
|
|
@@ -209,6 +211,16 @@ export const useOnSubmit = (): (options: OnSubmitHandlerOptions) => Promise<void
|
|
|
209
211
|
if (step === IDX_STEP.CANCEL_TRANSACTION) {
|
|
210
212
|
SessionStorage.removeStateHandle();
|
|
211
213
|
}
|
|
214
|
+
if (step === IDX_STEP.IDENTIFY && features?.deviceFingerprinting) {
|
|
215
|
+
const baseUrl = getBaseUrl(widgetProps);
|
|
216
|
+
if (baseUrl) {
|
|
217
|
+
// Proceeds with form submission even if device fingerprinting fails
|
|
218
|
+
const fingerprint = await generateDeviceFingerprint(baseUrl).catch(() => undefined);
|
|
219
|
+
if (fingerprint) {
|
|
220
|
+
authClient.http.setRequestHeader('X-Device-Fingerprint', fingerprint);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
212
224
|
setMessage(undefined);
|
|
213
225
|
try {
|
|
214
226
|
let newTransaction = await fn(payload);
|
|
@@ -24,3 +24,7 @@ export const isIOS = (): boolean => (
|
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
export const isAndroidOrIOS = (): boolean => isAndroid() || isIOS();
|
|
27
|
+
|
|
28
|
+
export const getUserAgent = (): string => navigator.userAgent;
|
|
29
|
+
|
|
30
|
+
export const isWindowsPhone = (userAgent: string): boolean => /windows phone|iemobile|wpdesktop/i.test(userAgent);
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as DeviceFingerprintingUtils from './deviceFingerprintingUtils';
|
|
14
|
+
|
|
15
|
+
describe('DeviceFingerprintingUtils', () => {
|
|
16
|
+
const oktaDomainUrl = '';
|
|
17
|
+
|
|
18
|
+
beforeAll(() => {
|
|
19
|
+
const mockForm = document.createElement('form');
|
|
20
|
+
mockForm.setAttribute('data-se', 'o-form');
|
|
21
|
+
document.body.append(mockForm);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
jest.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const mockIFrameMessages = (success: boolean, errorMessage?: { type: string }) => {
|
|
29
|
+
const message = success
|
|
30
|
+
? { type: 'FingerprintAvailable', fingerprint: 'thisIsTheFingerprint' }
|
|
31
|
+
: errorMessage;
|
|
32
|
+
|
|
33
|
+
// TODO (jest): event is missing `origin` property
|
|
34
|
+
window.postMessage(JSON.stringify(message), '*');
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const mockUserAgent = (userAgent: string) => {
|
|
38
|
+
jest.spyOn(navigator, 'userAgent', 'get').mockReturnValue(userAgent);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const bypassMessageSourceCheck = () => {
|
|
42
|
+
jest.spyOn(DeviceFingerprintingUtils, 'isMessageFromCorrectSource').mockReturnValue(true);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
it('creates hidden iframe during fingerprint generation', async () => {
|
|
46
|
+
mockIFrameMessages(true);
|
|
47
|
+
bypassMessageSourceCheck();
|
|
48
|
+
const fingerprintPromise = DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl);
|
|
49
|
+
let iframe = document.getElementById('device-fingerprint-container');
|
|
50
|
+
expect(iframe).not.toBeNull();
|
|
51
|
+
expect(iframe).not.toBeVisible();
|
|
52
|
+
expect(iframe?.getAttribute('src')).toBe('/auth/services/devicefingerprint');
|
|
53
|
+
await fingerprintPromise;
|
|
54
|
+
iframe = document.getElementById('device-fingerprint-container');
|
|
55
|
+
expect(iframe).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('returns a fingerprint if the communication with the iframe is successful', async () => {
|
|
59
|
+
mockIFrameMessages(true);
|
|
60
|
+
bypassMessageSourceCheck();
|
|
61
|
+
const fingerprint = await DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl);
|
|
62
|
+
expect(fingerprint).toBe('thisIsTheFingerprint');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('fails if there is a problem with communicating with the iframe', async () => {
|
|
66
|
+
mockIFrameMessages(false);
|
|
67
|
+
bypassMessageSourceCheck();
|
|
68
|
+
|
|
69
|
+
await expect(DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl))
|
|
70
|
+
.rejects
|
|
71
|
+
.toThrow('No data');
|
|
72
|
+
const iframe = document.getElementById('device-fingerprint-container');
|
|
73
|
+
expect(iframe).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('fails if the iframe sends invalid message content', async () => {
|
|
77
|
+
mockIFrameMessages(false, { type: 'InvalidMessageType' });
|
|
78
|
+
bypassMessageSourceCheck();
|
|
79
|
+
|
|
80
|
+
await expect(DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl))
|
|
81
|
+
.rejects
|
|
82
|
+
.toThrow('No data');
|
|
83
|
+
const iframe = document.getElementById('device-fingerprint-container');
|
|
84
|
+
expect(iframe).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('fails if user agent is not defined', async () => {
|
|
88
|
+
mockUserAgent('');
|
|
89
|
+
mockIFrameMessages(true);
|
|
90
|
+
bypassMessageSourceCheck();
|
|
91
|
+
|
|
92
|
+
await expect(DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl))
|
|
93
|
+
.rejects
|
|
94
|
+
.toThrow('User agent is not defined');
|
|
95
|
+
const iframe = document.getElementById('device-fingerprint-container');
|
|
96
|
+
expect(iframe).toBeNull();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('fails if it is called from a Windows phone', async () => {
|
|
100
|
+
mockUserAgent('Windows Phone');
|
|
101
|
+
mockIFrameMessages(true);
|
|
102
|
+
bypassMessageSourceCheck();
|
|
103
|
+
|
|
104
|
+
await expect(DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl))
|
|
105
|
+
.rejects
|
|
106
|
+
.toThrow('Device fingerprint is not supported on Windows phones');
|
|
107
|
+
const iframe = document.getElementById('device-fingerprint-container');
|
|
108
|
+
expect(iframe).toBeNull();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('fails if the iframe does not receive any messages', async () => {
|
|
112
|
+
// Not sending any mock messages should trigger a timeout
|
|
113
|
+
await expect(DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl, 1000))
|
|
114
|
+
.rejects
|
|
115
|
+
.toThrow('Device fingerprinting timed out');
|
|
116
|
+
const iframe = document.getElementById('device-fingerprint-container');
|
|
117
|
+
expect(iframe).toBeNull();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('fails if there is no form to attach the iframe to', async () => {
|
|
121
|
+
const form = document.querySelector('form[data-se="o-form"]');
|
|
122
|
+
expect(form).not.toBeNull();
|
|
123
|
+
document.body.removeChild(form!);
|
|
124
|
+
await expect(DeviceFingerprintingUtils.generateDeviceFingerprint(oktaDomainUrl))
|
|
125
|
+
.rejects
|
|
126
|
+
.toThrow('Form does not exist');
|
|
127
|
+
const iframe = document.getElementById('device-fingerprint-container');
|
|
128
|
+
expect(iframe).toBeNull();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { getUserAgent, isWindowsPhone } from './browserUtils';
|
|
14
|
+
|
|
15
|
+
export const isMessageFromCorrectSource = (iframe: HTMLIFrameElement, event: MessageEvent)
|
|
16
|
+
: boolean => event.source === iframe.contentWindow;
|
|
17
|
+
|
|
18
|
+
// NOTE: This utility is similar to the DeviceFingerprinting.js file used for V2 authentication flows.
|
|
19
|
+
export const generateDeviceFingerprint = (
|
|
20
|
+
oktaDomainUrl: string,
|
|
21
|
+
timeoutDuration?: number,
|
|
22
|
+
): Promise<string> => {
|
|
23
|
+
const userAgent = getUserAgent();
|
|
24
|
+
if (!userAgent) {
|
|
25
|
+
return Promise.reject(new Error('User agent is not defined'));
|
|
26
|
+
}
|
|
27
|
+
if (isWindowsPhone(userAgent)) {
|
|
28
|
+
return Promise.reject(new Error('Device fingerprint is not supported on Windows phones'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let timeout: NodeJS.Timeout;
|
|
32
|
+
let iframe: HTMLIFrameElement;
|
|
33
|
+
let listener: (this: Window, ev: MessageEvent) => void;
|
|
34
|
+
let msg;
|
|
35
|
+
const formElement = document.querySelector('form[data-se="o-form"]');
|
|
36
|
+
return new Promise<string>((resolve, reject) => {
|
|
37
|
+
iframe = document.createElement('iframe');
|
|
38
|
+
iframe.style.display = 'none';
|
|
39
|
+
iframe.id = 'device-fingerprint-container';
|
|
40
|
+
|
|
41
|
+
listener = (event: MessageEvent) => {
|
|
42
|
+
if (!isMessageFromCorrectSource(iframe, event)) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!event || !event.data || event.origin !== oktaDomainUrl) {
|
|
47
|
+
return reject(new Error('No data'));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
msg = JSON.parse(event.data);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
// iframe messages should all be parsable, skip not parsable messages that come from other
|
|
54
|
+
// sources in the same origin (browser extensions)
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!msg) { return undefined; }
|
|
59
|
+
if (msg.type === 'FingerprintAvailable') {
|
|
60
|
+
return resolve(msg.fingerprint as string);
|
|
61
|
+
} if (msg.type === 'FingerprintServiceReady') {
|
|
62
|
+
const win = iframe.contentWindow;
|
|
63
|
+
win?.postMessage(JSON.stringify({
|
|
64
|
+
type: 'GetFingerprint',
|
|
65
|
+
}), event.origin );
|
|
66
|
+
} else {
|
|
67
|
+
return reject(new Error('No data'));
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
};
|
|
71
|
+
window.addEventListener('message', listener, false);
|
|
72
|
+
|
|
73
|
+
iframe.src = `${oktaDomainUrl}/auth/services/devicefingerprint`;
|
|
74
|
+
if (formElement === null) {
|
|
75
|
+
reject(new Error('Form does not exist'));
|
|
76
|
+
}
|
|
77
|
+
formElement!.appendChild(iframe);
|
|
78
|
+
|
|
79
|
+
timeout = setTimeout(() => {
|
|
80
|
+
// If the iframe does not load, receive the right message type, or there is a slow connection, throw an error
|
|
81
|
+
reject(new Error('Device fingerprinting timed out'));
|
|
82
|
+
}, timeoutDuration || 2000);
|
|
83
|
+
}).finally(() => {
|
|
84
|
+
clearTimeout(timeout);
|
|
85
|
+
window.removeEventListener('message', listener);
|
|
86
|
+
if (formElement?.contains(iframe)) {
|
|
87
|
+
iframe.parentElement?.removeChild(iframe);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
};
|
|
@@ -24,3 +24,7 @@ export const isIOS = (): boolean => (
|
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
export const isAndroidOrIOS = (): boolean => isAndroid() || isIOS();
|
|
27
|
+
|
|
28
|
+
export const getUserAgent = (): string => navigator.userAgent;
|
|
29
|
+
|
|
30
|
+
export const isWindowsPhone = (userAgent: string): boolean => /windows phone|iemobile|wpdesktop/i.test(userAgent);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { getUserAgent, isWindowsPhone } from './browserUtils';
|
|
14
|
+
|
|
15
|
+
export const isMessageFromCorrectSource = (iframe: HTMLIFrameElement, event: MessageEvent)
|
|
16
|
+
: boolean => event.source === iframe.contentWindow;
|
|
17
|
+
|
|
18
|
+
// NOTE: This utility is similar to the DeviceFingerprinting.js file used for V2 authentication flows.
|
|
19
|
+
export const generateDeviceFingerprint = (
|
|
20
|
+
oktaDomainUrl: string,
|
|
21
|
+
timeoutDuration?: number,
|
|
22
|
+
): Promise<string> => {
|
|
23
|
+
const userAgent = getUserAgent();
|
|
24
|
+
if (!userAgent) {
|
|
25
|
+
return Promise.reject(new Error('User agent is not defined'));
|
|
26
|
+
}
|
|
27
|
+
if (isWindowsPhone(userAgent)) {
|
|
28
|
+
return Promise.reject(new Error('Device fingerprint is not supported on Windows phones'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let timeout: NodeJS.Timeout;
|
|
32
|
+
let iframe: HTMLIFrameElement;
|
|
33
|
+
let listener: (this: Window, ev: MessageEvent) => void;
|
|
34
|
+
let msg;
|
|
35
|
+
const formElement = document.querySelector('form[data-se="o-form"]');
|
|
36
|
+
return new Promise<string>((resolve, reject) => {
|
|
37
|
+
iframe = document.createElement('iframe');
|
|
38
|
+
iframe.style.display = 'none';
|
|
39
|
+
iframe.id = 'device-fingerprint-container';
|
|
40
|
+
|
|
41
|
+
listener = (event: MessageEvent) => {
|
|
42
|
+
if (!isMessageFromCorrectSource(iframe, event)) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!event || !event.data || event.origin !== oktaDomainUrl) {
|
|
47
|
+
return reject(new Error('No data'));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
msg = JSON.parse(event.data);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
// iframe messages should all be parsable, skip not parsable messages that come from other
|
|
54
|
+
// sources in the same origin (browser extensions)
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!msg) { return undefined; }
|
|
59
|
+
if (msg.type === 'FingerprintAvailable') {
|
|
60
|
+
return resolve(msg.fingerprint as string);
|
|
61
|
+
} if (msg.type === 'FingerprintServiceReady') {
|
|
62
|
+
const win = iframe.contentWindow;
|
|
63
|
+
win?.postMessage(JSON.stringify({
|
|
64
|
+
type: 'GetFingerprint',
|
|
65
|
+
}), event.origin );
|
|
66
|
+
} else {
|
|
67
|
+
return reject(new Error('No data'));
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
};
|
|
71
|
+
window.addEventListener('message', listener, false);
|
|
72
|
+
|
|
73
|
+
iframe.src = `${oktaDomainUrl}/auth/services/devicefingerprint`;
|
|
74
|
+
if (formElement === null) {
|
|
75
|
+
reject(new Error('Form does not exist'));
|
|
76
|
+
}
|
|
77
|
+
formElement!.appendChild(iframe);
|
|
78
|
+
|
|
79
|
+
timeout = setTimeout(() => {
|
|
80
|
+
// If the iframe does not load, receive the right message type, or there is a slow connection, throw an error
|
|
81
|
+
reject(new Error('Device fingerprinting timed out'));
|
|
82
|
+
}, timeoutDuration || 2000);
|
|
83
|
+
}).finally(() => {
|
|
84
|
+
clearTimeout(timeout);
|
|
85
|
+
window.removeEventListener('message', listener);
|
|
86
|
+
if (formElement?.contains(iframe)) {
|
|
87
|
+
iframe.parentElement?.removeChild(iframe);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
};
|