| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | /* This Source Code Form is subject to the terms of the Mozilla Public | 
					
						
							|  |  |  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | 
					
						
							|  |  |  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); | 
					
						
							|  |  |  | const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); | 
					
						
							|  |  |  | const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); | 
					
						
							|  |  |  | const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); | 
					
						
							|  |  |  | const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm"); | 
					
						
							|  |  |  | const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm"); | 
					
						
							|  |  |  | const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); | 
					
						
							|  |  |  | const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  | const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  | const Cr = Components.results; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | const helper = new Helper(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const IDENTITY_NAME = 'JUGGLER '; | 
					
						
							|  |  |  | const HUNDRED_YEARS = 60 * 60 * 24 * 365 * 100; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ALL_PERMISSIONS = [ | 
					
						
							|  |  |  |   'geo', | 
					
						
							|  |  |  |   'desktop-notification', | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DownloadInterceptor { | 
					
						
							|  |  |  |   constructor(registry) { | 
					
						
							|  |  |  |     this._registry = registry | 
					
						
							|  |  |  |     this._handlerToUuid = new Map(); | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |     this._uuidToHandler = new Map(); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   // nsIDownloadInterceptor implementation.
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   interceptDownloadRequest(externalAppHandler, request, browsingContext, outFile) { | 
					
						
							| 
									
										
										
										
											2020-10-06 00:15:24 -07:00
										 |  |  |     if (!(request instanceof Ci.nsIChannel)) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     const channel = request.QueryInterface(Ci.nsIChannel); | 
					
						
							| 
									
										
										
										
											2021-11-01 17:37:07 +01:00
										 |  |  |     let pageTarget = this._registry._browserBrowsingContextToTarget.get(channel.loadInfo.browsingContext.top); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     if (!pageTarget) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const browserContext = pageTarget.browserContext(); | 
					
						
							|  |  |  |     const options = browserContext.downloadOptions; | 
					
						
							|  |  |  |     if (!options) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const uuid = helper.generateId(); | 
					
						
							|  |  |  |     let file = null; | 
					
						
							|  |  |  |     if (options.behavior === 'saveToDisk') { | 
					
						
							|  |  |  |       file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); | 
					
						
							|  |  |  |       file.initWithPath(options.downloadsDir); | 
					
						
							|  |  |  |       file.append(uuid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         dump(`interceptDownloadRequest failed to create file: ${e}\n`); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     outFile.value = file; | 
					
						
							|  |  |  |     this._handlerToUuid.set(externalAppHandler, uuid); | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |     this._uuidToHandler.set(uuid, externalAppHandler); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     const downloadInfo = { | 
					
						
							|  |  |  |       uuid, | 
					
						
							|  |  |  |       browserContextId: browserContext.browserContextId, | 
					
						
							|  |  |  |       pageTargetId: pageTarget.id(), | 
					
						
							|  |  |  |       url: request.name, | 
					
						
							|  |  |  |       suggestedFileName: externalAppHandler.suggestedFileName, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     this._registry.emit(TargetRegistry.Events.DownloadCreated, downloadInfo); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onDownloadComplete(externalAppHandler, canceled, errorName) { | 
					
						
							|  |  |  |     const uuid = this._handlerToUuid.get(externalAppHandler); | 
					
						
							|  |  |  |     if (!uuid) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     this._handlerToUuid.delete(externalAppHandler); | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |     this._uuidToHandler.delete(uuid); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     const downloadInfo = { | 
					
						
							|  |  |  |       uuid, | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |       error: errorName, | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |     if (canceled === 'NS_BINDING_ABORTED') { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       downloadInfo.canceled = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._registry.emit(TargetRegistry.Events.DownloadFinished, downloadInfo); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   async cancelDownload(uuid) { | 
					
						
							|  |  |  |     const externalAppHandler = this._uuidToHandler.get(uuid); | 
					
						
							|  |  |  |     if (!externalAppHandler) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await externalAppHandler.cancel(Cr.NS_BINDING_ABORTED); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  | const screencastService = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | class TargetRegistry { | 
					
						
							|  |  |  |   constructor() { | 
					
						
							|  |  |  |     EventEmitter.decorate(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._browserContextIdToBrowserContext = new Map(); | 
					
						
							|  |  |  |     this._userContextIdToBrowserContext = new Map(); | 
					
						
							|  |  |  |     this._browserToTarget = new Map(); | 
					
						
							|  |  |  |     this._browserBrowsingContextToTarget = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 15:38:06 -07:00
										 |  |  |     this._browserProxy = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     // Cleanup containers from previous runs (if any)
 | 
					
						
							|  |  |  |     for (const identity of ContextualIdentityService.getPublicIdentities()) { | 
					
						
							|  |  |  |       if (identity.name && identity.name.startsWith(IDENTITY_NAME)) { | 
					
						
							|  |  |  |         ContextualIdentityService.remove(identity.userContextId); | 
					
						
							|  |  |  |         ContextualIdentityService.closeContainerTabs(identity.userContextId); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._defaultContext = new BrowserContext(this, undefined, undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Services.obs.addObserver({ | 
					
						
							|  |  |  |       observe: (subject, topic, data) => { | 
					
						
							|  |  |  |         const browser = subject.ownerElement; | 
					
						
							|  |  |  |         if (!browser) | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         const target = this._browserToTarget.get(browser); | 
					
						
							|  |  |  |         if (!target) | 
					
						
							|  |  |  |           return; | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |         target.emit(PageTarget.Events.Crashed); | 
					
						
							| 
									
										
										
										
											2020-08-25 14:50:40 -07:00
										 |  |  |         target.dispose(); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     }, 'oop-frameloader-crashed'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Services.mm.addMessageListener('juggler:content-ready', { | 
					
						
							|  |  |  |       receiveMessage: message => { | 
					
						
							|  |  |  |         const linkedBrowser = message.target; | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |         const target = this._browserToTarget.get(linkedBrowser); | 
					
						
							|  |  |  |         if (!target) | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |           return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							| 
									
										
										
										
											2022-02-14 20:32:12 -08:00
										 |  |  |           initScripts: target.browserContext().initScripts, | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |           bindings: target.browserContext().bindings, | 
					
						
							|  |  |  |           settings: target.browserContext().settings, | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |         }; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |     const onTabOpenListener = (appWindow, window, event) => { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       const tab = event.target; | 
					
						
							|  |  |  |       const userContextId = tab.userContextId; | 
					
						
							|  |  |  |       const browserContext = this._userContextIdToBrowserContext.get(userContextId); | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  |       const hasExplicitSize = appWindow && (appWindow.chromeFlags & Ci.nsIWebBrowserChrome.JUGGLER_WINDOW_EXPLICIT_SIZE) !== 0; | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |       const openerContext = tab.linkedBrowser.browsingContext.opener; | 
					
						
							|  |  |  |       let openerTarget; | 
					
						
							|  |  |  |       if (openerContext) { | 
					
						
							| 
									
										
										
										
											2021-10-28 02:16:37 -07:00
										 |  |  |         // Popups usually have opener context. Get top context for the case when opener is
 | 
					
						
							|  |  |  |         // an iframe.
 | 
					
						
							|  |  |  |         openerTarget = this._browserBrowsingContextToTarget.get(openerContext.top); | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |       } else if (tab.openerTab) { | 
					
						
							|  |  |  |         // Noopener popups from the same window have opener tab instead.
 | 
					
						
							|  |  |  |         openerTarget = this._browserToTarget.get(tab.openerTab.linkedBrowser); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!browserContext) | 
					
						
							|  |  |  |         throw new Error(`Internal error: cannot find context for userContextId=${userContextId}`); | 
					
						
							|  |  |  |       const target = new PageTarget(this, window, tab, browserContext, openerTarget); | 
					
						
							| 
									
										
										
										
											2020-09-30 08:02:22 -07:00
										 |  |  |       target.updateUserAgent(); | 
					
						
							| 
									
										
										
										
											2021-08-25 11:45:45 -04:00
										 |  |  |       target.updatePlatform(); | 
					
						
							| 
									
										
										
										
											2021-08-11 03:37:57 +03:00
										 |  |  |       target.updateJavaScriptDisabled(); | 
					
						
							| 
									
										
										
										
											2020-11-18 08:19:09 -08:00
										 |  |  |       target.updateTouchOverride(); | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |       target.updateColorSchemeOverride(); | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  |       target.updateReducedMotionOverride(); | 
					
						
							| 
									
										
										
										
											2021-06-08 16:00:15 -07:00
										 |  |  |       target.updateForcedColorsOverride(); | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |       if (!hasExplicitSize) | 
					
						
							|  |  |  |         target.updateViewportSize(); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |       if (browserContext.videoRecordingOptions) | 
					
						
							|  |  |  |         target._startVideoRecording(browserContext.videoRecordingOptions); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 12:52:43 -07:00
										 |  |  |     const onTabCloseListener = event => { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       const tab = event.target; | 
					
						
							|  |  |  |       const linkedBrowser = tab.linkedBrowser; | 
					
						
							|  |  |  |       const target = this._browserToTarget.get(linkedBrowser); | 
					
						
							| 
									
										
										
										
											2020-08-20 13:26:04 -07:00
										 |  |  |       if (target) | 
					
						
							| 
									
										
										
										
											2020-08-25 14:50:40 -07:00
										 |  |  |           target.dispose(); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |     const domWindowTabListeners = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const onOpenWindow = async (appWindow) => { | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       let domWindow; | 
					
						
							|  |  |  |       if (appWindow instanceof Ci.nsIAppWindow) { | 
					
						
							|  |  |  |         domWindow = appWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         domWindow = appWindow; | 
					
						
							|  |  |  |         appWindow = null; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |       if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |       // In persistent mode, window might be opened long ago and might be
 | 
					
						
							|  |  |  |       // already initialized.
 | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |       // In this case, we want to keep this callback synchronous so that we will call
 | 
					
						
							|  |  |  |       // `onTabOpenListener` synchronously and before the sync IPc message `juggler:content-ready`.
 | 
					
						
							|  |  |  |       if (domWindow.document.readyState === 'uninitialized' || domWindow.document.readyState === 'loading') { | 
					
						
							|  |  |  |         // For non-initialized windows, DOMContentLoaded initializes gBrowser
 | 
					
						
							|  |  |  |         // and starts tab loading (see //browser/base/content/browser.js), so we
 | 
					
						
							|  |  |  |         // are guaranteed to call `onTabOpenListener` before the sync IPC message
 | 
					
						
							|  |  |  |         // `juggler:content-ready`.
 | 
					
						
							|  |  |  |         await helper.awaitEvent(domWindow, 'DOMContentLoaded'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (!domWindow.gBrowser) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       const tabContainer = domWindow.gBrowser.tabContainer; | 
					
						
							|  |  |  |       domWindowTabListeners.set(domWindow, [ | 
					
						
							|  |  |  |         helper.addEventListener(tabContainer, 'TabOpen', event => onTabOpenListener(appWindow, domWindow, event)), | 
					
						
							|  |  |  |         helper.addEventListener(tabContainer, 'TabClose', onTabCloseListener), | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |       for (const tab of domWindow.gBrowser.tabs) | 
					
						
							|  |  |  |         onTabOpenListener(appWindow, domWindow, { target: tab }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const onCloseWindow = window => { | 
					
						
							|  |  |  |       const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); | 
					
						
							|  |  |  |       if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       if (!domWindow.gBrowser) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const listeners = domWindowTabListeners.get(domWindow) || []; | 
					
						
							|  |  |  |       domWindowTabListeners.delete(domWindow); | 
					
						
							|  |  |  |       helper.removeListeners(listeners); | 
					
						
							|  |  |  |       for (const tab of domWindow.gBrowser.tabs) | 
					
						
							|  |  |  |         onTabCloseListener({ target: tab }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |     const extHelperAppSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Ci.nsIExternalHelperAppService); | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |     this._downloadInterceptor = new DownloadInterceptor(this); | 
					
						
							|  |  |  |     extHelperAppSvc.setDownloadInterceptor(this._downloadInterceptor); | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |     Services.wm.addListener({ onOpenWindow, onCloseWindow }); | 
					
						
							|  |  |  |     for (const win of Services.wm.getEnumerator(null)) | 
					
						
							|  |  |  |       onOpenWindow(win); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-30 01:29:58 +02:00
										 |  |  |   async cancelDownload(options) { | 
					
						
							|  |  |  |     this._downloadInterceptor.cancelDownload(options.uuid); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 15:38:06 -07:00
										 |  |  |   setBrowserProxy(proxy) { | 
					
						
							|  |  |  |     this._browserProxy = proxy; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getProxyInfo(channel) { | 
					
						
							|  |  |  |     const originAttributes = channel.loadInfo && channel.loadInfo.originAttributes; | 
					
						
							|  |  |  |     const browserContext = originAttributes ? this.browserContextForUserContextId(originAttributes.userContextId) : null; | 
					
						
							|  |  |  |     // Prefer context proxy and fallback to browser-level proxy.
 | 
					
						
							|  |  |  |     const proxyInfo = (browserContext && browserContext._proxy) || this._browserProxy; | 
					
						
							|  |  |  |     if (!proxyInfo || proxyInfo.bypass.some(domainSuffix => channel.URI.host.endsWith(domainSuffix))) | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     return proxyInfo; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   defaultContext() { | 
					
						
							|  |  |  |     return this._defaultContext; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   createBrowserContext(removeOnDetach) { | 
					
						
							|  |  |  |     return new BrowserContext(this, helper.generateId(), removeOnDetach); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   browserContextForId(browserContextId) { | 
					
						
							|  |  |  |     return this._browserContextIdToBrowserContext.get(browserContextId); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 08:52:43 -07:00
										 |  |  |   browserContextForUserContextId(userContextId) { | 
					
						
							|  |  |  |     return this._userContextIdToBrowserContext.get(userContextId); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   async newPage({browserContextId}) { | 
					
						
							|  |  |  |     const browserContext = this.browserContextForId(browserContextId); | 
					
						
							| 
									
										
										
										
											2020-07-02 14:46:57 -07:00
										 |  |  |     const features = "chrome,dialog=no,all"; | 
					
						
							|  |  |  |     // See _callWithURIToLoad in browser.js for the structure of window.arguments
 | 
					
						
							|  |  |  |     // window.arguments[1]: unused (bug 871161)
 | 
					
						
							|  |  |  |     //                 [2]: referrerInfo (nsIReferrerInfo)
 | 
					
						
							|  |  |  |     //                 [3]: postData (nsIInputStream)
 | 
					
						
							|  |  |  |     //                 [4]: allowThirdPartyFixup (bool)
 | 
					
						
							|  |  |  |     //                 [5]: userContextId (int)
 | 
					
						
							|  |  |  |     //                 [6]: originPrincipal (nsIPrincipal)
 | 
					
						
							|  |  |  |     //                 [7]: originStoragePrincipal (nsIPrincipal)
 | 
					
						
							|  |  |  |     //                 [8]: triggeringPrincipal (nsIPrincipal)
 | 
					
						
							|  |  |  |     //                 [9]: allowInheritPrincipal (bool)
 | 
					
						
							|  |  |  |     //                 [10]: csp (nsIContentSecurityPolicy)
 | 
					
						
							|  |  |  |     //                 [11]: nsOpenWindowInfo
 | 
					
						
							|  |  |  |     const args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); | 
					
						
							|  |  |  |     const urlSupports = Cc["@mozilla.org/supports-string;1"].createInstance( | 
					
						
							|  |  |  |       Ci.nsISupportsString | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     urlSupports.data = 'about:blank'; | 
					
						
							|  |  |  |     args.appendElement(urlSupports); // 0
 | 
					
						
							|  |  |  |     args.appendElement(undefined); // 1
 | 
					
						
							|  |  |  |     args.appendElement(undefined); // 2
 | 
					
						
							|  |  |  |     args.appendElement(undefined); // 3
 | 
					
						
							|  |  |  |     args.appendElement(undefined); // 4
 | 
					
						
							|  |  |  |     const userContextIdSupports = Cc[ | 
					
						
							|  |  |  |       "@mozilla.org/supports-PRUint32;1" | 
					
						
							|  |  |  |     ].createInstance(Ci.nsISupportsPRUint32); | 
					
						
							|  |  |  |     userContextIdSupports.data = browserContext.userContextId; | 
					
						
							|  |  |  |     args.appendElement(userContextIdSupports); // 5
 | 
					
						
							|  |  |  |     args.appendElement(undefined); // 6
 | 
					
						
							|  |  |  |     args.appendElement(undefined); // 7
 | 
					
						
							|  |  |  |     args.appendElement(Services.scriptSecurityManager.getSystemPrincipal()); // 8
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const window = Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, '_blank', features, args); | 
					
						
							|  |  |  |     await waitForWindowReady(window); | 
					
						
							|  |  |  |     if (window.gBrowser.browsers.length !== 1) | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |       throw new Error(`Unexpected number of tabs in the new window: ${window.gBrowser.browsers.length}`); | 
					
						
							| 
									
										
										
										
											2020-07-02 14:46:57 -07:00
										 |  |  |     const browser = window.gBrowser.browsers[0]; | 
					
						
							| 
									
										
										
										
											2022-06-30 11:07:38 -07:00
										 |  |  |     let target = this._browserToTarget.get(browser); | 
					
						
							|  |  |  |     while (!target) { | 
					
						
							|  |  |  |       await helper.awaitEvent(this, TargetRegistry.Events.TargetCreated); | 
					
						
							|  |  |  |       target = this._browserToTarget.get(browser); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-02 14:46:57 -07:00
										 |  |  |     browser.focus(); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     if (browserContext.settings.timezoneId) { | 
					
						
							|  |  |  |       if (await target.hasFailedToOverrideTimezone()) | 
					
						
							|  |  |  |         throw new Error('Failed to override timezone'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return target.id(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  |   targets() { | 
					
						
							|  |  |  |     return Array.from(this._browserToTarget.values()); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   targetForBrowser(browser) { | 
					
						
							|  |  |  |     return this._browserToTarget.get(browser); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PageTarget { | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |   constructor(registry, win, tab, browserContext, opener) { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     EventEmitter.decorate(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._targetId = helper.generateId(); | 
					
						
							|  |  |  |     this._registry = registry; | 
					
						
							| 
									
										
										
										
											2020-07-07 14:04:07 -07:00
										 |  |  |     this._window = win; | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |     this._gBrowser = win.gBrowser; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this._tab = tab; | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |     this._linkedBrowser = tab.linkedBrowser; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this._browserContext = browserContext; | 
					
						
							|  |  |  |     this._viewportSize = undefined; | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |     this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this._url = 'about:blank'; | 
					
						
							|  |  |  |     this._openerId = opener ? opener.id() : undefined; | 
					
						
							|  |  |  |     this._channel = SimpleChannel.createForMessageManager(`browser::page[${this._targetId}]`, this._linkedBrowser.messageManager); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     this._videoRecordingInfo = undefined; | 
					
						
							|  |  |  |     this._screencastRecordingInfo = undefined; | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |     this._dialogs = new Map(); | 
					
						
							| 
									
										
										
										
											2021-06-08 16:00:15 -07:00
										 |  |  |     this.forcedColors = 'no-override'; | 
					
						
							| 
									
										
										
										
											2022-02-14 20:32:12 -08:00
										 |  |  |     this._pageInitScripts = []; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const navigationListener = { | 
					
						
							| 
									
										
										
										
											2020-08-06 10:32:50 -07:00
										 |  |  |       QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       onLocationChange: (aWebProgress, aRequest, aLocation) => this._onNavigated(aLocation), | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     this._eventListeners = [ | 
					
						
							| 
									
										
										
										
											2020-10-28 14:47:14 -07:00
										 |  |  |       helper.addObserver(this._updateModalDialogs.bind(this), 'tabmodal-dialog-loaded'), | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION), | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |       helper.addEventListener(this._linkedBrowser, 'DOMModalDialogClosed', event => this._updateModalDialogs()), | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._disposed = false; | 
					
						
							| 
									
										
										
										
											2020-08-19 15:39:46 -07:00
										 |  |  |     browserContext.pages.add(this); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this._registry._browserToTarget.set(this._linkedBrowser, this); | 
					
						
							|  |  |  |     this._registry._browserBrowsingContextToTarget.set(this._linkedBrowser.browsingContext, this); | 
					
						
							| 
									
										
										
										
											2020-09-10 14:37:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  |     this._registry.emit(TargetRegistry.Events.TargetCreated, this); | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |   dialog(dialogId) { | 
					
						
							|  |  |  |     return this._dialogs.get(dialogId); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dialogs() { | 
					
						
							|  |  |  |     return [...this._dialogs.values()]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-10 14:37:48 -07:00
										 |  |  |   async windowReady() { | 
					
						
							|  |  |  |     await waitForWindowReady(this._window); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   linkedBrowser() { | 
					
						
							|  |  |  |     return this._linkedBrowser; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   browserContext() { | 
					
						
							|  |  |  |     return this._browserContext; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 08:19:09 -08:00
										 |  |  |   updateTouchOverride() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.touchEventsOverride = this._browserContext.touchOverride ? 'enabled' : 'none'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 08:02:22 -07:00
										 |  |  |   updateUserAgent() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.customUserAgent = this._browserContext.defaultUserAgent; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 11:45:45 -04:00
										 |  |  |   updatePlatform() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.customPlatform = this._browserContext.defaultPlatform; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 03:37:57 +03:00
										 |  |  |   updateJavaScriptDisabled() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.allowJavascript = !this._browserContext.javaScriptDisabled; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |   _updateModalDialogs() { | 
					
						
							|  |  |  |     const prompts = new Set(this._linkedBrowser.tabModalPromptBox ? this._linkedBrowser.tabModalPromptBox.listPrompts() : []); | 
					
						
							|  |  |  |     for (const dialog of this._dialogs.values()) { | 
					
						
							|  |  |  |       if (!prompts.has(dialog.prompt())) { | 
					
						
							|  |  |  |         this._dialogs.delete(dialog.id()); | 
					
						
							|  |  |  |         this.emit(PageTarget.Events.DialogClosed, dialog); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         prompts.delete(dialog.prompt()); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (const prompt of prompts) { | 
					
						
							|  |  |  |       const dialog = Dialog.createIfSupported(prompt); | 
					
						
							|  |  |  |       if (!dialog) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       this._dialogs.set(dialog.id(), dialog); | 
					
						
							|  |  |  |       this.emit(PageTarget.Events.DialogOpened, dialog); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |   async updateViewportSize() { | 
					
						
							|  |  |  |     // Viewport size is defined by three arguments:
 | 
					
						
							|  |  |  |     // 1. default size. Could be explicit if set as part of `window.open` call, e.g.
 | 
					
						
							|  |  |  |     //   `window.open(url, title, 'width=400,height=400')`
 | 
					
						
							|  |  |  |     // 2. page viewport size
 | 
					
						
							|  |  |  |     // 3. browserContext viewport size
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // The "default size" (1) is only respected when the page is opened.
 | 
					
						
							|  |  |  |     // Otherwise, explicitly set page viewport prevales over browser context
 | 
					
						
							|  |  |  |     // default viewport.
 | 
					
						
							|  |  |  |     const viewportSize = this._viewportSize || this._browserContext.defaultViewportSize; | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  |     const actualSize = await setViewportSizeForBrowser(viewportSize, this._linkedBrowser, this._window); | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |     this._linkedBrowser.browsingContext.overrideDPPX = this._browserContext.deviceScaleFactor || this._initialDPPX; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     await this._channel.connect('').send('awaitViewportDimensions', { | 
					
						
							|  |  |  |       width: actualSize.width, | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |       height: actualSize.height, | 
					
						
							|  |  |  |       deviceSizeIsPageSize: !!this._browserContext.deviceScaleFactor, | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |   setEmulatedMedia(mediumOverride) { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.mediumOverride = mediumOverride || ''; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setColorScheme(colorScheme) { | 
					
						
							|  |  |  |     this.colorScheme = fromProtocolColorScheme(colorScheme); | 
					
						
							|  |  |  |     this.updateColorSchemeOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateColorSchemeOverride() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.prefersColorSchemeOverride = this.colorScheme || this._browserContext.colorScheme || 'none'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  |   setReducedMotion(reducedMotion) { | 
					
						
							|  |  |  |     this.reducedMotion = fromProtocolReducedMotion(reducedMotion); | 
					
						
							|  |  |  |     this.updateReducedMotionOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateReducedMotionOverride() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.prefersReducedMotionOverride = this.reducedMotion || this._browserContext.reducedMotion || 'none'; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 16:00:15 -07:00
										 |  |  |   setForcedColors(forcedColors) { | 
					
						
							|  |  |  |     this.forcedColors = fromProtocolForcedColors(forcedColors); | 
					
						
							|  |  |  |     this.updateForcedColorsOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateForcedColorsOverride() { | 
					
						
							|  |  |  |     this._linkedBrowser.browsingContext.forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 02:10:34 -07:00
										 |  |  |   async setViewportSize(viewportSize) { | 
					
						
							|  |  |  |     this._viewportSize = viewportSize; | 
					
						
							|  |  |  |     await this.updateViewportSize(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 17:29:54 -08:00
										 |  |  |   close(runBeforeUnload = false) { | 
					
						
							|  |  |  |     this._gBrowser.removeTab(this._tab, { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       skipPermitUnload: !runBeforeUnload, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  |   channel() { | 
					
						
							|  |  |  |     return this._channel; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   id() { | 
					
						
							|  |  |  |     return this._targetId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   info() { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       targetId: this.id(), | 
					
						
							|  |  |  |       type: 'page', | 
					
						
							| 
									
										
										
										
											2020-08-19 15:39:46 -07:00
										 |  |  |       browserContextId: this._browserContext.browserContextId, | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       openerId: this._openerId, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _onNavigated(aLocation) { | 
					
						
							|  |  |  |     this._url = aLocation.spec; | 
					
						
							|  |  |  |     this._browserContext.grantPermissionsToOrigin(this._url); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async ensurePermissions() { | 
					
						
							|  |  |  |     await this._channel.connect('').send('ensurePermissions', {}).catch(e => void e); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-14 20:32:12 -08:00
										 |  |  |   async setInitScripts(scripts) { | 
					
						
							|  |  |  |     this._pageInitScripts = scripts; | 
					
						
							|  |  |  |     await this.pushInitScripts(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async pushInitScripts() { | 
					
						
							|  |  |  |     await this._channel.connect('').send('setInitScripts', [...this._browserContext.initScripts, ...this._pageInitScripts]).catch(e => void e); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 16:27:39 +00:00
										 |  |  |   async addBinding(worldName, name, script) { | 
					
						
							|  |  |  |     await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async applyContextSetting(name, value) { | 
					
						
							|  |  |  |     await this._channel.connect('').send('applyContextSetting', { name, value }).catch(e => void e); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async hasFailedToOverrideTimezone() { | 
					
						
							|  |  |  |     return await this._channel.connect('').send('hasFailedToOverrideTimezone').catch(e => true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 13:27:51 -07:00
										 |  |  |   async _startVideoRecording({width, height, dir}) { | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |     // On Mac the window may not yet be visible when TargetCreated and its
 | 
					
						
							|  |  |  |     // NSWindow.windowNumber may be -1, so we wait until the window is known
 | 
					
						
							|  |  |  |     // to be initialized and visible.
 | 
					
						
							|  |  |  |     await this.windowReady(); | 
					
						
							|  |  |  |     const file = OS.Path.join(dir, helper.generateId() + '.webm'); | 
					
						
							|  |  |  |     if (width < 10 || width > 10000 || height < 10 || height > 10000) | 
					
						
							|  |  |  |       throw new Error("Invalid size"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const docShell = this._gBrowser.ownerGlobal.docShell; | 
					
						
							|  |  |  |     // Exclude address bar and navigation control from the video.
 | 
					
						
							|  |  |  |     const rect = this.linkedBrowser().getBoundingClientRect(); | 
					
						
							|  |  |  |     const devicePixelRatio = this._window.devicePixelRatio; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     let sessionId; | 
					
						
							|  |  |  |     const registry = this._registry; | 
					
						
							|  |  |  |     const screencastClient = { | 
					
						
							|  |  |  |       QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), | 
					
						
							|  |  |  |       screencastFrame(data, deviceWidth, deviceHeight) { | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       screencastStopped() { | 
					
						
							|  |  |  |         registry.emit(TargetRegistry.Events.ScreencastStopped, sessionId); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |     const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; | 
					
						
							|  |  |  |     sessionId = screencastService.startVideoRecording(screencastClient, docShell, true, file, width, height, 0, viewport.width, viewport.height, devicePixelRatio * rect.top); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     this._videoRecordingInfo = { sessionId, file }; | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |     this.emit(PageTarget.Events.ScreencastStarted); | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   _stopVideoRecording() { | 
					
						
							|  |  |  |     if (!this._videoRecordingInfo) | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |       throw new Error('No video recording in progress'); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     const videoRecordingInfo = this._videoRecordingInfo; | 
					
						
							|  |  |  |     this._videoRecordingInfo = undefined; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     screencastService.stopVideoRecording(videoRecordingInfo.sessionId); | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   videoRecordingInfo() { | 
					
						
							|  |  |  |     return this._videoRecordingInfo; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async startScreencast({ width, height, quality }) { | 
					
						
							|  |  |  |     // On Mac the window may not yet be visible when TargetCreated and its
 | 
					
						
							|  |  |  |     // NSWindow.windowNumber may be -1, so we wait until the window is known
 | 
					
						
							|  |  |  |     // to be initialized and visible.
 | 
					
						
							|  |  |  |     await this.windowReady(); | 
					
						
							|  |  |  |     if (width < 10 || width > 10000 || height < 10 || height > 10000) | 
					
						
							|  |  |  |       throw new Error("Invalid size"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const docShell = this._gBrowser.ownerGlobal.docShell; | 
					
						
							|  |  |  |     // Exclude address bar and navigation control from the video.
 | 
					
						
							|  |  |  |     const rect = this.linkedBrowser().getBoundingClientRect(); | 
					
						
							|  |  |  |     const devicePixelRatio = this._window.devicePixelRatio; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const self = this; | 
					
						
							|  |  |  |     const screencastClient = { | 
					
						
							|  |  |  |       QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), | 
					
						
							|  |  |  |       screencastFrame(data, deviceWidth, deviceHeight) { | 
					
						
							|  |  |  |         if (self._screencastRecordingInfo) | 
					
						
							|  |  |  |           self.emit(PageTarget.Events.ScreencastFrame, { data, deviceWidth, deviceHeight }); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       screencastStopped() { | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-05-10 22:01:41 -07:00
										 |  |  |     const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; | 
					
						
							|  |  |  |     const screencastId = screencastService.startVideoRecording(screencastClient, docShell, false, '', width, height, quality || 90, viewport.width, viewport.height, devicePixelRatio * rect.top); | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     this._screencastRecordingInfo = { screencastId }; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     return { screencastId }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   screencastFrameAck({ screencastId }) { | 
					
						
							|  |  |  |     if (!this._screencastRecordingInfo || this._screencastRecordingInfo.screencastId !== screencastId) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     screencastService.screencastFrameAck(screencastId); | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   stopScreencast() { | 
					
						
							|  |  |  |     if (!this._screencastRecordingInfo) | 
					
						
							|  |  |  |       throw new Error('No screencast in progress'); | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     const { screencastId } = this._screencastRecordingInfo; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     this._screencastRecordingInfo = undefined; | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |     screencastService.stopVideoRecording(screencastId); | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 14:50:40 -07:00
										 |  |  |   dispose() { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this._disposed = true; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     if (this._videoRecordingInfo) | 
					
						
							|  |  |  |       this._stopVideoRecording(); | 
					
						
							|  |  |  |     if (this._screencastRecordingInfo) | 
					
						
							|  |  |  |       this.stopScreencast(); | 
					
						
							| 
									
										
										
										
											2020-08-25 14:50:40 -07:00
										 |  |  |     this._browserContext.pages.delete(this); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this._registry._browserToTarget.delete(this._linkedBrowser); | 
					
						
							|  |  |  |     this._registry._browserBrowsingContextToTarget.delete(this._linkedBrowser.browsingContext); | 
					
						
							| 
									
										
										
										
											2020-11-20 10:48:06 -08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       helper.removeListeners(this._eventListeners); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       // In some cases, removing listeners from this._linkedBrowser fails
 | 
					
						
							|  |  |  |       // because it is already half-destroyed.
 | 
					
						
							|  |  |  |       if (e) | 
					
						
							|  |  |  |         dump(e.message + '\n' + e.stack + '\n'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  |     this._registry.emit(TargetRegistry.Events.TargetDestroyed, this); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  | PageTarget.Events = { | 
					
						
							|  |  |  |   ScreencastStarted: Symbol('PageTarget.ScreencastStarted'), | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   ScreencastFrame: Symbol('PageTarget.ScreencastFrame'), | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |   Crashed: Symbol('PageTarget.Crashed'), | 
					
						
							|  |  |  |   DialogOpened: Symbol('PageTarget.DialogOpened'), | 
					
						
							|  |  |  |   DialogClosed: Symbol('PageTarget.DialogClosed'), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  | function fromProtocolColorScheme(colorScheme) { | 
					
						
							|  |  |  |   if (colorScheme === 'light' || colorScheme === 'dark') | 
					
						
							|  |  |  |     return colorScheme; | 
					
						
							|  |  |  |   if (colorScheme === null || colorScheme === 'no-preference') | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   throw new Error('Unknown color scheme: ' + colorScheme); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  | function fromProtocolReducedMotion(reducedMotion) { | 
					
						
							| 
									
										
										
										
											2021-05-20 21:07:39 +02:00
										 |  |  |   if (reducedMotion === 'reduce' || reducedMotion === 'no-preference') | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  |     return reducedMotion; | 
					
						
							| 
									
										
										
										
											2021-05-20 21:07:39 +02:00
										 |  |  |   if (reducedMotion === null) | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  |     return undefined; | 
					
						
							|  |  |  |   throw new Error('Unknown reduced motion: ' + reducedMotion); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 16:00:15 -07:00
										 |  |  | function fromProtocolForcedColors(forcedColors) { | 
					
						
							|  |  |  |   if (forcedColors === 'active' || forcedColors === 'none') | 
					
						
							|  |  |  |     return forcedColors; | 
					
						
							|  |  |  |   if (forcedColors === null) | 
					
						
							|  |  |  |     return undefined; | 
					
						
							|  |  |  |   throw new Error('Unknown forced colors: ' + forcedColors); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | class BrowserContext { | 
					
						
							|  |  |  |   constructor(registry, browserContextId, removeOnDetach) { | 
					
						
							|  |  |  |     this._registry = registry; | 
					
						
							|  |  |  |     this.browserContextId = browserContextId; | 
					
						
							|  |  |  |     // Default context has userContextId === 0, but we pass undefined to many APIs just in case.
 | 
					
						
							|  |  |  |     this.userContextId = 0; | 
					
						
							|  |  |  |     if (browserContextId !== undefined) { | 
					
						
							|  |  |  |       const identity = ContextualIdentityService.create(IDENTITY_NAME + browserContextId); | 
					
						
							|  |  |  |       this.userContextId = identity.userContextId; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._principals = []; | 
					
						
							|  |  |  |     // Maps origins to the permission lists.
 | 
					
						
							|  |  |  |     this._permissions = new Map(); | 
					
						
							|  |  |  |     this._registry._browserContextIdToBrowserContext.set(this.browserContextId, this); | 
					
						
							|  |  |  |     this._registry._userContextIdToBrowserContext.set(this.userContextId, this); | 
					
						
							| 
									
										
										
										
											2020-08-07 15:38:06 -07:00
										 |  |  |     this._proxy = null; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this.removeOnDetach = removeOnDetach; | 
					
						
							|  |  |  |     this.extraHTTPHeaders = undefined; | 
					
						
							|  |  |  |     this.httpCredentials = undefined; | 
					
						
							|  |  |  |     this.requestInterceptionEnabled = undefined; | 
					
						
							|  |  |  |     this.ignoreHTTPSErrors = undefined; | 
					
						
							|  |  |  |     this.downloadOptions = undefined; | 
					
						
							|  |  |  |     this.defaultViewportSize = undefined; | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |     this.deviceScaleFactor = undefined; | 
					
						
							| 
									
										
										
										
											2020-09-30 08:02:22 -07:00
										 |  |  |     this.defaultUserAgent = null; | 
					
						
							| 
									
										
										
										
											2021-08-25 11:45:45 -04:00
										 |  |  |     this.defaultPlatform = null; | 
					
						
							| 
									
										
										
										
											2021-08-11 03:37:57 +03:00
										 |  |  |     this.javaScriptDisabled = false; | 
					
						
							| 
									
										
										
										
											2020-11-18 08:19:09 -08:00
										 |  |  |     this.touchOverride = false; | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |     this.colorScheme = 'none'; | 
					
						
							| 
									
										
										
										
											2021-06-08 16:00:15 -07:00
										 |  |  |     this.forcedColors = 'no-override'; | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  |     this.reducedMotion = 'none'; | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |     this.videoRecordingOptions = undefined; | 
					
						
							| 
									
										
										
										
											2022-02-14 20:32:12 -08:00
										 |  |  |     this.initScripts = []; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     this.bindings = []; | 
					
						
							|  |  |  |     this.settings = {}; | 
					
						
							|  |  |  |     this.pages = new Set(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |   setColorScheme(colorScheme) { | 
					
						
							|  |  |  |     this.colorScheme = fromProtocolColorScheme(colorScheme); | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updateColorSchemeOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 21:23:12 +02:00
										 |  |  |   setReducedMotion(reducedMotion) { | 
					
						
							|  |  |  |     this.reducedMotion = fromProtocolReducedMotion(reducedMotion); | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updateReducedMotionOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 16:00:15 -07:00
										 |  |  |   setForcedColors(forcedColors) { | 
					
						
							|  |  |  |     this.forcedColors = fromProtocolForcedColors(forcedColors); | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updateForcedColorsOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   async destroy() { | 
					
						
							|  |  |  |     if (this.userContextId !== 0) { | 
					
						
							|  |  |  |       ContextualIdentityService.remove(this.userContextId); | 
					
						
							| 
									
										
										
										
											2020-11-02 17:29:54 -08:00
										 |  |  |       for (const page of this.pages) | 
					
						
							|  |  |  |         page.close(); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       if (this.pages.size) { | 
					
						
							|  |  |  |         await new Promise(f => { | 
					
						
							|  |  |  |           const listener = helper.on(this._registry, TargetRegistry.Events.TargetDestroyed, () => { | 
					
						
							|  |  |  |             if (!this.pages.size) { | 
					
						
							|  |  |  |               helper.removeListeners([listener]); | 
					
						
							|  |  |  |               f(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._registry._browserContextIdToBrowserContext.delete(this.browserContextId); | 
					
						
							|  |  |  |     this._registry._userContextIdToBrowserContext.delete(this.userContextId); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 15:38:06 -07:00
										 |  |  |   setProxy(proxy) { | 
					
						
							| 
									
										
										
										
											2020-12-21 15:54:15 -08:00
										 |  |  |     // Clear AuthCache.
 | 
					
						
							|  |  |  |     Services.obs.notifyObservers(null, "net:clear-active-logins"); | 
					
						
							| 
									
										
										
										
											2020-08-07 15:38:06 -07:00
										 |  |  |     this._proxy = proxy; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   setIgnoreHTTPSErrors(ignoreHTTPSErrors) { | 
					
						
							|  |  |  |     if (this.ignoreHTTPSErrors === ignoreHTTPSErrors) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     this.ignoreHTTPSErrors = ignoreHTTPSErrors; | 
					
						
							|  |  |  |     const certOverrideService = Cc[ | 
					
						
							|  |  |  |       "@mozilla.org/security/certoverride;1" | 
					
						
							|  |  |  |     ].getService(Ci.nsICertOverrideService); | 
					
						
							|  |  |  |     if (ignoreHTTPSErrors) { | 
					
						
							|  |  |  |       Preferences.set("network.stricttransportsecurity.preloadlist", false); | 
					
						
							|  |  |  |       Preferences.set("security.cert_pinning.enforcement_level", 0); | 
					
						
							|  |  |  |       certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(true, this.userContextId); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(false, this.userContextId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 03:37:57 +03:00
										 |  |  |   setDefaultUserAgent(userAgent) { | 
					
						
							| 
									
										
										
										
											2020-09-30 08:02:22 -07:00
										 |  |  |     this.defaultUserAgent = userAgent; | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updateUserAgent(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 11:45:45 -04:00
										 |  |  |   setDefaultPlatform(platform) { | 
					
						
							|  |  |  |     this.defaultPlatform = platform; | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updatePlatform(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 03:37:57 +03:00
										 |  |  |   setJavaScriptDisabled(javaScriptDisabled) { | 
					
						
							|  |  |  |     this.javaScriptDisabled = javaScriptDisabled; | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updateJavaScriptDisabled(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 08:19:09 -08:00
										 |  |  |   setTouchOverride(touchOverride) { | 
					
						
							|  |  |  |     this.touchOverride = touchOverride; | 
					
						
							|  |  |  |     for (const page of this.pages) | 
					
						
							|  |  |  |       page.updateTouchOverride(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   async setDefaultViewport(viewport) { | 
					
						
							|  |  |  |     this.defaultViewportSize = viewport ? viewport.viewportSize : undefined; | 
					
						
							| 
									
										
										
										
											2021-03-02 18:52:19 -08:00
										 |  |  |     this.deviceScaleFactor = viewport ? viewport.deviceScaleFactor : undefined; | 
					
						
							|  |  |  |     await Promise.all(Array.from(this.pages).map(page => page.updateViewportSize())); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-14 20:32:12 -08:00
										 |  |  |   async setInitScripts(scripts) { | 
					
						
							|  |  |  |     this.initScripts = scripts; | 
					
						
							|  |  |  |     await Promise.all(Array.from(this.pages).map(page => page.pushInitScripts())); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 16:27:39 +00:00
										 |  |  |   async addBinding(worldName, name, script) { | 
					
						
							|  |  |  |     this.bindings.push({ worldName, name, script }); | 
					
						
							|  |  |  |     await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script))); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async applySetting(name, value) { | 
					
						
							|  |  |  |     this.settings[name] = value; | 
					
						
							|  |  |  |     await Promise.all(Array.from(this.pages).map(page => page.applyContextSetting(name, value))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async grantPermissions(origin, permissions) { | 
					
						
							|  |  |  |     this._permissions.set(origin, permissions); | 
					
						
							|  |  |  |     const promises = []; | 
					
						
							|  |  |  |     for (const page of this.pages) { | 
					
						
							|  |  |  |       if (origin === '*' || page._url.startsWith(origin)) { | 
					
						
							|  |  |  |         this.grantPermissionsToOrigin(page._url); | 
					
						
							|  |  |  |         promises.push(page.ensurePermissions()); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await Promise.all(promises); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   resetPermissions() { | 
					
						
							|  |  |  |     for (const principal of this._principals) { | 
					
						
							|  |  |  |       for (const permission of ALL_PERMISSIONS) | 
					
						
							|  |  |  |         Services.perms.removeFromPrincipal(principal, permission); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this._principals = []; | 
					
						
							|  |  |  |     this._permissions.clear(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   grantPermissionsToOrigin(url) { | 
					
						
							|  |  |  |     let origin = Array.from(this._permissions.keys()).find(key => url.startsWith(key)); | 
					
						
							|  |  |  |     if (!origin) | 
					
						
							|  |  |  |       origin = '*'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const permissions = this._permissions.get(origin); | 
					
						
							|  |  |  |     if (!permissions) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const attrs = { userContextId: this.userContextId || undefined }; | 
					
						
							|  |  |  |     const principal = Services.scriptSecurityManager.createContentPrincipal(NetUtil.newURI(url), attrs); | 
					
						
							|  |  |  |     this._principals.push(principal); | 
					
						
							|  |  |  |     for (const permission of ALL_PERMISSIONS) { | 
					
						
							|  |  |  |       const action = permissions.includes(permission) ? Ci.nsIPermissionManager.ALLOW_ACTION : Ci.nsIPermissionManager.DENY_ACTION; | 
					
						
							|  |  |  |       Services.perms.addFromPrincipal(principal, permission, action, Ci.nsIPermissionManager.EXPIRE_NEVER, 0 /* expireTime */); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setCookies(cookies) { | 
					
						
							|  |  |  |     const protocolToSameSite = { | 
					
						
							|  |  |  |       [undefined]: Ci.nsICookie.SAMESITE_NONE, | 
					
						
							|  |  |  |       'Lax': Ci.nsICookie.SAMESITE_LAX, | 
					
						
							|  |  |  |       'Strict': Ci.nsICookie.SAMESITE_STRICT, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     for (const cookie of cookies) { | 
					
						
							|  |  |  |       const uri = cookie.url ? NetUtil.newURI(cookie.url) : null; | 
					
						
							|  |  |  |       let domain = cookie.domain; | 
					
						
							|  |  |  |       if (!domain) { | 
					
						
							|  |  |  |         if (!uri) | 
					
						
							|  |  |  |           throw new Error('At least one of the url and domain needs to be specified'); | 
					
						
							|  |  |  |         domain = uri.host; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       let path = cookie.path; | 
					
						
							|  |  |  |       if (!path) | 
					
						
							|  |  |  |         path = uri ? dirPath(uri.filePath) : '/'; | 
					
						
							|  |  |  |       let secure = false; | 
					
						
							|  |  |  |       if (cookie.secure !== undefined) | 
					
						
							|  |  |  |         secure = cookie.secure; | 
					
						
							|  |  |  |       else if (uri && uri.scheme === 'https') | 
					
						
							|  |  |  |         secure = true; | 
					
						
							|  |  |  |       Services.cookies.add( | 
					
						
							|  |  |  |         domain, | 
					
						
							|  |  |  |         path, | 
					
						
							|  |  |  |         cookie.name, | 
					
						
							|  |  |  |         cookie.value, | 
					
						
							|  |  |  |         secure, | 
					
						
							|  |  |  |         cookie.httpOnly || false, | 
					
						
							|  |  |  |         cookie.expires === undefined || cookie.expires === -1 /* isSession */, | 
					
						
							|  |  |  |         cookie.expires === undefined ? Date.now() + HUNDRED_YEARS : cookie.expires, | 
					
						
							|  |  |  |         { userContextId: this.userContextId || undefined } /* originAttributes */, | 
					
						
							|  |  |  |         protocolToSameSite[cookie.sameSite], | 
					
						
							| 
									
										
										
										
											2020-08-06 10:32:50 -07:00
										 |  |  |         Ci.nsICookie.SCHEME_UNSET | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   clearCookies() { | 
					
						
							|  |  |  |     Services.cookies.removeCookiesWithOriginAttributes(JSON.stringify({ userContextId: this.userContextId || undefined })); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getCookies() { | 
					
						
							|  |  |  |     const result = []; | 
					
						
							|  |  |  |     const sameSiteToProtocol = { | 
					
						
							|  |  |  |       [Ci.nsICookie.SAMESITE_NONE]: 'None', | 
					
						
							|  |  |  |       [Ci.nsICookie.SAMESITE_LAX]: 'Lax', | 
					
						
							|  |  |  |       [Ci.nsICookie.SAMESITE_STRICT]: 'Strict', | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     for (let cookie of Services.cookies.cookies) { | 
					
						
							|  |  |  |       if (cookie.originAttributes.userContextId !== this.userContextId) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       if (cookie.host === 'addons.mozilla.org') | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       result.push({ | 
					
						
							|  |  |  |         name: cookie.name, | 
					
						
							|  |  |  |         value: cookie.value, | 
					
						
							|  |  |  |         domain: cookie.host, | 
					
						
							|  |  |  |         path: cookie.path, | 
					
						
							|  |  |  |         expires: cookie.isSession ? -1 : cookie.expiry, | 
					
						
							|  |  |  |         size: cookie.name.length + cookie.value.length, | 
					
						
							|  |  |  |         httpOnly: cookie.isHttpOnly, | 
					
						
							|  |  |  |         secure: cookie.isSecure, | 
					
						
							|  |  |  |         session: cookie.isSession, | 
					
						
							|  |  |  |         sameSite: sameSiteToProtocol[cookie.sameSite], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-08-19 12:43:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 19:11:42 -07:00
										 |  |  |   async setVideoRecordingOptions(options) { | 
					
						
							|  |  |  |     this.videoRecordingOptions = options; | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |     const promises = []; | 
					
						
							| 
									
										
										
										
											2021-08-12 17:17:54 -07:00
										 |  |  |     for (const page of this.pages) { | 
					
						
							|  |  |  |       if (options) | 
					
						
							|  |  |  |         promises.push(page._startVideoRecording(options)); | 
					
						
							|  |  |  |       else if (page._videoRecordingInfo) | 
					
						
							|  |  |  |         promises.push(page._stopVideoRecording()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-02 17:16:49 -07:00
										 |  |  |     await Promise.all(promises); | 
					
						
							| 
									
										
										
										
											2020-08-19 12:43:53 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  | class Dialog { | 
					
						
							|  |  |  |   static createIfSupported(prompt) { | 
					
						
							|  |  |  |     const type = prompt.args.promptType; | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |       case 'alert': | 
					
						
							| 
									
										
										
										
											2020-11-30 20:05:15 -08:00
										 |  |  |       case 'alertCheck': | 
					
						
							|  |  |  |         return new Dialog(prompt, 'alert'); | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |       case 'prompt': | 
					
						
							| 
									
										
										
										
											2020-11-30 20:05:15 -08:00
										 |  |  |         return new Dialog(prompt, 'prompt'); | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |       case 'confirm': | 
					
						
							| 
									
										
										
										
											2020-11-30 20:05:15 -08:00
										 |  |  |       case 'confirmCheck': | 
					
						
							|  |  |  |         return new Dialog(prompt, 'confirm'); | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  |       case 'confirmEx': | 
					
						
							|  |  |  |         return new Dialog(prompt, 'beforeunload'); | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(prompt, type) { | 
					
						
							|  |  |  |     this._id = helper.generateId(); | 
					
						
							|  |  |  |     this._type = type; | 
					
						
							|  |  |  |     this._prompt = prompt; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   id() { | 
					
						
							|  |  |  |     return this._id; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   message() { | 
					
						
							|  |  |  |     return this._prompt.ui.infoBody.textContent; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   type() { | 
					
						
							|  |  |  |     return this._type; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   prompt() { | 
					
						
							|  |  |  |     return this._prompt; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dismiss() { | 
					
						
							|  |  |  |     if (this._prompt.ui.button1) | 
					
						
							|  |  |  |       this._prompt.ui.button1.click(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       this._prompt.ui.button0.click(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   defaultValue() { | 
					
						
							|  |  |  |     return this._prompt.ui.loginTextbox.value; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   accept(promptValue) { | 
					
						
							|  |  |  |     if (typeof promptValue === 'string' && this._type === 'prompt') | 
					
						
							|  |  |  |       this._prompt.ui.loginTextbox.value = promptValue; | 
					
						
							|  |  |  |     this._prompt.ui.button0.click(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | function dirPath(path) { | 
					
						
							|  |  |  |   return path.substring(0, path.lastIndexOf('/') + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 22:48:10 -07:00
										 |  |  | async function waitForWindowReady(window) { | 
					
						
							|  |  |  |   if (window.delayedStartupPromise) { | 
					
						
							|  |  |  |     await window.delayedStartupPromise; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     await new Promise((resolve => { | 
					
						
							|  |  |  |       Services.obs.addObserver(function observer(aSubject, aTopic) { | 
					
						
							|  |  |  |         if (window == aSubject) { | 
					
						
							|  |  |  |           Services.obs.removeObserver(observer, aTopic); | 
					
						
							|  |  |  |           resolve(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, "browser-delayed-startup-finished"); | 
					
						
							|  |  |  |     })); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |   if (window.document.readyState !== 'complete') | 
					
						
							|  |  |  |     await helper.awaitEvent(window, 'load'); | 
					
						
							| 
									
										
										
										
											2020-06-09 22:48:10 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 04:13:42 -07:00
										 |  |  | async function setViewportSizeForBrowser(viewportSize, browser, window) { | 
					
						
							|  |  |  |   await waitForWindowReady(window); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   if (viewportSize) { | 
					
						
							|  |  |  |     const {width, height} = viewportSize; | 
					
						
							| 
									
										
										
										
											2020-07-07 14:04:07 -07:00
										 |  |  |     const rect = browser.getBoundingClientRect(); | 
					
						
							|  |  |  |     window.resizeBy(width - rect.width, height - rect.height); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     browser.style.setProperty('min-width', width + 'px'); | 
					
						
							|  |  |  |     browser.style.setProperty('min-height', height + 'px'); | 
					
						
							|  |  |  |     browser.style.setProperty('max-width', width + 'px'); | 
					
						
							|  |  |  |     browser.style.setProperty('max-height', height + 'px'); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     browser.style.removeProperty('min-width'); | 
					
						
							|  |  |  |     browser.style.removeProperty('min-height'); | 
					
						
							|  |  |  |     browser.style.removeProperty('max-width'); | 
					
						
							|  |  |  |     browser.style.removeProperty('max-height'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const rect = browser.getBoundingClientRect(); | 
					
						
							|  |  |  |   return { width: rect.width, height: rect.height }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TargetRegistry.Events = { | 
					
						
							|  |  |  |   TargetCreated: Symbol('TargetRegistry.Events.TargetCreated'), | 
					
						
							|  |  |  |   TargetDestroyed: Symbol('TargetRegistry.Events.TargetDestroyed'), | 
					
						
							|  |  |  |   DownloadCreated: Symbol('TargetRegistry.Events.DownloadCreated'), | 
					
						
							|  |  |  |   DownloadFinished: Symbol('TargetRegistry.Events.DownloadFinished'), | 
					
						
							| 
									
										
										
										
											2021-05-07 18:05:26 -07:00
										 |  |  |   ScreencastStopped: Symbol('TargetRegistry.ScreencastStopped'), | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  | var EXPORTED_SYMBOLS = ['TargetRegistry', 'PageTarget']; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | this.TargetRegistry = TargetRegistry; | 
					
						
							| 
									
										
										
										
											2020-10-06 01:53:25 -07:00
										 |  |  | this.PageTarget = PageTarget; |