From 009b08fa7ce55307362e68debd3c790eaf2966ff Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 15:14:03 +0300 Subject: [PATCH 01/11] Add fingerprint API to idx --- lib/idx/mixin.ts | 4 ++++ lib/idx/mixinMinimal.ts | 4 ++++ lib/idx/types/api.ts | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/lib/idx/mixin.ts b/lib/idx/mixin.ts index 2939dec6c..c4503cc5e 100644 --- a/lib/idx/mixin.ts +++ b/lib/idx/mixin.ts @@ -1,6 +1,7 @@ import { OktaAuthConstructor } from '../base/types'; import { OktaAuthOAuthInterface } from '../oidc/types'; import { + FingerprintAPI, IdxAPI, IdxTransactionManagerInterface, OktaAuthIdxInterface, @@ -11,6 +12,7 @@ import { import { IdxTransactionMeta } from './types/meta'; import { IdxStorageManagerInterface } from './types/storage'; import { createIdxAPI } from './factory/api'; +import fingerprint from '../browser/fingerprint'; import * as webauthn from './webauthn'; export function mixinIdx @@ -27,11 +29,13 @@ export function mixinIdx return class OktaAuthIdx extends Base implements OktaAuthIdxInterface { idx: IdxAPI; + fingerprint: FingerprintAPI; static webauthn: WebauthnAPI = webauthn; constructor(...args: any[]) { super(...args); this.idx = createIdxAPI(this); + this.fingerprint = fingerprint.bind(null, this); } }; } diff --git a/lib/idx/mixinMinimal.ts b/lib/idx/mixinMinimal.ts index 901d55bac..5831f7065 100644 --- a/lib/idx/mixinMinimal.ts +++ b/lib/idx/mixinMinimal.ts @@ -1,6 +1,7 @@ import { OktaAuthConstructor } from '../base/types'; import { MinimalOktaOAuthInterface } from '../oidc/types'; import { + FingerprintAPI, IdxTransactionManagerInterface, OktaAuthIdxConstructor, OktaAuthIdxOptions, @@ -11,6 +12,7 @@ import { import { IdxTransactionMeta } from './types/meta'; import { IdxStorageManagerInterface } from './types/storage'; import { createMinimalIdxAPI } from '../idx/factory/minimalApi'; +import fingerprint from '../browser/fingerprint'; import * as webauthn from './webauthn'; export function mixinMinimalIdx @@ -29,11 +31,13 @@ export function mixinMinimalIdx return class OktaAuthIdx extends Base implements MinimalOktaAuthIdxInterface { idx: MinimalIdxAPI; + fingerprint: FingerprintAPI; static webauthn: WebauthnAPI = webauthn; constructor(...args: any[]) { super(...args); this.idx = createMinimalIdxAPI(this); + this.fingerprint = fingerprint.bind(null, this); } }; } diff --git a/lib/idx/types/api.ts b/lib/idx/types/api.ts index 40f31c3cf..9d2c9c043 100644 --- a/lib/idx/types/api.ts +++ b/lib/idx/types/api.ts @@ -258,6 +258,13 @@ export interface WebauthnAPI { ): CredentialCreationOptions; } +export interface FingerprintOptions { + timeout?: number; +} + +export type FingerprintAPI = (options?: FingerprintOptions) => Promise; + + export interface OktaAuthIdxInterface < M extends IdxTransactionMeta = IdxTransactionMeta, @@ -268,6 +275,7 @@ export interface OktaAuthIdxInterface extends OktaAuthOAuthInterface { idx: IdxAPI; + fingerprint: FingerprintAPI; } export interface MinimalOktaAuthIdxInterface @@ -280,6 +288,7 @@ export interface MinimalOktaAuthIdxInterface extends MinimalOktaOAuthInterface { idx: MinimalIdxAPI; + fingerprint: FingerprintAPI; } export interface OktaAuthIdxConstructor From 84f44bc4ee9a8fdd011a8c2d4a7814482c93b01b Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 16:19:34 +0300 Subject: [PATCH 02/11] move fingerprint to base --- lib/authn/mixin.ts | 3 +-- lib/authn/types.ts | 11 ++--------- lib/base/types.ts | 5 +++++ lib/browser/fingerprint.ts | 2 +- lib/idx/mixin.ts | 3 +-- lib/idx/mixinMinimal.ts | 3 +-- lib/idx/types/api.ts | 8 +------- 7 files changed, 12 insertions(+), 23 deletions(-) diff --git a/lib/authn/mixin.ts b/lib/authn/mixin.ts index b109c6bf4..ffa85213d 100644 --- a/lib/authn/mixin.ts +++ b/lib/authn/mixin.ts @@ -17,7 +17,6 @@ import { } from '../util'; import fingerprint from '../browser/fingerprint'; import { - FingerprintAPI, SigninWithCredentialsOptions, ForgotPasswordOptions, VerifyRecoveryTokenOptions, @@ -31,7 +30,7 @@ import { } from './factory'; import { StorageManagerInterface } from '../storage/types'; import { OktaAuthHttpInterface, OktaAuthHttpOptions } from '../http/types'; -import { OktaAuthConstructor } from '../base/types'; +import { FingerprintAPI, OktaAuthConstructor } from '../base/types'; export function mixinAuthn < diff --git a/lib/authn/types.ts b/lib/authn/types.ts index 8a604457a..0f2554ec5 100644 --- a/lib/authn/types.ts +++ b/lib/authn/types.ts @@ -1,3 +1,5 @@ + +import { FingerprintAPI } from '../base/types'; import { StorageManagerInterface } from '../storage/types'; import { RequestData, RequestOptions, OktaAuthHttpInterface, OktaAuthHttpOptions } from '../http/types'; @@ -120,14 +122,6 @@ export interface AuthnAPI extends SigninAPI { verifyRecoveryToken(opts: VerifyRecoveryTokenOptions): Promise; } -// Fingerprint -export interface FingerprintOptions { - timeout?: number; -} - -export type FingerprintAPI = (options?: FingerprintOptions) => Promise; - - export interface OktaAuthTxInterface < S extends StorageManagerInterface = StorageManagerInterface, @@ -138,5 +132,4 @@ export interface OktaAuthTxInterface tx: AuthnTransactionAPI; // legacy name authn: AuthnTransactionAPI; // new name fingerprint: FingerprintAPI; - } diff --git a/lib/base/types.ts b/lib/base/types.ts index 791870777..cae61f9ae 100644 --- a/lib/base/types.ts +++ b/lib/base/types.ts @@ -31,6 +31,11 @@ export interface FeaturesAPI { } +export interface FingerprintOptions { + timeout?: number; +} +export type FingerprintAPI = (options?: FingerprintOptions) => Promise; + // options that can be passed to AuthJS export interface OktaAuthBaseOptions { devMode?: boolean; diff --git a/lib/browser/fingerprint.ts b/lib/browser/fingerprint.ts index df47756fd..7d86e38a8 100644 --- a/lib/browser/fingerprint.ts +++ b/lib/browser/fingerprint.ts @@ -17,7 +17,7 @@ import { addListener, removeListener } from '../oidc'; -import { FingerprintOptions } from '../authn/types'; +import { FingerprintOptions } from '../base/types'; import { OktaAuthHttpInterface } from '../http/types'; export default function fingerprint(sdk: OktaAuthHttpInterface, options?: FingerprintOptions): Promise { diff --git a/lib/idx/mixin.ts b/lib/idx/mixin.ts index c4503cc5e..49e6a5612 100644 --- a/lib/idx/mixin.ts +++ b/lib/idx/mixin.ts @@ -1,7 +1,6 @@ -import { OktaAuthConstructor } from '../base/types'; +import { FingerprintAPI, OktaAuthConstructor } from '../base/types'; import { OktaAuthOAuthInterface } from '../oidc/types'; import { - FingerprintAPI, IdxAPI, IdxTransactionManagerInterface, OktaAuthIdxInterface, diff --git a/lib/idx/mixinMinimal.ts b/lib/idx/mixinMinimal.ts index 5831f7065..2e6266da2 100644 --- a/lib/idx/mixinMinimal.ts +++ b/lib/idx/mixinMinimal.ts @@ -1,7 +1,6 @@ -import { OktaAuthConstructor } from '../base/types'; +import { FingerprintAPI, OktaAuthConstructor } from '../base/types'; import { MinimalOktaOAuthInterface } from '../oidc/types'; import { - FingerprintAPI, IdxTransactionManagerInterface, OktaAuthIdxConstructor, OktaAuthIdxOptions, diff --git a/lib/idx/types/api.ts b/lib/idx/types/api.ts index 9d2c9c043..0f535925d 100644 --- a/lib/idx/types/api.ts +++ b/lib/idx/types/api.ts @@ -54,7 +54,7 @@ import type { WebauthnEnrollValues, WebauthnVerificationValues } from '../authenticator'; -import { OktaAuthConstructor } from '../../base/types'; +import { OktaAuthConstructor, FingerprintAPI } from '../../base/types'; export enum IdxStatus { SUCCESS = 'SUCCESS', @@ -258,12 +258,6 @@ export interface WebauthnAPI { ): CredentialCreationOptions; } -export interface FingerprintOptions { - timeout?: number; -} - -export type FingerprintAPI = (options?: FingerprintOptions) => Promise; - export interface OktaAuthIdxInterface < From 3797b2fba86f211cfd2686178f6bb28cfe9f11aa Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 16:22:12 +0300 Subject: [PATCH 03/11] . --- lib/browser/browserStorage.ts | 29 ++++++++++++++++++----------- lib/storage/types.ts | 6 +++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/browser/browserStorage.ts b/lib/browser/browserStorage.ts index ee553eb07..cdca28b13 100644 --- a/lib/browser/browserStorage.ts +++ b/lib/browser/browserStorage.ts @@ -12,7 +12,8 @@ * */ -import Cookies from 'js-cookie'; +import * as Cookies from 'js-cookie'; +import type { CookieAttributes } from 'js-cookie'; import AuthSdkError from '../errors/AuthSdkError'; import { StorageOptions, @@ -39,7 +40,6 @@ export interface BrowserStorageUtil extends StorageUtil { getInMemoryStorage(): SimpleStorage; getCookieStorage(options?: StorageOptions): CookieStorage; testStorage(storage: any): boolean; - storage: Cookies; inMemoryStore: Record; } @@ -233,15 +233,22 @@ var storageUtil: BrowserStorageUtil = { }, storage: { - set: function(name: string, value: string, expiresAt: string, options: CookieOptions): string { - const { sameSite, secure } = options; - if (typeof secure === 'undefined' || typeof sameSite === 'undefined') { + /* eslint complexity:[0,8] */ + set: function(name: string, value: string, expiresAt: string, options: CookieOptions): string | undefined { + const { secure } = options; + if (typeof secure === 'undefined' || typeof options.sameSite === 'undefined') { throw new AuthSdkError('storage.set: "secure" and "sameSite" options must be provided'); } - var cookieOptions: CookieOptions = { + let sameSite: CookieAttributes['sameSite']; + if (typeof options.sameSite === 'string') { + sameSite = options.sameSite as CookieAttributes['sameSite']; + } else if (typeof options.sameSite === 'boolean') { + sameSite = options.sameSite ? 'lax' : 'none'; + } + var cookieOptions: CookieAttributes = { path: options.path || '/', secure, - sameSite + sameSite, }; // eslint-disable-next-line no-extra-boolean-cast @@ -257,15 +264,15 @@ var storageUtil: BrowserStorageUtil = { return this.get(name); }, - get: function(name?: string): string { + get: function(name?: string): string | undefined { // return all cookies when no args is provided if (!arguments.length) { - return Cookies.get(); + return Object.values(Cookies.get() ?? {}).map(([k, v]) => `${k}=${v}`).join(';'); } - return Cookies.get(name); + return name ? Cookies.get(name) : undefined; }, - delete: function(name: string): string { + delete: function(name: string): void { return Cookies.remove(name, { path: '/' }); } } diff --git a/lib/storage/types.ts b/lib/storage/types.ts index 7d354c36d..66249027f 100644 --- a/lib/storage/types.ts +++ b/lib/storage/types.ts @@ -55,9 +55,9 @@ export interface StorageOptions extends CookieOptions { // for V1 authn interface: tx.resume() export interface TxStorage { - get(name: string): string; - set(name: string, value: string, expiresAt: string, options: CookieOptions): string; - delete(name: string): string; + get(name: string): string | undefined; + set(name: string, value: string, expiresAt: string, options: CookieOptions): string | undefined; + delete(name: string): void; } export interface StorageUtil { From a3eb87b31184afa0584203b96d8d5c3109946b15 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 16:22:30 +0300 Subject: [PATCH 04/11] Revert "." This reverts commit 97e7ce1c99d8a9a49388bbb0d82dec043a693303. --- lib/browser/browserStorage.ts | 29 +++++++++++------------------ lib/storage/types.ts | 6 +++--- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/lib/browser/browserStorage.ts b/lib/browser/browserStorage.ts index cdca28b13..ee553eb07 100644 --- a/lib/browser/browserStorage.ts +++ b/lib/browser/browserStorage.ts @@ -12,8 +12,7 @@ * */ -import * as Cookies from 'js-cookie'; -import type { CookieAttributes } from 'js-cookie'; +import Cookies from 'js-cookie'; import AuthSdkError from '../errors/AuthSdkError'; import { StorageOptions, @@ -40,6 +39,7 @@ export interface BrowserStorageUtil extends StorageUtil { getInMemoryStorage(): SimpleStorage; getCookieStorage(options?: StorageOptions): CookieStorage; testStorage(storage: any): boolean; + storage: Cookies; inMemoryStore: Record; } @@ -233,22 +233,15 @@ var storageUtil: BrowserStorageUtil = { }, storage: { - /* eslint complexity:[0,8] */ - set: function(name: string, value: string, expiresAt: string, options: CookieOptions): string | undefined { - const { secure } = options; - if (typeof secure === 'undefined' || typeof options.sameSite === 'undefined') { + set: function(name: string, value: string, expiresAt: string, options: CookieOptions): string { + const { sameSite, secure } = options; + if (typeof secure === 'undefined' || typeof sameSite === 'undefined') { throw new AuthSdkError('storage.set: "secure" and "sameSite" options must be provided'); } - let sameSite: CookieAttributes['sameSite']; - if (typeof options.sameSite === 'string') { - sameSite = options.sameSite as CookieAttributes['sameSite']; - } else if (typeof options.sameSite === 'boolean') { - sameSite = options.sameSite ? 'lax' : 'none'; - } - var cookieOptions: CookieAttributes = { + var cookieOptions: CookieOptions = { path: options.path || '/', secure, - sameSite, + sameSite }; // eslint-disable-next-line no-extra-boolean-cast @@ -264,15 +257,15 @@ var storageUtil: BrowserStorageUtil = { return this.get(name); }, - get: function(name?: string): string | undefined { + get: function(name?: string): string { // return all cookies when no args is provided if (!arguments.length) { - return Object.values(Cookies.get() ?? {}).map(([k, v]) => `${k}=${v}`).join(';'); + return Cookies.get(); } - return name ? Cookies.get(name) : undefined; + return Cookies.get(name); }, - delete: function(name: string): void { + delete: function(name: string): string { return Cookies.remove(name, { path: '/' }); } } diff --git a/lib/storage/types.ts b/lib/storage/types.ts index 66249027f..7d354c36d 100644 --- a/lib/storage/types.ts +++ b/lib/storage/types.ts @@ -55,9 +55,9 @@ export interface StorageOptions extends CookieOptions { // for V1 authn interface: tx.resume() export interface TxStorage { - get(name: string): string | undefined; - set(name: string, value: string, expiresAt: string, options: CookieOptions): string | undefined; - delete(name: string): void; + get(name: string): string; + set(name: string, value: string, expiresAt: string, options: CookieOptions): string; + delete(name: string): string; } export interface StorageUtil { From 995b0c31bfae52e9727bade748964c81ab1bb0c9 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 19:50:41 +0300 Subject: [PATCH 05/11] send 'No data' if there is a problem with communicating with the iframe --- lib/browser/fingerprint.ts | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/browser/fingerprint.ts b/lib/browser/fingerprint.ts index 7d86e38a8..8cfcd16a5 100644 --- a/lib/browser/fingerprint.ts +++ b/lib/browser/fingerprint.ts @@ -20,6 +20,9 @@ import { import { FingerprintOptions } from '../base/types'; import { OktaAuthHttpInterface } from '../http/types'; +const isMessageFromCorrectSource = (iframe: HTMLIFrameElement, event: MessageEvent) +: boolean => event.source === iframe.contentWindow; + export default function fingerprint(sdk: OktaAuthHttpInterface, options?: FingerprintOptions): Promise { options = options || {}; @@ -27,21 +30,26 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger return Promise.reject(new AuthSdkError('Fingerprinting is not supported on this device')); } - var timeout; - var iframe; - var listener; - var promise = new Promise(function (resolve, reject) { + let timeout: NodeJS.Timeout; + let iframe: HTMLIFrameElement; + let listener: (this: Window, ev: MessageEvent) => void; + let msg; + const promise = new Promise(function (resolve, reject) { iframe = document.createElement('iframe'); iframe.style.display = 'none'; // eslint-disable-next-line complexity - listener = function listener(e) { + listener = function listener(e: MessageEvent) { + if (!isMessageFromCorrectSource(iframe, e)) { + return; + } + if (!e || !e.data || e.origin !== sdk.getIssuerOrigin()) { return; } try { - var msg = JSON.parse(e.data); + msg = JSON.parse(e.data); } catch (err) { // iframe messages should all be parsable // skip not parsable messages come from other sources in same origin (browser extensions) @@ -52,11 +60,12 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger if (!msg) { return; } if (msg.type === 'FingerprintAvailable') { return resolve(msg.fingerprint as string); - } - if (msg.type === 'FingerprintServiceReady') { - e.source.postMessage(JSON.stringify({ + } else if (msg.type === 'FingerprintServiceReady') { + iframe?.contentWindow?.postMessage(JSON.stringify({ type: 'GetFingerprint' }), e.origin); + } else { + return reject(new Error('No data')); } }; addListener(window, 'message', listener); @@ -73,7 +82,7 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger clearTimeout(timeout); removeListener(window, 'message', listener); if (document.body.contains(iframe)) { - iframe.parentElement.removeChild(iframe); + iframe.parentElement?.removeChild(iframe); } }) as Promise; } From 36881ce521bb710b4d31512b9f779019c54edfb8 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 21:07:21 +0300 Subject: [PATCH 06/11] add element to options --- lib/base/types.ts | 1 + lib/browser/fingerprint.ts | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/base/types.ts b/lib/base/types.ts index cae61f9ae..0944c95ae 100644 --- a/lib/base/types.ts +++ b/lib/base/types.ts @@ -33,6 +33,7 @@ export interface FeaturesAPI { export interface FingerprintOptions { timeout?: number; + element?: Element; } export type FingerprintAPI = (options?: FingerprintOptions) => Promise; diff --git a/lib/browser/fingerprint.ts b/lib/browser/fingerprint.ts index 8cfcd16a5..27176c231 100644 --- a/lib/browser/fingerprint.ts +++ b/lib/browser/fingerprint.ts @@ -24,12 +24,11 @@ const isMessageFromCorrectSource = (iframe: HTMLIFrameElement, event: MessageEve : boolean => event.source === iframe.contentWindow; export default function fingerprint(sdk: OktaAuthHttpInterface, options?: FingerprintOptions): Promise { - options = options || {}; - if (!isFingerprintSupported()) { return Promise.reject(new AuthSdkError('Fingerprinting is not supported on this device')); } + const container = options?.element ?? document.body; let timeout: NodeJS.Timeout; let iframe: HTMLIFrameElement; let listener: (this: Window, ev: MessageEvent) => void; @@ -71,7 +70,7 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger addListener(window, 'message', listener); iframe.src = sdk.getIssuerOrigin() + '/auth/services/devicefingerprint'; - document.body.appendChild(iframe); + container.appendChild(iframe); timeout = setTimeout(function() { reject(new AuthSdkError('Fingerprinting timed out')); @@ -81,7 +80,7 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger return promise.finally(function() { clearTimeout(timeout); removeListener(window, 'message', listener); - if (document.body.contains(iframe)) { + if (container.contains(iframe)) { iframe.parentElement?.removeChild(iframe); } }) as Promise; From 988330d0c222db41199cbc60a4a6a5440711b3e2 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 21:21:33 +0300 Subject: [PATCH 07/11] null --- lib/base/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base/types.ts b/lib/base/types.ts index 0944c95ae..1aeed19cf 100644 --- a/lib/base/types.ts +++ b/lib/base/types.ts @@ -33,7 +33,7 @@ export interface FeaturesAPI { export interface FingerprintOptions { timeout?: number; - element?: Element; + element?: Element | null; } export type FingerprintAPI = (options?: FingerprintOptions) => Promise; From 965aca5938d8d6443e7e452b5f27257c16eb7370 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 21:24:24 +0300 Subject: [PATCH 08/11] container --- lib/base/types.ts | 2 +- lib/browser/fingerprint.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/base/types.ts b/lib/base/types.ts index 1aeed19cf..e4db88c0b 100644 --- a/lib/base/types.ts +++ b/lib/base/types.ts @@ -33,7 +33,7 @@ export interface FeaturesAPI { export interface FingerprintOptions { timeout?: number; - element?: Element | null; + container?: Element | null; } export type FingerprintAPI = (options?: FingerprintOptions) => Promise; diff --git a/lib/browser/fingerprint.ts b/lib/browser/fingerprint.ts index 27176c231..5bd458182 100644 --- a/lib/browser/fingerprint.ts +++ b/lib/browser/fingerprint.ts @@ -28,7 +28,7 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger return Promise.reject(new AuthSdkError('Fingerprinting is not supported on this device')); } - const container = options?.element ?? document.body; + const container = options?.container ?? document.body; let timeout: NodeJS.Timeout; let iframe: HTMLIFrameElement; let listener: (this: Window, ev: MessageEvent) => void; From 37b9af3f54fb252f2f349bc9eb91904a783629ba Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Wed, 31 Jul 2024 23:07:01 +0300 Subject: [PATCH 09/11] fix unit --- test/spec/fingerprint.js | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/test/spec/fingerprint.js b/test/spec/fingerprint.js index 31ab7776a..ad91e281f 100644 --- a/test/spec/fingerprint.js +++ b/test/spec/fingerprint.js @@ -40,7 +40,8 @@ describe('fingerprint', function() { type: 'FingerprintAvailable', fingerprint: 'ABCD' }), - origin: 'http://example.okta.com' + origin: 'http://example.okta.com', + source: test.iframe.contentWindow }); }); @@ -48,6 +49,9 @@ describe('fingerprint', function() { style: {}, parentElement: { removeChild: jest.fn() + }, + contentWindow: { + postMessage: postMessageSpy } }; @@ -61,7 +65,7 @@ describe('fingerprint', function() { jest.spyOn(document.body, 'appendChild').mockImplementation(function() { if (options.timeout) { return; } // mimic async page load with setTimeouts - if (options.sendOtherMessage) { + if (options.sendMessageFromAnotherOrigin) { setTimeout(function() { listeners.message({ data: '{"not":"forUs"}', @@ -69,15 +73,24 @@ describe('fingerprint', function() { }); }); } + if (options.sendMessageFromAnotherSource) { + setTimeout(function() { + listeners.message({ + data: '{"not":"forUs"}', + origin: 'http://example.okta.com', + source: { + postMessage: postMessageSpy + } + }); + }); + } setTimeout(function() { listeners.message({ data: options.firstMessage || JSON.stringify({ type: 'FingerprintServiceReady' }), origin: 'http://example.okta.com', - source: { - postMessage: postMessageSpy - } + source: test.iframe.contentWindow }); }); }); @@ -112,8 +125,18 @@ describe('fingerprint', function() { }); }); - it('allows non-Okta postMessages', function () { - return setup({ sendOtherMessage: true }).fingerprint() + it('ignores postMessages from another origin', function () { + return setup({ sendMessageFromAnotherOrigin: true }).fingerprint() + .catch(function(err) { + expect(err).toBeUndefined(); + }) + .then(function(fingerprint) { + expect(fingerprint).toEqual('ABCD'); + }); + }); + + it('ignores postMessages from another source', function () { + return setup({ sendMessageFromAnotherSource: true }).fingerprint() .catch(function(err) { expect(err).toBeUndefined(); }) From 1156f72cc8350700ada66615b8f19d4850b4f755 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Fri, 23 Aug 2024 12:38:38 +0300 Subject: [PATCH 10/11] address comments --- lib/browser/fingerprint.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/browser/fingerprint.ts b/lib/browser/fingerprint.ts index 5bd458182..5f89cd85b 100644 --- a/lib/browser/fingerprint.ts +++ b/lib/browser/fingerprint.ts @@ -32,7 +32,6 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger let timeout: NodeJS.Timeout; let iframe: HTMLIFrameElement; let listener: (this: Window, ev: MessageEvent) => void; - let msg; const promise = new Promise(function (resolve, reject) { iframe = document.createElement('iframe'); iframe.style.display = 'none'; @@ -47,6 +46,7 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger return; } + let msg; try { msg = JSON.parse(e.data); } catch (err) { @@ -64,7 +64,7 @@ export default function fingerprint(sdk: OktaAuthHttpInterface, options?: Finger type: 'GetFingerprint' }), e.origin); } else { - return reject(new Error('No data')); + return reject(new AuthSdkError('No data')); } }; addListener(window, 'message', listener); From a51a15aa0cfb5d35d2eecb53c40b18f68408355c Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Tue, 27 Aug 2024 19:46:29 +0300 Subject: [PATCH 11/11] chlog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b973cf32..58fd3f954 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +# 7.8.0 + +### Features + +- [#1530](https://github.com/okta/okta-auth-js/pull/1530) add: fingerprint API to IDX bundle + # 7.7.1 - [#1529](https://github.com/okta/okta-auth-js/pull/1529) fix: persist `extraParams` passed to `/authorize` and include them during token refresh