diff --git a/.eslintignore b/.eslintignore index d79f80b4c6c4..69bc5b83c71a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -183,7 +183,6 @@ dom/payments/** dom/performance/** dom/permission/** dom/promise/** -dom/push/** dom/quota/** dom/security/test/cors/** dom/security/test/csp/** diff --git a/dom/push/Push.jsm b/dom/push/Push.jsm index 5cea0fa79c69..10f51e93d7b2 100644 --- a/dom/push/Push.jsm +++ b/dom/push/Push.jsm @@ -35,13 +35,13 @@ Push.prototype = { contractID: "@mozilla.org/push/PushManager;1", - classID : PUSH_CID, + classID: PUSH_CID, - QueryInterface : ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, - Ci.nsISupportsWeakReference, - Ci.nsIObserver]), + QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, + Ci.nsISupportsWeakReference, + Ci.nsIObserver]), - init: function(win) { + init(win) { console.debug("init()"); this._window = win; @@ -53,11 +53,11 @@ Push.prototype = { this._topLevelPrincipal = win.top.document.nodePrincipal; }, - __init: function(scope) { + __init(scope) { this._scope = scope; }, - askPermission: function () { + askPermission() { console.debug("askPermission()"); let isHandlingUserInput = this._window.windowUtils.isHandlingUserInput; @@ -78,7 +78,7 @@ Push.prototype = { }); }, - subscribe: function(options) { + subscribe(options) { console.debug("subscribe()", this._scope); return this.askPermission().then(() => @@ -102,7 +102,7 @@ Push.prototype = { ); }, - _normalizeAppServerKey: function(appServerKey) { + _normalizeAppServerKey(appServerKey) { let key; if (typeof appServerKey == "string") { try { @@ -124,7 +124,7 @@ Push.prototype = { return new this._window.Uint8Array(key); }, - getSubscription: function() { + getSubscription() { console.debug("getSubscription()", this._scope); return this.createPromise((resolve, reject) => { @@ -133,7 +133,7 @@ Push.prototype = { }); }, - permissionState: function() { + permissionState() { console.debug("permissionState()", this._scope); return this.createPromise((resolve, reject) => { @@ -141,7 +141,7 @@ Push.prototype = { try { permission = this._testPermission(); - } catch(e) { + } catch (e) { reject(); return; } @@ -156,7 +156,7 @@ Push.prototype = { }); }, - _testPermission: function() { + _testPermission() { let permission = Services.perms.testExactPermissionFromPrincipal( this._principal, "desktop-notification"); if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) { @@ -170,7 +170,7 @@ Push.prototype = { return permission; }, - _requestPermission: function(isHandlingUserInput, allowCallback, cancelCallback) { + _requestPermission(isHandlingUserInput, allowCallback, cancelCallback) { // Create an array with a single nsIContentPermissionType element. let type = { type: "desktop-notification", @@ -208,7 +208,7 @@ function PushSubscriptionCallback(pushManager, resolve, reject) { PushSubscriptionCallback.prototype = { QueryInterface: ChromeUtils.generateQI([Ci.nsIPushSubscriptionCallback]), - onPushSubscription: function(ok, subscription) { + onPushSubscription(ok, subscription) { let {pushManager} = this; if (!Components.isSuccessCode(ok)) { this._rejectWithError(ok); @@ -225,8 +225,8 @@ PushSubscriptionCallback.prototype = { let options = { endpoint: subscription.endpoint, scope: pushManager._scope, - p256dhKey: p256dhKey, - authSecret: authSecret, + p256dhKey, + authSecret, }; let appServerKey = this._getKey(subscription, "appServer"); if (appServerKey) { @@ -237,7 +237,7 @@ PushSubscriptionCallback.prototype = { this.resolve(sub); }, - _getKey: function(subscription, name) { + _getKey(subscription, name) { let outKeyLen = {}; let rawKey = Cu.cloneInto(subscription.getKey(name, outKeyLen), this.pushManager._window); @@ -251,7 +251,7 @@ PushSubscriptionCallback.prototype = { return key; }, - _rejectWithError: function(result) { + _rejectWithError(result) { let error; switch (result) { case Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR: @@ -278,4 +278,4 @@ PushSubscriptionCallback.prototype = { }, }; -var EXPORTED_SYMBOLS = ["Push"]; +const EXPORTED_SYMBOLS = ["Push"]; diff --git a/dom/push/PushBroadcastService.jsm b/dom/push/PushBroadcastService.jsm index 6733cfec3078..d60d5a24868a 100644 --- a/dom/push/PushBroadcastService.jsm +++ b/dom/push/PushBroadcastService.jsm @@ -9,7 +9,7 @@ const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.defineModuleGetter(this, "JSONFile", "resource://gre/modules/JSONFile.jsm"); -var EXPORTED_SYMBOLS = ["pushBroadcastService"]; +const EXPORTED_SYMBOLS = ["pushBroadcastService"]; // We are supposed to ignore any updates with this version. const DUMMY_VERSION_STRING = "____NOP____"; @@ -26,7 +26,7 @@ ChromeUtils.defineModuleGetter(this, "PushService", "resource://gre/modules/Push class InvalidSourceInfo extends Error { constructor(message) { super(message); - this.name = 'InvalidSourceInfo'; + this.name = "InvalidSourceInfo"; } } @@ -177,7 +177,7 @@ var BroadcastService = class { if (!module[symbolName]) { console.error("receivedBroadcastMessage: couldn't invoke", broadcastId, - "because module", moduleName, "missing attribute", symbolName); + "because module", moduleURI, "missing attribute", symbolName); continue; } @@ -214,7 +214,7 @@ var BroadcastService = class { _saveImmediately() { return this.jsonFile._save(); } -} +}; function initializeBroadcastService() { // Fallback path for xpcshell tests. @@ -224,6 +224,6 @@ function initializeBroadcastService() { path = OS.Path.join(OS.Constants.Path.profileDir, path); } return new BroadcastService(PushService, path); -}; +} var pushBroadcastService = initializeBroadcastService(); diff --git a/dom/push/PushComponents.jsm b/dom/push/PushComponents.jsm index 89d0910c31a3..45580ff58d5b 100644 --- a/dom/push/PushComponents.jsm +++ b/dom/push/PushComponents.jsm @@ -89,7 +89,6 @@ PushServiceBase.prototype = { if (topic === "android-push-service") { // Load PushService immediately. this._handleReady(); - return; } }, @@ -147,7 +146,7 @@ Object.assign(PushServiceParent.prototype, { subscribeWithKey(scope, principal, keyLen, key, callback) { this._handleRequest("Push:Register", principal, { - scope: scope, + scope, appServerKey: key, }).then(result => { this._deliverSubscription(callback, result); @@ -158,7 +157,7 @@ Object.assign(PushServiceParent.prototype, { unsubscribe(scope, principal, callback) { this._handleRequest("Push:Unregister", principal, { - scope: scope, + scope, }).then(result => { callback.onUnsubscribe(Cr.NS_OK, result); }, error => { @@ -168,7 +167,7 @@ Object.assign(PushServiceParent.prototype, { getSubscription(scope, principal, callback) { return this._handleRequest("Push:Registration", principal, { - scope: scope, + scope, }).then(result => { this._deliverSubscription(callback, result); }, error => { @@ -178,7 +177,7 @@ Object.assign(PushServiceParent.prototype, { clearForDomain(domain, callback) { return this._handleRequest("Push:Clear", null, { - domain: domain, + domain, }).then(result => { callback.onClear(Cr.NS_OK); }, error => { @@ -219,10 +218,10 @@ Object.assign(PushServiceParent.prototype, { this.reportDeliveryError(data.messageId, data.reason); return; } - return this._handleRequest(name, principal, data).then(result => { + this._handleRequest(name, principal, data).then(result => { target.sendAsyncMessage(this._getResponseName(name, "OK"), { requestID: data.requestID, - result: result + result, }); }, error => { target.sendAsyncMessage(this._getResponseName(name, "KO"), { @@ -353,35 +352,35 @@ Object.assign(PushServiceContent.prototype, { }, subscribeWithKey(scope, principal, keyLen, key, callback) { - let requestId = this._addRequest(callback); + let requestID = this._addRequest(callback); this._mm.sendAsyncMessage("Push:Register", { - scope: scope, + scope, appServerKey: key, - requestID: requestId, + requestID, }, null, principal); }, unsubscribe(scope, principal, callback) { - let requestId = this._addRequest(callback); + let requestID = this._addRequest(callback); this._mm.sendAsyncMessage("Push:Unregister", { - scope: scope, - requestID: requestId, + scope, + requestID, }, null, principal); }, getSubscription(scope, principal, callback) { - let requestId = this._addRequest(callback); + let requestID = this._addRequest(callback); this._mm.sendAsyncMessage("Push:Registration", { - scope: scope, - requestID: requestId, + scope, + requestID, }, null, principal); }, clearForDomain(domain, callback) { - let requestId = this._addRequest(callback); + let requestID = this._addRequest(callback); this._mm.sendAsyncMessage("Push:Clear", { - domain: domain, - requestID: requestId, + domain, + requestID, }); }, @@ -399,8 +398,8 @@ Object.assign(PushServiceContent.prototype, { reportDeliveryError(messageId, reason) { this._mm.sendAsyncMessage("Push:ReportError", { - messageId: messageId, - reason: reason, + messageId, + reason, }); }, @@ -560,4 +559,4 @@ PushSubscription.prototype = { // the parent or content process. let Service = isParent ? PushServiceParent : PushServiceContent; -var EXPORTED_SYMBOLS = ["Service"]; +const EXPORTED_SYMBOLS = ["Service"]; diff --git a/dom/push/PushCrypto.jsm b/dom/push/PushCrypto.jsm index 7d2259660bb3..b59ef4eee6b6 100644 --- a/dom/push/PushCrypto.jsm +++ b/dom/push/PushCrypto.jsm @@ -1,47 +1,48 @@ -/* jshint moz: true, esnext: true */ /* 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/. */ -'use strict'; +"use strict"; -const {Services} = ChromeUtils.import('resource://gre/modules/Services.jsm'); -const {XPCOMUtils} = ChromeUtils.import('resource://gre/modules/XPCOMUtils.jsm'); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyGetter(this, 'gDOMBundle', () => - Services.strings.createBundle('chrome://global/locale/dom/dom.properties')); +XPCOMUtils.defineLazyGetter(this, "gDOMBundle", () => + Services.strings.createBundle("chrome://global/locale/dom/dom.properties")); -XPCOMUtils.defineLazyGlobalGetters(this, ['crypto']); +XPCOMUtils.defineLazyGlobalGetters(this, ["crypto"]); -var EXPORTED_SYMBOLS = ['PushCrypto', 'concatArray']; +const EXPORTED_SYMBOLS = ["PushCrypto", "concatArray"]; -var UTF8 = new TextEncoder('utf-8'); +const UTF8 = new TextEncoder("utf-8"); -var ECDH_KEY = { name: 'ECDH', namedCurve: 'P-256' }; -var ECDSA_KEY = { name: 'ECDSA', namedCurve: 'P-256' }; +const ECDH_KEY = { name: "ECDH", namedCurve: "P-256" }; +const ECDSA_KEY = { name: "ECDSA", namedCurve: "P-256" }; +const HMAC_SHA256 = { name: "HMAC", hash: "SHA-256" }; +const NONCE_INFO = UTF8.encode("Content-Encoding: nonce"); // A default keyid with a name that won't conflict with a real keyid. -var DEFAULT_KEYID = ''; +const DEFAULT_KEYID = ""; /** Localized error property names. */ // `Encryption` header missing or malformed. -const BAD_ENCRYPTION_HEADER = 'PushMessageBadEncryptionHeader'; +const BAD_ENCRYPTION_HEADER = "PushMessageBadEncryptionHeader"; // `Crypto-Key` or legacy `Encryption-Key` header missing. -const BAD_CRYPTO_KEY_HEADER = 'PushMessageBadCryptoKeyHeader'; -const BAD_ENCRYPTION_KEY_HEADER = 'PushMessageBadEncryptionKeyHeader'; +const BAD_CRYPTO_KEY_HEADER = "PushMessageBadCryptoKeyHeader"; +const BAD_ENCRYPTION_KEY_HEADER = "PushMessageBadEncryptionKeyHeader"; // `Content-Encoding` header missing or contains unsupported encoding. -const BAD_ENCODING_HEADER = 'PushMessageBadEncodingHeader'; +const BAD_ENCODING_HEADER = "PushMessageBadEncodingHeader"; // `dh` parameter of `Crypto-Key` header missing or not base64url-encoded. -const BAD_DH_PARAM = 'PushMessageBadSenderKey'; +const BAD_DH_PARAM = "PushMessageBadSenderKey"; // `salt` parameter of `Encryption` header missing or not base64url-encoded. -const BAD_SALT_PARAM = 'PushMessageBadSalt'; +const BAD_SALT_PARAM = "PushMessageBadSalt"; // `rs` parameter of `Encryption` header not a number or less than pad size. -const BAD_RS_PARAM = 'PushMessageBadRecordSize'; +const BAD_RS_PARAM = "PushMessageBadRecordSize"; // Invalid or insufficient padding for encrypted chunk. -const BAD_PADDING = 'PushMessageBadPaddingError'; +const BAD_PADDING = "PushMessageBadPaddingError"; // Generic crypto error. -const BAD_CRYPTO = 'PushMessageBadCryptoError'; +const BAD_CRYPTO = "PushMessageBadCryptoError"; class CryptoError extends Error { /** @@ -80,9 +81,9 @@ function getEncryptionKeyParams(encryptKeyField) { if (!encryptKeyField) { return null; } - var params = encryptKeyField.split(','); + var params = encryptKeyField.split(","); return params.reduce((m, p) => { - var pmap = p.split(';').reduce(parseHeaderFieldParams, {}); + var pmap = p.split(";").reduce(parseHeaderFieldParams, {}); if (pmap.keyid && pmap.dh) { m[pmap.keyid] = pmap.dh; } @@ -95,34 +96,34 @@ function getEncryptionKeyParams(encryptKeyField) { function getEncryptionParams(encryptField) { if (!encryptField) { - throw new CryptoError('Missing encryption header', + throw new CryptoError("Missing encryption header", BAD_ENCRYPTION_HEADER); } - var p = encryptField.split(',', 1)[0]; + var p = encryptField.split(",", 1)[0]; if (!p) { - throw new CryptoError('Encryption header missing params', + throw new CryptoError("Encryption header missing params", BAD_ENCRYPTION_HEADER); } - return p.split(';').reduce(parseHeaderFieldParams, {}); + return p.split(";").reduce(parseHeaderFieldParams, {}); } // Extracts the sender public key, salt, and record size from the payload for the // aes128gcm scheme. function getCryptoParamsFromPayload(payload) { if (payload.byteLength < 21) { - throw new CryptoError('Truncated header', BAD_CRYPTO); + throw new CryptoError("Truncated header", BAD_CRYPTO); } let rs = (payload[16] << 24) | (payload[17] << 16) | (payload[18] << 8) | payload[19]; let keyIdLen = payload[20]; if (keyIdLen != 65) { - throw new CryptoError('Invalid sender public key', BAD_DH_PARAM); + throw new CryptoError("Invalid sender public key", BAD_DH_PARAM); } if (payload.byteLength <= 21 + keyIdLen) { - throw new CryptoError('Truncated payload', BAD_CRYPTO); + throw new CryptoError("Truncated payload", BAD_CRYPTO); } return { salt: payload.slice(0, 16), - rs: rs, + rs, senderKey: payload.slice(21, 21 + keyIdLen), ciphertext: payload.slice(21 + keyIdLen), }; @@ -143,7 +144,7 @@ function getCryptoParamsFromHeaders(headers) { // https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-01 keymap = getEncryptionKeyParams(headers.crypto_key); if (!keymap) { - throw new CryptoError('Missing Crypto-Key header', + throw new CryptoError("Missing Crypto-Key header", BAD_CRYPTO_KEY_HEADER); } } else if (headers.encoding == AESGCM128_ENCODING) { @@ -151,7 +152,7 @@ function getCryptoParamsFromHeaders(headers) { // https://tools.ietf.org/html/draft-thomson-http-encryption-02 keymap = getEncryptionKeyParams(headers.encryption_key); if (!keymap) { - throw new CryptoError('Missing Encryption-Key header', + throw new CryptoError("Missing Encryption-Key header", BAD_ENCRYPTION_KEY_HEADER); } } @@ -160,21 +161,21 @@ function getCryptoParamsFromHeaders(headers) { var dh = keymap[enc.keyid || DEFAULT_KEYID]; var senderKey = base64URLDecode(dh); if (!senderKey) { - throw new CryptoError('Invalid dh parameter', BAD_DH_PARAM); + throw new CryptoError("Invalid dh parameter", BAD_DH_PARAM); } var salt = base64URLDecode(enc.salt); if (!salt) { - throw new CryptoError('Invalid salt parameter', BAD_SALT_PARAM); + throw new CryptoError("Invalid salt parameter", BAD_SALT_PARAM); } var rs = enc.rs ? parseInt(enc.rs, 10) : 4096; if (isNaN(rs)) { - throw new CryptoError('rs parameter must be a number', BAD_RS_PARAM); + throw new CryptoError("rs parameter must be a number", BAD_RS_PARAM); } return { - salt: salt, - rs: rs, - senderKey: senderKey, + salt, + rs, + senderKey, }; } @@ -186,19 +187,19 @@ function base64URLDecode(string) { try { return ChromeUtils.base64URLDecode(string, { // draft-ietf-httpbis-encryption-encoding-01 prohibits padding. - padding: 'reject', + padding: "reject", }); } catch (ex) {} return null; } var parseHeaderFieldParams = (m, v) => { - var i = v.indexOf('='); + var i = v.indexOf("="); if (i >= 0) { // A quoted string with internal quotes is invalid for all the possible // values of this header field. m[v.substring(0, i).trim()] = v.substring(i + 1).trim() - .replace(/^"(.*)"$/, '$1'); + .replace(/^"(.*)"$/, "$1"); } return m; }; @@ -208,7 +209,7 @@ function chunkArray(array, size) { array = array.buffer || array; var index = 0; var result = []; - while(index + size <= array.byteLength) { + while (index + size <= array.byteLength) { result.push(new Uint8Array(array, start + index, size)); index += size; } @@ -218,7 +219,7 @@ function chunkArray(array, size) { return result; } -var concatArray = function(arrays) { +function concatArray(arrays) { var size = arrays.reduce((total, a) => total + a.byteLength, 0); var index = 0; return arrays.reduce((result, a) => { @@ -226,17 +227,15 @@ var concatArray = function(arrays) { index += a.byteLength; return result; }, new Uint8Array(size)); -}; - -var HMAC_SHA256 = { name: 'HMAC', hash: 'SHA-256' }; +} function hmac(key) { - this.keyPromise = crypto.subtle.importKey('raw', key, HMAC_SHA256, - false, ['sign']); + this.keyPromise = crypto.subtle.importKey("raw", key, HMAC_SHA256, + false, ["sign"]); } hmac.prototype.hash = function(input) { - return this.keyPromise.then(k => crypto.subtle.sign('HMAC', k, input)); + return this.keyPromise.then(k => crypto.subtle.sign("HMAC", k, input)); }; function hkdf(salt, ikm) { @@ -250,7 +249,7 @@ hkdf.prototype.extract = function(info, len) { .then(prkh => prkh.hash(input)) .then(h => { if (h.byteLength < len) { - throw new CryptoError('HKDF length is too long', BAD_CRYPTO); + throw new CryptoError("HKDF length is too long", BAD_CRYPTO); } return h.slice(0, len); }); @@ -259,7 +258,7 @@ hkdf.prototype.extract = function(info, len) { /* generate a 96-bit nonce for use in GCM, 48-bits of which are populated */ function generateNonce(base, index) { if (index >= Math.pow(2, 48)) { - throw new CryptoError('Nonce index is too large', BAD_CRYPTO); + throw new CryptoError("Nonce index is too large", BAD_CRYPTO); } var nonce = base.slice(0, 12); nonce = new Uint8Array(nonce); @@ -273,8 +272,6 @@ function encodeLength(buffer) { return new Uint8Array([0, buffer.byteLength]); } -var NONCE_INFO = UTF8.encode('Content-Encoding: nonce'); - class Decoder { /** * Creates a decoder for decrypting an incoming push message. @@ -312,8 +309,8 @@ class Decoder { try { let ikm = await this.computeSharedSecret(); let [gcmBits, nonce] = await this.deriveKeyAndNonce(ikm); - let key = await crypto.subtle.importKey('raw', gcmBits, 'AES-GCM', false, - ['decrypt']); + let key = await crypto.subtle.importKey("raw", gcmBits, "AES-GCM", false, + ["decrypt"]); let r = await Promise.all(chunkArray(this.ciphertext, this.chunkSize) .map((slice, index, chunks) => this.decodeChunk(slice, index, nonce, @@ -327,7 +324,7 @@ class Decoder { // Web Crypto returns an unhelpful "operation failed for an // operation-specific reason" error if decryption fails. We don't have // context about what went wrong, so we throw a generic error instead. - throw new CryptoError('Bad encryption', BAD_CRYPTO); + throw new CryptoError("Bad encryption", BAD_CRYPTO); } } @@ -339,12 +336,12 @@ class Decoder { */ async computeSharedSecret() { let [appServerKey, subscriptionPrivateKey] = await Promise.all([ - crypto.subtle.importKey('raw', this.senderKey, ECDH_KEY, - false, ['deriveBits']), - crypto.subtle.importKey('jwk', this.privateKey, ECDH_KEY, - false, ['deriveBits']) + crypto.subtle.importKey("raw", this.senderKey, ECDH_KEY, + false, ["deriveBits"]), + crypto.subtle.importKey("jwk", this.privateKey, ECDH_KEY, + false, ["deriveBits"]), ]); - return crypto.subtle.deriveBits({ name: 'ECDH', public: appServerKey }, + return crypto.subtle.deriveBits({ name: "ECDH", public: appServerKey }, subscriptionPrivateKey, 256); } @@ -355,7 +352,7 @@ class Decoder { * @returns {Array} A `[gcmBits, nonce]` tuple. */ async deriveKeyAndNonce(ikm) { - throw new Error('Missing `deriveKeyAndNonce` implementation'); + throw new Error("Missing `deriveKeyAndNonce` implementation"); } /** @@ -371,8 +368,8 @@ class Decoder { */ async decodeChunk(slice, index, nonce, key, last) { let params = { - name: 'AES-GCM', - iv: generateNonce(nonce, index) + name: "AES-GCM", + iv: generateNonce(nonce, index), }; let decoded = await crypto.subtle.decrypt(params, key, slice); return this.unpadChunk(new Uint8Array(decoded), last); @@ -386,12 +383,12 @@ class Decoder { * @returns {Uint8Array} The block with padding removed. */ unpadChunk(chunk, last) { - throw new Error('Missing `unpadChunk` implementation'); + throw new Error("Missing `unpadChunk` implementation"); } /** The record chunking size. */ get chunkSize() { - throw new Error('Missing `chunkSize` implementation'); + throw new Error("Missing `chunkSize` implementation"); } } @@ -401,7 +398,7 @@ class OldSchemeDecoder extends Decoder { // boundary. if (this.ciphertext.byteLength > 0 && this.ciphertext.byteLength % this.chunkSize === 0) { - throw new CryptoError('Encrypted data truncated', BAD_CRYPTO); + throw new CryptoError("Encrypted data truncated", BAD_CRYPTO); } return super.decode(); } @@ -412,19 +409,19 @@ class OldSchemeDecoder extends Decoder { */ unpadChunk(decoded) { if (decoded.length < this.padSize) { - throw new CryptoError('Decoded array is too short!', BAD_PADDING); + throw new CryptoError("Decoded array is too short!", BAD_PADDING); } - var pad = decoded[0] + var pad = decoded[0]; if (this.padSize == 2) { pad = (pad << 8) | decoded[1]; } if (pad > decoded.length - this.padSize) { - throw new CryptoError('Padding is wrong!', BAD_PADDING); + throw new CryptoError("Padding is wrong!", BAD_PADDING); } // All padded bytes must be zero except the first one. for (var i = this.padSize; i < this.padSize + pad; i++) { if (decoded[i] !== 0) { - throw new CryptoError('Padding is wrong!', BAD_PADDING); + throw new CryptoError("Padding is wrong!", BAD_PADDING); } } return decoded.slice(pad + this.padSize); @@ -439,16 +436,16 @@ class OldSchemeDecoder extends Decoder { } get padSize() { - throw new Error('Missing `padSize` implementation'); + throw new Error("Missing `padSize` implementation"); } } /** New encryption scheme (draft-ietf-httpbis-encryption-encoding-06). */ -var AES128GCM_ENCODING = 'aes128gcm'; -var AES128GCM_KEY_INFO = UTF8.encode('Content-Encoding: aes128gcm\0'); -var AES128GCM_AUTH_INFO = UTF8.encode('WebPush: info\0'); -var AES128GCM_NONCE_INFO = UTF8.encode('Content-Encoding: nonce\0'); +const AES128GCM_ENCODING = "aes128gcm"; +const AES128GCM_KEY_INFO = UTF8.encode("Content-Encoding: aes128gcm\0"); +const AES128GCM_AUTH_INFO = UTF8.encode("WebPush: info\0"); +const AES128GCM_NONCE_INFO = UTF8.encode("Content-Encoding: nonce\0"); class aes128gcmDecoder extends Decoder { /** @@ -461,13 +458,13 @@ class aes128gcmDecoder extends Decoder { let authInfo = concatArray([ AES128GCM_AUTH_INFO, this.publicKey, - this.senderKey + this.senderKey, ]); let prk = await authKdf.extract(authInfo, 32); let prkKdf = new hkdf(this.salt, prk); return Promise.all([ prkKdf.extract(AES128GCM_KEY_INFO, 16), - prkKdf.extract(AES128GCM_NONCE_INFO, 12) + prkKdf.extract(AES128GCM_NONCE_INFO, 12), ]); } @@ -479,11 +476,11 @@ class aes128gcmDecoder extends Decoder { } let recordPad = last ? 2 : 1; if (decoded[length] != recordPad) { - throw new CryptoError('Padding is wrong!', BAD_PADDING); + throw new CryptoError("Padding is wrong!", BAD_PADDING); } return decoded.slice(0, length); } - throw new CryptoError('Zero plaintext', BAD_PADDING); + throw new CryptoError("Zero plaintext", BAD_PADDING); } /** aes128gcm accounts for the authentication tag in the record size. */ @@ -494,10 +491,10 @@ class aes128gcmDecoder extends Decoder { /** Older encryption scheme (draft-ietf-httpbis-encryption-encoding-01). */ -var AESGCM_ENCODING = 'aesgcm'; -var AESGCM_KEY_INFO = UTF8.encode('Content-Encoding: aesgcm\0'); -var AESGCM_AUTH_INFO = UTF8.encode('Content-Encoding: auth\0'); // note nul-terminus -var AESGCM_P256DH_INFO = UTF8.encode('P-256\0'); +const AESGCM_ENCODING = "aesgcm"; +const AESGCM_KEY_INFO = UTF8.encode("Content-Encoding: aesgcm\0"); +const AESGCM_AUTH_INFO = UTF8.encode("Content-Encoding: auth\0"); // note nul-terminus +const AESGCM_P256DH_INFO = UTF8.encode("P-256\0"); class aesgcmDecoder extends OldSchemeDecoder { /** @@ -516,16 +513,16 @@ class aesgcmDecoder extends OldSchemeDecoder { let keyInfo = concatArray([ AESGCM_KEY_INFO, AESGCM_P256DH_INFO, encodeLength(this.publicKey), this.publicKey, - encodeLength(this.senderKey), this.senderKey + encodeLength(this.senderKey), this.senderKey, ]); let nonceInfo = concatArray([ NONCE_INFO, new Uint8Array([0]), AESGCM_P256DH_INFO, encodeLength(this.publicKey), this.publicKey, - encodeLength(this.senderKey), this.senderKey + encodeLength(this.senderKey), this.senderKey, ]); return Promise.all([ prkKdf.extract(keyInfo, 16), - prkKdf.extract(nonceInfo, 12) + prkKdf.extract(nonceInfo, 12), ]); } @@ -536,8 +533,8 @@ class aesgcmDecoder extends OldSchemeDecoder { /** Oldest encryption scheme (draft-thomson-http-encryption-02). */ -var AESGCM128_ENCODING = 'aesgcm128'; -var AESGCM128_KEY_INFO = UTF8.encode('Content-Encoding: aesgcm128'); +const AESGCM128_ENCODING = "aesgcm128"; +const AESGCM128_KEY_INFO = UTF8.encode("Content-Encoding: aesgcm128"); class aesgcm128Decoder extends OldSchemeDecoder { constructor(privateKey, publicKey, cryptoParams, ciphertext) { @@ -553,7 +550,7 @@ class aesgcm128Decoder extends OldSchemeDecoder { let prkKdf = new hkdf(this.salt, ikm); return Promise.all([ prkKdf.extract(AESGCM128_KEY_INFO, 16), - prkKdf.extract(NONCE_INFO, 12) + prkKdf.extract(NONCE_INFO, 12), ]); } @@ -569,17 +566,17 @@ var PushCrypto = { }, validateAppServerKey(key) { - return crypto.subtle.importKey('raw', key, ECDSA_KEY, - true, ['verify']) + return crypto.subtle.importKey("raw", key, ECDSA_KEY, + true, ["verify"]) .then(_ => key); }, generateKeys() { - return crypto.subtle.generateKey(ECDH_KEY, true, ['deriveBits']) + return crypto.subtle.generateKey(ECDH_KEY, true, ["deriveBits"]) .then(cryptoKey => Promise.all([ - crypto.subtle.exportKey('raw', cryptoKey.publicKey), - crypto.subtle.exportKey('jwk', cryptoKey.privateKey) + crypto.subtle.exportKey("raw", cryptoKey.publicKey), + crypto.subtle.exportKey("jwk", cryptoKey.privateKey), ])); }, @@ -604,7 +601,7 @@ var PushCrypto = { let encoding = headers.encoding; if (!headers.encoding) { - throw new CryptoError('Missing Content-Encoding header', + throw new CryptoError("Missing Content-Encoding header", BAD_ENCODING_HEADER); } @@ -630,7 +627,7 @@ var PushCrypto = { } if (!decoder) { - throw new CryptoError('Unsupported Content-Encoding: ' + encoding, + throw new CryptoError("Unsupported Content-Encoding: " + encoding, BAD_ENCODING_HEADER); } @@ -650,7 +647,7 @@ var PushCrypto = { * @param {options} Object Encryption options, used for tests. * @returns {ciphertext, encoding} The encrypted payload and encoding. */ - async encrypt(plaintext, receiverPublicKey, receiverAuthSecret, options={}) { + async encrypt(plaintext, receiverPublicKey, receiverAuthSecret, options = {}) { const encoding = options.encoding || AES128GCM_ENCODING; // We only support one encoding type. if (encoding != AES128GCM_ENCODING) { @@ -674,7 +671,7 @@ var PushCrypto = { // A class for aes128gcm encryption - the only kind we support. class aes128gcmEncoder { - constructor(plaintext ,receiverPublicKey, receiverAuthSecret, senderKeyPair, salt, rs) { + constructor(plaintext, receiverPublicKey, receiverAuthSecret, senderKeyPair, salt, rs) { this.receiverPublicKey = receiverPublicKey; this.receiverAuthSecret = receiverAuthSecret; this.senderKeyPair = senderKeyPair; @@ -689,7 +686,7 @@ class aes128gcmEncoder { const rawSenderPublicKey = await crypto.subtle.exportKey("raw", this.senderKeyPair.publicKey); const [gcmBits, nonce] = await this.deriveKeyAndNonce(sharedSecret, - rawSenderPublicKey) + rawSenderPublicKey); const contentEncryptionKey = await crypto.subtle.importKey("raw", gcmBits, "AES-GCM", false, @@ -712,17 +709,17 @@ class aes128gcmEncoder { // Send an authentication tag for empty messages. chunks = [await crypto.subtle.encrypt({ name: "AES-GCM", - iv: generateNonce(nonce, 0) + iv: generateNonce(nonce, 0), }, key, new Uint8Array([2]))]; } else { // Use specified recordsize, though we burn 1 for padding and 16 byte // overhead. let inChunks = chunkArray(this.plaintext, this.rs - 1 - 16); - chunks = await Promise.all(inChunks.map(async function (slice, index) { + chunks = await Promise.all(inChunks.map(async function(slice, index) { let isLast = index == inChunks.length - 1; let padding = new Uint8Array([isLast ? 2 : 1]); let input = concatArray([slice, padding]); - return await crypto.subtle.encrypt({ + return crypto.subtle.encrypt({ name: "AES-GCM", iv: generateNonce(nonce, index), }, key, input); diff --git a/dom/push/PushDB.jsm b/dom/push/PushDB.jsm index 0bed56ba450a..b5a4e94394d6 100644 --- a/dom/push/PushDB.jsm +++ b/dom/push/PushDB.jsm @@ -1,4 +1,3 @@ -/* jshint moz: true, esnext: true */ /* 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/. */ @@ -7,9 +6,8 @@ const {IndexedDBHelper} = ChromeUtils.import("resource://gre/modules/IndexedDBHelper.jsm"); const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyGlobalGetters(this, ["indexedDB"]); -var EXPORTED_SYMBOLS = ["PushDB"]; +const EXPORTED_SYMBOLS = ["PushDB"]; XPCOMUtils.defineLazyGetter(this, "console", () => { let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm"); @@ -33,24 +31,24 @@ function PushDB(dbName, dbVersion, dbStoreName, keyPath, model) { this.PushDB.prototype = { __proto__: IndexedDBHelper.prototype, - toPushRecord: function(record) { + toPushRecord(record) { if (!record) { - return; + return null; } return new this._model(record); }, - isValidRecord: function(record) { + isValidRecord(record) { return record && typeof record.scope == "string" && typeof record.originAttributes == "string" && record.quota >= 0 && typeof record[this._keyPath] == "string"; }, - upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) { + upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) { if (aOldVersion <= 3) { - //XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old - //registrations away without even informing the app. + // XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old + // registrations away without even informing the app. if (aDb.objectStoreNames.contains(this._dbStoreName)) { aDb.deleteObjectStore(this._dbStoreName); } @@ -83,7 +81,7 @@ this.PushDB.prototype = { * The record to be added. */ - put: function(aRecord) { + put(aRecord) { console.debug("put()", aRecord); if (!this.isValidRecord(aRecord)) { return Promise.reject(new TypeError( @@ -116,7 +114,7 @@ this.PushDB.prototype = { * @param aKeyID * The ID of record to be deleted. */ - delete: function(aKeyID) { + delete(aKeyID) { console.debug("delete()"); return new Promise((resolve, reject) => @@ -138,7 +136,7 @@ this.PushDB.prototype = { // testFn(record) is called with a database record and should return true if // that record should be deleted. - clearIf: function(testFn) { + clearIf(testFn) { console.debug("clearIf()"); return new Promise((resolve, reject) => this.newTxn( @@ -156,11 +154,11 @@ this.PushDB.prototype = { deleteRequest.onerror = e => { console.error("clearIf: Error removing record", record.keyID, e); - } + }; } cursor.continue(); } - } + }; }, resolve, reject @@ -168,7 +166,7 @@ this.PushDB.prototype = { ); }, - getByPushEndpoint: function(aPushEndpoint) { + getByPushEndpoint(aPushEndpoint) { console.debug("getByPushEndpoint()"); return new Promise((resolve, reject) => @@ -191,7 +189,7 @@ this.PushDB.prototype = { ); }, - getByKeyID: function(aKeyID) { + getByKeyID(aKeyID) { console.debug("getByKeyID()"); return new Promise((resolve, reject) => @@ -224,7 +222,7 @@ this.PushDB.prototype = { * `cursor` is an `IDBCursor`. * @returns {Promise} Resolves once all records have been processed. */ - forEachOrigin: function(origin, originAttributes, callback) { + forEachOrigin(origin, originAttributes, callback) { console.debug("forEachOrigin()"); return new Promise((resolve, reject) => @@ -255,7 +253,7 @@ this.PushDB.prototype = { }, // Perform a unique match against { scope, originAttributes } - getByIdentifiers: function(aPageRecord) { + getByIdentifiers(aPageRecord) { console.debug("getByIdentifiers()", aPageRecord); if (!aPageRecord.scope || aPageRecord.originAttributes == undefined) { console.error("getByIdentifiers: Scope and originAttributes are required", @@ -282,7 +280,7 @@ this.PushDB.prototype = { ); }, - _getAllByKey: function(aKeyName, aKeyValue) { + _getAllByKey(aKeyName, aKeyValue) { return new Promise((resolve, reject) => this.newTxn( "readonly", @@ -307,14 +305,14 @@ this.PushDB.prototype = { }, // aOriginAttributes must be a string! - getAllByOriginAttributes: function(aOriginAttributes) { + getAllByOriginAttributes(aOriginAttributes) { if (typeof aOriginAttributes !== "string") { return Promise.reject("Expected string!"); } return this._getAllByKey("originAttributes", aOriginAttributes); }, - getAllKeyIDs: function() { + getAllKeyIDs() { console.debug("getAllKeyIDs()"); return new Promise((resolve, reject) => @@ -334,7 +332,7 @@ this.PushDB.prototype = { ); }, - _getAllByPushQuota: function(range) { + _getAllByPushQuota(range) { console.debug("getAllByPushQuota()"); return new Promise((resolve, reject) => @@ -359,12 +357,12 @@ this.PushDB.prototype = { ); }, - getAllUnexpired: function() { + getAllUnexpired() { console.debug("getAllUnexpired()"); return this._getAllByPushQuota(IDBKeyRange.lowerBound(1)); }, - getAllExpired: function() { + getAllExpired() { console.debug("getAllExpired()"); return this._getAllByPushQuota(IDBKeyRange.only(0)); }, @@ -379,7 +377,7 @@ this.PushDB.prototype = { * Rejects if the record does not exist, or the function returns an invalid * record. */ - update: function(aKeyID, aUpdateFunc) { + update(aKeyID, aUpdateFunc) { return new Promise((resolve, reject) => this.newTxn( "readwrite", @@ -420,7 +418,7 @@ this.PushDB.prototype = { ); }, - drop: function() { + drop() { console.debug("drop()"); return new Promise((resolve, reject) => diff --git a/dom/push/PushRecord.jsm b/dom/push/PushRecord.jsm index 293bc17bf01c..977cd207ab5d 100644 --- a/dom/push/PushRecord.jsm +++ b/dom/push/PushRecord.jsm @@ -16,7 +16,7 @@ ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); -var EXPORTED_SYMBOLS = ["PushRecord"]; +const EXPORTED_SYMBOLS = ["PushRecord"]; const prefs = Services.prefs.getBranch("dom.push."); @@ -147,7 +147,7 @@ PushRecord.prototype = { Ci.nsINavHistoryService.TRANSITION_TYPED, Ci.nsINavHistoryService.TRANSITION_BOOKMARK, Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT, - Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY + Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY, ].join(","); let db = await PlacesUtils.promiseDBConnection(); @@ -282,7 +282,6 @@ Object.defineProperties(PushRecord.prototype, { let uri = Services.io.newURI(this.scope); // Allow tests to omit origin attributes. let originSuffix = this.originAttributes || ""; - let originAttributes = principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, ChromeUtils.createOriginAttributesFromOrigin(originSuffix)); principals.set(this, principal); diff --git a/dom/push/PushService.jsm b/dom/push/PushService.jsm index 8b1f342851e8..f9549c748843 100644 --- a/dom/push/PushService.jsm +++ b/dom/push/PushService.jsm @@ -1,4 +1,3 @@ -/* jshint moz: true, esnext: true */ /* 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/. */ @@ -11,23 +10,16 @@ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); const {clearTimeout, setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm"); const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -var { - PushCrypto, - CryptoError, -} = ChromeUtils.import("resource://gre/modules/PushCrypto.jsm", null); -const {PushDB} = ChromeUtils.import("resource://gre/modules/PushDB.jsm"); - var PushServiceWebSocket, PushServiceHttp2; const CONNECTION_PROTOCOLS = (function() { - if ('android' != AppConstants.MOZ_WIDGET_TOOLKIT) { + if ("android" != AppConstants.MOZ_WIDGET_TOOLKIT) { ({PushServiceWebSocket} = ChromeUtils.import("resource://gre/modules/PushServiceWebSocket.jsm")); ({PushServiceHttp2} = ChromeUtils.import("resource://gre/modules/PushServiceHttp2.jsm")); return [PushServiceWebSocket, PushServiceHttp2]; - } else { - const {PushServiceAndroidGCM} = ChromeUtils.import("resource://gre/modules/PushServiceAndroidGCM.jsm"); - return [PushServiceAndroidGCM]; } + const {PushServiceAndroidGCM} = ChromeUtils.import("resource://gre/modules/PushServiceAndroidGCM.jsm"); + return [PushServiceAndroidGCM]; })(); XPCOMUtils.defineLazyServiceGetter(this, "gPushNotifier", @@ -37,8 +29,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "eTLDService", "@mozilla.org/network/effective-tld-service;1", "nsIEffectiveTLDService"); ChromeUtils.defineModuleGetter(this, "pushBroadcastService", "resource://gre/modules/PushBroadcastService.jsm"); +ChromeUtils.defineModuleGetter(this, "PushCrypto", "resource://gre/modules/PushCrypto.jsm"); -var EXPORTED_SYMBOLS = ["PushService"]; +const EXPORTED_SYMBOLS = ["PushService"]; XPCOMUtils.defineLazyGetter(this, "console", () => { let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm"); @@ -52,7 +45,7 @@ const prefs = new Preferences("dom.push."); const PUSH_SERVICE_UNINIT = 0; const PUSH_SERVICE_INIT = 1; // No serverURI -const PUSH_SERVICE_ACTIVATING = 2;//activating db +const PUSH_SERVICE_ACTIVATING = 2; // activating db const PUSH_SERVICE_CONNECTION_DISABLE = 3; const PUSH_SERVICE_ACTIVE_OFFLINE = 4; const PUSH_SERVICE_RUNNING = 5; @@ -112,7 +105,7 @@ var PushService = { // When serverURI changes (this is used for testing), db is cleaned up and a // a new db is started. This events must be sequential. _stateChangeProcessQueue: null, - _stateChangeProcessEnqueue: function(op) { + _stateChangeProcessEnqueue(op) { if (!this._stateChangeProcessQueue) { this._stateChangeProcessQueue = Promise.resolve(); } @@ -137,24 +130,26 @@ var PushService = { _pendingRegisterRequest: {}, _notifyActivated: null, _activated: null, - _checkActivated: function() { + _checkActivated() { if (this._state < PUSH_SERVICE_ACTIVATING) { return Promise.reject(new Error("Push service not active")); - } else if (this._state > PUSH_SERVICE_ACTIVATING) { - return Promise.resolve(); - } else { - return (this._activated) ? this._activated : - this._activated = new Promise((res, rej) => - this._notifyActivated = {resolve: res, - reject: rej}); } + if (this._state > PUSH_SERVICE_ACTIVATING) { + return Promise.resolve(); + } + if (!this._activated) { + this._activated = new Promise((resolve, reject) => { + this._notifyActivated = {resolve, reject}; + }); + } + return this._activated; }, - _makePendingKey: function(aPageRecord) { + _makePendingKey(aPageRecord) { return aPageRecord.scope + "|" + aPageRecord.originAttributes; }, - _lookupOrPutPendingRequest: function(aPageRecord) { + _lookupOrPutPendingRequest(aPageRecord) { let key = this._makePendingKey(aPageRecord); if (this._pendingRegisterRequest[key]) { return this._pendingRegisterRequest[key]; @@ -163,14 +158,14 @@ var PushService = { return this._pendingRegisterRequest[key] = this._registerWithServer(aPageRecord); }, - _deletePendingRequest: function(aPageRecord) { + _deletePendingRequest(aPageRecord) { let key = this._makePendingKey(aPageRecord); if (this._pendingRegisterRequest[key]) { delete this._pendingRegisterRequest[key]; } }, - _setState: function(aNewState) { + _setState(aNewState) { console.debug("setState()", "new state", aNewState, "old state", this._state); if (this._state == aNewState) { @@ -232,7 +227,7 @@ var PushService = { this._service.connect(broadcastListeners); }, - _changeStateConnectionEnabledEvent: function(enabled) { + _changeStateConnectionEnabledEvent(enabled) { console.debug("changeStateConnectionEnabledEvent()", enabled); if (this._state < PUSH_SERVICE_CONNECTION_DISABLE && @@ -289,7 +284,6 @@ var PushService = { this._changeServerURL(prefs.get("serverURL"), CHANGING_SERVICE_EVENT) ); - } else if (aData == "dom.push.connection.enabled") { this._stateChangeProcessEnqueue(_ => this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled")) @@ -307,7 +301,7 @@ var PushService = { this._onPermissionChange(aSubject, aData).catch(error => { console.error("onPermissionChange: Error updating registrations:", error); - }) + }); break; case "clear-origin-attributes-data": @@ -318,7 +312,7 @@ var PushService = { } }, - _clearOriginData: function(data) { + _clearOriginData(data) { console.log("clearOriginData()"); if (!data) { @@ -353,7 +347,7 @@ var PushService = { }); }, - _findService: function(serverURL) { + _findService(serverURL) { console.debug("findService()"); let uri; @@ -381,10 +375,10 @@ var PushService = { return [service, uri]; }, - _changeServerURL: function(serverURI, event, options = {}) { + _changeServerURL(serverURI, event, options = {}) { console.debug("changeServerURL()"); - switch(event) { + switch (event) { case UNINIT_EVENT: return this._stopService(event); @@ -408,30 +402,22 @@ var PushService = { return this._startService(service, uri, options) .then(_ => this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled")) ); - - } else { - this._setState(PUSH_SERVICE_ACTIVATING); - // If we already had running service - stop service, start the new - // one and check connection.enabled and offline state(offline state - // check is called in changeStateConnectionEnabledEvent function) - return this._stopService(CHANGING_SERVICE_EVENT) - .then(_ => - this._startService(service, uri, options) - ) - .then(_ => this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled")) - ); - - } - } else { - if (this._state == PUSH_SERVICE_INIT) { - return Promise.resolve(); - - } else { - // The new serverUri is empty or misconfigured - stop service. - this._setState(PUSH_SERVICE_INIT); - return this._stopService(STOPPING_SERVICE_EVENT); } + this._setState(PUSH_SERVICE_ACTIVATING); + // If we already had running service - stop service, start the new + // one and check connection.enabled and offline state(offline state + // check is called in changeStateConnectionEnabledEvent function) + return this._stopService(CHANGING_SERVICE_EVENT) + .then(_ => this._startService(service, uri, options)) + .then(_ => this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled"))); } + if (this._state == PUSH_SERVICE_INIT) { + return Promise.resolve(); + } + // The new serverUri is empty or misconfigured - stop service. + this._setState(PUSH_SERVICE_INIT); + return this._stopService(STOPPING_SERVICE_EVENT); + default: console.error("Unexpected event in _changeServerURL", event); return Promise.reject(new Error(`Unexpected event ${event}`)); @@ -470,7 +456,6 @@ var PushService = { await this._stateChangeProcessEnqueue(_ => this._changeServerURL(options.serverURI, STARTING_SERVICE_EVENT, options)); - } else { // This is only used for testing. Different tests require connecting to // slightly different URLs. @@ -479,7 +464,7 @@ var PushService = { } }, - _startObservers: function() { + _startObservers() { console.debug("startObservers()"); if (this._state != PUSH_SERVICE_ACTIVATING) { @@ -534,7 +519,7 @@ var PushService = { * uninit() - stop listening for quit-application and serverURL changes. * state is change to PUSH_SERVICE_UNINIT */ - _stopService: function(event) { + _stopService(event) { console.debug("stopService()"); if (this._state < PUSH_SERVICE_ACTIVATING) { @@ -570,7 +555,7 @@ var PushService = { }); }, - _stopObservers: function() { + _stopObservers() { console.debug("stopObservers()"); if (this._state < PUSH_SERVICE_ACTIVATING) { @@ -616,7 +601,7 @@ var PushService = { * expired because the user revoked the notification permission are evicted * once the permission is reinstated. */ - dropUnexpiredRegistrations: function() { + dropUnexpiredRegistrations() { return this._db.clearIf(record => { if (record.isExpired()) { return false; @@ -626,7 +611,7 @@ var PushService = { }); }, - _notifySubscriptionChangeObservers: function(record) { + _notifySubscriptionChangeObservers(record) { if (!record) { return; } @@ -640,7 +625,7 @@ var PushService = { * @param {String} keyID The registration ID to remove. * @returns {Promise} Resolves once the worker has been notified. */ - dropRegistrationAndNotifyApp: function(aKeyID) { + dropRegistrationAndNotifyApp(aKeyID) { return this._db.delete(aKeyID) .then(record => this._notifySubscriptionChangeObservers(record)); }, @@ -653,7 +638,7 @@ var PushService = { * @param {PushRecord} aNewRecord The new record. * @returns {Promise} Resolves once the worker has been notified. */ - updateRegistrationAndNotifyApp: function(aOldKey, aNewRecord) { + updateRegistrationAndNotifyApp(aOldKey, aNewRecord) { return this.updateRecordAndNotifyApp(aOldKey, _ => aNewRecord); }, /** @@ -664,7 +649,7 @@ var PushService = { * @returns {Promise} Resolves with the updated record once the worker * has been notified. */ - updateRecordAndNotifyApp: function(aKeyID, aUpdateFunc) { + updateRecordAndNotifyApp(aKeyID, aUpdateFunc) { return this._db.update(aKeyID, aUpdateFunc) .then(record => { this._notifySubscriptionChangeObservers(record); @@ -672,7 +657,7 @@ var PushService = { }); }, - ensureCrypto: function(record) { + ensureCrypto(record) { if (record.hasAuthenticationSecret() && record.p256dhPublicKey && record.p256dhPrivateKey) { @@ -730,8 +715,7 @@ var PushService = { if (record.quotaApplies()) { // Update quota after the delay, at which point // we check for visible notifications. - let timeoutID = setTimeout(_ => - { + let timeoutID = setTimeout(_ => { this._updateQuota(keyID); if (!this._updateQuotaTimeouts.delete(timeoutID)) { console.debug("receivedPushMessage: quota update timeout missing?"); @@ -753,7 +737,7 @@ var PushService = { pushBroadcastService.receivedBroadcastMessage(message.broadcasts) .catch(e => { console.error(e); - });; + }); }, /** @@ -827,7 +811,7 @@ var PushService = { }); }, - _updateQuota: function(keyID) { + _updateQuota(keyID) { console.debug("updateQuota()"); this._db.update(keyID, record => { @@ -894,7 +878,6 @@ var PushService = { console.debug("reportDeliveryError()", messageID, reason); if (this._state == PUSH_SERVICE_RUNNING && this._service.isConnected()) { - // Only report errors if we're initialized and connected. this._service.reportDeliveryError(messageID, reason); } @@ -935,11 +918,11 @@ var PushService = { return Ci.nsIPushErrorReporter.ACK_DELIVERED; }, - getByKeyID: function(aKeyID) { + getByKeyID(aKeyID) { return this._db.getByKeyID(aKeyID); }, - getAllUnexpired: function() { + getAllUnexpired() { return this._db.getAllUnexpired(); }, @@ -968,7 +951,7 @@ var PushService = { * Called on message from the child process. aPageRecord is an object sent by * the push manager, identifying the sending page and other fields. */ - _registerWithServer: function(aPageRecord) { + _registerWithServer(aPageRecord) { console.debug("registerWithServer()", aPageRecord); return this._sendRequest("register", aPageRecord) @@ -993,7 +976,7 @@ var PushService = { * Exceptions thrown in _onRegisterSuccess are caught by the promise obtained * from _service.request, causing the promise to be rejected instead. */ - _onRegisterSuccess: function(aRecord) { + _onRegisterSuccess(aRecord) { console.debug("_onRegisterSuccess()"); return this._db.put(aRecord) @@ -1009,7 +992,7 @@ var PushService = { * Exceptions thrown in _onRegisterError are caught by the promise obtained * from _service.request, causing the promise to be rejected instead. */ - _onRegisterError: function(reply) { + _onRegisterError(reply) { console.debug("_onRegisterError()"); if (!reply.error) { @@ -1030,7 +1013,7 @@ var PushService = { ); }, - register: function(aPageRecord) { + register(aPageRecord) { console.debug("register()", aPageRecord); let keyPromise; @@ -1114,29 +1097,29 @@ var PushService = { * client acknowledge. On a server, data is cheap, reliable notification is * not. */ - unregister: function(aPageRecord) { + unregister(aPageRecord) { console.debug("unregister()", aPageRecord); return this._getByPageRecord(aPageRecord) .then(record => { - if (record === undefined) { + if (record === null) { return false; } let reason = Ci.nsIPushErrorReporter.UNSUBSCRIBE_MANUAL; return Promise.all([ this._sendUnregister(record, reason), - this._db.delete(record.keyID).then(record => { - if (record) { - gPushNotifier.notifySubscriptionModified(record.scope, - record.principal); + this._db.delete(record.keyID).then(rec => { + if (rec) { + gPushNotifier.notifySubscriptionModified(rec.scope, + rec.principal); } }), ]).then(([success]) => success); }); }, - clear: function(info) { + clear(info) { return this._checkActivated() .then(_ => { return this._dropRegistrationsIf(record => @@ -1151,7 +1134,7 @@ var PushService = { }); }, - registration: function(aPageRecord) { + registration(aPageRecord) { console.debug("registration()"); return this._getByPageRecord(aPageRecord) @@ -1171,7 +1154,7 @@ var PushService = { }); }, - _dropExpiredRegistrations: function() { + _dropExpiredRegistrations() { console.debug("dropExpiredRegistrations()"); return this._db.getAllExpired().then(records => { @@ -1180,7 +1163,7 @@ var PushService = { if (isChanged) { // If the user revisited the site, drop the expired push // registration and notify the associated service worker. - return this.dropRegistrationAndNotifyApp(record.keyID); + this.dropRegistrationAndNotifyApp(record.keyID); } }).catch(error => { console.error("dropExpiredRegistrations: Error dropping registration", @@ -1190,7 +1173,7 @@ var PushService = { }); }, - _onPermissionChange: function(subject, data) { + _onPermissionChange(subject, data) { console.debug("onPermissionChange()"); if (data == "cleared") { @@ -1219,7 +1202,7 @@ var PushService = { }); }, - _updatePermission: function(permission, type) { + _updatePermission(permission, type) { console.debug("updatePermission()"); let isAllow = permission.capability == @@ -1246,7 +1229,7 @@ var PushService = { return Promise.resolve(); }, - _forEachPrincipal: function(principal, callback) { + _forEachPrincipal(principal, callback) { return this._db.forEachOrigin( principal.URI.prePath, ChromeUtils.originAttributesToSuffix(principal.originAttributes), @@ -1264,7 +1247,7 @@ var PushService = { * @param {PushRecord} record The record to expire. * @param {IDBCursor} cursor The IndexedDB cursor. */ - _permissionDenied: function(record, cursor) { + _permissionDenied(record, cursor) { console.debug("permissionDenied()"); if (!record.quotaApplies() || record.isExpired()) { diff --git a/dom/push/PushServiceAndroidGCM.jsm b/dom/push/PushServiceAndroidGCM.jsm index 54c8da9a6bdb..6468263ce84d 100644 --- a/dom/push/PushServiceAndroidGCM.jsm +++ b/dom/push/PushServiceAndroidGCM.jsm @@ -1,21 +1,24 @@ -/* jshint moz: true, esnext: true */ /* 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/. */ "use strict"; -const {PushDB} = ChromeUtils.import("resource://gre/modules/PushDB.jsm"); -const {PushRecord} = ChromeUtils.import("resource://gre/modules/PushRecord.jsm"); -const {PushCrypto} = ChromeUtils.import("resource://gre/modules/PushCrypto.jsm"); -const {EventDispatcher} = ChromeUtils.import("resource://gre/modules/Messaging.jsm"); /*global: EventDispatcher */ -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); /*global: Services */ -const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm"); /*global: Preferences */ -const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); /*global: XPCOMUtils */ +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -const Log = ChromeUtils.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.bind("Push"); +ChromeUtils.defineModuleGetter(this, "PushDB", "resource://gre/modules/PushDB.jsm"); +ChromeUtils.defineModuleGetter(this, "PushRecord", "resource://gre/modules/PushRecord.jsm"); +ChromeUtils.defineModuleGetter(this, "PushCrypto", "resource://gre/modules/PushCrypto.jsm"); +ChromeUtils.defineModuleGetter(this, "EventDispatcher", "resource://gre/modules/Messaging.jsm"); +ChromeUtils.defineModuleGetter(this, "Preferences", "resource://gre/modules/Preferences.jsm"); -var EXPORTED_SYMBOLS = ["PushServiceAndroidGCM"]; +XPCOMUtils.defineLazyGetter(this, "Log", () => { + return ChromeUtils.import("resource://gre/modules/AndroidLog.jsm", {}) + .AndroidLog.bind("Push"); +}); + +const EXPORTED_SYMBOLS = ["PushServiceAndroidGCM"]; XPCOMUtils.defineLazyGetter(this, "console", () => { let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm"); @@ -42,7 +45,7 @@ var PushServiceAndroidGCM = { _mainPushService: null, _serverURI: null, - newPushDB: function() { + newPushDB() { return new PushDB(kPUSHANDROIDGCMDB_DB_NAME, kPUSHANDROIDGCMDB_DB_VERSION, kPUSHANDROIDGCMDB_STORE_NAME, @@ -50,7 +53,7 @@ var PushServiceAndroidGCM = { PushRecordAndroidGCM); }, - validServerURI: function(serverURI) { + validServerURI(serverURI) { if (!serverURI) { return false; } @@ -66,7 +69,7 @@ var PushServiceAndroidGCM = { return false; }, - observe: function(subject, topic, data) { + observe(subject, topic, data) { switch (topic) { case "nsPref:changed": if (data == "dom.push.debug") { @@ -121,7 +124,7 @@ var PushServiceAndroidGCM = { encryption: data.enc, encoding: data.con, }; - } else if (data.con == 'aes128gcm') { + } else if (data.con == "aes128gcm") { headers = { encoding: data.con, }; @@ -136,15 +139,15 @@ var PushServiceAndroidGCM = { return { headers, message }; }, - _configure: function(serverURL, debug) { + _configure(serverURL, debug) { return EventDispatcher.instance.sendRequestForResult({ type: "PushServiceAndroidGCM:Configure", endpoint: serverURL.spec, - debug: debug, + debug, }); }, - init: function(options, mainPushService, serverURL) { + init(options, mainPushService, serverURL) { console.debug("init()"); this._mainPushService = mainPushService; this._serverURI = serverURL; @@ -154,15 +157,15 @@ var PushServiceAndroidGCM = { return this._configure(serverURL, !!prefs.get("debug")).then(() => { EventDispatcher.instance.sendRequestForResult({ - type: "PushServiceAndroidGCM:Initialized" + type: "PushServiceAndroidGCM:Initialized", }); }); }, - uninit: function() { + uninit() { console.debug("uninit()"); EventDispatcher.instance.sendRequestForResult({ - type: "PushServiceAndroidGCM:Uninitialized" + type: "PushServiceAndroidGCM:Uninitialized", }); this._mainPushService = null; @@ -170,11 +173,11 @@ var PushServiceAndroidGCM = { prefs.ignore("debug", this); }, - onAlarmFired: function() { + onAlarmFired() { // No action required. }, - connect: function(records, broadcastListeners) { + connect(records, broadcastListeners) { console.debug("connect:", records); // It's possible for the registration or subscriptions backing the // PushService to not be registered with the underlying AndroidPushService. @@ -201,19 +204,19 @@ var PushServiceAndroidGCM = { }); }, - sendSubscribeBroadcast: async function(serviceId, version) { + async sendSubscribeBroadcast(serviceId, version) { // Not implemented yet }, - isConnected: function() { + isConnected() { return this._mainPushService != null; }, - disconnect: function() { + disconnect() { console.debug("disconnect"); }, - register: function(record) { + register(record) { console.debug("register:", record); let ctime = Date.now(); let appServerKey = record.appServerKey ? @@ -223,8 +226,8 @@ var PushServiceAndroidGCM = { }) : null; let message = { type: "PushServiceAndroidGCM:SubscribeChannel", - appServerKey: appServerKey, - } + appServerKey, + }; if (record.scope == FXA_PUSH_SCOPE) { message.service = "fxa"; } @@ -242,7 +245,7 @@ var PushServiceAndroidGCM = { // Common to all PushRecord implementations. scope: record.scope, originAttributes: record.originAttributes, - ctime: ctime, + ctime, systemRecord: record.systemRecord, // Cryptography! p256dhPublicKey: exportedKeys[0], @@ -254,7 +257,7 @@ var PushServiceAndroidGCM = { }); }, - unregister: function(record) { + unregister(record) { console.debug("unregister: ", record); return EventDispatcher.instance.sendRequestForResult({ type: "PushServiceAndroidGCM:UnsubscribeChannel", @@ -262,7 +265,7 @@ var PushServiceAndroidGCM = { }); }, - reportDeliveryError: function(messageID, reason) { + reportDeliveryError(messageID, reason) { console.warn("reportDeliveryError: Ignoring message delivery error", messageID, reason); }, diff --git a/dom/push/PushServiceHttp2.jsm b/dom/push/PushServiceHttp2.jsm index c79f622f364a..8b31fb2c70f2 100644 --- a/dom/push/PushServiceHttp2.jsm +++ b/dom/push/PushServiceHttp2.jsm @@ -52,16 +52,16 @@ PushSubscriptionListener.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIHttpPushListener", "nsIStreamListener"]), - getInterface: function(aIID) { + getInterface(aIID) { return this.QueryInterface(aIID); }, - onStartRequest: function(aRequest) { + onStartRequest(aRequest) { console.debug("PushSubscriptionListener: onStartRequest()"); // We do not do anything here. }, - onDataAvailable: function(aRequest, aStream, aOffset, aCount) { + onDataAvailable(aRequest, aStream, aOffset, aCount) { console.debug("PushSubscriptionListener: onDataAvailable()"); // Nobody should send data, but just to be sure, otherwise necko will // complain. @@ -73,10 +73,10 @@ PushSubscriptionListener.prototype = { .createInstance(Ci.nsIScriptableInputStream); inputStream.init(aStream); - var data = inputStream.read(aCount); + inputStream.read(aCount); }, - onStopRequest: function(aRequest, aStatusCode) { + onStopRequest(aRequest, aStatusCode) { console.debug("PushSubscriptionListener: onStopRequest()"); if (!this._pushService) { return; @@ -87,15 +87,15 @@ PushSubscriptionListener.prototype = { this.uri); }, - onPush: function(associatedChannel, pushChannel) { + onPush(associatedChannel, pushChannel) { console.debug("PushSubscriptionListener: onPush()"); var pushChannelListener = new PushChannelListener(this); pushChannel.asyncOpen(pushChannelListener); }, - disconnect: function() { + disconnect() { this._pushService = null; - } + }, }; /** @@ -111,11 +111,11 @@ var PushChannelListener = function(pushSubscriptionListener) { PushChannelListener.prototype = { - onStartRequest: function(aRequest) { + onStartRequest(aRequest) { this._ackUri = aRequest.URI.spec; }, - onDataAvailable: function(aRequest, aStream, aOffset, aCount) { + onDataAvailable(aRequest, aStream, aOffset, aCount) { console.debug("PushChannelListener: onDataAvailable()"); if (aCount === 0) { @@ -131,7 +131,7 @@ PushChannelListener.prototype = { this._message.push(chunk); }, - onStopRequest: function(aRequest, aStatusCode) { + onStopRequest(aRequest, aStatusCode) { console.debug("PushChannelListener: onStopRequest()", "status code", aStatusCode); if (Components.isSuccessCode(aStatusCode) && @@ -150,13 +150,13 @@ PushChannelListener.prototype = { headers, msg); } - } + }, }; function getHeaderField(aRequest, name) { try { return aRequest.getRequestHeader(name); - } catch(e) { + } catch (e) { // getRequestHeader can throw. return null; } @@ -169,9 +169,9 @@ var PushServiceDelete = function(resolve, reject) { PushServiceDelete.prototype = { - onStartRequest: function(aRequest) {}, + onStartRequest(aRequest) {}, - onDataAvailable: function(aRequest, aStream, aOffset, aCount) { + onDataAvailable(aRequest, aStream, aOffset, aCount) { // Nobody should send data, but just to be sure, otherwise necko will // complain. if (aCount === 0) { @@ -182,17 +182,16 @@ PushServiceDelete.prototype = { .createInstance(Ci.nsIScriptableInputStream); inputStream.init(aStream); - var data = inputStream.read(aCount); + inputStream.read(aCount); }, - onStopRequest: function(aRequest, aStatusCode) { - + onStopRequest(aRequest, aStatusCode) { if (Components.isSuccessCode(aStatusCode)) { this._resolve(); } else { this._reject(new Error("Error removing subscription: " + aStatusCode)); } - } + }, }; var SubscriptionListener = function(aSubInfo, aResolve, aReject, @@ -201,7 +200,6 @@ var SubscriptionListener = function(aSubInfo, aResolve, aReject, this._subInfo = aSubInfo; this._resolve = aResolve; this._reject = aReject; - this._data = ''; this._serverURI = aServerURI; this._service = aPushServiceHttp2; this._ctime = Date.now(); @@ -210,25 +208,11 @@ var SubscriptionListener = function(aSubInfo, aResolve, aReject, SubscriptionListener.prototype = { - onStartRequest: function(aRequest) {}, + onStartRequest(aRequest) {}, - onDataAvailable: function(aRequest, aStream, aOffset, aCount) { - console.debug("SubscriptionListener: onDataAvailable()"); + onDataAvailable(aRequest, aStream, aOffset, aCount) {}, - // We do not expect any data, but necko will complain if we do not consume - // it. - if (aCount === 0) { - return; - } - - let inputStream = Cc["@mozilla.org/scriptableinputstream;1"] - .createInstance(Ci.nsIScriptableInputStream); - - inputStream.init(aStream); - this._data.concat(inputStream.read(aCount)); - }, - - onStopRequest: function(aRequest, aStatus) { + onStopRequest(aRequest, aStatus) { console.debug("SubscriptionListener: onStopRequest()"); // Check if pushService is still active. @@ -248,12 +232,11 @@ SubscriptionListener.prototype = { if (this._subInfo.retries < prefs.getIntPref("http2.maxRetries")) { this._subInfo.retries++; var retryAfter = retryAfterParser(aRequest); - this._retryTimeoutID = setTimeout(_ => - { + this._retryTimeoutID = setTimeout(_ => { this._reject( { retry: true, - subInfo: this._subInfo + subInfo: this._subInfo, }); this._service.removeListenerPendingRetry(this); this._retryTimeoutID = null; @@ -299,7 +282,7 @@ SubscriptionListener.prototype = { return; } try { - let uriTry = Services.io.newURI(subscriptionUri); + Services.io.newURI(subscriptionUri); } catch (e) { console.error("onStopRequest: Invalid subscription URI", subscriptionUri); @@ -309,7 +292,7 @@ SubscriptionListener.prototype = { } let reply = new PushRecordHttp2({ - subscriptionUri: subscriptionUri, + subscriptionUri, pushEndpoint: linkParserResult.pushEndpoint, pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint, scope: this._subInfo.record.scope, @@ -322,7 +305,7 @@ SubscriptionListener.prototype = { this._resolve(reply); }, - abortRetry: function() { + abortRetry() { if (this._retryTimeoutID != null) { clearTimeout(this._retryTimeoutID); this._retryTimeoutID = null; @@ -333,41 +316,39 @@ SubscriptionListener.prototype = { }; function retryAfterParser(aRequest) { - var retryAfter = 0; + let retryAfter = 0; try { - var retryField = aRequest.getResponseHeader("retry-after"); + let retryField = aRequest.getResponseHeader("retry-after"); if (isNaN(retryField)) { retryAfter = Date.parse(retryField) - (new Date().getTime()); } else { retryAfter = parseInt(retryField, 10) * 1000; } retryAfter = (retryAfter > 0) ? retryAfter : 0; - } catch(e) {} + } catch (e) {} return retryAfter; } function linkParser(linkHeader, serverURI) { - - var linkList = linkHeader.split(','); + let linkList = linkHeader.split(","); if ((linkList.length < 1)) { throw new Error("Invalid Link header"); } - var pushEndpoint; - var pushReceiptEndpoint; + let pushEndpoint; + let pushReceiptEndpoint; linkList.forEach(link => { - var linkElems = link.split(';'); + let linkElems = link.split(";"); if (linkElems.length == 2) { if (linkElems[1].trim() === 'rel="urn:ietf:params:push"') { - pushEndpoint = linkElems[0].substring(linkElems[0].indexOf('<') + 1, - linkElems[0].indexOf('>')); - + pushEndpoint = linkElems[0].substring(linkElems[0].indexOf("<") + 1, + linkElems[0].indexOf(">")); } else if (linkElems[1].trim() === 'rel="urn:ietf:params:push:receipt"') { - pushReceiptEndpoint = linkElems[0].substring(linkElems[0].indexOf('<') + 1, - linkElems[0].indexOf('>')); + pushReceiptEndpoint = linkElems[0].substring(linkElems[0].indexOf("<") + 1, + linkElems[0].indexOf(">")); } } }); @@ -379,8 +360,8 @@ function linkParser(linkHeader, serverURI) { throw new Error("Missing push endpoint"); } - var pushURI = Services.io.newURI(pushEndpoint, null, serverURI); - var pushReceiptURI; + const pushURI = Services.io.newURI(pushEndpoint, null, serverURI); + let pushReceiptURI; if (pushReceiptEndpoint) { pushReceiptURI = Services.io.newURI(pushReceiptEndpoint, null, serverURI); @@ -406,7 +387,7 @@ var PushServiceHttp2 = { // Set of SubscriptionListeners that are pending a subscription retry attempt. _listenersPendingRetry: new Set(), - newPushDB: function() { + newPushDB() { return new PushDB(kPUSHHTTP2DB_DB_NAME, kPUSHHTTP2DB_DB_VERSION, kPUSHHTTP2DB_STORE_NAME, @@ -414,11 +395,11 @@ var PushServiceHttp2 = { PushRecordHttp2); }, - hasmainPushService: function() { + hasmainPushService() { return this._mainPushService !== null; }, - validServerURI: function(serverURI) { + validServerURI(serverURI) { if (serverURI.scheme == "http") { return !!prefs.getBoolPref("testing.allowInsecureServerURL", false); } @@ -430,19 +411,19 @@ var PushServiceHttp2 = { this.startConnections(subscriptions); }, - sendSubscribeBroadcast: async function(serviceId, version) { + async sendSubscribeBroadcast(serviceId, version) { // Not implemented yet }, - isConnected: function() { + isConnected() { return this._mainPushService != null; }, - disconnect: function() { + disconnect() { this._shutdownConnections(false); }, - _makeChannel: function(aUri) { + _makeChannel(aUri) { var chan = NetUtil.newChannel({uri: aUri, loadUsingSystemPrincipal: true}) .QueryInterface(Ci.nsIHttpChannel); @@ -455,33 +436,33 @@ var PushServiceHttp2 = { /** * Subscribe new resource. */ - register: function(aRecord) { + register(aRecord) { console.debug("subscribeResource()"); return this._subscribeResourceInternal({ record: aRecord, - retries: 0 + retries: 0, }) .then(result => PushCrypto.generateKeys() .then(([publicKey, privateKey]) => { - result.p256dhPublicKey = publicKey; - result.p256dhPrivateKey = privateKey; - result.authenticationSecret = PushCrypto.generateAuthenticationSecret(); - this._conns[result.subscriptionUri] = { - channel: null, - listener: null, - countUnableToConnect: 0, - lastStartListening: 0, - retryTimerID: 0, - }; - this._listenForMsgs(result.subscriptionUri); - return result; - }) + result.p256dhPublicKey = publicKey; + result.p256dhPrivateKey = privateKey; + result.authenticationSecret = PushCrypto.generateAuthenticationSecret(); + this._conns[result.subscriptionUri] = { + channel: null, + listener: null, + countUnableToConnect: 0, + lastStartListening: 0, + retryTimerID: 0, + }; + this._listenForMsgs(result.subscriptionUri); + return result; + }) ); }, - _subscribeResourceInternal: function(aSubInfo) { + _subscribeResourceInternal(aSubInfo) { console.debug("subscribeResourceInternal()"); return new Promise((resolve, reject) => { @@ -498,15 +479,13 @@ var PushServiceHttp2 = { .catch(err => { if ("retry" in err) { return this._subscribeResourceInternal(err.subInfo); - } else { - throw err; } - }) + throw err; + }); }, - _deleteResource: function(aUri) { - - return new Promise((resolve,reject) => { + _deleteResource(aUri) { + return new Promise((resolve, reject) => { var chan = this._makeChannel(aUri); chan.requestMethod = "DELETE"; chan.asyncOpen(new PushServiceDelete(resolve, reject)); @@ -517,7 +496,7 @@ var PushServiceHttp2 = { * Unsubscribe the resource with a subscription uri aSubscriptionUri. * We can't do anything about it if it fails, so we don't listen for response. */ - _unsubscribeResource: function(aSubscriptionUri) { + _unsubscribeResource(aSubscriptionUri) { console.debug("unsubscribeResource()"); return this._deleteResource(aSubscriptionUri); @@ -526,7 +505,7 @@ var PushServiceHttp2 = { /** * Start listening for messages. */ - _listenForMsgs: function(aSubscriptionUri) { + _listenForMsgs(aSubscriptionUri) { console.debug("listenForMsgs()", aSubscriptionUri); if (!this._conns[aSubscriptionUri]) { console.warn("listenForMsgs: We do not have this subscription", @@ -556,15 +535,14 @@ var PushServiceHttp2 = { this._conns[aSubscriptionUri].lastStartListening = Date.now(); this._conns[aSubscriptionUri].channel = conn.channel; this._conns[aSubscriptionUri].listener = conn.listener; - }, - _ackMsgRecv: function(aAckUri) { + _ackMsgRecv(aAckUri) { console.debug("ackMsgRecv()", aAckUri); return this._deleteResource(aAckUri); }, - init: function(aOptions, aMainPushService, aServerURL) { + init(aOptions, aMainPushService, aServerURL) { console.debug("init()"); this._mainPushService = aMainPushService; this._serverURI = aServerURL; @@ -572,7 +550,7 @@ var PushServiceHttp2 = { return Promise.resolve(); }, - _retryAfterBackoff: function(aSubscriptionUri, retryAfter) { + _retryAfterBackoff(aSubscriptionUri, retryAfter) { console.debug("retryAfterBackoff()"); var resetRetryCount = prefs.getIntPref("http2.reset_retry_count_after_ms"); @@ -610,7 +588,7 @@ var PushServiceHttp2 = { }, // Close connections. - _shutdownConnections: function(deleteInfo) { + _shutdownConnections(deleteInfo) { console.debug("shutdownConnections()"); for (let subscriptionUri in this._conns) { @@ -639,7 +617,7 @@ var PushServiceHttp2 = { }, // Start listening if subscriptions present. - startConnections: function(aSubscriptions) { + startConnections(aSubscriptions) { console.debug("startConnections()", aSubscriptions.length); for (let i = 0; i < aSubscriptions.length; i++) { @@ -653,7 +631,7 @@ var PushServiceHttp2 = { } }, - _startSingleConnection: function(record) { + _startSingleConnection(record) { console.debug("_startSingleConnection()"); if (typeof this._conns[record.subscriptionUri] != "object") { this._conns[record.subscriptionUri] = {channel: null, @@ -667,7 +645,7 @@ var PushServiceHttp2 = { }, // Close connection and notify apps that subscription are gone. - _shutdownSubscription: function(aSubscriptionUri) { + _shutdownSubscription(aSubscriptionUri) { console.debug("shutdownSubscriptions()"); if (typeof this._conns[aSubscriptionUri] == "object") { @@ -684,24 +662,24 @@ var PushServiceHttp2 = { } }, - uninit: function() { + uninit() { console.debug("uninit()"); this._abortPendingSubscriptionRetries(); this._shutdownConnections(true); this._mainPushService = null; }, - _abortPendingSubscriptionRetries: function() { + _abortPendingSubscriptionRetries() { this._listenersPendingRetry.forEach((listener) => listener.abortRetry()); this._listenersPendingRetry.clear(); }, - unregister: function(aRecord) { + unregister(aRecord) { this._shutdownSubscription(aRecord.subscriptionUri); return this._unsubscribeResource(aRecord.subscriptionUri); }, - reportDeliveryError: function(messageID, reason) { + reportDeliveryError(messageID, reason) { console.warn("reportDeliveryError: Ignoring message delivery error", messageID, reason); }, @@ -712,7 +690,7 @@ var PushServiceHttp2 = { * - on error delete record and send pushsubscriptionchange * TODO: maybe pushsubscriptionerror will be included. */ - _resubscribe: function(aSubscriptionUri) { + _resubscribe(aSubscriptionUri) { this._mainPushService.getByKeyID(aSubscriptionUri) .then(record => this.register(record) .then(recordNew => { @@ -731,8 +709,7 @@ var PushServiceHttp2 = { ); }, - connOnStop: function(aRequest, aSuccess, - aSubscriptionUri) { + connOnStop(aRequest, aSuccess, aSubscriptionUri) { console.debug("connOnStop() succeeded", aSuccess); var conn = this._conns[aSubscriptionUri]; @@ -748,11 +725,9 @@ var PushServiceHttp2 = { if (!aSuccess) { this._retryAfterBackoff(aSubscriptionUri, -1); - } else if (Math.floor(aRequest.responseStatus / 100) == 5) { var retryAfter = retryAfterParser(aRequest); this._retryAfterBackoff(aSubscriptionUri, retryAfter); - } else if (Math.floor(aRequest.responseStatus / 100) == 4) { this._shutdownSubscription(aSubscriptionUri); this._resubscribe(aSubscriptionUri); @@ -763,17 +738,17 @@ var PushServiceHttp2 = { } }, - addListenerPendingRetry: function(aListener) { + addListenerPendingRetry(aListener) { this._listenersPendingRetry.add(aListener); }, - removeListenerPendingRetry: function(aListener) { + removeListenerPendingRetry(aListener) { if (!this._listenersPendingRetry.remove(aListener)) { console.debug("removeListenerPendingRetry: listener not in list?"); } }, - _pushChannelOnStop: function(aUri, aAckUri, aHeaders, aMessage) { + _pushChannelOnStop(aUri, aAckUri, aHeaders, aMessage) { console.debug("pushChannelOnStop()"); this._mainPushService.receivedPushMessage( diff --git a/dom/push/PushServiceWebSocket.jsm b/dom/push/PushServiceWebSocket.jsm index 9c471e3f6cc1..75424991a0a1 100644 --- a/dom/push/PushServiceWebSocket.jsm +++ b/dom/push/PushServiceWebSocket.jsm @@ -43,7 +43,7 @@ const kDELIVERY_REASON_TO_CODE = { const prefs = new Preferences("dom.push."); -var EXPORTED_SYMBOLS = ["PushServiceWebSocket"]; +const EXPORTED_SYMBOLS = ["PushServiceWebSocket"]; XPCOMUtils.defineLazyGetter(this, "console", () => { let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm"); @@ -66,41 +66,41 @@ var PushWebSocketListener = function(pushService) { }; PushWebSocketListener.prototype = { - onStart: function(context) { + onStart(context) { if (!this._pushService) { return; } this._pushService._wsOnStart(context); }, - onStop: function(context, statusCode) { + onStop(context, statusCode) { if (!this._pushService) { return; } this._pushService._wsOnStop(context, statusCode); }, - onAcknowledge: function(context, size) { + onAcknowledge(context, size) { // EMPTY }, - onBinaryMessageAvailable: function(context, message) { + onBinaryMessageAvailable(context, message) { // EMPTY }, - onMessageAvailable: function(context, message) { + onMessageAvailable(context, message) { if (!this._pushService) { return; } this._pushService._wsOnMessageAvailable(context, message); }, - onServerClose: function(context, aStatusCode, aReason) { + onServerClose(context, aStatusCode, aReason) { if (!this._pushService) { return; } this._pushService._wsOnServerClose(context, aStatusCode, aReason); - } + }, }; // websocket states @@ -118,7 +118,7 @@ var PushServiceWebSocket = { _mainPushService: null, _serverURI: null, - newPushDB: function() { + newPushDB() { return new PushDB(kPUSHWSDB_DB_NAME, kPUSHWSDB_DB_VERSION, kPUSHWSDB_STORE_NAME, @@ -126,11 +126,11 @@ var PushServiceWebSocket = { PushRecordWebSocket); }, - disconnect: function() { + disconnect() { this._shutdownWS(); }, - observe: function(aSubject, aTopic, aData) { + observe(aSubject, aTopic, aData) { if (aTopic == "nsPref:changed" && aData == "dom.push.userAgentID") { this._onUAIDChanged(); } else if (aTopic == "timer-callback") { @@ -167,7 +167,6 @@ var PushServiceWebSocket = { if (timer == this._requestTimeoutTimer) { this._timeOutRequests(); - return; } }, @@ -208,10 +207,8 @@ var PushServiceWebSocket = { if (this._lastPingTime > 0 && now - this._lastPingTime > this._requestTimeout) { - console.debug("timeOutRequests: Did not receive pong in time"); requestTimedOut = true; - } else { for (let [key, request] of this._pendingRequests) { let duration = now - request.ctime; @@ -233,7 +230,7 @@ var PushServiceWebSocket = { } }, - validServerURI: function(serverURI) { + validServerURI(serverURI) { if (serverURI.scheme == "ws") { return !!prefs.get("testing.allowInsecureServerURL"); } @@ -296,7 +293,7 @@ var PushServiceWebSocket = { * Sends a message to the Push Server through an open websocket. * typeof(msg) shall be an object */ - _wsSendMessage: function(msg) { + _wsSendMessage(msg) { if (!this._ws) { console.warn("wsSendMessage: No WebSocket initialized.", "Cannot send a message"); @@ -307,7 +304,7 @@ var PushServiceWebSocket = { this._ws.sendMsg(msg); }, - init: function(options, mainPushService, serverURI) { + init(options, mainPushService, serverURI) { console.debug("init()"); this._mainPushService = mainPushService; @@ -327,13 +324,13 @@ var PushServiceWebSocket = { return Promise.resolve(); }, - _reconnect: function () { + _reconnect() { console.debug("reconnect()"); this._shutdownWS(false); this._startBackoffTimer(); }, - _shutdownWS: function(shouldCancelPending = true) { + _shutdownWS(shouldCancelPending = true) { console.debug("shutdownWS()"); if (this._currentState == STATE_READY) { @@ -367,7 +364,7 @@ var PushServiceWebSocket = { } }, - uninit: function() { + uninit() { // All pending requests (ideally none) are dropped at this point. We // shouldn't have any applications performing registration/unregistration // or receiving notifications. @@ -449,7 +446,7 @@ var PushServiceWebSocket = { Ci.nsITimer.TYPE_ONE_SHOT); }, - _makeWebSocket: function(uri) { + _makeWebSocket(uri) { if (!prefs.get("connection.enabled")) { console.warn("makeWebSocket: connection.enabled is not set to true.", "Aborting."); @@ -473,7 +470,7 @@ var PushServiceWebSocket = { return socket; }, - _beginWSSetup: function() { + _beginWSSetup() { console.debug("beginWSSetup()"); if (this._currentState != STATE_SHUT_DOWN) { console.error("_beginWSSetup: Not in shutdown state! Current state", @@ -505,27 +502,27 @@ var PushServiceWebSocket = { // sleep before connection the is opened. this._ws.asyncOpen(uri, uri.spec, 0, this._wsListener, null); this._currentState = STATE_WAITING_FOR_WS_START; - } catch(e) { + } catch (e) { console.error("beginWSSetup: Error opening websocket.", "asyncOpen failed", e); this._reconnect(); } }, - connect: function(broadcastListeners) { + connect(broadcastListeners) { console.debug("connect()", broadcastListeners); this._broadcastListeners = broadcastListeners; this._beginWSSetup(); }, - isConnected: function() { + isConnected() { return !!this._ws; }, /** * Protocol handler invoked by server message. */ - _handleHelloReply: function(reply) { + _handleHelloReply(reply) { console.debug("handleHelloReply()"); if (this._currentState != STATE_WAITING_FOR_HELLO) { console.error("handleHelloReply: Unexpected state", this._currentState, @@ -611,7 +608,7 @@ var PushServiceWebSocket = { /** * Protocol handler invoked by server message. */ - _handleRegisterReply: function(reply) { + _handleRegisterReply(reply) { console.debug("handleRegisterReply()"); let tmp = this._takeRequestForReply(reply); @@ -622,8 +619,7 @@ var PushServiceWebSocket = { if (reply.status == 200) { try { Services.io.newURI(reply.pushEndpoint); - } - catch (e) { + } catch (e) { tmp.reject(new Error("Invalid push endpoint: " + reply.pushEndpoint)); return; } @@ -658,7 +654,7 @@ var PushServiceWebSocket = { request.resolve(success); }, - _handleDataUpdate: function(update) { + _handleDataUpdate(update) { let promise; if (typeof update.channelID != "string") { console.warn("handleDataUpdate: Discarding update without channel ID", @@ -714,14 +710,14 @@ var PushServiceWebSocket = { /** * Protocol handler invoked by server message. */ - _handleNotificationReply: function(reply) { + _handleNotificationReply(reply) { console.debug("handleNotificationReply()"); if (this._dataEnabled) { this._handleDataUpdate(reply); return; } - if (typeof reply.updates !== 'object') { + if (typeof reply.updates !== "object") { console.warn("handleNotificationReply: Missing updates", reply.updates); return; } @@ -755,7 +751,7 @@ var PushServiceWebSocket = { } }, - _handleBroadcastReply: function(reply) { + _handleBroadcastReply(reply) { this._mainPushService.receivedBroadcastMessage(reply); }, @@ -763,11 +759,11 @@ var PushServiceWebSocket = { console.debug("reportDeliveryError()"); let code = kDELIVERY_REASON_TO_CODE[reason]; if (!code) { - throw new Error('Invalid delivery error reason'); + throw new Error("Invalid delivery error reason"); } - let data = {messageType: 'nack', + let data = {messageType: "nack", version: messageID, - code: code}; + code}; this._queueRequest(data); }, @@ -775,16 +771,16 @@ var PushServiceWebSocket = { console.debug("sendAck()"); let code = kACK_STATUS_TO_CODE[status]; if (!code) { - throw new Error('Invalid ack status'); + throw new Error("Invalid ack status"); } - let data = {messageType: 'ack', - updates: [{channelID: channelID, - version: version, - code: code}]}; + let data = {messageType: "ack", + updates: [{channelID, + version, + code}]}; this._queueRequest(data); }, - _generateID: function() { + _generateID() { let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"] .getService(Ci.nsIUUIDGenerator); // generateUUID() gives a UUID surrounded by {...}, slice them off. @@ -824,11 +820,11 @@ var PushServiceWebSocket = { return Promise.resolve().then(_ => { let code = kUNREGISTER_REASON_TO_CODE[reason]; if (!code) { - throw new Error('Invalid unregister reason'); + throw new Error("Invalid unregister reason"); } let data = {channelID: record.channelID, messageType: "unregister", - code: code}; + code}; return this._sendRequestForReply(record, data); }); @@ -837,7 +833,7 @@ var PushServiceWebSocket = { _queueStart: Promise.resolve(), _notifyRequestQueue: null, _queue: null, - _enqueue: function(op) { + _enqueue(op) { console.debug("enqueue()"); if (!this._queue) { this._queue = this._queueStart; @@ -923,7 +919,7 @@ var PushServiceWebSocket = { } }, - _receivedUpdate: function(aChannelID, aLatestVersion) { + _receivedUpdate(aChannelID, aLatestVersion) { console.debug("receivedUpdate: Updating", aChannelID, "->", aLatestVersion); this._mainPushService.receivedPushMessage(aChannelID, "", null, null, record => { @@ -946,7 +942,7 @@ var PushServiceWebSocket = { }, // begin Push protocol handshake - _wsOnStart: function(context) { + _wsOnStart(context) { console.debug("wsOnStart()"); if (this._currentState != STATE_WAITING_FOR_WS_START) { @@ -976,7 +972,7 @@ var PushServiceWebSocket = { * If we do not explicitly call ws.close() then statusCode is always * NS_BASE_STREAM_CLOSED, even on a successful close. */ - _wsOnStop: function(context, statusCode) { + _wsOnStop(context, statusCode) { console.debug("wsOnStop()"); if (statusCode != Cr.NS_OK && !this._skipReconnect) { @@ -988,7 +984,7 @@ var PushServiceWebSocket = { this._shutdownWS(); }, - _wsOnMessageAvailable: function(context, message) { + _wsOnMessageAvailable(context, message) { console.debug("wsOnMessageAvailable()", message); // Clearing the last ping time indicates we're no longer waiting for a pong. @@ -997,7 +993,7 @@ var PushServiceWebSocket = { let reply; try { reply = JSON.parse(message); - } catch(e) { + } catch (e) { console.warn("wsOnMessageAvailable: Invalid JSON", message, e); return; } @@ -1007,7 +1003,7 @@ var PushServiceWebSocket = { this._retryFailCount = 0; let doNotHandle = false; - if ((message === '{}') || + if ((message === "{}") || (reply.messageType === undefined) || (reply.messageType === "ping") || (typeof reply.messageType != "string")) { @@ -1060,7 +1056,7 @@ var PushServiceWebSocket = { * next network state change event, or until we need to send a new register * request. */ - _wsOnServerClose: function(context, aStatusCode, aReason) { + _wsOnServerClose(context, aStatusCode, aReason) { console.debug("wsOnServerClose()", aStatusCode, aReason); if (aStatusCode == kBACKOFF_WS_STATUS_CODE) { @@ -1093,8 +1089,8 @@ var PushServiceWebSocket = { let key = this._makePendingRequestKey(data); if (!this._pendingRequests.has(key)) { let request = { - data: data, - record: record, + data, + record, ctime: Date.now(), }; request.promise = new Promise((resolve, reject) => { @@ -1130,7 +1126,7 @@ var PushServiceWebSocket = { let data = { messageType: "broadcast_subscribe", broadcasts: { - [serviceId]: version + [serviceId]: version, }, }; diff --git a/dom/push/test/lifetime_worker.js b/dom/push/test/lifetime_worker.js index 1fc6a46fc89e..172ee991ec40 100644 --- a/dom/push/test/lifetime_worker.js +++ b/dom/push/test/lifetime_worker.js @@ -1,7 +1,7 @@ var state = "from_scope"; var resolvePromiseCallback; -onfetch = function(event) { +self.onfetch = function(event) { if (event.request.url.includes("lifetime_frame.html")) { event.respondWith(new Response("iframe_lifetime")); return; @@ -9,12 +9,12 @@ onfetch = function(event) { var currentState = state; event.waitUntil( - clients.matchAll() - .then(clients => { - clients.forEach(client => { - client.postMessage({type: "fetch", state: currentState}); - }); - }) + self.clients.matchAll() + .then(clients => { + clients.forEach(client => { + client.postMessage({type: "fetch", state: currentState}); + }); + }) ); if (event.request.url.includes("update")) { @@ -33,7 +33,7 @@ onfetch = function(event) { state = "release"; resolvePromise(); } -} +}; function resolvePromise() { if (resolvePromiseCallback === undefined || resolvePromiseCallback == null) { @@ -44,23 +44,23 @@ function resolvePromise() { resolvePromiseCallback = null; } -onmessage = function(event) { +self.onmessage = function(event) { var lastState = state; state = event.data; - if (state === 'wait') { + if (state === "wait") { event.waitUntil(new Promise(function(res, rej) { if (resolvePromiseCallback) { dump("ERROR: service worker was already waiting on a promise.\n"); } resolvePromiseCallback = res; })); - } else if (state === 'release') { + } else if (state === "release") { resolvePromise(); } event.source.postMessage({type: "message", state: lastState}); -} +}; -onpush = function(event) { +self.onpush = function(event) { var pushResolve; event.waitUntil(new Promise(function(resolve) { pushResolve = resolve; @@ -68,12 +68,12 @@ onpush = function(event) { // FIXME(catalinb): push message carry no data. So we assume the only // push message we get is "wait" - clients.matchAll().then(function(client) { + self.clients.matchAll().then(function(client) { if (client.length == 0) { dump("ERROR: no clients to send the response to.\n"); } - client[0].postMessage({type: "push", state: state}); + client[0].postMessage({type: "push", state}); state = "wait"; if (resolvePromiseCallback) { @@ -82,4 +82,4 @@ onpush = function(event) { resolvePromiseCallback = pushResolve; } }); -} +}; diff --git a/dom/push/test/mockpushserviceparent.js b/dom/push/test/mockpushserviceparent.js index 65a2fa143735..279196ed46a7 100644 --- a/dom/push/test/mockpushserviceparent.js +++ b/dom/push/test/mockpushserviceparent.js @@ -1,3 +1,5 @@ +/* eslint-env mozilla/frame-script */ + "use strict"; /** @@ -61,7 +63,7 @@ var pushService = Cc["@mozilla.org/push/Service;1"]. var mockSocket; var serverMsgs = []; -addMessageListener("socket-setup", function () { +addMessageListener("socket-setup", function() { pushService.replaceServiceBackend({ serverURI: "wss://push.example.org/", makeWebSocket(uri) { @@ -71,11 +73,11 @@ addMessageListener("socket-setup", function () { mockSocket.serverSendMsg(msg); } return mockSocket; - } + }, }); }); -addMessageListener("socket-teardown", function (msg) { +addMessageListener("socket-teardown", function(msg) { pushService.restoreServiceBackend().then(_ => { serverMsgs.length = 0; if (mockSocket) { @@ -85,10 +87,10 @@ addMessageListener("socket-teardown", function (msg) { sendAsyncMessage("socket-server-teardown"); }).catch(error => { Cu.reportError(`Error restoring service backend: ${error}`); - }) + }); }); -addMessageListener("socket-server-msg", function (msg) { +addMessageListener("socket-server-msg", function(msg) { if (mockSocket) { mockSocket.serverSendMsg(msg); } else { @@ -105,9 +107,9 @@ var MockService = { let id = this.requestID++; this.resolvers.set(id, { resolve, reject }); sendAsyncMessage("service-request", { - name: name, - id: id, - params: params, + name, + id, + params, }); }); }, @@ -142,8 +144,8 @@ var MockService = { reportDeliveryError(messageId, reason) { sendAsyncMessage("service-delivery-error", { - messageId: messageId, - reason: reason, + messageId, + reason, }); }, @@ -174,6 +176,6 @@ addMessageListener("service-restore", function() { }); }); -addMessageListener("service-response", function (response) { +addMessageListener("service-response", function(response) { MockService.handleResponse(response); }); diff --git a/dom/push/test/test_data.html b/dom/push/test/test_data.html index ff70a8d18693..f06609daa5e3 100644 --- a/dom/push/test/test_data.html +++ b/dom/push/test/test_data.html @@ -25,6 +25,10 @@ http://creativecommons.org/licenses/publicdomain/ diff --git a/dom/push/test/test_subscription_change.html b/dom/push/test/test_subscription_change.html index 012eaf9530c9..7e123f830cd9 100644 --- a/dom/push/test/test_subscription_change.html +++ b/dom/push/test/test_subscription_change.html @@ -24,13 +24,14 @@ http://creativecommons.org/licenses/publicdomain/