| 
									
										
										
										
											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 uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); | 
					
						
							|  |  |  | const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Helper { | 
					
						
							| 
									
										
										
										
											2023-01-23 11:29:48 -08:00
										 |  |  |   decorateAsEventEmitter(objectToDecorate) { | 
					
						
							|  |  |  |     const { EventEmitter } = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); | 
					
						
							|  |  |  |     const emitter = new EventEmitter(); | 
					
						
							|  |  |  |     objectToDecorate.on = emitter.on.bind(emitter); | 
					
						
							|  |  |  |     objectToDecorate.addEventListener = emitter.on.bind(emitter); | 
					
						
							|  |  |  |     objectToDecorate.off = emitter.off.bind(emitter); | 
					
						
							|  |  |  |     objectToDecorate.removeEventListener = emitter.off.bind(emitter); | 
					
						
							|  |  |  |     objectToDecorate.once = emitter.once.bind(emitter); | 
					
						
							|  |  |  |     objectToDecorate.emit = emitter.emit.bind(emitter); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-09-29 11:22:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |   collectAllBrowsingContexts(rootBrowsingContext, allBrowsingContexts = []) { | 
					
						
							|  |  |  |     allBrowsingContexts.push(rootBrowsingContext); | 
					
						
							|  |  |  |     for (const child of rootBrowsingContext.children) | 
					
						
							|  |  |  |       this.collectAllBrowsingContexts(child, allBrowsingContexts); | 
					
						
							|  |  |  |     return allBrowsingContexts; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   toProtocolNavigationId(loadIdentifier) { | 
					
						
							|  |  |  |     return `nav-${loadIdentifier}`; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   addObserver(handler, topic) { | 
					
						
							|  |  |  |     Services.obs.addObserver(handler, topic); | 
					
						
							|  |  |  |     return () => Services.obs.removeObserver(handler, topic); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addMessageListener(receiver, eventName, handler) { | 
					
						
							|  |  |  |     receiver.addMessageListener(eventName, handler); | 
					
						
							|  |  |  |     return () => receiver.removeMessageListener(eventName, handler); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |   addEventListener(receiver, eventName, handler, options) { | 
					
						
							|  |  |  |     receiver.addEventListener(eventName, handler, options); | 
					
						
							| 
									
										
										
										
											2023-01-23 11:29:48 -08:00
										 |  |  |     return () => { | 
					
						
							|  |  |  |       try { | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |         receiver.removeEventListener(eventName, handler, options); | 
					
						
							| 
									
										
										
										
											2023-01-23 11:29:48 -08:00
										 |  |  |       } catch (e) { | 
					
						
							|  |  |  |         // This could fail when window has navigated cross-process
 | 
					
						
							|  |  |  |         // and we remove the listener from WindowProxy.
 | 
					
						
							| 
									
										
										
										
											2023-07-06 12:22:45 -07:00
										 |  |  |         // Nothing we can do here - so ignore the error.
 | 
					
						
							| 
									
										
										
										
											2023-01-23 11:29:48 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 00:36:46 -07:00
										 |  |  |   awaitEvent(receiver, eventName) { | 
					
						
							|  |  |  |     return new Promise(resolve => { | 
					
						
							|  |  |  |       receiver.addEventListener(eventName, function listener() { | 
					
						
							|  |  |  |         receiver.removeEventListener(eventName, listener); | 
					
						
							|  |  |  |         resolve(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |   on(receiver, eventName, handler, options) { | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     // The toolkit/modules/EventEmitter.jsm dispatches event name as a first argument.
 | 
					
						
							|  |  |  |     // Fire event listeners without it for convenience.
 | 
					
						
							|  |  |  |     const handlerWrapper = (_, ...args) => handler(...args); | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |     receiver.on(eventName, handlerWrapper, options); | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  |     return () => receiver.off(eventName, handlerWrapper); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addProgressListener(progress, listener, flags) { | 
					
						
							|  |  |  |     progress.addProgressListener(listener, flags); | 
					
						
							|  |  |  |     return () => progress.removeProgressListener(listener); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   removeListeners(listeners) { | 
					
						
							|  |  |  |     for (const tearDown of listeners) | 
					
						
							|  |  |  |       tearDown.call(null); | 
					
						
							|  |  |  |     listeners.splice(0, listeners.length); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateId() { | 
					
						
							|  |  |  |     const string = uuidGen.generateUUID().toString(); | 
					
						
							|  |  |  |     return string.substring(1, string.length - 1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getLoadContext(channel) { | 
					
						
							|  |  |  |     let loadContext = null; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       if (channel.notificationCallbacks) | 
					
						
							|  |  |  |         loadContext = channel.notificationCallbacks.getInterface(Ci.nsILoadContext); | 
					
						
							|  |  |  |     } catch (e) {} | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       if (!loadContext && channel.loadGroup) | 
					
						
							|  |  |  |         loadContext = channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext); | 
					
						
							|  |  |  |     } catch (e) { } | 
					
						
							|  |  |  |     return loadContext; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getNetworkErrorStatusText(status) { | 
					
						
							|  |  |  |     if (!status) | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     for (const key of Object.keys(Cr)) { | 
					
						
							|  |  |  |       if (Cr[key] === status) | 
					
						
							|  |  |  |         return key; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Security module. The following is taken from
 | 
					
						
							|  |  |  |     // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL
 | 
					
						
							|  |  |  |     if ((status & 0xff0000) === 0x5a0000) { | 
					
						
							|  |  |  |       // NSS_SEC errors (happen below the base value because of negative vals)
 | 
					
						
							|  |  |  |       if ((status & 0xffff) < Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)) { | 
					
						
							|  |  |  |         // The bases are actually negative, so in our positive numeric space, we
 | 
					
						
							|  |  |  |         // need to subtract the base off our value.
 | 
					
						
							|  |  |  |         const nssErr = Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff); | 
					
						
							|  |  |  |         switch (nssErr) { | 
					
						
							|  |  |  |           case 11: | 
					
						
							|  |  |  |             return 'SEC_ERROR_EXPIRED_CERTIFICATE'; | 
					
						
							|  |  |  |           case 12: | 
					
						
							|  |  |  |             return 'SEC_ERROR_REVOKED_CERTIFICATE'; | 
					
						
							|  |  |  |           case 13: | 
					
						
							|  |  |  |             return 'SEC_ERROR_UNKNOWN_ISSUER'; | 
					
						
							|  |  |  |           case 20: | 
					
						
							|  |  |  |             return 'SEC_ERROR_UNTRUSTED_ISSUER'; | 
					
						
							|  |  |  |           case 21: | 
					
						
							|  |  |  |             return 'SEC_ERROR_UNTRUSTED_CERT'; | 
					
						
							|  |  |  |           case 36: | 
					
						
							|  |  |  |             return 'SEC_ERROR_CA_CERT_INVALID'; | 
					
						
							|  |  |  |           case 90: | 
					
						
							|  |  |  |             return 'SEC_ERROR_INADEQUATE_KEY_USAGE'; | 
					
						
							|  |  |  |           case 176: | 
					
						
							|  |  |  |             return 'SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED'; | 
					
						
							|  |  |  |           default: | 
					
						
							|  |  |  |             return 'SEC_ERROR_UNKNOWN'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const sslErr = Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff); | 
					
						
							|  |  |  |       switch (sslErr) { | 
					
						
							|  |  |  |         case 3: | 
					
						
							|  |  |  |           return 'SSL_ERROR_NO_CERTIFICATE'; | 
					
						
							|  |  |  |         case 4: | 
					
						
							|  |  |  |           return 'SSL_ERROR_BAD_CERTIFICATE'; | 
					
						
							|  |  |  |         case 8: | 
					
						
							|  |  |  |           return 'SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE'; | 
					
						
							|  |  |  |         case 9: | 
					
						
							|  |  |  |           return 'SSL_ERROR_UNSUPPORTED_VERSION'; | 
					
						
							|  |  |  |         case 12: | 
					
						
							|  |  |  |           return 'SSL_ERROR_BAD_CERT_DOMAIN'; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |           return 'SSL_ERROR_UNKNOWN'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return '<unknown error>'; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-09-29 11:22:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   browsingContextToFrameId(browsingContext) { | 
					
						
							|  |  |  |     if (!browsingContext) | 
					
						
							|  |  |  |       return undefined; | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |     if (!browsingContext.parent) | 
					
						
							|  |  |  |       return 'mainframe-' + browsingContext.browserId; | 
					
						
							|  |  |  |     return 'subframe-' + browsingContext.id; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const helper = new Helper(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EventWatcher { | 
					
						
							| 
									
										
										
										
											2023-06-06 15:08:23 -07:00
										 |  |  |   constructor(receiver, eventNames, pendingEventWatchers = new Set()) { | 
					
						
							|  |  |  |     this._pendingEventWatchers = pendingEventWatchers; | 
					
						
							|  |  |  |     this._pendingEventWatchers.add(this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |     this._events = []; | 
					
						
							|  |  |  |     this._pendingPromises = []; | 
					
						
							|  |  |  |     this._eventListeners = eventNames.map(eventName => | 
					
						
							|  |  |  |       helper.on(receiver, eventName, this._onEvent.bind(this, eventName)), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _onEvent(eventName, eventObject) { | 
					
						
							|  |  |  |     this._events.push({eventName, eventObject}); | 
					
						
							|  |  |  |     for (const promise of this._pendingPromises) | 
					
						
							|  |  |  |       promise.resolve(); | 
					
						
							|  |  |  |     this._pendingPromises = []; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async ensureEvent(aEventName, predicate) { | 
					
						
							|  |  |  |     if (typeof aEventName !== 'string') | 
					
						
							|  |  |  |       throw new Error('ERROR: ensureEvent expects a "string" as its first argument'); | 
					
						
							|  |  |  |     while (true) { | 
					
						
							|  |  |  |       const result = this.getEvent(aEventName, predicate); | 
					
						
							|  |  |  |       if (result) | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |       await new Promise((resolve, reject) => this._pendingPromises.push({resolve, reject})); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async ensureEvents(eventNames, predicate) { | 
					
						
							|  |  |  |     if (!Array.isArray(eventNames)) | 
					
						
							|  |  |  |       throw new Error('ERROR: ensureEvents expects an array of event names as its first argument'); | 
					
						
							|  |  |  |     return await Promise.all(eventNames.map(eventName => this.ensureEvent(eventName, predicate))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async ensureEventsAndDispose(eventNames, predicate) { | 
					
						
							|  |  |  |     if (!Array.isArray(eventNames)) | 
					
						
							|  |  |  |       throw new Error('ERROR: ensureEventsAndDispose expects an array of event names as its first argument'); | 
					
						
							|  |  |  |     const result = await this.ensureEvents(eventNames, predicate); | 
					
						
							|  |  |  |     this.dispose(); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getEvent(aEventName, predicate = (eventObject) => true) { | 
					
						
							|  |  |  |     return this._events.find(({eventName, eventObject}) => eventName === aEventName && predicate(eventObject))?.eventObject; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   hasEvent(aEventName, predicate) { | 
					
						
							|  |  |  |     return !!this.getEvent(aEventName, predicate); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dispose() { | 
					
						
							| 
									
										
										
										
											2023-06-06 15:08:23 -07:00
										 |  |  |     this._pendingEventWatchers.delete(this); | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  |     for (const promise of this._pendingPromises) | 
					
						
							|  |  |  |       promise.reject(new Error('EventWatcher is being disposed')); | 
					
						
							|  |  |  |     this._pendingPromises = []; | 
					
						
							|  |  |  |     helper.removeListeners(this._eventListeners); | 
					
						
							| 
									
										
										
										
											2020-09-29 11:22:00 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  | var EXPORTED_SYMBOLS = [ "Helper", "EventWatcher" ]; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | this.Helper = Helper; | 
					
						
							| 
									
										
										
										
											2023-03-21 01:23:12 +00:00
										 |  |  | this.EventWatcher = EventWatcher; | 
					
						
							| 
									
										
										
										
											2020-06-02 16:51:13 -07:00
										 |  |  | 
 |