From ef3ec2c009d9b6502bf8c33c14877d71ed942c06 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 20:57:56 +0000 Subject: [PATCH 01/35] move unsupported os.tc check IsUsingSubscriptionWorkaround is going to be removed in future commits so moved this into a more permanent place, in the app config logic. --- src/shared/helpers/ConfigHelper.ts | 24 ++++++++++++++++++++++++ src/shared/utils/OneSignalUtils.ts | 20 -------------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index 402912494..c1df97e72 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -58,6 +58,7 @@ export class ConfigHelper { const serverConfig = await downloadServerAppConfig(userConfig.appId); ConverterHelper.upgradeConfigToVersionTwo(userConfig); const appConfig = this.getMergedConfig(userConfig, serverConfig); + this.checkUnsupportedSubdomain(appConfig); this.checkRestrictedOrigin(appConfig); return appConfig; } catch (e) { @@ -70,6 +71,29 @@ export class ConfigHelper { } } + // The os.tc domain feature is no longer supported in v16, so throw if the + // OneSignal app is still configured this way after they migrated from v15. + private static checkUnsupportedSubdomain(appConfig: AppConfig): void { + const windowEnv = SdkEnvironment.getWindowEnv(); + const isHttp = location.protocol === 'http:'; + const useSubdomain = + (windowEnv === WindowEnvironmentKind.Host || + windowEnv === WindowEnvironmentKind.CustomIframe) && + (!!appConfig.subdomain || isHttp); + + if (useSubdomain) { + if (isHttp) { + throw new Error( + "OneSignalSDK: HTTP sites are no longer supported starting with version 16 (User Model), your public site must start with https://. Please visit the OneSignal dashboard's Settings > Web Configuration to find this option.", + ); + } else { + throw new Error( + 'OneSignalSDK: The "My site is not fully HTTPS" option is no longer supported starting with version 16 (User Model) of the OneSignal SDK. Please visit the OneSignal dashboard\'s Settings > Web Configuration to find this option.', + ); + } + } + } + public static checkRestrictedOrigin(appConfig: AppConfig) { if (appConfig.restrictedOriginEnabled) { if ( diff --git a/src/shared/utils/OneSignalUtils.ts b/src/shared/utils/OneSignalUtils.ts index 8d20c6552..c2eddd03e 100644 --- a/src/shared/utils/OneSignalUtils.ts +++ b/src/shared/utils/OneSignalUtils.ts @@ -71,26 +71,6 @@ export class OneSignalUtils { return false; } - const windowEnv = SdkEnvironment.getWindowEnv(); - - const isHttp = location.protocol === 'http:'; - const useSubdomain = - (windowEnv === WindowEnvironmentKind.Host || - windowEnv === WindowEnvironmentKind.CustomIframe) && - (!!subdomain || isHttp); - - if (useSubdomain) { - if (isHttp) { - throw new Error( - "OneSignalSDK: HTTP sites are no longer supported starting with version 16 (User Model), your public site must start with https://. Please visit the OneSignal dashboard's Settings > Web Configuration to find this option.", - ); - } else { - throw new Error( - 'OneSignalSDK: The "My site is not fully HTTPS" option is no longer supported starting with version 16 (User Model) of the OneSignal SDK. Please visit the OneSignal dashboard\'s Settings > Web Configuration to find this option.', - ); - } - } - return false; } From 090d872d3c0167f4e028e06e649a5893e1ce7807 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 21:06:14 +0000 Subject: [PATCH 02/35] rm internalIsUsingSubscriptionWorkaround Removed the internalIsUsingSubscriptionWorkaround function and all code dependent on it. --- __test__/unit/helpers/configHelper.test.ts | 116 --------------------- src/shared/helpers/ConfigHelper.ts | 36 +------ src/shared/utils/OneSignalUtils.ts | 21 ---- 3 files changed, 4 insertions(+), 169 deletions(-) diff --git a/__test__/unit/helpers/configHelper.test.ts b/__test__/unit/helpers/configHelper.test.ts index 41bfb469c..cdfdacf72 100644 --- a/__test__/unit/helpers/configHelper.test.ts +++ b/__test__/unit/helpers/configHelper.test.ts @@ -38,28 +38,6 @@ describe('ConfigHelper Tests', () => { expect(finalPromptOptions?.autoPrompt).toBe(true); }); - test('promptOptions 2 - autoRegister = true backwards compatibility for custom integration (shows slidedown on HTTP)', async () => { - test.stub( - OneSignalUtils, - 'internalIsUsingSubscriptionWorkaround', - Promise.resolve(true), - ); - - const fakeUserConfig: AppUserConfig = { - appId: getRandomUuid(), - autoRegister: true, - }; - - const appConfig = await getFinalAppConfig(fakeUserConfig); - const finalPromptOptions = appConfig.userConfig.promptOptions; - - expect(finalPromptOptions?.native?.enabled).toBe(false); - expect(finalPromptOptions?.native?.autoPrompt).toBe(false); - - expect(finalPromptOptions?.slidedown?.prompts[0].autoPrompt).toBe(true); - expect(finalPromptOptions?.autoPrompt).toBe(true); - }); - test('promptOptions 3 - autoRegister = false backwards compatibility for custom integration (no enabled prompts)', async () => { const fakeUserConfig: AppUserConfig = { appId: getRandomUuid(), @@ -97,36 +75,6 @@ describe('ConfigHelper Tests', () => { expect(finalPromptOptions?.autoPrompt).toBe(true); }); - test(`promptOptions 5 - autoRegister backwards compatibility for custom integration (ignores config, shows slidedown on HTTP)`, async () => { - const internalIsUsingSubscriptionWorkaround = test.stub( - OneSignalUtils, - 'internalIsUsingSubscriptionWorkaround', - Promise.resolve(true), - ); - - const fakeUserConfig: AppUserConfig = { - appId: getRandomUuid(), - autoRegister: true, - }; - - (fakeUserConfig as any).promptOptions = { - slidedown: { - enabled: true, - }, - }; - - const appConfig = await getFinalAppConfig(fakeUserConfig); - const finalPromptOptions = appConfig.userConfig.promptOptions; - - expect(finalPromptOptions?.native?.enabled).toBe(false); - expect(finalPromptOptions?.native?.autoPrompt).toBe(false); - - expect(finalPromptOptions?.slidedown?.prompts[0].autoPrompt).toBe(true); - expect(finalPromptOptions?.autoPrompt).toBe(true); - - internalIsUsingSubscriptionWorkaround.mockRestore(); - }); - test(`promptOptions 6 - autoRegister = true backwards compatibility for custom integration (ignores config, shows native on HTTPS)`, async () => { const fakeUserConfig: AppUserConfig = { appId: getRandomUuid(), @@ -150,37 +98,6 @@ describe('ConfigHelper Tests', () => { expect(finalPromptOptions?.autoPrompt).toBe(true); }); - test(`promptOptions 7 - autoRegister = true backwards compatibility for custom integration (ignores config, shows slidedown on HTTP)`, async () => { - const internalIsUsingSubscriptionWorkaround = test.stub( - OneSignalUtils, - 'internalIsUsingSubscriptionWorkaround', - Promise.resolve(true), - ); - - const fakeUserConfig: AppUserConfig = { - appId: getRandomUuid(), - autoRegister: true, - }; - - (fakeUserConfig as any).promptOptions = { - slidedown: { - enabled: true, - autoPrompt: false, - }, - }; - - const appConfig = await getFinalAppConfig(fakeUserConfig); - const finalPromptOptions = appConfig.userConfig.promptOptions; - - expect(finalPromptOptions?.native?.enabled).toBe(false); - expect(finalPromptOptions?.native?.autoPrompt).toBe(false); - - expect(finalPromptOptions?.slidedown?.prompts[0].autoPrompt).toBe(true); - expect(finalPromptOptions?.autoPrompt).toBe(true); - - internalIsUsingSubscriptionWorkaround.mockRestore(); - }); - test(`promptOptions 8 - autoRegister = true backwards compatibility for custom integration (ignores config, shows native on HTTPS)`, async () => { const fakeUserConfig: AppUserConfig = { appId: getRandomUuid(), @@ -235,39 +152,6 @@ describe('ConfigHelper Tests', () => { expect(finalPromptOptions?.autoPrompt).toBe(true); }); - test(`promptOptions 10 - autoRegister backwards compatibility for custom integration (ignores config, shows slidedown on HTTP)`, async () => { - test.stub( - OneSignalUtils, - 'internalIsUsingSubscriptionWorkaround', - Promise.resolve(true), - ); - - const fakeUserConfig: AppUserConfig = { - appId: getRandomUuid(), - autoRegister: true, - }; - - (fakeUserConfig as any).promptOptions = { - native: { - enabled: true, - autoPrompt: false, - }, - slidedown: { - enabled: true, - autoPrompt: false, - }, - }; - - const appConfig = await getFinalAppConfig(fakeUserConfig); - const finalPromptOptions = appConfig.userConfig.promptOptions; - - expect(finalPromptOptions?.native?.enabled).toBe(false); - expect(finalPromptOptions?.native?.autoPrompt).toBe(false); - - expect(finalPromptOptions?.slidedown?.prompts[0].autoPrompt).toBe(true); - expect(finalPromptOptions?.autoPrompt).toBe(true); - }); - test('autoResubscribe - autoRegister backwards compatibility for custom integration 1', () => { const fakeUserConfig: AppUserConfig = { appId: getRandomUuid(), diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index c1df97e72..bec11159a 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -146,20 +146,11 @@ export class ConfigHelper { userConfig, serverConfig, ); - const allowLocalhostAsSecureOrigin = serverConfig.config.setupBehavior - ? serverConfig.config.setupBehavior.allowLocalhostAsSecureOrigin - : userConfig.allowLocalhostAsSecureOrigin; - const isUsingSubscriptionWorkaround = - OneSignalUtils.internalIsUsingSubscriptionWorkaround( - subdomain, - allowLocalhostAsSecureOrigin, - ); const mergedUserConfig = this.getUserConfigForConfigIntegrationKind( configIntegrationKind, userConfig, serverConfig, - isUsingSubscriptionWorkaround, ); return { @@ -267,7 +258,6 @@ export class ConfigHelper { promptOptions: AppUserConfigPromptOptions | undefined, defaultsFromServer: ServerAppPromptConfig, wholeUserConfig: AppUserConfig, - isUsingSubscriptionWorkaround = false, ): AppUserConfigPromptOptions | undefined { let customlinkUser: AppUserConfigCustomLinkOptions = { enabled: false }; if (promptOptions && promptOptions.customlink) { @@ -432,27 +422,11 @@ export class ConfigHelper { * prompt options. */ if (wholeUserConfig.autoRegister === true) { - if (isUsingSubscriptionWorkaround) { - // disable native prompt - promptOptionsConfig.native.enabled = false; - promptOptionsConfig.native.autoPrompt = false; - - // enable slidedown & make it autoPrompt - const text = { - actionMessage: SERVER_CONFIG_DEFAULTS_SLIDEDOWN.actionMessage, - acceptButton: SERVER_CONFIG_DEFAULTS_SLIDEDOWN.acceptButton, - cancelButton: SERVER_CONFIG_DEFAULTS_SLIDEDOWN.cancelButton, - }; - promptOptionsConfig.slidedown.prompts = [ - { type: DelayedPromptType.Push, autoPrompt: true, text }, - ]; - } else { - //enable native prompt & make it autoPrompt - promptOptionsConfig.native.enabled = true; - promptOptionsConfig.native.autoPrompt = true; + //enable native prompt & make it autoPrompt + promptOptionsConfig.native.enabled = true; + promptOptionsConfig.native.autoPrompt = true; - //leave slidedown settings without change - } + //leave slidedown settings without change } // sets top level `autoPrompt` to trigger autoprompt codepath in initialization / prompting flow @@ -524,7 +498,6 @@ export class ConfigHelper { configIntegrationKind: ConfigIntegrationKind, userConfig: AppUserConfig, serverConfig: ServerAppConfig, - isUsingSubscriptionWorkaround = false, ): AppUserConfig { const integrationCapabilities = this.getIntegrationCapabilities( configIntegrationKind, @@ -666,7 +639,6 @@ export class ConfigHelper { userConfig.promptOptions, serverConfig.config.staticPrompts, userConfig, - isUsingSubscriptionWorkaround, ), ...{ serviceWorkerParam: !!userConfig.serviceWorkerParam diff --git a/src/shared/utils/OneSignalUtils.ts b/src/shared/utils/OneSignalUtils.ts index c2eddd03e..5918949b4 100644 --- a/src/shared/utils/OneSignalUtils.ts +++ b/src/shared/utils/OneSignalUtils.ts @@ -50,27 +50,6 @@ export class OneSignalUtils { const allowLocalhostAsSecureOrigin: boolean = this.isLocalhostAllowedAsSecureOrigin(); - return OneSignalUtils.internalIsUsingSubscriptionWorkaround( - OneSignal.config.subdomain, - allowLocalhostAsSecureOrigin, - ); - } - - public static internalIsUsingSubscriptionWorkaround( - subdomain: string | undefined, - allowLocalhostAsSecureOrigin: boolean | undefined, - ): boolean { - if (bowserCastle().name == 'safari') { - return false; - } - - if ( - allowLocalhostAsSecureOrigin === true && - (location.hostname === 'localhost' || location.hostname === '127.0.0.1') - ) { - return false; - } - return false; } From 4c069236be78c3956e42e43e84445b3d175aee50 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 21:51:34 +0000 Subject: [PATCH 03/35] rm isUsingSubscriptionWorkaround() Removed isUsingSubscriptionWorkaround() and all usages of it --- __test__/unit/core/modelRepo.test.ts | 1 - __test__/unit/helpers/initHelper.test.ts | 24 ----- src/onesignal/OneSignal.ts | 33 ------ src/page/bell/Bell.ts | 16 +-- src/page/bell/Button.ts | 17 +--- src/page/helpers/EnvironmentInfoHelper.ts | 7 +- src/shared/helpers/DismissHelper.ts | 42 +------- src/shared/helpers/InitHelper.ts | 31 +----- src/shared/helpers/MainHelper.ts | 8 +- src/shared/managers/PermissionManager.ts | 22 ++-- src/shared/managers/ServiceWorkerManager.ts | 31 ++---- src/shared/services/Database.ts | 105 ++------------------ src/shared/utils/OneSignalUtils.ts | 39 +------- src/shared/utils/utils.ts | 80 ++++----------- test/unit/helpers/MainHelper.ts | 18 ---- test/unit/meta/environment.ts | 24 ----- test/unit/prompts/CustomLink.ts | 69 ------------- 17 files changed, 51 insertions(+), 516 deletions(-) delete mode 100644 test/unit/meta/environment.ts diff --git a/__test__/unit/core/modelRepo.test.ts b/__test__/unit/core/modelRepo.test.ts index fafeabe1c..36d978724 100644 --- a/__test__/unit/core/modelRepo.test.ts +++ b/__test__/unit/core/modelRepo.test.ts @@ -27,7 +27,6 @@ jest.mock('../../../src/core/operationRepo/Operation'); describe('ModelRepo tests', () => { beforeEach(async () => { test.stub(ModelCache.prototype, 'load', Promise.resolve({})); - test.stub(OneSignalUtils, 'isUsingSubscriptionWorkaround', () => false); jest.useFakeTimers(); core = new CoreModule(); coreDirector = new CoreModuleDirector(core); diff --git a/__test__/unit/helpers/initHelper.test.ts b/__test__/unit/helpers/initHelper.test.ts index 54f70fd34..d90b99a99 100644 --- a/__test__/unit/helpers/initHelper.test.ts +++ b/__test__/unit/helpers/initHelper.test.ts @@ -21,20 +21,6 @@ describe('InitHelper', () => { expect(OneSignal.subscriptionModalHost.modal).not.toBeUndefined(); }); - test('registerForPushNotifications: load fullscreen popup when using subscription workaround', async () => { - const utilsStub = jest - .spyOn(OneSignalUtils, 'isUsingSubscriptionWorkaround') - .mockReturnValue(true); - const loadStub = jest - .spyOn(InitHelper, 'loadSubscriptionPopup') - .mockResolvedValue(undefined); - - await InitHelper.registerForPushNotifications(); - - expect(utilsStub).toHaveBeenCalledTimes(1); - expect(loadStub).toHaveBeenCalledTimes(1); - }); - /** onSdkInitialized */ test('onSdkInitialized: ensure public sdk initialized triggered', async () => { OneSignal.emitter.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { @@ -58,11 +44,6 @@ describe('InitHelper', () => { const spy = jest .spyOn(OneSignal.context.updateManager, 'sendOnSessionUpdate') .mockResolvedValue(undefined); - test.stub( - OneSignalUtils, - 'isUsingSubscriptionWorkaround', - Promise.resolve(false), - ); OneSignal.config.userConfig.promptOptions.autoPrompt = false; OneSignal.config.userConfig.autoResubscribe = false; @@ -76,11 +57,6 @@ describe('InitHelper', () => { const spy = jest .spyOn(OneSignal.context.updateManager, 'sendOnSessionUpdate') .mockResolvedValue(undefined); - test.stub( - OneSignalUtils, - 'isUsingSubscriptionWorkaround', - Promise.resolve(false), - ); OneSignal.config.userConfig.promptOptions.autoPrompt = true; OneSignal.config.userConfig.autoResubscribe = true; diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index 4359d0898..a38d71281 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -193,39 +193,6 @@ export default class OneSignal { InitHelper.onSdkInitialized, ); - if (OneSignalUtils.isUsingSubscriptionWorkaround()) { - /** - * The user may have forgot to choose a subdomain in his web app setup. - * - * Or, the user may have an HTTP & HTTPS site while using an HTTPS-only - * config on both variants. This would cause the HTTPS site to work - * perfectly, while causing errors and preventing web push from working - * on the HTTP site. - */ - if (!OneSignal.config || !OneSignal.config.subdomain) - throw new SdkInitError(SdkInitErrorKind.MissingSubdomain); - - /** - * We'll need to set up page activity tracking events on the main page but we can do so - * only after the main initialization in the iframe is successful and a new session - * is initiated. - */ - OneSignal.emitter.on( - OneSignal.EVENTS.SESSION_STARTED, - SessionManager.setupSessionEventListenersForHttp, - ); - - /** - * The iFrame may never load (e.g. OneSignal might be down), in which - * case the rest of the SDK's initialization will be blocked. This is a - * good thing! We don't want to access IndexedDb before we know which - * origin to store data on. - */ - OneSignal.proxyFrameHost = await AltOriginManager.discoverAltOrigin( - OneSignal.config, - ); - } - window.addEventListener('focus', () => { // Checks if permission changed every time a user focuses on the page, // since a user has to click out of and back on the page to check permissions diff --git a/src/page/bell/Bell.ts b/src/page/bell/Bell.ts index d7934f73d..a03dd3c8e 100755 --- a/src/page/bell/Bell.ts +++ b/src/page/bell/Bell.ts @@ -9,7 +9,6 @@ import { nothing, once, removeDomElement, - isUsingSubscriptionWorkaround, } from '../../shared/utils/utils'; import Badge from './Badge'; import Button from './Button'; @@ -524,20 +523,7 @@ export default class Bell { }) .then(() => delay(this.options.showLauncherAfter || 0)) .then(() => { - if ( - isUsingSubscriptionWorkaround() && - doNotPrompt !== true && - !isPushEnabled && - OneSignal.config?.userConfig.promptOptions?.autoPrompt === true && - !MainHelper.isHttpPromptAlreadyShown() - ) { - Log.debug( - 'Not showing notify button because slidedown will be shown.', - ); - return nothing(); - } else { - return this.launcher.show(); - } + return this.launcher.show(); }) .then(() => { return delay(this.options.showBadgeAfter || 0); diff --git a/src/page/bell/Button.ts b/src/page/bell/Button.ts index 11bb1d74f..7dad56843 100755 --- a/src/page/bell/Button.ts +++ b/src/page/bell/Button.ts @@ -1,8 +1,4 @@ -import { - removeDomElement, - addDomElement, - isUsingSubscriptionWorkaround, -} from '../../shared/utils/utils'; +import { removeDomElement, addDomElement } from '../../shared/utils/utils'; import OneSignalEvent from '../../shared/services/OneSignalEvent'; import ActiveAnimatedElement from './ActiveAnimatedElement'; import Bell from './Bell'; @@ -138,14 +134,9 @@ export default class Button extends ActiveAnimatedElement { this.bell.showDialogProcedure(); }); } else if (this.bell.blocked) { - if (isUsingSubscriptionWorkaround()) { - // Show the HTTP popup so users can re-allow notifications - InitHelper.registerForPushNotifications(); - } else { - this.bell.launcher.activateIfInactive().then(() => { - this.bell.showDialogProcedure(); - }); - } + this.bell.launcher.activateIfInactive().then(() => { + this.bell.showDialogProcedure(); + }); } return this.bell.message.hide(); } diff --git a/src/page/helpers/EnvironmentInfoHelper.ts b/src/page/helpers/EnvironmentInfoHelper.ts index 2d9fb9906..5500f1367 100644 --- a/src/page/helpers/EnvironmentInfoHelper.ts +++ b/src/page/helpers/EnvironmentInfoHelper.ts @@ -1,7 +1,6 @@ import bowser from 'bowser'; import { EnvironmentInfo } from '../models/EnvironmentInfo'; import { Browser } from '../../shared/models/Browser'; -import { OneSignalUtils } from '../../shared/utils/OneSignalUtils'; import { isMacOSSafariInIframe } from '../utils/BrowserSupportsPush'; import Utils from '../../shared/context/Utils'; import { bowserCastle } from '../../shared/utils/bowserCastle'; @@ -17,7 +16,7 @@ export class EnvironmentInfoHelper { browserType: this.getBrowser(), browserVersion: this.getBrowserVersion(), isHttps: this.isHttps(), - isUsingSubscriptionWorkaround: this.isUsingSubscriptionWorkaround(), + isUsingSubscriptionWorkaround: false, isBrowserAndSupportsServiceWorkers: this.supportsServiceWorkers(), requiresUserInteraction: this.requiresUserInteraction(), osVersion: this.getOsVersion(), @@ -65,10 +64,6 @@ export class EnvironmentInfoHelper { : false; } - private static isUsingSubscriptionWorkaround(): boolean { - return OneSignalUtils.isUsingSubscriptionWorkaround(); - } - private static supportsServiceWorkers(): boolean { return window.navigator && 'serviceWorker' in window.navigator; } diff --git a/src/shared/helpers/DismissHelper.ts b/src/shared/helpers/DismissHelper.ts index a58727ecf..f5206d1e9 100644 --- a/src/shared/helpers/DismissHelper.ts +++ b/src/shared/helpers/DismissHelper.ts @@ -7,7 +7,6 @@ import TimedLocalStorage from '../../page/modules/TimedLocalStorage'; import Log from '../libraries/Log'; import SdkEnvironment from '../managers/SdkEnvironment'; import Database from '../services/Database'; -import { isUsingSubscriptionWorkaround } from '../utils/utils'; declare let OneSignal: any; @@ -26,40 +25,6 @@ export class DismissHelper { * Creates an expiring local storage entry to note that the user does not want to be disturbed. */ static async markPromptDismissedWithType(type: DismissPrompt) { - /** - * Note: LocalStorage is set both on subdomain.onesignal.com and the main site. - * - * When checking whether the prompt was previously dismissed, certain code cannot be - * asynchronous otherwise the browser treats it like a blocked popup, so LocalStorage is - * synchronous while IndexedDb access / PostMessage querying across origins are both - * asynchronous. - */ - if (isUsingSubscriptionWorkaround()) { - try { - await new Promise((resolve, reject) => { - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.MARK_PROMPT_DISMISSED, - {}, - (reply) => { - if ( - reply.data === - OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE - ) { - resolve(); - } else { - reject(); - } - }, - ); - }); - } catch (e) { - Log.debug( - "Proxy Frame possibly didn't not receive MARK_PROMPT_DISMISSED message", - e || '', - ); - } - } - const countKey = DISMISS_TYPE_COUNT_MAP[type]; const timeKey = DISMISS_TYPE_TIME_MAP[type]; @@ -67,12 +32,7 @@ export class DismissHelper { if (!dismissCount) { dismissCount = 0; } - /** - * This will be run twice for HTTP sites, since we share IndexedDb, so we don't run it for HTTP sites. - */ - if (!isUsingSubscriptionWorkaround()) { - dismissCount += 1; - } + dismissCount += 1; let dismissDays = 3; if (dismissCount == 2) { diff --git a/src/shared/helpers/InitHelper.ts b/src/shared/helpers/InitHelper.ts index 6280ab4fc..9fe991855 100755 --- a/src/shared/helpers/InitHelper.ts +++ b/src/shared/helpers/InitHelper.ts @@ -104,14 +104,7 @@ export default class InitHelper { const subscription = await Database.getSubscription(); subscription.optedOut = isOptedOut; await Database.setSubscription(subscription); - - /** - * Auto-resubscribe is working only on HTTPS (and in safari) - * Should be called before autoprompting to make sure user gets a chance to be re-subscribed first. - */ - if (!OneSignalUtils.isUsingSubscriptionWorkaround()) { - await InitHelper.handleAutoResubscribe(isOptedOut); - } + await InitHelper.handleAutoResubscribe(isOptedOut); const isSubscribed = await OneSignal.context.subscriptionManager.isPushNotificationsEnabled(); @@ -141,28 +134,6 @@ export default class InitHelper { return; } - if (OneSignalUtils.isUsingSubscriptionWorkaround()) { - if (options.httpPermissionRequest) { - /* - * Do not throw an error because it may cause the parent event handler to - * throw and stop processing the rest of their code. Typically, for this - * prompt sequence, a custom modal is being shown thanking the user for - * granting permissions. Throwing an error might cause the modal to stay - * on screen and not close. - * - * Only log an error for HTTP sites. A few HTTPS sites are mistakenly be - * using this API instead of the parameter-less version to register for - * push notifications. - */ - Log.error( - new DeprecatedApiError(DeprecatedApiReason.HttpPermissionRequest), - ); - return; - } - await InitHelper.loadSubscriptionPopup(options); - return; - } - await SubscriptionHelper.registerForPush(); } diff --git a/src/shared/helpers/MainHelper.ts b/src/shared/helpers/MainHelper.ts index 58e93919f..90ac66451 100755 --- a/src/shared/helpers/MainHelper.ts +++ b/src/shared/helpers/MainHelper.ts @@ -15,7 +15,6 @@ import { RawPushSubscription } from '../models/RawPushSubscription'; import SubscriptionHelper from './SubscriptionHelper'; import Utils from '../context/Utils'; import Database from '../services/Database'; -import OneSignalUtils from '../utils/OneSignalUtils'; import { PermissionUtils } from '../utils/PermissionUtils'; import OneSignalEvent from '../services/OneSignalEvent'; import Environment from './Environment'; @@ -32,12 +31,7 @@ export default class MainHelper { } if (currentPermission === NotificationPermission.Denied) { - // Due to this issue https://github.com/OneSignal/OneSignal-Website-SDK/issues/289 we cannot reliably detect - // "default" permission in HTTP context. Browser reports denied for both "default" and "denied" statuses. - // Returning SubscriptionStateKind.NoNativePermission for this case. - return OneSignalUtils.isUsingSubscriptionWorkaround() - ? SubscriptionStateKind.NoNativePermission - : SubscriptionStateKind.NotSubscribed; + return SubscriptionStateKind.NotSubscribed; } const existingUser = diff --git a/src/shared/managers/PermissionManager.ts b/src/shared/managers/PermissionManager.ts index c76c0b935..782e441f5 100644 --- a/src/shared/managers/PermissionManager.ts +++ b/src/shared/managers/PermissionManager.ts @@ -101,21 +101,14 @@ export default class PermissionManager { if (Environment.useSafariLegacyPush()) return PermissionManager.getSafariNotificationPermission(safariWebId); - // Is this web push setup using subdomain.os.tc or subdomain.onesignal.com? - if (OneSignalUtils.isUsingSubscriptionWorkaround()) - return await this.getOneSignalSubdomainNotificationPermission( - safariWebId, - ); - else { - const reportedPermission: NotificationPermission = - this.getW3cNotificationPermission(); - - if (await this.isPermissionEnvironmentAmbiguous(reportedPermission)) { - return await this.getInterpretedAmbiguousPermission(reportedPermission); - } + const reportedPermission: NotificationPermission = + this.getW3cNotificationPermission(); - return this.getW3cNotificationPermission(); + if (await this.isPermissionEnvironmentAmbiguous(reportedPermission)) { + return await this.getInterpretedAmbiguousPermission(reportedPermission); } + + return this.getW3cNotificationPermission(); } /** @@ -186,8 +179,7 @@ export default class PermissionManager { !browser.firefox && permission === NotificationPermission.Denied && (this.isCurrentFrameContextCrossOrigin() || - (await SdkEnvironment.isFrameContextInsecure()) || - OneSignalUtils.isUsingSubscriptionWorkaround()) + (await SdkEnvironment.isFrameContextInsecure())) ); } diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index 182da639b..e5196b27e 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -149,28 +149,15 @@ export class ServiceWorkerManager { public async getWorkerVersion(): Promise { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { - if (OneSignalUtils.isUsingSubscriptionWorkaround()) { - const proxyFrameHost: ProxyFrameHost = OneSignal.proxyFrameHost; - if (!proxyFrameHost) { - /* On init, this function may be called. Return a null state for now */ - resolve(NaN); - } else { - const proxyWorkerVersion = await proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.GET_WORKER_VERSION, - ); - resolve(proxyWorkerVersion); - } - } else { - this.context.workerMessenger.once( - WorkerMessengerCommand.WorkerVersion, - (workerVersion) => { - resolve(workerVersion); - }, - ); - await this.context.workerMessenger.unicast( - WorkerMessengerCommand.WorkerVersion, - ); - } + this.context.workerMessenger.once( + WorkerMessengerCommand.WorkerVersion, + (workerVersion) => { + resolve(workerVersion); + }, + ); + await this.context.workerMessenger.unicast( + WorkerMessengerCommand.WorkerVersion, + ); }); } diff --git a/src/shared/services/Database.ts b/src/shared/services/Database.ts index 618c591f3..c56742d1e 100644 --- a/src/shared/services/Database.ts +++ b/src/shared/services/Database.ts @@ -112,14 +112,6 @@ export default class Database { } } - private shouldUsePostmam(): boolean { - return ( - SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.ServiceWorker && - OneSignalUtils.isUsingSubscriptionWorkaround() && - SdkEnvironment.getTestEnv() === TestEnvironmentKind.None - ); - } - /** * Asynchronously retrieves the value of the key at the table (if key is specified), or the entire table * (if key is not specified). @@ -129,47 +121,14 @@ export default class Database { * @returns {Promise} Returns a promise that fulfills when the value(s) are available. */ async get(table: OneSignalDbTable, key?: string): Promise { - if (this.shouldUsePostmam()) { - return await new Promise((resolve) => { - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_GET, - [ - { - table: table, - key: key, - }, - ], - (reply: any) => { - const result = reply.data[0]; - resolve(result); - }, - ); - }); - } else { - const result = await this.database.get(table, key); - const cleanResult = Database.applyDbResultFilter(table, key, result); - return cleanResult; - } + const result = await this.database.get(table, key); + const cleanResult = Database.applyDbResultFilter(table, key, result); + return cleanResult; } public async getAll(table: OneSignalDbTable): Promise { - if (this.shouldUsePostmam()) { - return await new Promise((resolve) => { - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_GET_ALL, - { - table: table, - }, - (reply: any) => { - const result = reply.data; - resolve(result); - }, - ); - }); - } else { - const result = await this.database.getAll(table); - return result; - } + const result = await this.database.getAll(table); + return result; } /** @@ -179,31 +138,7 @@ export default class Database { */ async put(table: OneSignalDbTable, keypath: any): Promise { await new Promise((resolve, reject) => { - if ( - SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.ServiceWorker && - OneSignalUtils.isUsingSubscriptionWorkaround() && - SdkEnvironment.getTestEnv() === TestEnvironmentKind.None - ) { - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_PUT, - [{ table: table, keypath: keypath }], - (reply: any) => { - if ( - reply.data === - OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE - ) { - resolve(); - } else { - reject( - `(Database) Attempted remote IndexedDB put(${table}, ${keypath}),` + - `but did not get success response.`, - ); - } - }, - ); - } else { - this.database.put(table, keypath).then(() => resolve()); - } + this.database.put(table, keypath).then(() => resolve()); }); this.emitter.emit(Database.EVENTS.SET, keypath); } @@ -214,33 +149,7 @@ export default class Database { * @returns {Promise} Returns a promise containing a key that is fulfilled when deletion is completed. */ remove(table: OneSignalDbTable, keypath?: string) { - if ( - SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.ServiceWorker && - OneSignalUtils.isUsingSubscriptionWorkaround() && - SdkEnvironment.getTestEnv() === TestEnvironmentKind.None - ) { - return new Promise((resolve, reject) => { - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_REMOVE, - [{ table: table, keypath: keypath }], - (reply: any) => { - if ( - reply.data === - OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE - ) { - resolve(); - } else { - reject( - `(Database) Attempted remote IndexedDB remove(${table}, ${keypath}),` + - `but did not get success response.`, - ); - } - }, - ); - }); - } else { - return this.database.remove(table, keypath); - } + return this.database.remove(table, keypath); } async getAppConfig(): Promise { diff --git a/src/shared/utils/OneSignalUtils.ts b/src/shared/utils/OneSignalUtils.ts index 5918949b4..c773f0fa5 100644 --- a/src/shared/utils/OneSignalUtils.ts +++ b/src/shared/utils/OneSignalUtils.ts @@ -19,40 +19,6 @@ export class OneSignalUtils { ); } - /** - * Returns true if web push subscription occurs on a subdomain of OneSignal. - * If true, our main IndexedDB is stored on the subdomain of onesignal.com, and not the user"s site. - * @remarks - * This method returns true if: - * - The browser is not Safari - * - Safari uses a different method of subscription and does not require our workaround - * - The init parameters contain a subdomain (even if the protocol is HTTPS) - * - HTTPS users using our subdomain workaround still have the main IndexedDB stored on our subdomain - * - The protocol of the current webpage is http: - * Exceptions are: - * - Safe hostnames like localhost and 127.0.0.1 - * - Because we don"t want users to get the wrong idea when testing on localhost that direct permission - * is supported on HTTP, we"ll ignore these exceptions. HTTPS will always be required for direct permission - * - We are already in popup or iFrame mode, or this is called from the service worker - */ - public static isUsingSubscriptionWorkaround(): boolean { - const windowEnv = SdkEnvironment.getWindowEnv(); - - if (!OneSignal.config) { - throw new Error( - `(${windowEnv.toString()}) isUsingSubscriptionWorkaround() cannot be called until OneSignal.config exists.`, - ); - } - if (bowserCastle().name == 'safari') { - return false; - } - - const allowLocalhostAsSecureOrigin: boolean = - this.isLocalhostAllowedAsSecureOrigin(); - - return false; - } - public static redetectBrowserUserAgent(): IBowser { // During testing, the browser object may be initialized before the userAgent is injected if (bowserCastle().name === '' && bowserCastle().version === '') { @@ -95,10 +61,7 @@ export class OneSignalUtils { } static isHttps(): boolean { - if (OneSignalUtils.isSafari()) { - return window.location.protocol === 'https:'; - } - return !OneSignalUtils.isUsingSubscriptionWorkaround(); + return window.location.protocol === 'https:'; } static isSafari(): boolean { diff --git a/src/shared/utils/utils.ts b/src/shared/utils/utils.ts index 528d637a9..29d1735ab 100755 --- a/src/shared/utils/utils.ts +++ b/src/shared/utils/utils.ts @@ -36,27 +36,6 @@ export async function awaitOneSignalInitAndSupported(): Promise { }); } -/** - * Returns true if web push subscription occurs on a subdomain of OneSignal. - * If true, our main IndexedDB is stored on the subdomain of onesignal.com, and not the user's site. - * @remarks - * This method returns true if: - * - The browser is not Safari - * - Safari uses a different method of subscription and does not require our workaround - * - The init parameters contain a subdomain (even if the protocol is HTTPS) - * - HTTPS users using our subdomain workaround still have the main IndexedDB stored on our subdomain - * - The protocol of the current webpage is http: - * Exceptions are: - * - Safe hostnames like localhost and 127.0.0.1 - * - Because we don't want users to get the wrong idea when testing on localhost that - * direct permission is supported on HTTP, we'll ignore these exceptions. HTTPS will - * always be required for direct permission - * - We are already in popup or iFrame mode, or this is called from the service worker - */ -export function isUsingSubscriptionWorkaround() { - return OneSignalUtils.isUsingSubscriptionWorkaround(); -} - export async function triggerNotificationPermissionChanged( updateIfIdentical = false, ) { @@ -297,48 +276,25 @@ export function unsubscribeFromPush() { } else throw new Error('Cannot unsubscribe because not subscribed.'); }); } else { - if (isUsingSubscriptionWorkaround()) { - return new Promise((resolve, reject) => { - Log.debug( - "Unsubscribe from push got called, and we're going to remotely execute it in HTTPS iFrame.", - ); - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.UNSUBSCRIBE_FROM_PUSH, - null, - (reply: any) => { - Log.debug('Unsubscribe from push succesfully remotely executed.'); - if ( - reply.data === - OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE - ) { - resolve(); - } else { - reject('Failed to remotely unsubscribe from push.'); - } - }, - ); + return OneSignal.context.serviceWorkerManager + .getRegistration() + .then((serviceWorker: ServiceWorkerRegistration | null | undefined) => { + if (!serviceWorker) { + return Promise.resolve(); + } + return serviceWorker; + }) + .then( + (registration: ServiceWorkerRegistration) => registration.pushManager, + ) + .then((pushManager: PushManager) => pushManager.getSubscription()) + .then((subscription: any) => { + if (subscription) { + return subscription.unsubscribe(); + } else { + return Promise.resolve(); + } }); - } else { - return OneSignal.context.serviceWorkerManager - .getRegistration() - .then((serviceWorker: ServiceWorkerRegistration | null | undefined) => { - if (!serviceWorker) { - return Promise.resolve(); - } - return serviceWorker; - }) - .then( - (registration: ServiceWorkerRegistration) => registration.pushManager, - ) - .then((pushManager: PushManager) => pushManager.getSubscription()) - .then((subscription: any) => { - if (subscription) { - return subscription.unsubscribe(); - } else { - return Promise.resolve(); - } - }); - } } } diff --git a/test/unit/helpers/MainHelper.ts b/test/unit/helpers/MainHelper.ts index 72b4cbdc1..6436f7a0a 100644 --- a/test/unit/helpers/MainHelper.ts +++ b/test/unit/helpers/MainHelper.ts @@ -6,7 +6,6 @@ import { TestEnvironment, HttpHttpsEnvironment, } from '../../support/sdk/TestEnvironment'; -import { OneSignalUtils } from '../../../src/shared/utils/OneSignalUtils'; import MainHelper from '../../../src/shared/helpers/MainHelper'; let sinonSandbox: SinonSandbox; @@ -36,27 +35,10 @@ test('getCurrentNotificationType for default permission', async (t) => { ); }); -test('getCurrentNotificationType for denied permission in HTTP context', async (t) => { - sinonSandbox - .stub(OneSignal.context.permissionManager, 'getNotificationPermission') - .resolves(NotificationPermission.Denied); - sinonSandbox - .stub(OneSignalUtils, 'isUsingSubscriptionWorkaround') - .returns(true); - - t.is( - await MainHelper.getCurrentNotificationType(), - SubscriptionStateKind.NoNativePermission, - ); -}); - test('getCurrentNotificationType for denied permission in HTTPS context', async (t) => { sinonSandbox .stub(OneSignal.context.permissionManager, 'getNotificationPermission') .resolves(NotificationPermission.Denied); - sinonSandbox - .stub(OneSignalUtils, 'isUsingSubscriptionWorkaround') - .returns(false); t.is( await MainHelper.getCurrentNotificationType(), diff --git a/test/unit/meta/environment.ts b/test/unit/meta/environment.ts deleted file mode 100644 index 6b52e0578..000000000 --- a/test/unit/meta/environment.ts +++ /dev/null @@ -1,24 +0,0 @@ -import '../../support/polyfills/polyfills'; -import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; -import { isUsingSubscriptionWorkaround } from '../../../src/shared/utils/utils'; - -test(`can simulate HTTPS site`, async (t) => { - await TestEnvironment.initialize({ - initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, - }); - t.false(isUsingSubscriptionWorkaround()); -}); - -test(`can simulate HTTP site`, async (t) => { - await TestEnvironment.initialize({ - initOptions: { - subdomain: 'testSubdomain', - }, - }); - t.true(isUsingSubscriptionWorkaround()); -}); diff --git a/test/unit/prompts/CustomLink.ts b/test/unit/prompts/CustomLink.ts index 7a77f3396..07e1b5cff 100644 --- a/test/unit/prompts/CustomLink.ts +++ b/test/unit/prompts/CustomLink.ts @@ -5,7 +5,6 @@ import { HttpHttpsEnvironment, } from '../../support/sdk/TestEnvironment'; import { AppUserConfigCustomLinkOptions } from '../../../src/shared/models/Prompts'; -import OneSignalUtils from '../../../src/shared/utils/OneSignalUtils'; import { ResourceLoadState } from '../../../src/page/services/DynamicResourceLoader'; import { hasCssClass } from '../../../src/shared/utils/utils'; import { DismissHelper } from '../../../src/shared/helpers/DismissHelper'; @@ -16,7 +15,6 @@ import { import { CustomLinkManager } from '../../../src/shared/managers/CustomLinkManager'; import EventsTestHelper from '../../support/tester/EventsTestHelper'; import { simulateEventOfTypeOnElement } from '../../support/tester/utils'; -import PermissionManager from '../../../src/shared/managers/PermissionManager'; import NotificationsNamespace from '../../../src/onesignal/NotificationsNamespace'; const sandbox: SinonSandbox = sinon.sandbox.create(); @@ -271,7 +269,6 @@ test('customlink: subscribe: clicked: subscribed -> unsubscribed', async (t) => .callsFake(async () => { await setSubscriptionStub(); }); - sandbox.stub(OneSignalUtils, 'isUsingSubscriptionWorkaround').returns(false); sandbox .stub(OneSignal.context.subscriptionManager, 'getSubscriptionState') .returns({ @@ -302,7 +299,6 @@ test('customlink: subscribe: clicked: subscribed -> unsubscribed', async (t) => test('customlink: subscribe: clicked: unsubscribed -> subscribed. https. opted out', async (t) => { const subscriptionPromise = EventsTestHelper.getSubscriptionPromise(); sandbox.stub(CustomLinkManager, 'isPushEnabled').returns(false); - sandbox.stub(OneSignalUtils, 'isUsingSubscriptionWorkaround').returns(false); const subscriptionSpy = sandbox .stub(NotificationsNamespace.prototype, 'disable') .callsFake(async () => { @@ -347,7 +343,6 @@ test('customlink: subscribe: clicked: unsubscribed -> subscribed. https. never s .callsFake(async () => { await setSubscriptionStub(); }); - sandbox.stub(OneSignalUtils, 'isUsingSubscriptionWorkaround').returns(false); sandbox.stub(CustomLinkManager, 'isOptedOut').returns(false); sandbox @@ -373,67 +368,3 @@ test('customlink: subscribe: clicked: unsubscribed -> subscribed. https. never s t.is(subscriptionSpy.calledOnce, true); } }); - -test('customlink: subscribe: clicked: unsubscribed -> subscribed. http. never subscribed.', async (t) => { - const subscriptionPromise = EventsTestHelper.getSubscriptionPromise(); - TestEnvironment.overrideEnvironmentInfo({ requiresUserInteraction: false }); - sandbox.stub(CustomLinkManager, 'isPushEnabled').returns(false); - const registerSpy = sandbox - .stub(OneSignal, 'registerForPushNotifications') - .callsFake(async () => { - await setSubscriptionStub(); - }); - sandbox.stub(OneSignalUtils, 'isUsingSubscriptionWorkaround').returns(true); - sandbox.stub(CustomLinkManager, 'isOptedOut').returns(false); - - await new CustomLinkManager(config).initialize(); - const subscribeElement = document.querySelector( - CUSTOM_LINK_CSS_SELECTORS.subscribeSelector, - ); - const explanationElement = document.querySelector( - CUSTOM_LINK_CSS_SELECTORS.explanationSelector, - ); - t.not(subscribeElement, null); - t.not(explanationElement, null); - - if (subscribeElement && explanationElement) { - simulateEventOfTypeOnElement('click', subscribeElement); - await subscriptionPromise; - - t.is(registerSpy.calledOnce, true); - t.is(registerSpy.getCall(0).args.length, 1); - t.is(registerSpy.getCall(0).args[0].autoAccept, true); - } -}); - -test('customlink: subscribe: clicked: unsubscribed -> subscribed. http. opted out.', async (t) => { - const subscriptionPromise = EventsTestHelper.getSubscriptionPromise(); - sandbox - .stub(PermissionManager.prototype, 'getReportedNotificationPermission') - .returns(false); - sandbox.stub(OneSignalUtils, 'isUsingSubscriptionWorkaround').returns(true); - sandbox.stub(CustomLinkManager, 'isPushEnabled').returns(false); - sandbox.stub(CustomLinkManager, 'isOptedOut').returns(true); - const subscriptionSpy = sandbox - .stub(NotificationsNamespace.prototype, 'disable') - .callsFake(async () => { - await setSubscriptionStub(); - }); - - await new CustomLinkManager(config).initialize(); - const subscribeElement = document.querySelector( - CUSTOM_LINK_CSS_SELECTORS.subscribeSelector, - ); - const explanationElement = document.querySelector( - CUSTOM_LINK_CSS_SELECTORS.explanationSelector, - ); - t.not(subscribeElement, null); - t.not(explanationElement, null); - - if (subscribeElement && explanationElement) { - simulateEventOfTypeOnElement('click', subscribeElement); - await subscriptionPromise; - - t.is(subscriptionSpy.calledOnce, true); - } -}); From 3c53766c7568bcb97149e5157ea2e3bbc1d7c3ad Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 22:08:44 +0000 Subject: [PATCH 04/35] rm isUsingSubscriptionWorkaround --- src/page/helpers/EnvironmentInfoHelper.ts | 1 - src/page/models/EnvironmentInfo.ts | 1 - src/shared/helpers/ConfigHelper.ts | 1 - src/shared/helpers/SubscriptionHelper.ts | 9 ---- .../managers/sessionManager/SessionManager.ts | 43 +++---------------- 5 files changed, 5 insertions(+), 50 deletions(-) diff --git a/src/page/helpers/EnvironmentInfoHelper.ts b/src/page/helpers/EnvironmentInfoHelper.ts index 5500f1367..e21a3d756 100644 --- a/src/page/helpers/EnvironmentInfoHelper.ts +++ b/src/page/helpers/EnvironmentInfoHelper.ts @@ -16,7 +16,6 @@ export class EnvironmentInfoHelper { browserType: this.getBrowser(), browserVersion: this.getBrowserVersion(), isHttps: this.isHttps(), - isUsingSubscriptionWorkaround: false, isBrowserAndSupportsServiceWorkers: this.supportsServiceWorkers(), requiresUserInteraction: this.requiresUserInteraction(), osVersion: this.getOsVersion(), diff --git a/src/page/models/EnvironmentInfo.ts b/src/page/models/EnvironmentInfo.ts index e01af2df4..8f2a3907f 100644 --- a/src/page/models/EnvironmentInfo.ts +++ b/src/page/models/EnvironmentInfo.ts @@ -5,7 +5,6 @@ export interface EnvironmentInfo { browserType: Browser; browserVersion: number; isHttps: boolean; - isUsingSubscriptionWorkaround: boolean; isBrowserAndSupportsServiceWorkers: boolean; requiresUserInteraction: boolean; osVersion: string | number; diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index bec11159a..ea25d26fa 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -251,7 +251,6 @@ export class ConfigHelper { * @param {AppUserConfigPromptOptions|undefined} promptOptions * @param {ServerAppPromptConfig} defaultsFromServer * @param {AppUserConfig} wholeUserConfig - * @param {boolean=false} isUsingSubscriptionWorkaround * @returns AppUserConfigPromptOptions */ public static injectDefaultsIntoPromptOptions( diff --git a/src/shared/helpers/SubscriptionHelper.ts b/src/shared/helpers/SubscriptionHelper.ts index f772a7ae4..ac1f70a49 100755 --- a/src/shared/helpers/SubscriptionHelper.ts +++ b/src/shared/helpers/SubscriptionHelper.ts @@ -162,11 +162,6 @@ export default class SubscriptionHelper { return RawPushSubscription.setFromW3cSubscription(swSubscription); } - static async getRawPushSubscriptionWhenUsingSubscriptionWorkaround(): Promise { - // we would need to message service worker to get it. we'll get it from inside if necessary - return null; - } - static async getRawPushSubscription( environmentInfo: EnvironmentInfo, safariWebId: string, @@ -177,10 +172,6 @@ export default class SubscriptionHelper { ); } - if (environmentInfo.isUsingSubscriptionWorkaround) { - return SubscriptionHelper.getRawPushSubscriptionWhenUsingSubscriptionWorkaround(); - } - if (environmentInfo.isBrowserAndSupportsServiceWorkers) { const registration = await OneSignal.context.serviceWorkerManager.getRegistration(); diff --git a/src/shared/managers/sessionManager/SessionManager.ts b/src/shared/managers/sessionManager/SessionManager.ts index 75fcc657b..be1780817 100644 --- a/src/shared/managers/sessionManager/SessionManager.ts +++ b/src/shared/managers/sessionManager/SessionManager.ts @@ -43,24 +43,12 @@ export class SessionManager implements ISessionManager { isSafari: OneSignalUtils.isSafari(), outcomesConfig: this.context.appConfig.userConfig.outcomes!, }; - if ( - this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers && - !this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { + if (this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers) { Log.debug('Notify SW to upsert session'); await this.context.workerMessenger.unicast( WorkerMessengerCommand.SessionUpsert, payload, ); - } else if ( - this.context.environmentInfo?.canTalkToServiceWorker && - this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { - Log.debug('Notify iframe to notify SW to upsert session'); - await OneSignal.proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.SESSION_UPSERT, - payload, - ); } else { // http w/o our iframe // we probably shouldn't even be here @@ -86,24 +74,12 @@ export class SessionManager implements ISessionManager { isSafari: OneSignalUtils.isSafari(), outcomesConfig: this.context.appConfig.userConfig.outcomes!, }; - if ( - this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers && - !this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { + if (this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers) { Log.debug('Notify SW to deactivate session'); await this.context.workerMessenger.unicast( WorkerMessengerCommand.SessionDeactivate, payload, ); - } else if ( - this.context.environmentInfo?.canTalkToServiceWorker && - this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { - Log.debug('Notify SW to deactivate session'); - await OneSignal.proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.SESSION_DEACTIVATE, - payload, - ); } else { // http w/o our iframe // we probably shouldn't even be here @@ -309,20 +285,14 @@ export class SessionManager implements ISessionManager { ); } - if ( - this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers || - this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { + if (this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers) { if (!this.context.environmentInfo?.canTalkToServiceWorker) { this.onSessionSent = sessionOrigin === SessionOrigin.PlayerCreate; OneSignal.emitter.emit(OneSignal.EVENTS.SESSION_STARTED); } else { this.setupSessionEventListeners(); } - } else if ( - !this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers && - !this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { + } else { this.onSessionSent = sessionOrigin === SessionOrigin.PlayerCreate; OneSignal.emitter.emit(OneSignal.EVENTS.SESSION_STARTED); } @@ -330,10 +300,7 @@ export class SessionManager implements ISessionManager { setupSessionEventListeners(): void { // Only want these events if it's using subscription workaround - if ( - !this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers && - !this.context.environmentInfo?.isUsingSubscriptionWorkaround - ) { + if (!this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers) { Log.debug( 'Not setting session event listeners. No service worker possible.', ); From ab3c9a17f2688b31f0f32c8cd7aeb68bfd4699a8 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 22:41:46 +0000 Subject: [PATCH 05/35] rm getIntegration, everything is secure now Remove SdkEnvironment.getIntegration() as the SDK only supports IntegrationKind.Secure now. If the developer attempted to init the SDK in a non-secure env then we would have thrown before this. --- src/shared/helpers/InitHelper.ts | 56 +------ src/shared/managers/SdkEnvironment.ts | 105 ------------- src/shared/managers/ServiceWorkerManager.ts | 39 ----- src/shared/managers/SubscriptionManager.ts | 67 +------- src/shared/models/IntegrationKind.ts | 16 -- test/unit/managers/SubscriptionManager.ts | 56 +------ test/unit/modules/sdkEnvironment.ts | 161 +------------------- 7 files changed, 14 insertions(+), 486 deletions(-) delete mode 100644 src/shared/models/IntegrationKind.ts diff --git a/src/shared/helpers/InitHelper.ts b/src/shared/helpers/InitHelper.ts index 9fe991855..b07fdf7e8 100755 --- a/src/shared/helpers/InitHelper.ts +++ b/src/shared/helpers/InitHelper.ts @@ -1,32 +1,24 @@ import { NotificationPermission } from '../models/NotificationPermission'; import SdkEnvironment from '../managers/SdkEnvironment'; import { AppConfig } from '../models/AppConfig'; -import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import MainHelper from './MainHelper'; import SubscriptionHelper from './SubscriptionHelper'; import { SdkInitError, SdkInitErrorKind } from '../errors/SdkInitError'; import { WorkerMessengerCommand } from '../libraries/WorkerMessenger'; import { SubscriptionStrategyKind } from '../models/SubscriptionStrategyKind'; -import { IntegrationKind } from '../models/IntegrationKind'; import { Subscription } from '../models/Subscription'; import Log from '../libraries/Log'; import { CustomLinkManager } from '../managers/CustomLinkManager'; import Bell from '../../page/bell/Bell'; -import { - DeprecatedApiError, - DeprecatedApiReason, -} from '../../page/errors/DeprecatedApiError'; import { ContextInterface } from '../../page/models/Context'; import SubscriptionModalHost from '../../page/modules/frames/SubscriptionModalHost'; import SubscriptionPopupHost from '../../page/modules/frames/SubscriptionPopupHost'; import { DynamicResourceLoader } from '../../page/services/DynamicResourceLoader'; import Database from '../services/Database'; import LimitStore from '../services/LimitStore'; -import OneSignalUtils from '../utils/OneSignalUtils'; import { once, triggerNotificationPermissionChanged } from '../utils/utils'; import Environment from './Environment'; import OneSignalEvent from '../services/OneSignalEvent'; -import ProxyFrameHost from '../../page/modules/frames/ProxyFrameHost'; import { bowserCastle } from '../utils/bowserCastle'; declare let OneSignal: any; @@ -250,51 +242,11 @@ export default class InitHelper { return false; } - const integrationKind = await SdkEnvironment.getIntegration(); - const windowEnv = SdkEnvironment.getWindowEnv(); - - Log.debug( - 'Subscription is considered expiring. Current Integration:', - integrationKind, + Log.debug('Subscription is considered expiring.'); + const rawPushSubscription = await context.subscriptionManager.subscribe( + SubscriptionStrategyKind.SubscribeNew, ); - switch (integrationKind) { - /* - Resubscribe via the service worker. - - For Secure, we can definitely resubscribe via the current page, but for SecureProxy, we - used to not be able to subscribe for push within secure child frames. The common supported - and safe way is to resubscribe via the service worker. - */ - case IntegrationKind.Secure: { - const rawPushSubscription = await context.subscriptionManager.subscribe( - SubscriptionStrategyKind.SubscribeNew, - ); - await context.subscriptionManager.registerSubscription( - rawPushSubscription, - ); - break; - } - case IntegrationKind.SecureProxy: - if (windowEnv === WindowEnvironmentKind.OneSignalProxyFrame) { - await this.registerSubscriptionInProxyFrame(context); - } else { - const proxyFrame: ProxyFrameHost = OneSignal.proxyFrameHost; - await proxyFrame.runCommand( - OneSignal.POSTMAM_COMMANDS.PROCESS_EXPIRING_SUBSCRIPTIONS, - ); - } - break; - case IntegrationKind.InsecureProxy: - /* - We can't really do anything here except remove a value checked by - isPushNotificationsEnabled to simulate unsubscribing. - */ - await Database.remove('Ids', 'registrationId'); - Log.debug( - 'Unsubscribed expiring HTTP subscription by removing registration ID.', - ); - break; - } + await context.subscriptionManager.registerSubscription(rawPushSubscription); return true; } diff --git a/src/shared/managers/SdkEnvironment.ts b/src/shared/managers/SdkEnvironment.ts index da0c0f5e4..14c9907b9 100644 --- a/src/shared/managers/SdkEnvironment.ts +++ b/src/shared/managers/SdkEnvironment.ts @@ -5,9 +5,7 @@ import { InvalidArgumentError, InvalidArgumentReason, } from '../errors/InvalidArgumentError'; -import { IntegrationKind } from '../models/IntegrationKind'; import Environment from '../helpers/Environment'; -import OneSignalUtils from '../utils/OneSignalUtils'; const RESOURCE_HTTP_PORT = 4000; const RESOURCE_HTTPS_PORT = 4001; @@ -61,109 +59,6 @@ export default class SdkEnvironment { } } - /** - * Determines whether the current frame context executing this function is part of a: - * - * a) HTTP site using a proxy subscription origin - * - * b) or, HTTPS site using a proxy subscription origin - * - * c) or, HTTPS site using its own origin for subscribing - * - * The determination affects permissions and subscription: - * - * a) Because the parent (top frame) of the proxy origin frame is HTTP, the entire context is - * insecure. In the proxy origin frame, notification permissions are always "denied", access to - * the service worker's registration throws a security error, and no service worker controls the - * proxy origin frame. - * - * b) The context is secure. In the proxy origin frame, notification permissions are "granted" if - * actually granted otherwise "denied" if either unprompted or blocked. The service worker - * controls the proxy origin frame and access to the service worker's registration is allowed. - * Requesting permissions from child frames is not allowed. Subscribing from child frames wasn't - * allowed but is now allowed. - * - * c) All features are allowed. - * - * @param usingProxyOrigin Using a subdomain of os.tc or onesignal.com for subscribing to push. - */ - public static async getIntegration( - usingProxyOrigin?: boolean, - ): Promise { - if (Environment.useSafariLegacyPush()) { - /* Safari Legacy works on HTTP sites */ - return IntegrationKind.Secure; - } - - const isTopFrame = window === window.top; - const isHttpsProtocol = window.location.protocol === 'https:'; - - // For convenience, try to look up usingProxyOrigin instead of requiring it to be passed in - if (usingProxyOrigin === undefined) { - if ( - typeof OneSignal !== 'undefined' && - OneSignal.context && - OneSignal.context.appConfig - ) { - usingProxyOrigin = !!OneSignal.context.appConfig.subdomain; - } else { - throw new InvalidArgumentError( - 'usingProxyOrigin', - InvalidArgumentReason.Empty, - ); - } - } - - /* - Executing from the top frame, we can easily determine whether we're HTTPS or HTTP. - - Executing from a child frame of any depth, we can check the current frame's protocol. If it's - HTTP it's definitely insecure. If it's HTTPS, we attempt to call - ServiceWorkerContainer.getRegistration and see if the call throws an error or succeeds. If the - call throws an error, we can assume some parent frame in the chain above us is insecure. - */ - if (isTopFrame) { - if (isHttpsProtocol) { - return usingProxyOrigin - ? IntegrationKind.SecureProxy - : IntegrationKind.Secure; - } else { - // If localhost and allowLocalhostAsSecureOrigin, it's still considered secure - if ( - OneSignalUtils.isLocalhostAllowedAsSecureOrigin() && - (location.hostname === 'localhost' || - location.hostname === '127.0.0.1') - ) { - return IntegrationKind.Secure; - } - - /* The case of HTTP and not using a proxy origin isn't possible, because the SDK will throw - an initialization error stating a proxy origin is required for HTTP sites. */ - return IntegrationKind.InsecureProxy; - } - } else { - if (isHttpsProtocol) { - /* Check whether any parent frames are insecure */ - const isFrameContextInsecure = - await SdkEnvironment.isFrameContextInsecure(); - if (isFrameContextInsecure) { - return IntegrationKind.InsecureProxy; - } else { - return usingProxyOrigin - ? IntegrationKind.SecureProxy - : IntegrationKind.Secure; - } - } else { - /* - Because this frame is insecure, the entire chain is insecure. - - The case of HTTP and not using a proxy origin isn't possible, because the SDK will throw an - initialization error stating a proxy origin is required for HTTP sites. */ - return IntegrationKind.InsecureProxy; - } - } - } - /** * From a child frame, returns true if the current frame context is insecure. * diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index e5196b27e..2cd732b75 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -3,10 +3,7 @@ import { WorkerMessengerCommand } from '../libraries/WorkerMessenger'; import Path from '../models/Path'; import SdkEnvironment from './SdkEnvironment'; import Database from '../services/Database'; -import { IntegrationKind } from '../models/IntegrationKind'; import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; -import NotImplementedError from '../errors/NotImplementedError'; -import ProxyFrameHost from '../../page/modules/frames/ProxyFrameHost'; import Log from '../libraries/Log'; import OneSignalEvent from '../services/OneSignalEvent'; import ProxyFrame from '../../page/modules/frames/ProxyFrame'; @@ -49,42 +46,6 @@ export class ServiceWorkerManager { } public async getActiveState(): Promise { - /* - Note: This method can only be called on a secure origin. On an insecure - origin, it'll throw on getRegistration(). - */ - - const integration = await SdkEnvironment.getIntegration(); - if (integration === IntegrationKind.InsecureProxy) { - /* Service workers are not accessible on insecure origins */ - return ServiceWorkerActiveState.Indeterminate; - } else if (integration === IntegrationKind.SecureProxy) { - /* If the site setup is secure proxy, we're either on the top frame without access to the - registration, or the child proxy frame that does have access to the registration. */ - const env = SdkEnvironment.getWindowEnv(); - switch (env) { - case WindowEnvironmentKind.Host: - case WindowEnvironmentKind.CustomIframe: { - /* Both these top-ish frames will need to ask the proxy frame to access the service worker - registration */ - const proxyFrameHost: ProxyFrameHost = OneSignal.proxyFrameHost; - if (!proxyFrameHost) { - /* On init, this function may be called. Return a null state for now */ - return ServiceWorkerActiveState.Indeterminate; - } else { - return await proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.SERVICE_WORKER_STATE, - ); - } - } - case WindowEnvironmentKind.OneSignalSubscriptionPopup: - /* This is a top-level frame, so it can access the service worker registration */ - break; - case WindowEnvironmentKind.OneSignalSubscriptionModal: - throw new NotImplementedError(); - } - } - const workerRegistration = await this.context.serviceWorkerManager.getRegistration(); if (!workerRegistration) { diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index 1212c29a2..0bd6a6cf3 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -3,15 +3,12 @@ import Environment from '../helpers/Environment'; import OneSignalEvent from '../services/OneSignalEvent'; import { ServiceWorkerActiveState } from '../helpers/ServiceWorkerHelper'; import SdkEnvironment from './SdkEnvironment'; - -import ProxyFrameHost from '../../page/modules/frames/ProxyFrameHost'; import { NotificationPermission } from '../models/NotificationPermission'; import { SubscriptionStateKind } from '../models/SubscriptionStateKind'; import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import { Subscription } from '../models/Subscription'; import { UnsubscriptionStrategy } from '../models/UnsubscriptionStrategy'; import { SubscriptionStrategyKind } from '../models/SubscriptionStrategyKind'; -import { IntegrationKind } from '../models/IntegrationKind'; import { PermissionUtils } from '../utils/PermissionUtils'; import { base64ToUint8Array } from '../utils/Encoding'; @@ -773,40 +770,7 @@ export class SubscriptionManager { } public async isSubscriptionExpiring(): Promise { - const integrationKind = await SdkEnvironment.getIntegration(); - const windowEnv = SdkEnvironment.getWindowEnv(); - - switch (integrationKind) { - case IntegrationKind.Secure: - return await this.isSubscriptionExpiringForSecureIntegration(); - case IntegrationKind.SecureProxy: - if (windowEnv === WindowEnvironmentKind.Host) { - const proxyFrameHost: ProxyFrameHost = OneSignal.proxyFrameHost; - if (!proxyFrameHost) { - throw new InvalidStateError(InvalidStateReason.NoProxyFrame); - } else { - return await proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.SUBSCRIPTION_EXPIRATION_STATE, - ); - } - } else { - return await this.isSubscriptionExpiringForSecureIntegration(); - } - case IntegrationKind.InsecureProxy: { - /* If we're in an insecure frame context, check the stored expiration since we can't access - the actual push subscription. */ - const { expirationTime } = await Database.getSubscription(); - if (!expirationTime) { - /* If an existing subscription does not have a stored expiration time, do not - treat it as expired. The subscription may have been created before this feature was added, - or the browser may not assign any expiration time. */ - return false; - } - - /* The current time (in UTC) is past the expiration time (also in UTC) */ - return new Date().getTime() >= expirationTime; - } - } + return await this.isSubscriptionExpiringForSecureIntegration(); } private async isSubscriptionExpiringForSecureIntegration(): Promise { @@ -878,34 +842,7 @@ export class SubscriptionManager { } default: { /* Regular browser window environments */ - const integration = await SdkEnvironment.getIntegration(); - - switch (integration) { - case IntegrationKind.Secure: - return this.getSubscriptionStateForSecure(); - case IntegrationKind.SecureProxy: - switch (windowEnv) { - case WindowEnvironmentKind.OneSignalProxyFrame: - case WindowEnvironmentKind.OneSignalSubscriptionPopup: - case WindowEnvironmentKind.OneSignalSubscriptionModal: - return this.getSubscriptionStateForSecure(); - default: { - /* Re-run this command in the proxy frame */ - const proxyFrameHost: ProxyFrameHost = OneSignal.proxyFrameHost; - const pushSubscriptionState = - await proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.GET_SUBSCRIPTION_STATE, - ); - return pushSubscriptionState; - } - } - case IntegrationKind.InsecureProxy: - return await this.getSubscriptionStateForInsecure(); - default: - throw new InvalidStateError( - InvalidStateReason.UnsupportedEnvironment, - ); - } + return this.getSubscriptionStateForSecure(); } } } diff --git a/src/shared/models/IntegrationKind.ts b/src/shared/models/IntegrationKind.ts deleted file mode 100644 index 773820a41..000000000 --- a/src/shared/models/IntegrationKind.ts +++ /dev/null @@ -1,16 +0,0 @@ -export enum IntegrationKind { - /** - * An secure HTTPS site using its own origin for subscribing. - */ - Secure = 'Secure', - /** - * A secure HTTPS site using a proxy subscription origin (e.g. subdomain.os.tc or - * subdomain.onesignal.com). - */ - SecureProxy = 'Secure Proxy', - /** - * An insecure HTTP site using a proxy subscription origin (e.g. subdomain.os.tc or - * subdomain.onesignal.com). - */ - InsecureProxy = 'Insecure Proxy', -} diff --git a/test/unit/managers/SubscriptionManager.ts b/test/unit/managers/SubscriptionManager.ts index 0deb51ccc..1535691c4 100644 --- a/test/unit/managers/SubscriptionManager.ts +++ b/test/unit/managers/SubscriptionManager.ts @@ -24,7 +24,6 @@ import { import Random from '../../support/tester/Random'; import { setBrowser } from '../../support/tester/browser'; import { SubscriptionStrategyKind } from '../../../src/shared/models/SubscriptionStrategyKind'; -import { IntegrationKind } from '../../../src/shared/models/IntegrationKind'; import { SubscriptionStateKind } from '../../../src/shared/models/SubscriptionStateKind'; import { WindowEnvironmentKind } from '../../../src/shared/models/WindowEnvironmentKind'; import SdkEnvironment from '../../../src/shared/managers/SdkEnvironment'; @@ -463,9 +462,6 @@ test('safari 11.1+ with service worker but not pushManager', async (t) => { }; await TestEnvironment.mockInternalOneSignal(); - sandbox - .stub(SdkEnvironment, 'getIntegration') - .returns(IntegrationKind.Secure); sandbox .stub(SdkEnvironment, 'getWindowEnv') .returns(WindowEnvironmentKind.ServiceWorker); @@ -600,7 +596,6 @@ async function expirationTestCase( subscriptionExpirationTime: number, expirationCheckTime: number, skipCreationDateSet: boolean, - env: IntegrationKind, ) { const initialVapidKeys = generateVapidKeys(); @@ -608,9 +603,6 @@ async function expirationTestCase( const stub = sandbox .stub(ServiceWorkerManager.prototype, 'getActiveState') .resolves(ServiceWorkerActiveState.OneSignalWorker); - const integrationStub = sandbox - .stub(SdkEnvironment, 'getIntegration') - .resolves(env); // Set the initial datetime, which is used internally for the subscription created at timemachine.config({ @@ -645,29 +637,14 @@ async function expirationTestCase( const isExpiring = await subscriptionManager.isSubscriptionExpiring(); if (subscriptionExpirationTime) { - if ( - env === IntegrationKind.Secure || - env === IntegrationKind.SecureProxy - ) { - // Checks in an HTTPS environment expire at the midpoint because we can silently - // resubscribe (HTTPS top frame silently resubscribe, HTTPS in child frame send message to - // SW to resubscribe) - const midpointExpirationTime = - subscriptionCreationTime + - (subscriptionExpirationTime - subscriptionCreationTime) / 2; - if (expirationCheckTime >= midpointExpirationTime) { - t.true(isExpiring); - } else { - t.false(isExpiring); - } + // Checks expire at the midpoint because we can silently resubscribe + const midpointExpirationTime = + subscriptionCreationTime + + (subscriptionExpirationTime - subscriptionCreationTime) / 2; + if (expirationCheckTime >= midpointExpirationTime) { + t.true(isExpiring); } else { - // Checks in an HTTP environment only expire at or after the expiration time, since we - // can't silently resubscribe - if (expirationCheckTime >= subscriptionExpirationTime) { - t.true(isExpiring); - } else { - t.false(isExpiring); - } + t.false(isExpiring); } } else { return t.false(isExpiring); @@ -694,7 +671,6 @@ test('a subscription expiring in 30 days is not refreshed before the midpoint', subscriptionExpirationTime, newTimeBeforeMidpoint, false, - IntegrationKind.Secure, ); }); @@ -711,7 +687,6 @@ test('a subscription expiring in 30 days is refreshed at the midpoint', async (t subscriptionExpirationTime, newTimeAfterMidpoint, false, - IntegrationKind.Secure, ); }); @@ -729,7 +704,6 @@ test('a subscription expiring in 30 days is refreshed after the midpoint', async subscriptionExpirationTime, newTimeAfterMidpoint, false, - IntegrationKind.Secure, ); }); @@ -745,7 +719,6 @@ test('a subscription without a recorded creation date is always considered expir subscriptionExpirationTime, subscriptionCreationTime, true, - IntegrationKind.Secure, ); }); @@ -760,7 +733,6 @@ test('a subscription without an expiration time is never considered expired', as null, subscriptionCreationTime, false, - IntegrationKind.Secure, ); }); @@ -787,20 +759,6 @@ test('the subscription expiration time should be recorded', async (t) => { ); }); -test('for HTTP, a subscription expiring in 30 days only expires after 30 days and not before', async (t) => { - const THIRTY_DAYS_MS = 1000 * 60 * 60 * 24 * 30; - const subscriptionCreationTime = 1; - - await expirationTestCase( - t, - subscriptionCreationTime, - subscriptionCreationTime + THIRTY_DAYS_MS, - subscriptionCreationTime + THIRTY_DAYS_MS - 10, - false, - IntegrationKind.InsecureProxy, - ); -}); - test("Service worker failed to install due to 403. Send a notification for the first user's session.", async (t) => { const context: Context = OneSignal.context; const serviceWorkerManager = context.serviceWorkerManager; diff --git a/test/unit/modules/sdkEnvironment.ts b/test/unit/modules/sdkEnvironment.ts index 0a35cc0cd..36d6dbcf4 100644 --- a/test/unit/modules/sdkEnvironment.ts +++ b/test/unit/modules/sdkEnvironment.ts @@ -1,14 +1,10 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; import sinon from 'sinon'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import SdkEnvironment from '../../../src/shared/managers/SdkEnvironment'; import { WindowEnvironmentKind } from '../../../src/shared/models/WindowEnvironmentKind'; import { EnvironmentKind } from '../../../src/shared/models/EnvironmentKind'; -import { IntegrationKind } from '../../../src/shared/models/IntegrationKind'; test('should get service worker window environment', async (t) => { await TestEnvironment.stubServiceWorkerEnvironment(); @@ -112,158 +108,3 @@ test('API URL should be valid for production environment', async (t) => { 'https://onesignal.com/api/v1', ); }); - -function mockParentFrame(https: boolean): sinon.SinonStub { - let stub: sinon.SinonStub; - if (https) { - stub = sinon.stub(navigator.serviceWorker, 'getRegistration').resolves({}); - } else { - // HTTP sites can't use ServiceWorkerContainer.getRegistration() - stub = sinon - .stub(navigator.serviceWorker, 'getRegistration') - .throws('SecurityError'); - } - return stub; -} - -function restoreParentFrameMock(stub: sinon.SinonStub) { - if (stub) { - stub.restore(); - } -} - -test('getIntegration should return Secure in HTTPS top-level frame', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'https://site.com'); - t.is(await SdkEnvironment.getIntegration(false), IntegrationKind.Secure); -}); - -test('getIntegration should return Secure in HTTPS child frame under top-level HTTPS frame', async (t) => { - const OneSignal: any = await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: 'another frame' as any }); - browser.changeURL(window, 'https://site.com'); - const stub = mockParentFrame(true); - t.is(await SdkEnvironment.getIntegration(false), IntegrationKind.Secure); - restoreParentFrameMock(stub); -}); - -test('getIntegration should return SecureProxy in HTTPS top-level frame using proxy origin', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'https://site.com'); - t.is(await SdkEnvironment.getIntegration(true), IntegrationKind.SecureProxy); -}); - -test('getIntegration should return SecureProxy in HTTPS child frame using proxy origin under top-level HTTPS frame', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: 'another frame' as any }); - browser.changeURL(window, 'https://site.com'); - const stub = mockParentFrame(true); - t.is(await SdkEnvironment.getIntegration(true), IntegrationKind.SecureProxy); - restoreParentFrameMock(stub); -}); - -test('getIntegration should return InsecureProxy in HTTP top-level frame using proxy origin', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'http://site.com'); - t.is( - await SdkEnvironment.getIntegration(true), - IntegrationKind.InsecureProxy, - ); -}); - -test('getIntegration should return InsecureProxy in HTTP top-level frame not using proxy origin', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'http://site.com'); - t.is( - await SdkEnvironment.getIntegration(false), - IntegrationKind.InsecureProxy, - ); -}); - -test('getIntegration should return InsecureProxy in HTTPS child frame under top-level HTTP frame', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: 'another frame' as any }); - browser.changeURL(window, 'https://site.com'); - const stub = mockParentFrame(false); - t.is( - await SdkEnvironment.getIntegration(true), - IntegrationKind.InsecureProxy, - ); - restoreParentFrameMock(stub); -}); - -test('getIntegration should return InsecureProxy in HTTP top-level frame for not localhost and allowLocalhostAsSecureOrigin = true', async (t) => { - const OneSignal: any = await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'http://site.com'); - OneSignal.config.userConfig.allowLocalhostAsSecureOrigin = true; - t.is( - await SdkEnvironment.getIntegration(true), - IntegrationKind.InsecureProxy, - ); -}); - -test('getIntegration should return InsecureProxy in HTTP top-level frame for 127.0.0.1 and allowLocalhostAsSecureOrigin not present', async (t) => { - const OneSignal: any = await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'http://127.0.0.1'); - OneSignal.config.userConfig.allowLocalhostAsSecureOrigin = undefined; - t.is( - await SdkEnvironment.getIntegration(true), - IntegrationKind.InsecureProxy, - ); -}); - -test('getIntegration should return Secure in HTTP top-level frame for 127.0.0.1 and allowLocalhostAsSecureOrigin = true', async (t) => { - const OneSignal: any = await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: window }); - browser.changeURL(window, 'http://127.0.0.1'); - OneSignal.config.userConfig.allowLocalhostAsSecureOrigin = true; - t.is(await SdkEnvironment.getIntegration(true), IntegrationKind.Secure); -}); - -test('getIntegration should return InsecureProxy in HTTP top-level frame for localhost and allowLocalhostAsSecureOrigin not present', async (t) => { - const OneSignal: any = await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - OneSignal.config.userConfig.allowLocalhostAsSecureOrigin = undefined; - t.is( - await SdkEnvironment.getIntegration(true), - IntegrationKind.InsecureProxy, - ); -}); - -test('getIntegration should return Secure in HTTP top-level frame for localhost and allowLocalhostAsSecureOrigin = true', async (t) => { - const OneSignal: any = await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - TestEnvironment.mockInternalOneSignal(); - OneSignal.config.userConfig.allowLocalhostAsSecureOrigin = true; - t.is(await SdkEnvironment.getIntegration(true), IntegrationKind.Secure); -}); From 42848b9987c9c9d12b0b6e5ba7a64a2e73b2b809 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 22:50:53 +0000 Subject: [PATCH 06/35] rm AltOriginManager Remove AltOriginManager as it was only used to manage proxy iframes to os.tc. --- src/onesignal/OneSignal.ts | 1 - src/page/managers/AltOriginManager.ts | 158 ------------- test/support/tester/utils.ts | 26 --- test/unit/managers/AltOriginManager.ts | 312 ------------------------- 4 files changed, 497 deletions(-) delete mode 100644 src/page/managers/AltOriginManager.ts delete mode 100644 test/unit/managers/AltOriginManager.ts diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index a38d71281..1a3961532 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -1,5 +1,4 @@ import { EnvironmentInfoHelper } from '../page/helpers/EnvironmentInfoHelper'; -import AltOriginManager from '../page/managers/AltOriginManager'; import ConfigManager from '../page/managers/ConfigManager'; import LegacyManager from '../page/managers/LegacyManager'; import Context from '../page/models/Context'; diff --git a/src/page/managers/AltOriginManager.ts b/src/page/managers/AltOriginManager.ts deleted file mode 100644 index bc879826e..000000000 --- a/src/page/managers/AltOriginManager.ts +++ /dev/null @@ -1,158 +0,0 @@ -import ProxyFrameHost from '../modules/frames/ProxyFrameHost'; -import SdkEnvironment from '../../shared/managers/SdkEnvironment'; -import { Utils } from '../../shared/context/Utils'; -import { AppConfig } from '../../shared/models/AppConfig'; -import { EnvironmentKind } from '../../shared/models/EnvironmentKind'; - -export default class AltOriginManager { - /* - * This loads all possible iframes that a site could be subscribed to - * (os.tc & onesignal.com) then checks to see we are subscribed to any. - * If we find what we are subscribed to both unsubscribe from onesignal.com. - * This method prefers os.tc over onesignal.com where possible. - */ - static async discoverAltOrigin( - appConfig: AppConfig, - ): Promise { - const iframeUrls = AltOriginManager.getOneSignalProxyIframeUrls(appConfig); - - const allProxyFrameHosts: ProxyFrameHost[] = []; - for (const iframeUrl of iframeUrls) { - const proxyFrameHost = new ProxyFrameHost(iframeUrl); - // A TimeoutError could happen here; it gets rejected out of this entire loop - await proxyFrameHost.load(); - allProxyFrameHosts.push(proxyFrameHost); - } - - const subscribedProxyFrameHosts = - await AltOriginManager.subscribedProxyFrameHosts(allProxyFrameHosts); - await AltOriginManager.removeDuplicatedAltOriginSubscription( - subscribedProxyFrameHosts, - ); - - let preferredProxyFrameHost: ProxyFrameHost; - if (subscribedProxyFrameHosts.length === 0) { - // Use the first (preferred) host (os.tc in this case) if not subscribed to any - preferredProxyFrameHost = allProxyFrameHosts[0]; - } else { - // Otherwise if their was one or more use the highest preferred one in the list - preferredProxyFrameHost = subscribedProxyFrameHosts[0]; - } - - // Remove all other unneeded iframes from the page - for (const proxyFrameHost of allProxyFrameHosts) { - if (preferredProxyFrameHost !== proxyFrameHost) { - proxyFrameHost.dispose(); - } - } - - return preferredProxyFrameHost; - } - - static async subscribedProxyFrameHosts( - proxyFrameHosts: ProxyFrameHost[], - ): Promise { - const subscribed: ProxyFrameHost[] = []; - for (const proxyFrameHost of proxyFrameHosts) { - if (await proxyFrameHost.isSubscribed()) { - subscribed.push(proxyFrameHost); - } - } - return subscribed; - } - - /* - * If the user is subscribed to more than OneSignal subdomain (AKA HTTP setup) - * unsubscribe them from ones lower in the list. - * Example: Such as being being subscribed to mysite.os.tc & mysite.onesignal.com - */ - static async removeDuplicatedAltOriginSubscription( - subscribedProxyFrameHosts: ProxyFrameHost[], - ): Promise { - // Not subscribed or subscribed to just one domain, nothing to do, no duplicates - if (subscribedProxyFrameHosts.length < 2) { - return; - } - - // At this point we have 2+ subscriptions - // Keep only the first (highest priority) domain and unsubscribe the rest. - const toUnsubscribeProxyFrameHosts = subscribedProxyFrameHosts.slice(1); - for (const dupSubscribedHost of toUnsubscribeProxyFrameHosts) { - await dupSubscribedHost.unsubscribeFromPush(); - } - } - - /** - * Only used for sites using a OneSignal subdomain (AKA HTTP setup). - * - * Returns the array of possible URL in which the push subscription and - * IndexedDb site data will be stored. - * - * This URL was typically subdomain.onesignal.com, until we switched - * to subdomain.os.tc for a shorter origin to fit into Mac's native - * notifications on Chrome 59+. - * - * Because a user may be subscribed to subdomain.onesignal.com or - * subdomain.os.tc, we have to load both in certain scenarios to determine - * which the user is subscribed to; hence, this method returns an array of - * possible URLs. - * - * Order of URL is in priority order of one should be used. - */ - static getCanonicalSubscriptionUrls( - config: AppConfig, - buildEnv: EnvironmentKind = SdkEnvironment.getApiEnv(), - ): Array { - const subscriptionDomain = - AltOriginManager.getWildcardLegacySubscriptionDomain(buildEnv); - const legacyDomainUrl = new URL( - `https://${config.subdomain}.${subscriptionDomain}`, - ); - - // Staging and Dev don't support going through the os.tc domain - if (buildEnv !== EnvironmentKind.Production) { - return [legacyDomainUrl]; - } - - // Use os.tc as a first pick - const urls = [new URL(`https://${config.subdomain}.os.tc`)]; - - if (config.httpUseOneSignalCom) { - urls.push(legacyDomainUrl); - } - - return urls; - } - - /** - * Get the wildcard part of the legacy subscription domain. - * Examples: onesignal.com, staging.onesignal.com, or localhost - */ - static getWildcardLegacySubscriptionDomain( - buildEnv: EnvironmentKind, - ): string { - const apiUrl = SdkEnvironment.getOneSignalApiUrl(buildEnv); - - // Prod and Dev support domains like *.onesignal.com and *.localhost - let envSubdomainParts = 2; - if (buildEnv === EnvironmentKind.Staging) { - // Allow up to 3 parts so *.staging.onesignal.com works. - envSubdomainParts = 3; - } - - return Utils.lastParts(apiUrl.host, '.', envSubdomainParts); - } - - /** - * Returns the URL of the OneSignal proxy iFrame helper. - */ - static getOneSignalProxyIframeUrls(config: AppConfig): Array { - const urls = AltOriginManager.getCanonicalSubscriptionUrls(config); - - for (const url of urls) { - url.pathname = 'webPushIframe'; - } - - return urls; - } -} diff --git a/test/support/tester/utils.ts b/test/support/tester/utils.ts index effbd60e3..f5c16c63d 100644 --- a/test/support/tester/utils.ts +++ b/test/support/tester/utils.ts @@ -1,7 +1,5 @@ import { SinonSandbox } from 'sinon'; import nock from 'nock'; -import ProxyFrameHost from '../../../src/page/modules/frames/ProxyFrameHost'; -import AltOriginManager from '../../../src/page/managers/AltOriginManager'; import OneSignalApi from '../../../src/shared/api/OneSignalApi'; import { TestEnvironment, @@ -32,30 +30,6 @@ export function stubMessageChannel( (global as any).MessageChannel = fakeClass; } -// Mocks out any messages going to the *.os.tc iframe. -export function mockIframeMessaging(sinonSandbox: SinonSandbox) { - sinonSandbox.stub(ProxyFrameHost.prototype, 'load').resolves(undefined); - sinonSandbox - .stub(AltOriginManager, 'removeDuplicatedAltOriginSubscription') - .resolves(undefined); - sinonSandbox - .stub(ProxyFrameHost.prototype, 'isSubscribed') - .callsFake(() => {}); - sinonSandbox.stub(ProxyFrameHost.prototype, 'runCommand').resolves(undefined); - - const mockIframeMessageReceiver = function ( - _msg: string, - _data: object, - resolve: Function, - ) { - // OneSignal.POSTMAM_COMMANDS.REMOTE_NOTIFICATION_PERMISSION - resolve(true); - }; - sinonSandbox - .stub(ProxyFrameHost.prototype, 'message') - .callsFake(mockIframeMessageReceiver); -} - export function mockGetIcon() { nock('https://onesignal.com') .get(/.*icon$/) diff --git a/test/unit/managers/AltOriginManager.ts b/test/unit/managers/AltOriginManager.ts deleted file mode 100644 index f6849d853..000000000 --- a/test/unit/managers/AltOriginManager.ts +++ /dev/null @@ -1,312 +0,0 @@ -import '../../support/polyfills/polyfills'; -import test, { TestInterface } from 'ava'; -import AltOriginManager from '../../../src/page/managers/AltOriginManager'; -import sinon from 'sinon'; -import ProxyFrameHost from '../../../src/page/modules/frames/ProxyFrameHost'; -import { TestEnvironment } from '../../support/sdk/TestEnvironment'; -import { AppConfig } from '../../../src/shared/models/AppConfig'; -import { EnvironmentKind } from '../../../src/shared/models/EnvironmentKind'; - -interface AltOriginContext { - appConfig?: AppConfig; - subdomainOneSignalHost?: string; - subdomainOsTcHost?: string; - stubIsSubscribedToOneSignalImpl: () => boolean; - stubIsSubscribedToOsTcImpl: () => boolean; - stubIsSubscribedToNoneImpl: () => boolean; - stubIsSubscribedToBothImpl: () => boolean; -} - -const testWithAltOriginContext = test as TestInterface; - -testWithAltOriginContext( - `should get correct canonical subscription URL for development environment`, - async (t) => { - const config = TestEnvironment.getFakeAppConfig(); - config.subdomain = 'test'; - config.httpUseOneSignalCom = true; - - const devUrlsOsTcDomain = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Development, - ); - t.is(devUrlsOsTcDomain.length, 1); - t.is( - devUrlsOsTcDomain[0].host, - new URL('https://test.localhost:3001').host, - ); - - config.httpUseOneSignalCom = false; - - const devUrls = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Development, - ); - t.is(devUrls.length, 1); - t.is(devUrls[0].host, new URL('https://test.localhost:3001').host); - }, -); - -testWithAltOriginContext( - `should get correct canonical subscription URL for staging environment`, - async (t) => { - const stagingDomain = 'staging.onesignal.com'; - (global).__API_ORIGIN__ = stagingDomain; - const config = TestEnvironment.getFakeAppConfig(); - config.subdomain = 'test'; - config.httpUseOneSignalCom = true; - - const browser = await TestEnvironment.stubDomEnvironment(); - browser.changeURL(window, `http://${stagingDomain}`); - - const stagingUrlsOsTcDomain = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Staging, - ); - t.is(stagingUrlsOsTcDomain.length, 1); - t.is( - stagingUrlsOsTcDomain[0].host, - new URL(`https://test.${stagingDomain}`).host, - ); - - // staging does not support an alt domain so it should be the same. - config.httpUseOneSignalCom = false; - const stagingUrls = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Staging, - ); - t.is(stagingUrls.length, 1); - t.is(stagingUrls[0].host, new URL(`https://test.${stagingDomain}`).host); - }, -); - -testWithAltOriginContext( - `should get correct canonical subscription URL when api.staging.onesignal.com is used`, - async (t) => { - const stagingDomain = 'staging.onesignal.com'; - (global).__API_ORIGIN__ = `api.${stagingDomain}`; - const config = TestEnvironment.getFakeAppConfig(); - config.subdomain = 'test'; - config.httpUseOneSignalCom = true; - - const browser = await TestEnvironment.stubDomEnvironment(); - browser.changeURL(window, `http://${stagingDomain}`); - - const stagingUrlsOsTcDomain = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Staging, - ); - t.is(stagingUrlsOsTcDomain.length, 1); - t.is( - stagingUrlsOsTcDomain[0].host, - new URL(`https://test.${stagingDomain}`).host, - ); - }, -); - -testWithAltOriginContext( - `should get correct canonical subscription URL for production environment`, - async (t) => { - const config = TestEnvironment.getFakeAppConfig(); - config.subdomain = 'test'; - config.httpUseOneSignalCom = true; - - const prodUrlsOsTcDomain = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Production, - ); - t.is(prodUrlsOsTcDomain.length, 2); - t.is(prodUrlsOsTcDomain[0].host, new URL('https://test.os.tc').host); - t.is( - prodUrlsOsTcDomain[1].host, - new URL('https://test.onesignal.com').host, - ); - - config.httpUseOneSignalCom = false; - - const prodUrls = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Production, - ); - t.is(prodUrls.length, 1); - t.is(prodUrls[0].host, new URL('https://test.os.tc').host); - }, -); - -testWithAltOriginContext( - `should get correct canonical subscription URL for production environment with api. prefix`, - async (t) => { - (global).__API_ORIGIN__ = `api.onesignal.com`; - const config = TestEnvironment.getFakeAppConfig(); - config.subdomain = 'test'; - config.httpUseOneSignalCom = true; - - const prodUrlsOsTcDomain = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Production, - ); - t.is(prodUrlsOsTcDomain.length, 2); - t.is(prodUrlsOsTcDomain[0].host, new URL('https://test.os.tc').host); - t.is( - prodUrlsOsTcDomain[1].host, - new URL('https://test.onesignal.com').host, - ); - - config.httpUseOneSignalCom = false; - - const prodUrls = AltOriginManager.getCanonicalSubscriptionUrls( - config, - EnvironmentKind.Production, - ); - t.is(prodUrls.length, 1); - t.is(prodUrls[0].host, new URL('https://test.os.tc').host); - }, -); - -function setupDiscoverAltOriginTest(t: any) { - const appConfig = TestEnvironment.getFakeAppConfig(); - appConfig.subdomain = 'test'; - appConfig.httpUseOneSignalCom = true; - - t.context.appConfig = appConfig; - t.context.subdomainOneSignalHost = `${appConfig.subdomain}.onesignal.com`; - t.context.subdomainOsTcHost = `${appConfig.subdomain}.os.tc`; - - t.context.stubIsSubscribedToOneSignalImpl = async function () { - if (this.url.host === t.context.subdomainOneSignalHost) { - return true; - } else return false; - }; - - t.context.stubIsSubscribedToOsTcImpl = async function () { - if (this.url.host === t.context.subdomainOsTcHost) { - return true; - } else return false; - }; - - t.context.stubIsSubscribedToNoneImpl = async function () { - return false; - }; - - t.context.stubIsSubscribedToBothImpl = async function () { - if ( - this.url.host === t.context.subdomainOneSignalHost || - this.url.host === t.context.subdomainOsTcHost - ) { - return true; - } else return false; - }; -} - -testWithAltOriginContext( - `should discover alt origin to be subdomain.onesignal.com if user is already subscribed there`, - async (t) => { - setupDiscoverAltOriginTest(t); - const { appConfig } = t.context; - if (!appConfig) { - return; - } - - const stubLoad = sinon - .stub(ProxyFrameHost.prototype, 'load') - .resolves(undefined); - const stubIsSubscribed = sinon - .stub(ProxyFrameHost.prototype, 'isSubscribed') - .callsFake(t.context.stubIsSubscribedToOneSignalImpl); - const stubRemoveDuplicatedAltOriginSubscription = sinon - .stub(AltOriginManager, 'removeDuplicatedAltOriginSubscription') - .resolves(undefined); - - const proxyFrame = await AltOriginManager.discoverAltOrigin(appConfig); - t.is(proxyFrame.url.host, t.context.subdomainOneSignalHost); - - stubRemoveDuplicatedAltOriginSubscription.restore(); - stubIsSubscribed.restore(); - stubLoad.restore(); - }, -); - -testWithAltOriginContext( - `should discover alt origin to be subdomain.os.tc if user is not subscribed to onesignal.com but is subscribed to os.tc`, - async (t) => { - setupDiscoverAltOriginTest(t); - const { appConfig } = t.context; - if (!appConfig) { - return; - } - - const stubLoad = sinon - .stub(ProxyFrameHost.prototype, 'load') - .resolves(undefined); - const stubIsSubscribed = sinon - .stub(ProxyFrameHost.prototype, 'isSubscribed') - .callsFake(t.context.stubIsSubscribedToOsTcImpl); - const stubRemoveDuplicatedAltOriginSubscription = sinon - .stub(AltOriginManager, 'removeDuplicatedAltOriginSubscription') - .resolves(undefined); - - const proxyFrame = await AltOriginManager.discoverAltOrigin(appConfig); - t.is(proxyFrame.url.host, t.context.subdomainOsTcHost); - - stubRemoveDuplicatedAltOriginSubscription.restore(); - stubIsSubscribed.restore(); - stubLoad.restore(); - }, -); - -testWithAltOriginContext( - `should discover alt origin to be subdomain.os.tc if user is not subscribed to either onesignal.com or os.tc`, - async (t) => { - setupDiscoverAltOriginTest(t); - const { appConfig } = t.context; - if (!appConfig) { - return; - } - - const stubLoad = sinon - .stub(ProxyFrameHost.prototype, 'load') - .resolves(undefined); - const stubIsSubscribed = sinon - .stub(ProxyFrameHost.prototype, 'isSubscribed') - .callsFake(t.context.stubIsSubscribedToNoneImpl); - const stubRemoveDuplicatedAltOriginSubscription = sinon - .stub(AltOriginManager, 'removeDuplicatedAltOriginSubscription') - .resolves(undefined); - - const proxyFrame = await AltOriginManager.discoverAltOrigin(appConfig); - t.is(proxyFrame.url.host, t.context.subdomainOsTcHost); - - stubRemoveDuplicatedAltOriginSubscription.restore(); - stubIsSubscribed.restore(); - stubLoad.restore(); - }, -); - -testWithAltOriginContext( - `should discover alt origin to be subdomain.os.tc if user is subscribed to both onesignal.com and os.tc`, - async (t) => { - setupDiscoverAltOriginTest(t); - const { appConfig } = t.context; - if (!appConfig) { - return; - } - - const stubLoad = sinon - .stub(ProxyFrameHost.prototype, 'load') - .resolves(undefined); - const stubIsSubscribed = sinon - .stub(ProxyFrameHost.prototype, 'isSubscribed') - .callsFake(t.context.stubIsSubscribedToBothImpl); - const stubUnsubscribeFromPush = sinon - .stub(ProxyFrameHost.prototype, 'unsubscribeFromPush') - .resolves(undefined); - - const proxyFrame = await AltOriginManager.discoverAltOrigin(appConfig); - t.is(proxyFrame.url.host, t.context.subdomainOsTcHost); - t.true(stubUnsubscribeFromPush.called); - - stubUnsubscribeFromPush.restore(); - stubIsSubscribed.restore(); - stubLoad.restore(); - }, -); From eb2176b02c6db01f312b6bd56b9910b3937bd332 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 22:55:14 +0000 Subject: [PATCH 07/35] rm canTalkToServiceWorker() Remove canTalkToServiceWorker() as we already check HTTPS on init. --- src/page/helpers/EnvironmentInfoHelper.ts | 5 ----- src/page/models/EnvironmentInfo.ts | 1 - .../managers/sessionManager/SessionManager.ts | 14 +------------- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/page/helpers/EnvironmentInfoHelper.ts b/src/page/helpers/EnvironmentInfoHelper.ts index e21a3d756..821563f26 100644 --- a/src/page/helpers/EnvironmentInfoHelper.ts +++ b/src/page/helpers/EnvironmentInfoHelper.ts @@ -19,7 +19,6 @@ export class EnvironmentInfoHelper { isBrowserAndSupportsServiceWorkers: this.supportsServiceWorkers(), requiresUserInteraction: this.requiresUserInteraction(), osVersion: this.getOsVersion(), - canTalkToServiceWorker: this.canTalkToServiceWorker(), }; } @@ -84,8 +83,4 @@ export class EnvironmentInfoHelper { private static getOsVersion(): string | number { return bowser.osversion; } - - private static canTalkToServiceWorker(): boolean { - return !!window.isSecureContext; - } } diff --git a/src/page/models/EnvironmentInfo.ts b/src/page/models/EnvironmentInfo.ts index 8f2a3907f..91d0d335a 100644 --- a/src/page/models/EnvironmentInfo.ts +++ b/src/page/models/EnvironmentInfo.ts @@ -8,5 +8,4 @@ export interface EnvironmentInfo { isBrowserAndSupportsServiceWorkers: boolean; requiresUserInteraction: boolean; osVersion: string | number; - canTalkToServiceWorker: boolean; } diff --git a/src/shared/managers/sessionManager/SessionManager.ts b/src/shared/managers/sessionManager/SessionManager.ts index be1780817..0f4a7a796 100644 --- a/src/shared/managers/sessionManager/SessionManager.ts +++ b/src/shared/managers/sessionManager/SessionManager.ts @@ -286,12 +286,7 @@ export class SessionManager implements ISessionManager { } if (this.context.environmentInfo?.isBrowserAndSupportsServiceWorkers) { - if (!this.context.environmentInfo?.canTalkToServiceWorker) { - this.onSessionSent = sessionOrigin === SessionOrigin.PlayerCreate; - OneSignal.emitter.emit(OneSignal.EVENTS.SESSION_STARTED); - } else { - this.setupSessionEventListeners(); - } + this.setupSessionEventListeners(); } else { this.onSessionSent = sessionOrigin === SessionOrigin.PlayerCreate; OneSignal.emitter.emit(OneSignal.EVENTS.SESSION_STARTED); @@ -307,13 +302,6 @@ export class SessionManager implements ISessionManager { return; } - if (!this.context.environmentInfo?.canTalkToServiceWorker) { - Log.debug( - "Not setting session event listeners. Can't talk to ServiceWorker due being hosted on an HTTP page.", - ); - return; - } - // Page lifecycle events https://developers.google.com/web/updates/2018/07/page-lifecycle-api this.setupOnFocusAndOnBlurForSession(); From a15799bfb2c0b38b09eebce362183960ef1221ad Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 22:57:19 +0000 Subject: [PATCH 08/35] rm ONESIGNAL_HTTP_PROMPT_SHOWN --- src/page/managers/PromptsManager.ts | 2 -- src/shared/helpers/MainHelper.ts | 15 --------------- 2 files changed, 17 deletions(-) diff --git a/src/page/managers/PromptsManager.ts b/src/page/managers/PromptsManager.ts index b2c055832..3870fbb92 100644 --- a/src/page/managers/PromptsManager.ts +++ b/src/page/managers/PromptsManager.ts @@ -186,7 +186,6 @@ export class PromptsManager { } this.isNativePromptShowing = true; - MainHelper.markHttpSlidedownShown(); await InitHelper.registerForPushNotifications(); this.isNativePromptShowing = false; DismissHelper.markPromptDismissedWithType(DismissPrompt.Push); @@ -201,7 +200,6 @@ export class PromptsManager { options.slidedownPromptOptions = CONFIG_DEFAULTS_SLIDEDOWN_OPTIONS; } - MainHelper.markHttpSlidedownShown(); const sdkStylesLoadResult = await this.context.dynamicResourceLoader.loadSdkStylesheet(); if (sdkStylesLoadResult !== ResourceLoadState.Loaded) { diff --git a/src/shared/helpers/MainHelper.ts b/src/shared/helpers/MainHelper.ts index 90ac66451..3d431b07a 100755 --- a/src/shared/helpers/MainHelper.ts +++ b/src/shared/helpers/MainHelper.ts @@ -47,21 +47,6 @@ export default class MainHelper { return SubscriptionStateKind.NoNativePermission; } - /** - * Stores a flag in sessionStorage that we've already shown the HTTP slidedown to this user and that we should not - * show it again until they open a new window or tab to the site. - */ - static markHttpSlidedownShown() { - sessionStorage.setItem('ONESIGNAL_HTTP_PROMPT_SHOWN', 'true'); - } - - /** - * Returns true if the HTTP slidedown was already shown inside the same session. - */ - static isHttpPromptAlreadyShown() { - return sessionStorage.getItem('ONESIGNAL_HTTP_PROMPT_SHOWN') == 'true'; - } - static async checkAndTriggerNotificationPermissionChanged() { const previousPermission = await Database.get( 'Options', From a2ad30ee180e9a92c1434bd11e5630e9e09f7512 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 22:59:52 +0000 Subject: [PATCH 09/35] rm getOneSignalSubdomainNotificationPermission --- src/shared/managers/PermissionManager.ts | 21 ------ test/support/tester/sinonSandboxUtils.ts | 14 ---- test/unit/public-sdk-apis/onSession.ts | 84 ------------------------ 3 files changed, 119 deletions(-) diff --git a/src/shared/managers/PermissionManager.ts b/src/shared/managers/PermissionManager.ts index 782e441f5..55a7c0610 100644 --- a/src/shared/managers/PermissionManager.ts +++ b/src/shared/managers/PermissionManager.ts @@ -134,27 +134,6 @@ export default class PermissionManager { return Notification.permission as NotificationPermission; } - /** - * Returns the notification permission as reported by the browser for the OneSignal subdomain - * iframe. - * - * @param safariWebId The Safari web ID necessary to access the permission state on Safari. - */ - public async getOneSignalSubdomainNotificationPermission( - safariWebId?: string, - ): Promise { - return new Promise((resolve) => { - OneSignal.proxyFrameHost.message( - OneSignal.POSTMAM_COMMANDS.REMOTE_NOTIFICATION_PERMISSION, - { safariWebId: safariWebId }, - (reply: any) => { - const remoteNotificationPermission = reply.data; - resolve(remoteNotificationPermission); - }, - ); - }); - } - /** * To interpret the browser's reported notification permission, we need to know whether we're in * an environment where the returned permission should be treated ambiguously. diff --git a/test/support/tester/sinonSandboxUtils.ts b/test/support/tester/sinonSandboxUtils.ts index 7c638683d..ea146bc74 100644 --- a/test/support/tester/sinonSandboxUtils.ts +++ b/test/support/tester/sinonSandboxUtils.ts @@ -44,20 +44,6 @@ export async function markUserAsSubscribed( } } -export async function markUserAsSubscribedOnHttp( - sinonSandbox: SinonSandbox, - playerId?: string, - expired?: boolean, -) { - markUserAsSubscribed(sinonSandbox, playerId, expired); - sinonSandbox - .stub( - PermissionManager.prototype, - 'getOneSignalSubdomainNotificationPermission', - ) - .resolves(NotificationPermission.Granted); -} - export function stubServiceWorkerInstallation(sinonSandbox: SinonSandbox) { const swRegistration = new MockServiceWorkerRegistration(); diff --git a/test/unit/public-sdk-apis/onSession.ts b/test/unit/public-sdk-apis/onSession.ts index fb53c2358..fcfe44039 100644 --- a/test/unit/public-sdk-apis/onSession.ts +++ b/test/unit/public-sdk-apis/onSession.ts @@ -16,7 +16,6 @@ import InitHelper from '../../../src/shared/helpers/InitHelper'; import { markUserAsOptedOut, markUserAsSubscribed, - markUserAsSubscribedOnHttp, stubServiceWorkerInstallation, } from '../../support/tester/sinonSandboxUtils'; import { createSubscription } from '../../support/tester/utils'; @@ -889,89 +888,6 @@ test.serial( }, ); -test.serial( - `HTTP: User subscribed => first page view => expiring subscription => sends player update`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Granted, - pushIdentifier: 'granted', - }; - - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - sinonSandbox - .stub(InitHelper, 'registerSubscriptionInProxyFrame') - .resolves(createSubscription()); - - await markUserAsSubscribedOnHttp(sinonSandbox, playerId, true); - stubServiceWorkerInstallation(sinonSandbox); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - // t.is(registerStub.callCount, 1); - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - }, -); - -test.serial( - `HTTP: User subscribed => first page view => sends on session`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Granted, - pushIdentifier: 'granted', - }; - - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - await markUserAsSubscribedOnHttp(sinonSandbox, playerId); - stubServiceWorkerInstallation(sinonSandbox); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 1); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - }, -); - /** Helper methods */ async function inspectPushRecordCreationRequest( t: ExecutionContext, From 098cd7691da40a543a3c12601fc1a6dc30934b59 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 23:02:52 +0000 Subject: [PATCH 10/35] rm DeprecatedApiError Remove DeprecatedApiError, this could have been removed with the v16 release since these APIs were droped then --- src/page/errors/DeprecatedApiError.ts | 53 --------------------------- 1 file changed, 53 deletions(-) delete mode 100755 src/page/errors/DeprecatedApiError.ts diff --git a/src/page/errors/DeprecatedApiError.ts b/src/page/errors/DeprecatedApiError.ts deleted file mode 100755 index 2734bb422..000000000 --- a/src/page/errors/DeprecatedApiError.ts +++ /dev/null @@ -1,53 +0,0 @@ -import OneSignalError from '../../shared/errors/OneSignalError'; -import { - ApiUsageMetricEvent, - ApiUsageMetricKind, -} from '../managers/MetricsManager'; - -export enum DeprecatedApiReason { - HttpPermissionRequest, - SyncHashedEmail, -} - -export class DeprecatedApiError extends OneSignalError { - constructor(reason: DeprecatedApiReason) { - let errorMessage: string; - let kind: ApiUsageMetricKind; - switch (reason) { - case DeprecatedApiReason.HttpPermissionRequest: - errorMessage = - `The HTTP permission request has been deprecated. Please remove any custom popups from ` + - `your code.`; - kind = ApiUsageMetricKind.HttpPermissionRequest; - break; - case DeprecatedApiReason.SyncHashedEmail: - errorMessage = - 'API syncHashedEmail() has been deprecated and will be removed in a future SDK release.' + - ' Please remove any usages from your code.'; - kind = ApiUsageMetricKind.SyncHashedEmail; - break; - } - - super(errorMessage); - this.reportUsage(kind); - /** - * Important! Required to make sure the correct error type is detected during instanceof checks. - * Same applies to all derived classes. - * https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md - * #extending-built-ins-like-error-array-and-map-may-no-longer-work - */ - Object.setPrototypeOf(this, DeprecatedApiError.prototype); - } - - reportUsage(apiKind: ApiUsageMetricKind) { - if ( - typeof OneSignal !== 'undefined' && - OneSignal.context && - OneSignal.context.metricsManager - ) { - OneSignal.context.metricsManager.reportEvent( - new ApiUsageMetricEvent(apiKind), - ); - } - } -} From efcfd8518629d384e272e670f22c9b63584fc508 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 23:10:07 +0000 Subject: [PATCH 11/35] rm LegacyManager and metrics for dropped APIs --- src/onesignal/OneSignal.ts | 3 -- src/page/managers/LegacyManager.ts | 69 ----------------------------- src/page/managers/MetricsManager.ts | 22 --------- 3 files changed, 94 deletions(-) delete mode 100644 src/page/managers/LegacyManager.ts diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index 1a3961532..97ac8cb14 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -1,6 +1,5 @@ import { EnvironmentInfoHelper } from '../page/helpers/EnvironmentInfoHelper'; import ConfigManager from '../page/managers/ConfigManager'; -import LegacyManager from '../page/managers/LegacyManager'; import Context from '../page/models/Context'; import { EnvironmentInfo } from '../page/models/EnvironmentInfo'; import ProxyFrame from '../page/modules/frames/ProxyFrame'; @@ -382,8 +381,6 @@ export default class OneSignal { }; } -LegacyManager.ensureBackwardsCompatibility(OneSignal); - Log.info( `OneSignal Web SDK loaded (version ${OneSignal._VERSION}, ${SdkEnvironment.getWindowEnv().toString()} environment).`, diff --git a/src/page/managers/LegacyManager.ts b/src/page/managers/LegacyManager.ts deleted file mode 100644 index 05a0914e1..000000000 --- a/src/page/managers/LegacyManager.ts +++ /dev/null @@ -1,69 +0,0 @@ -import SdkEnvironment from '../../shared/managers/SdkEnvironment'; -import { WindowEnvironmentKind } from '../../shared/models/WindowEnvironmentKind'; - -/** - * Creates method proxies for once-supported methods. - */ -export default class LegacyManager { - static promiseStub() { - return { - then: LegacyManager.promiseStub, - catch: LegacyManager.promiseStub, - }; - } - - static ensureBackwardsCompatibility(oneSignal) { - LegacyManager.environmentPolyfill(oneSignal); - LegacyManager.postmams(oneSignal); - oneSignal.syncHashedEmail = LegacyManager.promiseStub; - } - - static environmentPolyfill(oneSignal) { - oneSignal.environment = {}; - oneSignal.environment.getEnv = function () { - return ''; - }; - oneSignal.environment.isPopup = function () { - return ( - SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalSubscriptionPopup - ); - }; - oneSignal.environment.isIframe = function () { - return ( - SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalProxyFrame - ); - }; - } - - static postmams(oneSignal) { - const postmamMessageFunc = function message(this: any) { - // eslint-disable-next-line prefer-spread, prefer-rest-params - this.messenger.message.apply(this.messenger, arguments); - }; - - const postmamPostMessageFunc = function postMessage(this: any) { - // eslint-disable-next-line prefer-spread, prefer-rest-params - this.messenger.postMessage.apply(this.messenger, arguments); - }; - - function assignPostmamLegacyFunctions(postmamLikeObject) { - postmamLikeObject.message = postmamMessageFunc; - postmamLikeObject.postMessage = postmamPostMessageFunc; - } - - if (oneSignal.proxyFrame) { - oneSignal.iframePostmam = oneSignal.proxyFrame; - assignPostmamLegacyFunctions(oneSignal.iframePostmam); - } - if (oneSignal.subscriptionPopup) { - oneSignal.popupPostmam = oneSignal.subscriptionPopup; - assignPostmamLegacyFunctions(oneSignal.popupPostmam); - } - if (oneSignal.subscriptionModal) { - oneSignal.modalPostmam = oneSignal.subscriptionModal; - assignPostmamLegacyFunctions(oneSignal.modalPostmam); - } - } -} diff --git a/src/page/managers/MetricsManager.ts b/src/page/managers/MetricsManager.ts index 0074fd481..21b9c3d9c 100644 --- a/src/page/managers/MetricsManager.ts +++ b/src/page/managers/MetricsManager.ts @@ -18,28 +18,6 @@ abstract class MetricEngagement { abstract getOperationData(); } -export enum ApiUsageMetricKind { - HttpPermissionRequest = 'HttpPermissionRequest', - SyncHashedEmail = 'SyncHashedEmail', -} - -export class ApiUsageMetricEvent extends MetricEvent { - constructor(public apiName: ApiUsageMetricKind) { - super(); - } - - getEventName() { - return 'api-usage'; - } - - getPropertiesAsJson() { - return { - api: this.apiName.toString(), - ...super.getPropertiesAsJson(), - }; - } -} - export class PageViewMetricEngagement extends MetricEngagement { constructor() { super(); From ecf838932b99a74447d126ed9d6503896c66cae0 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 23:12:08 +0000 Subject: [PATCH 12/35] rm httpPermissionRequest --- src/shared/helpers/InitHelper.ts | 1 - test/unit/modules/mergedLegacyConfig.ts | 54 ------------------------- 2 files changed, 55 deletions(-) diff --git a/src/shared/helpers/InitHelper.ts b/src/shared/helpers/InitHelper.ts index b07fdf7e8..cf8c7aa65 100755 --- a/src/shared/helpers/InitHelper.ts +++ b/src/shared/helpers/InitHelper.ts @@ -25,7 +25,6 @@ declare let OneSignal: any; export interface RegisterOptions extends SubscriptionPopupHostOptions { modalPrompt?: boolean; - httpPermissionRequest?: boolean; slidedown?: boolean; } diff --git a/test/unit/modules/mergedLegacyConfig.ts b/test/unit/modules/mergedLegacyConfig.ts index dfbcd7254..6b836b304 100644 --- a/test/unit/modules/mergedLegacyConfig.ts +++ b/test/unit/modules/mergedLegacyConfig.ts @@ -57,24 +57,6 @@ test('should assign the default service worker registration params if not provid t.deepEqual(result.userConfig.serviceWorkerParam, { scope: '/' }); }); -test('should not overwrite a provided service worker registration params', async (t) => { - await TestEnvironment.initialize({ - initOptions: { - httpPermissionRequest: { - enable: true, - }, - }, - httpOrHttps: HttpHttpsEnvironment.Http, - }); - - OneSignal.SERVICE_WORKER_PARAM = { scope: 'customValue' }; - const result = new ConfigManager().getMergedConfig( - {}, - TestEnvironment.getFakeServerAppConfig(ConfigIntegrationKind.Custom), - ); - t.deepEqual(result.userConfig.serviceWorkerParam, { scope: 'customValue' }); -}); - test('should assign the default service worker A filename if not provided', async (t) => { const result = new ConfigManager().getMergedConfig( {}, @@ -83,42 +65,6 @@ test('should assign the default service worker A filename if not provided', asyn t.is(result.userConfig.serviceWorkerPath, 'OneSignalSDK.sw.js'); }); -test("should not use server's subdomain if subdomain not specified in user config on HTTPS site", async (t) => { - await TestEnvironment.initialize({ - initOptions: { - httpPermissionRequest: { - enable: true, - }, - }, - httpOrHttps: HttpHttpsEnvironment.Https, - }); - - const serverConfig = TestEnvironment.getFakeServerAppConfig( - ConfigIntegrationKind.Custom, - ); - serverConfig.config.subdomain = 'test-subdomain'; - const result = new ConfigManager().getMergedConfig({}, serverConfig); - t.is(result.subdomain, undefined); -}); - -test("should use server's subdomain if subdomain not specified in user config but on HTTP site", async (t) => { - await TestEnvironment.initialize({ - initOptions: { - httpPermissionRequest: { - enable: true, - }, - }, - httpOrHttps: HttpHttpsEnvironment.Http, - }); - - const serverConfig = TestEnvironment.getFakeServerAppConfig( - ConfigIntegrationKind.Custom, - ); - serverConfig.config.subdomain = 'test-subdomain'; - const result = new ConfigManager().getMergedConfig({}, serverConfig); - t.is(result.subdomain, 'test-subdomain'); -}); - test('should not overwrite provided subdomain', async (t) => { const serverConfig = TestEnvironment.getFakeServerAppConfig( ConfigIntegrationKind.Custom, From 7a15e3d2b0c3a06c56c800024c590781b2038b6d Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Wed, 22 Nov 2023 23:55:06 +0000 Subject: [PATCH 13/35] Clean up WindowEnvironmentKind Removed all the unsupported HTTP subdmain (os.tc) types from WindowEnvironmentKind and code using them. --- src/onesignal/OneSignal.ts | 12 +-- src/shared/api/OneSignalApi.ts | 2 +- src/shared/helpers/ConfigHelper.ts | 12 +-- src/shared/helpers/HttpHelper.ts | 70 ---------------- src/shared/helpers/SubscriptionHelper.ts | 90 --------------------- src/shared/managers/PageViewManager.ts | 15 ---- src/shared/managers/SdkEnvironment.ts | 26 +----- src/shared/managers/ServiceWorkerManager.ts | 33 +------- src/shared/managers/SubscriptionManager.ts | 11 +-- src/shared/models/WindowEnvironmentKind.ts | 25 ------ src/shared/services/Database.ts | 1 - src/shared/services/OneSignalEvent.ts | 32 -------- src/shared/utils/OneSignalUtils.ts | 2 - test/unit/managers/LegacyManager.ts | 26 ------ test/unit/managers/ServiceWorkerManager.ts | 43 ---------- test/unit/modules/sdkEnvironment.ts | 61 -------------- 16 files changed, 10 insertions(+), 451 deletions(-) delete mode 100755 src/shared/helpers/HttpHelper.ts delete mode 100644 test/unit/managers/LegacyManager.ts diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index 97ac8cb14..0bd3eefa8 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -13,7 +13,6 @@ import { ProcessOneSignalPushCalls } from '../page/utils/ProcessOneSignalPushCal import { SdkInitError, SdkInitErrorKind } from '../shared/errors/SdkInitError'; import Environment from '../shared/helpers/Environment'; import EventHelper from '../shared/helpers/EventHelper'; -import HttpHelper from '../shared/helpers/HttpHelper'; import InitHelper from '../shared/helpers/InitHelper'; import MainHelper from '../shared/helpers/MainHelper'; import Emitter from '../shared/libraries/Emitter'; @@ -23,7 +22,6 @@ import { SessionManager } from '../shared/managers/sessionManager/SessionManager import { AppUserConfig, AppConfig } from '../shared/models/AppConfig'; import { DeviceRecord } from '../shared/models/DeviceRecord'; import { AppUserConfigNotifyButton } from '../shared/models/Prompts'; -import { WindowEnvironmentKind } from '../shared/models/WindowEnvironmentKind'; import Database from '../shared/services/Database'; import OneSignalUtils from '../shared/utils/OneSignalUtils'; import { logMethodCall } from '../shared/utils/utils'; @@ -199,9 +197,7 @@ export default class OneSignal { await InitHelper.initSaveState(); await InitHelper.saveInitOptions(); - if (SdkEnvironment.getWindowEnv() === WindowEnvironmentKind.CustomIframe) - await OneSignalEvent.trigger(OneSignal.EVENTS.SDK_INITIALIZED); - else await InitHelper.internalInit(); + await InitHelper.internalInit(); } if ( @@ -325,12 +321,6 @@ export default class OneSignal { static Debug = new DebugNamespace(); /* END NEW USER MODEL CHANGES */ - /** - * Used by Rails-side HTTP popup. Must keep the same name. - * @InternalApi - */ - static _initHttp = HttpHelper.initHttp; - /** * Used by Rails-side HTTP popup. Must keep the same name. * @InternalApi diff --git a/src/shared/api/OneSignalApi.ts b/src/shared/api/OneSignalApi.ts index 007974adb..0e95fb04d 100755 --- a/src/shared/api/OneSignalApi.ts +++ b/src/shared/api/OneSignalApi.ts @@ -53,7 +53,7 @@ export default class OneSignalApi { static async downloadServerAppConfig( appId: string, ): Promise { - if (SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.ServiceWorker) { + if (SdkEnvironment.getWindowEnv() === WindowEnvironmentKind.Host) { return await new Promise((resolve, reject) => { // Due to CloudFlare's algorithms, the .js extension is required for proper caching. Don't remove it! OneSignalApi.jsonpLib( diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index ea25d26fa..95b7616d4 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -74,12 +74,8 @@ export class ConfigHelper { // The os.tc domain feature is no longer supported in v16, so throw if the // OneSignal app is still configured this way after they migrated from v15. private static checkUnsupportedSubdomain(appConfig: AppConfig): void { - const windowEnv = SdkEnvironment.getWindowEnv(); - const isHttp = location.protocol === 'http:'; - const useSubdomain = - (windowEnv === WindowEnvironmentKind.Host || - windowEnv === WindowEnvironmentKind.CustomIframe) && - (!!appConfig.subdomain || isHttp); + const isHttp = !window.isSecureContext; + const useSubdomain = !!appConfig.subdomain || isHttp; if (useSubdomain) { if (isHttp) { @@ -96,9 +92,7 @@ export class ConfigHelper { public static checkRestrictedOrigin(appConfig: AppConfig) { if (appConfig.restrictedOriginEnabled) { - if ( - SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.ServiceWorker - ) { + if (SdkEnvironment.getWindowEnv() === WindowEnvironmentKind.Host) { if ( window.top === window && !Utils.contains(window.location.hostname, '.os.tc') && diff --git a/src/shared/helpers/HttpHelper.ts b/src/shared/helpers/HttpHelper.ts deleted file mode 100755 index 77a58f437..000000000 --- a/src/shared/helpers/HttpHelper.ts +++ /dev/null @@ -1,70 +0,0 @@ -import LegacyManager from '../../page/managers/LegacyManager'; -import ProxyFrame from '../../page/modules/frames/ProxyFrame'; -import { RemoteFrameOptions } from '../../page/modules/frames/RemoteFrame'; -import SubscriptionModal from '../../page/modules/frames/SubscriptionModal'; -import SubscriptionPopup from '../../page/modules/frames/SubscriptionPopup'; -import Log from '../libraries/Log'; -import SdkEnvironment from '../managers/SdkEnvironment'; -import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; -import OneSignalEvent from '../services/OneSignalEvent'; - -declare let OneSignal: any; - -export default class HttpHelper { - // Http only - Only called from iframe's init.js - static async initHttp(options: RemoteFrameOptions) { - Log.debug(`Called initHttp(${JSON.stringify(options, null, 4)})`); - - switch (SdkEnvironment.getWindowEnv()) { - case WindowEnvironmentKind.OneSignalProxyFrame: - OneSignal.proxyFrame = new ProxyFrame(options); - await OneSignal.proxyFrame.initialize(); - /** - * Our Rails-side subscription popup/modal depends on - * OneSignal.iframePostmam, OneSignal.popupPostmam, and - * OneSignal.modalPostmam, which don't exist anymore. - */ - LegacyManager.ensureBackwardsCompatibility(OneSignal); - break; - case WindowEnvironmentKind.OneSignalSubscriptionPopup: - OneSignal.subscriptionPopup = new SubscriptionPopup(options); - await OneSignal.subscriptionPopup.initialize(); - /** - * Our Rails-side subscription popup/modal depends on - * OneSignal.iframePostmam, OneSignal.popupPostmam, and - * OneSignal.modalPostmam, which don't exist anymore. - */ - LegacyManager.ensureBackwardsCompatibility(OneSignal); - OneSignalEvent.trigger('httpInitialize'); - break; - case WindowEnvironmentKind.OneSignalSubscriptionModal: - OneSignal.subscriptionModal = new SubscriptionModal(options); - - /* - WARNING: Do not await on modal initialization; the modal uses direct - postmessage and does not establish a "connection" to wait on - */ - /* - WARNING: The establishCrossOriginMessaging() statement is necessary. - The common base class implementation of initialize() does an - asynchronous download of settings, but the modal needs the 'messenger' - variable (created by calling establishCrossOriginmessaging()) to exist - immediately. The hacky way to solve this for now is to force this part - of the initialization earlier. - */ - OneSignal.subscriptionModal.establishCrossOriginMessaging(); - OneSignal.subscriptionModal.initialize(); - - /* Our Rails-side subscription popup/modal depends on - * OneSignal.iframePostmam, OneSignal.popupPostmam, and - * OneSignal.modalPostmam, which don't exist anymore. - */ - LegacyManager.ensureBackwardsCompatibility(OneSignal); - OneSignalEvent.trigger('httpInitialize'); - break; - default: - Log.error('Unsupported HTTP initialization branch.'); - break; - } - } -} diff --git a/src/shared/helpers/SubscriptionHelper.ts b/src/shared/helpers/SubscriptionHelper.ts index ac1f70a49..fc945af9f 100755 --- a/src/shared/helpers/SubscriptionHelper.ts +++ b/src/shared/helpers/SubscriptionHelper.ts @@ -1,5 +1,3 @@ -import PushPermissionNotGrantedError from '../errors/PushPermissionNotGrantedError'; -import { PushPermissionNotGrantedErrorReason } from '../errors/PushPermissionNotGrantedError'; import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import EventHelper from './EventHelper'; import { @@ -7,7 +5,6 @@ import { InvalidStateReason, } from '../errors/InvalidStateError'; import { Subscription } from '../models/Subscription'; -import { NotificationPermission } from '../models/NotificationPermission'; import { RawPushSubscription } from '../models/RawPushSubscription'; import { SubscriptionStrategyKind } from '../models/SubscriptionStrategyKind'; import Log from '../libraries/Log'; @@ -28,7 +25,6 @@ export default class SubscriptionHelper { switch (SdkEnvironment.getWindowEnv()) { case WindowEnvironmentKind.Host: - case WindowEnvironmentKind.OneSignalSubscriptionModal: try { const rawSubscription = await context.subscriptionManager.subscribe( SubscriptionStrategyKind.ResubscribeExisting, @@ -44,92 +40,6 @@ export default class SubscriptionHelper { Log.error(e); } break; - case WindowEnvironmentKind.OneSignalSubscriptionPopup: { - /* - This is the code for the HTTP popup. - */ - const windowCreator = opener || parent; - let rawSubscription: RawPushSubscription; - - // Update the stored permission first, so we know the real value even if the user closes the - // popup - await context.permissionManager.updateStoredPermission(); - - try { - /* If the user doesn't grant permissions, a PushPermissionNotGrantedError will be thrown here. */ - rawSubscription = await context.subscriptionManager.subscribe( - SubscriptionStrategyKind.SubscribeNew, - ); - - // Update the permission to granted - await context.permissionManager.updateStoredPermission(); - } catch (e) { - // Update the permission to denied or default - await context.permissionManager.updateStoredPermission(); - - if (e instanceof PushPermissionNotGrantedError) { - switch ((e as PushPermissionNotGrantedError).reason) { - case PushPermissionNotGrantedErrorReason.Blocked: - await context.permissionManager.updateStoredPermission(); - /* Force update false, because the iframe installs a native - permission change handler that will be triggered when the user - clicks out of the popup back to the parent page */ - (OneSignal.subscriptionPopup as any).message( - OneSignal.POSTMAM_COMMANDS - .REMOTE_NOTIFICATION_PERMISSION_CHANGED, - { - permission: NotificationPermission.Denied, - forceUpdatePermission: false, - }, - ); - break; - case PushPermissionNotGrantedErrorReason.Dismissed: - /* Force update true because default permissions (before - prompting) -> default permissions (after prompting) isn't a - change, but we still want to be notified about it */ - (OneSignal.subscriptionPopup as any).message( - OneSignal.POSTMAM_COMMANDS - .REMOTE_NOTIFICATION_PERMISSION_CHANGED, - { - permission: NotificationPermission.Default, - forceUpdatePermission: true, - }, - ); - break; - } - } - /* - Popup native permission request was blocked or dismissed - Close the window - */ - if (windowCreator) { - window.close(); - return null; - } - } - - OneSignal.subscriptionPopup.message( - OneSignal.POSTMAM_COMMANDS.FINISH_REMOTE_REGISTRATION, - { - rawPushSubscription: rawSubscription.serialize(), - }, - (message: any) => { - if (message.data.progress === true) { - Log.debug( - 'Got message from host page that remote reg. is in progress, closing popup.', - ); - if (windowCreator) { - window.close(); - } - } else { - Log.debug( - 'Got message from host page that remote reg. could not be finished.', - ); - } - }, - ); - break; - } default: throw new InvalidStateError(InvalidStateReason.UnsupportedEnvironment); } diff --git a/src/shared/managers/PageViewManager.ts b/src/shared/managers/PageViewManager.ts index 9bf94ce22..60909c875 100644 --- a/src/shared/managers/PageViewManager.ts +++ b/src/shared/managers/PageViewManager.ts @@ -1,5 +1,3 @@ -import SdkEnvironment from './SdkEnvironment'; -import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import Log from '../libraries/Log'; import LocalStorage from '../utils/LocalStorage'; @@ -38,19 +36,6 @@ export class PageViewManager { PageViewManager.SESSION_STORAGE_KEY_NAME, sessionCount.toString(), ); - - if ( - SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalSubscriptionPopup - ) { - // If we're setting sessionStorage and we're in an Popup, we need to also set sessionStorage on the - // main page - if (OneSignal.subscriptionPopup) { - OneSignal.subscriptionPopup.message( - OneSignal.POSTMAM_COMMANDS.SET_SESSION_COUNT, - ); - } - } } catch (e) { /* If sessionStorage isn't available, don't error. diff --git a/src/shared/managers/SdkEnvironment.ts b/src/shared/managers/SdkEnvironment.ts index 14c9907b9..4e86787c5 100644 --- a/src/shared/managers/SdkEnvironment.ts +++ b/src/shared/managers/SdkEnvironment.ts @@ -112,32 +112,10 @@ export default class SdkEnvironment { ) { return WindowEnvironmentKind.ServiceWorker; } else { - return WindowEnvironmentKind.Unknown; - } - } else { - // If the window is the root top-most level - if (window === window.top) { - if ( - location.href.indexOf('initOneSignal') !== -1 || - (location.pathname === '/subscribe' && - location.search === '' && - (location.hostname.endsWith('.onesignal.com') || - location.hostname.endsWith('.os.tc') || - (location.hostname.indexOf('.localhost') !== -1 && - SdkEnvironment.getBuildEnv() === EnvironmentKind.Development))) - ) { - return WindowEnvironmentKind.OneSignalSubscriptionPopup; - } else { - return WindowEnvironmentKind.Host; - } - } else if (location.pathname === '/webPushIframe') { - return WindowEnvironmentKind.OneSignalProxyFrame; - } else if (location.pathname === '/webPushModal') { - return WindowEnvironmentKind.OneSignalSubscriptionModal; - } else { - return WindowEnvironmentKind.CustomIframe; + throw Error('OneSignalSDK: Unsupported JS runtime!'); } } + return WindowEnvironmentKind.Host; } /** diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index 2cd732b75..2fd190465 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -282,28 +282,8 @@ export class ServiceWorkerManager { workerMessenger.on( WorkerMessengerCommand.NotificationClicked, async (event: NotificationClickEventInternal) => { - let clickedListenerCallbackCount: number; - if ( - SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalProxyFrame - ) { - clickedListenerCallbackCount = await new Promise( - (resolve) => { - const proxyFrame: ProxyFrame = OneSignal.proxyFrame; - if (proxyFrame) { - proxyFrame.messenger.message( - OneSignal.POSTMAM_COMMANDS.GET_EVENT_LISTENER_COUNT, - OneSignal.EVENTS.NOTIFICATION_CLICKED, - (reply: any) => { - const callbackCount: number = reply.data; - resolve(callbackCount); - }, - ); - } - }, - ); - } else - clickedListenerCallbackCount = OneSignal.emitter.numberOfListeners( + const clickedListenerCallbackCount = + OneSignal.emitter.numberOfListeners( OneSignal.EVENTS.NOTIFICATION_CLICKED, ); @@ -474,15 +454,6 @@ export class ServiceWorkerManager { Log.error( `[Service Worker Installation] Installing service worker failed ${error}`, ); - // Try accessing the service worker path directly to find out what the problem is and report it to OneSignal api. - - // If we are inside the popup and service worker fails to register, it's not developer's fault. - // No need to report it to the api then. - const env = SdkEnvironment.getWindowEnv(); - if (env === WindowEnvironmentKind.OneSignalSubscriptionPopup) { - throw error; - } - registration = await this.fallbackToUserModelBetaWorker(); } Log.debug( diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index 0bd6a6cf3..876dfa2a7 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -119,13 +119,6 @@ export class SubscriptionManager { ): Promise { const env = SdkEnvironment.getWindowEnv(); - switch (env) { - case WindowEnvironmentKind.CustomIframe: - case WindowEnvironmentKind.Unknown: - case WindowEnvironmentKind.OneSignalProxyFrame: - throw new InvalidStateError(InvalidStateReason.UnsupportedEnvironment); - } - let rawPushSubscription: RawPushSubscription; switch (env) { @@ -134,8 +127,6 @@ export class SubscriptionManager { await this.subscribeFcmFromWorker(subscriptionStrategy); break; case WindowEnvironmentKind.Host: - case WindowEnvironmentKind.OneSignalSubscriptionModal: - case WindowEnvironmentKind.OneSignalSubscriptionPopup: /* Check our notification permission before subscribing. @@ -457,7 +448,7 @@ export class SubscriptionManager { Trigger the permissionPromptDisplay event to the best of our knowledge. */ if ( - SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.ServiceWorker && + SdkEnvironment.getWindowEnv() === WindowEnvironmentKind.Host && Notification.permission === NotificationPermission.Default ) { await OneSignalEvent.trigger( diff --git a/src/shared/models/WindowEnvironmentKind.ts b/src/shared/models/WindowEnvironmentKind.ts index 94f301a3b..dffad8838 100644 --- a/src/shared/models/WindowEnvironmentKind.ts +++ b/src/shared/models/WindowEnvironmentKind.ts @@ -8,29 +8,4 @@ export enum WindowEnvironmentKind { * The top-level frame to the "main" client's site. */ Host = 'Host', - - /** - * Our subscription popup for alt-origin sites. - */ - OneSignalSubscriptionPopup = 'Popup', - - /** - * Our subscription modal for HTTPS sites, which loads in an iFrame. - */ - OneSignalSubscriptionModal = 'Modal', - - /** - * Our subscription helper iFrame. - */ - OneSignalProxyFrame = 'ProxyFrame', - - /** - * A custom iFrame on the site. - */ - CustomIframe = 'CustomFrame', - - /** - * An unknown window context type not matching any of the above. - */ - Unknown = 'Unknown', } diff --git a/src/shared/services/Database.ts b/src/shared/services/Database.ts index c56742d1e..cce5ab4e6 100644 --- a/src/shared/services/Database.ts +++ b/src/shared/services/Database.ts @@ -11,7 +11,6 @@ import { import { ServiceWorkerState } from '../models/ServiceWorkerState'; import { Subscription } from '../models/Subscription'; import { TestEnvironmentKind } from '../models/TestEnvironmentKind'; -import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import { BundleEmail, EmailProfile } from '../models/EmailProfile'; import { Session, ONESIGNAL_SESSION_KEY } from '../models/Session'; import SdkEnvironment from '../managers/SdkEnvironment'; diff --git a/src/shared/services/OneSignalEvent.ts b/src/shared/services/OneSignalEvent.ts index 1120e4f3c..064d8a0c6 100755 --- a/src/shared/services/OneSignalEvent.ts +++ b/src/shared/services/OneSignalEvent.ts @@ -1,6 +1,5 @@ import Environment from '../helpers/Environment'; import SdkEnvironment from '../managers/SdkEnvironment'; -import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import Utils from '../context/Utils'; import Log from '../libraries/Log'; @@ -91,37 +90,6 @@ export default class OneSignalEvent { const legacyEventName = LEGACY_EVENT_MAP[eventName]; OneSignalEvent._triggerLegacy(legacyEventName, data); } - - // If this event was triggered in an iFrame or Popup environment, also trigger it on the host page - if ( - Environment.isBrowser() && - (SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalSubscriptionPopup || - SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalProxyFrame) - ) { - const creator = opener || parent; - if (!creator) { - Log.error( - `Could not send event '${eventName}' back to host page because no creator (opener or parent) found!`, - ); - } else { - // But only if the event matches certain events - if (Utils.contains(RETRIGGER_REMOTE_EVENTS, eventName)) { - if ( - SdkEnvironment.getWindowEnv() === - WindowEnvironmentKind.OneSignalSubscriptionPopup - ) { - OneSignal.subscriptionPopup.message( - OneSignal.POSTMAM_COMMANDS.REMOTE_RETRIGGER_EVENT, - { eventName: eventName, eventData: data }, - ); - } else { - OneSignal.proxyFrame.retriggerRemoteEvent(eventName, data); - } - } - } - } } /** diff --git a/src/shared/utils/OneSignalUtils.ts b/src/shared/utils/OneSignalUtils.ts index c773f0fa5..45accda64 100644 --- a/src/shared/utils/OneSignalUtils.ts +++ b/src/shared/utils/OneSignalUtils.ts @@ -1,7 +1,5 @@ import bowser, { IBowser } from 'bowser'; -import SdkEnvironment from '../managers/SdkEnvironment'; import Environment from '../helpers/Environment'; -import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import { Utils } from '../context/Utils'; import Log from '../libraries/Log'; import { bowserCastle } from './bowserCastle'; diff --git a/test/unit/managers/LegacyManager.ts b/test/unit/managers/LegacyManager.ts deleted file mode 100644 index 67ecf44e2..000000000 --- a/test/unit/managers/LegacyManager.ts +++ /dev/null @@ -1,26 +0,0 @@ -import '../../support/polyfills/polyfills'; -import test from 'ava'; -import sinon from 'sinon'; -import SdkEnvironment from '../../../src/shared/managers/SdkEnvironment'; -import { WindowEnvironmentKind } from '../../../src/shared/models/WindowEnvironmentKind'; -import OneSignal from '../../../src/onesignal/OneSignal'; - -test('OneSignal.environment.getEnv()', async (t) => { - t.is((OneSignal as any).environment.getEnv(), ''); -}); - -test('OneSignal.environment.isPopup()', async (t) => { - const stub = sinon - .stub(SdkEnvironment, 'getWindowEnv') - .returns(WindowEnvironmentKind.OneSignalSubscriptionPopup); - t.is((OneSignal as any).environment.isPopup(), true); - stub.restore(); -}); - -test('OneSignal.environment.isIframe()', async (t) => { - const stub = sinon - .stub(SdkEnvironment, 'getWindowEnv') - .returns(WindowEnvironmentKind.OneSignalProxyFrame); - t.is((OneSignal as any).environment.isIframe(), true); - stub.restore(); -}); diff --git a/test/unit/managers/ServiceWorkerManager.ts b/test/unit/managers/ServiceWorkerManager.ts index 135b55c8f..ae9f4412c 100644 --- a/test/unit/managers/ServiceWorkerManager.ts +++ b/test/unit/managers/ServiceWorkerManager.ts @@ -398,49 +398,6 @@ test('Service worker failed to install due to 404 on host page. Send notificatio }); }); -test('Service worker failed to install in popup. No handling.', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); - sandbox.stub(Notification, 'permission').value('granted'); - - const context = OneSignal.context; - - const workerPath = 'Worker-does-not-exist.js'; - const manager = new ServiceWorkerManager(context, { - workerPath: new Path(workerPath), - registrationOptions: { - scope: '/', - }, - }); - - const origin = 'https://onesignal.com'; - nock(origin) - .get(function (uri) { - return uri.indexOf(workerPath) !== -1; - }) - .reply(404, (_uri: string, _requestBody: any) => { - return { - status: 404, - statusText: '404 Not Found', - }; - }); - - const workerRegistrationError = new Error('Registration failed'); - - sandbox - .stub(navigator.serviceWorker, 'register') - .throws(workerRegistrationError); - sandbox.stub(location, 'origin').returns(origin); - sandbox - .stub(SdkEnvironment, 'getWindowEnv') - .returns(WindowEnvironmentKind.OneSignalSubscriptionPopup); - const error = await t.throwsAsync(async () => manager.installWorker(), { - instanceOf: Error, - }); - t.is(error.message, workerRegistrationError.message); -}); - test('installWorker() should not install when on an HTTPS site with a subdomain set', async (t) => { // 1. Mock site page as HTTPS await TestEnvironment.initialize({ httpOrHttps: HttpHttpsEnvironment.Https }); diff --git a/test/unit/modules/sdkEnvironment.ts b/test/unit/modules/sdkEnvironment.ts index 36d6dbcf4..cb137025e 100644 --- a/test/unit/modules/sdkEnvironment.ts +++ b/test/unit/modules/sdkEnvironment.ts @@ -11,42 +11,6 @@ test('should get service worker window environment', async (t) => { t.is(SdkEnvironment.getWindowEnv(), WindowEnvironmentKind.ServiceWorker); }); -test('getWindowEnv should get subscription popup window environment', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - - // For legacy popup URL - browser.changeURL(window, 'https://anything.onesignal.com/initOneSignal'); - t.is( - SdkEnvironment.getWindowEnv(), - WindowEnvironmentKind.OneSignalSubscriptionPopup, - ); - - // For modern popup URL, using .onesignal.com - browser.changeURL(window, 'https://anything.onesignal.com/subscribe'); - t.is( - SdkEnvironment.getWindowEnv(), - WindowEnvironmentKind.OneSignalSubscriptionPopup, - ); - - // For modern popup URL, using .os.tc - browser.changeURL(window, 'https://anything.os.tc/subscribe'); - t.is( - SdkEnvironment.getWindowEnv(), - WindowEnvironmentKind.OneSignalSubscriptionPopup, - ); - - // For modern popup URL, using localhost dev - const stub = sinon - .stub(SdkEnvironment, 'getBuildEnv') - .returns(EnvironmentKind.Development); - browser.changeURL(window, 'https://anything.localhost:3001/subscribe'); - t.is( - SdkEnvironment.getWindowEnv(), - WindowEnvironmentKind.OneSignalSubscriptionPopup, - ); - stub.restore(); -}); - test('getWindowEnv should get host window environment', async (t) => { const browser = await TestEnvironment.stubDomEnvironment(); @@ -60,31 +24,6 @@ test('getWindowEnv should get host window environment', async (t) => { t.is(SdkEnvironment.getWindowEnv(), WindowEnvironmentKind.Host); }); -test('getWindowEnv should get proxy frame window environment', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: 'something else' as any }); - - browser.changeURL(window, 'https://something/webPushIframe'); - t.is( - SdkEnvironment.getWindowEnv(), - WindowEnvironmentKind.OneSignalProxyFrame, - ); - - browser.changeURL(window, 'https://something/webPushModal'); - t.is( - SdkEnvironment.getWindowEnv(), - WindowEnvironmentKind.OneSignalSubscriptionModal, - ); -}); - -test('getWindowEnv should get custom iFrame window environment', async (t) => { - const browser = await TestEnvironment.stubDomEnvironment(); - browser.reconfigureWindow(window, { top: 'something else' as any }); - - browser.changeURL(window, 'https://my-special-site.com/somepage'); - t.is(SdkEnvironment.getWindowEnv(), WindowEnvironmentKind.CustomIframe); -}); - test('API URL should be valid for development environment', async (t) => { t.is( SdkEnvironment.getOneSignalApiUrl(EnvironmentKind.Development).toString(), From fa4da7b29bc3f62de54e993bae16facb734de4e1 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 00:13:03 +0000 Subject: [PATCH 14/35] rm lastKnownHostUrl and logic around it --- src/page/modules/frames/ProxyFrame.ts | 12 --- src/sw/serviceWorker/ServiceWorker.ts | 127 +++++--------------------- src/sw/serviceWorker/types.ts | 4 - 3 files changed, 22 insertions(+), 121 deletions(-) diff --git a/src/page/modules/frames/ProxyFrame.ts b/src/page/modules/frames/ProxyFrame.ts index 8417f26bb..601344158 100644 --- a/src/page/modules/frames/ProxyFrame.ts +++ b/src/page/modules/frames/ProxyFrame.ts @@ -171,18 +171,6 @@ export default class ProxyFrame extends RemoteFrame { value: new URL(OneSignal.config.pageUrl).origin, }); } - - /** - * When a user is on http://example.com and receives a notification, we want to open a new window only if the - * notification's URL is different from http://example.com. The service worker, which only controls - * subdomain.onesignal.com, doesn't know that the host URL is http://example.com. Although defaultUrl above - * sets the HTTP's origin, this can be modified if users call setDefaultTitle(). lastKnownHostUrl therefore - * stores the last visited full page URL. - */ - await Database.put('Options', { - key: 'lastKnownHostUrl', - value: OneSignal.config.pageUrl, - }); await InitHelper.initSaveState(); await InitHelper.storeInitialValues(); await InitHelper.saveInitOptions(); diff --git a/src/sw/serviceWorker/ServiceWorker.ts b/src/sw/serviceWorker/ServiceWorker.ts index d1b125b85..d9d88d1f0 100755 --- a/src/sw/serviceWorker/ServiceWorker.ts +++ b/src/sw/serviceWorker/ServiceWorker.ts @@ -9,11 +9,7 @@ import { PushDeviceRecord } from '../../shared/models/PushDeviceRecord'; import Log from '../libraries/Log'; import { ConfigHelper } from '../../shared/helpers/ConfigHelper'; import { Utils } from '../../shared/context/Utils'; -import { - OSWindowClient, - OSServiceWorkerFields, - SubscriptionChangeEvent, -} from './types'; +import { OSServiceWorkerFields, SubscriptionChangeEvent } from './types'; import ServiceWorkerHelper from '../../shared/helpers/ServiceWorkerHelper'; import { cancelableTimeout } from '../helpers/CancelableTimeout'; import { awaitableTimeout } from '../../shared/utils/AwaitableTimeout'; @@ -487,38 +483,14 @@ export class ServiceWorker { } /** - * Gets an array of active window clients along with whether each window client is the HTTP site's iFrame or an - * HTTPS site page. - * An active window client is a browser tab that is controlled by the service worker. - * Technically, this list should only ever contain clients that are iFrames, or clients that are HTTPS site pages, - * and not both. This doesn't really matter though. + * Gets an array of window clients * @returns {Promise} */ - static async getActiveClients(): Promise> { - const windowClients: ReadonlyArray = await self.clients.matchAll({ + static async getWindowClients(): Promise> { + return await self.clients.matchAll({ type: 'window', includeUncontrolled: true, }); - const activeClients: Array = []; - - for (const client of windowClients) { - const windowClient: OSWindowClient = client as OSWindowClient; - windowClient.isSubdomainIframe = false; - // Test if this window client is the HTTP subdomain iFrame pointing to subdomain.onesignal.com - if (client.frameType && client.frameType === 'nested') { - // Subdomain iFrames point to 'https://subdomain.onesignal.com...' - if ( - !Utils.contains(client.url, '.os.tc') && - !Utils.contains(client.url, '.onesignal.com') - ) { - continue; - } - // Indicates this window client is an HTTP subdomain iFrame - windowClient.isSubdomainIframe = true; - } - activeClients.push(windowClient); - } - return activeClients; } static async updateSessionBasedOnHasActive( @@ -558,45 +530,26 @@ export class ServiceWorker { ): Promise { Log.debug('[Service Worker] refreshSession'); /** - * if https -> getActiveClients -> check for the first focused + * getWindowClients -> check for the first focused * unfortunately, not enough for safari, it always returns false for focused state of a client * have to workaround it with messaging to the client. - * - * if http, also have to workaround with messaging: - * SW to iframe -> iframe to page -> page to iframe -> iframe to SW */ - if (options.isHttps) { - const windowClients: ReadonlyArray = await self.clients.matchAll({ - type: 'window', - includeUncontrolled: true, - }); + const windowClients = await this.getWindowClients(); - if (options.isSafari) { - await ServiceWorker.checkIfAnyClientsFocusedAndUpdateSession( - event, - windowClients, - options, - ); - } else { - const hasAnyActiveSessions: boolean = windowClients.some( - (w) => (w as WindowClient).focused, - ); - Log.debug( - '[Service Worker] isHttps hasAnyActiveSessions', - hasAnyActiveSessions, - ); - await ServiceWorker.updateSessionBasedOnHasActive( - event, - hasAnyActiveSessions, - options, - ); - } - return; - } else { - const osClients = await ServiceWorker.getActiveClients(); + if (options.isSafari) { await ServiceWorker.checkIfAnyClientsFocusedAndUpdateSession( event, - osClients, + windowClients, + options, + ); + } else { + const hasAnyActiveSessions: boolean = windowClients.some( + (w) => (w as WindowClient).focused, + ); + Log.debug('[Service Worker] hasAnyActiveSessions', hasAnyActiveSessions); + await ServiceWorker.updateSessionBasedOnHasActive( + event, + hasAnyActiveSessions, options, ); } @@ -983,23 +936,10 @@ export class ServiceWorker { an identical new tab being created. With a special setting, any existing tab matching the origin will be focused instead of an identical new tab being created. */ - const activeClients = await ServiceWorker.getActiveClients(); + const activeClients = await ServiceWorker.getWindowClients(); let doNotOpenLink = false; for (const client of activeClients) { - let clientUrl = client.url; - if ((client as any).isSubdomainIframe) { - const lastKnownHostUrl = await Database.get( - 'Options', - 'lastKnownHostUrl', - ); - // TODO: clientUrl is being overwritten by defaultUrl and lastKnownHostUrl. - // Should only use clientUrl if it is not null. - // Also need to decide which to use over the other. - clientUrl = lastKnownHostUrl; - if (!lastKnownHostUrl) { - clientUrl = await Database.get('Options', 'defaultUrl'); - } - } + const clientUrl = client.url; let clientOrigin = ''; try { clientOrigin = new URL(clientUrl).origin; @@ -1021,8 +961,7 @@ export class ServiceWorker { clientOrigin === launchOrigin) ) { if ( - (client['isSubdomainIframe'] && clientUrl === launchUrl) || - (!client['isSubdomainIframe'] && client.url === launchUrl) || + client.url === launchUrl || (notificationClickHandlerAction === 'focus' && clientOrigin === launchOrigin) ) { @@ -1043,29 +982,7 @@ export class ServiceWorker { client.navigate() is available on Chrome 49+ and Firefox 50+. */ - if (client['isSubdomainIframe']) { - try { - Log.debug( - 'Client is subdomain iFrame. Attempting to focus() client.', - ); - if (client instanceof WindowClient) await client.focus(); - } catch (e) { - Log.error('Failed to focus:', client, e); - } - if (notificationOpensLink) { - Log.debug(`Redirecting HTTP site to ${launchUrl}.`); - await Database.putNotificationClickedEventPendingUrlOpening( - notificationClickEvent, - ); - ServiceWorker.workerMessenger.unicast( - WorkerMessengerCommand.RedirectPage, - launchUrl, - client, - ); - } else { - Log.debug('Not navigating because link is special.'); - } - } else if (client instanceof WindowClient && client.navigate) { + if (client instanceof WindowClient && client.navigate) { try { Log.debug( 'Client is standard HTTPS site. Attempting to focus() client.', diff --git a/src/sw/serviceWorker/types.ts b/src/sw/serviceWorker/types.ts index e0806e682..817f9b175 100644 --- a/src/sw/serviceWorker/types.ts +++ b/src/sw/serviceWorker/types.ts @@ -1,7 +1,3 @@ -export interface OSWindowClient extends WindowClient { - isSubdomainIframe: boolean; -} - export interface ClientStatus { timestamp: number; sentRequestsCount: number; From 9f4245784ef511668ae3fa1fa9e969b2342d88fb Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 01:25:11 +0000 Subject: [PATCH 15/35] remove all proxy frame classes --- src/onesignal/OneSignal.ts | 18 - src/onesignal/OneSignalEvents.ts | 6 - .../slidedownManager/SlidedownManager.ts | 8 +- src/page/models/MessengerMessageEvent.ts | 7 - .../models/SubscriptionPopupHostOptions.ts | 31 -- src/page/modules/frames/ProxyFrame.ts | 369 ------------------ src/page/modules/frames/ProxyFrameHost.ts | 281 ------------- src/page/modules/frames/RemoteFrame.ts | 116 ------ src/page/modules/frames/SubscriptionModal.ts | 24 -- .../modules/frames/SubscriptionModalHost.ts | 159 -------- src/page/modules/frames/SubscriptionPopup.ts | 54 --- .../modules/frames/SubscriptionPopupHost.ts | 280 ------------- src/shared/helpers/InitHelper.ts | 61 +-- src/shared/helpers/MainHelper.ts | 6 - src/shared/managers/CustomLinkManager.ts | 1 - src/shared/managers/ServiceWorkerManager.ts | 25 -- 16 files changed, 3 insertions(+), 1443 deletions(-) delete mode 100644 src/page/models/MessengerMessageEvent.ts delete mode 100644 src/page/models/SubscriptionPopupHostOptions.ts delete mode 100644 src/page/modules/frames/ProxyFrame.ts delete mode 100644 src/page/modules/frames/ProxyFrameHost.ts delete mode 100644 src/page/modules/frames/RemoteFrame.ts delete mode 100644 src/page/modules/frames/SubscriptionModal.ts delete mode 100644 src/page/modules/frames/SubscriptionModalHost.ts delete mode 100644 src/page/modules/frames/SubscriptionPopup.ts delete mode 100644 src/page/modules/frames/SubscriptionPopupHost.ts diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index 0bd3eefa8..8cfb86421 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -2,12 +2,6 @@ import { EnvironmentInfoHelper } from '../page/helpers/EnvironmentInfoHelper'; import ConfigManager from '../page/managers/ConfigManager'; import Context from '../page/models/Context'; import { EnvironmentInfo } from '../page/models/EnvironmentInfo'; -import ProxyFrame from '../page/modules/frames/ProxyFrame'; -import ProxyFrameHost from '../page/modules/frames/ProxyFrameHost'; -import SubscriptionModal from '../page/modules/frames/SubscriptionModal'; -import SubscriptionModalHost from '../page/modules/frames/SubscriptionModalHost'; -import SubscriptionPopup from '../page/modules/frames/SubscriptionPopup'; -import SubscriptionPopupHost from '../page/modules/frames/SubscriptionPopupHost'; import TimedLocalStorage from '../page/modules/TimedLocalStorage'; import { ProcessOneSignalPushCalls } from '../page/utils/ProcessOneSignalPushCalls'; import { SdkInitError, SdkInitErrorKind } from '../shared/errors/SdkInitError'; @@ -297,12 +291,6 @@ export default class OneSignal { static event = OneSignalEvent; private static pendingInit = true; - static subscriptionPopup: SubscriptionPopup; - static subscriptionPopupHost: SubscriptionPopupHost; - static subscriptionModal: SubscriptionModal; - static subscriptionModalHost: SubscriptionModalHost; - static proxyFrameHost: ProxyFrameHost; - static proxyFrame: ProxyFrame; static emitter: Emitter = new Emitter(); static cache: any = {}; static _LOGGING = false; @@ -321,12 +309,6 @@ export default class OneSignal { static Debug = new DebugNamespace(); /* END NEW USER MODEL CHANGES */ - /** - * Used by Rails-side HTTP popup. Must keep the same name. - * @InternalApi - */ - static _initPopup = () => OneSignal.subscriptionPopup.subscribe(); - static POSTMAM_COMMANDS = { CONNECTED: 'connect', REMOTE_NOTIFICATION_PERMISSION: 'postmam.remoteNotificationPermission', diff --git a/src/onesignal/OneSignalEvents.ts b/src/onesignal/OneSignalEvents.ts index 553febaf0..106c4a16e 100644 --- a/src/onesignal/OneSignalEvents.ts +++ b/src/onesignal/OneSignalEvents.ts @@ -1,10 +1,4 @@ export const ONESIGNAL_EVENTS = { - /** - * Occurs when the user clicks the "Continue" or "No Thanks" button on the HTTP popup or HTTPS modal prompt. - * For HTTP sites (and HTTPS sites using the modal prompt), this event is fired before the native permission - * prompt is shown. This event is mostly used for HTTP sites. - */ - CUSTOM_PROMPT_CLICKED: 'customPromptClick', /** * Occurs immediately when the notification permission changes for the domain at the browser level. * This normally happens when the user clicks "Allow" or "Block" on the native permission prompt diff --git a/src/page/managers/slidedownManager/SlidedownManager.ts b/src/page/managers/slidedownManager/SlidedownManager.ts index 69d044c9e..234957241 100644 --- a/src/page/managers/slidedownManager/SlidedownManager.ts +++ b/src/page/managers/slidedownManager/SlidedownManager.ts @@ -24,9 +24,7 @@ import PushPermissionNotGrantedError, { PushPermissionNotGrantedErrorReason, } from '../../../shared/errors/PushPermissionNotGrantedError'; import { DismissHelper } from '../../../shared/helpers/DismissHelper'; -import InitHelper, { - RegisterOptions, -} from '../../../shared/helpers/InitHelper'; +import InitHelper from '../../../shared/helpers/InitHelper'; import PromptsHelper from '../../../shared/helpers/PromptsHelper'; import Log from '../../../shared/libraries/Log'; import { DelayedPromptType } from '../../../shared/models/Prompts'; @@ -135,9 +133,7 @@ export class SlidedownManager { } private registerForPush(): void { - const autoAccept = !OneSignal.environmentInfo.requiresUserInteraction; - const options: RegisterOptions = { autoAccept, slidedown: true }; - InitHelper.registerForPushNotifications(options); + InitHelper.registerForPushNotifications(); } private async handleAllowForCategoryType(): Promise { diff --git a/src/page/models/MessengerMessageEvent.ts b/src/page/models/MessengerMessageEvent.ts deleted file mode 100644 index 0125952f0..000000000 --- a/src/page/models/MessengerMessageEvent.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface MessengerMessageEvent { - id: string; - command: string; - data: any; - source: string; - reply: (param: unknown) => void; -} diff --git a/src/page/models/SubscriptionPopupHostOptions.ts b/src/page/models/SubscriptionPopupHostOptions.ts deleted file mode 100644 index 465bf3105..000000000 --- a/src/page/models/SubscriptionPopupHostOptions.ts +++ /dev/null @@ -1,31 +0,0 @@ -interface SubscriptionPopupHostOptions { - /** - * Describes whether the first screen of the popup (asking users No Thanks or - * Continue) is shown. - * - * If true, this screen is skipped, and users see "Click Allow to receive - * notifications" with the prompt auto-appearing. - * - * If false or undefined, users see the first screen. - */ - autoAccept?: boolean; -} - -interface PromptOptionsPostData { - autoAcceptTitle?: string; - siteName?: string; - subscribeText?: string; - showGraphic?: boolean; - actionMessage?: string; - exampleNotificationTitle?: string; - exampleNotificationMessage?: string; - exampleNotificationCaption?: string; - acceptButton?: string; - cancelButton?: string; - timeout?: number; -} - -interface PostData extends PromptOptionsPostData, SubscriptionPopupHostOptions { - promptType: 'popup' | 'modal'; - parentHostname: string; -} diff --git a/src/page/modules/frames/ProxyFrame.ts b/src/page/modules/frames/ProxyFrame.ts deleted file mode 100644 index 601344158..000000000 --- a/src/page/modules/frames/ProxyFrame.ts +++ /dev/null @@ -1,369 +0,0 @@ -import OneSignalEvent from '../../../shared/services/OneSignalEvent'; -import SdkEnvironment from '../../../shared/managers/SdkEnvironment'; -import { MessengerMessageEvent } from '../../models/MessengerMessageEvent'; -import Postmam from '../../../shared/services/Postmam'; -import Database, { OneSignalDbTable } from '../../../shared/services/Database'; -import { unsubscribeFromPush } from '../../../shared/utils/utils'; -import RemoteFrame from './RemoteFrame'; -import Context from '../../models/Context'; -import { WorkerMessengerCommand } from '../../../shared/libraries/WorkerMessenger'; -import { DismissPrompt } from '../../models/Dismiss'; -import { - UpsertOrDeactivateSessionPayload, - PageVisibilityResponse, -} from '../../../shared/models/Session'; -import { DismissHelper } from '../../../shared/helpers/DismissHelper'; -import InitHelper from '../../../shared/helpers/InitHelper'; -import Log from '../../../shared/libraries/Log'; -import { AppConfig } from '../../../shared/models/AppConfig'; -/** - * The actual OneSignal proxy frame contents / implementation, that is loaded - * into the iFrame URL as subdomain.onesignal.com/webPushIFrame or - * subdomain.os.tc/webPushIFrame. * - */ -export default class ProxyFrame extends RemoteFrame { - public messenger: Postmam; - - /** - * Loads the messenger on the iFrame to communicate with the host page and - * assigns init options to an iFrame-only initialization of OneSignal. - * - * Our main host page will wait for all iFrame scripts to complete since the - * host page uses the iFrame onload event to begin sending handshake messages - * to the iFrame. - * - * There is no load timeout here; the iFrame initializes it scripts and waits - * forever for the first handshake message. - */ - initialize(): Promise { - const promise = super.initialize(); - OneSignalEvent.trigger('httpInitialize'); - return promise; - } - - establishCrossOriginMessaging() { - if (this.messenger) { - this.messenger.destroy(); - } - this.messenger = new Postmam( - window, - this.options.origin, - this.options.origin, - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.CONNECTED, - this.onMessengerConnect.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.IFRAME_POPUP_INITIALIZE, - this.onProxyFrameInitializing.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_NOTIFICATION_PERMISSION, - this.onRemoteNotificationPermission.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_GET, - this.onRemoteDatabaseGet.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_GET_ALL, - this.onRemoteDatabaseGetAll.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_PUT, - this.onRemoteDatabasePut.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_DATABASE_REMOVE, - this.onRemoteDatabaseRemove.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.UNSUBSCRIBE_FROM_PUSH, - this.onUnsubscribeFromPush.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.MARK_PROMPT_DISMISSED, - this.onMarkPromptDismissed.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.IS_SUBSCRIBED, - this.onIsSubscribed.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.UNSUBSCRIBE_PROXY_FRAME, - this.onUnsubscribeProxyFrame.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.SERVICE_WORKER_STATE, - this.onServiceWorkerState.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.GET_WORKER_VERSION, - this.onWorkerVersion.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.SUBSCRIPTION_EXPIRATION_STATE, - this.onSubscriptionExpirationState.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.PROCESS_EXPIRING_SUBSCRIPTIONS, - this.onProcessExpiringSubscriptions.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.GET_SUBSCRIPTION_STATE, - this.onGetSubscriptionState.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.SESSION_UPSERT, - this.onSessionUpsert.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.SESSION_DEACTIVATE, - this.onSessionDeactivate.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.ARE_YOU_VISIBLE_REQUEST, - this.onAreYouVisibleRequest.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.ARE_YOU_VISIBLE_RESPONSE, - this.onAreYouVisibleResponse.bind(this), - ); - this.messenger.listen(); - } - - retriggerRemoteEvent(eventName: string, eventData: any) { - this.messenger.message(OneSignal.POSTMAM_COMMANDS.REMOTE_RETRIGGER_EVENT, { - eventName, - eventData, - }); - } - - async onMessengerConnect(_: MessengerMessageEvent) { - Log.debug( - `(${SdkEnvironment.getWindowEnv().toString()}) Successfully established cross-origin communication.`, - ); - this.finishInitialization(); - return false; - } - - async onProxyFrameInitializing(message: MessengerMessageEvent) { - Log.info( - `(${SdkEnvironment.getWindowEnv().toString()}) The iFrame has just received initOptions from the host page!`, - ); - - const config: AppConfig = { - ...message.data.hostInitOptions, - ...OneSignal.config, - pageUrl: message.data.pageUrl, - }; - - OneSignal.config = config; - - InitHelper.installNativePromptPermissionChangedHook(); - - // 3/30/16: For HTTP sites, put the host page URL as default URL if one doesn't exist already - const defaultUrl = await Database.get('Options', 'defaultUrl'); - if (!defaultUrl) { - await Database.put('Options', { - key: 'defaultUrl', - value: new URL(OneSignal.config.pageUrl).origin, - }); - } - await InitHelper.initSaveState(); - await InitHelper.storeInitialValues(); - await InitHelper.saveInitOptions(); - - if (navigator.serviceWorker && window.location.protocol === 'https:') { - try { - const context: Context = OneSignal.context; - context.serviceWorkerManager.establishServiceWorkerChannel(); - } catch (e) { - Log.error( - `Error interacting with Service Worker inside an HTTP-hosted iFrame:`, - e, - ); - } - } - - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - } - - async onRemoteNotificationPermission(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const permission = - await context.permissionManager.getReportedNotificationPermission( - context.appConfig.safariWebId, - ); - message.reply(permission); - return false; - } - - async onRemoteDatabaseGet(message: MessengerMessageEvent) { - // retrievals is an array of key-value pairs e.g. [{table: 'Ids', keys: - // 'someId'}, {table: 'Ids', keys: 'someId'}] - const retrievals: Array<{ table: OneSignalDbTable; key: string }> = - message.data; - const retrievalOpPromises = []; - for (const retrieval of retrievals) { - const { table, key } = retrieval; - retrievalOpPromises.push(Database.get(table, key)); - } - const results = await Promise.all(retrievalOpPromises); - message.reply(results); - return false; - } - - async onRemoteDatabaseGetAll(message: MessengerMessageEvent) { - const table: OneSignalDbTable = message.data.table; - const results = await Database.getAll(table); - - message.reply(results); - return false; - } - - async onRemoteDatabasePut(message: MessengerMessageEvent) { - // insertions is an array of key-value pairs e.g. [table: {'Options': keypath: {key: persistNotification, value: '...'}}, {table: 'Ids', keypath: {type: 'userId', id: '...'}] - // It's formatted that way because our IndexedDB database is formatted that way - const insertions: Array<{ table: OneSignalDbTable; keypath: any }> = - message.data; - const insertionOpPromises = []; - for (const insertion of insertions) { - const { table, keypath } = insertion; - insertionOpPromises.push(Database.put(table, keypath)); - } - await Promise.all(insertionOpPromises); - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - return false; - } - - async onRemoteDatabaseRemove(message: MessengerMessageEvent) { - // removals is an array of key-value pairs e.g. [table: {'Options': keypath: {key: persistNotification, value: '...'}}, {table: 'Ids', keypath: {type: 'userId', id: '...'}] - // It's formatted that way because our IndexedDB database is formatted that way - const removals: Array<{ table: OneSignalDbTable; keypath: any }> = - message.data; - const removalOpPromises = []; - for (const removal of removals) { - const { table, keypath } = removal; - removalOpPromises.push(Database.remove(table, keypath)); - } - await Promise.all(removalOpPromises); - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - return false; - } - - async onUnsubscribeFromPush(message: MessengerMessageEvent) { - Log.debug( - '(Reposted from iFrame -> Host) User unsubscribed but permission granted. Re-prompting the user for push.', - ); - try { - await unsubscribeFromPush(); - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - } catch (e) { - Log.debug('Failed to unsubscribe from push remotely:', e); - } - } - - async onMarkPromptDismissed(message: MessengerMessageEvent) { - Log.debug('(Reposted from iFrame -> Host) Marking prompt as dismissed.'); - await DismissHelper.markPromptDismissedWithType(DismissPrompt.Push); - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - return false; - } - - async onIsSubscribed(message: MessengerMessageEvent) { - const isSubscribed = await OneSignal.isPushNotificationsEnabled(); - message.reply(isSubscribed); - return false; - } - - async onUnsubscribeProxyFrame(message: MessengerMessageEvent) { - const isSubscribed = await OneSignal.isPushNotificationsEnabled(); - if (isSubscribed) { - /* - Set a flag to prevent a notification from being sent from OneSignal's - side. The subscription stored locally on the browser is live and - messageable, but we can't query it or unsubscribe from it since we're on - an insecure origin. The most we can do is have our SDK delete the stored - information to pretend we're not subscribed on both the client SDK side - and the server side. - */ - // Set a flag remotely to prevent notifications from being sent - await OneSignal.User.PushSubscription.optOut(); - // Orphan the subscription by removing data stored about it - // This causes our SDK to think we're no longer subscribed on this frame - await OneSignal.database.rebuild(); - } - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - return false; - } - - async onServiceWorkerState(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const result = await context.serviceWorkerManager.getActiveState(); - message.reply(result); - return false; - } - - async onWorkerVersion(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const result = await context.serviceWorkerManager.getWorkerVersion(); - message.reply(result); - return false; - } - - async onSubscriptionExpirationState(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const result = await context.subscriptionManager.isSubscriptionExpiring(); - message.reply(result); - return false; - } - - async onProcessExpiringSubscriptions(message: MessengerMessageEvent) { - message.reply(OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE); - return false; - } - - async onGetSubscriptionState(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const result = await context.subscriptionManager.getSubscriptionState(); - message.reply(result); - return false; - } - - async onSessionUpsert(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const payload = message.data as UpsertOrDeactivateSessionPayload; - context.workerMessenger.directPostMessageToSW( - WorkerMessengerCommand.SessionUpsert, - payload, - ); - message.reply(true); - } - - async onSessionDeactivate(message: MessengerMessageEvent) { - const context: Context = OneSignal.context; - const payload = message.data as UpsertOrDeactivateSessionPayload; - context.workerMessenger.directPostMessageToSW( - WorkerMessengerCommand.SessionDeactivate, - payload, - ); - message.reply(true); - } - - async onAreYouVisibleRequest(message: MessengerMessageEvent) { - Log.debug('onAreYouVisibleRequest iframe', message); - } - - async onAreYouVisibleResponse(message: MessengerMessageEvent) { - Log.debug('onAreYouVisibleResponse iframe', message); - const context: Context = OneSignal.context; - const payload = message.data as PageVisibilityResponse; - context.workerMessenger.directPostMessageToSW( - WorkerMessengerCommand.AreYouVisibleResponse, - payload, - ); - message.reply(true); - } -} diff --git a/src/page/modules/frames/ProxyFrameHost.ts b/src/page/modules/frames/ProxyFrameHost.ts deleted file mode 100644 index 5d9fad6c0..000000000 --- a/src/page/modules/frames/ProxyFrameHost.ts +++ /dev/null @@ -1,281 +0,0 @@ -import Environment from '../../../shared/helpers/Environment'; -import OneSignalEvent from '../../../shared/services/OneSignalEvent'; -import { MessengerMessageEvent } from '../../models/MessengerMessageEvent'; -import Postmam from '../../../shared/services/Postmam'; -import { - timeoutPromise, - triggerNotificationPermissionChanged, - deepCopy, -} from '../../../shared/utils/utils'; -import { ServiceWorkerActiveState } from '../../../shared/helpers/ServiceWorkerHelper'; -import { PageVisibilityRequest } from '../../../shared/models/Session'; -import Log from '../../../shared/libraries/Log'; - -interface Reply { - data: any; -} -/** - * Manager for an instance of the OneSignal proxy frame, for use from the main - * page (not the iFrame itself). - * - * This is loaded as subdomain.onesignal.com/webPushIFrame or - * subdomain.os.tc/webPushIFrame. * - */ -export default class ProxyFrameHost implements OSDisposable { - public url: URL; - private element: HTMLIFrameElement; - private messenger: Postmam; - - // Promise to track whether the frame has finished loading - private loadPromise: { - promise: Promise; - resolver: (value?: unknown) => void; - rejector: (reason?: unknown) => void; - }; - - /** - * How long to wait to load the proxy frame before timing out. - */ - static get LOAD_TIMEOUT_MS() { - return 15000; - } - - /** - * - * @param origin The URL object describing the origin to load. - */ - constructor(origin: URL) { - this.url = origin; - this.url.pathname = 'webPushIframe'; - } - - /** - * Creates and loads an iFrame on the DOM, replacing any existing iFrame of - * the same URL. - * - * Rejects with a TimeoutError if the frame doesn't load within a specified time. - */ - async load(): Promise { - /* - This class removes existing iFrames with the same URL. This prevents - multiple iFrames to the same origin, which can cause issues with - cross-origin messaging. - */ - Log.debug('Opening an iFrame to', this.url.toString()); - this.removeFrame(); - - const iframe = document.createElement('iframe'); - iframe.style.display = 'none'; - iframe.src = this.url.toString(); - (iframe as any).sandbox = - 'allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation'; - (this as any).loadPromise = {}; - (this as any).loadPromise.promise = new Promise((resolve, reject) => { - this.loadPromise.resolver = resolve; - this.loadPromise.rejector = reject; - }); - document.body.appendChild(iframe); - iframe.onload = this.onFrameLoad.bind(this); - - this.element = iframe; - // Display a timeout warning if frame doesn't load in time, but don't prevent it from loading if the network is just slow - timeoutPromise( - this.loadPromise.promise, - ProxyFrameHost.LOAD_TIMEOUT_MS, - ).catch(() => { - if (window === window.top) { - Log.warn( - `OneSignal: Loading the required iFrame ${this.url.toString()} timed out. Check that the Site URL onesignal.com dashboard web config is ${ - location.origin - }. Only the Site URL specified there is allowed to use load the iFrame.`, - ); - } - }); - return this.loadPromise.promise; - } - - removeFrame() { - if (!Environment.isBrowser()) return; - - const existingInstance = document.querySelector( - `iframe[src='${this.url.toString()}']`, - ); - if (existingInstance) existingInstance.remove(); - } - - onFrameLoad(_: UIEvent): void { - this.establishCrossOriginMessaging(); - } - - establishCrossOriginMessaging() { - if (this.messenger) { - // Remove all previous events; window message events should not go to any previous listeners - this.messenger.destroy(); - } - this.messenger = new Postmam( - this.element.contentWindow, - this.url.toString(), - this.url.toString(), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.CONNECTED, - this.onMessengerConnect.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_RETRIGGER_EVENT, - this.onRemoteRetriggerEvent.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_NOTIFICATION_PERMISSION_CHANGED, - this.onRemoteNotificationPermissionChanged.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REQUEST_HOST_URL, - this.onRequestHostUrl.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.SERVICEWORKER_COMMAND_REDIRECT, - this.onServiceWorkerCommandRedirect.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.GET_EVENT_LISTENER_COUNT, - this.onGetEventListenerCount.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.ARE_YOU_VISIBLE_REQUEST, - this.onAreYouVisibleRequest.bind(this), - ); - this.messenger.connect(); - } - - dispose() { - // Removes all events - if (this.messenger) { - this.messenger.destroy(); - } - this.removeFrame(); - } - - async onMessengerConnect(_: MessengerMessageEvent) { - Log.debug( - `Successfully established cross-origin communication for iFrame at ${this.url.toString()}`, - ); - - this.messenger.message( - OneSignal.POSTMAM_COMMANDS.IFRAME_POPUP_INITIALIZE, - { - hostInitOptions: deepCopy(OneSignal.config), // Removes functions and unmessageable objects - pageUrl: window.location.href, - }, - (reply: Reply) => { - if ( - reply.data === OneSignal.POSTMAM_COMMANDS.REMOTE_OPERATION_COMPLETE - ) { - this.loadPromise.resolver(); - // This needs to be initialized so that isSubscribed() can be called to - // determine whether the user is subscribed to Frame A or B - //Event.trigger(OneSignal.EVENTS.SDK_INITIALIZED); - } - return false; - }, - ); - } - - onRemoteRetriggerEvent(message: MessengerMessageEvent) { - // e.g. { eventName: 'subscriptionChange', eventData: true} - const { eventName, eventData } = message.data as any; - OneSignalEvent.trigger(eventName, eventData, message.source); - return false; - } - - onRemoteNotificationPermissionChanged(message: MessengerMessageEvent) { - const { forceUpdatePermission } = message.data as any; - triggerNotificationPermissionChanged(forceUpdatePermission); - return false; - } - - onRequestHostUrl(message: MessengerMessageEvent) { - message.reply(location.href); - return false; - } - - onServiceWorkerCommandRedirect(message: MessengerMessageEvent) { - const url = message.data as any; - if (url && url.startsWith('http')) { - window.location.href = url; - } - return false; - } - - onGetEventListenerCount(message: MessengerMessageEvent) { - const eventName: string = message.data; - Log.debug( - '(Reposted from iFrame -> Host) Getting event listener count for ', - eventName, - ); - message.reply(OneSignal.emitter.numberOfListeners(eventName)); - return false; - } - - isSubscribed(): Promise { - return new Promise((resolve) => { - this.messenger.message( - OneSignal.POSTMAM_COMMANDS.IS_SUBSCRIBED, - null, - (reply: Reply) => { - resolve(reply.data); - }, - ); - }); - } - - unsubscribeFromPush(): Promise { - return new Promise((resolve) => { - this.messenger.message( - OneSignal.POSTMAM_COMMANDS.UNSUBSCRIBE_PROXY_FRAME, - null, - (_reply: Reply) => { - resolve(); - }, - ); - }); - } - - getProxyServiceWorkerActiveState() { - return new Promise((resolve, reject) => { - this.message( - OneSignal.POSTMAM_COMMANDS.SERVICE_WORKER_STATE, - null, - (reply: Reply) => { - resolve(reply.data); - }, - ); - }); - } - - async runCommand(command: string, payload: any = null): Promise { - const result = await new Promise((resolve, _reject) => { - this.message(command, payload, (reply: Reply) => { - resolve(reply.data as T); - }); - }); - return result; - } - - onAreYouVisibleRequest(event: { data: PageVisibilityRequest }) { - Log.debug('onAreYouVisibleRequest page', event); - const response = { - timestamp: event.data.timestamp, - focused: document.hasFocus(), - }; - this.message(OneSignal.POSTMAM_COMMANDS.ARE_YOU_VISIBLE_RESPONSE, response); - } - - /** - * Shortcut method to messenger.message(). - */ - message(..._) { - // eslint-disable-next-line prefer-spread, prefer-rest-params - this.messenger.message.apply(this.messenger, arguments); - } -} diff --git a/src/page/modules/frames/RemoteFrame.ts b/src/page/modules/frames/RemoteFrame.ts deleted file mode 100644 index 87ad408f8..000000000 --- a/src/page/modules/frames/RemoteFrame.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { ProxyFrameInitOptions } from '../../models/ProxyFrameInitOptions'; -import Postmam from '../../../shared/services/Postmam'; -import Context from '../../models/Context'; -import { EnvironmentInfoHelper } from '../../helpers/EnvironmentInfoHelper'; -import ConfigManager from '../../../page/managers/ConfigManager'; -import SubscriptionHelper from '../../../shared/helpers/SubscriptionHelper'; - -/* - These options are passed from the Rails app as plain raw untyped values. - They have to be converted to the right types. -*/ -export interface RemoteFrameOptions { - appId: string; - /* Passed to both the iFrame and popup */ - subdomainName: string; - /* Passed to both the iFrame and popup. Represents Site URL in dashboard config. */ - origin: string; - siteName: string; - /* These three flags may be deprecated */ - continuePressed?: boolean; - isPopup?: boolean; - isModal?: boolean; -} - -export default class RemoteFrame implements OSDisposable { - protected messenger: Postmam; - protected options: ProxyFrameInitOptions; - - // Promise to track whether connecting back to the host - // page has finished - private loadPromise: { - promise: Promise; - resolver: (value?: unknown) => void; - rejector: (reason?: unknown) => void; - }; - - constructor(initOptions: RemoteFrameOptions) { - this.options = { - appId: initOptions.appId, - subdomain: initOptions.subdomainName, - origin: initOptions.origin, - siteName: initOptions.siteName, - metrics: { - enable: false, - mixpanelReportingToken: null, - }, - userConfig: {}, - }; - } - - /** - * Loads the messenger on the iFrame to communicate with the host page and - * assigns init options to an iFrame-only initialization of OneSignal. - * - * Our main host page will wait for all iFrame scripts to complete since the - * host page uses the iFrame onload event to begin sending handshake messages - * to the iFrame. - * - * There is no load timeout here; the iFrame initializes it scripts and waits - * forever for the first handshake message. - */ - async initialize(): Promise { - const creator = window.opener || window.parent; - if (creator == window) { - document.write( - `OneSignal: This page cannot be directly opened, and must be opened as a result of a subscription call.`, - ); - return Promise.resolve(); - } - // The rest of our SDK isn't refactored enough yet to accept typed objects - // Within this class, we can use them, but when we assign them to - // OneSignal.config, assign the simple string versions - const rasterizedOptions = { ...this.options }; - /* This is necessary, otherwise the subdomain is lost after ConfigManager.getAppConfig */ - (rasterizedOptions as any).subdomainName = rasterizedOptions.subdomain; - OneSignal.config = rasterizedOptions || {}; - - const appConfig = await new ConfigManager().getAppConfig(rasterizedOptions); - OneSignal.environmentInfo = EnvironmentInfoHelper.getEnvironmentInfo(); - OneSignal.context = new Context(appConfig); - OneSignal.context.workerMessenger.listen(true); - - OneSignal.initialized = true; - - (this as any).loadPromise = {}; - (this as any).loadPromise.promise = new Promise((resolve, reject) => { - this.loadPromise.resolver = resolve; - this.loadPromise.rejector = reject; - }); - - return this.loadPromise.promise; - } - - dispose(): void { - // Removes all events - this.messenger.destroy(); - } - - protected finishInitialization() { - this.loadPromise.resolver(); - } - - async subscribe() { - const isPushEnabled = - await OneSignal.context.subscriptionManager.isPushNotificationsEnabled(); - const windowCreator = opener || parent; - - if (!isPushEnabled) { - SubscriptionHelper.registerForPush(); - } else { - if (windowCreator) { - window.close(); - } - } - } -} diff --git a/src/page/modules/frames/SubscriptionModal.ts b/src/page/modules/frames/SubscriptionModal.ts deleted file mode 100644 index 01e2c3ae6..000000000 --- a/src/page/modules/frames/SubscriptionModal.ts +++ /dev/null @@ -1,24 +0,0 @@ -import Postmam from '../../../shared/services/Postmam'; -import RemoteFrame from './RemoteFrame'; - -/** - * The actual OneSignal proxy frame contents / implementation, that is loaded - * into the iFrame URL as subdomain.onesignal.com/webPushIFrame or - * subdomain.os.tc/webPushIFrame. * - */ -export default class SubscriptionModal extends RemoteFrame { - constructor(initOptions: any) { - super(initOptions); - } - - establishCrossOriginMessaging() { - if (this.messenger) { - this.messenger.destroy(); - } - this.messenger = new Postmam( - window.parent, - this.options.origin, - this.options.origin, - ); - } -} diff --git a/src/page/modules/frames/SubscriptionModalHost.ts b/src/page/modules/frames/SubscriptionModalHost.ts deleted file mode 100644 index 4f876103e..000000000 --- a/src/page/modules/frames/SubscriptionModalHost.ts +++ /dev/null @@ -1,159 +0,0 @@ -import OneSignalEvent from '../../../shared/services/OneSignalEvent'; -import SdkEnvironment from '../../../shared/managers/SdkEnvironment'; -import { MessengerMessageEvent } from '../../models/MessengerMessageEvent'; -import Postmam from '../../../shared/services/Postmam'; -import MainHelper from '../../../shared/helpers/MainHelper'; -import SubscriptionHelper from '../../../shared/helpers/SubscriptionHelper'; -import Log from '../../../shared/libraries/Log'; - -/** - * The actual OneSignal proxy frame contents / implementation, that is loaded - * into the iFrame URL as subdomain.onesignal.com/webPushIFrame or - * subdomain.os.tc/webPushIFrame. * - */ -export default class SubscriptionModalHost implements OSDisposable { - private messenger: Postmam; - private appId: string; - private modal: HTMLIFrameElement; - private url: URL; - private registrationOptions: any; - - constructor(appId: string, registrationOptions: any) { - this.appId = appId; - this.registrationOptions = registrationOptions; - } - - /** - * Loads the messenger on the iFrame to communicate with the host page and - * assigns init options to an iFrame-only initialization of OneSignal. - * - * Our main host page will wait for all iFrame scripts to complete since the - * host page uses the iFrame onload event to begin sending handshake messages - * to the iFrame. - * - * There is no load timeout here; the iFrame initializes it scripts and waits - * forever for the first handshake message. - */ - async load(): Promise { - const isPushEnabled = - await OneSignal.context.subscriptionManager.isPushNotificationsEnabled(); - const notificationPermission = - await OneSignal.context.permissionManager.getPermissionStatus(); - this.url = SdkEnvironment.getOneSignalApiUrl(); - this.url.pathname = 'webPushModal'; - this.url.search = `${MainHelper.getPromptOptionsQueryString()}&id=${ - this.appId - }&httpsPrompt=true&pushEnabled=${isPushEnabled}&permissionBlocked=${ - (notificationPermission as any) === 'denied' - }&promptType=modal`; - Log.info( - `Loading iFrame for HTTPS subscription modal at ${this.url.toString()}`, - ); - - this.modal = this.createHiddenSubscriptionDomModal(this.url.toString()); - - this.establishCrossOriginMessaging(); - } - - createHiddenSubscriptionDomModal(url) { - const iframeContainer = document.createElement('div'); - iframeContainer.setAttribute('id', 'OneSignal-iframe-modal'); - iframeContainer.setAttribute('style', 'display:none !important'); - iframeContainer.innerHTML = - '
'; - document.body.appendChild(iframeContainer); - - const iframeContainerStyle = document.createElement('style'); - iframeContainerStyle.innerHTML = `@media (max-width: 560px) { .OneSignal-permission-iframe { width: 100%; height: 100%;} }`; - document.getElementsByTagName('head')[0].appendChild(iframeContainerStyle); - - const iframe = document.createElement('iframe'); - iframe.className = 'OneSignal-permission-iframe'; - iframe.setAttribute('frameborder', '0'); - iframe.width = OneSignal._windowWidth.toString(); - iframe.height = OneSignal._windowHeight.toString(); - iframe.src = url; - - document.getElementById('notif-permission').appendChild(iframe); - return iframe; - } - - removeFrame() { - const existingInstance = document.querySelector('#OneSignal-iframe-modal'); - if (existingInstance) { - existingInstance.remove(); - } - } - - showSubscriptionDomModal() { - const iframeContainer = document.getElementById('OneSignal-iframe-modal'); - iframeContainer.setAttribute('style', ''); - } - - establishCrossOriginMessaging() { - this.messenger = new Postmam(this.modal, this.url.origin, this.url.origin); - this.messenger.startPostMessageReceive(); - - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.MODAL_LOADED, - this.onModalLoaded.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.MODAL_PROMPT_ACCEPTED, - this.onModalAccepted.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.MODAL_PROMPT_REJECTED, - this.onModalRejected.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.POPUP_CLOSING, - this.onModalClosing.bind(this), - ); - } - - onModalLoaded(_: MessengerMessageEvent) { - this.showSubscriptionDomModal(); - OneSignalEvent.trigger('modalLoaded'); - } - - async onModalAccepted(_: MessengerMessageEvent) { - Log.debug('User accepted the HTTPS modal prompt.', location.origin); - OneSignal._sessionInitAlreadyRunning = false; - this.dispose(); - MainHelper.triggerCustomPromptClicked('granted'); - Log.debug('Calling setSubscription(true)'); - await SubscriptionHelper.registerForPush(); - await OneSignal.User.PushSubscription.optIn(); - } - - onModalRejected(_: MessengerMessageEvent) { - Log.debug('User rejected the HTTPS modal prompt.'); - OneSignal._sessionInitAlreadyRunning = false; - this.dispose(); - MainHelper.triggerCustomPromptClicked('denied'); - } - - onModalClosing(_: MessengerMessageEvent) { - Log.info('Detected modal is closing.'); - this.dispose(); - } - - dispose() { - if (this.messenger) { - // Removes all events - this.messenger.destroy(); - } - this.removeFrame(); - } - - /** - * Shortcut method to messenger.message(). - */ - message() { - // eslint-disable-next-line prefer-spread, prefer-rest-params - this.messenger.message.apply(this.messenger, arguments); - } -} diff --git a/src/page/modules/frames/SubscriptionPopup.ts b/src/page/modules/frames/SubscriptionPopup.ts deleted file mode 100644 index 4af1fd1a5..000000000 --- a/src/page/modules/frames/SubscriptionPopup.ts +++ /dev/null @@ -1,54 +0,0 @@ -import SdkEnvironment from '../../../shared/managers/SdkEnvironment'; -import { MessengerMessageEvent } from '../../models/MessengerMessageEvent'; -import Postmam from '../../../shared/services/Postmam'; -import RemoteFrame from './RemoteFrame'; -import Log from '../../../shared/libraries/Log'; - -/** - * The actual OneSignal proxy frame contents / implementation, that is loaded - * into the iFrame URL as subdomain.onesignal.com/webPushIFrame or - * subdomain.os.tc/webPushIFrame. * - */ -export default class SubscriptionPopup extends RemoteFrame { - constructor(initOptions: any) { - super(initOptions); - } - - /** - * Loads the messenger on the iFrame to communicate with the host page and - * assigns init options to an iFrame-only initialization of OneSignal. - * - * Our main host page will wait for all iFrame scripts to complete since the - * host page uses the iFrame onload event to begin sending handshake messages - * to the iFrame. - * - * There is no load timeout here; the iFrame initializes it scripts and waits - * forever for the first handshake message. - */ - // initialize() is implemented by base RemoteFrame class - - establishCrossOriginMessaging() { - this.messenger = new Postmam( - window.opener, - this.options.origin, - this.options.origin, - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.CONNECTED, - this.onMessengerConnected.bind(this), - ); - // The host page will receive this event, and then call connect() - this.messenger.postMessage( - OneSignal.POSTMAM_COMMANDS.POPUP_BEGIN_MESSAGEPORT_COMMS, - null, - ); - this.messenger.listen(); - } - - onMessengerConnected(_: MessengerMessageEvent) { - Log.debug( - `(${SdkEnvironment.getWindowEnv().toString()}) The host page is now ready to receive commands from the HTTP popup.`, - ); - this.finishInitialization(); - } -} diff --git a/src/page/modules/frames/SubscriptionPopupHost.ts b/src/page/modules/frames/SubscriptionPopupHost.ts deleted file mode 100644 index da976ce5c..000000000 --- a/src/page/modules/frames/SubscriptionPopupHost.ts +++ /dev/null @@ -1,280 +0,0 @@ -import OneSignalEvent from '../../../shared/services/OneSignalEvent'; -import SdkEnvironment from '../../../shared/managers/SdkEnvironment'; -import { MessengerMessageEvent } from '../../models/MessengerMessageEvent'; -import Postmam from '../../../shared/services/Postmam'; -import { SubscriptionManager } from '../../../shared/managers/SubscriptionManager'; -import Context from '../../models/Context'; -import EventHelper from '../../../shared/helpers/EventHelper'; -import MainHelper from '../../../shared/helpers/MainHelper'; -import Log from '../../../shared/libraries/Log'; -import { RawPushSubscription } from '../../../shared/models/RawPushSubscription'; - -/** - * Manager for an instance of the OneSignal proxy frame, for use from the main - * page (not the iFrame itself). - * - * This is loaded as subdomain.onesignal.com/webPushIFrame or - * subdomain.os.tc/webPushIFrame. * - */ -export default class SubscriptionPopupHost implements OSDisposable { - public url: URL; - private popupWindow: Window | undefined | null; - private messenger: Postmam | undefined; - private options: SubscriptionPopupHostOptions; - - // Promise to track whether the frame has finished loading - private loadPromise: { - promise: Promise; - resolver: (value?: unknown) => void; - rejector: (reason?: unknown) => void; - }; - - /** - * - * @param origin The URL object describing the origin to load. - */ - constructor(origin: URL, options?: SubscriptionPopupHostOptions) { - this.url = origin; - this.url.pathname = 'subscribe'; - this.options = options || {}; - } - - /** - * Opens a new Window to subscribe the user. - */ - load(): Promise { - // Instead of using URL query parameters, which are confusing and unsightly, - // post the data invisible - const postData: PostData = { - ...MainHelper.getPromptOptionsPostHash(), - ...{ - promptType: 'popup', - parentHostname: encodeURIComponent(location.hostname), - }, - }; - if (this.options.autoAccept) { - postData.autoAccept = true; - } - Log.info( - `Opening a popup to ${this.url.toString()} with POST data:`, - postData, - ); - this.popupWindow = this.openWindowViaPost( - this.url.toString(), - postData, - null, - ); - - this.establishCrossOriginMessaging(); - (this as any).loadPromise = {}; - (this as any).loadPromise.promise = new Promise((resolve, reject) => { - this.loadPromise.resolver = resolve; - this.loadPromise.rejector = reject; - }); - - // This can throw a TimeoutError, which should go up the stack - return this.loadPromise.promise; - } - - // Arguments : - // verb : 'GET'|'POST' - // target : an optional opening target (a name, or "_blank"), defaults to "_self" - openWindowViaPost(url: string, data, overrides) { - const form = document.createElement('form'); - form.action = url; - form.method = 'POST'; - form.target = 'onesignal-http-popup'; - - const dualScreenLeft = - window.screenLeft != undefined ? window.screenLeft : (screen as any).left; - const dualScreenTop = - window.screenTop != undefined ? window.screenTop : (screen as any).top; - const thisWidth = window.innerWidth - ? window.innerWidth - : document.documentElement.clientWidth - ? document.documentElement.clientWidth - : screen.width; - const thisHeight = window.innerHeight - ? window.innerHeight - : document.documentElement.clientHeight - ? document.documentElement.clientHeight - : screen.height; - let childWidth = OneSignal._windowWidth; - let childHeight = OneSignal._windowHeight; - let left = thisWidth / 2 - childWidth / 2 + dualScreenLeft; - let top = thisHeight / 2 - childHeight / 2 + dualScreenTop; - - if (overrides) { - if (overrides.childWidth) { - childWidth = overrides.childWidth; - } - if (overrides.childHeight) { - childHeight = overrides.childHeight; - } - if (overrides.left) { - left = overrides.left; - } - if (overrides.top) { - top = overrides.top; - } - } - const windowRef = window.open( - 'about:blank', - 'onesignal-http-popup', - `'scrollbars=yes, width=${childWidth}, height=${childHeight}, top=${top}, left=${left}`, - ); - - if (data) { - for (const key in data) { - const input = document.createElement('textarea'); - input.name = key; - input.value = - typeof data[key] === 'object' ? JSON.stringify(data[key]) : data[key]; - form.appendChild(input); - } - } - form.style.display = 'none'; - document.body.appendChild(form); - form.submit(); - document.body.removeChild(form); - - return windowRef; - } - - establishCrossOriginMessaging() { - this.messenger = new Postmam( - this.popupWindow, - this.url.toString(), - this.url.toString(), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.POPUP_BEGIN_MESSAGEPORT_COMMS, - this.onBeginMessagePortCommunications.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.POPUP_LOADED, - this.onPopupLoaded.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.POPUP_ACCEPTED, - this.onPopupAccepted.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.POPUP_REJECTED, - this.onPopupRejected.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.POPUP_CLOSING, - this.onPopupClosing.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.SET_SESSION_COUNT, - this.onSetSessionCount.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.WINDOW_TIMEOUT, - this.onWindowTimeout.bind(this), - ); - this.messenger.once( - OneSignal.POSTMAM_COMMANDS.FINISH_REMOTE_REGISTRATION, - this.onFinishingRegistrationRemotely.bind(this), - ); - this.messenger.on( - OneSignal.POSTMAM_COMMANDS.REMOTE_RETRIGGER_EVENT, - this.onRemoteRetriggerEvent.bind(this), - ); - this.messenger.startPostMessageReceive(); - } - - dispose() { - // Removes all events - this.messenger.destroy(); - } - - async onBeginMessagePortCommunications(_: MessengerMessageEvent) { - Log.debug( - `(${SdkEnvironment.getWindowEnv().toString()}) Successfully established cross-origin messaging with the popup window.`, - ); - this.messenger.connect(); - return false; - } - - async onPopupLoaded(_: MessengerMessageEvent) { - this.loadPromise.resolver(); - OneSignalEvent.trigger('popupLoad'); - } - - async onPopupAccepted(_: MessengerMessageEvent) { - MainHelper.triggerCustomPromptClicked('granted'); - } - - async onPopupRejected(_: MessengerMessageEvent) { - MainHelper.triggerCustomPromptClicked('denied'); - } - - async onPopupClosing(_: MessengerMessageEvent) { - Log.info('Popup window is closing, running cleanup events.'); - OneSignalEvent.trigger(OneSignal.EVENTS.POPUP_CLOSING); - this.dispose(); - } - - async onSetSessionCount(message: MessengerMessageEvent) { - Log.debug( - SdkEnvironment.getWindowEnv().toString() + - ' Marking current session as a continuing browsing session.', - ); - const { sessionCount }: { sessionCount: number } = message.data; - const context: Context = OneSignal.context; - context.pageViewManager.setPageViewCount(sessionCount); - } - - async onWindowTimeout(_: MessengerMessageEvent) { - Log.debug( - SdkEnvironment.getWindowEnv().toString() + - ' Popup window timed out and was closed.', - ); - OneSignalEvent.trigger(OneSignal.EVENTS.POPUP_WINDOW_TIMEOUT); - } - - async onFinishingRegistrationRemotely(message: MessengerMessageEvent) { - Log.debug( - location.origin, - SdkEnvironment.getWindowEnv().toString() + - ' Finishing HTTP popup registration inside the iFrame, sent from popup.', - ); - - message.reply({ progress: true }); - - const { - rawPushSubscription, - }: { rawPushSubscription: RawPushSubscription } = message.data; - - if (this.messenger) { - this.messenger.stopPostMessageReceive(); - } - - const subscriptionManager: SubscriptionManager = - OneSignal.context.subscriptionManager; - await subscriptionManager.registerSubscription(rawPushSubscription); - - await EventHelper.checkAndTriggerSubscriptionChanged(); - await MainHelper.checkAndTriggerNotificationPermissionChanged(); - } - - onRemoteRetriggerEvent(message: MessengerMessageEvent) { - // e.g. { eventName: 'subscriptionChange', eventData: true} - const { eventName, eventData } = message.data as any; - OneSignalEvent.trigger(eventName, eventData, message.source); - return false; - } - - /** - * Shortcut method to messenger.message(). - */ - message() { - if (this.messenger) { - // eslint-disable-next-line prefer-spread, prefer-rest-params - this.messenger.message.apply(this.messenger, arguments); - } - } -} diff --git a/src/shared/helpers/InitHelper.ts b/src/shared/helpers/InitHelper.ts index cf8c7aa65..ae3a0abf4 100755 --- a/src/shared/helpers/InitHelper.ts +++ b/src/shared/helpers/InitHelper.ts @@ -4,15 +4,11 @@ import { AppConfig } from '../models/AppConfig'; import MainHelper from './MainHelper'; import SubscriptionHelper from './SubscriptionHelper'; import { SdkInitError, SdkInitErrorKind } from '../errors/SdkInitError'; -import { WorkerMessengerCommand } from '../libraries/WorkerMessenger'; import { SubscriptionStrategyKind } from '../models/SubscriptionStrategyKind'; -import { Subscription } from '../models/Subscription'; import Log from '../libraries/Log'; import { CustomLinkManager } from '../managers/CustomLinkManager'; import Bell from '../../page/bell/Bell'; import { ContextInterface } from '../../page/models/Context'; -import SubscriptionModalHost from '../../page/modules/frames/SubscriptionModalHost'; -import SubscriptionPopupHost from '../../page/modules/frames/SubscriptionPopupHost'; import { DynamicResourceLoader } from '../../page/services/DynamicResourceLoader'; import Database from '../services/Database'; import LimitStore from '../services/LimitStore'; @@ -23,11 +19,6 @@ import { bowserCastle } from '../utils/bowserCastle'; declare let OneSignal: any; -export interface RegisterOptions extends SubscriptionPopupHostOptions { - modalPrompt?: boolean; - slidedown?: boolean; -} - export default class InitHelper { /** Main methods */ @@ -110,21 +101,7 @@ export default class InitHelper { await OneSignalEvent.trigger(OneSignal.EVENTS.SDK_INITIALIZED); } - // In-Addition to registering for push, this shows a native browser - // notification permission prompt, if needed. - public static async registerForPushNotifications( - options: RegisterOptions = {}, - ): Promise { - if (options && options.modalPrompt) { - /* Show the HTTPS fullscreen modal permission message. */ - OneSignal.subscriptionModalHost = new SubscriptionModalHost( - OneSignal.config.appId, - options, - ); - await OneSignal.subscriptionModalHost.load(); - return; - } - + public static async registerForPushNotifications(): Promise { await SubscriptionHelper.registerForPush(); } @@ -164,23 +141,6 @@ export default class InitHelper { await OneSignalEvent.trigger(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC); } - public static async loadSubscriptionPopup( - options?: SubscriptionPopupHostOptions, - ) { - /** - * Users may be subscribed to either .onesignal.com or .os.tc. By this time - * that they are subscribing to the popup, the Proxy Frame has already been - * loaded and the user's subscription status has been obtained. We can then - * use the Proxy Frame present now and check its URL to see whether the user - * is finally subscribed to .onesignal.com or .os.tc. - */ - OneSignal.subscriptionPopupHost = new SubscriptionPopupHost( - OneSignal.proxyFrameHost.url, - options, - ); - await OneSignal.subscriptionPopupHost.load(); - } - /** Helper methods */ public static async storeInitialValues() { @@ -249,25 +209,6 @@ export default class InitHelper { return true; } - public static async registerSubscriptionInProxyFrame( - context: ContextInterface, - ): Promise { - const newSubscription = await new Promise((resolve) => { - context.workerMessenger.once( - WorkerMessengerCommand.SubscribeNew, - (subscription) => { - resolve(Subscription.deserialize(subscription)); - }, - ); - context.workerMessenger.unicast( - WorkerMessengerCommand.SubscribeNew, - context.appConfig, - ); - }); - Log.debug('Finished registering brand new subscription:', newSubscription); - return newSubscription; - } - public static async doInitialize(): Promise { const promises: Promise[] = []; diff --git a/src/shared/helpers/MainHelper.ts b/src/shared/helpers/MainHelper.ts index 3d431b07a..6f22fc6e3 100755 --- a/src/shared/helpers/MainHelper.ts +++ b/src/shared/helpers/MainHelper.ts @@ -166,12 +166,6 @@ export default class MainHelper { return hash; } - static triggerCustomPromptClicked(clickResult) { - OneSignalEvent.trigger(OneSignal.EVENTS.CUSTOM_PROMPT_CLICKED, { - result: clickResult, - }); - } - static async getAppId(): Promise { if (OneSignal.config.appId) { return Promise.resolve(OneSignal.config.appId); diff --git a/src/shared/managers/CustomLinkManager.ts b/src/shared/managers/CustomLinkManager.ts index 900e0e14f..87deddd1c 100644 --- a/src/shared/managers/CustomLinkManager.ts +++ b/src/shared/managers/CustomLinkManager.ts @@ -4,7 +4,6 @@ import { CUSTOM_LINK_CSS_SELECTORS, } from '../slidedown/constants'; import { addCssClass } from '../utils/utils'; -import InitHelper, { RegisterOptions } from '../helpers/InitHelper'; import Log from '../libraries/Log'; import { AppUserConfigCustomLinkOptions } from '../models/Prompts'; diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index 2fd190465..6d49a5db3 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -6,7 +6,6 @@ import Database from '../services/Database'; import { WindowEnvironmentKind } from '../models/WindowEnvironmentKind'; import Log from '../libraries/Log'; import OneSignalEvent from '../services/OneSignalEvent'; -import ProxyFrame from '../../page/modules/frames/ProxyFrame'; import ServiceWorkerRegistrationError from '../errors/ServiceWorkerRegistrationError'; import OneSignalUtils from '../utils/OneSignalUtils'; import ServiceWorkerHelper, { @@ -321,19 +320,6 @@ export class ServiceWorkerManager { }, ); - workerMessenger.on(WorkerMessengerCommand.RedirectPage, (data) => { - Log.debug( - `${SdkEnvironment.getWindowEnv().toString()} Picked up command.redirect to ${data}, forwarding to host page.`, - ); - const proxyFrame: ProxyFrame = OneSignal.proxyFrame; - if (proxyFrame) { - proxyFrame.messenger.message( - OneSignal.POSTMAM_COMMANDS.SERVICEWORKER_COMMAND_REDIRECT, - data, - ); - } - }); - workerMessenger.on( WorkerMessengerCommand.NotificationDismissed, async (data) => { @@ -361,17 +347,6 @@ export class ServiceWorkerManager { WorkerMessengerCommand.AreYouVisibleResponse, payload, ); - } else { - const httpPayload: PageVisibilityRequest = { - timestamp: incomingPayload.timestamp, - }; - const proxyFrame: ProxyFrame | undefined = OneSignal.proxyFrame; - if (proxyFrame) { - proxyFrame.messenger.message( - OneSignal.POSTMAM_COMMANDS.ARE_YOU_VISIBLE_REQUEST, - httpPayload, - ); - } } }, ); From 1d1c6525097d32ec6e01216a75d4416a5535ab0a Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 01:48:19 +0000 Subject: [PATCH 16/35] rm HTTP logic from PermisionManager Remove all notification permission logic for HTTP / subdomain detection --- src/shared/managers/PermissionManager.ts | 187 ++----------------- src/shared/utils/LocalStorage.ts | 18 -- test/unit/managers/PermissionManager.ts | 219 ----------------------- 3 files changed, 13 insertions(+), 411 deletions(-) delete mode 100644 test/unit/managers/PermissionManager.ts diff --git a/src/shared/managers/PermissionManager.ts b/src/shared/managers/PermissionManager.ts index 55a7c0610..96ab5ca59 100644 --- a/src/shared/managers/PermissionManager.ts +++ b/src/shared/managers/PermissionManager.ts @@ -1,11 +1,8 @@ -import OneSignalUtils from '../utils/OneSignalUtils'; import { InvalidArgumentError, InvalidArgumentReason, } from '../errors/InvalidArgumentError'; import { NotificationPermission } from '../models/NotificationPermission'; -import SdkEnvironment from './SdkEnvironment'; -import LocalStorage from '../utils/LocalStorage'; import OneSignalError from '../errors/OneSignalError'; import Environment from '../helpers/Environment'; @@ -21,8 +18,6 @@ export default class PermissionManager { /** * Returns a promise that resolves to the browser's current notification permission as * 'default', 'granted', or 'denied'. - * @param callback A callback function that will be called when the browser's current notification permission - * has been obtained, with one of 'default', 'granted', or 'denied'. */ async getPermissionStatus(): Promise { if (!OneSignal.context) { @@ -31,92 +26,34 @@ export default class PermissionManager { ); } - const permission = - await OneSignal.context.permissionManager.getNotificationPermission( - OneSignal.config!.safariWebId, - ); - - return permission; + return await OneSignal.context.permissionManager.getNotificationPermission( + OneSignal.config!.safariWebId, + ); } /** - * Returns an interpreted version of the browser's notification permission. - * - * On some environments, it isn't possible to obtain the actual notification - * permission. For example, starting with Chrome 62+, cross-origin iframes and - * insecure origins can no longer accurately detect the default notification - * permission state. - * - * For cross-origin iframes, returned permissions are correct except that - * "denied" is returned instead of "default". - * - * For insecure origins, returned permissions are always "denied". This - * differs from cross-origin iframes where the cross-origin iframes are - * acurrate if returning "granted", but insecure origins will always return - * "denied" regardless of the actual permission. - * - * This method therefore returns the notification permission best suited for - * our SDK, and it may not always be accurate. On most environments (i.e. not - * Chrome 62+), the returned permission will be accurate. + * Notification permission reported by the browser. * * @param safariWebId The Safari web ID necessary to access the permission - * state on Safari. + * state on Legacy Safari on macOS. */ public async getNotificationPermission( safariWebId?: string, ): Promise { - const reportedPermission = - await this.getReportedNotificationPermission(safariWebId); - if (await this.isPermissionEnvironmentAmbiguous(reportedPermission)) - return await this.getInterpretedAmbiguousPermission(reportedPermission); - return reportedPermission; - } - - /** - * Returns the browser's actual notification permission as reported without any modifications. - * - * One challenge is determining the frame context our permission query needs to run in: - * - * - For a regular top-level HTTPS site, query our current top-level frame - * - * - For a custom web push setup in a child HTTPS iframe, query our current child iframe (even - * though the returned permission is ambiguous on Chrome 62+ if our origin is different from - * that of the top-level frame) - * - * - For a regular HTTP site, query OneSignal's child subdomain.os.tc or subdomain.onesignal.com - * iframe - * - * - For a regular HTTP site embedded in a child iframe, still query the nested child's - * OneSignal subdomain.os.tc or subdomain.onesignal.com iframe - * - * This simplifies into determining whether the web push setup is using OneSignal's subdomain. If - * not, we assume the current frame context, regardless of whether it is a child or top-level - * frame, is the current context to run the permission query in. - * - * @param safariWebId The Safari web ID necessary to access the permission state on Safari. - */ - public async getReportedNotificationPermission( - safariWebId?: string, - ): Promise { - if (Environment.useSafariLegacyPush()) - return PermissionManager.getSafariNotificationPermission(safariWebId); - - const reportedPermission: NotificationPermission = - this.getW3cNotificationPermission(); - - if (await this.isPermissionEnvironmentAmbiguous(reportedPermission)) { - return await this.getInterpretedAmbiguousPermission(reportedPermission); + if (Environment.useSafariLegacyPush()) { + return PermissionManager.getLegacySafariNotificationPermission( + safariWebId, + ); } - return this.getW3cNotificationPermission(); } /** * Returns the Safari browser's notification permission as reported by the browser. * - * @param safariWebId The Safari web ID necessary to access the permission state on Safari. + * @param safariWebId The Safari web ID necessary for Legacy Safari on macOS. */ - private static getSafariNotificationPermission( + private static getLegacySafariNotificationPermission( safariWebId?: string, ): NotificationPermission { if (safariWebId) @@ -126,108 +63,10 @@ export default class PermissionManager { } /** - * Returns the notification permission as reported by the browser for non-Safari browsers. This - * includes Chrome, Firefox, Opera, Yandex, and every browser following the Notification API - * standard. + * Returns the notification permission as reported by the browser. + * - Expect for legacy Safari on macOS. */ private getW3cNotificationPermission(): NotificationPermission { return Notification.permission as NotificationPermission; } - - /** - * To interpret the browser's reported notification permission, we need to know whether we're in - * an environment where the returned permission should be treated ambiguously. - * - * The reported permission should only be treated ambiguously if: - * - * - We're not on Safari or Firefox (Chromium, Chrome, Opera, and Yandex will all eventually - * share the same Chrome 62+ codebase) - * - * - And the reported permission is "denied" - * - * - And the current frame context is either a cross-origin iframe or insecure - */ - public async isPermissionEnvironmentAmbiguous( - permission: NotificationPermission, - ): Promise { - // For testing purposes, allows changing the browser user agent - const browser = OneSignalUtils.redetectBrowserUserAgent(); - - return ( - !browser.safari && - !browser.firefox && - permission === NotificationPermission.Denied && - (this.isCurrentFrameContextCrossOrigin() || - (await SdkEnvironment.isFrameContextInsecure())) - ); - } - - /** - * Returns true if we're a cross-origin iframe. - * - * This means: - * - * - We're not the top-level frame - * - We're unable to access to the top-level frame's origin, or we can access the origin but it - * is different. On most browsers, accessing the top-level origin should throw an exception. - */ - public isCurrentFrameContextCrossOrigin(): boolean { - let topFrameOrigin: string; - - try { - // Accessing a cross-origin top-level frame's origin should throw an error - topFrameOrigin = window.top.location.origin; - } catch (e) { - // We're in a cross-origin child iframe - return true; - } - - return window.top !== window && topFrameOrigin !== window.location.origin; - } - - /** - * To workaround Chrome 62+'s permission ambiguity for "denied" permissions, - * we assume the permission is "default" until we actually record the - * permission being "denied" or "granted". - * - * This allows our best-effort approach to subscribe new users, and upon - * subscribing, if we discover the actual permission to be denied, we record - * this for next time. - * - * @param reportedPermission The notification permission as reported by the - * browser without any modifications. - */ - public async getInterpretedAmbiguousPermission( - reportedPermission: NotificationPermission, - ) { - switch (reportedPermission) { - case NotificationPermission.Denied: { - const storedPermission = this.getStoredPermission(); - - if (storedPermission) { - // If we've recorded the last known actual browser permission, return that - return storedPermission; - } else { - // If we don't have any stored permission, assume default - return NotificationPermission.Default; - } - } - default: - return reportedPermission; - } - } - - public getStoredPermission(): NotificationPermission { - return LocalStorage.getStoredPermission(); - } - - public setStoredPermission(permission: NotificationPermission) { - LocalStorage.setStoredPermission(permission); - } - - public async updateStoredPermission() { - // TODO verify if `OneSignal.config.safariWebId` should be passed as a parameter - const permission = await this.getNotificationPermission(); - return this.setStoredPermission(permission); - } } diff --git a/src/shared/utils/LocalStorage.ts b/src/shared/utils/LocalStorage.ts index 8d77cad3b..e359721ca 100644 --- a/src/shared/utils/LocalStorage.ts +++ b/src/shared/utils/LocalStorage.ts @@ -24,24 +24,6 @@ export default class LocalStorage { return localStorage.getItem(REQUIRES_PRIVACY_CONSENT) === 'true'; } - public static setStoredPermission(value: NotificationPermission): void { - localStorage.setItem(PermissionManager.STORED_PERMISSION_KEY, value); - } - - public static getStoredPermission(): NotificationPermission { - const permission = - localStorage.getItem(PermissionManager.STORED_PERMISSION_KEY) || - 'default'; - switch (permission) { - case 'granted': - return NotificationPermission.Granted; - case 'denied': - return NotificationPermission.Denied; - default: - return NotificationPermission.Default; - } - } - public static setLocalPageViewCount(count: number): void { localStorage.setItem(PAGE_VIEWS, count.toString()); } diff --git a/test/unit/managers/PermissionManager.ts b/test/unit/managers/PermissionManager.ts deleted file mode 100644 index 652f3968c..000000000 --- a/test/unit/managers/PermissionManager.ts +++ /dev/null @@ -1,219 +0,0 @@ -import '../../support/polyfills/polyfills'; -import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, - BrowserUserAgent, -} from '../../support/sdk/TestEnvironment'; -import OneSignal from '../../../src/onesignal/OneSignal'; -import sinon from 'sinon'; -import Context from '../../../src/page/models/Context'; -import { NotificationPermission } from '../../../src/shared/models/NotificationPermission'; -import { setUserAgent } from '../../support/tester/browser'; -import Random from '../../support/tester/Random'; -import SdkEnvironment from '../../../src/shared/managers/SdkEnvironment'; - -test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); - - const appConfig = TestEnvironment.getFakeAppConfig(); - appConfig.appId = Random.getRandomUuid(); - OneSignal.context = new Context(appConfig); -}); - -test('should set and get stored permission correctly', async (t) => { - const permissionManager = OneSignal.context.permissionManager; - - // No existing stored permission should exist - t.is(permissionManager.getStoredPermission(), 'default'); - - permissionManager.setStoredPermission(NotificationPermission.Default); - t.is(permissionManager.getStoredPermission(), NotificationPermission.Default); -}); - -test('should interpret ambiguous browser permission correctly', async (t) => { - const permissionManager = OneSignal.context.permissionManager; - - // A reported permission of default is always accurate - t.is( - await permissionManager.getInterpretedAmbiguousPermission( - NotificationPermission.Default, - ), - NotificationPermission.Default, - ); - - // A reported permission of granted is always accurate - t.is( - await permissionManager.getInterpretedAmbiguousPermission( - NotificationPermission.Granted, - ), - NotificationPermission.Granted, - ); - - // A reported permission of denied, without any previously stored permission, should be assumed to - // be default - t.is(permissionManager.getStoredPermission(), 'default'); - t.is( - await permissionManager.getInterpretedAmbiguousPermission( - NotificationPermission.Denied, - ), - NotificationPermission.Default, - ); - - // A reported permission of denied, with a stored permission, should be assumed to be the stored - // permission (in this case default) - permissionManager.setStoredPermission(NotificationPermission.Default); - t.is( - await permissionManager.getInterpretedAmbiguousPermission( - NotificationPermission.Denied, - ), - NotificationPermission.Default, - ); - - // A reported permission of denied, with a stored permission, should be assumed to be the stored - // permission (in this case granted) - permissionManager.setStoredPermission(NotificationPermission.Granted); - t.is( - await permissionManager.getInterpretedAmbiguousPermission( - NotificationPermission.Denied, - ), - NotificationPermission.Granted, - ); - - // A reported permission of denied, with a stored permission, should be assumed to be the stored - // permission (in this case denied) - permissionManager.setStoredPermission(NotificationPermission.Denied); - t.is( - await permissionManager.getInterpretedAmbiguousPermission( - NotificationPermission.Denied, - ), - NotificationPermission.Denied, - ); -}); - -test('should detect an insecure top-level frame', async (t) => { - t.false(SdkEnvironment.isInsecureOrigin()); - - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - initializeAsIframe: false, - }); - t.true(SdkEnvironment.isInsecureOrigin()); -}); - -test('should detect a cross-origin frame-context', async (t) => { - const permissionManager = OneSignal.context.permissionManager; - - // Default test harness should mock a top-level frame - t.false(permissionManager.isCurrentFrameContextCrossOrigin()); - - // The test initializer will construct window.top as an inaccessible cross-origin frame - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - initializeAsIframe: true, - }); - t.true(permissionManager.isCurrentFrameContextCrossOrigin()); -}); - -test('should not detect an ambiguous permission environment', async (t) => { - const permissionManager = OneSignal.context.permissionManager; - - setUserAgent(BrowserUserAgent.FirefoxMacSupported); - t.false( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Denied, - ), - ); - - setUserAgent(BrowserUserAgent.SafariSupportedMac); - t.false( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Denied, - ), - ); - - setUserAgent(BrowserUserAgent.ChromeMacSupported); - t.false( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Granted, - ), - ); - t.false( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Default, - ), - ); - - const isCurrentFrameContextCrossOriginStub = sinon - .stub(permissionManager, 'isCurrentFrameContextCrossOrigin') - .returns(false); - const isFrameContextInsecureStub = sinon - .stub(SdkEnvironment, 'isFrameContextInsecure') - .resolves(false); - t.false( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Denied, - ), - ); - isCurrentFrameContextCrossOriginStub.restore(); - isFrameContextInsecureStub.restore(); -}); - -test('should use browser reported permission value in non-ambiguous environment for getNotificationPermission', async (t) => { - // Catches the case where getNotificationPermission doesn't wait on the isPermissionEnvironmentAmbiguous promise - const permissionManager = OneSignal.context.permissionManager; - (window as any).Notification.permission = 'denied'; - setUserAgent(BrowserUserAgent.FirefoxLinuxSupported); - - const isCurrentFrameContextCrossOriginStub = sinon - .stub(permissionManager, 'isCurrentFrameContextCrossOrigin') - .returns(false); - const isFrameContextInsecureStub = sinon - .stub(SdkEnvironment, 'isFrameContextInsecure') - .resolves(false); - t.deepEqual( - await permissionManager.getNotificationPermission(), - NotificationPermission.Denied, - ); - isCurrentFrameContextCrossOriginStub.restore(); - isFrameContextInsecureStub.restore(); -}); - -test('should detect an ambiguous permission environment', async (t) => { - const permissionManager = OneSignal.context.permissionManager; - - setUserAgent(BrowserUserAgent.OperaDesktopSupported); - - const isCurrentFrameContextCrossOriginStub = sinon - .stub(permissionManager, 'isCurrentFrameContextCrossOrigin') - .returns(true); - const isFrameContextInsecureStub = sinon - .stub(SdkEnvironment, 'isFrameContextInsecure') - .resolves(false); - t.true( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Denied, - ), - ); - isCurrentFrameContextCrossOriginStub.restore(); - isFrameContextInsecureStub.restore(); - - // Reverse false/true - { - const isCurrentFrameContextCrossOriginStub = sinon - .stub(permissionManager, 'isCurrentFrameContextCrossOrigin') - .returns(false); - const isFrameContextInsecureStub = sinon - .stub(SdkEnvironment, 'isFrameContextInsecure') - .resolves(true); - t.true( - await permissionManager.isPermissionEnvironmentAmbiguous( - NotificationPermission.Denied, - ), - ); - isCurrentFrameContextCrossOriginStub.restore(); - isFrameContextInsecureStub.restore(); - } -}); From 3cc2b05058892b4b2861c9c96ad479014ee281d6 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 01:59:00 +0000 Subject: [PATCH 17/35] rm isFrameContextInsecure This is no longer need and corrected related http checks to use window.isSecureContext instead. (as localhost is a secure context) --- src/shared/helpers/InitHelper.ts | 7 +------ src/shared/managers/SdkEnvironment.ts | 28 +-------------------------- 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/shared/helpers/InitHelper.ts b/src/shared/helpers/InitHelper.ts index ae3a0abf4..945e13dcc 100755 --- a/src/shared/helpers/InitHelper.ts +++ b/src/shared/helpers/InitHelper.ts @@ -1,5 +1,4 @@ import { NotificationPermission } from '../models/NotificationPermission'; -import SdkEnvironment from '../managers/SdkEnvironment'; import { AppConfig } from '../models/AppConfig'; import MainHelper from './MainHelper'; import SubscriptionHelper from './SubscriptionHelper'; @@ -176,11 +175,7 @@ export default class InitHelper { } protected static async establishServiceWorkerChannel(): Promise { - if ( - navigator.serviceWorker && - window.location.protocol === 'https:' && - !(await SdkEnvironment.isFrameContextInsecure()) - ) { + if (navigator.serviceWorker && window.isSecureContext) { try { await OneSignal.context.serviceWorkerManager.establishServiceWorkerChannel(); } catch (e) { diff --git a/src/shared/managers/SdkEnvironment.ts b/src/shared/managers/SdkEnvironment.ts index 4e86787c5..589727293 100644 --- a/src/shared/managers/SdkEnvironment.ts +++ b/src/shared/managers/SdkEnvironment.ts @@ -59,34 +59,8 @@ export default class SdkEnvironment { } } - /** - * From a child frame, returns true if the current frame context is insecure. - * - * This is used to check if isPushNotificationsEnabled() should grab the service worker - * registration. In an HTTPS iframe of an HTTP page, getting the service worker registration would - * throw an error. - * - * This method can trigger console warnings due to using ServiceWorkerContainer.getRegistration in - * an insecure frame. - */ - public static async isFrameContextInsecure() { - // If we are the top frame, or service workers aren't available, don't run this check - if ( - window === window.top || - !('serviceWorker' in navigator) || - typeof navigator.serviceWorker.getRegistration === 'undefined' - ) { - return false; - } - - // Will be null if there was an issue retrieving a status - const registrationResult = - await OneSignal.context.serviceWorkerManager.getRegistration(); - return !registrationResult; - } - public static isInsecureOrigin() { - return window.location.protocol === 'http:'; + return !window.isSecureContext; } static getOrigin(): string { From 964dbe7fe942e65ad15b2e09229ab4e8265ab477 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 02:00:18 +0000 Subject: [PATCH 18/35] rm MissingSubdomain --- src/shared/errors/SdkInitError.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shared/errors/SdkInitError.ts b/src/shared/errors/SdkInitError.ts index e6e765d4b..beca48063 100755 --- a/src/shared/errors/SdkInitError.ts +++ b/src/shared/errors/SdkInitError.ts @@ -3,7 +3,6 @@ import OneSignalError from './OneSignalError'; export enum SdkInitErrorKind { InvalidAppId, AppNotConfiguredForWebPush, - MissingSubdomain, WrongSiteUrl, MultipleInitialization, MissingSafariWebId, @@ -30,9 +29,6 @@ export class SdkInitError extends OneSignalError { `OneSignal: This app ID does not have any web platforms enabled. Double check your app` + ` ID, or see step 1 on our setup guide (https://tinyurl.com/2x5jzk83).`; break; - case SdkInitErrorKind.MissingSubdomain: - errorMessage = `Non-HTTPS pages require the subdomainName parameter within the label set within the OneSignal Web configuration (https://tinyurl.com/ry39x7mk).`; - break; case SdkInitErrorKind.WrongSiteUrl: if (extra && extra.siteUrl) { errorMessage = From 23ba387de170acf58872642b8e212e2712adb138 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 02:52:43 +0000 Subject: [PATCH 19/35] rm isHttps checks, this is already true now --- src/page/helpers/EnvironmentInfoHelper.ts | 7 ---- src/page/models/EnvironmentInfo.ts | 1 - src/shared/managers/ServiceWorkerManager.ts | 3 +- .../managers/sessionManager/SessionManager.ts | 39 +++---------------- src/shared/models/Session.ts | 1 - src/shared/utils/OneSignalUtils.ts | 4 -- 6 files changed, 6 insertions(+), 49 deletions(-) diff --git a/src/page/helpers/EnvironmentInfoHelper.ts b/src/page/helpers/EnvironmentInfoHelper.ts index 821563f26..6eece666a 100644 --- a/src/page/helpers/EnvironmentInfoHelper.ts +++ b/src/page/helpers/EnvironmentInfoHelper.ts @@ -15,7 +15,6 @@ export class EnvironmentInfoHelper { return { browserType: this.getBrowser(), browserVersion: this.getBrowserVersion(), - isHttps: this.isHttps(), isBrowserAndSupportsServiceWorkers: this.supportsServiceWorkers(), requiresUserInteraction: this.requiresUserInteraction(), osVersion: this.getOsVersion(), @@ -56,12 +55,6 @@ export class EnvironmentInfoHelper { return Utils.parseVersionString(bowserCastle().version); } - private static isHttps(): boolean { - return window - ? window.location && window.location.protocol === 'https:' - : false; - } - private static supportsServiceWorkers(): boolean { return window.navigator && 'serviceWorker' in window.navigator; } diff --git a/src/page/models/EnvironmentInfo.ts b/src/page/models/EnvironmentInfo.ts index 91d0d335a..e88fde0b5 100644 --- a/src/page/models/EnvironmentInfo.ts +++ b/src/page/models/EnvironmentInfo.ts @@ -4,7 +4,6 @@ import { Browser } from '../../shared/models/Browser'; export interface EnvironmentInfo { browserType: Browser; browserVersion: number; - isHttps: boolean; isBrowserAndSupportsServiceWorkers: boolean; requiresUserInteraction: boolean; osVersion: string | number; diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index 6d49a5db3..309951e86 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -330,7 +330,6 @@ export class ServiceWorkerManager { }, ); - const isHttps = OneSignalUtils.isHttps(); const isSafari = OneSignalUtils.isSafari(); workerMessenger.on( @@ -338,7 +337,7 @@ export class ServiceWorkerManager { async (incomingPayload: PageVisibilityRequest) => { // For https sites in Chrome and Firefox service worker (SW) can get correct value directly. // For Safari, unfortunately, we need this messaging workaround because SW always gets false. - if (isHttps && isSafari) { + if (isSafari) { const payload: PageVisibilityResponse = { timestamp: incomingPayload.timestamp, focused: document.hasFocus(), diff --git a/src/shared/managers/sessionManager/SessionManager.ts b/src/shared/managers/sessionManager/SessionManager.ts index 0f4a7a796..3033d8f4b 100644 --- a/src/shared/managers/sessionManager/SessionManager.ts +++ b/src/shared/managers/sessionManager/SessionManager.ts @@ -30,8 +30,6 @@ export class SessionManager implements ISessionManager { subscriptionId: string, sessionOrigin: SessionOrigin, ): Promise { - const isHttps = OneSignalUtils.isHttps(); - const payload: UpsertOrDeactivateSessionPayload = { onesignalId, subscriptionId, @@ -39,7 +37,6 @@ export class SessionManager implements ISessionManager { sessionThreshold: this.context.appConfig.sessionThreshold || 0, enableSessionDuration: !!this.context.appConfig.enableSessionDuration, sessionOrigin, - isHttps, isSafari: OneSignalUtils.isSafari(), outcomesConfig: this.context.appConfig.userConfig.outcomes!, }; @@ -61,8 +58,6 @@ export class SessionManager implements ISessionManager { subscriptionId: string, sessionOrigin: SessionOrigin, ): Promise { - const isHttps = OneSignalUtils.isHttps(); - const payload: UpsertOrDeactivateSessionPayload = { appId: this.context.appConfig.appId, subscriptionId, @@ -70,7 +65,6 @@ export class SessionManager implements ISessionManager { sessionThreshold: this.context.appConfig.sessionThreshold!, enableSessionDuration: this.context.appConfig.enableSessionDuration!, sessionOrigin, - isHttps, isSafari: OneSignalUtils.isSafari(), outcomesConfig: this.context.appConfig.userConfig.outcomes!, }; @@ -183,7 +177,6 @@ export class SessionManager implements ISessionManager { try { // don't have much time on before unload // have to skip adding device record to the payload - const isHttps = OneSignalUtils.isHttps(); const { onesignalId, subscriptionId } = await this._getOneSignalAndSubscriptionIds(); const payload: UpsertOrDeactivateSessionPayload = { @@ -193,26 +186,15 @@ export class SessionManager implements ISessionManager { sessionThreshold: this.context.appConfig.sessionThreshold!, enableSessionDuration: this.context.appConfig.enableSessionDuration!, sessionOrigin: SessionOrigin.BeforeUnload, - isHttps, isSafari: OneSignalUtils.isSafari(), outcomesConfig: this.context.appConfig.userConfig.outcomes!, }; - if (isHttps) { - Log.debug('Notify SW to deactivate session (beforeunload)'); - this.context.workerMessenger.directPostMessageToSW( - WorkerMessengerCommand.SessionDeactivate, - payload, - ); - } else { - Log.debug( - 'Notify iframe to notify SW to deactivate session (beforeunload)', - ); - await OneSignal.proxyFrameHost.runCommand( - OneSignal.POSTMAM_COMMANDS.SESSION_DEACTIVATE, - payload, - ); - } + Log.debug('Notify SW to deactivate session (beforeunload)'); + this.context.workerMessenger.directPostMessageToSW( + WorkerMessengerCommand.SessionDeactivate, + payload, + ); } catch (e) { Log.error('Error handling onbeforeunload:', e); } @@ -352,17 +334,6 @@ export class SessionManager implements ISessionManager { } } - static setupSessionEventListenersForHttp(): void { - if (!OneSignal.context || !OneSignal.context.sessionManager) { - Log.error( - 'OneSignal.context not available for http to setup session event listeners.', - ); - return; - } - - OneSignal.context.sessionManager.setupSessionEventListeners(); - } - // If user has been subscribed before, send the on_session update to our backend on the first page view. async sendOnSessionUpdateFromPage(): Promise { const earlyReturn = diff --git a/src/shared/models/Session.ts b/src/shared/models/Session.ts index 6c5946e0e..9b12e9acc 100644 --- a/src/shared/models/Session.ts +++ b/src/shared/models/Session.ts @@ -37,7 +37,6 @@ interface BaseSessionPayload { sessionThreshold: number; enableSessionDuration: boolean; sessionOrigin: SessionOrigin; - isHttps: boolean; isSafari: boolean; outcomesConfig: OutcomesConfig; } diff --git a/src/shared/utils/OneSignalUtils.ts b/src/shared/utils/OneSignalUtils.ts index 45accda64..9cd8bd7e1 100644 --- a/src/shared/utils/OneSignalUtils.ts +++ b/src/shared/utils/OneSignalUtils.ts @@ -58,10 +58,6 @@ export class OneSignalUtils { ); } - static isHttps(): boolean { - return window.location.protocol === 'https:'; - } - static isSafari(): boolean { return Environment.isBrowser() && typeof window.safari !== 'undefined'; } From d4211ea61e3167079dbf6d05a7968f676880d179 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 02:55:30 +0000 Subject: [PATCH 20/35] rm HttpHttpsEnvironment from tests This is always HTTPS now as HTTP is no longer supported. --- __test__/support/environment/TestContext.ts | 32 +- .../support/environment/TestEnvironment.ts | 1 - .../environment/TestEnvironmentHelpers.ts | 24 +- .../support/models/HttpHttpsEnvironment.ts | 4 - __test__/unit/helpers/configHelper.test.ts | 6 +- __test__/unit/helpers/initHelper.test.ts | 8 - __test__/unit/helpers/mainHelper.test.ts | 5 +- __test__/unit/push/registerForPush.test.ts | 2 - test/support/tester/utils.ts | 6 - test/unit/helpers/ConverterHelper.ts | 9 +- test/unit/helpers/DismissHelper.ts | 2 - test/unit/helpers/MainHelper.ts | 9 +- test/unit/helpers/ServiceWorkerHelper.ts | 6 +- test/unit/managers/ConfigManager.ts | 9 +- test/unit/managers/MetricsManager.ts | 9 +- test/unit/managers/PageViewManager.ts | 9 +- test/unit/managers/ServiceWorkerManager.ts | 42 +-- test/unit/managers/SessionManager.ts | 6 +- test/unit/managers/SubscriptionManager.ts | 5 +- test/unit/managers/UpdateManager.ts | 6 +- test/unit/meta/mockPushManager.ts | 9 +- test/unit/meta/mockServiceWorker.ts | 9 +- .../mockServiceWorkerContainerWithAPIBan.ts | 9 +- test/unit/modules/entryInitialization.ts | 9 +- test/unit/modules/loadSdkStyles.ts | 6 - test/unit/modules/postmam.ts | 9 +- test/unit/modules/subscriptionHelper.ts | 9 +- test/unit/modules/timedLocalStorage.ts | 21 +- .../ChannelCaptureContainer.ts | 3 - test/unit/prompts/ConfirmationToast.ts | 2 - test/unit/prompts/CustomLink.ts | 6 +- test/unit/prompts/DelayedPrompts.ts | 2 - test/unit/prompts/Slidedown.ts | 5 +- .../SlidedownPrompting/SlidedownPrompting.ts | 2 - test/unit/prompts/TaggingContainer.ts | 2 - test/unit/public-sdk-apis/init.ts | 9 +- test/unit/public-sdk-apis/onSession.ts | 324 ------------------ 37 files changed, 48 insertions(+), 588 deletions(-) delete mode 100644 __test__/support/models/HttpHttpsEnvironment.ts diff --git a/__test__/support/environment/TestContext.ts b/__test__/support/environment/TestContext.ts index 589c9ec78..ba8458498 100644 --- a/__test__/support/environment/TestContext.ts +++ b/__test__/support/environment/TestContext.ts @@ -11,18 +11,16 @@ import { DelayedPromptType } from '../../../src/shared/models/Prompts'; import { APP_ID } from '../constants'; import deepmerge from 'deepmerge'; import ConfigManager from '../../../src/page/managers/ConfigManager'; -import { HttpHttpsEnvironment } from '../models/HttpHttpsEnvironment'; import { TestEnvironmentConfig } from './TestEnvironment'; export default class TestContext { static getFakeServerAppConfig( configIntegrationKind: ConfigIntegrationKind, - isHttps = true, overrideServerConfig: RecursivePartial | null = null, appId: string = APP_ID, ): ServerAppConfig { if (configIntegrationKind === ConfigIntegrationKind.Custom) { - const customConfigHttps: ServerAppConfig = { + return { success: true, version: 2, app_id: appId, @@ -172,31 +170,6 @@ export default class TestContext { }, generated_at: 1531177265, }; - if (isHttps) { - return customConfigHttps; - } - return { - ...customConfigHttps, - config: { - ...customConfigHttps.config, - subdomain: 'helloworld123', - origin: 'http://localhost:3000', - siteInfo: { - name: 'localhost http', - origin: 'http://localhost:3000', - proxyOrigin: 'helloworld123', - defaultIconUrl: null, - proxyOriginEnabled: true, - }, - welcomeNotification: { - enable: true, - url: 'http://localhost:3000/?_osp=do_not_open', - title: 'localhost http', - message: 'Thanks for subscribing!', - urlEnabled: false, - }, - }, - }; } const remoteConfigMockDefaults: ServerAppConfig = { @@ -495,9 +468,6 @@ export default class TestContext { const fakeUserConfig = config.userConfig || this.getFakeAppUserConfig(); const fakeServerConfig = this.getFakeServerAppConfig( config.integration || ConfigIntegrationKind.Custom, - config.httpOrHttps - ? config.httpOrHttps === HttpHttpsEnvironment.Https - : undefined, config.overrideServerConfig, ); const configManager = new ConfigManager(); diff --git a/__test__/support/environment/TestEnvironment.ts b/__test__/support/environment/TestEnvironment.ts index fbec0db38..1582798e8 100644 --- a/__test__/support/environment/TestEnvironment.ts +++ b/__test__/support/environment/TestEnvironment.ts @@ -37,7 +37,6 @@ export interface TestEnvironmentConfig { url?: string; initializeAsIframe?: boolean; userAgent?: BrowserUserAgent; - httpOrHttps?: HttpHttpsEnvironment; overrideServerConfig?: RecursivePartial; integration?: ConfigIntegrationKind; useMockIdentityModel?: boolean; diff --git a/__test__/support/environment/TestEnvironmentHelpers.ts b/__test__/support/environment/TestEnvironmentHelpers.ts index 5b0493d0c..0617b96e2 100644 --- a/__test__/support/environment/TestEnvironmentHelpers.ts +++ b/__test__/support/environment/TestEnvironmentHelpers.ts @@ -83,15 +83,7 @@ export async function stubDomEnvironment(config: TestEnvironmentConfig) { config = {}; } - let url: string | undefined = undefined; - let isSecureContext: boolean | undefined = undefined; - if (config.httpOrHttps == HttpHttpsEnvironment.Http) { - url = 'http://localhost:3000/webpush/sandbox?http=1'; - isSecureContext = false; - } else { - url = 'https://localhost:3001/webpush/sandbox?https=1'; - isSecureContext = true; - } + let url = 'https://localhost:3001/webpush/sandbox?https=1'; if (config.url) { url = config.url.toString(); @@ -129,24 +121,14 @@ export async function stubDomEnvironment(config: TestEnvironmentConfig) { new MockServiceWorkerContainerWithAPIBan(); // (windowDef as any).TextEncoder = TextEncoder; // (windowDef as any).TextDecoder = TextDecoder; - (windowDef as any).isSecureContext = isSecureContext; (windowDef as any).location = url; addCustomEventPolyfill(windowDef); - const windowTop: DOMWindow = config.initializeAsIframe - ? ({ - location: { - get origin() { - throw new Error( - "SecurityError: Permission denied to access property 'origin' on cross-origin object", - ); - }, - }, - } as any) - : windowDef; + const windowTop: DOMWindow = windowDef; dom.reconfigure({ url, windowTop }); global.window = windowDef; + global.window.isSecureContext = true; global.document = windowDef.document; return dom; } diff --git a/__test__/support/models/HttpHttpsEnvironment.ts b/__test__/support/models/HttpHttpsEnvironment.ts deleted file mode 100644 index 42ac5a041..000000000 --- a/__test__/support/models/HttpHttpsEnvironment.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum HttpHttpsEnvironment { - Http, - Https, -} diff --git a/__test__/unit/helpers/configHelper.test.ts b/__test__/unit/helpers/configHelper.test.ts index cdfdacf72..c854e89b5 100644 --- a/__test__/unit/helpers/configHelper.test.ts +++ b/__test__/unit/helpers/configHelper.test.ts @@ -4,17 +4,13 @@ import { } from '../../../src/shared/models/AppConfig'; import { getRandomUuid } from '../../../src/shared/utils/utils'; import { TestEnvironment } from '../../support/environment/TestEnvironment'; -import { HttpHttpsEnvironment } from '../../support/models/HttpHttpsEnvironment'; import { getFinalAppConfig } from '../../support/helpers/configHelper'; import { ConfigHelper } from '../../../src/shared/helpers/ConfigHelper'; -import OneSignalUtils from '../../../src/shared/utils/OneSignalUtils'; import TestContext from '../../support/environment/TestContext'; describe('ConfigHelper Tests', () => { beforeEach(async () => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); test.stub(ConfigHelper, 'checkRestrictedOrigin'); }); diff --git a/__test__/unit/helpers/initHelper.test.ts b/__test__/unit/helpers/initHelper.test.ts index d90b99a99..8fe272ded 100644 --- a/__test__/unit/helpers/initHelper.test.ts +++ b/__test__/unit/helpers/initHelper.test.ts @@ -13,14 +13,6 @@ describe('InitHelper', () => { jest.restoreAllMocks(); }); - /** registerForPushNotifications */ - test('registerForPushNotifications: requesting a modal prompt', async () => { - await InitHelper.registerForPushNotifications({ modalPrompt: true }); - - expect(OneSignal.subscriptionModalHost).not.toBeUndefined(); - expect(OneSignal.subscriptionModalHost.modal).not.toBeUndefined(); - }); - /** onSdkInitialized */ test('onSdkInitialized: ensure public sdk initialized triggered', async () => { OneSignal.emitter.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { diff --git a/__test__/unit/helpers/mainHelper.test.ts b/__test__/unit/helpers/mainHelper.test.ts index 9e14547f9..cc6ab090e 100644 --- a/__test__/unit/helpers/mainHelper.test.ts +++ b/__test__/unit/helpers/mainHelper.test.ts @@ -1,15 +1,12 @@ import MainHelper from '../../../src/shared/helpers/MainHelper'; import { SubscriptionStateKind } from '../../../src/shared/models/SubscriptionStateKind'; -import { HttpHttpsEnvironment } from '../../support/models/HttpHttpsEnvironment'; import { TestEnvironment } from '../../support/environment/TestEnvironment'; import { NotificationPermission } from '../../../src/shared/models/NotificationPermission'; describe('MainHelper Tests', () => { beforeEach(async () => { jest.useFakeTimers(); - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); }); afterEach(() => { diff --git a/__test__/unit/push/registerForPush.test.ts b/__test__/unit/push/registerForPush.test.ts index 576f132a6..76080a535 100644 --- a/__test__/unit/push/registerForPush.test.ts +++ b/__test__/unit/push/registerForPush.test.ts @@ -1,4 +1,3 @@ -import { HttpHttpsEnvironment } from '../../support/models/HttpHttpsEnvironment'; import { TestEnvironment } from '../../support/environment/TestEnvironment'; import InitHelper from '../../../src/shared/helpers/InitHelper'; import OneSignalEvent from '../../../src/shared/services/OneSignalEvent'; @@ -12,7 +11,6 @@ describe('Register for push', () => { jest.useFakeTimers(); await TestEnvironment.initialize({ addPrompts: true, - httpOrHttps: HttpHttpsEnvironment.Https, userAgent: BrowserUserAgent.Default, }); }); diff --git a/test/support/tester/utils.ts b/test/support/tester/utils.ts index f5c16c63d..b6b212924 100644 --- a/test/support/tester/utils.ts +++ b/test/support/tester/utils.ts @@ -4,7 +4,6 @@ import OneSignalApi from '../../../src/shared/api/OneSignalApi'; import { TestEnvironment, TestEnvironmentConfig, - HttpHttpsEnvironment, } from '../../support/sdk/TestEnvironment'; import { ServerAppConfig } from '../../../src/shared/models/AppConfig'; import Random from '../../support/tester/Random'; @@ -60,15 +59,10 @@ export class InitTestHelper { OneSignal.initialized = false; this.sinonSandbox.stub(document, 'visibilityState').value('visible'); - - const isHttps = testEnvironmentConfig.httpOrHttps - ? testEnvironmentConfig.httpOrHttps == HttpHttpsEnvironment.Https - : undefined; const serverAppConfig = customServerAppConfig || TestEnvironment.getFakeServerAppConfig( testEnvironmentConfig.integration!, - isHttps, ); this.stubJSONP(serverAppConfig); this.sinonSandbox.stub(OneSignalApiBase, 'get').resolves({}); diff --git a/test/unit/helpers/ConverterHelper.ts b/test/unit/helpers/ConverterHelper.ts index ad99b6a76..1100577eb 100644 --- a/test/unit/helpers/ConverterHelper.ts +++ b/test/unit/helpers/ConverterHelper.ts @@ -1,9 +1,6 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { AppUserConfig } from '../../../src/shared/models/AppConfig'; import Random from '../../support/tester/Random'; import { @@ -17,9 +14,7 @@ import PromptsHelper from '../../../src/shared/helpers/PromptsHelper'; const sandbox: SinonSandbox = sinon.sandbox.create(); test.beforeEach(async () => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); }); test.afterEach(() => { diff --git a/test/unit/helpers/DismissHelper.ts b/test/unit/helpers/DismissHelper.ts index c743ce5c3..9feaa45e1 100644 --- a/test/unit/helpers/DismissHelper.ts +++ b/test/unit/helpers/DismissHelper.ts @@ -4,7 +4,6 @@ import { ConfigIntegrationKind } from '../../../src/shared/models/AppConfig'; import { NotificationPermission } from '../../../src/shared/models/NotificationPermission'; import { TestEnvironmentConfig, - HttpHttpsEnvironment, TestEnvironment, } from '../../support/sdk/TestEnvironment'; import EventsTestHelper from '../../support/tester/EventsTestHelper'; @@ -42,7 +41,6 @@ test.afterEach(function (_t: ExecutionContext) { }); const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Default, pushIdentifier: 'granted', diff --git a/test/unit/helpers/MainHelper.ts b/test/unit/helpers/MainHelper.ts index 6436f7a0a..29db9c9db 100644 --- a/test/unit/helpers/MainHelper.ts +++ b/test/unit/helpers/MainHelper.ts @@ -2,19 +2,14 @@ import test, { ExecutionContext } from 'ava'; import sinon, { SinonSandbox } from 'sinon'; import { NotificationPermission } from '../../../src/shared/models/NotificationPermission'; import { SubscriptionStateKind } from '../../../src/shared/models/SubscriptionStateKind'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import MainHelper from '../../../src/shared/helpers/MainHelper'; let sinonSandbox: SinonSandbox; test.beforeEach(async () => { sinonSandbox = sinon.sandbox.create(); - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); // Required for sessionContext, not async TestEnvironment.mockInternalOneSignal(); diff --git a/test/unit/helpers/ServiceWorkerHelper.ts b/test/unit/helpers/ServiceWorkerHelper.ts index a1370d31e..cf2083928 100644 --- a/test/unit/helpers/ServiceWorkerHelper.ts +++ b/test/unit/helpers/ServiceWorkerHelper.ts @@ -1,8 +1,5 @@ import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { NotificationPermission } from '../../../src/shared/models/NotificationPermission'; import { setupFakePlayerId } from '../../support/tester/utils'; import { NockOneSignalHelper } from '../../support/tester/NockOneSignalHelper'; @@ -18,7 +15,6 @@ import { test.beforeEach(async (t) => { await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, permission: NotificationPermission.Granted, }); TestEnvironment.mockInternalOneSignal(); diff --git a/test/unit/managers/ConfigManager.ts b/test/unit/managers/ConfigManager.ts index 9a1f06a64..72122c4e8 100644 --- a/test/unit/managers/ConfigManager.ts +++ b/test/unit/managers/ConfigManager.ts @@ -1,9 +1,6 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { ConfigIntegrationKind, AppUserConfig, @@ -14,9 +11,7 @@ import { AppUserConfigCustomLinkOptions } from '../../../src/shared/models/Promp import ConfigManager from '../../../src/page/managers/ConfigManager'; test.beforeEach(async () => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); }); test('can customize initialization options', async (t) => { diff --git a/test/unit/managers/MetricsManager.ts b/test/unit/managers/MetricsManager.ts index a93989dbe..fa24ac6c1 100644 --- a/test/unit/managers/MetricsManager.ts +++ b/test/unit/managers/MetricsManager.ts @@ -1,9 +1,6 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import OneSignal from '../../../src/onesignal/OneSignal'; import Context from '../../../src/page/models/Context'; @@ -11,9 +8,7 @@ import timemachine from 'timemachine'; import Random from '../../support/tester/Random'; test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); const appConfig = TestEnvironment.getFakeAppConfig(); appConfig.appId = Random.getRandomUuid(); diff --git a/test/unit/managers/PageViewManager.ts b/test/unit/managers/PageViewManager.ts index 57404f667..1ea9f54bc 100644 --- a/test/unit/managers/PageViewManager.ts +++ b/test/unit/managers/PageViewManager.ts @@ -1,18 +1,13 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import OneSignal from '../../../src/onesignal/OneSignal'; import Context from '../../../src/page/models/Context'; import Random from '../../support/tester/Random'; test.beforeEach(async (_t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); const appConfig = TestEnvironment.getFakeAppConfig(); appConfig.appId = Random.getRandomUuid(); diff --git a/test/unit/managers/ServiceWorkerManager.ts b/test/unit/managers/ServiceWorkerManager.ts index ae9f4412c..ec3cae50f 100644 --- a/test/unit/managers/ServiceWorkerManager.ts +++ b/test/unit/managers/ServiceWorkerManager.ts @@ -6,7 +6,6 @@ import nock from 'nock'; import { ServiceWorkerManager } from '../../../src/shared/managers/ServiceWorkerManager'; import { ServiceWorkerActiveState } from '../../../src/shared/helpers/ServiceWorkerHelper'; import { - HttpHttpsEnvironment, TestEnvironment, TestEnvironmentConfig, } from '../../support/sdk/TestEnvironment'; @@ -126,7 +125,6 @@ test('getActiveState() should detect Akamai akam-sw.js as 3rd party if othersw= test('notification clicked - While page is opened in background', async (t) => { await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, initOptions: { pageUrl: 'https://localhost:3001/', }, @@ -163,25 +161,13 @@ test('notification clicked - While page is opened in background', async (t) => { listenerRecord.callback.apply(null, ['test']); }); -test('getActiveState() returns an indeterminate status for insecure HTTP pages', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Http, - }); - - const manager = LocalHelpers.getServiceWorkerManager(); - - t.is(await manager.getActiveState(), ServiceWorkerActiveState.Indeterminate); -}); - /*************************************************** * installWorker() *************************************************** */ test('installWorker() installs worker A with the correct file name and query parameter when no service worker exists', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); sandbox.stub(Notification, 'permission').value('granted'); const manager = LocalHelpers.getServiceWorkerManager(); @@ -203,9 +189,7 @@ test('installWorker() installs worker A with the correct file name and query par }); test('installWorker() does NOT install ServiceWorker when permission has NOT been granted', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); const manager = LocalHelpers.getServiceWorkerManager(); @@ -216,9 +200,7 @@ test('installWorker() does NOT install ServiceWorker when permission has NOT bee }); test('installWorker() installs worker A when a third party service worker exists', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); sandbox.stub(Notification, 'permission').value('granted'); await navigator.serviceWorker.register('/another-service-worker.js'); @@ -234,9 +216,7 @@ test('installWorker() installs worker A when a third party service worker exists }); test('installWorker() installs worker 1 -> simulate SDK upgrade -> install worker 2', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); sandbox.stub(Notification, 'permission').value('granted'); const manager = new ServiceWorkerManager(OneSignal.context, { @@ -287,9 +267,7 @@ test('installWorker() installs worker 1 -> simulate SDK upgrade -> install worke }); test('installWorker() installs Worker new scope when it changes', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); sandbox.stub(Notification, 'permission').value('granted'); // We don't want the version number check from "workerNeedsUpdate" interfering with this test. sandbox @@ -335,9 +313,7 @@ test('installWorker() installs Worker new scope when it changes', async (t) => { }); test('Service worker register URL correct when service worker path is an absolute URL', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); sandbox.stub(Notification, 'permission').value('granted'); const manager = new ServiceWorkerManager(OneSignal.context, { @@ -357,9 +333,7 @@ test('Service worker register URL correct when service worker path is an absolut }); test('Service worker failed to install due to 404 on host page. Send notification to OneSignal api', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); sandbox.stub(Notification, 'permission').value('granted'); const context = OneSignal.context; @@ -400,7 +374,7 @@ test('Service worker failed to install due to 404 on host page. Send notificatio test('installWorker() should not install when on an HTTPS site with a subdomain set', async (t) => { // 1. Mock site page as HTTPS - await TestEnvironment.initialize({ httpOrHttps: HttpHttpsEnvironment.Https }); + await TestEnvironment.initialize(); TestEnvironment.mockInternalOneSignal(); // 2. Set is set to use our subdomain however const subdomain = 'abc'; diff --git a/test/unit/managers/SessionManager.ts b/test/unit/managers/SessionManager.ts index b84c54bf8..4958e16cf 100644 --- a/test/unit/managers/SessionManager.ts +++ b/test/unit/managers/SessionManager.ts @@ -3,10 +3,7 @@ import { DeliveryPlatformKind } from '../../../src/shared/models/DeliveryPlatfor import { SessionManager } from '../../../src/shared/managers/sessionManager/SessionManager'; import { NotificationPermission } from '../../../src/shared/models/NotificationPermission'; import Database from '../../../src/shared/services/Database'; -import { - HttpHttpsEnvironment, - TestEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { NockOneSignalHelper } from '../../support/tester/NockOneSignalHelper'; import { setupFakePlayerId } from '../../support/tester/utils'; @@ -14,7 +11,6 @@ let pushPlayerId: string; test.beforeEach(async (t) => { await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, permission: NotificationPermission.Granted, }); TestEnvironment.mockInternalOneSignal(); diff --git a/test/unit/managers/SubscriptionManager.ts b/test/unit/managers/SubscriptionManager.ts index 1535691c4..3bf6db316 100644 --- a/test/unit/managers/SubscriptionManager.ts +++ b/test/unit/managers/SubscriptionManager.ts @@ -8,7 +8,6 @@ import { ServiceWorkerManager } from '../../../src/shared/managers/ServiceWorker import { ServiceWorkerActiveState } from '../../../src/shared/helpers/ServiceWorkerHelper'; import { TestEnvironment, - HttpHttpsEnvironment, BrowserUserAgent, } from '../../support/sdk/TestEnvironment'; import Database from '../../../src/shared/services/Database'; @@ -39,9 +38,7 @@ import Environment from '../../../src/Environment'; const sandbox: SinonSandbox = sinon.sandbox.create(); test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); TestEnvironment.mockInternalOneSignal(); timemachine.reset(); diff --git a/test/unit/managers/UpdateManager.ts b/test/unit/managers/UpdateManager.ts index 1c3adaf54..c574178ba 100644 --- a/test/unit/managers/UpdateManager.ts +++ b/test/unit/managers/UpdateManager.ts @@ -1,9 +1,6 @@ import test from 'ava'; import sinon, { SinonSandbox } from 'sinon'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { UpdateManager } from '../../../src/shared/managers/UpdateManager'; import Database from '../../../src/shared/services/Database'; import Random from '../../support/tester/Random'; @@ -23,7 +20,6 @@ const sandbox: SinonSandbox = sinon.sandbox.create(); test.beforeEach(async (t) => { await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, permission: NotificationPermission.Granted, }); TestEnvironment.mockInternalOneSignal(); diff --git a/test/unit/meta/mockPushManager.ts b/test/unit/meta/mockPushManager.ts index 5b910b1b7..263a3d561 100644 --- a/test/unit/meta/mockPushManager.ts +++ b/test/unit/meta/mockPushManager.ts @@ -2,10 +2,7 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import Random from '../../support/tester/Random'; import { MockPushManager } from '../../support/mocks/service-workers/models/MockPushManager'; import { MockPushSubscription } from '../../support/mocks/service-workers/models/MockPushSubscription'; @@ -17,9 +14,7 @@ async function getServiceWorkerRegistration(): Promise< } test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); await navigator.serviceWorker.register('/worker.js'); }); diff --git a/test/unit/meta/mockServiceWorker.ts b/test/unit/meta/mockServiceWorker.ts index 2e53e4ef0..6b903a704 100644 --- a/test/unit/meta/mockServiceWorker.ts +++ b/test/unit/meta/mockServiceWorker.ts @@ -2,10 +2,7 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { MockServiceWorkerContainer } from '../../support/mocks/service-workers/models/MockServiceWorkerContainer'; import { MockServiceWorker } from '../../support/mocks/service-workers/models/MockServiceWorker'; import { MockServiceWorkerRegistration } from '../../support/mocks/service-workers/models/MockServiceWorkerRegistration'; @@ -13,9 +10,7 @@ import { MockServiceWorkerRegistration } from '../../support/mocks/service-worke class TestMockServiceWorkerContainer extends MockServiceWorkerContainer {} test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); (global as any).navigator.serviceWorker = new TestMockServiceWorkerContainer(); }); diff --git a/test/unit/meta/mockServiceWorkerContainerWithAPIBan.ts b/test/unit/meta/mockServiceWorkerContainerWithAPIBan.ts index 0b01386fa..a3c448eed 100644 --- a/test/unit/meta/mockServiceWorkerContainerWithAPIBan.ts +++ b/test/unit/meta/mockServiceWorkerContainerWithAPIBan.ts @@ -1,15 +1,10 @@ import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { MockServiceWorkerContainerWithAPIBan } from '../../support/mocks/service-workers/models/MockServiceWorkerContainerWithAPIBan'; test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); }); test('mock service worker browser API properties should exist', async (t) => { diff --git a/test/unit/modules/entryInitialization.ts b/test/unit/modules/entryInitialization.ts index f3046017b..9bea4e41f 100644 --- a/test/unit/modules/entryInitialization.ts +++ b/test/unit/modules/entryInitialization.ts @@ -1,9 +1,6 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - HttpHttpsEnvironment, - TestEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import '../../support/sdk/TestEnvironment'; import { ReplayCallsOnOneSignal } from '../../../src/page/utils/ReplayCallsOnOneSignal'; @@ -22,9 +19,7 @@ let sandbox: SinonSandbox; test.beforeEach(async function () { sandbox = sinon.sandbox.create(); - await TestEnvironment.stubDomEnvironment({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.stubDomEnvironment(); }); test.afterEach(function () { diff --git a/test/unit/modules/loadSdkStyles.ts b/test/unit/modules/loadSdkStyles.ts index cea83b1f9..93c8b72ba 100644 --- a/test/unit/modules/loadSdkStyles.ts +++ b/test/unit/modules/loadSdkStyles.ts @@ -2,7 +2,6 @@ import '../../support/polyfills/polyfills'; import anyTest, { TestInterface } from 'ava'; import { TestEnvironment, - HttpHttpsEnvironment, TestEnvironmentConfig, } from '../../support/sdk/TestEnvironment'; import OneSignal from '../../../src/onesignal/OneSignal'; @@ -44,7 +43,6 @@ test.afterEach.always((t) => { test('should call loadSdkStylesheet if notify button is used', async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, userConfig: { notifyButton: { enable: true, @@ -64,7 +62,6 @@ test('should call loadSdkStylesheet if notify button is used', async (t) => { test('should call loadSdkStylesheet if slidedown permission message is used', async (t) => { await TestEnvironment.initialize({ initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, }); TestEnvironment.mockInternalOneSignal(); try { @@ -86,7 +83,6 @@ test('loadIfNew called twice should not load the same stylesheet or script more await TestEnvironment.initialize({ initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, }); const dynamicResourceLoader = new DynamicResourceLoader(); const resourceLoadAttempts = []; @@ -114,7 +110,6 @@ test('loadIfNew called twice should not load the same stylesheet or script more test('load successfully fetches and installs stylesheet', async (t) => { await TestEnvironment.initialize({ initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, }); await DynamicResourceLoader.load( ResourceType.Stylesheet, @@ -129,7 +124,6 @@ test('load successfully fetches and installs stylesheet', async (t) => { test('load successfully fetches and executes script', async (t) => { await TestEnvironment.initialize({ initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, }); await DynamicResourceLoader.load( ResourceType.Script, diff --git a/test/unit/modules/postmam.ts b/test/unit/modules/postmam.ts index 3b6ac014e..74bbd713c 100644 --- a/test/unit/modules/postmam.ts +++ b/test/unit/modules/postmam.ts @@ -1,9 +1,6 @@ import '../../support/polyfills/polyfills'; import anyTest, { TestInterface } from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import Postmam from '../../../src/shared/services/Postmam'; interface PostmamContext { @@ -17,9 +14,7 @@ interface PostmamContext { const test = anyTest as TestInterface; test.beforeEach(async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); // Stub MessageChannel const fakeClass = class Test {}; diff --git a/test/unit/modules/subscriptionHelper.ts b/test/unit/modules/subscriptionHelper.ts index 18b56c70a..b945edd64 100644 --- a/test/unit/modules/subscriptionHelper.ts +++ b/test/unit/modules/subscriptionHelper.ts @@ -1,9 +1,6 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import sinon from 'sinon'; import { SubscriptionManager } from '../../../src/shared/managers/SubscriptionManager'; import LocalStorage from '../../../src/shared/utils/LocalStorage'; @@ -13,9 +10,7 @@ import SubscriptionHelper from '../../../src/shared/helpers/SubscriptionHelper'; const sinonSandbox = sinon.sandbox.create(); test.beforeEach(async () => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); TestEnvironment.mockInternalOneSignal(); }); diff --git a/test/unit/modules/timedLocalStorage.ts b/test/unit/modules/timedLocalStorage.ts index d5214e5c9..28b1203ff 100644 --- a/test/unit/modules/timedLocalStorage.ts +++ b/test/unit/modules/timedLocalStorage.ts @@ -1,16 +1,11 @@ import '../../support/polyfills/polyfills'; import test from 'ava'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import TimedLocalStorage from '../../../src/page/modules/TimedLocalStorage'; import timemachine from 'timemachine'; test('should not throw and return null if LocalStorage is not supported', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); delete (window as any).localStorage; t.deepEqual(window.localStorage, undefined); const value = TimedLocalStorage.getItem('test'); @@ -18,9 +13,7 @@ test('should not throw and return null if LocalStorage is not supported', async }); test('should set and get item without expiration', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); TimedLocalStorage.setItem('my-key', 'my-value'); t.deepEqual(TimedLocalStorage.getItem('my-key'), 'my-value'); timemachine.config({ @@ -31,9 +24,7 @@ test('should set and get item without expiration', async (t) => { }); test('should set and get complex item without expiration', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); const hash = { number: 4, string: 'text', @@ -49,9 +40,7 @@ test('should set and get complex item without expiration', async (t) => { }); test('should set and get item with expiration', async (t) => { - await TestEnvironment.initialize({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.initialize(); TimedLocalStorage.setItem('my-key', 'my-value', 3); t.deepEqual(TimedLocalStorage.getItem('my-key'), 'my-value'); timemachine.config({ diff --git a/test/unit/prompts/ChannelCaptureContainer/ChannelCaptureContainer.ts b/test/unit/prompts/ChannelCaptureContainer/ChannelCaptureContainer.ts index 60272d933..b1c25d98c 100644 --- a/test/unit/prompts/ChannelCaptureContainer/ChannelCaptureContainer.ts +++ b/test/unit/prompts/ChannelCaptureContainer/ChannelCaptureContainer.ts @@ -2,7 +2,6 @@ import test from 'ava'; import sinon, { SinonSandbox } from 'sinon'; import { TestEnvironment, - HttpHttpsEnvironment, BrowserUserAgent, TestEnvironmentConfig, } from '../../../support/sdk/TestEnvironment'; @@ -28,7 +27,6 @@ test.beforeEach(async () => { (global as any).location = new URL('https://localhost:4001'); const userConfig = TestEnvironment.getFakeMergedConfig({}); const options = { - httpOrHttps: HttpHttpsEnvironment.Https, initOptions: userConfig, addPrompts: true, }; @@ -98,7 +96,6 @@ test('resetting validation styles works correctly', async (t) => { }); const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Default, pushIdentifier: 'granted', diff --git a/test/unit/prompts/ConfirmationToast.ts b/test/unit/prompts/ConfirmationToast.ts index 4d16a2cf1..bd6a7bc86 100644 --- a/test/unit/prompts/ConfirmationToast.ts +++ b/test/unit/prompts/ConfirmationToast.ts @@ -6,7 +6,6 @@ import { getDomElementOrStub } from '../../../src/shared/utils/utils'; import { BrowserUserAgent, TestEnvironment, - HttpHttpsEnvironment, } from '../../../test/support/sdk/TestEnvironment'; const sandbox: SinonSandbox = sinon.sandbox.create(); @@ -16,7 +15,6 @@ test.beforeEach(async () => { (global as any).location = new URL('https://localhost:4001'); const userConfig = TestEnvironment.getFakeMergedConfig({}); const options = { - httpOrHttps: HttpHttpsEnvironment.Https, initOptions: userConfig, addPrompts: true, }; diff --git a/test/unit/prompts/CustomLink.ts b/test/unit/prompts/CustomLink.ts index 07e1b5cff..14d95b6e3 100644 --- a/test/unit/prompts/CustomLink.ts +++ b/test/unit/prompts/CustomLink.ts @@ -1,9 +1,6 @@ import test from 'ava'; import sinon, { SinonSandbox } from 'sinon'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import { AppUserConfigCustomLinkOptions } from '../../../src/shared/models/Prompts'; import { ResourceLoadState } from '../../../src/page/services/DynamicResourceLoader'; import { hasCssClass } from '../../../src/shared/utils/utils'; @@ -43,7 +40,6 @@ test.beforeEach(async () => { await TestEnvironment.initialize({ addPrompts: true, - httpOrHttps: HttpHttpsEnvironment.Https, }); TestEnvironment.mockInternalOneSignal(); sandbox diff --git a/test/unit/prompts/DelayedPrompts.ts b/test/unit/prompts/DelayedPrompts.ts index e3c300610..d638e7ecb 100644 --- a/test/unit/prompts/DelayedPrompts.ts +++ b/test/unit/prompts/DelayedPrompts.ts @@ -3,7 +3,6 @@ import test, { ExecutionContext } from 'ava'; import sinon, { SinonSandbox } from 'sinon'; import { TestEnvironment, - HttpHttpsEnvironment, TestEnvironmentConfig, } from '../../support/sdk/TestEnvironment'; import { ConfigIntegrationKind } from '../../../src/shared/models/AppConfig'; @@ -34,7 +33,6 @@ test.afterEach(function (_t: ExecutionContext) { * setTimeout doesn't work as intended in testing environment due to jsdom bugs */ const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Default, }; diff --git a/test/unit/prompts/Slidedown.ts b/test/unit/prompts/Slidedown.ts index e6e39e233..0d56a1dbc 100644 --- a/test/unit/prompts/Slidedown.ts +++ b/test/unit/prompts/Slidedown.ts @@ -8,7 +8,6 @@ import { import '../../support/polyfills/polyfills'; import { TestEnvironment, - HttpHttpsEnvironment, BrowserUserAgent, } from '../../support/sdk/TestEnvironment'; import { setUserAgent } from '../../support/tester/browser'; @@ -27,9 +26,7 @@ const options: SlidedownPromptOptions = { test.beforeEach(async () => { (global as any).BrowserUserAgent = BrowserUserAgent; - await TestEnvironment.stubDomEnvironment({ - httpOrHttps: HttpHttpsEnvironment.Https, - }); + await TestEnvironment.stubDomEnvironment(); }); test.afterEach(function () { diff --git a/test/unit/prompts/SlidedownPrompting/SlidedownPrompting.ts b/test/unit/prompts/SlidedownPrompting/SlidedownPrompting.ts index 7f6604df9..cb6a3a6b4 100644 --- a/test/unit/prompts/SlidedownPrompting/SlidedownPrompting.ts +++ b/test/unit/prompts/SlidedownPrompting/SlidedownPrompting.ts @@ -1,7 +1,6 @@ import sinon, { SinonSandbox } from 'sinon'; import test, { ExecutionContext } from 'ava'; import { - HttpHttpsEnvironment, TestEnvironment, TestEnvironmentConfig, } from '../../../support/sdk/TestEnvironment'; @@ -48,7 +47,6 @@ test.afterEach(function (_t: ExecutionContext) { }); const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Default, pushIdentifier: 'granted', diff --git a/test/unit/prompts/TaggingContainer.ts b/test/unit/prompts/TaggingContainer.ts index 072ccb580..976220138 100644 --- a/test/unit/prompts/TaggingContainer.ts +++ b/test/unit/prompts/TaggingContainer.ts @@ -3,7 +3,6 @@ import TaggingContainer from '../../../src/page/slidedown/TaggingContainer'; import sinon, { SinonSandbox } from 'sinon'; import { TestEnvironment, - HttpHttpsEnvironment, BrowserUserAgent, } from '../../support/sdk/TestEnvironment'; import { TagsObjectWithBoolean } from '../../../src/page/models/Tags'; @@ -22,7 +21,6 @@ test.beforeEach(async () => { (global as any).location = new URL('https://localhost:4001'); const userConfig = TestEnvironment.getFakeMergedConfig({}); const options = { - httpOrHttps: HttpHttpsEnvironment.Https, initOptions: userConfig, addPrompts: true, }; diff --git a/test/unit/public-sdk-apis/init.ts b/test/unit/public-sdk-apis/init.ts index 9f586f5f5..4c6e8114a 100644 --- a/test/unit/public-sdk-apis/init.ts +++ b/test/unit/public-sdk-apis/init.ts @@ -2,10 +2,7 @@ import '../../support/polyfills/polyfills'; import test, { ExecutionContext } from 'ava'; import sinon, { SinonSandbox } from 'sinon'; import Database from '../../../src/shared/services/Database'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import Context from '../../../src/page/models/Context'; import InitHelper from '../../../src/shared/helpers/InitHelper'; import { AppConfig } from '../../../src/shared/models/AppConfig'; @@ -33,7 +30,6 @@ test.afterEach(function (_t: ExecutionContext) { test('correct degree of persistNotification setting should be stored', async (t) => { await TestEnvironment.initialize({ initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, }); const appConfig = TestEnvironment.getFakeAppConfig(); @@ -78,7 +74,6 @@ test('correct degree of persistNotification setting should be stored', async (t) test('Test OneSignal.init, Custom, with requiresUserPrivacyConsent', async (t) => { const testConfig = { initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, pushIdentifier: (await TestEnvironment.getFakePushSubscription()).endpoint, stubSetTimeout: true, }; @@ -111,7 +106,6 @@ test('Test OneSignal.init, Custom, with requiresUserPrivacyConsent', async (t) = test('Test OneSignal.init, TypicalSite, with requiresUserPrivacyConsent', async (t) => { const testConfig = { initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, pushIdentifier: (await TestEnvironment.getFakePushSubscription()).endpoint, stubSetTimeout: true, }; @@ -141,7 +135,6 @@ test('Test OneSignal.init, TypicalSite, with requiresUserPrivacyConsent', async test('Test OneSignal.init, No app id or wrong format of app id', async (t) => { const testConfig = { initOptions: {}, - httpOrHttps: HttpHttpsEnvironment.Https, pushIdentifier: (await TestEnvironment.getFakePushSubscription()).endpoint, }; await TestEnvironment.initialize(testConfig); diff --git a/test/unit/public-sdk-apis/onSession.ts b/test/unit/public-sdk-apis/onSession.ts index fcfe44039..379857be8 100644 --- a/test/unit/public-sdk-apis/onSession.ts +++ b/test/unit/public-sdk-apis/onSession.ts @@ -3,7 +3,6 @@ import test, { ExecutionContext } from 'ava'; import sinon, { SinonSandbox, SinonStub } from 'sinon'; import { TestEnvironment, - HttpHttpsEnvironment, TestEnvironmentConfig, } from '../../support/sdk/TestEnvironment'; import { ConfigIntegrationKind } from '../../../src/shared/models/AppConfig'; @@ -72,7 +71,6 @@ test.serial( click allow => sends player create`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, pushIdentifier: 'granted', stubSetTimeout: true, @@ -122,7 +120,6 @@ test.serial( click dismiss => no requests`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, pushIdentifier: 'granted', stubSetTimeout: true, @@ -167,7 +164,6 @@ test.serial( permissions already granted => sends player create`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Granted, }; @@ -219,7 +215,6 @@ test.serial( permissions default => no requests`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Default, }; @@ -260,7 +255,6 @@ test.serial( no requests`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, pushIdentifier: 'granted', @@ -299,7 +293,6 @@ test.serial( `HTTPS: User opted out => first page view => onSession flag is on => do not send on session`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Granted, pushIdentifier: 'granted', @@ -342,7 +335,6 @@ test.serial( `HTTPS: User opted out => first page view => onSession flag is off => no requests`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Granted, pushIdentifier: 'granted', @@ -390,7 +382,6 @@ test.serial( `HTTPS: User opted out => second page view => onSession flag is on => no requests`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Granted, pushIdentifier: 'granted', @@ -441,7 +432,6 @@ test.serial( `HTTPS: User subscribed => first page view => expiring subscription => sends player update`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Granted, pushIdentifier: 'granted', @@ -490,7 +480,6 @@ test.serial( `HTTPS: User subscribed => first page view => sends on session`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, permission: NotificationPermission.Granted, pushIdentifier: 'granted', @@ -530,7 +519,6 @@ test.serial( click allow => sends player create`, async (t) => { const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Https, integration: ConfigIntegrationKind.Custom, pushIdentifier: 'granted', stubSetTimeout: true, @@ -576,318 +564,6 @@ test.serial( }, ); -test.serial( - `HTTP: User not subscribed and not opted out => first page view => slidedown's autoPrompt is on => - click dismiss => no requests`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - pushIdentifier: 'granted', - stubSetTimeout: true, - }; - - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - EventsTestHelper.simulateSlidedownDismissAfterShown(); - - const subscribeSpy = sinonSandbox.spy( - SubscriptionManager.prototype, - 'subscribe', - ); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - autoResubscribe: false, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - t.is(subscribeSpy.callCount, 0); - }, -); - -// autoResubscribe works only on https -test.serial( - `HTTP: User not subscribed and not opted out => first page view => autoResubscribe is on => - permissions already granted => no requests`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Granted, - }; - - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - stubServiceWorkerInstallation(sinonSandbox); - - const subscribeSpy = sinonSandbox.spy( - SubscriptionManager.prototype, - 'subscribe', - ); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - t.is(subscribeSpy.callCount, 0); - }, -); - -test.serial( - `HTTP: User not subscribed and not opted out => first page view => autoResubscribe is on => - permissions default => no requests`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Default, - }; - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - const subscribeSpy = sinonSandbox.spy( - SubscriptionManager.prototype, - 'subscribe', - ); - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - t.is(subscribeSpy.callCount, 0); - }, -); - -test.serial( - `HTTP: User not subscribed and not opted out => first page view => no autoResubscribe and no autoPrompt => - no requests`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - pushIdentifier: 'granted', - permission: NotificationPermission.Granted, - }; - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - const subscribeSpy = sinonSandbox.spy( - SubscriptionManager.prototype, - 'subscribe', - ); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: false, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - t.is(subscribeSpy.callCount, 0); - }, -); - -test.serial( - `HTTP: User opted out => first page view => onSession flag is on => send on session`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Granted, - pushIdentifier: 'granted', - }; - - const serverAppConfig = TestEnvironment.getFakeServerAppConfig( - testConfig.integration!, - false, - ); - serverAppConfig.features.enable_on_session = true; - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - serverAppConfig, - ); - await markUserAsOptedOut(sinonSandbox, playerId); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 1); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - }, -); - -test.serial( - `HTTP: User opted out => first page view => onSession flag is off => no requests`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Granted, - pushIdentifier: 'granted', - }; - - const serverAppConfig = TestEnvironment.getFakeServerAppConfig( - testConfig.integration!, - false, - ); - serverAppConfig.features.enable_on_session = false; - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - serverAppConfig, - ); - const subscribeSpy = sinonSandbox.spy( - SubscriptionManager.prototype, - 'subscribe', - ); - await markUserAsOptedOut(sinonSandbox, playerId); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - t.is(subscribeSpy.callCount, 0); - }, -); - -test.serial( - `HTTP: User opted out => second page view => onSession flag is on => no requests`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - httpOrHttps: HttpHttpsEnvironment.Http, - integration: ConfigIntegrationKind.Custom, - permission: NotificationPermission.Granted, - pushIdentifier: 'granted', - }; - - const serverAppConfig = TestEnvironment.getFakeServerAppConfig( - testConfig.integration!, - false, - ); - serverAppConfig.features.enable_on_session = true; - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - serverAppConfig, - ); - const subscribeSpy = sinonSandbox.spy( - SubscriptionManager.prototype, - 'subscribe', - ); - await markUserAsOptedOut(sinonSandbox, playerId); - - sinonSandbox - .stub(PageViewManager.prototype, 'getPageViewCount') - .resolves(2); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - autoResubscribe: true, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - }); - await initPromise; - await initializePromise; - t.is(subscribeSpy.callCount, 0); - }, -); - /** Helper methods */ async function inspectPushRecordCreationRequest( t: ExecutionContext, From 541d93d01fd3c3a3d4e1228441aa821eb330dec5 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 03:00:23 +0000 Subject: [PATCH 21/35] rm subdomain checks from checkRestrictedOrigin OneSignal must be included on the intented page and we no longer support the os.tc / onesginal.com subdomain option. --- src/shared/helpers/ConfigHelper.ts | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index 95b7616d4..c5e3083a8 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -91,19 +91,18 @@ export class ConfigHelper { } public static checkRestrictedOrigin(appConfig: AppConfig) { - if (appConfig.restrictedOriginEnabled) { - if (SdkEnvironment.getWindowEnv() === WindowEnvironmentKind.Host) { - if ( - window.top === window && - !Utils.contains(window.location.hostname, '.os.tc') && - !Utils.contains(window.location.hostname, '.onesignal.com') && - !this.doesCurrentOriginMatchConfigOrigin(appConfig.origin) - ) { - throw new SdkInitError(SdkInitErrorKind.WrongSiteUrl, { - siteUrl: appConfig.origin, - }); - } - } + if (!appConfig.restrictedOriginEnabled) { + return; + } + + if (SdkEnvironment.getWindowEnv() !== WindowEnvironmentKind.Host) { + return; + } + + if (!this.doesCurrentOriginMatchConfigOrigin(appConfig.origin)) { + throw new SdkInitError(SdkInitErrorKind.WrongSiteUrl, { + siteUrl: appConfig.origin, + }); } } From cf614a62b7c810d33f093a774bfc16c2488bb1f5 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 03:33:53 +0000 Subject: [PATCH 22/35] AppConfig.subdomain to hasUnsupportedSubdomain Made this change to make this more clear that this is an unsupported setting. Cleaned up some usages of subdomain as well. --- src/shared/helpers/ConfigHelper.ts | 79 ++++----------------- src/shared/managers/ServiceWorkerManager.ts | 18 +---- src/shared/models/AppConfig.ts | 5 +- src/shared/services/Database.ts | 6 -- test/unit/managers/ConfigManager.ts | 4 +- test/unit/managers/ServiceWorkerManager.ts | 23 ------ test/unit/modules/mergedLegacyConfig.ts | 7 +- 7 files changed, 23 insertions(+), 119 deletions(-) diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index c5e3083a8..7b7ddff5a 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -75,9 +75,9 @@ export class ConfigHelper { // OneSignal app is still configured this way after they migrated from v15. private static checkUnsupportedSubdomain(appConfig: AppConfig): void { const isHttp = !window.isSecureContext; - const useSubdomain = !!appConfig.subdomain || isHttp; + const unsupportedEnv = appConfig.hasUnsupportedSubdomain || isHttp; - if (useSubdomain) { + if (unsupportedEnv) { if (isHttp) { throw new Error( "OneSignalSDK: HTTP sites are no longer supported starting with version 16 (User Model), your public site must start with https://. Please visit the OneSignal dashboard's Settings > Web Configuration to find this option.", @@ -134,11 +134,12 @@ export class ConfigHelper { ): AppConfig { const configIntegrationKind = this.getConfigIntegrationKind(serverConfig); - const subdomain = this.getSubdomainForConfigIntegrationKind( - configIntegrationKind, - userConfig, - serverConfig, - ); + const hasUnsupportedSubdomain = + this.hasUnsupportedSubdomainForConfigIntegrationKind( + configIntegrationKind, + userConfig, + serverConfig, + ); const mergedUserConfig = this.getUserConfigForConfigIntegrationKind( configIntegrationKind, @@ -148,7 +149,7 @@ export class ConfigHelper { return { appId: serverConfig.app_id, - subdomain, + hasUnsupportedSubdomain, siteName: serverConfig.config.siteInfo.name, origin: serverConfig.config.origin, httpUseOneSignalCom: serverConfig.config.http_use_onesignal_com, @@ -674,73 +675,19 @@ export class ConfigHelper { /** * Describes how to merge a dashboard-set subdomain with a/lack of user-supplied subdomain. */ - public static getSubdomainForConfigIntegrationKind( + public static hasUnsupportedSubdomainForConfigIntegrationKind( configIntegrationKind: ConfigIntegrationKind, userConfig: AppUserConfig, serverConfig: ServerAppConfig, - ): string | undefined { + ): boolean { const integrationCapabilities = this.getIntegrationCapabilities( configIntegrationKind, ); - const userValue: string | undefined = userConfig.subdomainName; - let serverValue: string | undefined = ''; - switch (integrationCapabilities.configuration) { case IntegrationConfigurationKind.Dashboard: - serverValue = serverConfig.config.siteInfo.proxyOriginEnabled - ? serverConfig.config.siteInfo.proxyOrigin - : undefined; - break; + return serverConfig.config.siteInfo.proxyOriginEnabled; case IntegrationConfigurationKind.JavaScript: - serverValue = serverConfig.config.subdomain; - break; - } - - if ( - serverValue && - !this.shouldUseServerConfigSubdomain(userValue, integrationCapabilities) - ) { - return undefined; - } else { - return serverValue; - } - } - - public static shouldUseServerConfigSubdomain( - userProvidedSubdomain: string | undefined, - capabilities: IntegrationCapabilities, - ): boolean { - switch (capabilities.configuration) { - case IntegrationConfigurationKind.Dashboard: - /* - Dashboard config using the new web config editor always takes precedence. - */ - return true; - case IntegrationConfigurationKind.JavaScript: - /* - * An HTTPS site may be using either a native push integration or a fallback - * subdomain integration. Our SDK decides the integration based on whether - * init option subdomainName appears and the site's protocol. - * - * To avoid having developers write JavaScript to customize the SDK, - * configuration properties like subdomainName are downloaded on page start. - * - * New developers setting up web push can omit subdomainName, but existing - * developers already having written code to configure OneSignal aren't - * removing their code. - * - * When an HTTPS site is configured with a subdomain on the server-side, we do - * not apply it even though we've downloaded this configuration unless the - * user also declares it manually in their initialization code. - */ - switch (location.protocol) { - case 'https:': - return !!userProvidedSubdomain; - case 'http:': - return true; - default: - return false; - } + return !!userConfig.subdomainName; } } } diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index 309951e86..9299e4138 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -130,19 +130,7 @@ export class ServiceWorkerManager { // 2. Is OneSignal initialized? if (!OneSignal.config) return false; - // 3. Will the service worker be installed on os.tc instead of the current domain? - if (OneSignal.config.subdomain) { - // No, if configured to use our subdomain (AKA HTTP setup) AND this is on their page (HTTP or HTTPS). - // But since safari does not need subscription workaround, installing SW for session tracking. - if ( - OneSignal.environmentInfo.browserType !== 'safari' && - SdkEnvironment.getWindowEnv() === WindowEnvironmentKind.Host - ) { - return false; - } - } - - // 4. Is a OneSignal ServiceWorker not installed now? + // 3. Is a OneSignal ServiceWorker not installed now? // If not and notification permissions are enabled we should install. // This prevents an unnecessary install of the OneSignal worker which saves bandwidth const workerState = await this.getActiveState(); @@ -164,12 +152,12 @@ export class ServiceWorkerManager { return notificationsEnabled; } - // 5. We have a OneSignal ServiceWorker installed, but did the path or scope of the ServiceWorker change? + // 4. We have a OneSignal ServiceWorker installed, but did the path or scope of the ServiceWorker change? if (await this.haveParamsChanged()) { return true; } - // 6. We have a OneSignal ServiceWorker installed, is there an update? + // 5. We have a OneSignal ServiceWorker installed, is there an update? return this.workerNeedsUpdate(); } diff --git a/src/shared/models/AppConfig.ts b/src/shared/models/AppConfig.ts index 6da135b68..37a0f31d3 100755 --- a/src/shared/models/AppConfig.ts +++ b/src/shared/models/AppConfig.ts @@ -16,9 +16,10 @@ export interface AppConfig { appId: string; /** - * The subdomain chosen on the dashboard for non-HTTPS apps. + * Is the app configured for a subdomain (AKA os.tc) that + * is no longer supported by OneSignal. */ - subdomain?: string; + hasUnsupportedSubdomain: boolean; /** * The allowed origin this web push config is allowed to run on. diff --git a/src/shared/services/Database.ts b/src/shared/services/Database.ts index cce5ab4e6..a35ee7129 100644 --- a/src/shared/services/Database.ts +++ b/src/shared/services/Database.ts @@ -155,7 +155,6 @@ export default class Database { const config: any = {}; const appIdStr: string = await this.get('Ids', 'appId'); config.appId = appIdStr; - config.subdomain = await this.get('Options', 'subdomain'); config.vapidPublicKey = await this.get('Options', 'vapidPublicKey'); return config; } @@ -198,11 +197,6 @@ export default class Database { async setAppConfig(appConfig: AppConfig): Promise { if (appConfig.appId) await this.put('Ids', { type: 'appId', id: appConfig.appId }); - if (appConfig.subdomain) - await this.put('Options', { - key: 'subdomain', - value: appConfig.subdomain, - }); if (appConfig.httpUseOneSignalCom === true) await this.put('Options', { key: 'httpUseOneSignalCom', value: true }); else if (appConfig.httpUseOneSignalCom === false) diff --git a/test/unit/managers/ConfigManager.ts b/test/unit/managers/ConfigManager.ts index 72122c4e8..a2b488cac 100644 --- a/test/unit/managers/ConfigManager.ts +++ b/test/unit/managers/ConfigManager.ts @@ -48,7 +48,7 @@ test('should use server-provided subdomain if enabled', async (t) => { fakeServerConfig, ); - t.deepEqual(fakeMergedConfig.subdomain, 'some-subdomain'); + t.deepEqual(fakeMergedConfig.hasUnsupportedSubdomain, true); }); test('should not use server-provided subdomain if not enabled', async (t) => { @@ -66,7 +66,7 @@ test('should not use server-provided subdomain if not enabled', async (t) => { fakeServerConfig, ); - t.deepEqual(fakeMergedConfig.subdomain, undefined); + t.deepEqual(fakeMergedConfig.hasUnsupportedSubdomain, false); }); test('should initialize custom link config for typical setup', (t) => { diff --git a/test/unit/managers/ServiceWorkerManager.ts b/test/unit/managers/ServiceWorkerManager.ts index ec3cae50f..91cc2a08c 100644 --- a/test/unit/managers/ServiceWorkerManager.ts +++ b/test/unit/managers/ServiceWorkerManager.ts @@ -372,29 +372,6 @@ test('Service worker failed to install due to 404 on host page. Send notificatio }); }); -test('installWorker() should not install when on an HTTPS site with a subdomain set', async (t) => { - // 1. Mock site page as HTTPS - await TestEnvironment.initialize(); - TestEnvironment.mockInternalOneSignal(); - // 2. Set is set to use our subdomain however - const subdomain = 'abc'; - const testConfig: TestEnvironmentConfig = { - integration: ConfigIntegrationKind.TypicalSite, - overrideServerConfig: { - config: { - subdomain: subdomain, - siteInfo: { proxyOriginEnabled: true, proxyOrigin: subdomain }, - }, - }, - }; - TestEnvironment.mockInternalOneSignal(testConfig); - - const manager = LocalHelpers.getServiceWorkerManager(); - await manager.installWorker(); - // Since ServiceWorker will be installed in the iframe on os.tc Indeterminate is expected - t.is(await manager.getActiveState(), ServiceWorkerActiveState.Indeterminate); -}); - test('ServiceWorkerManager.getRegistration() returns valid instance when sw is registered', async (t) => { await navigator.serviceWorker.register('/Worker.js'); const result = await OneSignal.context.serviceWorkerManager.getRegistration(); diff --git a/test/unit/modules/mergedLegacyConfig.ts b/test/unit/modules/mergedLegacyConfig.ts index 6b836b304..31cba96b5 100644 --- a/test/unit/modules/mergedLegacyConfig.ts +++ b/test/unit/modules/mergedLegacyConfig.ts @@ -4,10 +4,7 @@ import { ConfigIntegrationKind, ServerAppConfig, } from '../../../src/shared/models/AppConfig'; -import { - TestEnvironment, - HttpHttpsEnvironment, -} from '../../support/sdk/TestEnvironment'; +import { TestEnvironment } from '../../support/sdk/TestEnvironment'; import ConfigManager from '../../../src/page/managers/ConfigManager'; interface ConfigContext { @@ -76,7 +73,7 @@ test('should not overwrite provided subdomain', async (t) => { }, serverConfig, ); - t.is(result.subdomain, 'test-subdomain'); + t.is(result.hasUnsupportedSubdomain, true); }); test('should assign downloaded safari web ID if not provided', async (t) => { From 3a4efe71560f7a2e44aea3cac51d0217e507b92e Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 03:37:47 +0000 Subject: [PATCH 23/35] rm httpUseOneSignalCom This was related to subdomain which was removed in the previous commit --- src/shared/helpers/ConfigHelper.ts | 1 - src/shared/models/AppConfig.ts | 5 ----- src/shared/services/Database.ts | 4 ---- 3 files changed, 10 deletions(-) diff --git a/src/shared/helpers/ConfigHelper.ts b/src/shared/helpers/ConfigHelper.ts index 7b7ddff5a..a2caec9da 100644 --- a/src/shared/helpers/ConfigHelper.ts +++ b/src/shared/helpers/ConfigHelper.ts @@ -152,7 +152,6 @@ export class ConfigHelper { hasUnsupportedSubdomain, siteName: serverConfig.config.siteInfo.name, origin: serverConfig.config.origin, - httpUseOneSignalCom: serverConfig.config.http_use_onesignal_com, restrictedOriginEnabled: serverConfig.features.restrict_origin && serverConfig.features.restrict_origin.enable, diff --git a/src/shared/models/AppConfig.ts b/src/shared/models/AppConfig.ts index 37a0f31d3..cdf5e6e14 100755 --- a/src/shared/models/AppConfig.ts +++ b/src/shared/models/AppConfig.ts @@ -26,11 +26,6 @@ export interface AppConfig { */ origin: string; - /** - * Describes whether the subdomain HTTP users subscribe to should belong to - * the legacy domain onesignal.com, or the newer domain os.tc. - */ - httpUseOneSignalCom?: boolean; restrictedOriginEnabled?: boolean | null; metrics: { enable: boolean; diff --git a/src/shared/services/Database.ts b/src/shared/services/Database.ts index a35ee7129..0adcc2498 100644 --- a/src/shared/services/Database.ts +++ b/src/shared/services/Database.ts @@ -197,10 +197,6 @@ export default class Database { async setAppConfig(appConfig: AppConfig): Promise { if (appConfig.appId) await this.put('Ids', { type: 'appId', id: appConfig.appId }); - if (appConfig.httpUseOneSignalCom === true) - await this.put('Options', { key: 'httpUseOneSignalCom', value: true }); - else if (appConfig.httpUseOneSignalCom === false) - await this.put('Options', { key: 'httpUseOneSignalCom', value: false }); if (appConfig.vapidPublicKey) await this.put('Options', { key: 'vapidPublicKey', From 443c8b843b0d182385761dbc82cdcfd3e6630ed9 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 03:47:15 +0000 Subject: [PATCH 24/35] remove reduntent useSafariLegacyPush check useSafariLegacyPush is already checked in getSubscriptionStateForSecure --- src/shared/managers/SubscriptionManager.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index 876dfa2a7..e763cb589 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -813,13 +813,7 @@ export class SubscriptionManager { * Returns an object describing the user's actual push subscription state and opt-out status. */ public async getSubscriptionState(): Promise { - /* Safari Legacy supports HTTP so we don't have to use the subdomain workaround. */ - if (Environment.useSafariLegacyPush()) { - return this.getSubscriptionStateForSecure(); - } - const windowEnv = SdkEnvironment.getWindowEnv(); - switch (windowEnv) { case WindowEnvironmentKind.ServiceWorker: { const pushSubscription = await (( From f8ec7235b8831ea1addeaaef415509dfa67ee8ee Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 03:51:58 +0000 Subject: [PATCH 25/35] corrected ForSecure naming --- src/shared/managers/SubscriptionManager.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index e763cb589..3f3ffd86f 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -761,10 +761,6 @@ export class SubscriptionManager { } public async isSubscriptionExpiring(): Promise { - return await this.isSubscriptionExpiringForSecureIntegration(); - } - - private async isSubscriptionExpiringForSecureIntegration(): Promise { const serviceWorkerState = await this.context.serviceWorkerManager.getActiveState(); if (!(serviceWorkerState === ServiceWorkerActiveState.OneSignalWorker)) { @@ -827,12 +823,12 @@ export class SubscriptionManager { } default: { /* Regular browser window environments */ - return this.getSubscriptionStateForSecure(); + return this.getSubscriptionStateFromBrowserContext(); } } } - private async getSubscriptionStateForSecure(): Promise { + private async getSubscriptionStateFromBrowserContext(): Promise { const { optedOut, subscriptionToken } = await Database.getSubscription(); const pushSubscriptionOSModel: OSModel | undefined = From 522cf9c0a1b3c81ecb63a3bb75cef02e66099ef2 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 03:54:25 +0000 Subject: [PATCH 26/35] rm isInsecureOrigin(), as it is deadcode --- src/shared/managers/SdkEnvironment.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shared/managers/SdkEnvironment.ts b/src/shared/managers/SdkEnvironment.ts index 589727293..bd2f286bf 100644 --- a/src/shared/managers/SdkEnvironment.ts +++ b/src/shared/managers/SdkEnvironment.ts @@ -59,10 +59,6 @@ export default class SdkEnvironment { } } - public static isInsecureOrigin() { - return !window.isSecureContext; - } - static getOrigin(): string { if (Environment.isBrowser()) { return window.location.origin; From 12e835ae59428a551dadc3d8548548ecd0697689 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 04:00:02 +0000 Subject: [PATCH 27/35] rm postmam This was used to talk between the removed os.tc iframe and the main page --- src/onesignal/OneSignal.ts | 43 ---- src/shared/services/Postmam.ts | 381 --------------------------------- test/unit/modules/postmam.ts | 169 --------------- 3 files changed, 593 deletions(-) delete mode 100755 src/shared/services/Postmam.ts delete mode 100644 test/unit/modules/postmam.ts diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index 8cfb86421..b9fbc2fd2 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -308,49 +308,6 @@ export default class OneSignal { static User = new UserNamespace(false); static Debug = new DebugNamespace(); /* END NEW USER MODEL CHANGES */ - - static POSTMAM_COMMANDS = { - CONNECTED: 'connect', - REMOTE_NOTIFICATION_PERMISSION: 'postmam.remoteNotificationPermission', - REMOTE_DATABASE_GET: 'postmam.remoteDatabaseGet', - REMOTE_DATABASE_GET_ALL: 'postmam.remoteDatabaseGetAll', - REMOTE_DATABASE_PUT: 'postmam.remoteDatabasePut', - REMOTE_DATABASE_REMOVE: 'postmam.remoteDatabaseRemove', - REMOTE_OPERATION_COMPLETE: 'postman.operationComplete', - REMOTE_RETRIGGER_EVENT: 'postmam.remoteRetriggerEvent', - MODAL_LOADED: 'postmam.modalPrompt.loaded', - MODAL_PROMPT_ACCEPTED: 'postmam.modalPrompt.accepted', - MODAL_PROMPT_REJECTED: 'postmam.modalPrompt.canceled', - POPUP_LOADED: 'postmam.popup.loaded', - POPUP_ACCEPTED: 'postmam.popup.accepted', - POPUP_REJECTED: 'postmam.popup.canceled', - POPUP_CLOSING: 'postman.popup.closing', - REMOTE_NOTIFICATION_PERMISSION_CHANGED: - 'postmam.remoteNotificationPermissionChanged', - IFRAME_POPUP_INITIALIZE: 'postmam.iframePopupInitialize', - UNSUBSCRIBE_FROM_PUSH: 'postmam.unsubscribeFromPush', - SET_SESSION_COUNT: 'postmam.setSessionCount', - REQUEST_HOST_URL: 'postmam.requestHostUrl', - WINDOW_TIMEOUT: 'postmam.windowTimeout', - FINISH_REMOTE_REGISTRATION: 'postmam.finishRemoteRegistration', - FINISH_REMOTE_REGISTRATION_IN_PROGRESS: - 'postmam.finishRemoteRegistrationInProgress', - POPUP_BEGIN_MESSAGEPORT_COMMS: 'postmam.beginMessagePortComms', - SERVICEWORKER_COMMAND_REDIRECT: 'postmam.command.redirect', - MARK_PROMPT_DISMISSED: 'postmam.markPromptDismissed', - IS_SUBSCRIBED: 'postmam.isSubscribed', - UNSUBSCRIBE_PROXY_FRAME: 'postman.unsubscribeProxyFrame', - GET_EVENT_LISTENER_COUNT: 'postmam.getEventListenerCount', - SERVICE_WORKER_STATE: 'postmam.serviceWorkerState', - GET_WORKER_VERSION: 'postmam.getWorkerVersion', - SUBSCRIPTION_EXPIRATION_STATE: 'postmam.subscriptionExpirationState', - PROCESS_EXPIRING_SUBSCRIPTIONS: 'postmam.processExpiringSubscriptions', - GET_SUBSCRIPTION_STATE: 'postmam.getSubscriptionState', - SESSION_UPSERT: 'postmam.sessionUpsert', - SESSION_DEACTIVATE: 'postmam.sessionDeactivate', - ARE_YOU_VISIBLE_REQUEST: 'postmam.areYouVisibleRequest', - ARE_YOU_VISIBLE_RESPONSE: 'postmam.areYouVisibleResponse', - }; } Log.info( diff --git a/src/shared/services/Postmam.ts b/src/shared/services/Postmam.ts deleted file mode 100755 index b25e6251c..000000000 --- a/src/shared/services/Postmam.ts +++ /dev/null @@ -1,381 +0,0 @@ -import Environment from '../helpers/Environment'; -import SdkEnvironment from '../managers/SdkEnvironment'; -import Emitter from '../libraries/Emitter'; -import Log from '../libraries/Log'; -import { Utils } from '../context/Utils'; -import { OneSignalUtils } from '../utils/OneSignalUtils'; - -/** - * Establishes a cross-domain MessageChannel between the current browsing context (this page) and another - * (an iFrame, popup, or parent page). - */ -export default class Postmam { - static get HANDSHAKE_MESSAGE() { - return 'onesignal.postmam.handshake'; - } - - static get CONNECTED_MESSAGE() { - return 'onesignal.postmam.connected'; - } - - public emitter: Emitter; - public channel: MessageChannel; - public messagePort: MessagePort | null; - public isListening: boolean; - public isConnected: boolean; - public replies: any; - - /** - * Initializes Postmam with settings but does not establish a connection a channel or set up any message listeners. - * @param windowReference The window to postMessage() the initial MessageChannel port to. - * @param sendToOrigin The origin that will receive the initial postMessage with the transferred message channel - * port object. - * @param receiveFromOrigin The origin to allow incoming messages from. If messages do not come from this origin - * they will be discarded. Only affects the initial handshake. - * @remarks The initiating (client) page must call this after the page has been loaded so that the other page has - * a chance to receive the initial handshake message. The receiving (server) page must set up a message listener - * to catch the initial handshake message. - */ - constructor( - public windowReference: any, - public sendToOrigin: string, - public receiveFromOrigin: string, - ) { - if (!window || !window.postMessage) { - throw new Error( - `Must pass in a valid window reference supporting postMessage(): ${windowReference}`, - ); - } - if (!sendToOrigin || !receiveFromOrigin) { - throw new Error('Invalid origin. Must be set.'); - } - this.emitter = new Emitter(); - this.channel = new MessageChannel(); - this.messagePort = null; - this.isListening = false; - this.isConnected = false; - this.replies = {}; - } - - /** - * Opens a message event listener to listen for a Postmam handshake from another browsing context. This - * listener is closed as soon as the connection is established. - */ - listen() { - Log.debug('(Postmam) Called listen().'); - if (this.isListening) { - Log.debug('(Postmam) Already listening for Postmam connections.'); - return; - } - if (!Environment.isBrowser()) { - return; - } - this.isListening = true; - Log.debug('(Postmam) Listening for Postmam connections.', this); - // One of the messages will contain our MessageChannel port - window.addEventListener( - 'message', - this.onWindowMessagePostmanConnectReceived.bind(this), - ); - } - - startPostMessageReceive() { - window.addEventListener( - 'message', - this.onWindowPostMessageReceived.bind(this), - ); - } - - stopPostMessageReceive() { - window.removeEventListener('message', this.onWindowPostMessageReceived); - } - - destroy() { - this.stopPostMessageReceive(); - this.emitter.removeAllListeners(); - } - - onWindowPostMessageReceived(e) { - // Discard messages from unexpected origins; messages come frequently from other origins - if (!this.isSafeOrigin(e.origin)) { - // Log.debug(`(Postmam) Discarding message because ${e.origin} is not an allowed origin:`, e.data); - return; - } - //Log.debug(`(Postmam) (onWindowPostMessageReceived) (${SdkEnvironment.getWindowEnv().toString()}):`, e); - const { - id: messageId, - command: messageCommand, - data: messageData, - source: messageSource, - } = e.data; - if (messageCommand === Postmam.CONNECTED_MESSAGE) { - this.emitter.emit('connect'); - this.isConnected = true; - return; - } - const messageBundle = { - id: messageId, - command: messageCommand, - data: messageData, - source: messageSource, - }; - const messageBundleWithReply = { - reply: this.reply.bind(this, messageBundle), - ...messageBundle, - }; - // eslint-disable-next-line no-prototype-builtins - if (this.replies.hasOwnProperty(messageId)) { - Log.info('(Postmam) This message is a reply.'); - const replyFn = this.replies[messageId].bind(window); - const replyFnReturnValue = replyFn(messageBundleWithReply); - if (replyFnReturnValue === false) { - delete this.replies[messageId]; - } - } else { - this.emitter.emit(messageCommand, messageBundleWithReply); - } - } - - onWindowMessagePostmanConnectReceived(e) { - const env = SdkEnvironment.getWindowEnv().toString(); - Log.debug( - `(Postmam) (${env}) Window postmessage for Postman connect received:`, - e, - ); - // Discard messages from unexpected origins; messages come frequently from other origins - if (!this.isSafeOrigin(e.origin)) { - // Log.debug(`(Postmam) Discarding message because ${e.origin} is not an allowed origin:`, e.data) - return; - } - const { handshake } = e.data; - if (handshake !== Postmam.HANDSHAKE_MESSAGE) { - Log.info( - '(Postmam) Got a postmam message, but not our expected handshake:', - e.data, - ); - // This was not our expected handshake message - return; - } else { - Log.info( - '(Postmam) Got our expected Postmam handshake message (and connecting...):', - e.data, - ); - // This was our expected handshake message - // Remove our message handler so we don't get spammed with cross-domain messages - window.removeEventListener( - 'message', - this.onWindowMessagePostmanConnectReceived, - ); - // Get the message port - this.messagePort = e.ports[0]; - this.messagePort?.addEventListener( - 'message', - this.onMessageReceived.bind(this), - false, - ); - Log.info( - '(Postmam) Removed previous message event listener for handshakes, replaced with main message listener.', - ); - this.messagePort?.start(); - this.isConnected = true; - Log.info(`(Postmam) (${env}) Connected.`); - this.message(Postmam.CONNECTED_MESSAGE); - this.emitter.emit('connect'); - } - } - - /** - * Establishes a message channel with a listening Postmam on another browsing context. - * @remarks Only call this if listen() is called on another page. - */ - connect() { - Log.info( - `(Postmam) (${SdkEnvironment.getWindowEnv().toString()}) Establishing a connection to ${ - this.sendToOrigin - }.`, - ); - this.messagePort = this.channel.port1; - this.messagePort.addEventListener( - 'message', - this.onMessageReceived.bind(this), - false, - ); - this.messagePort.start(); - this.windowReference.postMessage( - { - handshake: Postmam.HANDSHAKE_MESSAGE, - }, - this.sendToOrigin, - [this.channel.port2], - ); - } - - onMessageReceived(e) { - //Log.debug(`(Postmam) (${SdkEnvironment.getWindowEnv().toString()}):`, e.data); - if (!e.data) { - Log.debug( - `(${SdkEnvironment.getWindowEnv().toString()}) Received an empty Postmam message:`, - e, - ); - return; - } - const { - id: messageId, - command: messageCommand, - data: messageData, - source: messageSource, - } = e.data; - if (messageCommand === Postmam.CONNECTED_MESSAGE) { - this.emitter.emit('connect'); - this.isConnected = true; - return; - } - const messageBundle = { - id: messageId, - command: messageCommand, - data: messageData, - source: messageSource, - }; - const messageBundleWithReply = { - reply: this.reply.bind(this, messageBundle), - ...messageBundle, - }; - // eslint-disable-next-line no-prototype-builtins - if (this.replies.hasOwnProperty(messageId)) { - const replyFn = this.replies[messageId].bind(window); - const replyFnReturnValue = replyFn(messageBundleWithReply); - if (replyFnReturnValue === false) { - delete this.replies[messageId]; - } - } else { - this.emitter.emit(messageCommand, messageBundleWithReply); - } - } - - reply(originalMessageBundle, data, onReply) { - const messageBundle = { - id: originalMessageBundle.id, - command: originalMessageBundle.command, - data: data, - source: SdkEnvironment.getWindowEnv().toString(), - isReply: true, - }; - if (typeof onReply === 'function') { - this.replies[messageBundle.id] = onReply; - } - this.messagePort.postMessage(messageBundle); - } - - /** - * Sends via window.postMessage. - */ - postMessage(command, data, onReply?) { - if (!command || command == '') { - throw new Error('(Postmam) Postmam command must not be empty.'); - } - if (typeof data === 'function') { - Log.debug('You passed a function to data, did you mean to pass null?'); - return; - } - const messageBundle = { - id: OneSignalUtils.getRandomUuid(), - command: command, - data: data, - source: SdkEnvironment.getWindowEnv().toString(), - }; - if (typeof onReply === 'function') { - this.replies[messageBundle.id] = onReply; - } - - // This is a dead code path, this file will be deleted in the future. - // this.windowReference.postMessage(messageBundle, '*'); - } - - /** - * Sends via MessageChannel.port.postMessage - */ - message(command, data?, onReply?) { - if (!command || command == '') { - throw new Error('(Postmam) Postmam command must not be empty.'); - } - if (typeof data === 'function') { - Log.debug('You passed a function to data, did you mean to pass null?'); - return; - } - const messageBundle = { - id: OneSignalUtils.getRandomUuid(), - command: command, - data: data, - source: SdkEnvironment.getWindowEnv().toString(), - }; - if (typeof onReply === 'function') { - this.replies[messageBundle.id] = onReply; - } - this.messagePort?.postMessage(messageBundle); - } - - /** - * If the provided Site URL on the dashboard, which restricts the post message origin, uses the https:// protocol - * Then relax the postMessage restriction to also allow the http:// protocol for the same domain. - */ - generateSafeOrigins(inputOrigin: string) { - // Trims trailing slashes and other undesirable artifacts - const safeOrigins = []; - try { - const url = new URL(inputOrigin); - let reducedHost = url.host; - if (url.host.indexOf('www.') === 0) { - reducedHost = url.host.replace('www.', ''); - } - if (url.protocol === 'https:') { - safeOrigins.push(`https://${reducedHost}`); - safeOrigins.push(`https://www.${reducedHost}`); - } else if (url.protocol === 'http:') { - safeOrigins.push(`http://${reducedHost}`); - safeOrigins.push(`http://www.${reducedHost}`); - safeOrigins.push(`https://${reducedHost}`); - safeOrigins.push(`https://www.${reducedHost}`); - } - } catch (ex) { - // Invalid URL: Users can enter '*' or 'https://*.google.com' which is invalid. - } - return safeOrigins; - } - - isSafeOrigin(messageOrigin) { - let subdomain; - if (!OneSignal.config) { - subdomain = 'x'; - } else { - subdomain = OneSignal.config.subdomain as string; - } - - const otherAllowedOrigins = this.generateSafeOrigins( - this.receiveFromOrigin, - ); - - return ( - // messageOrigin === '' || TODO: See if messageOrigin can be blank - messageOrigin === 'https://onesignal.com' || - messageOrigin === `https://${subdomain || ''}.onesignal.com` || - messageOrigin === `https://${subdomain || ''}.os.tc` || - messageOrigin === `https://${subdomain || ''}.os.tc:3001` || - messageOrigin === SdkEnvironment.getOneSignalApiUrl().origin || - this.receiveFromOrigin === '*' || - Utils.contains(otherAllowedOrigins, messageOrigin) - ); - } - - async on(...args: any[]) { - // eslint-disable-next-line prefer-spread - return this.emitter.on.apply(this.emitter, args); - } - async off(...args: any[]) { - // eslint-disable-next-line prefer-spread - return this.emitter.off.apply(this.emitter, args); - } - async once(...args: any[]) { - // eslint-disable-next-line prefer-spread - return this.emitter.once.apply(this.emitter, args); - } -} diff --git a/test/unit/modules/postmam.ts b/test/unit/modules/postmam.ts deleted file mode 100644 index 74bbd713c..000000000 --- a/test/unit/modules/postmam.ts +++ /dev/null @@ -1,169 +0,0 @@ -import '../../support/polyfills/polyfills'; -import anyTest, { TestInterface } from 'ava'; -import { TestEnvironment } from '../../support/sdk/TestEnvironment'; -import Postmam from '../../../src/shared/services/Postmam'; - -interface PostmamContext { - originalMessageChannel: MessageChannel; - expectedSafeHttpOrigins: string[]; - expectedSafeHttpsOrigins: string[]; - expectedSafeHttpOriginsForIrregularSubdomains: string[]; - expectedSafeHttpOriginsForReallyIrregularSubdomains: string[]; -} - -const test = anyTest as TestInterface; - -test.beforeEach(async (t) => { - await TestEnvironment.initialize(); - - // Stub MessageChannel - const fakeClass = class Test {}; - t.context.originalMessageChannel = (global as any).MessageChannel; - (global as any).MessageChannel = fakeClass; - - t.context.expectedSafeHttpOrigins = [ - 'http://site.com', - 'http://www.site.com', - 'https://site.com', - 'https://www.site.com', - ]; - - t.context.expectedSafeHttpsOrigins = [ - 'https://site.com', - 'https://www.site.com', - ]; - - t.context.expectedSafeHttpOriginsForIrregularSubdomains = [ - 'http://dev.www.site.com', - 'https://dev.www.site.com', - ]; - - t.context.expectedSafeHttpOriginsForReallyIrregularSubdomains = [ - 'http://dev.www2-6.en.site.com', - 'http://www.dev.www2-6.en.site.com', - 'https://dev.www2-6.en.site.com', - 'https://www.dev.www2-6.en.site.com', - ]; -}); - -test.afterEach(async (t) => { - (global as any).MessageChannel = t.context.originalMessageChannel; -}); - -/* - When a developer chooses a site URL to integrate HTTP web push, multiple - variants of his site origin will support prompting the user to subscribe - because the final subscription takes place outside of his site origins on our - subdomain of .os.tc. - - If a developer chooses to integrate HTTP web push on 'http://site.com', for - example, the prefix variants 'http://', 'http://www.', 'https://', and - 'https://www.' will all support prompting the user. The user will still be - subscribed on subdomain.os.tc though, and not on any one of the listed - origins. - - The above changes if the developer chooses to integrate HTTP web push on - 'https://site.com'. A developer might be forced to integrate HTTP web push on - an HTTPS site on platforms that don't allow uploading service worker files to - the root, which is a required stpe. We assume the user only wants users to be - prompted on the secure origins of his site, so we don't allow the 'http://' - and 'http://www.' variants. - - For HTTPS web push, we want to restrict visitors to subscribing on only one - single origin (the one listed on the dashboard web push config). - */ - -test('should generate correct safe HTTP site origins for varying inputs of the same origin', async (t) => { - const dashboardConfigSiteOrigins = [ - 'http://site.com', - 'http://site.com/', - 'http://www.site.com', - 'http://www.site.com/', - ]; - for (const dashboardConfigSiteOrigin of dashboardConfigSiteOrigins) { - const postmam = new Postmam( - window, - dashboardConfigSiteOrigin, - dashboardConfigSiteOrigin, - ); - for (const expectedSafeHttpOrigin of t.context.expectedSafeHttpOrigins) { - t.true(postmam.isSafeOrigin(expectedSafeHttpOrigin)); - } - } -}); - -test('should generate correct safe HTTPS site origins for varying inputs of the same origin', async (t) => { - const dashboardConfigSiteOrigins = [ - 'https://site.com', - 'https://site.com/', - 'https://www.site.com', - 'https://www.site.com/', - ]; - for (const dashboardConfigSiteOrigin of dashboardConfigSiteOrigins) { - const postmam = new Postmam( - window, - dashboardConfigSiteOrigin, - dashboardConfigSiteOrigin, - ); - for (const expectedSafeHttpsOrigin of t.context.expectedSafeHttpsOrigins) { - t.true(postmam.isSafeOrigin(expectedSafeHttpsOrigin)); - } - } -}); - -test('should generate correct safe HTTP site origins for an origin with an irregular subdomain', async (t) => { - const dashboardConfigSiteOrigins = [ - 'http://dev.www.site.com', - 'http://dev.www.site.com/', - ]; - for (const dashboardConfigSiteOrigin of dashboardConfigSiteOrigins) { - const postmam = new Postmam( - window, - dashboardConfigSiteOrigin, - dashboardConfigSiteOrigin, - ); - for (const expectedSafeHttpOrigin of t.context - .expectedSafeHttpOriginsForIrregularSubdomains) { - t.true(postmam.isSafeOrigin(expectedSafeHttpOrigin)); - } - } -}); - -test('should generate correct safe HTTP site origins for an origin with a really irregular subdomain', async (t) => { - const dashboardConfigSiteOrigins = [ - 'http://dev.www2-6.en.site.com', - 'http://dev.www2-6.en.site.com/', - 'http://www.dev.www2-6.en.site.com', - 'http://www.dev.www2-6.en.site.com/', - ]; - for (const dashboardConfigSiteOrigin of dashboardConfigSiteOrigins) { - const postmam = new Postmam( - window, - dashboardConfigSiteOrigin, - dashboardConfigSiteOrigin, - ); - for (const expectedSafeHttpOrigin of t.context - .expectedSafeHttpOriginsForReallyIrregularSubdomains) { - t.true(postmam.isSafeOrigin(expectedSafeHttpOrigin)); - } - } -}); - -test('should generate no safe origins for an invalid origin', async (t) => { - const dashboardConfigSiteOrigins = ['http://*.google.com', 'asdf']; - for (const dashboardConfigSiteOrigin of dashboardConfigSiteOrigins) { - const postmam = new Postmam( - window, - dashboardConfigSiteOrigin, - dashboardConfigSiteOrigin, - ); - t.false(postmam.isSafeOrigin('http://site.com')); - } -}); - -test('should allow any origin for legacy wildcard *', async (t) => { - const postmam = new Postmam(window, '*', '*'); - t.true(postmam.isSafeOrigin('http://site.com')); - t.true(postmam.isSafeOrigin('http://abcde.com')); - t.true(postmam.isSafeOrigin('http://1234.com')); -}); From 5dc895925a943690dc8eebeafc9519580aaa8fa8 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 04:32:57 +0000 Subject: [PATCH 28/35] clean up comments referring to subdomain feature --- src/entries/pageSdkInit.ts | 3 --- src/onesignal/OneSignalEvents.ts | 4 +--- src/shared/helpers/EventHelper.ts | 3 --- src/shared/helpers/InitHelper.ts | 5 ----- src/shared/managers/SubscriptionManager.ts | 6 ++---- src/shared/models/Subscription.ts | 3 +-- src/shared/services/Database.ts | 1 - src/sw/serviceWorker/ServiceWorker.ts | 9 +++------ 8 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/entries/pageSdkInit.ts b/src/entries/pageSdkInit.ts index 69cabd2db..0f6d52a9d 100644 --- a/src/entries/pageSdkInit.ts +++ b/src/entries/pageSdkInit.ts @@ -21,10 +21,7 @@ function onesignalSdkInit() { return; } - // We're running in the host page, iFrame of the host page, or popup window // Load OneSignal's web SDK - // TODO: A new iFrame and popup window pages probably need to be created for this major release? - // TODO: We might be able to remove this down the line but reasons to keep for now: // * Number of internal SDK code expects window.OneSignal // * Keep JS console usage easier for debugging / testing. diff --git a/src/onesignal/OneSignalEvents.ts b/src/onesignal/OneSignalEvents.ts index 106c4a16e..a6881729b 100644 --- a/src/onesignal/OneSignalEvents.ts +++ b/src/onesignal/OneSignalEvents.ts @@ -37,9 +37,7 @@ export const ONESIGNAL_EVENTS = { */ NOTIFICATION_CLICKED: 'click', /** - * Occurs after the document ready event fires and, for HTTP sites, the iFrame to subdomain.onesignal.com has - * loaded. - * Before this event, IndexedDB access is not possible for HTTP sites. + * Occurs after the document ready event fires */ SDK_INITIALIZED: 'initializeInternal', /** diff --git a/src/shared/helpers/EventHelper.ts b/src/shared/helpers/EventHelper.ts index b94a65708..a11c79e70 100755 --- a/src/shared/helpers/EventHelper.ts +++ b/src/shared/helpers/EventHelper.ts @@ -240,9 +240,6 @@ export default class EventHelper { /** * When notifications are clicked, because the site isn't open, the notification is stored in the database. The next * time the page opens, the event is triggered if its less than 5 minutes (usually page opens instantly from click). - * - * This method is fired for both HTTPS and HTTP sites, so for HTTP sites, the host URL needs to be used, not the - * subdomain.onesignal.com URL. */ static async fireStoredNotificationClicks() { await awaitOneSignalInitAndSupported(); diff --git a/src/shared/helpers/InitHelper.ts b/src/shared/helpers/InitHelper.ts index 945e13dcc..43f62ce4b 100755 --- a/src/shared/helpers/InitHelper.ts +++ b/src/shared/helpers/InitHelper.ts @@ -106,9 +106,6 @@ export default class InitHelper { /** * This event occurs after init. - * For HTTPS sites, this event is called after init. - * For HTTP sites, this event is called after the iFrame is created, - * and a message is received from the iFrame signaling cross-origin messaging is ready. * @private */ public static async onSdkInitialized() { @@ -209,8 +206,6 @@ export default class InitHelper { // Store initial values of notification permission, user ID, and manual subscription status // This is done so that the values can be later compared to see if anything changed - // This is done here for HTTPS, it is done after the call to _addSessionIframe in sessionInit for HTTP sites, - // since the iframe is needed for communication promises.push(InitHelper.storeInitialValues()); promises.push(InitHelper.installNativePromptPermissionChangedHook()); promises.push(InitHelper.setWelcomeNotificationFlag()); diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index 3f3ffd86f..5bec21db7 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -109,10 +109,8 @@ export class SubscriptionManager { /** * Subscribes for a web push subscription. * - * This method is aware of different subscription environments like subscribing from a webpage, - * service worker, or OneSignal HTTP popup and will select the correct method. This is intended to - * be the single public API for obtaining a raw web push subscription (i.e. what the browser - * returns from a successful subscription). + * This method can be called from the page context or a webpage a service worker context + * and will select the correct method. */ public async subscribe( subscriptionStrategy: SubscriptionStrategyKind, diff --git a/src/shared/models/Subscription.ts b/src/shared/models/Subscription.ts index 4cfd50fb7..aa9dd401b 100755 --- a/src/shared/models/Subscription.ts +++ b/src/shared/models/Subscription.ts @@ -19,8 +19,7 @@ export class Subscription implements Serializable { */ createdAt: number | undefined; /** - * For HTTP sites only. This property is stored on the native PushSubscription object, but it's inaccessible - * in cross-origin frames. + * This property is stored on the native PushSubscription object. */ expirationTime: number | null | undefined; diff --git a/src/shared/services/Database.ts b/src/shared/services/Database.ts index 0adcc2498..b52e98126 100644 --- a/src/shared/services/Database.ts +++ b/src/shared/services/Database.ts @@ -114,7 +114,6 @@ export default class Database { /** * Asynchronously retrieves the value of the key at the table (if key is specified), or the entire table * (if key is not specified). - * If on an iFrame or popup environment, retrieves from the correct IndexedDB database using cross-domain messaging. * @param table The table to retrieve the value from. * @param key The key in the table to retrieve the value of. Leave blank to get the entire table. * @returns {Promise} Returns a promise that fulfills when the value(s) are available. diff --git a/src/sw/serviceWorker/ServiceWorker.ts b/src/sw/serviceWorker/ServiceWorker.ts index d9d88d1f0..163df3e42 100755 --- a/src/sw/serviceWorker/ServiceWorker.ts +++ b/src/sw/serviceWorker/ServiceWorker.ts @@ -55,9 +55,6 @@ const MAX_CONFIRMED_DELIVERY_DELAY = 25; * The main service worker script fetching and displaying notifications to users in the background even when the client * site is not running. The worker is registered via the navigator.serviceWorker.register() call after the user first * allows notification permissions, and is a pre-requisite to subscribing for push notifications. - * - * For HTTPS sites, the service worker is registered site-wide at the top-level scope. For HTTP sites, the service - * worker is registered to the iFrame pointing to subdomain.onesignal.com. */ export class ServiceWorker { static UNSUBSCRIBED_FROM_NOTIFICATIONS: boolean | undefined; @@ -104,9 +101,9 @@ export class ServiceWorker { /** * Allows message passing between this service worker and pages on the same domain. - * Clients include any HTTPS site page, or the nested iFrame pointing to OneSignal on any HTTP site. This allows - * events like notification dismissed, clicked, and displayed to be fired on the clients. It also allows the - * clients to communicate with the service worker to close all active notifications. + * This allows events like notification dismissed, clicked, and displayed to be + * fired on the clients. It also allows the clients to communicate with the + * service worker to close all active notifications. */ static get workerMessenger(): WorkerMessenger { if (!(self as any).workerMessenger) { From 8a54932a4eba6ef7921d7d9cf1e32ca73d5a9a28 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 04:44:54 +0000 Subject: [PATCH 29/35] rm misc types and properites related to os.tc --- .../support/environment/TestEnvironment.ts | 1 - src/onesignal/OneSignal.ts | 3 -- src/onesignal/OneSignalEvents.ts | 7 ---- src/page/models/ProxyFrameInitOptions.ts | 13 -------- src/shared/errors/InvalidStateError.ts | 4 --- src/shared/models/PermissionPromptType.ts | 8 ----- src/shared/services/OneSignalEvent.ts | 33 +------------------ 7 files changed, 1 insertion(+), 68 deletions(-) delete mode 100644 src/page/models/ProxyFrameInitOptions.ts diff --git a/__test__/support/environment/TestEnvironment.ts b/__test__/support/environment/TestEnvironment.ts index 1582798e8..88a1aff5e 100644 --- a/__test__/support/environment/TestEnvironment.ts +++ b/__test__/support/environment/TestEnvironment.ts @@ -35,7 +35,6 @@ export interface TestEnvironmentConfig { permission?: NotificationPermission; addPrompts?: boolean; url?: string; - initializeAsIframe?: boolean; userAgent?: BrowserUserAgent; overrideServerConfig?: RecursivePartial; integration?: ConfigIntegrationKind; diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index b9fbc2fd2..dd86f9b32 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -278,10 +278,7 @@ export default class OneSignal { static environmentInfo?: EnvironmentInfo; static config: AppConfig | null = null; static _sessionInitAlreadyRunning = false; - static _windowWidth = 650; - static _windowHeight = 568; static _isNewVisitor = false; - static _channel = null; static timedLocalStorage = TimedLocalStorage; static initialized = false; static _didLoadITILibrary = false; diff --git a/src/onesignal/OneSignalEvents.ts b/src/onesignal/OneSignalEvents.ts index a6881729b..5c2d1e9ee 100644 --- a/src/onesignal/OneSignalEvents.ts +++ b/src/onesignal/OneSignalEvents.ts @@ -50,10 +50,6 @@ export const ONESIGNAL_EVENTS = { * OneSignal's server. */ REGISTERED: 'register', - /** - * Occurs as the HTTP popup is closing. - */ - POPUP_CLOSING: 'popupClose', /** * Occurs when the native permission prompt is displayed. */ @@ -69,9 +65,6 @@ export const ONESIGNAL_EVENTS = { /** * For internal testing only. Used for all sorts of things. */ - TEST_INIT_OPTION_DISABLED: 'testInitOptionDisabled', - TEST_WOULD_DISPLAY: 'testWouldDisplay', TEST_FINISHED_ALLOW_CLICK_HANDLING: 'testFinishedAllowClickHandling', - POPUP_WINDOW_TIMEOUT: 'popupWindowTimeout', SESSION_STARTED: 'os.sessionStarted', }; diff --git a/src/page/models/ProxyFrameInitOptions.ts b/src/page/models/ProxyFrameInitOptions.ts deleted file mode 100644 index fe386b1cf..000000000 --- a/src/page/models/ProxyFrameInitOptions.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AppConfig } from '../../shared/models/AppConfig'; - -export interface ProxyFrameInitOptions extends AppConfig { - /** - * Describes which origin is allowed to load our iFrame in a top-level page. - * - * This is set on OneSignal's dashboard as the Site URL property and passed - * in. - * - * This can be set to *. - */ - origin: string; -} diff --git a/src/shared/errors/InvalidStateError.ts b/src/shared/errors/InvalidStateError.ts index ff22a309c..300917dc6 100755 --- a/src/shared/errors/InvalidStateError.ts +++ b/src/shared/errors/InvalidStateError.ts @@ -8,7 +8,6 @@ export enum InvalidStateReason { UnsupportedEnvironment, MissingDomElement, ServiceWorkerNotActivated, - NoProxyFrame, } export class InvalidStateError extends OneSignalError { @@ -42,9 +41,6 @@ export class InvalidStateError extends OneSignalError { case InvalidStateReason.ServiceWorkerNotActivated: errorMessage = `The service worker must be activated first.`; break; - case InvalidStateReason.NoProxyFrame: - errorMessage = `No proxy frame.`; - break; } super(errorMessage); diff --git a/src/shared/models/PermissionPromptType.ts b/src/shared/models/PermissionPromptType.ts index 0b9a98317..cacb438ab 100644 --- a/src/shared/models/PermissionPromptType.ts +++ b/src/shared/models/PermissionPromptType.ts @@ -3,14 +3,6 @@ export enum PermissionPromptType { * The "main" browser native permission request dialog when prompting for local or push notification permissions. */ HttpsPermissionRequest = 'HTTPS permission request', - /** - * The "popup" to subdomain.onesignal.com. - */ - FullscreenHttpPermissionMessage = 'fullscreen HTTP permission message', - /** - * The full-screen HTTPS modal with a dimmed backdrop. - */ - FullscreenHttpsPermissionMessage = 'fullscreen HTTPS permission message', /** * The "sliding down" prompt. */ diff --git a/src/shared/services/OneSignalEvent.ts b/src/shared/services/OneSignalEvent.ts index 064d8a0c6..71ae73175 100755 --- a/src/shared/services/OneSignalEvent.ts +++ b/src/shared/services/OneSignalEvent.ts @@ -22,28 +22,6 @@ const SILENT_EVENTS = [ 'testEvent', ]; -const RETRIGGER_REMOTE_EVENTS = [ - 'onesignal.prompt.custom.clicked', - 'onesignal.prompt.native.permissionchanged', - 'onesignal.subscription.changed', - 'onesignal.internal.subscriptionset', - 'dbRebuilt', - 'initialize', - 'subscriptionSet', - 'sendWelcomeNotification', - 'subscriptionChange', - 'permissionChange', // notification - 'dbSet', - 'register', - 'willDisplay', // notification - 'dismiss', // notification - 'click', // notification - 'permissionPromptDisplay', - 'testWouldDisplay', - 'testInitOptionDisabled', - 'popupWindowTimeout', -]; - const LEGACY_EVENT_MAP: { [key: string]: string } = { permissionChange: 'onesignal.prompt.native.permissionchanged', subscriptionChange: 'onesignal.subscription.changed', @@ -55,20 +33,11 @@ export default class OneSignalEvent { * Triggers the specified event with optional custom data. * @param eventName The string event name to be emitted. * @param data Any JavaScript variable to be passed with the event. - * @param remoteTriggerEnv If this method is being called in a different environment (e.g. was triggered - * in iFrame but now retriggered on main host), this is the string of the original environment for logging purposes. */ - static async trigger( - eventName: string, - data?: any, - remoteTriggerEnv: string | null = null, - ) { + static async trigger(eventName: string, data?: any) { if (!Utils.contains(SILENT_EVENTS, eventName)) { const displayData = data; let env = Utils.capitalize(SdkEnvironment.getWindowEnv().toString()); - if (remoteTriggerEnv) { - env = `${env} ⬸ ${Utils.capitalize(remoteTriggerEnv)}`; - } if (displayData || displayData === false) { Log.debug(`(${env}) » ${eventName}:`, displayData); From 02352689eda34742e6db574a9b8073b12405b0ca Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 04:45:59 +0000 Subject: [PATCH 30/35] remove unused imports --- __test__/support/environment/TestEnvironment.ts | 1 - __test__/support/environment/TestEnvironmentHelpers.ts | 1 - __test__/unit/core/modelRepo.test.ts | 1 - __test__/unit/helpers/initHelper.test.ts | 1 - src/onesignal/OneSignal.ts | 2 -- src/shared/services/Database.ts | 3 --- src/shared/utils/LocalStorage.ts | 3 --- 7 files changed, 12 deletions(-) diff --git a/__test__/support/environment/TestEnvironment.ts b/__test__/support/environment/TestEnvironment.ts index 88a1aff5e..933f47cbe 100644 --- a/__test__/support/environment/TestEnvironment.ts +++ b/__test__/support/environment/TestEnvironment.ts @@ -13,7 +13,6 @@ import { stubNotification, mockUserAgent, } from './TestEnvironmentHelpers'; -import { HttpHttpsEnvironment } from '../models/HttpHttpsEnvironment'; import OperationCache from '../../../src/core/caching/OperationCache'; import 'fake-indexeddb/auto'; import { RecursivePartial } from '../../../src/shared/context/Utils'; diff --git a/__test__/support/environment/TestEnvironmentHelpers.ts b/__test__/support/environment/TestEnvironmentHelpers.ts index 0617b96e2..af523fe3a 100644 --- a/__test__/support/environment/TestEnvironmentHelpers.ts +++ b/__test__/support/environment/TestEnvironmentHelpers.ts @@ -8,7 +8,6 @@ import OneSignal from '../../../src/onesignal/OneSignal'; import { CUSTOM_LINK_CSS_CLASSES } from '../../../src/shared/slidedown/constants'; import { getSlidedownElement } from '../../../src/page/slidedown/SlidedownElement'; import { MockServiceWorkerContainerWithAPIBan } from '../mocks/models/MockServiceWorkerContainerWithAPIBan'; -import { HttpHttpsEnvironment } from '../models/HttpHttpsEnvironment'; import BrowserUserAgent from '../models/BrowserUserAgent'; import TestContext from './TestContext'; import { CoreModuleDirector } from '../../../src/core/CoreModuleDirector'; diff --git a/__test__/unit/core/modelRepo.test.ts b/__test__/unit/core/modelRepo.test.ts index 36d978724..b8ea7a36a 100644 --- a/__test__/unit/core/modelRepo.test.ts +++ b/__test__/unit/core/modelRepo.test.ts @@ -1,4 +1,3 @@ -import OneSignalUtils from '../../../src/shared/utils/OneSignalUtils'; import ModelCache from '../../../src/core/caching/ModelCache'; import CoreModule from '../../../src/core/CoreModule'; import { CoreModuleDirector } from '../../../src/core/CoreModuleDirector'; diff --git a/__test__/unit/helpers/initHelper.test.ts b/__test__/unit/helpers/initHelper.test.ts index 8fe272ded..8a7ec1bcc 100644 --- a/__test__/unit/helpers/initHelper.test.ts +++ b/__test__/unit/helpers/initHelper.test.ts @@ -1,4 +1,3 @@ -import OneSignalUtils from '../../../src/shared/utils/OneSignalUtils'; import InitHelper from '../../../src/shared/helpers/InitHelper'; import { TestEnvironment } from '../../support/environment/TestEnvironment'; import { MessageChannel } from 'worker_threads'; diff --git a/src/onesignal/OneSignal.ts b/src/onesignal/OneSignal.ts index dd86f9b32..bb6401603 100644 --- a/src/onesignal/OneSignal.ts +++ b/src/onesignal/OneSignal.ts @@ -12,12 +12,10 @@ import MainHelper from '../shared/helpers/MainHelper'; import Emitter from '../shared/libraries/Emitter'; import Log from '../shared/libraries/Log'; import SdkEnvironment from '../shared/managers/SdkEnvironment'; -import { SessionManager } from '../shared/managers/sessionManager/SessionManager'; import { AppUserConfig, AppConfig } from '../shared/models/AppConfig'; import { DeviceRecord } from '../shared/models/DeviceRecord'; import { AppUserConfigNotifyButton } from '../shared/models/Prompts'; import Database from '../shared/services/Database'; -import OneSignalUtils from '../shared/utils/OneSignalUtils'; import { logMethodCall } from '../shared/utils/utils'; import OneSignalEvent from '../shared/services/OneSignalEvent'; import NotificationsNamespace from './NotificationsNamespace'; diff --git a/src/shared/services/Database.ts b/src/shared/services/Database.ts index b52e98126..08a85d34c 100644 --- a/src/shared/services/Database.ts +++ b/src/shared/services/Database.ts @@ -10,11 +10,8 @@ import { } from '../models/OutcomesNotificationEvents'; import { ServiceWorkerState } from '../models/ServiceWorkerState'; import { Subscription } from '../models/Subscription'; -import { TestEnvironmentKind } from '../models/TestEnvironmentKind'; import { BundleEmail, EmailProfile } from '../models/EmailProfile'; import { Session, ONESIGNAL_SESSION_KEY } from '../models/Session'; -import SdkEnvironment from '../managers/SdkEnvironment'; -import OneSignalUtils from '../utils/OneSignalUtils'; import Log from '../libraries/Log'; import { SentUniqueOutcome } from '../models/Outcomes'; import { BundleSMS, SMSProfile } from '../models/SMSProfile'; diff --git a/src/shared/utils/LocalStorage.ts b/src/shared/utils/LocalStorage.ts index e359721ca..92b206fd4 100644 --- a/src/shared/utils/LocalStorage.ts +++ b/src/shared/utils/LocalStorage.ts @@ -1,6 +1,3 @@ -import { NotificationPermission } from '../models/NotificationPermission'; -import PermissionManager from '../managers/PermissionManager'; - const IS_OPTED_OUT = 'isOptedOut'; const IS_PUSH_NOTIFICATIONS_ENABLED = 'isPushNotificationsEnabled'; const PAGE_VIEWS = 'os_pageViews'; From 97fdfd11a1d4077cd66b767090f8f30ddf5f9f9c Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 04:59:03 +0000 Subject: [PATCH 31/35] clean up Safari in iframe detection OneSignal SDK can't be run in an iframe so this detection can be removed now. --- src/page/helpers/EnvironmentInfoHelper.ts | 7 +------ src/page/utils/BrowserSupportsPush.ts | 18 ++++-------------- test/unit/modules/browserSupport.ts | 12 ------------ 3 files changed, 5 insertions(+), 32 deletions(-) diff --git a/src/page/helpers/EnvironmentInfoHelper.ts b/src/page/helpers/EnvironmentInfoHelper.ts index 6eece666a..ed6d754b6 100644 --- a/src/page/helpers/EnvironmentInfoHelper.ts +++ b/src/page/helpers/EnvironmentInfoHelper.ts @@ -1,7 +1,6 @@ import bowser from 'bowser'; import { EnvironmentInfo } from '../models/EnvironmentInfo'; import { Browser } from '../../shared/models/Browser'; -import { isMacOSSafariInIframe } from '../utils/BrowserSupportsPush'; import Utils from '../../shared/context/Utils'; import { bowserCastle } from '../../shared/utils/bowserCastle'; @@ -44,11 +43,7 @@ export class EnvironmentInfoHelper { // NOTE: Returns false in a ServiceWorker context private static isMacOSSafari(): boolean { - if (typeof window.safari !== 'undefined') { - return true; - } - - return isMacOSSafariInIframe(); + return typeof window.safari !== 'undefined'; } private static getBrowserVersion(): number { diff --git a/src/page/utils/BrowserSupportsPush.ts b/src/page/utils/BrowserSupportsPush.ts index f42a45104..71303dc6e 100644 --- a/src/page/utils/BrowserSupportsPush.ts +++ b/src/page/utils/BrowserSupportsPush.ts @@ -6,24 +6,14 @@ // Checks if the browser supports push notifications by checking if specific // classes and properties on them exist export function isPushNotificationsSupported() { - return supportsVapidPush() || supportsSafariPush(); -} - -// Fallback detection for Safari on macOS in an iframe context -// - window.safari is undefined in this context -export function isMacOSSafariInIframe(): boolean { - return ( - window.top !== window && // isContextIframe - isSafariBrowser() && - navigator.platform === 'MacIntel' - ); // isMacOS + return supportsVapidPush() || supportsSafariLegacyPush(); } // Does the browser support legacy Safari push? (only available on macOS) -export function supportsSafariPush(): boolean { +export function supportsSafariLegacyPush(): boolean { return ( - (window.safari && typeof window.safari.pushNotification !== 'undefined') || - isMacOSSafariInIframe() + typeof window.safari !== 'undefined' && + typeof window.safari.pushNotification !== 'undefined' ); } diff --git a/test/unit/modules/browserSupport.ts b/test/unit/modules/browserSupport.ts index c32396177..882d9ac7e 100644 --- a/test/unit/modules/browserSupport.ts +++ b/test/unit/modules/browserSupport.ts @@ -32,13 +32,6 @@ function setupSafariWithoutPushEnv(): void { sandbox.stub(window, 'safari').value({}); } -// Safari on macOS when running in iframe context -function setupSafariMacOSInIframeContext(): void { - sandbox.stub(window, 'top').value('someOtherWindow'); - sandbox.stub(navigator, 'vendor').value('Apple Computer, Inc.'); - sandbox.stub(navigator, 'platform').value('MacIntel'); -} - test('should support browsers that have PushSubscriptionOptions.applicationServerKey defined', async (t) => { setupBrowserWithPushAPIWithVAPIDEnv(sandbox); t.true(isPushNotificationsSupported()); @@ -62,8 +55,3 @@ test('should not support Safari unless pushNotification is defined on window.saf setupSafariWithoutPushEnv(); t.false(isPushNotificationsSupported()); }); - -test('should support macOS Safari if running in iframe', async (t) => { - setupSafariMacOSInIframeContext(); - t.true(isPushNotificationsSupported()); -}); From e1be1bbd2291975d3d77de655d6982f27f8a9b90 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 04:59:28 +0000 Subject: [PATCH 32/35] remove onSession HTTP test --- test/unit/public-sdk-apis/onSession.ts | 52 -------------------------- 1 file changed, 52 deletions(-) diff --git a/test/unit/public-sdk-apis/onSession.ts b/test/unit/public-sdk-apis/onSession.ts index 379857be8..6c8b92b02 100644 --- a/test/unit/public-sdk-apis/onSession.ts +++ b/test/unit/public-sdk-apis/onSession.ts @@ -11,13 +11,11 @@ import { NotificationPermission } from '../../../src/shared/models/NotificationP import { UpdateManager } from '../../../src/shared/managers/UpdateManager'; import { PageViewManager } from '../../../src/shared/managers/PageViewManager'; import { SubscriptionManager } from '../../../src/shared/managers/SubscriptionManager'; -import InitHelper from '../../../src/shared/helpers/InitHelper'; import { markUserAsOptedOut, markUserAsSubscribed, stubServiceWorkerInstallation, } from '../../support/tester/sinonSandboxUtils'; -import { createSubscription } from '../../support/tester/utils'; import EventsTestHelper from '../../support/tester/EventsTestHelper'; import { DelayedPromptType } from '../../../src/shared/models/Prompts'; @@ -514,56 +512,6 @@ test.serial( }, ); -test.serial( - `HTTP: User not subscribed and not opted out => first page view => slidedown's autoPrompt is on => - click allow => sends player create`, - async (t) => { - const testConfig: TestEnvironmentConfig = { - integration: ConfigIntegrationKind.Custom, - pushIdentifier: 'granted', - stubSetTimeout: true, - }; - const stubs = await TestEnvironment.setupOneSignalPageWithStubs( - sinonSandbox, - testConfig, - t, - ); - - const eventsHelper = new EventsTestHelper(sinonSandbox); - EventsTestHelper.simulateSlidedownAllowAfterShown(); - eventsHelper.simulateSubscribingAfterNativeAllow(); - - const initializePromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => { - t.is(stubs.onSessionStub.callCount, 0); - t.is(stubs.createPlayerPostStub.callCount, 0); - resolve(); - }); - }); - - const subscriptionPromise = new Promise((resolve) => { - OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => { - t.is(stubs.onSessionStub.callCount, 1); - t.is(stubs.createPlayerPostStub.callCount, 1); - inspectPushRecordCreationRequest(t, stubs.createPlayerPostStub); - resolve(); - }); - }); - - const initPromise = OneSignal.init({ - appId, - promptOptions: { - slidedown: defaultSlidedownOptions, - }, - autoResubscribe: false, - }); - await initPromise; - t.is(OneSignal.context.pageViewManager.getPageViewCount(), 1); - await initializePromise; - await subscriptionPromise; - }, -); - /** Helper methods */ async function inspectPushRecordCreationRequest( t: ExecutionContext, From 593f80ff09bdc3e4a1eddaa41576ab847da8d169 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 05:00:47 +0000 Subject: [PATCH 33/35] rm dead code getSubscriptionStateForInsecure --- src/shared/managers/SubscriptionManager.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index 5bec21db7..8eb96b010 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -896,27 +896,6 @@ export class SubscriptionManager { }; } - private async getSubscriptionStateForInsecure(): Promise { - /* For HTTP, we need to rely on stored values; we never have access to the actual data */ - const { deviceId, subscriptionToken, optedOut } = - await Database.getSubscription(); - const notificationPermission = - await this.context.permissionManager.getNotificationPermission( - this.context.appConfig.safariWebId, - ); - - const isPushEnabled = !!( - deviceId && - subscriptionToken && - notificationPermission === NotificationPermission.Granted - ); - - return { - subscribed: isPushEnabled, - optedOut: !!optedOut, - }; - } - /** * Broadcasting to the server the fact user tried to subscribe but there was an error during service worker registration. * Do it only once for the first page view. From 6efdb7023623cfb5f1a8e645c29805d1c77bdb50 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 05:32:48 +0000 Subject: [PATCH 34/35] rm os.tc from cert gen config --- express_webpack/certs/ssl-cert-gen.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/express_webpack/certs/ssl-cert-gen.conf b/express_webpack/certs/ssl-cert-gen.conf index 598536ee7..1c36304e3 100644 --- a/express_webpack/certs/ssl-cert-gen.conf +++ b/express_webpack/certs/ssl-cert-gen.conf @@ -45,6 +45,3 @@ DNS.7 = washington DNS.8 = washington.localhost DNS.9 = 127.0.0.1 DNS.10 = 192.168.20.31 -DNS.11 = os.tc -DNS.12 = washington.os.tc -DNS.13 = oregon.os.tc From d869a8e2cdfc18e25d648d1cec009311054aadfb Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Thu, 23 Nov 2023 06:01:55 +0000 Subject: [PATCH 35/35] fix flaky test carry over It isn't clear why this started failing recently, but tests no longer fail after this change. --- __test__/unit/notifications/eventListeners.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__test__/unit/notifications/eventListeners.test.ts b/__test__/unit/notifications/eventListeners.test.ts index 5c86e7ecd..4f2804b7b 100644 --- a/__test__/unit/notifications/eventListeners.test.ts +++ b/__test__/unit/notifications/eventListeners.test.ts @@ -3,7 +3,7 @@ import EventHelper from '../../../src/shared/helpers/EventHelper'; describe('Notification Events', () => { beforeEach(async () => { - TestEnvironment.initialize(); + await TestEnvironment.initialize(); }); afterEach(() => {