Bug 1541888 - Enable ESLinting in dom/push/ r=glasserc,lina

Enable ESLinting in dom/push/

Differential Revision: https://phabricator.services.mozilla.com/D26321

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mathieu Leplatre 2019-04-09 10:05:51 +00:00
Родитель bc581a4d5e
Коммит 1cdc04dfda
89 изменённых файлов: 2531 добавлений и 2607 удалений

Просмотреть файл

@ -183,7 +183,6 @@ dom/payments/**
dom/performance/**
dom/permission/**
dom/promise/**
dom/push/**
dom/quota/**
dom/security/test/cors/**
dom/security/test/csp/**

Просмотреть файл

@ -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"];

Просмотреть файл

@ -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();

Просмотреть файл

@ -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"];

Просмотреть файл

@ -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);

Просмотреть файл

@ -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) =>

Просмотреть файл

@ -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);

Просмотреть файл

@ -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()) {

Просмотреть файл

@ -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);
},

Просмотреть файл

@ -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(

Просмотреть файл

@ -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,
},
};

Просмотреть файл

@ -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;
}
});
}
};

Просмотреть файл

@ -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);
});

Просмотреть файл

@ -25,6 +25,10 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
/* globals webPushEncrypt */
var userAgentID = "ac44402c-85fc-41e4-a0d0-483316d15351";
var channelID = null;
@ -36,7 +40,7 @@ http://creativecommons.org/licenses/publicdomain/
uaid: userAgentID,
channelID,
status: 200,
pushEndpoint: "https://example.com/endpoint/1"
pushEndpoint: "https://example.com/endpoint/1",
}));
};
@ -45,7 +49,7 @@ http://creativecommons.org/licenses/publicdomain/
await setupPrefsAndMockSocket(mockSocket);
await setPushPermission(true);
var url = "worker.js" + "?" + (Math.random());
var url = "worker.js?" + (Math.random());
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});
@ -92,28 +96,28 @@ http://creativecommons.org/licenses/publicdomain/
});
var version = 0;
function sendEncryptedMsg(pushSubscription, message) {
return webPushEncrypt(pushSubscription, message)
function sendEncryptedMsg(pushSub, message) {
return webPushEncrypt(pushSub, message)
.then((encryptedData) => {
mockSocket.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
version: version++,
channelID: channelID,
channelID,
data: encryptedData.data,
headers: {
encryption: encryptedData.encryption,
encryption_key: encryptedData.encryption_key,
encoding: encryptedData.encoding
}
encoding: encryptedData.encoding,
},
}));
});
}
function waitForMessage(pushSubscription, message) {
function waitForMessage(pushSub, message) {
return Promise.all([
controlledFrame.waitOnWorkerMessage("finished"),
sendEncryptedMsg(pushSubscription, message),
]).then(([message]) => message);
sendEncryptedMsg(pushSub, message),
]).then(([msg]) => msg);
}
add_task(async function sendPushMessageFromPage() {
@ -169,11 +173,11 @@ http://creativecommons.org/licenses/publicdomain/
mockSocket.serverSendMsg(JSON.stringify({
messageType: "notification",
version: "vDummy",
channelID: channelID
channelID,
}));
var message = await finishedPromise;
ok(!message.data, "Should exclude data for blank messages");
var msg = await finishedPromise;
ok(!msg.data, "Should exclude data for blank messages");
});
add_task(async function unsubscribe() {

Просмотреть файл

@ -24,6 +24,7 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
var pushNotifier = SpecialPowers.Cc["@mozilla.org/push/Notifier;1"]
.getService(SpecialPowers.Ci.nsIPushNotifier);
@ -35,7 +36,7 @@ http://creativecommons.org/licenses/publicdomain/
await setupPrefsAndReplaceService({
reportDeliveryError(messageId, reason) {
ok(reporters.has(messageId),
'Unexpected error reported for message ' + messageId);
"Unexpected error reported for message " + messageId);
var resolve = reporters.get(messageId);
reporters.delete(messageId);
resolve(reason);
@ -43,7 +44,7 @@ http://creativecommons.org/licenses/publicdomain/
});
await setPushPermission(true);
var url = "error_worker.js" + "?" + (Math.random());
var url = "error_worker.js?" + (Math.random());
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});
@ -78,15 +79,15 @@ http://creativecommons.org/licenses/publicdomain/
add_task(async function reportDecryptionError() {
var message = await new Promise(resolve => {
SpecialPowers.registerConsoleListener(message => {
if (!message.isScriptError && !message.isConsoleEvent) {
SpecialPowers.registerConsoleListener(msg => {
if (!msg.isScriptError && !msg.isConsoleEvent) {
return;
}
const scope = "http://mochi.test:8888/tests/dom/push/test/";
if (message.innerWindowID === "ServiceWorker" &&
message.windowID === scope) {
if (msg.innerWindowID === "ServiceWorker" &&
msg.windowID === scope) {
SpecialPowers.postConsoleSentinel();
resolve(message);
resolve(msg);
}
});

Просмотреть файл

@ -24,15 +24,18 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
function debug(str) {
// console.log(str + "\n");
}
var registration;
add_task(async function start() {
await setupPrefsAndMockSocket(new MockWebSocket());
var url = "worker.js" + "?" + Math.random();
var url = "worker.js?" + Math.random();
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});

Просмотреть файл

@ -23,15 +23,18 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
function debug(str) {
// console.log(str + "\n");
}
var registration;
function start() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
return navigator.serviceWorker.register("worker.js?" + (Math.random()), {scope: "."})
.then((swr) => {
registration = swr
registration = swr;
return waitForActive(registration);
});
}
@ -49,7 +52,7 @@ http://creativecommons.org/licenses/publicdomain/
swr.pushManager.subscribe().then(
function(pushSubscription) {
ok(true, "successful registered for push notification");
res({swr: swr, pushSubscription: pushSubscription});
res({swr, pushSubscription});
}, function(error) {
ok(false, "could not register for push notification");
res(null);

Просмотреть файл

@ -23,6 +23,7 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
var scopeA = "./a/";
var scopeB = "./b/";
@ -32,7 +33,7 @@ http://creativecommons.org/licenses/publicdomain/
}
function registerServiceWorker(scope) {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: scope})
return navigator.serviceWorker.register("worker.js?" + (Math.random()), {scope})
.then(swr => waitForActive(swr));
}
@ -41,7 +42,7 @@ http://creativecommons.org/licenses/publicdomain/
.then(result => {
ok(result, "Unregister should return true.");
}, err => {
ok(false,"Unregistering the SW failed with " + err + "\n");
ok(false, "Unregistering the SW failed with " + err + "\n");
throw err;
});
}
@ -61,7 +62,7 @@ http://creativecommons.org/licenses/publicdomain/
function setupMultipleSubscriptions(swr1, swr2) {
return Promise.all([
subscribe(swr1),
subscribe(swr2)
subscribe(swr2),
]).then(a => {
ok(a[0].endpoint != a[1].endpoint, "setupMultipleSubscriptions - Got different endpoints.");
return a;

Просмотреть файл

@ -25,13 +25,16 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
/* globals setupMockPushSocket,teardownMockPushSocket */
function debug(str) {
// console.log(str + "\n");
}
function registerServiceWorker() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."});
return navigator.serviceWorker.register("worker.js?" + (Math.random()), {scope: "."});
}
function unregister(swr) {
@ -63,7 +66,7 @@ http://creativecommons.org/licenses/publicdomain/
var pushSubscription;
return Promise.all([
subscribe(swr),
subscribe(swr)
subscribe(swr),
]).then(a => {
ok(a[0].endpoint == a[1].endpoint, "setupMultipleSubscriptions - Got the same endpoint back.");
pushSubscription = a[0];

Просмотреть файл

@ -24,6 +24,7 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
function debug(str) {
// console.log(str + "\n");
@ -34,7 +35,7 @@ http://creativecommons.org/licenses/publicdomain/
await setupPrefsAndMockSocket(new MockWebSocket());
await setPushPermission(false);
var url = "worker.js" + "?" + Math.random();
var url = "worker.js?" + Math.random();
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});

Просмотреть файл

@ -24,6 +24,7 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
function debug(str) {
// console.log(str + "\n");
@ -40,7 +41,7 @@ http://creativecommons.org/licenses/publicdomain/
uaid: "c69e2014-9e15-438d-b253-d79cc2df60a8",
channelID,
status: 200,
pushEndpoint: "https://example.com/endpoint/1"
pushEndpoint: "https://example.com/endpoint/1",
}));
};
@ -49,7 +50,7 @@ http://creativecommons.org/licenses/publicdomain/
await setupPrefsAndMockSocket(mockSocket);
await setPushPermission(true);
var url = "worker.js" + "?" + (Math.random());
var url = "worker.js?" + (Math.random());
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});
@ -88,7 +89,7 @@ http://creativecommons.org/licenses/publicdomain/
mockSocket.serverSendMsg(JSON.stringify({
messageType: "notification",
version: "vDummy",
channelID: channelID
channelID,
}));
await finishedPromise;

Просмотреть файл

@ -24,6 +24,7 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
var isTestingMismatchedKey = false;
var subscriptions = 0;
@ -45,10 +46,12 @@ http://creativecommons.org/licenses/publicdomain/
ok(pageRecord.appServerKey.length > 0,
"App server key should not be empty");
if (pageRecord.appServerKey.length != 65) {
// eslint-disable-next-line no-throw-literal
throw { result:
SpecialPowers.Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR };
}
if (isTestingMismatchedKey) {
SpecialPowers.Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR };
}
if (isTestingMismatchedKey) {
// eslint-disable-next-line no-throw-literal
throw { result:
SpecialPowers.Cr.NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR };
}
@ -68,7 +71,7 @@ http://creativecommons.org/licenses/publicdomain/
await setPushPermission(true);
testKey = await generateKey();
var url = "worker.js" + "?" + (Math.random());
var url = "worker.js?" + (Math.random());
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});
@ -171,7 +174,7 @@ http://creativecommons.org/licenses/publicdomain/
var key = await generateKey();
var data = await sendRequestToWorker({
type: "subscribeWithKey",
key: key,
key,
});
is(data.endpoint, "https://example.com/push/2",
"Wrong endpoint for subscription with key created in worker");

Просмотреть файл

@ -36,6 +36,7 @@
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
function start() {
return navigator.serviceWorker.register("lifetime_worker.js", {scope: "./"})
@ -82,7 +83,7 @@
uaid: "fa8f2e4b-5ddc-4408-b1e3-5f25a02abff0",
channelID,
status: 200,
pushEndpoint: endpoint
pushEndpoint: endpoint,
}));
};
@ -91,7 +92,7 @@
mockSocket.serverSendMsg(JSON.stringify({
messageType: "notification",
version: "vDummy",
channelID
channelID,
}));
}
@ -105,7 +106,7 @@
function createIframe(ctx) {
var p = new Promise(function(res, rej) {
var iframe = document.createElement('iframe');
var iframe = document.createElement("iframe");
// This file doesn't exist, the service worker will give us an empty
// document.
iframe.src = "http://mochi.test:8888/tests/dom/push/test/lifetime_frame.html";
@ -113,7 +114,7 @@
iframe.onload = function() {
ctx.iframe = iframe;
res(ctx);
}
};
document.body.appendChild(iframe);
});
return p;
@ -130,9 +131,9 @@
}
function waitAndCheckMessage(contentWindow, expected) {
function checkMessage(expected, resolve, event) {
ok(event.data.type == expected.type, "Received correct message type: " + expected.type);
ok(event.data.state == expected.state, "Service worker is in the correct state: " + expected.state);
function checkMessage({ type, state }, resolve, event) {
ok(event.data.type == type, "Received correct message type: " + type);
ok(event.data.state == state, "Service worker is in the correct state: " + state);
this.navigator.serviceWorker.onmessage = null;
resolve();
}
@ -174,7 +175,7 @@
return function(ctx) {
return eventFunction(ctx, expected_state, new_state)
.then(() => ctx);
}
};
}
let shutdownTopic =
@ -190,21 +191,21 @@
ctx.observer_promise = new Promise(function(res, rej) {
ctx.observer = {
observe: function(subject, topic, data) {
observe(subject, topic, data) {
ok((topic == shutdownTopic) && expectingEvent, "Service worker was terminated.");
this.remove(ctx);
},
remove: function(ctx) {
remove(context) {
SpecialPowers.removeObserver(this, shutdownTopic);
ctx.observer = null;
res(ctx);
}
}
context.observer = null;
res(context);
},
};
SpecialPowers.addObserver(ctx.observer, shutdownTopic);
});
return ctx;
}
};
}
function waitOnShutdownObserver(ctx) {
@ -225,22 +226,22 @@
function run() {
test.steps(ctx).catch(function(e) {
ok(false, "Some test failed with error: " + e);
}).then((ctx) => res(ctx));
}).then(res);
}
SpecialPowers.pushPrefEnv({"set" : test.prefs}, run);
SpecialPowers.pushPrefEnv({"set": test.prefs}, run);
});
}
};
}
var test1 = {
prefs: [
["dom.serviceWorkers.idle_timeout", 0],
["dom.serviceWorkers.idle_extended_timeout", 2999999]
["dom.serviceWorkers.idle_extended_timeout", 2999999],
],
// Test that service workers are terminated after the grace period expires
// when there are no pending waitUntil or respondWith promises.
steps: function(ctx) {
steps(ctx) {
// Test with fetch events and respondWith promises
return createIframe(ctx)
.then(setShutdownObserver(true))
@ -271,16 +272,16 @@
.then(setShutdownObserver(true))
.then(checkStateAndUpdate(messageEventIframe, "update", "release"))
.then(waitOnShutdownObserver)
.then(closeIframe)
}
}
.then(closeIframe);
},
};
var test2 = {
prefs: [
["dom.serviceWorkers.idle_timeout", 0],
["dom.serviceWorkers.idle_extended_timeout", 2999999]
["dom.serviceWorkers.idle_extended_timeout", 2999999],
],
steps: function(ctx) {
steps(ctx) {
// Older versions used to terminate workers when the last controlled
// window was closed. This should no longer happen, though. Verify
// the new behavior.
@ -308,30 +309,30 @@
.then(closeIframe)
.then(setShutdownObserver(true))
.then(checkStateAndUpdate(messageEvent, "wait", "release"))
.then(waitOnShutdownObserver)
}
.then(waitOnShutdownObserver);
},
};
var test3 = {
prefs: [
["dom.serviceWorkers.idle_timeout", 2999999],
["dom.serviceWorkers.idle_extended_timeout", 0]
["dom.serviceWorkers.idle_extended_timeout", 0],
],
steps: function(ctx) {
steps(ctx) {
// set the grace period to 0 and dispatch a message which will reset
// the internal sw timer to the new value.
var test3_1 = {
prefs: [
["dom.serviceWorkers.idle_timeout", 0],
["dom.serviceWorkers.idle_extended_timeout", 0]
["dom.serviceWorkers.idle_extended_timeout", 0],
],
steps: function(ctx) {
return new Promise(function(res, rej) {
ctx.iframe.contentWindow.fetch("update");
res(ctx);
});
}
}
steps(context) {
return new Promise(function(res, rej) {
context.iframe.contentWindow.fetch("update");
res(context);
});
},
};
// Test that service worker is closed when the extended timeout expired
return createIframe(ctx)
@ -342,9 +343,9 @@
.then(setShutdownObserver(true))
.then(subTest(test3_1)) // This should cause the internal timer to expire.
.then(waitOnShutdownObserver)
.then(closeIframe)
}
}
.then(closeIframe);
},
};
function runTest() {
start()
@ -356,12 +357,12 @@
.then(unregisterPushNotification)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e)
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
setupPrefsAndMockSocket(mockSocket).then(_ => runTest());
SpecialPowers.addPermission('desktop-notification', true, document);
SpecialPowers.addPermission("desktop-notification", true, document);
SimpleTest.waitForExplicitFinish();
</script>
</body>

Просмотреть файл

@ -24,13 +24,14 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
var registration;
add_task(async function start() {
await setupPrefsAndMockSocket(new MockWebSocket());
await setPushPermission(true);
var url = "worker.js" + "?" + (Math.random());
var url = "worker.js?" + (Math.random());
registration = await navigator.serviceWorker.register(url, {scope: "."});
await waitForActive(registration);
});
@ -48,7 +49,7 @@ http://creativecommons.org/licenses/publicdomain/
var permissionState = await registration.pushManager.permissionState();
is(permissionState, "denied", "Should deny push permission");
var subscription = await registration.pushManager.getSubscription();
subscription = await registration.pushManager.getSubscription();
is(subscription, null, "Should not return subscription when permission is revoked");
var changePromise = controlledFrame.waitOnWorkerMessage("changed");

Просмотреть файл

@ -23,13 +23,15 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* eslint-env mozilla/frame-script */
/* import-globals-from ./test_utils.js */
function debug(str) {
// console.log(str + "\n");
}
function registerServiceWorker() {
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
return navigator.serviceWorker.register("worker.js?" + (Math.random()), {scope: "."})
.then(swr => waitForActive(swr));
}
@ -59,7 +61,7 @@ http://creativecommons.org/licenses/publicdomain/
swr.pushManager.subscribe()
.then(sub => {
ok(false, "successful registered for push notification");
throw "Should fail";
throw new Error("Should fail");
}, err => {
ok(true, "could not register for push notification");
res(swr);
@ -90,10 +92,11 @@ http://creativecommons.org/licenses/publicdomain/
// Load chrome script to change offline status in the
// parent process.
var chromeScript = SpecialPowers.loadChromeScript(_ => {
var ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var offlineChromeScript = SpecialPowers.loadChromeScript(_ => {
addMessageListener("change-status", function(offline) {
// eslint-disable-next-line mozilla/use-services
const ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
ioService.offline = offline;
});
});
@ -104,24 +107,26 @@ http://creativecommons.org/licenses/publicdomain/
offlineObserver.prototype = {
_res: null,
observe: function(subject, topic, data) {
debug("observe: " + subject + " " + topic + " " + data);
if (topic === "network:offline-status-changed") {
var obsService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
obsService.removeObserver(this, topic);
this._res(null);
}
observe(subject, topic, data) {
debug("observe: " + subject + " " + topic + " " + data);
if (topic === "network:offline-status-changed") {
// eslint-disable-next-line mozilla/use-services
const obsService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
obsService.removeObserver(this, topic);
this._res(null);
}
}
},
};
function changeOfflineState(offline) {
return new Promise(function(res, rej) {
var obsService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
// eslint-disable-next-line mozilla/use-services
const obsService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
obsService.addObserver(SpecialPowers.wrapCallbackObject(new offlineObserver(res)),
"network:offline-status-changed");
chromeScript.sendAsyncMessage("change-status", offline);
"network:offline-status-changed");
offlineChromeScript.sendAsyncMessage("change-status", offline);
});
}
@ -132,7 +137,7 @@ http://creativecommons.org/licenses/publicdomain/
function unsubscribe(sub) {
return sub.unsubscribe()
.then(_ => {ok(true, "Unsubscribed!");});
.then(_ => { ok(true, "Unsubscribed!"); });
}
// go offline then go online
@ -146,14 +151,14 @@ http://creativecommons.org/licenses/publicdomain/
.then(_ => changeOfflineState(false))
.then(_ => subscribe(swr))
.then(sub => getEndpoint(swr, sub)
.then(sub => unsubscribe(sub))
.then(s => unsubscribe(s))
)
.then(_ => getEndpointExpectNull(swr))
.then(_ => unregister(swr))
)
.catch(err => {
ok(false, "Some test failed with error " + err);
})
});
}
// disable - enable push connection.
@ -167,14 +172,14 @@ http://creativecommons.org/licenses/publicdomain/
.then(_ => changePushServerConnectionEnabled(true))
.then(_ => subscribe(swr))
.then(sub => getEndpoint(swr, sub)
.then(sub => unsubscribe(sub))
.then(s => unsubscribe(s))
)
.then(_ => getEndpointExpectNull(swr))
.then(_ => unregister(swr))
)
.catch(err => {
ok(false, "Some test failed with error " + err);
})
});
}
// go offline - disable - enable - go online
@ -194,14 +199,14 @@ http://creativecommons.org/licenses/publicdomain/
.then(_ => changeOfflineState(false))
.then(_ => subscribe(swr))
.then(sub => getEndpoint(swr, sub)
.then(sub => unsubscribe(sub))
.then(s => unsubscribe(s))
)
.then(_ => getEndpointExpectNull(swr))
.then(_ => unregister(swr))
)
.catch(err => {
ok(false, "Some test failed with error " + err);
})
});
}
// disable - offline - online - enable.
@ -221,14 +226,14 @@ http://creativecommons.org/licenses/publicdomain/
.then(_ => changePushServerConnectionEnabled(true))
.then(_ => subscribe(swr))
.then(sub => getEndpoint(swr, sub)
.then(sub => unsubscribe(sub))
.then(s => unsubscribe(s))
)
.then(_ => getEndpointExpectNull(swr))
.then(_ => unregister(swr))
)
.catch(err => {
ok(false, "Some test failed with error " + err);
})
});
}
// go offline - disable - go online - enable
@ -248,14 +253,14 @@ http://creativecommons.org/licenses/publicdomain/
.then(_ => changePushServerConnectionEnabled(true))
.then(_ => subscribe(swr))
.then(sub => getEndpoint(swr, sub)
.then(sub => unsubscribe(sub))
.then(s => unsubscribe(s))
)
.then(_ => getEndpointExpectNull(swr))
.then(_ => unregister(swr))
)
.catch(err => {
ok(false, "Some test failed with error " + err);
})
});
}
// disable - go offline - enable - go online.
@ -275,14 +280,14 @@ http://creativecommons.org/licenses/publicdomain/
.then(_ => changeOfflineState(false))
.then(_ => subscribe(swr))
.then(sub => getEndpoint(swr, sub)
.then(sub => unsubscribe(sub))
.then(s => unsubscribe(s))
)
.then(_ => getEndpointExpectNull(swr))
.then(_ => unregister(swr))
)
.catch(err => {
ok(false, "Some test failed with error " + err);
})
});
}
function runTest() {

Просмотреть файл

@ -24,9 +24,10 @@ http://creativecommons.org/licenses/publicdomain/
</pre>
<script class="testbody" type="text/javascript">
/* import-globals-from ./test_utils.js */
function generateURL() {
return "worker.js" + "?" + (Math.random());
return "worker.js?" + (Math.random());
}
var registration;
@ -65,7 +66,7 @@ http://creativecommons.org/licenses/publicdomain/
registration = await navigator.serviceWorker.register(
generateURL(), {scope: "."});
await waitForActive(registration);
var pushSubscription = await registration.pushManager.getSubscription();
pushSubscription = await registration.pushManager.getSubscription();
ok(!pushSubscription,
"Unregistering a service worker should drop its subscription");
});

Просмотреть файл

@ -1,168 +1,158 @@
(function (g) {
"use strict";
"use strict";
let url = SimpleTest.getTestFileURL("mockpushserviceparent.js");
let chromeScript = SpecialPowers.loadChromeScript(url);
const url = SimpleTest.getTestFileURL("mockpushserviceparent.js");
const chromeScript = SpecialPowers.loadChromeScript(url);
/**
* Replaces `PushService.jsm` with a mock implementation that handles requests
* from the DOM API. This allows tests to simulate local errors and error
* reporting, bypassing the `PushService.jsm` machinery.
*/
async function replacePushService(mockService) {
chromeScript.addMessageListener("service-delivery-error", function(msg) {
mockService.reportDeliveryError(msg.messageId, msg.reason);
});
chromeScript.addMessageListener("service-request", function(msg) {
let promise;
try {
let handler = mockService[msg.name];
promise = Promise.resolve(handler(msg.params));
} catch (error) {
promise = Promise.reject(error);
}
promise.then(result => {
chromeScript.sendAsyncMessage("service-response", {
id: msg.id,
result: result,
});
}, error => {
chromeScript.sendAsyncMessage("service-response", {
id: msg.id,
error: error,
});
});
});
await new Promise(resolve => {
chromeScript.addMessageListener("service-replaced", function onReplaced() {
chromeScript.removeMessageListener("service-replaced", onReplaced);
resolve();
});
chromeScript.sendAsyncMessage("service-replace");
});
}
async function restorePushService() {
await new Promise(resolve => {
chromeScript.addMessageListener("service-restored", function onRestored() {
chromeScript.removeMessageListener("service-restored", onRestored);
resolve();
});
chromeScript.sendAsyncMessage("service-restore");
});
}
let userAgentID = "8e1c93a9-139b-419c-b200-e715bb1e8ce8";
let currentMockSocket = null;
/**
* Sets up a mock connection for the WebSocket backend. This only replaces
* the transport layer; `PushService.jsm` still handles DOM API requests,
* observes permission changes, writes to IndexedDB, and notifies service
* workers of incoming push messages.
*/
function setupMockPushSocket(mockWebSocket) {
currentMockSocket = mockWebSocket;
currentMockSocket._isActive = true;
chromeScript.sendSyncMessage("socket-setup");
chromeScript.addMessageListener("socket-client-msg", function(msg) {
mockWebSocket.handleMessage(msg);
});
}
function teardownMockPushSocket() {
if (currentMockSocket) {
return new Promise(resolve => {
currentMockSocket._isActive = false;
chromeScript.addMessageListener("socket-server-teardown", resolve);
chromeScript.sendSyncMessage("socket-teardown");
});
/**
* Replaces `PushService.jsm` with a mock implementation that handles requests
* from the DOM API. This allows tests to simulate local errors and error
* reporting, bypassing the `PushService.jsm` machinery.
*/
async function replacePushService(mockService) {
chromeScript.addMessageListener("service-delivery-error", function(msg) {
mockService.reportDeliveryError(msg.messageId, msg.reason);
});
chromeScript.addMessageListener("service-request", function(msg) {
let promise;
try {
let handler = mockService[msg.name];
promise = Promise.resolve(handler(msg.params));
} catch (error) {
promise = Promise.reject(error);
}
return Promise.resolve();
promise.then(result => {
chromeScript.sendAsyncMessage("service-response", {
id: msg.id,
result,
});
}, error => {
chromeScript.sendAsyncMessage("service-response", {
id: msg.id,
error,
});
});
});
await new Promise(resolve => {
chromeScript.addMessageListener("service-replaced", function onReplaced() {
chromeScript.removeMessageListener("service-replaced", onReplaced);
resolve();
});
chromeScript.sendAsyncMessage("service-replace");
});
}
async function restorePushService() {
await new Promise(resolve => {
chromeScript.addMessageListener("service-restored", function onRestored() {
chromeScript.removeMessageListener("service-restored", onRestored);
resolve();
});
chromeScript.sendAsyncMessage("service-restore");
});
}
let currentMockSocket = null;
/**
* Sets up a mock connection for the WebSocket backend. This only replaces
* the transport layer; `PushService.jsm` still handles DOM API requests,
* observes permission changes, writes to IndexedDB, and notifies service
* workers of incoming push messages.
*/
function setupMockPushSocket(mockWebSocket) {
currentMockSocket = mockWebSocket;
currentMockSocket._isActive = true;
chromeScript.sendSyncMessage("socket-setup");
chromeScript.addMessageListener("socket-client-msg", function(msg) {
mockWebSocket.handleMessage(msg);
});
}
function teardownMockPushSocket() {
if (currentMockSocket) {
return new Promise(resolve => {
currentMockSocket._isActive = false;
chromeScript.addMessageListener("socket-server-teardown", resolve);
chromeScript.sendSyncMessage("socket-teardown");
});
}
return Promise.resolve();
}
/**
* Minimal implementation of web sockets for use in testing. Forwards
* messages to a mock web socket in the parent process that is used
* by the push service.
*/
function MockWebSocket() {}
let registerCount = 0;
/**
* Minimal implementation of web sockets for use in testing. Forwards
* messages to a mock web socket in the parent process that is used
* by the push service.
*/
class MockWebSocket {
// Default implementation to make the push server work minimally.
// Override methods to implement custom functionality.
MockWebSocket.prototype = {
constructor() {
this.userAgentID = "8e1c93a9-139b-419c-b200-e715bb1e8ce8";
this.registerCount = 0;
// We only allow one active mock web socket to talk to the parent.
// This flag is used to keep track of which mock web socket is active.
_isActive: false,
this._isActive = false;
}
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: "hello",
uaid: userAgentID,
status: 200,
use_webpush: true,
}));
},
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: "hello",
uaid: this.userAgentID,
status: 200,
use_webpush: true,
}));
}
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: "register",
uaid: userAgentID,
channelID: request.channelID,
status: 200,
pushEndpoint: "https://example.com/endpoint/" + registerCount++
}));
},
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: "register",
uaid: this.userAgentID,
channelID: request.channelID,
status: 200,
pushEndpoint: "https://example.com/endpoint/" + this.registerCount++,
}));
}
onUnregister(request) {
this.serverSendMsg(JSON.stringify({
messageType: "unregister",
channelID: request.channelID,
status: 200,
}));
},
onUnregister(request) {
this.serverSendMsg(JSON.stringify({
messageType: "unregister",
channelID: request.channelID,
status: 200,
}));
}
onAck(request) {
// Do nothing.
},
onAck(request) {
// Do nothing.
}
handleMessage(msg) {
let request = JSON.parse(msg);
let messageType = request.messageType;
switch (messageType) {
case "hello":
this.onHello(request);
break;
case "register":
this.onRegister(request);
break;
case "unregister":
this.onUnregister(request);
break;
case "ack":
this.onAck(request);
break;
default:
throw new Error("Unexpected message: " + messageType);
}
},
handleMessage(msg) {
let request = JSON.parse(msg);
let messageType = request.messageType;
switch (messageType) {
case "hello":
this.onHello(request);
break;
case "register":
this.onRegister(request);
break;
case "unregister":
this.onUnregister(request);
break;
case "ack":
this.onAck(request);
break;
default:
throw new Error("Unexpected message: " + messageType);
}
}
serverSendMsg(msg) {
if (this._isActive) {
chromeScript.sendAsyncMessage("socket-server-msg", msg);
}
},
};
g.MockWebSocket = MockWebSocket;
g.setupMockPushSocket = setupMockPushSocket;
g.teardownMockPushSocket = teardownMockPushSocket;
g.replacePushService = replacePushService;
g.restorePushService = restorePushService;
}(this));
serverSendMsg(msg) {
if (this._isActive) {
chromeScript.sendAsyncMessage("socket-server-msg", msg);
}
}
}
// Remove permissions and prefs when the test finishes.
SimpleTest.registerCleanupFunction(async function() {
@ -187,7 +177,7 @@ function setupPrefs() {
["dom.push.maxRecentMessageIDsPerSubscription", 0],
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
["dom.serviceWorkers.testing.enabled", true],
]});
}
@ -241,13 +231,13 @@ function sendRequestToWorker(request) {
function waitForActive(swr) {
let sw = swr.installing || swr.waiting || swr.active;
return new Promise(resolve => {
if (sw.state === 'activated') {
if (sw.state === "activated") {
resolve(swr);
return;
}
sw.addEventListener('statechange', function onStateChange(evt) {
if (sw.state === 'activated') {
sw.removeEventListener('statechange', onStateChange);
sw.addEventListener("statechange", function onStateChange(evt) {
if (sw.state === "activated") {
sw.removeEventListener("statechange", onStateChange);
resolve(swr);
}
});
@ -255,7 +245,7 @@ function waitForActive(swr) {
}
function base64UrlDecode(s) {
s = s.replace(/-/g, '+').replace(/_/g, '/');
s = s.replace(/-/g, "+").replace(/_/g, "/");
// Replace padding if it was stripped by the sender.
// See http://tools.ietf.org/html/rfc4648#section-4
@ -263,13 +253,13 @@ function base64UrlDecode(s) {
case 0:
break; // No pad chars in this case
case 2:
s += '==';
s += "==";
break; // Two pad chars
case 3:
s += '=';
s += "=";
break; // One pad char
default:
throw new Error('Illegal base64url string!');
throw new Error("Illegal base64url string!");
}
// With correct padding restored, apply the standard base64 decoder

Просмотреть файл

@ -12,23 +12,23 @@
* use PushCrypto directly is easier said than done.)
*/
(function (g) {
'use strict';
(function(g) {
"use strict";
var P256DH = {
name: 'ECDH',
namedCurve: 'P-256'
name: "ECDH",
namedCurve: "P-256",
};
var webCrypto = g.crypto.subtle;
var ENCRYPT_INFO = new TextEncoder('utf-8').encode("Content-Encoding: aesgcm128");
var NONCE_INFO = new TextEncoder('utf-8').encode("Content-Encoding: nonce");
var ENCRYPT_INFO = new TextEncoder("utf-8").encode("Content-Encoding: aesgcm128");
var NONCE_INFO = new TextEncoder("utf-8").encode("Content-Encoding: nonce");
function chunkArray(array, size) {
var start = array.byteOffset || 0;
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;
}
@ -42,21 +42,21 @@
* Note: these are not efficient, merely expedient.
*/
var base64url = {
_strmap: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
encode: function(data) {
_strmap: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
encode(data) {
data = new Uint8Array(data);
var len = Math.ceil(data.length * 4 / 3);
return chunkArray(data, 3).map(chunk => [
chunk[0] >>> 2,
((chunk[0] & 0x3) << 4) | (chunk[1] >>> 4),
((chunk[1] & 0xf) << 2) | (chunk[2] >>> 6),
chunk[2] & 0x3f
].map(v => base64url._strmap[v]).join('')).join('').slice(0, len);
chunk[2] & 0x3f,
].map(v => base64url._strmap[v]).join("")).join("").slice(0, len);
},
_lookup: function(s, i) {
_lookup(s, i) {
return base64url._strmap.indexOf(s.charAt(i));
},
decode: function(str) {
decode(str) {
var v = new Uint8Array(Math.floor(str.length * 3 / 4));
var vi = 0;
for (var si = 0; si < str.length;) {
@ -69,15 +69,15 @@
v[vi++] = y << 6 | z;
}
return v;
}
},
};
g.base64url = base64url;
/* Coerces data into a Uint8Array */
function ensureView(data) {
if (typeof data === 'string') {
return new TextEncoder('utf-8').encode(data);
if (typeof data === "string") {
return new TextEncoder("utf-8").encode(data);
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
@ -85,7 +85,7 @@
if (ArrayBuffer.isView(data)) {
return new Uint8Array(data.buffer);
}
throw new Error('webpush() needs a string or BufferSource');
throw new Error("webpush() needs a string or BufferSource");
}
function bsConcat(arrays) {
@ -99,11 +99,11 @@
}
function hmac(key) {
this.keyPromise = webCrypto.importKey('raw', key, { name: 'HMAC', hash: 'SHA-256' },
false, ['sign']);
this.keyPromise = webCrypto.importKey("raw", key, { name: "HMAC", hash: "SHA-256" },
false, ["sign"]);
}
hmac.prototype.hash = function(input) {
return this.keyPromise.then(k => webCrypto.sign('HMAC', k, input));
return this.keyPromise.then(k => webCrypto.sign("HMAC", k, input));
};
function hkdf(salt, ikm) {
@ -117,7 +117,7 @@
.then(prkh => prkh.hash(input))
.then(h => {
if (h.byteLength < len) {
throw new Error('Length is too long');
throw new Error("Length is too long");
}
return h.slice(0, len);
});
@ -133,7 +133,7 @@
}
function encrypt(localKey, remoteShare, salt, data) {
return webCrypto.importKey('raw', remoteShare, P256DH, false, ['deriveBits'])
return webCrypto.importKey("raw", remoteShare, P256DH, false, ["deriveBits"])
.then(remoteKey =>
webCrypto.deriveBits({ name: P256DH.name, public: remoteKey },
localKey, 256))
@ -142,24 +142,24 @@
return Promise.all([
kdf.generate(ENCRYPT_INFO, 16)
.then(gcmBits =>
webCrypto.importKey('raw', gcmBits, 'AES-GCM', false, ['encrypt'])),
kdf.generate(NONCE_INFO, 12)
webCrypto.importKey("raw", gcmBits, "AES-GCM", false, ["encrypt"])),
kdf.generate(NONCE_INFO, 12),
]);
})
.then(([key, nonce]) => {
if (data.byteLength === 0) {
// Send an authentication tag for empty messages.
return webCrypto.encrypt({
name: 'AES-GCM',
iv: generateNonce(nonce, 0)
name: "AES-GCM",
iv: generateNonce(nonce, 0),
}, key, new Uint8Array([0])).then(value => [value]);
}
// 4096 is the default size, though we burn 1 for padding
return Promise.all(chunkArray(data, 4095).map((slice, index) => {
var padded = bsConcat([new Uint8Array([0]), slice]);
return webCrypto.encrypt({
name: 'AES-GCM',
iv: generateNonce(nonce, index)
name: "AES-GCM",
iv: generateNonce(nonce, index),
}, key, padded);
}));
}).then(bsConcat);
@ -169,19 +169,19 @@
data = ensureView(data);
var salt = g.crypto.getRandomValues(new Uint8Array(16));
return webCrypto.generateKey(P256DH, false, ['deriveBits'])
return webCrypto.generateKey(P256DH, false, ["deriveBits"])
.then(localKey => {
return Promise.all([
encrypt(localKey.privateKey, subscription.getKey("p256dh"), salt, data),
// 1337 p-256 specific haxx to get the raw value out of the spki value
webCrypto.exportKey('raw', localKey.publicKey),
webCrypto.exportKey("raw", localKey.publicKey),
]);
}).then(([payload, pubkey]) => {
return {
data: base64url.encode(payload),
encryption: 'keyid=p256dh;salt=' + base64url.encode(salt),
encryption_key: 'keyid=p256dh;dh=' + base64url.encode(pubkey),
encoding: 'aesgcm128'
encryption: "keyid=p256dh;salt=" + base64url.encode(salt),
encryption_key: "keyid=p256dh;dh=" + base64url.encode(pubkey),
encoding: "aesgcm128",
};
});
}

Просмотреть файл

@ -8,6 +8,8 @@
// and `test_data.html`, and verifies that `PushManager` can be used from
// the worker.
/* globals PushEvent */
this.onpush = handlePush;
this.onmessage = handleMessage;
this.onpushsubscriptionchange = handlePushSubscriptionChange;
@ -51,7 +53,7 @@ function reply(event, promise) {
function handlePush(event) {
if (event instanceof PushEvent) {
if (!('data' in event)) {
if (!("data" in event)) {
broadcast(event, {type: "finished", okay: "yes"});
return;
}

Просмотреть файл

@ -24,6 +24,6 @@ PushServiceHandler.prototype = {
observe(subject, topic, data) {
this.observed.push({ subject, topic, data });
},
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PushServiceHandler]);

Просмотреть файл

@ -12,5 +12,5 @@ var broadcastHandler = {
this.notifications.push(Array.from(arguments));
};
});
}
},
};

Просмотреть файл

@ -1,32 +1,30 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
var {XPCOMUtils} = ChromeUtils.import('resource://gre/modules/XPCOMUtils.jsm');
var {Services} = ChromeUtils.import('resource://gre/modules/Services.jsm');
var {clearInterval, clearTimeout, setInterval, setIntervalWithTarget, setTimeout, setTimeoutWithTarget} = ChromeUtils.import('resource://gre/modules/Timer.jsm');
var {Preferences} = ChromeUtils.import('resource://gre/modules/Preferences.jsm');
var {PlacesUtils} = ChromeUtils.import('resource://gre/modules/PlacesUtils.jsm');
var {ObjectUtils} = ChromeUtils.import('resource://gre/modules/ObjectUtils.jsm');
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var {clearInterval, clearTimeout, setInterval, setIntervalWithTarget, setTimeout, setTimeoutWithTarget} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
var {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
var {PlacesUtils} = ChromeUtils.import("resource://gre/modules/PlacesUtils.jsm");
var {ObjectUtils} = ChromeUtils.import("resource://gre/modules/ObjectUtils.jsm");
ChromeUtils.defineModuleGetter(this, 'PlacesTestUtils',
'resource://testing-common/PlacesTestUtils.jsm');
ChromeUtils.defineModuleGetter(this, 'pushBroadcastService',
'resource://gre/modules/PushBroadcastService.jsm', {});
XPCOMUtils.defineLazyServiceGetter(this, 'PushServiceComponent',
'@mozilla.org/push/Service;1', 'nsIPushService');
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm");
ChromeUtils.defineModuleGetter(this, "pushBroadcastService",
"resource://gre/modules/PushBroadcastService.jsm", {});
XPCOMUtils.defineLazyServiceGetter(this, "PushServiceComponent",
"@mozilla.org/push/Service;1", "nsIPushService");
const serviceExports = ChromeUtils.import("resource://gre/modules/PushService.jsm", null);
const servicePrefs = new Preferences('dom.push.');
const servicePrefs = new Preferences("dom.push.");
const WEBSOCKET_CLOSE_GOING_AWAY = 1001;
const MS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
var isParent = Cc['@mozilla.org/xre/runtime;1']
.getService(Ci.nsIXULRuntime).processType ==
Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
var isParent = Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
// Stop and clean up after the PushService.
Services.obs.addObserver(function observe(subject, topic, data) {
@ -46,7 +44,7 @@ Services.obs.addObserver(function observe(subject, topic, data) {
Cu.reportError(e);
}
}
}, 'profile-change-net-teardown');
}, "profile-change-net-teardown");
/**
* Gates a function so that it is called only after the wrapper is called a
@ -59,7 +57,7 @@ Services.obs.addObserver(function observe(subject, topic, data) {
function after(times, func) {
return function afterFunc() {
if (--times <= 0) {
return func.apply(this, arguments);
func.apply(this, arguments);
}
};
}
@ -85,12 +83,12 @@ function waterfall(...callbacks) {
*/
function promiseObserverNotification(topic, matchFunc) {
return new Promise((resolve, reject) => {
Services.obs.addObserver(function observe(subject, topic, data) {
let matches = typeof matchFunc != 'function' || matchFunc(subject, data);
Services.obs.addObserver(function observe(subject, aTopic, data) {
let matches = typeof matchFunc != "function" || matchFunc(subject, data);
if (!matches) {
return;
}
Services.obs.removeObserver(observe, topic);
Services.obs.removeObserver(observe, aTopic);
resolve({subject, data});
}, topic);
});
@ -108,22 +106,22 @@ function promiseObserverNotification(topic, matchFunc) {
*/
function makeStub(target, stubs) {
return new Proxy(target, {
get(target, property) {
if (!stubs || typeof stubs != 'object' || !(property in stubs)) {
return target[property];
get(aTarget, property) {
if (!stubs || typeof stubs != "object" || !(property in stubs)) {
return aTarget[property];
}
let stub = stubs[property];
if (typeof stub != 'function') {
if (typeof stub != "function") {
return stub;
}
let original = target[property];
if (typeof original != 'function') {
let original = aTarget[property];
if (typeof original != "function") {
return stub.call(this, original);
}
return function callStub(...params) {
return stub.call(this, original, ...params);
};
}
},
});
}
@ -135,22 +133,22 @@ function makeStub(target, stubs) {
*/
function setPrefs(prefs = {}) {
let defaultPrefs = Object.assign({
loglevel: 'all',
serverURL: 'wss://push.example.org',
'connection.enabled': true,
userAgentID: '',
loglevel: "all",
serverURL: "wss://push.example.org",
"connection.enabled": true,
userAgentID: "",
enabled: true,
// Defaults taken from /modules/libpref/init/all.js.
requestTimeout: 10000,
retryBaseInterval: 5000,
pingInterval: 30 * 60 * 1000,
// Misc. defaults.
'http2.maxRetries': 2,
'http2.retryInterval': 500,
'http2.reset_retry_count_after_ms': 60000,
"http2.maxRetries": 2,
"http2.retryInterval": 500,
"http2.reset_retry_count_after_ms": 60000,
maxQuotaPerSubscription: 16,
quotaUpdateDelay: 3000,
'testing.notifyWorkers': false,
"testing.notifyWorkers": false,
}, prefs);
for (let pref in defaultPrefs) {
servicePrefs.set(pref, defaultPrefs[pref]);
@ -158,7 +156,10 @@ function setPrefs(prefs = {}) {
}
function compareAscending(a, b) {
return a > b ? 1 : a < b ? -1 : 0;
if (a > b) {
return 1;
}
return a < b ? -1 : 0;
}
/**
@ -215,60 +216,60 @@ MockWebSocket.prototype = {
_handleMessage(msg) {
let messageType, request;
if (msg == '{}') {
if (msg == "{}") {
request = {};
messageType = 'ping';
messageType = "ping";
} else {
request = JSON.parse(msg);
messageType = request.messageType;
}
switch (messageType) {
case 'hello':
if (typeof this._onHello != 'function') {
throw new Error('Unexpected handshake request');
case "hello":
if (typeof this._onHello != "function") {
throw new Error("Unexpected handshake request");
}
this._onHello(request);
break;
case 'register':
if (typeof this._onRegister != 'function') {
throw new Error('Unexpected register request');
case "register":
if (typeof this._onRegister != "function") {
throw new Error("Unexpected register request");
}
this._onRegister(request);
break;
case 'unregister':
if (typeof this._onUnregister != 'function') {
throw new Error('Unexpected unregister request');
case "unregister":
if (typeof this._onUnregister != "function") {
throw new Error("Unexpected unregister request");
}
this._onUnregister(request);
break;
case 'ack':
if (typeof this._onACK != 'function') {
throw new Error('Unexpected acknowledgement');
case "ack":
if (typeof this._onACK != "function") {
throw new Error("Unexpected acknowledgement");
}
this._onACK(request);
break;
case 'ping':
if (typeof this._onPing == 'function') {
case "ping":
if (typeof this._onPing == "function") {
this._onPing(request);
} else {
// Echo ping packets.
this.serverSendMsg('{}');
this.serverSendMsg("{}");
}
break;
case 'broadcast_subscribe':
if (typeof this._onBroadcastSubscribe != 'function') {
throw new Error('Unexpected broadcast_subscribe');
case "broadcast_subscribe":
if (typeof this._onBroadcastSubscribe != "function") {
throw new Error("Unexpected broadcast_subscribe");
}
this._onBroadcastSubscribe(request);
break;
default:
throw new Error('Unexpected message: ' + messageType);
throw new Error("Unexpected message: " + messageType);
}
},
@ -288,8 +289,8 @@ MockWebSocket.prototype = {
* @param {String} msg The message to send to the client.
*/
serverSendMsg(msg) {
if (typeof msg != 'string') {
throw new Error('Invalid response message');
if (typeof msg != "string") {
throw new Error("Invalid response message");
}
waterfall(
() => this._listener.onMessageAvailable(this._context, msg),
@ -304,7 +305,7 @@ MockWebSocket.prototype = {
* @param {Number} [statusCode] The WebSocket connection close code.
* @param {String} [reason] The connection close reason.
*/
serverClose(statusCode, reason = '') {
serverClose(statusCode, reason = "") {
if (!isFinite(statusCode)) {
statusCode = WEBSOCKET_CLOSE_GOING_AWAY;
}
@ -324,36 +325,36 @@ var setUpServiceInParent = async function(service, db) {
return;
}
let userAgentID = 'ce704e41-cb77-4206-b07b-5bf47114791b';
let userAgentID = "ce704e41-cb77-4206-b07b-5bf47114791b";
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
await db.put({
channelID: '6e2814e1-5f84-489e-b542-855cc1311f09',
pushEndpoint: 'https://example.org/push/get',
scope: 'https://example.com/get/ok',
originAttributes: '',
channelID: "6e2814e1-5f84-489e-b542-855cc1311f09",
pushEndpoint: "https://example.org/push/get",
scope: "https://example.com/get/ok",
originAttributes: "",
version: 1,
pushCount: 10,
lastPush: 1438360548322,
quota: 16,
});
await db.put({
channelID: '3a414737-2fd0-44c0-af05-7efc172475fc',
pushEndpoint: 'https://example.org/push/unsub',
scope: 'https://example.com/unsub/ok',
originAttributes: '',
channelID: "3a414737-2fd0-44c0-af05-7efc172475fc",
pushEndpoint: "https://example.org/push/unsub",
scope: "https://example.com/unsub/ok",
originAttributes: "",
version: 2,
pushCount: 10,
lastPush: 1438360848322,
quota: 4,
});
await db.put({
channelID: 'ca3054e8-b59b-4ea0-9c23-4a3c518f3161',
pushEndpoint: 'https://example.org/push/stale',
scope: 'https://example.com/unsub/fail',
originAttributes: '',
channelID: "ca3054e8-b59b-4ea0-9c23-4a3c518f3161",
pushEndpoint: "https://example.org/push/stale",
scope: "https://example.com/unsub/fail",
originAttributes: "",
version: 3,
pushCount: 10,
lastPush: 1438362348322,
@ -361,23 +362,23 @@ var setUpServiceInParent = async function(service, db) {
});
service.init({
serverURI: 'wss://push.example.org/',
serverURI: "wss://push.example.org/",
db: makeStub(db, {
put(prev, record) {
if (record.scope == 'https://example.com/sub/fail') {
return Promise.reject('synergies not aligned');
if (record.scope == "https://example.com/sub/fail") {
return Promise.reject("synergies not aligned");
}
return prev.call(this, record);
},
delete: function(prev, channelID) {
if (channelID == 'ca3054e8-b59b-4ea0-9c23-4a3c518f3161') {
return Promise.reject('splines not reticulated');
delete(prev, channelID) {
if (channelID == "ca3054e8-b59b-4ea0-9c23-4a3c518f3161") {
return Promise.reject("splines not reticulated");
}
return prev.call(this, channelID);
},
getByIdentifiers(prev, identifiers) {
if (identifiers.scope == 'https://example.com/get/fail') {
return Promise.reject('qualia unsynchronized');
if (identifiers.scope == "https://example.com/get/fail") {
return Promise.reject("qualia unsynchronized");
}
return prev.call(this, identifiers);
},
@ -386,7 +387,7 @@ var setUpServiceInParent = async function(service, db) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
uaid: userAgentID,
status: 200,
}));
@ -398,20 +399,20 @@ var setUpServiceInParent = async function(service, db) {
padding: "require",
})
);
equal(appServerKey.length, 65, 'Wrong app server key length');
equal(appServerKey[0], 4, 'Wrong app server key format');
equal(appServerKey.length, 65, "Wrong app server key length");
equal(appServerKey[0], 4, "Wrong app server key format");
}
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
uaid: userAgentID,
channelID: request.channelID,
status: 200,
pushEndpoint: 'https://example.org/push/' + request.channelID,
pushEndpoint: "https://example.org/push/" + request.channelID,
}));
},
onUnregister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
channelID: request.channelID,
status: 200,
}));
@ -427,26 +428,26 @@ var tearDownServiceInParent = async function(db) {
}
let record = await db.getByIdentifiers({
scope: 'https://example.com/sub/ok',
originAttributes: '',
scope: "https://example.com/sub/ok",
originAttributes: "",
});
ok(record.pushEndpoint.startsWith('https://example.org/push'),
'Wrong push endpoint in subscription record');
ok(record.pushEndpoint.startsWith("https://example.org/push"),
"Wrong push endpoint in subscription record");
record = await db.getByKeyID('3a414737-2fd0-44c0-af05-7efc172475fc');
ok(!record, 'Unsubscribed record should not exist');
record = await db.getByKeyID("3a414737-2fd0-44c0-af05-7efc172475fc");
ok(!record, "Unsubscribed record should not exist");
};
function putTestRecord(db, keyID, scope, quota) {
return db.put({
channelID: keyID,
pushEndpoint: 'https://example.org/push/' + keyID,
scope: scope,
pushEndpoint: "https://example.org/push/" + keyID,
scope,
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
quota: quota,
originAttributes: "",
quota,
systemRecord: quota == Infinity,
});
}

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const {BroadcastService} = ChromeUtils.import("resource://gre/modules/PushBroadcastService.jsm", null);
@ -12,8 +12,8 @@ const {broadcastHandler} = ChromeUtils.import("resource://test/broadcast_handler
const broadcastService = pushBroadcastService;
const assert = Assert;
const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
const channelID = '0ef2ad4a-6c49-41ad-af6e-95d2425276bf';
const userAgentID = "bd744428-f125-436a-b6d0-dd0c9845837f";
const channelID = "0ef2ad4a-6c49-41ad-af6e-95d2425276bf";
function run_test() {
do_get_profile();
@ -21,7 +21,7 @@ function run_test() {
userAgentID,
alwaysConnect: true,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
@ -29,7 +29,7 @@ function run_test() {
function getPushServiceMock() {
return {
subscribed: [],
subscribeBroadcast: function(broadcastId, version) {
subscribeBroadcast(broadcastId, version) {
this.subscribed.push([broadcastId, version]);
},
};
@ -41,7 +41,7 @@ add_task(async function test_register_success() {
broadcastHandler.reset();
let notifications = broadcastHandler.notifications;
let socket;
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await broadcastService.addListener("broadcast-test", "2018-02-01", {
moduleURI: "resource://test/broadcast_handler.jsm",
@ -60,12 +60,12 @@ add_task(async function test_register_success() {
onHello(data) {
socket = this;
deepEqual(data.broadcasts, {"broadcast-test": "2018-02-01"}, "Handshake: doesn't consult listeners");
equal(data.messageType, 'hello', 'Handshake: wrong message type');
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
equal(data.messageType, "hello", "Handshake: wrong message type");
equal(data.uaid, userAgentID, "Handshake: wrong device ID");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
},
@ -73,14 +73,14 @@ add_task(async function test_register_success() {
broadcastSubscriptions.push(data);
},
});
}
})
},
});
socket.serverSendMsg(JSON.stringify({
messageType: "broadcast",
broadcasts: {
"broadcast-test": "2018-03-02"
}
"broadcast-test": "2018-03-02",
},
}));
await broadcastHandler.wasNotified;
@ -88,17 +88,17 @@ add_task(async function test_register_success() {
deepEqual(notifications, [["2018-03-02", "broadcast-test"]], "Broadcast notification didn't get delivered");
deepEqual(await broadcastService.getListeners(), {
"broadcast-test": "2018-03-02"
"broadcast-test": "2018-03-02",
}, "Broadcast version wasn't updated");
await broadcastService.addListener("example-listener", "2018-03-01", {
moduleURI: "resource://gre/modules/not-real-example.jsm",
symbolName: "doesntExist"
symbolName: "doesntExist",
});
deepEqual(broadcastSubscriptions, [{
messageType: "broadcast_subscribe",
broadcasts: {"example-listener": "2018-03-01"}
broadcasts: {"example-listener": "2018-03-01"},
}]);
});
@ -108,7 +108,7 @@ add_task(async function test_handle_hello_broadcasts() {
let db = PushServiceWebSocket.newPushDB();
broadcastHandler.reset();
let notifications = broadcastHandler.notifications;
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await broadcastService.addListener("broadcast-test", "2018-02-01", {
moduleURI: "resource://test/broadcast_handler.jsm",
@ -124,31 +124,29 @@ add_task(async function test_handle_hello_broadcasts() {
return new MockWebSocket(uri, {
onHello(data) {
deepEqual(data.broadcasts, {"broadcast-test": "2018-02-01"}, "Handshake: doesn't consult listeners");
equal(data.messageType, 'hello', 'Handshake: wrong message type');
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
equal(data.messageType, "hello", "Handshake: wrong message type");
equal(data.uaid, userAgentID, "Handshake: wrong device ID");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
broadcasts: {
"broadcast-test": "2018-02-02"
}
"broadcast-test": "2018-02-02",
},
}));
},
onBroadcastSubscribe(data) {
broadcastSubscriptions.push(data);
},
onBroadcastSubscribe(data) {},
});
}
})
},
});
await broadcastHandler.wasNotified;
deepEqual(notifications, [["2018-02-02", "broadcast-test"]], "Broadcast notification on hello was delivered");
deepEqual(await broadcastService.getListeners(), {
"broadcast-test": "2018-02-02"
"broadcast-test": "2018-02-02",
}, "Broadcast version wasn't updated");
});
@ -158,16 +156,16 @@ add_task(async function test_broadcast_unit() {
version: "2018-03-04",
sourceInfo: {
moduleURI: "resource://gre/modules/abc.jsm",
symbolName: "getAbc"
}
symbolName: "getAbc",
},
},
"def": {
version: "2018-04-05",
sourceInfo: {
moduleURI: "resource://gre/modules/def.jsm",
symbolName: "getDef"
}
}
symbolName: "getDef",
},
},
};
const path = FileTestUtils.getTempFile("broadcast-listeners.json").path;
@ -179,23 +177,23 @@ add_task(async function test_broadcast_unit() {
const pushServiceMock = getPushServiceMock();
const broadcastService = new BroadcastService(pushServiceMock, path);
const listeners = await broadcastService.getListeners();
const mockBroadcastService = new BroadcastService(pushServiceMock, path);
const listeners = await mockBroadcastService.getListeners();
deepEqual(listeners, {
"abc": "2018-03-04",
"def": "2018-04-05"
"def": "2018-04-05",
});
await broadcastService.addListener("ghi", "2018-05-06", {
await mockBroadcastService.addListener("ghi", "2018-05-06", {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
symbolName: "getGhi",
});
deepEqual(pushServiceMock.subscribed, [
["ghi", "2018-05-06"]
["ghi", "2018-05-06"],
]);
await broadcastService._saveImmediately();
await mockBroadcastService._saveImmediately();
const newJSONFile = new JSONFile({path});
await newJSONFile.load();
@ -207,36 +205,36 @@ add_task(async function test_broadcast_unit() {
version: "2018-05-06",
sourceInfo: {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
}
}
symbolName: "getGhi",
},
},
},
version: 1,
});
deepEqual(await broadcastService.getListeners(), {
deepEqual(await mockBroadcastService.getListeners(), {
"abc": "2018-03-04",
"def": "2018-04-05",
"ghi": "2018-05-06"
"ghi": "2018-05-06",
});
});
add_task(async function test_broadcast_initialize_sane() {
const path = FileTestUtils.getTempFile("broadcast-listeners.json").path;
const broadcastService = new BroadcastService(getPushServiceMock(), path);
deepEqual(await broadcastService.getListeners(), {}, "listeners should start out sane");
await broadcastService._saveImmediately();
const mockBroadcastService = new BroadcastService(getPushServiceMock(), path);
deepEqual(await mockBroadcastService.getListeners(), {}, "listeners should start out sane");
await mockBroadcastService._saveImmediately();
let onDiskJSONFile = new JSONFile({path});
await onDiskJSONFile.load();
deepEqual(onDiskJSONFile.data, {listeners: {}, version: 1},
"written JSON file has listeners and version fields");
await broadcastService.addListener("ghi", "2018-05-06", {
await mockBroadcastService.addListener("ghi", "2018-05-06", {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
symbolName: "getGhi",
});
await broadcastService._saveImmediately();
await mockBroadcastService._saveImmediately();
onDiskJSONFile = new JSONFile({path});
await onDiskJSONFile.load();
@ -247,9 +245,9 @@ add_task(async function test_broadcast_initialize_sane() {
version: "2018-05-06",
sourceInfo: {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
}
}
symbolName: "getGhi",
},
},
},
version: 1,
}, "adding listeners to initial state is written OK");
@ -257,24 +255,24 @@ add_task(async function test_broadcast_initialize_sane() {
add_task(async function test_broadcast_reject_invalid_sourceinfo() {
const path = FileTestUtils.getTempFile("broadcast-listeners.json").path;
const broadcastService = new BroadcastService(getPushServiceMock(), path);
const mockBroadcastService = new BroadcastService(getPushServiceMock(), path);
await assert.rejects(broadcastService.addListener("ghi", "2018-05-06", {
await assert.rejects(mockBroadcastService.addListener("ghi", "2018-05-06", {
moduleName: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
symbolName: "getGhi",
}), /moduleURI must be a string/, "rejects sourceInfo that doesn't have moduleURI");
});
add_task(async function test_broadcast_reject_version_not_string() {
await assert.rejects(broadcastService.addListener("ghi", {}, {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
symbolName: "getGhi",
}), /version should be a string/, "rejects version that isn't a string");
});
add_task(async function test_broadcast_reject_version_empty_string() {
await assert.rejects(broadcastService.addListener("ghi", "", {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
symbolName: "getGhi",
}), /version should not be an empty string/, "rejects version that is an empty string");
});

Просмотреть файл

@ -1,13 +1,13 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
var db;
var unregisterDefers = {};
var userAgentID = '4ce480ef-55b2-4f83-924c-dcd35ab978b4';
var userAgentID = "4ce480ef-55b2-4f83-924c-dcd35ab978b4";
function promiseUnregister(keyID, code) {
return new Promise(r => unregisterDefers[keyID] = r);
@ -16,36 +16,36 @@ function promiseUnregister(keyID, code) {
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
add_task(async function setup() {
db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(_ => db.drop().then(_ => db.close()));
registerCleanupFunction(() => db.drop().then(() => db.close()));
// Active subscriptions; should be expired then dropped.
await putTestRecord(db, 'active-1', 'https://example.info/some-page', 8);
await putTestRecord(db, 'active-2', 'https://example.com/another-page', 16);
await putTestRecord(db, "active-1", "https://example.info/some-page", 8);
await putTestRecord(db, "active-2", "https://example.com/another-page", 16);
// Expired subscription; should be dropped.
await putTestRecord(db, 'expired', 'https://example.net/yet-another-page', 0);
await putTestRecord(db, "expired", "https://example.net/yet-another-page", 0);
// A privileged subscription that should not be affected by sanitizing data
// because its quota is set to `Infinity`.
await putTestRecord(db, 'privileged', 'app://chrome/only', Infinity);
await putTestRecord(db, "privileged", "app://chrome/only", Infinity);
let handshakeDone;
let handshakePromise = new Promise(r => handshakeDone = r);
PushService.init({
serverURI: 'wss://push.example.org/',
db: db,
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
uaid: userAgentID,
status: 200,
use_webpush: true,
@ -54,13 +54,13 @@ add_task(async function setup() {
},
onUnregister(request) {
let resolve = unregisterDefers[request.channelID];
equal(typeof resolve, 'function',
'Dropped unexpected channel ID ' + request.channelID);
equal(typeof resolve, "function",
"Dropped unexpected channel ID " + request.channelID);
delete unregisterDefers[request.channelID];
equal(request.code, 200,
'Expected manual unregister reason');
"Expected manual unregister reason");
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
channelID: request.channelID,
status: 200,
}));
@ -78,8 +78,8 @@ add_task(async function test_sanitize() {
let promiseCleared = Promise.all([
// Active subscriptions should be unregistered.
promiseUnregister('active-1'),
promiseUnregister('active-2'),
promiseUnregister("active-1"),
promiseUnregister("active-2"),
promiseObserverNotification(
PushServiceComponent.subscriptionModifiedTopic, (subject, data) => {
modifiedScopes.push(data);
@ -87,7 +87,7 @@ add_task(async function test_sanitize() {
}),
// Privileged should be recreated.
promiseUnregister('privileged'),
promiseUnregister("privileged"),
promiseObserverNotification(
PushServiceComponent.subscriptionChangeTopic, (subject, data) => {
changeScopes.push(data);
@ -96,20 +96,20 @@ add_task(async function test_sanitize() {
]);
await PushService.clear({
domain: '*',
domain: "*",
});
await promiseCleared;
deepEqual(modifiedScopes.sort(compareAscending), [
'app://chrome/only',
'https://example.com/another-page',
'https://example.info/some-page',
], 'Should modify active subscription scopes');
"app://chrome/only",
"https://example.com/another-page",
"https://example.info/some-page",
], "Should modify active subscription scopes");
deepEqual(changeScopes, ['app://chrome/only'],
'Should fire change notification for privileged scope');
deepEqual(changeScopes, ["app://chrome/only"],
"Should fire change notification for privileged scope");
let remainingIDs = await getAllKeyIDs(db);
deepEqual(remainingIDs, [], 'Should drop all subscriptions');
deepEqual(remainingIDs, [], "Should drop all subscriptions");
});

Просмотреть файл

@ -1,11 +1,11 @@
'use strict';
"use strict";
const {PushService, PushServiceWebSocket} = serviceExports;
const {ForgetAboutSite} = ChromeUtils.import("resource://gre/modules/ForgetAboutSite.jsm");
var db;
var unregisterDefers = {};
var userAgentID = '4fe01c2d-72ac-4c13-93d2-bb072caf461d';
var userAgentID = "4fe01c2d-72ac-4c13-93d2-bb072caf461d";
function promiseUnregister(keyID) {
return new Promise(r => unregisterDefers[keyID] = r);
@ -14,40 +14,40 @@ function promiseUnregister(keyID) {
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
add_task(async function setup() {
db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(_ => db.drop().then(_ => db.close()));
registerCleanupFunction(() => db.drop().then(() => db.close()));
// Active and expired subscriptions for a subdomain. The active subscription
// should be expired, then removed; the expired subscription should be
// removed immediately.
await putTestRecord(db, 'active-sub', 'https://sub.example.com/sub-page', 4);
await putTestRecord(db, 'expired-sub', 'https://sub.example.com/yet-another-page', 0);
await putTestRecord(db, "active-sub", "https://sub.example.com/sub-page", 4);
await putTestRecord(db, "expired-sub", "https://sub.example.com/yet-another-page", 0);
// Active subscriptions for another subdomain. Should be unsubscribed and
// dropped.
await putTestRecord(db, 'active-1', 'https://sub2.example.com/some-page', 8);
await putTestRecord(db, 'active-2', 'https://sub3.example.com/another-page', 16);
await putTestRecord(db, "active-1", "https://sub2.example.com/some-page", 8);
await putTestRecord(db, "active-2", "https://sub3.example.com/another-page", 16);
// A privileged subscription with a real URL that should not be affected
// because its quota is set to `Infinity`.
await putTestRecord(db, 'privileged', 'https://sub.example.com/real-url', Infinity);
await putTestRecord(db, "privileged", "https://sub.example.com/real-url", Infinity);
let handshakeDone;
let handshakePromise = new Promise(r => handshakeDone = r);
PushService.init({
serverURI: 'wss://push.example.org/',
db: db,
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
uaid: userAgentID,
status: 200,
use_webpush: true,
@ -56,14 +56,14 @@ add_task(async function setup() {
},
onUnregister(request) {
let resolve = unregisterDefers[request.channelID];
equal(typeof resolve, 'function',
'Dropped unexpected channel ID ' + request.channelID);
equal(typeof resolve, "function",
"Dropped unexpected channel ID " + request.channelID);
delete unregisterDefers[request.channelID];
equal(request.code, 200,
'Expected manual unregister reason');
"Expected manual unregister reason");
resolve();
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
status: 200,
channelID: request.channelID,
}));
@ -80,7 +80,7 @@ add_task(async function test_forgetAboutSubdomain() {
let modifiedScopes = [];
let promiseForgetSubs = Promise.all([
// Active subscriptions should be dropped.
promiseUnregister('active-sub'),
promiseUnregister("active-sub"),
promiseObserverNotification(
PushServiceComponent.subscriptionModifiedTopic, (subject, data) => {
modifiedScopes.push(data);
@ -88,23 +88,23 @@ add_task(async function test_forgetAboutSubdomain() {
}
),
]);
await ForgetAboutSite.removeDataFromDomain('sub.example.com');
await ForgetAboutSite.removeDataFromDomain("sub.example.com");
await promiseForgetSubs;
deepEqual(modifiedScopes.sort(compareAscending), [
'https://sub.example.com/sub-page',
], 'Should fire modified notifications for active subscriptions');
"https://sub.example.com/sub-page",
], "Should fire modified notifications for active subscriptions");
let remainingIDs = await getAllKeyIDs(db);
deepEqual(remainingIDs, ['active-1', 'active-2', 'privileged'],
'Should only forget subscriptions for subdomain');
deepEqual(remainingIDs, ["active-1", "active-2", "privileged"],
"Should only forget subscriptions for subdomain");
});
add_task(async function test_forgetAboutRootDomain() {
let modifiedScopes = [];
let promiseForgetSubs = Promise.all([
promiseUnregister('active-1'),
promiseUnregister('active-2'),
promiseUnregister("active-1"),
promiseUnregister("active-2"),
promiseObserverNotification(
PushServiceComponent.subscriptionModifiedTopic, (subject, data) => {
modifiedScopes.push(data);
@ -113,15 +113,15 @@ add_task(async function test_forgetAboutRootDomain() {
),
]);
await ForgetAboutSite.removeDataFromDomain('example.com');
await ForgetAboutSite.removeDataFromDomain("example.com");
await promiseForgetSubs;
deepEqual(modifiedScopes.sort(compareAscending), [
'https://sub2.example.com/some-page',
'https://sub3.example.com/another-page',
], 'Should fire modified notifications for entire domain');
"https://sub2.example.com/some-page",
"https://sub3.example.com/another-page",
], "Should fire modified notifications for entire domain");
let remainingIDs = await getAllKeyIDs(db);
deepEqual(remainingIDs, ['privileged'],
'Should ignore privileged records with a real URL');
deepEqual(remainingIDs, ["privileged"],
"Should ignore privileged records with a real URL");
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
const userAgentID = "bd744428-f125-436a-b6d0-dd0c9845837f";
let clearForPattern = async function(testRecords, pattern) {
let patternString = JSON.stringify(pattern);
@ -24,12 +24,12 @@ let clearForPattern = async function(testRecords, pattern) {
let url = test.scope + originSuffix;
if (ObjectUtils.deepEqual(test.clearIf, pattern)) {
ok(!registration, 'Should clear registration ' + url +
' for pattern ' + patternString);
ok(!registration, "Should clear registration " + url +
" for pattern " + patternString);
testRecords.splice(length, 1);
} else {
ok(registration, 'Should not clear registration ' + url +
' for pattern ' + patternString);
ok(registration, "Should not clear registration " + url +
" for pattern " + patternString);
}
}
};
@ -39,41 +39,41 @@ function run_test() {
setPrefs({
userAgentID,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_webapps_cleardata() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let testRecords = [{
scope: 'https://example.org/1',
scope: "https://example.org/1",
originAttributes: { appId: 1 },
clearIf: { appId: 1, inIsolatedMozBrowser: false },
}, {
scope: 'https://example.org/1',
scope: "https://example.org/1",
originAttributes: { appId: 1, inIsolatedMozBrowser: true },
clearIf: { appId: 1 },
}, {
scope: 'https://example.org/1',
scope: "https://example.org/1",
originAttributes: { appId: 2, inIsolatedMozBrowser: true },
clearIf: { appId: 2, inIsolatedMozBrowser: true },
}, {
scope: 'https://example.org/2',
scope: "https://example.org/2",
originAttributes: { appId: 1 },
clearIf: { appId: 1, inIsolatedMozBrowser: false },
}, {
scope: 'https://example.org/2',
scope: "https://example.org/2",
originAttributes: { appId: 2, inIsolatedMozBrowser: true },
clearIf: { appId: 2, inIsolatedMozBrowser: true },
}, {
scope: 'https://example.org/3',
scope: "https://example.org/3",
originAttributes: { appId: 3, inIsolatedMozBrowser: true },
clearIf: { inIsolatedMozBrowser: true },
}, {
scope: 'https://example.org/3',
scope: "https://example.org/3",
originAttributes: { appId: 4, inIsolatedMozBrowser: true },
clearIf: { inIsolatedMozBrowser: true },
}];
@ -88,30 +88,30 @@ add_task(async function test_webapps_cleardata() {
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(data) {
equal(data.messageType, 'hello', 'Handshake: wrong message type');
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
equal(data.messageType, "hello", "Handshake: wrong message type");
equal(data.uaid, userAgentID, "Handshake: wrong device ID");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
},
onRegister(data) {
equal(data.messageType, 'register', 'Register: wrong message type');
equal(data.messageType, "register", "Register: wrong message type");
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
channelID: data.channelID,
uaid: userAgentID,
pushEndpoint: 'https://example.com/update/' + Math.random(),
pushEndpoint: "https://example.com/update/" + Math.random(),
}));
},
onUnregister(data) {
equal(data.code, 200, 'Expected manual unregister reason');
equal(data.code, 200, "Expected manual unregister reason");
unregisterDone();
},
});
}
},
});
await Promise.all(testRecords.map(test =>
@ -136,6 +136,6 @@ add_task(async function test_webapps_cleardata() {
// Removes all records where `inIsolatedMozBrowser` is true.
await clearForPattern(testRecords, { inIsolatedMozBrowser: true });
equal(testRecords.length, 0, 'Should remove all test records');
equal(testRecords.length, 0, "Should remove all test records");
await unregisterPromise;
});

Просмотреть файл

@ -1,24 +1,24 @@
'use strict';
"use strict";
const {
getCryptoParamsFromHeaders,
PushCrypto,
} = ChromeUtils.import("resource://gre/modules/PushCrypto.jsm", null);
const REJECT_PADDING = { padding: 'reject' };
const REJECT_PADDING = { padding: "reject" };
// A common key to decrypt some aesgcm and aesgcm128 messages. Other decryption
// tests have their own keys.
const LEGACY_PRIVATE_KEY = {
kty: 'EC',
crv: 'P-256',
d: '4h23G_KkXC9TvBSK2v0Q7ImpS2YAuRd8hQyN0rFAwBg',
x: 'sd85ZCbEG6dEkGMCmDyGBIt454Qy-Yo-1xhbaT2Jlk4',
y: 'vr3cKpQ-Sp1kpZ9HipNjUCwSA55yy0uM8N9byE8dmLs',
kty: "EC",
crv: "P-256",
d: "4h23G_KkXC9TvBSK2v0Q7ImpS2YAuRd8hQyN0rFAwBg",
x: "sd85ZCbEG6dEkGMCmDyGBIt454Qy-Yo-1xhbaT2Jlk4",
y: "vr3cKpQ-Sp1kpZ9HipNjUCwSA55yy0uM8N9byE8dmLs",
ext: true,
};
const LEGACY_PUBLIC_KEY = 'BLHfOWQmxBunRJBjApg8hgSLeOeEMvmKPtcYW2k9iZZOvr3cKpQ-Sp1kpZ9HipNjUCwSA55yy0uM8N9byE8dmLs';
const LEGACY_PUBLIC_KEY = "BLHfOWQmxBunRJBjApg8hgSLeOeEMvmKPtcYW2k9iZZOvr3cKpQ-Sp1kpZ9HipNjUCwSA55yy0uM8N9byE8dmLs";
async function assertDecrypts(test, headers) {
let privateKey = test.privateKey;
@ -30,7 +30,7 @@ async function assertDecrypts(test, headers) {
let payload = ChromeUtils.base64URLDecode(test.data, REJECT_PADDING);
let result = await PushCrypto.decrypt(privateKey, publicKey, authSecret,
headers, payload);
let decoder = new TextDecoder('utf-8');
let decoder = new TextDecoder("utf-8");
equal(decoder.decode(new Uint8Array(result)), test.result, test.desc);
}
@ -43,71 +43,71 @@ async function assertNotDecrypts(test, headers) {
let publicKey = ChromeUtils.base64URLDecode(test.publicKey, REJECT_PADDING);
let promise = PushCrypto.decrypt(test.privateKey, publicKey, authSecret,
headers, data);
await rejects(promise, test.expected, test.desc);
await Assert.rejects(promise, test.expected, test.desc);
}
add_task(async function test_crypto_getCryptoParamsFromHeaders() {
// These headers should parse correctly.
let shouldParse = [{
desc: 'aesgcm with multiple keys',
desc: "aesgcm with multiple keys",
headers: {
encoding: 'aesgcm',
crypto_key: 'keyid=p256dh;dh=Iy1Je2Kv11A,p256ecdsa=o2M8QfiEKuI',
encryption: 'keyid=p256dh;salt=upk1yFkp1xI',
encoding: "aesgcm",
crypto_key: "keyid=p256dh;dh=Iy1Je2Kv11A,p256ecdsa=o2M8QfiEKuI",
encryption: "keyid=p256dh;salt=upk1yFkp1xI",
},
params: {
senderKey: 'Iy1Je2Kv11A',
salt: 'upk1yFkp1xI',
senderKey: "Iy1Je2Kv11A",
salt: "upk1yFkp1xI",
rs: 4096,
},
}, {
desc: 'aesgcm with quoted key param',
desc: "aesgcm with quoted key param",
headers: {
encoding: 'aesgcm',
encoding: "aesgcm",
crypto_key: 'dh="byfHbUffc-k"',
encryption: 'salt=C11AvAsp6Gc',
encryption: "salt=C11AvAsp6Gc",
},
params: {
senderKey: 'byfHbUffc-k',
salt: 'C11AvAsp6Gc',
senderKey: "byfHbUffc-k",
salt: "C11AvAsp6Gc",
rs: 4096,
},
}, {
desc: 'aesgcm with Crypto-Key and rs = 24',
desc: "aesgcm with Crypto-Key and rs = 24",
headers: {
encoding: 'aesgcm',
encoding: "aesgcm",
crypto_key: 'dh="ybuT4VDz-Bg"',
encryption: 'salt=H7U7wcIoIKs; rs=24',
encryption: "salt=H7U7wcIoIKs; rs=24",
},
params: {
senderKey: 'ybuT4VDz-Bg',
salt: 'H7U7wcIoIKs',
senderKey: "ybuT4VDz-Bg",
salt: "H7U7wcIoIKs",
rs: 24,
},
}, {
desc: 'aesgcm128 with Encryption-Key and rs = 2',
desc: "aesgcm128 with Encryption-Key and rs = 2",
headers: {
encoding: 'aesgcm128',
encryption_key: 'keyid=legacy; dh=LqrDQuVl9lY',
encryption: 'keyid=legacy; salt=YngI8B7YapM; rs=2',
encoding: "aesgcm128",
encryption_key: "keyid=legacy; dh=LqrDQuVl9lY",
encryption: "keyid=legacy; salt=YngI8B7YapM; rs=2",
},
params: {
senderKey: 'LqrDQuVl9lY',
salt: 'YngI8B7YapM',
senderKey: "LqrDQuVl9lY",
salt: "YngI8B7YapM",
rs: 2,
},
}, {
desc: 'aesgcm128 with Encryption-Key',
desc: "aesgcm128 with Encryption-Key",
headers: {
encoding: 'aesgcm128',
encryption_key: 'keyid=v2; dh=VA6wmY1IpiE',
encryption: 'keyid=v2; salt=khtpyXhpDKM',
encoding: "aesgcm128",
encryption_key: "keyid=v2; dh=VA6wmY1IpiE",
encryption: "keyid=v2; salt=khtpyXhpDKM",
},
params: {
senderKey: 'VA6wmY1IpiE',
salt: 'khtpyXhpDKM',
senderKey: "VA6wmY1IpiE",
salt: "khtpyXhpDKM",
rs: 4096,
}
},
}];
for (let test of shouldParse) {
let params = getCryptoParamsFromHeaders(test.headers);
@ -124,33 +124,33 @@ add_task(async function test_crypto_getCryptoParamsFromHeaders() {
// These headers should be rejected.
let shouldThrow = [{
desc: 'aesgcm128 with Crypto-Key',
desc: "aesgcm128 with Crypto-Key",
headers: {
encoding: 'aesgcm128',
crypto_key: 'keyid=v2; dh=VA6wmY1IpiE',
encryption: 'keyid=v2; salt=F0Im7RtGgNY',
encoding: "aesgcm128",
crypto_key: "keyid=v2; dh=VA6wmY1IpiE",
encryption: "keyid=v2; salt=F0Im7RtGgNY",
},
exception: /Missing Encryption-Key header/,
}, {
desc: 'Invalid encoding',
desc: "Invalid encoding",
headers: {
encoding: 'nonexistent',
encoding: "nonexistent",
},
exception: /Missing encryption header/,
}, {
desc: 'Invalid record size',
desc: "Invalid record size",
headers: {
encoding: 'aesgcm',
crypto_key: 'dh=pbmv1QkcEDY',
encryption: 'dh=Esao8aTBfIk;rs=bad',
encoding: "aesgcm",
crypto_key: "dh=pbmv1QkcEDY",
encryption: "dh=Esao8aTBfIk;rs=bad",
},
exception: /Invalid salt parameter/,
}, {
desc: 'aesgcm with Encryption-Key',
desc: "aesgcm with Encryption-Key",
headers: {
encoding: 'aesgcm',
encryption_key: 'dh=FplK5KkvUF0',
encryption: 'salt=p6YHhFF3BQY',
encoding: "aesgcm",
encryption_key: "dh=FplK5KkvUF0",
encryption: "salt=p6YHhFF3BQY",
},
exception: /Missing Crypto-Key header/,
}];
@ -161,77 +161,77 @@ add_task(async function test_crypto_getCryptoParamsFromHeaders() {
add_task(async function test_aes128gcm_ok() {
let expectedSuccesses = [{
desc: 'Example from draft-ietf-webpush-encryption-latest',
result: 'When I grow up, I want to be a watermelon',
data: 'DGv6ra1nlYgDCS1FRnbzlwAAEABBBP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZIIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A_yl95bQpu6cVPTpK4Mqgkf1CXztLVBSt2Ks3oZwbuwXPXLWyouBWLVWGNWQexSgSxsj_Qulcy4a-fN',
authSecret: 'BTBZMqHH6r4Tts7J_aSIgg',
desc: "Example from draft-ietf-webpush-encryption-latest",
result: "When I grow up, I want to be a watermelon",
data: "DGv6ra1nlYgDCS1FRnbzlwAAEABBBP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZIIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A_yl95bQpu6cVPTpK4Mqgkf1CXztLVBSt2Ks3oZwbuwXPXLWyouBWLVWGNWQexSgSxsj_Qulcy4a-fN",
authSecret: "BTBZMqHH6r4Tts7J_aSIgg",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'q1dXpw3UpT5VOmu_cf_v6ih07Aems3njxI-JWgLcM94',
x: 'JXGyvs3942BVGq8e0PTNNmwRzr5VX4m8t7GGpTM5FzE',
y: 'aOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4',
kty: "EC",
crv: "P-256",
d: "q1dXpw3UpT5VOmu_cf_v6ih07Aems3njxI-JWgLcM94",
x: "JXGyvs3942BVGq8e0PTNNmwRzr5VX4m8t7GGpTM5FzE",
y: "aOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4",
ext: true,
},
publicKey: 'BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcxaOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4',
publicKey: "BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcxaOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4",
}, {
desc: 'rs = 24, pad = 0',
desc: "rs = 24, pad = 0",
result: "I am the very model of a modern Major-General; I've information vegetable, animal, and mineral",
data: 'goagSH7PP0ZGwUsgShmdkwAAABhBBDJVyIuUJbOSVMeWHP8VNPnxY-dZSw86doqOkEzZZZY1ALBWVXTVf0rUDH3oi68I9Hrp-01zA-mr8XKWl5kcH8cX0KiV2PtCwdkEyaQ73YF5fsDxgoWDiaTA3wPqMvuLDqGsZWHnE9Psnfoy7UMEqKlh2a1nE7ZOXiXcOBHLNj260jYzSJnEPV2eXixSXfyWpaSJHAwfj4wVdAAocmViIg6ywk8wFB1hgJpnX2UVEU_qIOcaP6AOIOr1UUQPfosQqC2MEHe5u9gHXF5pi-E267LAlkoYefq01KV_xK_vjbxpw8GAYfSjQEm0L8FG-CN37c8pnQ2Yf61MkihaXac9OctfNeWq_22cN6hn4qsOq0F7QoWIiZqWhB1vS9cJ3KUlyPQvKI9cvevDxw0fJHWeTFzhuwT9BjdILjjb2Vkqc0-qTDOawqD4c8WXsvdGDQCec5Y1x3UhdQXdjR_mhXypxFM37OZTvKJBr1vPCpRXl-bI6iOd7KScgtMM1x5luKhGzZyz25HyuFyj1ec82A',
authSecret: '_tK2LDGoIt6be6agJ_nvGA',
data: "goagSH7PP0ZGwUsgShmdkwAAABhBBDJVyIuUJbOSVMeWHP8VNPnxY-dZSw86doqOkEzZZZY1ALBWVXTVf0rUDH3oi68I9Hrp-01zA-mr8XKWl5kcH8cX0KiV2PtCwdkEyaQ73YF5fsDxgoWDiaTA3wPqMvuLDqGsZWHnE9Psnfoy7UMEqKlh2a1nE7ZOXiXcOBHLNj260jYzSJnEPV2eXixSXfyWpaSJHAwfj4wVdAAocmViIg6ywk8wFB1hgJpnX2UVEU_qIOcaP6AOIOr1UUQPfosQqC2MEHe5u9gHXF5pi-E267LAlkoYefq01KV_xK_vjbxpw8GAYfSjQEm0L8FG-CN37c8pnQ2Yf61MkihaXac9OctfNeWq_22cN6hn4qsOq0F7QoWIiZqWhB1vS9cJ3KUlyPQvKI9cvevDxw0fJHWeTFzhuwT9BjdILjjb2Vkqc0-qTDOawqD4c8WXsvdGDQCec5Y1x3UhdQXdjR_mhXypxFM37OZTvKJBr1vPCpRXl-bI6iOd7KScgtMM1x5luKhGzZyz25HyuFyj1ec82A",
authSecret: "_tK2LDGoIt6be6agJ_nvGA",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'bGViEe3PvjjFJg8lcnLsqu71b2yqWGnZN9J2MTed-9s',
x: 'auB0GHF0AZ2LAocFnvOXDS7EeCMopnzbg-tS21FMHrU',
y: 'GpbhrW-_xKj3XhhXA-kDZSicKZ0kn0BuVhqzhLOB-Cc',
kty: "EC",
crv: "P-256",
d: "bGViEe3PvjjFJg8lcnLsqu71b2yqWGnZN9J2MTed-9s",
x: "auB0GHF0AZ2LAocFnvOXDS7EeCMopnzbg-tS21FMHrU",
y: "GpbhrW-_xKj3XhhXA-kDZSicKZ0kn0BuVhqzhLOB-Cc",
ext: true,
},
publicKey: 'BGrgdBhxdAGdiwKHBZ7zlw0uxHgjKKZ824PrUttRTB61GpbhrW-_xKj3XhhXA-kDZSicKZ0kn0BuVhqzhLOB-Cc',
publicKey: "BGrgdBhxdAGdiwKHBZ7zlw0uxHgjKKZ824PrUttRTB61GpbhrW-_xKj3XhhXA-kDZSicKZ0kn0BuVhqzhLOB-Cc",
}, {
desc: 'rs = 49, pad = 84; ciphertext length falls on record boundary',
result: 'Hello, world',
data: '-yiDzsHE_K3W0TcfbqSR4AAAADFBBC1EHuf5_2oDKaZJJ9BST9vnsixvtl4Qq0_cA4-UQgoMo_oo2tNshOyRoWLq4Hj6rSwc7XjegRPhlgKyDolPSXa5c-L89oL6DIzNmvPVv_Ht4W-tWjHOGdOLXh_h94pPrYQrvBAlTCxs3ZaitVKE2XLFPK2MO6yxD19X6w1KQzO2BBAroRfK4pEI-9n2Kai6aWDdAZRbOe03unBsQ0oQ_SvSCU_5JJvNrUUTX1_kX804Bx-LLTlBr9pDmBDXeqyvfOULVDJb9YyVAzN9BzeFoyPfo0M',
authSecret: 'lfF1cOUI72orKtG09creMw',
desc: "rs = 49, pad = 84; ciphertext length falls on record boundary",
result: "Hello, world",
data: "-yiDzsHE_K3W0TcfbqSR4AAAADFBBC1EHuf5_2oDKaZJJ9BST9vnsixvtl4Qq0_cA4-UQgoMo_oo2tNshOyRoWLq4Hj6rSwc7XjegRPhlgKyDolPSXa5c-L89oL6DIzNmvPVv_Ht4W-tWjHOGdOLXh_h94pPrYQrvBAlTCxs3ZaitVKE2XLFPK2MO6yxD19X6w1KQzO2BBAroRfK4pEI-9n2Kai6aWDdAZRbOe03unBsQ0oQ_SvSCU_5JJvNrUUTX1_kX804Bx-LLTlBr9pDmBDXeqyvfOULVDJb9YyVAzN9BzeFoyPfo0M",
authSecret: "lfF1cOUI72orKtG09creMw",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'ZwBKTqgg3u2OSdtelIDmPT6jzOGujhpgYJcT1SfQAe8',
x: 'AU6PFLktoHzgg7k_ljZ-h7IXpH9-8u6TqdNDqgY-V1o',
y: 'nzDVnGkMajmz_IFbFQyn3RSWAXQTN7U1B6UfQbFzpyE',
kty: "EC",
crv: "P-256",
d: "ZwBKTqgg3u2OSdtelIDmPT6jzOGujhpgYJcT1SfQAe8",
x: "AU6PFLktoHzgg7k_ljZ-h7IXpH9-8u6TqdNDqgY-V1o",
y: "nzDVnGkMajmz_IFbFQyn3RSWAXQTN7U1B6UfQbFzpyE",
ext: true,
},
publicKey: 'BAFOjxS5LaB84IO5P5Y2foeyF6R_fvLuk6nTQ6oGPldanzDVnGkMajmz_IFbFQyn3RSWAXQTN7U1B6UfQbFzpyE',
publicKey: "BAFOjxS5LaB84IO5P5Y2foeyF6R_fvLuk6nTQ6oGPldanzDVnGkMajmz_IFbFQyn3RSWAXQTN7U1B6UfQbFzpyE",
}, {
desc: 'rs = 18, pad = 0',
result: '1',
data: 'fK69vCCTjuNAqUbxvU9o8QAAABJBBDfP21Ij2fleqgL27ZQP8i6vBbNiLpSdw86fM15u-bJq6qzKD3QICos2RZLyzMbV7d1DAEtwuRiH0UTZ-pPxbDvH6mj0_VR6lOyoSxbhOKYIAXc',
authSecret: '1loE35Xy215gSDn3F9zeeQ',
desc: "rs = 18, pad = 0",
result: "1",
data: "fK69vCCTjuNAqUbxvU9o8QAAABJBBDfP21Ij2fleqgL27ZQP8i6vBbNiLpSdw86fM15u-bJq6qzKD3QICos2RZLyzMbV7d1DAEtwuRiH0UTZ-pPxbDvH6mj0_VR6lOyoSxbhOKYIAXc",
authSecret: "1loE35Xy215gSDn3F9zeeQ",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'J0M_q4lws8tShLYRg--0YoZWLNKnMw2MrpYJEaVXHQw',
x: 'UV1DJjVWUjmdoksr6SQeYztc8U-vDPOm_WAxe5VMCi8',
y: 'SEhUgASyewz3SAvIEMa-wDqPt5yOoA_IsF4A-INFY-8',
kty: "EC",
crv: "P-256",
d: "J0M_q4lws8tShLYRg--0YoZWLNKnMw2MrpYJEaVXHQw",
x: "UV1DJjVWUjmdoksr6SQeYztc8U-vDPOm_WAxe5VMCi8",
y: "SEhUgASyewz3SAvIEMa-wDqPt5yOoA_IsF4A-INFY-8",
ext: true,
},
publicKey: 'BFFdQyY1VlI5naJLK-kkHmM7XPFPrwzzpv1gMXuVTAovSEhUgASyewz3SAvIEMa-wDqPt5yOoA_IsF4A-INFY-8',
publicKey: "BFFdQyY1VlI5naJLK-kkHmM7XPFPrwzzpv1gMXuVTAovSEhUgASyewz3SAvIEMa-wDqPt5yOoA_IsF4A-INFY-8",
}];
for (let test of expectedSuccesses) {
let privateKey = test.privateKey;
let publicKey = ChromeUtils.base64URLDecode(test.publicKey, {
padding: 'reject',
padding: "reject",
});
let authSecret = ChromeUtils.base64URLDecode(test.authSecret, {
padding: 'reject',
padding: "reject",
});
let payload = ChromeUtils.base64URLDecode(test.data, {
padding: 'reject',
padding: "reject",
});
let result = await PushCrypto.decrypt(privateKey, publicKey, authSecret, {
encoding: 'aes128gcm',
encoding: "aes128gcm",
}, payload);
let decoder = new TextDecoder('utf-8');
let decoder = new TextDecoder("utf-8");
equal(decoder.decode(new Uint8Array(result)), test.result, test.desc);
}
});
@ -239,127 +239,127 @@ add_task(async function test_aes128gcm_ok() {
add_task(async function test_aes128gcm_err() {
let expectedFailures = [{
// Just the payload; no header at all.
desc: 'Missing header block',
data: 'RbdNK2m-mwdN47NaqH58FWEd',
desc: "Missing header block",
data: "RbdNK2m-mwdN47NaqH58FWEd",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'G-g_ODMu8JaB-vPzB7H_LhDKt4zHzatoOsDukqw_buE',
x: '26mRyiFTQ_Nr3T6FfK_ePRi_V_GDWygzutQU8IhBYgU',
y: 'GslqCyRJADfQfPUo5OGOEAoaZOt0R0hUS_HiINq6zyw',
kty: "EC",
crv: "P-256",
d: "G-g_ODMu8JaB-vPzB7H_LhDKt4zHzatoOsDukqw_buE",
x: "26mRyiFTQ_Nr3T6FfK_ePRi_V_GDWygzutQU8IhBYgU",
y: "GslqCyRJADfQfPUo5OGOEAoaZOt0R0hUS_HiINq6zyw",
ext: true,
},
publicKey: 'BNupkcohU0Pza90-hXyv3j0Yv1fxg1soM7rUFPCIQWIFGslqCyRJADfQfPUo5OGOEAoaZOt0R0hUS_HiINq6zyw',
authSecret: 'NHG7mEgeAlM785VCvPPbpA',
publicKey: "BNupkcohU0Pza90-hXyv3j0Yv1fxg1soM7rUFPCIQWIFGslqCyRJADfQfPUo5OGOEAoaZOt0R0hUS_HiINq6zyw",
authSecret: "NHG7mEgeAlM785VCvPPbpA",
expected: /Truncated header/,
}, {
// The sender key should be 65 bytes; this header contains an invalid key
// that's only 1 byte.
desc: 'Truncated sender key',
data: '3ltpa4fxoVy2revdedb5ngAAABIBALa8GCbDfJ9z3WtIWcK1BRgZUg',
desc: "Truncated sender key",
data: "3ltpa4fxoVy2revdedb5ngAAABIBALa8GCbDfJ9z3WtIWcK1BRgZUg",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'zojo4LMFekdS60yPqTHrYhwwLaWtA7ga9FnPZzVWDK4',
x: 'oyXZkITEDeDOcioELESNlKMmkXIcp54890XnjGmIYZQ',
y: 'sCzqGSJBdnlanU27sgc68szW-m8KTHxJaFVr5QKjuoE',
kty: "EC",
crv: "P-256",
d: "zojo4LMFekdS60yPqTHrYhwwLaWtA7ga9FnPZzVWDK4",
x: "oyXZkITEDeDOcioELESNlKMmkXIcp54890XnjGmIYZQ",
y: "sCzqGSJBdnlanU27sgc68szW-m8KTHxJaFVr5QKjuoE",
ext: true,
},
publicKey: 'BKMl2ZCExA3gznIqBCxEjZSjJpFyHKeePPdF54xpiGGUsCzqGSJBdnlanU27sgc68szW-m8KTHxJaFVr5QKjuoE',
authSecret: 'XDHg2W2aE5iZrAlp01n3QA',
publicKey: "BKMl2ZCExA3gznIqBCxEjZSjJpFyHKeePPdF54xpiGGUsCzqGSJBdnlanU27sgc68szW-m8KTHxJaFVr5QKjuoE",
authSecret: "XDHg2W2aE5iZrAlp01n3QA",
expected: /Invalid sender public key/,
}, {
// The message is encrypted with only the first 12 bytes of the 16-byte
// auth secret, so the derived decryption key and nonce won't match.
desc: 'Encrypted with mismatched auth secret',
data: 'gRX0mIuMOSp7rLQ8jxrFZQAAABJBBBmUSDxUHpvDmmrwP_cTqndFwoThOKQqJDW3l7IMS2mM9RGLT4VVMXwZDqvr-rdJwWTT9r3r4NRBcZExo1fYiQoTxNvUsW_z3VqD98ka1uBArEJzCn8LPNMkXp-Nb_McdR1BDP0',
desc: "Encrypted with mismatched auth secret",
data: "gRX0mIuMOSp7rLQ8jxrFZQAAABJBBBmUSDxUHpvDmmrwP_cTqndFwoThOKQqJDW3l7IMS2mM9RGLT4VVMXwZDqvr-rdJwWTT9r3r4NRBcZExo1fYiQoTxNvUsW_z3VqD98ka1uBArEJzCn8LPNMkXp-Nb_McdR1BDP0",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'YMdjalF95wOaCsLQ4wZEAHlMeOfgSTmBKaInzuD5qAE',
x: '_dBBKKhcBYltf4H-EYvcuIe588H_QYOtxMgk0ShgcwA',
y: '6Yay37WmEOWvQ-QIoAcwWE-T49_d_ERzfV8I-y1viRY',
kty: "EC",
crv: "P-256",
d: "YMdjalF95wOaCsLQ4wZEAHlMeOfgSTmBKaInzuD5qAE",
x: "_dBBKKhcBYltf4H-EYvcuIe588H_QYOtxMgk0ShgcwA",
y: "6Yay37WmEOWvQ-QIoAcwWE-T49_d_ERzfV8I-y1viRY",
ext: true,
},
publicKey: 'BP3QQSioXAWJbX-B_hGL3LiHufPB_0GDrcTIJNEoYHMA6Yay37WmEOWvQ-QIoAcwWE-T49_d_ERzfV8I-y1viRY',
authSecret: 'NVo4zW2b7xWZDi0zCNvWAA',
publicKey: "BP3QQSioXAWJbX-B_hGL3LiHufPB_0GDrcTIJNEoYHMA6Yay37WmEOWvQ-QIoAcwWE-T49_d_ERzfV8I-y1viRY",
authSecret: "NVo4zW2b7xWZDi0zCNvWAA",
expected: /Bad encryption/,
}, {
// Multiple records; the first has padding delimiter = 2, but should be 1.
desc: 'Early final record',
data: '2-IVUH0a09Lq6r6ubodNjwAAABJBBHvEND80qDSM3E5GL_x8QKpqjGGnOcTEHUUSVQX3Dp_F-e-oaFLdSI3Pjo6iyvt14Hq9XufJ1cA4uv7weVcbC9opRBHOmMdt0DHA5YBXekmAo3XkXtMEKb4OLunafm34aW0BuOw',
desc: "Early final record",
data: "2-IVUH0a09Lq6r6ubodNjwAAABJBBHvEND80qDSM3E5GL_x8QKpqjGGnOcTEHUUSVQX3Dp_F-e-oaFLdSI3Pjo6iyvt14Hq9XufJ1cA4uv7weVcbC9opRBHOmMdt0DHA5YBXekmAo3XkXtMEKb4OLunafm34aW0BuOw",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'XdodkYvEB7o82hLLgBTUmqfgJpACggMERmvIADTKkkA',
x: 'yVxlINrRHo9qG_gDGkDCpO4QRcGQO-BqHfp_gpzOst4',
y: 'Akga5r0EdhIbEsVTLQsjF4gHfvoGg6W_4NYjObJRyzU',
kty: "EC",
crv: "P-256",
d: "XdodkYvEB7o82hLLgBTUmqfgJpACggMERmvIADTKkkA",
x: "yVxlINrRHo9qG_gDGkDCpO4QRcGQO-BqHfp_gpzOst4",
y: "Akga5r0EdhIbEsVTLQsjF4gHfvoGg6W_4NYjObJRyzU",
ext: true,
},
publicKey: 'BMlcZSDa0R6Pahv4AxpAwqTuEEXBkDvgah36f4KczrLeAkga5r0EdhIbEsVTLQsjF4gHfvoGg6W_4NYjObJRyzU',
authSecret: 'QMJB_eQmnuHm1yVZLZgnGA',
publicKey: "BMlcZSDa0R6Pahv4AxpAwqTuEEXBkDvgah36f4KczrLeAkga5r0EdhIbEsVTLQsjF4gHfvoGg6W_4NYjObJRyzU",
authSecret: "QMJB_eQmnuHm1yVZLZgnGA",
expected: /Padding is wrong!/,
}];
for (let test of expectedFailures) {
await assertNotDecrypts(test, { encoding: 'aes128gcm' });
await assertNotDecrypts(test, { encoding: "aes128gcm" });
}
});
add_task(async function test_aesgcm_ok() {
let expectedSuccesses = [{
desc: 'padSize = 2, rs = 24, pad = 0',
result: 'Some message',
data: 'Oo34w2F9VVnTMFfKtdx48AZWQ9Li9M6DauWJVgXU',
authSecret: 'aTDc6JebzR6eScy2oLo4RQ',
desc: "padSize = 2, rs = 24, pad = 0",
result: "Some message",
data: "Oo34w2F9VVnTMFfKtdx48AZWQ9Li9M6DauWJVgXU",
authSecret: "aTDc6JebzR6eScy2oLo4RQ",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BCHFVrflyxibGLlgztLwKelsRZp4gqX3tNfAKFaxAcBhpvYeN1yIUMrxaDKiLh4LNKPtj0BOXGdr-IQ-QP82Wjo',
encryption: 'salt=zCU18Rw3A5aB_Xi-vfixmA; rs=24',
encoding: 'aesgcm',
crypto_key: "dh=BCHFVrflyxibGLlgztLwKelsRZp4gqX3tNfAKFaxAcBhpvYeN1yIUMrxaDKiLh4LNKPtj0BOXGdr-IQ-QP82Wjo",
encryption: "salt=zCU18Rw3A5aB_Xi-vfixmA; rs=24",
encoding: "aesgcm",
},
}, {
desc: 'padSize = 2, rs = 8, pad = 16',
result: 'Yet another message',
data: 'uEC5B_tR-fuQ3delQcrzrDCp40W6ipMZjGZ78USDJ5sMj-6bAOVG3AK6JqFl9E6AoWiBYYvMZfwThVxmDnw6RHtVeLKFM5DWgl1EwkOohwH2EhiDD0gM3io-d79WKzOPZE9rDWUSv64JstImSfX_ADQfABrvbZkeaWxh53EG59QMOElFJqHue4dMURpsMXg',
authSecret: '6plwZnSpVUbF7APDXus3UQ',
desc: "padSize = 2, rs = 8, pad = 16",
result: "Yet another message",
data: "uEC5B_tR-fuQ3delQcrzrDCp40W6ipMZjGZ78USDJ5sMj-6bAOVG3AK6JqFl9E6AoWiBYYvMZfwThVxmDnw6RHtVeLKFM5DWgl1EwkOohwH2EhiDD0gM3io-d79WKzOPZE9rDWUSv64JstImSfX_ADQfABrvbZkeaWxh53EG59QMOElFJqHue4dMURpsMXg",
authSecret: "6plwZnSpVUbF7APDXus3UQ",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BEaA4gzA3i0JDuirGhiLgymS4hfFX7TNTdEhSk_HBlLpkjgCpjPL5c-GL9uBGIfa_fhGNKKFhXz1k9Kyens2ZpQ',
encryption: 'salt=ZFhzj0S-n29g9P2p4-I7tA; rs=8',
encoding: 'aesgcm',
crypto_key: "dh=BEaA4gzA3i0JDuirGhiLgymS4hfFX7TNTdEhSk_HBlLpkjgCpjPL5c-GL9uBGIfa_fhGNKKFhXz1k9Kyens2ZpQ",
encryption: "salt=ZFhzj0S-n29g9P2p4-I7tA; rs=8",
encoding: "aesgcm",
},
}, {
desc: 'padSize = 2, rs = 3, pad = 0',
result: 'Small record size',
data: 'oY4e5eDatDVt2fpQylxbPJM-3vrfhDasfPc8Q1PWt4tPfMVbz_sDNL_cvr0DXXkdFzS1lxsJsj550USx4MMl01ihjImXCjrw9R5xFgFrCAqJD3GwXA1vzS4T5yvGVbUp3SndMDdT1OCcEofTn7VC6xZ-zP8rzSQfDCBBxmPU7OISzr8Z4HyzFCGJeBfqiZ7yUfNlKF1x5UaZ4X6iU_TXx5KlQy_toV1dXZ2eEAMHJUcSdArvB6zRpFdEIxdcHcJyo1BIYgAYTDdAIy__IJVCPY_b2CE5W_6ohlYKB7xDyH8giNuWWXAgBozUfScLUVjPC38yJTpAUi6w6pXgXUWffende5FreQpnMFL1L4G-38wsI_-ISIOzdO8QIrXHxmtc1S5xzYu8bMqSgCinvCEwdeGFCmighRjj8t1zRWo0D14rHbQLPR_b1P5SvEeJTtS9Nm3iibM',
authSecret: 'g2rWVHUCpUxgcL9Tz7vyeQ',
desc: "padSize = 2, rs = 3, pad = 0",
result: "Small record size",
data: "oY4e5eDatDVt2fpQylxbPJM-3vrfhDasfPc8Q1PWt4tPfMVbz_sDNL_cvr0DXXkdFzS1lxsJsj550USx4MMl01ihjImXCjrw9R5xFgFrCAqJD3GwXA1vzS4T5yvGVbUp3SndMDdT1OCcEofTn7VC6xZ-zP8rzSQfDCBBxmPU7OISzr8Z4HyzFCGJeBfqiZ7yUfNlKF1x5UaZ4X6iU_TXx5KlQy_toV1dXZ2eEAMHJUcSdArvB6zRpFdEIxdcHcJyo1BIYgAYTDdAIy__IJVCPY_b2CE5W_6ohlYKB7xDyH8giNuWWXAgBozUfScLUVjPC38yJTpAUi6w6pXgXUWffende5FreQpnMFL1L4G-38wsI_-ISIOzdO8QIrXHxmtc1S5xzYu8bMqSgCinvCEwdeGFCmighRjj8t1zRWo0D14rHbQLPR_b1P5SvEeJTtS9Nm3iibM",
authSecret: "g2rWVHUCpUxgcL9Tz7vyeQ",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BCg6ZIGuE2ZNm2ti6Arf4CDVD_8--aLXAGLYhpghwjl1xxVjTLLpb7zihuEOGGbyt8Qj0_fYHBP4ObxwJNl56bk',
encryption: 'salt=5LIDBXbvkBvvb7ZdD-T4PQ; rs=3',
encoding: 'aesgcm',
crypto_key: "dh=BCg6ZIGuE2ZNm2ti6Arf4CDVD_8--aLXAGLYhpghwjl1xxVjTLLpb7zihuEOGGbyt8Qj0_fYHBP4ObxwJNl56bk",
encryption: "salt=5LIDBXbvkBvvb7ZdD-T4PQ; rs=3",
encoding: "aesgcm",
},
}, {
desc: 'Example from draft-ietf-httpbis-encryption-encoding-02',
result: 'I am the walrus',
data: '6nqAQUME8hNqw5J3kl8cpVVJylXKYqZOeseZG8UueKpA',
authSecret: 'R29vIGdvbyBnJyBqb29iIQ',
desc: "Example from draft-ietf-httpbis-encryption-encoding-02",
result: "I am the walrus",
data: "6nqAQUME8hNqw5J3kl8cpVVJylXKYqZOeseZG8UueKpA",
authSecret: "R29vIGdvbyBnJyBqb29iIQ",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: '9FWl15_QUQAWDaD3k3l50ZBZQJ4au27F1V4F0uLSD_M',
x: 'ISQGPMvxncL6iLZDugTm3Y2n6nuiyMYuD3epQ_TC-pE',
y: 'T21EEWyf0cQDQcakQMqz4hQKYOQ3il2nNZct4HgAUQU',
kty: "EC",
crv: "P-256",
d: "9FWl15_QUQAWDaD3k3l50ZBZQJ4au27F1V4F0uLSD_M",
x: "ISQGPMvxncL6iLZDugTm3Y2n6nuiyMYuD3epQ_TC-pE",
y: "T21EEWyf0cQDQcakQMqz4hQKYOQ3il2nNZct4HgAUQU",
ext: true,
},
publicKey: 'BCEkBjzL8Z3C-oi2Q7oE5t2Np-p7osjGLg93qUP0wvqRT21EEWyf0cQDQcakQMqz4hQKYOQ3il2nNZct4HgAUQU',
publicKey: "BCEkBjzL8Z3C-oi2Q7oE5t2Np-p7osjGLg93qUP0wvqRT21EEWyf0cQDQcakQMqz4hQKYOQ3il2nNZct4HgAUQU",
headers: {
crypto_key: 'keyid="dhkey"; dh="BNoRDbb84JGm8g5Z5CFxurSqsXWJ11ItfXEWYVLE85Y7CYkDjXsIEc4aqxYaQ1G8BqkXCJ6DPpDrWtdWj_mugHU"',
encryption: 'keyid="dhkey"; salt="lngarbyKfMoi9Z75xYXmkg"',
encoding: 'aesgcm',
encoding: "aesgcm",
},
}];
for (let test of expectedSuccesses) {
@ -369,120 +369,120 @@ add_task(async function test_aesgcm_ok() {
add_task(async function test_aesgcm_err() {
let expectedFailures = [{
desc: 'aesgcm128 message decrypted as aesgcm',
data: 'fwkuwTTChcLnrzsbDI78Y2EoQzfnbMI8Ax9Z27_rwX8',
authSecret: 'BhbpNTWyO5wVJmVKTV6XaA',
desc: "aesgcm128 message decrypted as aesgcm",
data: "fwkuwTTChcLnrzsbDI78Y2EoQzfnbMI8Ax9Z27_rwX8",
authSecret: "BhbpNTWyO5wVJmVKTV6XaA",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BCHn-I-J3dfPRLJBlNZ3xFoAqaBLZ6qdhpaz9W7Q00JW1oD-hTxyEECn6KYJNK8AxKUyIDwn6Icx_PYWJiEYjQ0',
encryption: 'salt=c6JQl9eJ0VvwrUVCQDxY7Q',
encoding: 'aesgcm',
crypto_key: "dh=BCHn-I-J3dfPRLJBlNZ3xFoAqaBLZ6qdhpaz9W7Q00JW1oD-hTxyEECn6KYJNK8AxKUyIDwn6Icx_PYWJiEYjQ0",
encryption: "salt=c6JQl9eJ0VvwrUVCQDxY7Q",
encoding: "aesgcm",
},
expected: /Bad encryption/,
}, {
// The plaintext is "O hai". The ciphertext is exactly `rs + 16` bytes,
// but we didn't include the empty trailing block that aesgcm requires for
// exact multiples.
desc: 'rs = 7, no trailing block',
data: 'YG4F-b06y590hRlnSsw_vuOw62V9Iz8',
authSecret: 'QoDi0u6vcslIVJKiouXMXw',
desc: "rs = 7, no trailing block",
data: "YG4F-b06y590hRlnSsw_vuOw62V9Iz8",
authSecret: "QoDi0u6vcslIVJKiouXMXw",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: '2bu4paOAZbL2ef1u-wTzONuTIcDPc00o0zUJgg46XTc',
x: 'uEvLZUMVn1my0cwnLdcFT0mj1gSU5uzI3HeGwXC7jX8',
y: 'SfNVLGL-FurydsuzciDfw8K1cUHyoDWnJJ_16UG6Dbo',
kty: "EC",
crv: "P-256",
d: "2bu4paOAZbL2ef1u-wTzONuTIcDPc00o0zUJgg46XTc",
x: "uEvLZUMVn1my0cwnLdcFT0mj1gSU5uzI3HeGwXC7jX8",
y: "SfNVLGL-FurydsuzciDfw8K1cUHyoDWnJJ_16UG6Dbo",
ext: true,
},
publicKey: 'BLhLy2VDFZ9ZstHMJy3XBU9Jo9YElObsyNx3hsFwu41_SfNVLGL-FurydsuzciDfw8K1cUHyoDWnJJ_16UG6Dbo',
publicKey: "BLhLy2VDFZ9ZstHMJy3XBU9Jo9YElObsyNx3hsFwu41_SfNVLGL-FurydsuzciDfw8K1cUHyoDWnJJ_16UG6Dbo",
headers: {
crypto_key: 'dh=BD_bsTUpxBMvSv8eksith3vijMLj44D4jhJjO51y7wK1ytbUlsyYBBYYyB5AAe5bnREA_WipTgemDVz00LiWcfM',
encryption: 'salt=xKWvs_jWWeg4KOsot_uBhA; rs=7',
encoding: 'aesgcm',
crypto_key: "dh=BD_bsTUpxBMvSv8eksith3vijMLj44D4jhJjO51y7wK1ytbUlsyYBBYYyB5AAe5bnREA_WipTgemDVz00LiWcfM",
encryption: "salt=xKWvs_jWWeg4KOsot_uBhA; rs=7",
encoding: "aesgcm",
},
expected: /Encrypted data truncated/,
}, {
// The last block is only 1 byte, but valid blocks must be at least 2 bytes.
desc: 'Pad size > last block length',
data: 'JvX9HsJ4lL5gzP8_uCKc6s15iRIaNhD4pFCgq5-dfwbUqEcNUkqv',
authSecret: 'QtGZeY8MQfCaq-XwKOVGBQ',
desc: "Pad size > last block length",
data: "JvX9HsJ4lL5gzP8_uCKc6s15iRIaNhD4pFCgq5-dfwbUqEcNUkqv",
authSecret: "QtGZeY8MQfCaq-XwKOVGBQ",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'CosERAVXgvTvoh7UkrRC2V-iXoNs0bXle9I68qzkles',
x: '_D0YqEwirvTJQJdjG6xXrjstMVpeAzf221cUqZz6hgY',
y: '9MnFbM7U14uiYMDI5e2I4jN29tYmsM9F66QodhKmA-c',
kty: "EC",
crv: "P-256",
d: "CosERAVXgvTvoh7UkrRC2V-iXoNs0bXle9I68qzkles",
x: "_D0YqEwirvTJQJdjG6xXrjstMVpeAzf221cUqZz6hgY",
y: "9MnFbM7U14uiYMDI5e2I4jN29tYmsM9F66QodhKmA-c",
ext: true,
},
publicKey: 'BPw9GKhMIq70yUCXYxusV647LTFaXgM39ttXFKmc-oYG9MnFbM7U14uiYMDI5e2I4jN29tYmsM9F66QodhKmA-c',
publicKey: "BPw9GKhMIq70yUCXYxusV647LTFaXgM39ttXFKmc-oYG9MnFbM7U14uiYMDI5e2I4jN29tYmsM9F66QodhKmA-c",
headers: {
crypto_key: 'dh=BBNZNEi5Ew_ID5S4Y9jWBi1NeVDje6Mjs7SDLViUn6A8VAZj-6X3QAuYQ3j20BblqjwTgYst7PRnY6UGrKyLbmU',
encryption: 'salt=ot8hzbwOo6CYe6ZhdlwKtg; rs=6',
encoding: 'aesgcm',
crypto_key: "dh=BBNZNEi5Ew_ID5S4Y9jWBi1NeVDje6Mjs7SDLViUn6A8VAZj-6X3QAuYQ3j20BblqjwTgYst7PRnY6UGrKyLbmU",
encryption: "salt=ot8hzbwOo6CYe6ZhdlwKtg; rs=6",
encoding: "aesgcm",
},
expected: /Decoded array is too short/,
}, {
// The last block is 3 bytes (2 bytes for the pad length; 1 byte of data),
// but claims its pad length is 2.
desc: 'Padding length > last block length',
data: 'oWSOFA-UO5oWq-kI79RHaFfwAejLiQJ4C7eTmrSTBl4gArLXfx7lZ-Y',
authSecret: 'gKG_P6-de5pyzS8hyH_NyQ',
desc: "Padding length > last block length",
data: "oWSOFA-UO5oWq-kI79RHaFfwAejLiQJ4C7eTmrSTBl4gArLXfx7lZ-Y",
authSecret: "gKG_P6-de5pyzS8hyH_NyQ",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: '9l-ahcBM-I0ykwbWiDS9KRrPdhyvTZ0SxKiPpj2aeaI',
x: 'qx0tU4EDaQv6ayFA3xvLLBdMmn4mLxjn7SK6mIeIxeg',
y: 'ymbMcmUOEyh_-rLrBsi26NG4UFCis2MTDs5FG2VdDPI',
kty: "EC",
crv: "P-256",
d: "9l-ahcBM-I0ykwbWiDS9KRrPdhyvTZ0SxKiPpj2aeaI",
x: "qx0tU4EDaQv6ayFA3xvLLBdMmn4mLxjn7SK6mIeIxeg",
y: "ymbMcmUOEyh_-rLrBsi26NG4UFCis2MTDs5FG2VdDPI",
ext: true,
},
publicKey: 'BKsdLVOBA2kL-mshQN8byywXTJp-Ji8Y5-0iupiHiMXoymbMcmUOEyh_-rLrBsi26NG4UFCis2MTDs5FG2VdDPI',
publicKey: "BKsdLVOBA2kL-mshQN8byywXTJp-Ji8Y5-0iupiHiMXoymbMcmUOEyh_-rLrBsi26NG4UFCis2MTDs5FG2VdDPI",
headers: {
crypto_key: 'dh=BKe2IBO_cwmEzQyTVscSbQcj0Y3uBSzGZ_mHlANMciS8uGpb7U8_Bw7TNdlYfpwWDLd0cxM8YYWNDbNJ_p2Rp4o',
encryption: 'salt=z7QJ6UR89SiFRkd4RsC4Vg; rs=6',
encoding: 'aesgcm',
crypto_key: "dh=BKe2IBO_cwmEzQyTVscSbQcj0Y3uBSzGZ_mHlANMciS8uGpb7U8_Bw7TNdlYfpwWDLd0cxM8YYWNDbNJ_p2Rp4o",
encryption: "salt=z7QJ6UR89SiFRkd4RsC4Vg; rs=6",
encoding: "aesgcm",
},
expected: /Padding is wrong/,
}, {
// The first block has no padding, but claims its pad length is 1.
desc: 'Non-zero padding',
data: 'Qdvjh0LkZXKu_1Hvv56D0rOSF6Mww3y0F8xkxUNlwVu2U1iakOUUGRs',
authSecret: 'cMpWQW58BrpDbJ8KqbS9ig',
desc: "Non-zero padding",
data: "Qdvjh0LkZXKu_1Hvv56D0rOSF6Mww3y0F8xkxUNlwVu2U1iakOUUGRs",
authSecret: "cMpWQW58BrpDbJ8KqbS9ig",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'IzuaxLqFJmjSu8GjLCo2oEaDZjDButW4m4T0qx02XsM',
x: 'Xy7vt_TJTynxwWsQyY069BcKmrhkRjhKPFuTi-AphoY',
y: '0M10IVM1ourR7Q5AUX2b2fgdmGyTWcYsdHcdFK_b4Hk',
kty: "EC",
crv: "P-256",
d: "IzuaxLqFJmjSu8GjLCo2oEaDZjDButW4m4T0qx02XsM",
x: "Xy7vt_TJTynxwWsQyY069BcKmrhkRjhKPFuTi-AphoY",
y: "0M10IVM1ourR7Q5AUX2b2fgdmGyTWcYsdHcdFK_b4Hk",
ext: true,
},
publicKey: 'BF8u77f0yU8p8cFrEMmNOvQXCpq4ZEY4Sjxbk4vgKYaG0M10IVM1ourR7Q5AUX2b2fgdmGyTWcYsdHcdFK_b4Hk',
publicKey: "BF8u77f0yU8p8cFrEMmNOvQXCpq4ZEY4Sjxbk4vgKYaG0M10IVM1ourR7Q5AUX2b2fgdmGyTWcYsdHcdFK_b4Hk",
headers: {
crypto_key: 'dh=BBicj01QI0ryiFzAaty9VpW_crgq9XbU1bOCtEZI9UNE6tuOgp4lyN_UN0N905ECnLWK5v_sCPUIxnQgOuCseSo',
encryption: 'salt=SbkGHONbQBBsBcj9dLyIUw; rs=6',
encoding: 'aesgcm',
crypto_key: "dh=BBicj01QI0ryiFzAaty9VpW_crgq9XbU1bOCtEZI9UNE6tuOgp4lyN_UN0N905ECnLWK5v_sCPUIxnQgOuCseSo",
encryption: "salt=SbkGHONbQBBsBcj9dLyIUw; rs=6",
encoding: "aesgcm",
},
expected: /Padding is wrong/,
}, {
// The first record is 22 bytes: 2 bytes for the pad length, 4 bytes of
// data, and a 16-byte auth tag. The second "record" is missing the pad
// and data, and contains just the auth tag.
desc: 'rs = 6, second record truncated to only auth tag',
data: 'C7u3j5AL4Yzh2yYB_umN6tzrVHxrt7D5baTEW9DE1Bk3up9fY4w',
authSecret: '3rWhsRCU_KdaqfKPbd3zBQ',
desc: "rs = 6, second record truncated to only auth tag",
data: "C7u3j5AL4Yzh2yYB_umN6tzrVHxrt7D5baTEW9DE1Bk3up9fY4w",
authSecret: "3rWhsRCU_KdaqfKPbd3zBQ",
privateKey: {
kty: 'EC',
crv: 'P-256',
d: 'nhOT9171xuoQBJGkiZ3aqT5qw_ILJ94_PPiVNu1LFSY',
x: 'lCj7ctQTmRfwzTMcODlNfHjFMAHmgdI44OhTQXX_xpE',
y: 'WBdgz4GWGtGAisC63O9DtP5l--hnCzPZiV-YZ-a6Lcw',
kty: "EC",
crv: "P-256",
d: "nhOT9171xuoQBJGkiZ3aqT5qw_ILJ94_PPiVNu1LFSY",
x: "lCj7ctQTmRfwzTMcODlNfHjFMAHmgdI44OhTQXX_xpE",
y: "WBdgz4GWGtGAisC63O9DtP5l--hnCzPZiV-YZ-a6Lcw",
ext: true,
},
publicKey: 'BJQo-3LUE5kX8M0zHDg5TXx4xTAB5oHSOODoU0F1_8aRWBdgz4GWGtGAisC63O9DtP5l--hnCzPZiV-YZ-a6Lcw',
publicKey: "BJQo-3LUE5kX8M0zHDg5TXx4xTAB5oHSOODoU0F1_8aRWBdgz4GWGtGAisC63O9DtP5l--hnCzPZiV-YZ-a6Lcw",
headers: {
crypto_key: 'dh=BI38Qs_OhDmQIxbszc6Nako-MrX3FzAE_8HzxM1wgoEIG4ocxyF-YAAVhfkpJUvDpRyKW2LDHIaoylaZuxQfRhE',
encryption: 'salt=QClh48OlvGpSjZ0Mg0e8rg; rs=6',
encoding: 'aesgcm',
crypto_key: "dh=BI38Qs_OhDmQIxbszc6Nako-MrX3FzAE_8HzxM1wgoEIG4ocxyF-YAAVhfkpJUvDpRyKW2LDHIaoylaZuxQfRhE",
encryption: "salt=QClh48OlvGpSjZ0Mg0e8rg; rs=6",
encoding: "aesgcm",
},
expected: /Decoded array is too short/,
}];
@ -493,15 +493,15 @@ add_task(async function test_aesgcm_err() {
add_task(async function test_aesgcm128_ok() {
let expectedSuccesses = [{
desc: 'padSize = 1, rs = 4096, pad = 2',
result: 'aesgcm128 encrypted message',
data: 'ljBJ44NPzJFH9EuyT5xWMU4vpZ90MdAqaq1TC1kOLRoPNHtNFXeJ0GtuSaE',
desc: "padSize = 1, rs = 4096, pad = 2",
result: "aesgcm128 encrypted message",
data: "ljBJ44NPzJFH9EuyT5xWMU4vpZ90MdAqaq1TC1kOLRoPNHtNFXeJ0GtuSaE",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
encryption_key: 'dh=BOmnfg02vNd6RZ7kXWWrCGFF92bI-rQ-bV0Pku3-KmlHwbGv4ejWqgasEdLGle5Rhmp6SKJunZw2l2HxKvrIjfI',
encryption: 'salt=btxxUtclbmgcc30b9rT3Bg; rs=4096',
encoding: 'aesgcm128',
encryption_key: "dh=BOmnfg02vNd6RZ7kXWWrCGFF92bI-rQ-bV0Pku3-KmlHwbGv4ejWqgasEdLGle5Rhmp6SKJunZw2l2HxKvrIjfI",
encryption: "salt=btxxUtclbmgcc30b9rT3Bg; rs=4096",
encoding: "aesgcm128",
},
}];
for (let test of expectedSuccesses) {
@ -513,49 +513,49 @@ add_task(async function test_aesgcm128_err() {
let expectedFailures = [{
// aesgcm128 doesn't use an auth secret, but we've mixed one in during
// encryption, so the decryption key and nonce won't match.
desc: 'padSize = 1, rs = 4096, auth secret, pad = 8',
data: 'h0FmyldY8aT5EQ6CJrbfRn_IdDvytoLeHb9_q5CjtdFRfgDRknxLmOzavLaVG4oOiS0r',
authSecret: 'Sxb6u0gJIhGEogyLawjmCw',
desc: "padSize = 1, rs = 4096, auth secret, pad = 8",
data: "h0FmyldY8aT5EQ6CJrbfRn_IdDvytoLeHb9_q5CjtdFRfgDRknxLmOzavLaVG4oOiS0r",
authSecret: "Sxb6u0gJIhGEogyLawjmCw",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BCXHk7O8CE-9AOp6xx7g7c-NCaNpns1PyyHpdcmDaijLbT6IdGq0ezGatBwtFc34BBfscFxdk4Tjksa2Mx5rRCM',
encryption: 'salt=aGBpoKklLtrLcAUCcCr7JQ',
encoding: 'aesgcm128',
crypto_key: "dh=BCXHk7O8CE-9AOp6xx7g7c-NCaNpns1PyyHpdcmDaijLbT6IdGq0ezGatBwtFc34BBfscFxdk4Tjksa2Mx5rRCM",
encryption: "salt=aGBpoKklLtrLcAUCcCr7JQ",
encoding: "aesgcm128",
},
expected: /Missing Encryption-Key header/,
}, {
// The first byte of each record must be the pad length.
desc: 'Missing padding',
data: 'anvsHj7oBQTPMhv7XSJEsvyMS4-8EtbC7HgFZsKaTg',
desc: "Missing padding",
data: "anvsHj7oBQTPMhv7XSJEsvyMS4-8EtbC7HgFZsKaTg",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BMSqfc3ohqw2DDgu3nsMESagYGWubswQPGxrW1bAbYKD18dIHQBUmD3ul_lu7MyQiT5gNdzn5JTXQvCcpf-oZE4',
encryption: 'salt=Czx2i18rar8XWOXAVDnUuw',
encoding: 'aesgcm128',
crypto_key: "dh=BMSqfc3ohqw2DDgu3nsMESagYGWubswQPGxrW1bAbYKD18dIHQBUmD3ul_lu7MyQiT5gNdzn5JTXQvCcpf-oZE4",
encryption: "salt=Czx2i18rar8XWOXAVDnUuw",
encoding: "aesgcm128",
},
expected: /Missing Encryption-Key header/,
}, {
desc: 'Truncated input',
data: 'AlDjj6NvT5HGyrHbT8M5D6XBFSra6xrWS9B2ROaCIjwSu3RyZ1iyuv0',
desc: "Truncated input",
data: "AlDjj6NvT5HGyrHbT8M5D6XBFSra6xrWS9B2ROaCIjwSu3RyZ1iyuv0",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BCHn-I-J3dfPRLJBlNZ3xFoAqaBLZ6qdhpaz9W7Q00JW1oD-hTxyEECn6KYJNK8AxKUyIDwn6Icx_PYWJiEYjQ0',
encryption: 'salt=c6JQl9eJ0VvwrUVCQDxY7Q; rs=25',
encoding: 'aesgcm128',
crypto_key: "dh=BCHn-I-J3dfPRLJBlNZ3xFoAqaBLZ6qdhpaz9W7Q00JW1oD-hTxyEECn6KYJNK8AxKUyIDwn6Icx_PYWJiEYjQ0",
encryption: "salt=c6JQl9eJ0VvwrUVCQDxY7Q; rs=25",
encoding: "aesgcm128",
},
expected: /Missing Encryption-Key header/,
}, {
desc: 'Padding length > rs',
data: 'Ct_h1g7O55e6GvuhmpjLsGnv8Rmwvxgw8iDESNKGxk_8E99iHKDzdV8wJPyHA-6b2E6kzuVa5UWiQ7s4Zms1xzJ4FKgoxvBObXkc_r_d4mnb-j245z3AcvRmcYGk5_HZ0ci26SfhAN3lCgxGzTHS4nuHBRkGwOb4Tj4SFyBRlLoTh2jyVK2jYugNjH9tTrGOBg7lP5lajLTQlxOi91-RYZSfFhsLX3LrAkXuRoN7G1CdiI7Y3_eTgbPIPabDcLCnGzmFBTvoJSaQF17huMl_UnWoCj2WovA4BwK_TvWSbdgElNnQ4CbArJ1h9OqhDOphVu5GUGr94iitXRQR-fqKPMad0ULLjKQWZOnjuIdV1RYEZ873r62Yyd31HoveJcSDb1T8l_QK2zVF8V4k0xmK9hGuC0rF5YJPYPHgl5__usknzxMBnRrfV5_MOL5uPZwUEFsu',
desc: "Padding length > rs",
data: "Ct_h1g7O55e6GvuhmpjLsGnv8Rmwvxgw8iDESNKGxk_8E99iHKDzdV8wJPyHA-6b2E6kzuVa5UWiQ7s4Zms1xzJ4FKgoxvBObXkc_r_d4mnb-j245z3AcvRmcYGk5_HZ0ci26SfhAN3lCgxGzTHS4nuHBRkGwOb4Tj4SFyBRlLoTh2jyVK2jYugNjH9tTrGOBg7lP5lajLTQlxOi91-RYZSfFhsLX3LrAkXuRoN7G1CdiI7Y3_eTgbPIPabDcLCnGzmFBTvoJSaQF17huMl_UnWoCj2WovA4BwK_TvWSbdgElNnQ4CbArJ1h9OqhDOphVu5GUGr94iitXRQR-fqKPMad0ULLjKQWZOnjuIdV1RYEZ873r62Yyd31HoveJcSDb1T8l_QK2zVF8V4k0xmK9hGuC0rF5YJPYPHgl5__usknzxMBnRrfV5_MOL5uPZwUEFsu",
privateKey: LEGACY_PRIVATE_KEY,
publicKey: LEGACY_PUBLIC_KEY,
headers: {
crypto_key: 'dh=BAcMdWLJRGx-kPpeFtwqR3GE1LWzd1TYh2rg6CEFu53O-y3DNLkNe_BtGtKRR4f7ZqpBMVS6NgfE2NwNPm3Ndls',
encryption: 'salt=NQVTKhB0rpL7ZzKkotTGlA; rs=1',
encoding: 'aesgcm128',
crypto_key: "dh=BAcMdWLJRGx-kPpeFtwqR3GE1LWzd1TYh2rg6CEFu53O-y3DNLkNe_BtGtKRR4f7ZqpBMVS6NgfE2NwNPm3Ndls",
encryption: "salt=NQVTKhB0rpL7ZzKkotTGlA; rs=1",
encoding: "aesgcm128",
},
expected: /Missing Encryption-Key header/,
}];

Просмотреть файл

@ -7,9 +7,9 @@ const {PushCrypto} = ChromeUtils.import("resource://gre/modules/PushCrypto.jsm")
let from64 = v => {
// allow whitespace in the strings.
let stripped = v.replace(/ |\t|\r|\n/g, '');
let stripped = v.replace(/ |\t|\r|\n/g, "");
return new Uint8Array(ChromeUtils.base64URLDecode(stripped, {padding: "reject"}));
}
};
let to64 = v => ChromeUtils.base64URLEncode(v, {pad: false});
@ -24,13 +24,13 @@ async function importKeyPair(publicKeyBuffer, privateKeyBuffer) {
y: to64(publicKeyBuffer.slice(33, 65)),
ext: true,
};
let publicKey = await crypto.subtle.importKey('jwk', jwk,
{ name: 'ECDH', namedCurve: 'P-256' },
let publicKey = await crypto.subtle.importKey("jwk", jwk,
{ name: "ECDH", namedCurve: "P-256" },
true, []);
jwk.d = to64(privateKeyBuffer);
let privateKey = await crypto.subtle.importKey('jwk', jwk,
{ name: 'ECDH', namedCurve: 'P-256' },
true, ['deriveBits']);
let privateKey = await crypto.subtle.importKey("jwk", jwk,
{ name: "ECDH", namedCurve: "P-256" },
true, ["deriveBits"]);
return {publicKey, privateKey};
}
@ -55,14 +55,10 @@ add_task(async function static_aes128gcm() {
salt: from64("DGv6ra1nlYgDCS1FRnbzlw"),
};
let publicKeyBuffer = from64(`BP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZ
IIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A8`);
let privateKeyBuffer = from64("yfWPiYE-n46HLnH0KqZOF1fJJU3MYrct3AELtAQ-oRw");
let options = {
senderKeyPair: await importKeyPair(fixture.sender.public, fixture.sender.private),
salt: fixture.salt,
}
};
let {ciphertext, encoding} = await PushCrypto.encrypt(fixture.plaintext,
fixture.receiver.public,
@ -130,7 +126,7 @@ add_task(async function aes128gcm_rs() {
add_task(async function aes128gcm_edgecases() {
let [recvPublicKey, recvPrivateKey] = await PushCrypto.generateKeys();
for (let size of [0, 4096-16, 4096-16-1, 4096-16+1,
for (let size of [0, 4096 - 16, 4096 - 16 - 1, 4096 - 16 + 1,
4095, 4096, 4097, 10240]) {
info(`testing encryption of ${size} byte payload`);
let message = new TextEncoder("utf-8").encode("x".repeat(size));

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '2c43af06-ab6e-476a-adc4-16cbda54fb89';
const userAgentID = "2c43af06-ab6e-476a-adc4-16cbda54fb89";
var db;
var quotaURI;
@ -13,33 +13,33 @@ var permURI;
function visitURI(uri, timestamp) {
return PlacesTestUtils.addVisits({
uri: uri,
uri,
title: uri.spec,
visitDate: timestamp * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
});
}
var putRecord = async function({scope, perm, quota, lastPush, lastVisit}) {
let uri = Services.io.newURI(scope);
Services.perms.add(uri, 'desktop-notification',
Services.perms.add(uri, "desktop-notification",
Ci.nsIPermissionManager[perm]);
registerCleanupFunction(() => {
Services.perms.remove(uri, 'desktop-notification');
Services.perms.remove(uri, "desktop-notification");
});
await visitURI(uri, lastVisit);
await db.put({
channelID: uri.pathQueryRef,
pushEndpoint: 'https://example.org/push' + uri.pathQueryRef,
pushEndpoint: "https://example.org/push" + uri.pathQueryRef,
scope: uri.spec,
pushCount: 0,
lastPush: lastPush,
lastPush,
version: null,
originAttributes: '',
quota: quota,
originAttributes: "",
quota,
});
return uri;
@ -48,11 +48,11 @@ var putRecord = async function({scope, perm, quota, lastPush, lastVisit}) {
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
run_next_test();
}
@ -62,8 +62,8 @@ add_task(async function setUp() {
// granted for this origin, and the last visit is more recent than the last
// push message.
await putRecord({
scope: 'https://example.com/expired-quota-restored',
perm: 'ALLOW_ACTION',
scope: "https://example.com/expired-quota-restored",
perm: "ALLOW_ACTION",
quota: 0,
lastPush: Date.now() - 10,
lastVisit: Date.now(),
@ -72,8 +72,8 @@ add_task(async function setUp() {
// An expired registration that we should evict when the origin is visited
// again.
quotaURI = await putRecord({
scope: 'https://example.xyz/expired-quota-exceeded',
perm: 'ALLOW_ACTION',
scope: "https://example.xyz/expired-quota-exceeded",
perm: "ALLOW_ACTION",
quota: 0,
lastPush: Date.now() - 10,
lastVisit: Date.now() - 20,
@ -82,8 +82,8 @@ add_task(async function setUp() {
// An expired registration that we should evict when permission is granted
// again.
permURI = await putRecord({
scope: 'https://example.info/expired-perm-revoked',
perm: 'DENY_ACTION',
scope: "https://example.info/expired-perm-revoked",
perm: "DENY_ACTION",
quota: 0,
lastPush: Date.now() - 10,
lastVisit: Date.now(),
@ -91,8 +91,8 @@ add_task(async function setUp() {
// An active registration that we should leave alone.
await putRecord({
scope: 'https://example.ninja/active',
perm: 'ALLOW_ACTION',
scope: "https://example.ninja/active",
perm: "ALLOW_ACTION",
quota: 16,
lastPush: Date.now() - 10,
lastVisit: Date.now() - 20,
@ -100,24 +100,24 @@ add_task(async function setUp() {
let subChangePromise = promiseObserverNotification(
PushServiceComponent.subscriptionChangeTopic,
(subject, data) => data == 'https://example.com/expired-quota-restored'
(subject, data) => data == "https://example.com/expired-quota-restored"
);
PushService.init({
serverURI: 'wss://push.example.org/',
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
},
onUnregister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
channelID: request.channelID,
status: 200,
}));
@ -132,11 +132,11 @@ add_task(async function setUp() {
add_task(async function test_site_visited() {
let subChangePromise = promiseObserverNotification(
PushServiceComponent.subscriptionChangeTopic,
(subject, data) => data == 'https://example.xyz/expired-quota-exceeded'
(subject, data) => data == "https://example.xyz/expired-quota-exceeded"
);
await visitURI(quotaURI, Date.now());
PushService.observe(null, 'idle-daily', '');
PushService.observe(null, "idle-daily", "");
await subChangePromise;
});
@ -144,10 +144,10 @@ add_task(async function test_site_visited() {
add_task(async function test_perm_restored() {
let subChangePromise = promiseObserverNotification(
PushServiceComponent.subscriptionChangeTopic,
(subject, data) => data == 'https://example.info/expired-perm-revoked'
(subject, data) => data == "https://example.info/expired-perm-revoked"
);
Services.perms.add(permURI, 'desktop-notification',
Services.perms.add(permURI, "desktop-notification",
Ci.nsIPermissionManager.ALLOW_ACTION);
await subChangePromise;

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
var userAgentID = '5ab1d1df-7a3d-4024-a469-b9e1bb399fad';
var userAgentID = "5ab1d1df-7a3d-4024-a469-b9e1bb399fad";
function run_test() {
do_get_profile();
@ -15,28 +15,28 @@ function run_test() {
add_task(async function test_notification_ack() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let records = [{
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
pushEndpoint: 'https://example.com/update/1',
scope: 'https://example.org/1',
originAttributes: '',
channelID: "21668e05-6da8-42c9-b8ab-9cc3f4d5630c",
pushEndpoint: "https://example.com/update/1",
scope: "https://example.org/1",
originAttributes: "",
version: 1,
quota: Infinity,
systemRecord: true,
}, {
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
pushEndpoint: 'https://example.com/update/2',
scope: 'https://example.org/2',
originAttributes: '',
channelID: "9a5ff87f-47c9-4215-b2b8-0bdd38b4b305",
pushEndpoint: "https://example.com/update/2",
scope: "https://example.org/2",
originAttributes: "",
version: 2,
quota: Infinity,
systemRecord: true,
}, {
channelID: '5477bfda-22db-45d4-9614-fee369630260',
pushEndpoint: 'https://example.com/update/3',
scope: 'https://example.org/3',
originAttributes: '',
channelID: "5477bfda-22db-45d4-9614-fee369630260",
pushEndpoint: "https://example.com/update/3",
scope: "https://example.org/3",
originAttributes: "",
version: 3,
quota: Infinity,
systemRecord: true,
@ -59,65 +59,65 @@ add_task(async function test_notification_ack() {
return new MockWebSocket(uri, {
onHello(request) {
equal(request.uaid, userAgentID,
'Should send matching device IDs in handshake');
"Should send matching device IDs in handshake");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
uaid: userAgentID,
status: 200
status: 200,
}));
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
version: 2
}]
channelID: "21668e05-6da8-42c9-b8ab-9cc3f4d5630c",
version: 2,
}],
}));
},
onACK(request) {
equal(request.messageType, 'ack', 'Should send acknowledgements');
equal(request.messageType, "ack", "Should send acknowledgements");
let updates = request.updates;
switch (++acks) {
case 1:
deepEqual([{
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
channelID: "21668e05-6da8-42c9-b8ab-9cc3f4d5630c",
version: 2,
code: 100,
}], updates, 'Wrong updates for acknowledgement 1');
}], updates, "Wrong updates for acknowledgement 1");
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
version: 4
channelID: "9a5ff87f-47c9-4215-b2b8-0bdd38b4b305",
version: 4,
}, {
channelID: '5477bfda-22db-45d4-9614-fee369630260',
version: 6
}]
channelID: "5477bfda-22db-45d4-9614-fee369630260",
version: 6,
}],
}));
break;
case 2:
deepEqual([{
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
channelID: "9a5ff87f-47c9-4215-b2b8-0bdd38b4b305",
version: 4,
code: 100,
}], updates, 'Wrong updates for acknowledgement 2');
}], updates, "Wrong updates for acknowledgement 2");
break;
case 3:
deepEqual([{
channelID: '5477bfda-22db-45d4-9614-fee369630260',
channelID: "5477bfda-22db-45d4-9614-fee369630260",
version: 6,
code: 100,
}], updates, 'Wrong updates for acknowledgement 3');
}], updates, "Wrong updates for acknowledgement 3");
ackDone();
break;
default:
ok(false, 'Unexpected acknowledgement ' + acks);
ok(false, "Unexpected acknowledgement " + acks);
}
}
},
});
}
},
});
await notifyPromise;

Просмотреть файл

@ -1,29 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
let db;
let userAgentID = 'f5b47f8d-771f-4ea3-b999-91c135f8766d';
let userAgentID = "f5b47f8d-771f-4ea3-b999-91c135f8766d";
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
function putRecord(channelID, scope, publicKey, privateKey, authSecret) {
return db.put({
channelID: channelID,
pushEndpoint: 'https://example.org/push/' + channelID,
scope: scope,
channelID,
pushEndpoint: "https://example.org/push/" + channelID,
scope,
pushCount: 0,
lastPush: 0,
originAttributes: '',
originAttributes: "",
quota: Infinity,
systemRecord: true,
p256dhPublicKey: ChromeUtils.base64URLDecode(publicKey, {
@ -40,52 +40,52 @@ let ackDone;
let server;
add_task(async function test_notification_ack_data_setup() {
db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await putRecord(
'subscription1',
'https://example.com/page/1',
'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA',
"subscription1",
"https://example.com/page/1",
"BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA",
{
crv: 'P-256',
d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM',
crv: "P-256",
d: "1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM",
ext: true,
key_ops: ["deriveBits"],
kty: "EC",
x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
x: "8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM",
y: "26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA",
},
'c_sGN6uCv9Hu7JOQT34jAQ'
"c_sGN6uCv9Hu7JOQT34jAQ"
);
await putRecord(
'subscription2',
'https://example.com/page/2',
'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E',
"subscription2",
"https://example.com/page/2",
"BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E",
{
crv: 'P-256',
d: 'lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4',
crv: "P-256",
d: "lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4",
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE',
y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E'
kty: "EC",
x: "-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE",
y: "5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E",
},
't3P246Gj9vjKDHHRYaY6hw'
"t3P246Gj9vjKDHHRYaY6hw"
);
await putRecord(
'subscription3',
'https://example.com/page/3',
'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI',
"subscription3",
"https://example.com/page/3",
"BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI",
{
crv: 'P-256',
d: 'Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8',
crv: "P-256",
d: "Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8",
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po',
y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI'
kty: "EC",
x: "OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po",
y: "Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI",
},
'E0qiXGWvFSR0PS352ES1_Q'
"E0qiXGWvFSR0PS352ES1_Q"
);
let setupDone;
@ -98,9 +98,9 @@ add_task(async function test_notification_ack_data_setup() {
return new MockWebSocket(uri, {
onHello(request) {
equal(request.uaid, userAgentID,
'Should send matching device IDs in handshake');
"Should send matching device IDs in handshake");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
uaid: userAgentID,
status: 200,
use_webpush: true,
@ -112,9 +112,9 @@ add_task(async function test_notification_ack_data_setup() {
if (ackDone) {
ackDone(request);
}
}
},
});
}
},
});
await setupDonePromise;
});
@ -122,121 +122,121 @@ add_task(async function test_notification_ack_data_setup() {
add_task(async function test_notification_ack_data() {
let allTestData = [
{
channelID: 'subscription1',
version: 'v1',
channelID: "subscription1",
version: "v1",
send: {
headers: {
encryption_key: 'keyid="notification1"; dh="BO_tgGm-yvYAGLeRe16AvhzaUcpYRiqgsGOlXpt0DRWDRGGdzVLGlEVJMygqAUECarLnxCiAOHTP_znkedrlWoU"',
encryption: 'keyid="notification1";salt="uAZaiXpOSfOLJxtOCZ09dA"',
encoding: 'aesgcm128',
encoding: "aesgcm128",
},
data: 'NwrrOWPxLE8Sv5Rr0Kep7n0-r_j3rsYrUw_CXPo',
version: 'v1',
data: "NwrrOWPxLE8Sv5Rr0Kep7n0-r_j3rsYrUw_CXPo",
version: "v1",
},
ackCode: 100,
receive: {
scope: 'https://example.com/page/1',
data: 'Some message'
}
scope: "https://example.com/page/1",
data: "Some message",
},
},
{
channelID: 'subscription2',
version: 'v2',
channelID: "subscription2",
version: "v2",
send: {
headers: {
encryption_key: 'keyid="notification2"; dh="BKVdQcgfncpNyNWsGrbecX0zq3eHIlHu5XbCGmVcxPnRSbhjrA6GyBIeGdqsUL69j5Z2CvbZd-9z1UBH0akUnGQ"',
encryption: 'keyid="notification2";salt="vFn3t3M_k42zHBdpch3VRw"',
encoding: 'aesgcm128',
encoding: "aesgcm128",
},
data: 'Zt9dEdqgHlyAL_l83385aEtb98ZBilz5tgnGgmwEsl5AOCNgesUUJ4p9qUU',
data: "Zt9dEdqgHlyAL_l83385aEtb98ZBilz5tgnGgmwEsl5AOCNgesUUJ4p9qUU",
},
ackCode: 100,
receive: {
scope: 'https://example.com/page/2',
data: 'Some message'
}
scope: "https://example.com/page/2",
data: "Some message",
},
},
{
channelID: 'subscription3',
version: 'v3',
channelID: "subscription3",
version: "v3",
send: {
headers: {
encryption_key: 'keyid="notification3";dh="BD3xV_ACT8r6hdIYES3BJj1qhz9wyv7MBrG9vM2UCnjPzwE_YFVpkD-SGqE-BR2--0M-Yf31wctwNsO1qjBUeMg"',
encryption: 'keyid="notification3"; salt="DFq188piWU7osPBgqn4Nlg"; rs=24',
encoding: 'aesgcm128',
encoding: "aesgcm128",
},
data: 'LKru3ZzxBZuAxYtsaCfaj_fehkrIvqbVd1iSwnwAUgnL-cTeDD-83blxHXTq7r0z9ydTdMtC3UjAcWi8LMnfY-BFzi0qJAjGYIikDA',
data: "LKru3ZzxBZuAxYtsaCfaj_fehkrIvqbVd1iSwnwAUgnL-cTeDD-83blxHXTq7r0z9ydTdMtC3UjAcWi8LMnfY-BFzi0qJAjGYIikDA",
},
ackCode: 100,
receive: {
scope: 'https://example.com/page/3',
data: 'Some message'
}
scope: "https://example.com/page/3",
data: "Some message",
},
},
// A message encoded with `aesgcm` (2 bytes of padding, authenticated).
{
channelID: 'subscription1',
version: 'v5',
channelID: "subscription1",
version: "v5",
send: {
headers: {
crypto_key: 'keyid=v4;dh="BMh_vsnqu79ZZkMTYkxl4gWDLdPSGE72Lr4w2hksSFW398xCMJszjzdblAWXyhSwakRNEU_GopAm4UGzyMVR83w"',
encryption: 'keyid="v4";salt="C14Wb7rQTlXzrgcPHtaUzw"',
encoding: 'aesgcm',
encoding: "aesgcm",
},
data: 'pus4kUaBWzraH34M-d_oN8e0LPpF_X6acx695AMXovDe',
data: "pus4kUaBWzraH34M-d_oN8e0LPpF_X6acx695AMXovDe",
},
ackCode: 100,
receive: {
scope: 'https://example.com/page/1',
data: 'Another message'
}
scope: "https://example.com/page/1",
data: "Another message",
},
},
// A message with 17 bytes of padding and rs of 24
{
channelID: 'subscription2',
version: 'v5',
channelID: "subscription2",
version: "v5",
send: {
headers: {
crypto_key: 'keyid="v5"; dh="BOp-DpyR9eLY5Ci11_loIFqeHzWfc_0evJmq7N8NKzgp60UAMMM06XIi2VZp2_TSdw1omk7E19SyeCCwRp76E-U"',
encryption: 'keyid=v5;salt="TvjOou1TqJOQY_ZsOYV3Ww";rs=24',
encoding: 'aesgcm',
encoding: "aesgcm",
},
data: 'rG9WYQ2ZwUgfj_tMlZ0vcIaNpBN05FW-9RUBZAM-UUZf0_9eGpuENBpUDAw3mFmd2XJpmvPvAtLVs54l3rGwg1o',
data: "rG9WYQ2ZwUgfj_tMlZ0vcIaNpBN05FW-9RUBZAM-UUZf0_9eGpuENBpUDAw3mFmd2XJpmvPvAtLVs54l3rGwg1o",
},
ackCode: 100,
receive: {
scope: 'https://example.com/page/2',
data: 'Some message'
}
scope: "https://example.com/page/2",
data: "Some message",
},
},
// A message without key identifiers.
{
channelID: 'subscription3',
version: 'v6',
channelID: "subscription3",
version: "v6",
send: {
headers: {
crypto_key: 'dh="BEEjwWbF5jZKCgW0kmUWgG-wNcRvaa9_3zZElHAF8przHwd4cp5_kQsc-IMNZcVA0iUix31jxuMOytU-5DwWtyQ"',
encryption: 'salt=aAQcr2khAksgNspPiFEqiQ',
encoding: 'aesgcm',
encryption: "salt=aAQcr2khAksgNspPiFEqiQ",
encoding: "aesgcm",
},
data: 'pEYgefdI-7L46CYn5dR9TIy2AXGxe07zxclbhstY',
data: "pEYgefdI-7L46CYn5dR9TIy2AXGxe07zxclbhstY",
},
ackCode: 100,
receive: {
scope: 'https://example.com/page/3',
data: 'Some message'
}
scope: "https://example.com/page/3",
data: "Some message",
},
},
// A malformed encrypted message.
{
channelID: 'subscription3',
version: 'v7',
channelID: "subscription3",
version: "v7",
send: {
headers: {
crypto_key: 'dh=AAAAAAAA',
encryption: 'salt=AAAAAAAA',
crypto_key: "dh=AAAAAAAA",
encryption: "salt=AAAAAAAA",
},
data: 'AAAAAAAA',
data: "AAAAAAAA",
},
ackCode: 101,
receive: null,
@ -247,26 +247,26 @@ add_task(async function test_notification_ack_data() {
let messageReceived = testData.receive ? promiseObserverNotification(PushServiceComponent.pushTopic, (subject, data) => {
let notification = subject.QueryInterface(Ci.nsIPushMessage).data;
equal(notification.text(), testData.receive.data,
'Check data for notification ' + testData.version);
"Check data for notification " + testData.version);
equal(data, testData.receive.scope,
'Check scope for notification ' + testData.version);
"Check scope for notification " + testData.version);
return true;
}) : Promise.resolve();
let ackReceived = new Promise(resolve => ackDone = resolve)
.then(ackData => {
deepEqual({
messageType: 'ack',
messageType: "ack",
updates: [{
channelID: testData.channelID,
version: testData.version,
code: testData.ackCode,
}],
}, ackData, 'Check updates for acknowledgment ' + testData.version);
}, ackData, "Check updates for acknowledgment " + testData.version);
});
let msg = JSON.parse(JSON.stringify(testData.send));
msg.messageType = 'notification';
msg.messageType = "notification";
msg.channelID = testData.channelID;
msg.version = testData.version;
server.serverSendMsg(JSON.stringify(msg));

Просмотреть файл

@ -1,17 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '1500e7d9-8cbe-4ee6-98da-7fa5d6a39852';
const userAgentID = "1500e7d9-8cbe-4ee6-98da-7fa5d6a39852";
function run_test() {
do_get_profile();
setPrefs({
maxRecentMessageIDsPerSubscription: 4,
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
@ -19,28 +19,28 @@ function run_test() {
// Should acknowledge duplicate notifications, but not notify apps.
add_task(async function test_notification_duplicate() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let records = [{
channelID: 'has-recents',
pushEndpoint: 'https://example.org/update/1',
scope: 'https://example.com/1',
channelID: "has-recents",
pushEndpoint: "https://example.org/update/1",
scope: "https://example.com/1",
originAttributes: "",
recentMessageIDs: ['dupe'],
recentMessageIDs: ["dupe"],
quota: Infinity,
systemRecord: true,
}, {
channelID: 'no-recents',
pushEndpoint: 'https://example.org/update/2',
scope: 'https://example.com/2',
channelID: "no-recents",
pushEndpoint: "https://example.org/update/2",
scope: "https://example.com/2",
originAttributes: "",
quota: Infinity,
systemRecord: true,
}, {
channelID: 'dropped-recents',
pushEndpoint: 'https://example.org/update/3',
scope: 'https://example.com/3',
originAttributes: '',
recentMessageIDs: ['newest', 'newer', 'older', 'oldest'],
channelID: "dropped-recents",
pushEndpoint: "https://example.org/update/3",
scope: "https://example.com/3",
originAttributes: "",
recentMessageIDs: ["newest", "newer", "older", "oldest"],
quota: Infinity,
systemRecord: true,
}];
@ -49,35 +49,35 @@ add_task(async function test_notification_duplicate() {
}
let testData = [{
channelID: 'has-recents',
channelID: "has-recents",
updates: 1,
acks: [{
version: 'dupe',
version: "dupe",
code: 102,
}, {
version: 'not-dupe',
version: "not-dupe",
code: 100,
}],
recents: ['not-dupe', 'dupe'],
recents: ["not-dupe", "dupe"],
}, {
channelID: 'no-recents',
channelID: "no-recents",
updates: 1,
acks: [{
version: 'not-dupe',
version: "not-dupe",
code: 100,
}],
recents: ['not-dupe'],
recents: ["not-dupe"],
}, {
channelID: 'dropped-recents',
channelID: "dropped-recents",
acks: [{
version: 'overflow',
version: "overflow",
code: 100,
}, {
version: 'oldest',
version: "oldest",
code: 100,
}],
updates: 2,
recents: ['oldest', 'overflow', 'newest', 'newer'],
recents: ["oldest", "overflow", "newest", "newer"],
}];
let expectedUpdates = testData.reduce((sum, {updates}) => sum + updates, 0);
@ -97,7 +97,7 @@ add_task(async function test_notification_duplicate() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
use_webpush: true,
@ -105,10 +105,10 @@ add_task(async function test_notification_duplicate() {
for (let {channelID, acks} of testData) {
for (let {version} of acks) {
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
channelID: channelID,
version: version,
}))
messageType: "notification",
channelID,
version,
}));
}
}
},
@ -117,8 +117,7 @@ add_task(async function test_notification_duplicate() {
let expectedData = testData.find(test =>
test.channelID == ack.channelID);
ok(expectedData, `Unexpected channel ${ack.channelID}`);
let expectedAck = expectedData.acks.find(expectedAck =>
expectedAck.version == ack.version);
let expectedAck = expectedData.acks.find(a => a.version == ack.version);
ok(expectedAck, `Unexpected ack for message ${
ack.version} on ${ack.channelID}`);
equal(expectedAck.code, ack.code, `Wrong ack status for message ${
@ -126,7 +125,7 @@ add_task(async function test_notification_duplicate() {
ackDone();
},
});
}
},
});
await notifyPromise;

Просмотреть файл

@ -1,46 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '3c7462fc-270f-45be-a459-b9d631b0d093';
const userAgentID = "3c7462fc-270f-45be-a459-b9d631b0d093";
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
add_task(async function test_notification_error() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let originAttributes = '';
let originAttributes = "";
let records = [{
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
pushEndpoint: 'https://example.org/update/success-1',
scope: 'https://example.com/a',
originAttributes: originAttributes,
channelID: "f04f1e46-9139-4826-b2d1-9411b0821283",
pushEndpoint: "https://example.org/update/success-1",
scope: "https://example.com/a",
originAttributes,
version: 1,
quota: Infinity,
systemRecord: true,
}, {
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
pushEndpoint: 'https://example.org/update/error',
scope: 'https://example.com/b',
originAttributes: originAttributes,
channelID: "3c3930ba-44de-40dc-a7ca-8a133ec1a866",
pushEndpoint: "https://example.org/update/error",
scope: "https://example.com/b",
originAttributes,
version: 2,
quota: Infinity,
systemRecord: true,
}, {
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
pushEndpoint: 'https://example.org/update/success-2',
scope: 'https://example.com/c',
originAttributes: originAttributes,
channelID: "b63f7bef-0a0d-4236-b41e-086a69dfd316",
pushEndpoint: "https://example.org/update/success-2",
scope: "https://example.com/c",
originAttributes,
version: 3,
quota: Infinity,
systemRecord: true,
@ -59,59 +59,59 @@ add_task(async function test_notification_error() {
serverURI: "wss://push.example.org/",
db: makeStub(db, {
getByKeyID(prev, channelID) {
if (channelID == '3c3930ba-44de-40dc-a7ca-8a133ec1a866') {
return Promise.reject('splines not reticulated');
if (channelID == "3c3930ba-44de-40dc-a7ca-8a133ec1a866") {
return Promise.reject("splines not reticulated");
}
return prev.call(this, channelID);
}
},
}),
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: records.map(({channelID, version}) =>
({channelID, version: ++version}))
({channelID, version: ++version})),
}));
},
// Should acknowledge all received updates, even if updating
// IndexedDB fails.
onACK: ackDone
onACK: ackDone,
});
}
},
});
await notifyPromise;
ok(scopes.includes('https://example.com/a'),
'Missing scope for notification A');
ok(scopes.includes('https://example.com/c'),
'Missing scope for notification C');
ok(scopes.includes("https://example.com/a"),
"Missing scope for notification A");
ok(scopes.includes("https://example.com/c"),
"Missing scope for notification C");
await ackPromise;
let aRecord = await db.getByIdentifiers({scope: 'https://example.com/a',
originAttributes: originAttributes });
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
'Wrong channel ID for record A');
let aRecord = await db.getByIdentifiers({scope: "https://example.com/a",
originAttributes });
equal(aRecord.channelID, "f04f1e46-9139-4826-b2d1-9411b0821283",
"Wrong channel ID for record A");
strictEqual(aRecord.version, 2,
'Should return the new version for record A');
"Should return the new version for record A");
let bRecord = await db.getByIdentifiers({scope: 'https://example.com/b',
originAttributes: originAttributes });
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
'Wrong channel ID for record B');
let bRecord = await db.getByIdentifiers({scope: "https://example.com/b",
originAttributes });
equal(bRecord.channelID, "3c3930ba-44de-40dc-a7ca-8a133ec1a866",
"Wrong channel ID for record B");
strictEqual(bRecord.version, 2,
'Should return the previous version for record B');
"Should return the previous version for record B");
let cRecord = await db.getByIdentifiers({scope: 'https://example.com/c',
originAttributes: originAttributes });
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
'Wrong channel ID for record C');
let cRecord = await db.getByIdentifiers({scope: "https://example.com/c",
originAttributes });
equal(cRecord.channelID, "b63f7bef-0a0d-4236-b41e-086a69dfd316",
"Wrong channel ID for record C");
strictEqual(cRecord.version, 4,
'Should return the new version for record C');
"Should return the new version for record C");
});

Просмотреть файл

@ -1,12 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var prefs;
var serverPort = -1;
function run_test() {
@ -14,25 +12,22 @@ function run_test() {
do_get_profile();
setPrefs({
'testing.allowInsecureServerURL': true,
"testing.allowInsecureServerURL": true,
});
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
// Set to allow the cert presented by our H2 server
var oldPref = prefs.getIntPref("network.http.speculative-parallel-limit");
prefs.setIntPref("network.http.speculative-parallel-limit", 0);
prefs.setBoolPref("dom.push.enabled", true);
prefs.setBoolPref("dom.push.connection.enabled", true);
var oldPref = Services.prefs.getIntPref("network.http.speculative-parallel-limit");
Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
Services.prefs.setBoolPref("dom.push.enabled", true);
Services.prefs.setBoolPref("dom.push.connection.enabled", true);
trustHttp2CA();
prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
Services.prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
run_next_test();
}
add_task(async function test_pushNotifications() {
// /pushNotifications/subscription1 will send a message with no rs and padding
// length 1.
// /pushNotifications/subscription2 will send a message with no rs and padding
@ -50,80 +45,80 @@ add_task(async function test_pushNotifications() {
var serverURL = "https://localhost:" + serverPort;
let records = [{
subscriptionUri: serverURL + '/pushNotifications/subscription1',
pushEndpoint: serverURL + '/pushEndpoint1',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint1',
scope: 'https://example.com/page/1',
p256dhPublicKey: 'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA',
subscriptionUri: serverURL + "/pushNotifications/subscription1",
pushEndpoint: serverURL + "/pushEndpoint1",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint1",
scope: "https://example.com/page/1",
p256dhPublicKey: "BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA",
p256dhPrivateKey: {
crv: 'P-256',
d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM',
crv: "P-256",
d: "1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM",
ext: true,
key_ops: ["deriveBits"],
kty: "EC",
x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
x: "8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM",
y: "26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA",
},
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
systemRecord: true,
}, {
subscriptionUri: serverURL + '/pushNotifications/subscription2',
pushEndpoint: serverURL + '/pushEndpoint2',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2',
scope: 'https://example.com/page/2',
p256dhPublicKey: 'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E',
subscriptionUri: serverURL + "/pushNotifications/subscription2",
pushEndpoint: serverURL + "/pushEndpoint2",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint2",
scope: "https://example.com/page/2",
p256dhPublicKey: "BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E",
p256dhPrivateKey: {
crv: 'P-256',
d: 'lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4',
crv: "P-256",
d: "lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4",
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE',
y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E'
kty: "EC",
x: "-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE",
y: "5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E",
},
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
systemRecord: true,
}, {
subscriptionUri: serverURL + '/pushNotifications/subscription3',
pushEndpoint: serverURL + '/pushEndpoint3',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3',
scope: 'https://example.com/page/3',
p256dhPublicKey: 'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI',
subscriptionUri: serverURL + "/pushNotifications/subscription3",
pushEndpoint: serverURL + "/pushEndpoint3",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint3",
scope: "https://example.com/page/3",
p256dhPublicKey: "BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI",
p256dhPrivateKey: {
crv: 'P-256',
d: 'Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8',
crv: "P-256",
d: "Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8",
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po',
y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI'
kty: "EC",
x: "OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po",
y: "Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI",
},
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
systemRecord: true,
}, {
subscriptionUri: serverURL + '/pushNotifications/subscription4',
pushEndpoint: serverURL + '/pushEndpoint4',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint4',
scope: 'https://example.com/page/4',
p256dhPublicKey: ChromeUtils.base64URLDecode('BEcvDzkWCrUtjU_wygL98sbQCQrW1lY9irtgGnlCc4B0JJXLCHB9MTM73qD6GZYfL0YOvKo8XLOflh-J4dMGklU', {
subscriptionUri: serverURL + "/pushNotifications/subscription4",
pushEndpoint: serverURL + "/pushEndpoint4",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint4",
scope: "https://example.com/page/4",
p256dhPublicKey: ChromeUtils.base64URLDecode("BEcvDzkWCrUtjU_wygL98sbQCQrW1lY9irtgGnlCc4B0JJXLCHB9MTM73qD6GZYfL0YOvKo8XLOflh-J4dMGklU", {
padding: "reject",
}),
p256dhPrivateKey: {
crv: 'P-256',
d: 'fWi7tZaX0Pk6WnLrjQ3kiRq_g5XStL5pdH4pllNCqXw',
crv: "P-256",
d: "fWi7tZaX0Pk6WnLrjQ3kiRq_g5XStL5pdH4pllNCqXw",
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: 'Ry8PORYKtS2NT_DKAv3yxtAJCtbWVj2Ku2AaeUJzgHQ',
y: 'JJXLCHB9MTM73qD6GZYfL0YOvKo8XLOflh-J4dMGklU'
kty: "EC",
x: "Ry8PORYKtS2NT_DKAv3yxtAJCtbWVj2Ku2AaeUJzgHQ",
y: "JJXLCHB9MTM73qD6GZYfL0YOvKo8XLOflh-J4dMGklU",
},
authenticationSecret: ChromeUtils.base64URLDecode('cwDVC1iwAn8E37mkR3tMSg', {
authenticationSecret: ChromeUtils.base64URLDecode("cwDVC1iwAn8E37mkR3tMSg", {
padding: "reject",
}),
originAttributes: ChromeUtils.originAttributesToSuffix(
@ -139,37 +134,41 @@ add_task(async function test_pushNotifications() {
let notifyPromise = Promise.all([
promiseObserverNotification(PushServiceComponent.pushTopic, function(subject, data) {
var message = subject.QueryInterface(Ci.nsIPushMessage).data;
if (message && (data == "https://example.com/page/1")){
if (message && (data == "https://example.com/page/1")) {
equal(message.text(), "Some message", "decoded message is incorrect");
return true;
}
return false;
}),
promiseObserverNotification(PushServiceComponent.pushTopic, function(subject, data) {
var message = subject.QueryInterface(Ci.nsIPushMessage).data;
if (message && (data == "https://example.com/page/2")){
if (message && (data == "https://example.com/page/2")) {
equal(message.text(), "Some message", "decoded message is incorrect");
return true;
}
return false;
}),
promiseObserverNotification(PushServiceComponent.pushTopic, function(subject, data) {
var message = subject.QueryInterface(Ci.nsIPushMessage).data;
if (message && (data == "https://example.com/page/3")){
if (message && (data == "https://example.com/page/3")) {
equal(message.text(), "Some message", "decoded message is incorrect");
return true;
}
return false;
}),
promiseObserverNotification(PushServiceComponent.pushTopic, function(subject, data) {
var message = subject.QueryInterface(Ci.nsIPushMessage).data;
if (message && (data == "https://example.com/page/4")){
if (message && (data == "https://example.com/page/4")) {
equal(message.text(), "Yet another message", "decoded message is incorrect");
return true;
}
return false;
}),
]);
PushService.init({
serverURI: serverURL,
db
db,
});
await notifyPromise;

Просмотреть файл

@ -1,50 +1,50 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '1ca1cf66-eeb4-4df7-87c1-d5c92906ab90';
const userAgentID = "1ca1cf66-eeb4-4df7-87c1-d5c92906ab90";
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
add_task(async function test_notification_incomplete() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let records = [{
channelID: '123',
pushEndpoint: 'https://example.org/update/1',
scope: 'https://example.com/page/1',
channelID: "123",
pushEndpoint: "https://example.org/update/1",
scope: "https://example.com/page/1",
version: 1,
originAttributes: '',
originAttributes: "",
quota: Infinity,
}, {
channelID: '3ad1ed95-d37a-4d88-950f-22cbe2e240d7',
pushEndpoint: 'https://example.org/update/2',
scope: 'https://example.com/page/2',
channelID: "3ad1ed95-d37a-4d88-950f-22cbe2e240d7",
pushEndpoint: "https://example.org/update/2",
scope: "https://example.com/page/2",
version: 1,
originAttributes: '',
originAttributes: "",
quota: Infinity,
}, {
channelID: 'd239498b-1c85-4486-b99b-205866e82d1f',
pushEndpoint: 'https://example.org/update/3',
scope: 'https://example.com/page/3',
channelID: "d239498b-1c85-4486-b99b-205866e82d1f",
pushEndpoint: "https://example.org/update/3",
scope: "https://example.com/page/3",
version: 3,
originAttributes: '',
originAttributes: "",
quota: Infinity,
}, {
channelID: 'a50de97d-b496-43ce-8b53-05522feb78db',
pushEndpoint: 'https://example.org/update/4',
scope: 'https://example.com/page/4',
channelID: "a50de97d-b496-43ce-8b53-05522feb78db",
pushEndpoint: "https://example.org/update/4",
scope: "https://example.com/page/4",
version: 10,
originAttributes: '',
originAttributes: "",
quota: Infinity,
}];
for (let record of records) {
@ -52,7 +52,7 @@ add_task(async function test_notification_incomplete() {
}
function observeMessage(subject, topic, data) {
ok(false, 'Should not deliver malformed updates');
ok(false, "Should not deliver malformed updates");
}
registerCleanupFunction(() =>
Services.obs.removeObserver(observeMessage, PushServiceComponent.pushTopic));
@ -72,39 +72,39 @@ add_task(async function test_notification_incomplete() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
this.serverSendMsg(JSON.stringify({
// Missing "updates" field; should ignore message.
messageType: 'notification'
messageType: "notification",
}));
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
// Wrong channel ID field type.
channelID: 123,
version: 3
version: 3,
}, {
// Missing version field.
channelID: '3ad1ed95-d37a-4d88-950f-22cbe2e240d7'
channelID: "3ad1ed95-d37a-4d88-950f-22cbe2e240d7",
}, {
// Wrong version field type.
channelID: 'd239498b-1c85-4486-b99b-205866e82d1f',
version: true
channelID: "d239498b-1c85-4486-b99b-205866e82d1f",
version: true,
}, {
// Negative versions should be ignored.
channelID: 'a50de97d-b496-43ce-8b53-05522feb78db',
version: -5
}]
channelID: "a50de97d-b496-43ce-8b53-05522feb78db",
version: -5,
}],
}));
},
onACK() {
ok(false, 'Should not acknowledge malformed updates');
}
ok(false, "Should not acknowledge malformed updates");
},
});
}
},
});
await notificationPromise;
@ -116,14 +116,14 @@ add_task(async function test_notification_incomplete() {
});
function recordIsEqual(a, b) {
strictEqual(a.channelID, b.channelID, 'Wrong channel ID in record');
strictEqual(a.pushEndpoint, b.pushEndpoint, 'Wrong push endpoint in record');
strictEqual(a.scope, b.scope, 'Wrong scope in record');
strictEqual(a.version, b.version, 'Wrong version in record');
strictEqual(a.channelID, b.channelID, "Wrong channel ID in record");
strictEqual(a.pushEndpoint, b.pushEndpoint, "Wrong push endpoint in record");
strictEqual(a.scope, b.scope, "Wrong scope in record");
strictEqual(a.version, b.version, "Wrong version in record");
}
function recordsAreEqual(a, b) {
equal(a.length, b.length, 'Mismatched record count');
equal(a.length, b.length, "Mismatched record count");
for (let i = 0; i < a.length; i++) {
recordIsEqual(a[i], b[i]);
}

Просмотреть файл

@ -1,28 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'ba31ac13-88d4-4984-8e6b-8731315a7cf8';
const userAgentID = "ba31ac13-88d4-4984-8e6b-8731315a7cf8";
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
add_task(async function test_notification_version_string() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await db.put({
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
pushEndpoint: 'https://example.org/updates/1',
scope: 'https://example.com/page/1',
originAttributes: '',
channelID: "6ff97d56-d0c0-43bc-8f5b-61b855e1d93b",
pushEndpoint: "https://example.org/updates/1",
scope: "https://example.com/page/1",
originAttributes: "",
version: 2,
quota: Infinity,
systemRecord: true,
@ -39,31 +39,31 @@ add_task(async function test_notification_version_string() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
version: '4'
}]
channelID: "6ff97d56-d0c0-43bc-8f5b-61b855e1d93b",
version: "4",
}],
}));
},
onACK: ackDone
onACK: ackDone,
});
}
},
});
let {subject: message, data: scope} = await notifyPromise;
let {subject: message} = await notifyPromise;
equal(message.QueryInterface(Ci.nsIPushMessage).data, null,
'Unexpected data for Simple Push message');
"Unexpected data for Simple Push message");
await ackPromise;
let storeRecord = await db.getByKeyID(
'6ff97d56-d0c0-43bc-8f5b-61b855e1d93b');
strictEqual(storeRecord.version, 4, 'Wrong record version');
equal(storeRecord.quota, Infinity, 'Wrong quota');
"6ff97d56-d0c0-43bc-8f5b-61b855e1d93b");
strictEqual(storeRecord.version, 4, "Wrong record version");
equal(storeRecord.quota, Infinity, "Wrong quota");
});

Просмотреть файл

@ -1,43 +1,39 @@
'use strict';
"use strict";
var pushNotifier = Cc['@mozilla.org/push/Notifier;1']
var pushNotifier = Cc["@mozilla.org/push/Notifier;1"]
.getService(Ci.nsIPushNotifier);
var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
function run_test() {
run_next_test();
}
add_task(async function test_notifyWithData() {
let textData = '{"hello":"world"}';
let payload = new TextEncoder('utf-8').encode(textData);
let payload = new TextEncoder("utf-8").encode(textData);
let notifyPromise =
promiseObserverNotification(PushServiceComponent.pushTopic);
pushNotifier.notifyPushWithData('chrome://notify-test', systemPrincipal,
'' /* messageId */, payload.length, payload);
pushNotifier.notifyPushWithData("chrome://notify-test", systemPrincipal,
"" /* messageId */, payload.length, payload);
let data = (await notifyPromise).subject.QueryInterface(
Ci.nsIPushMessage).data;
deepEqual(data.json(), {
hello: 'world',
}, 'Should extract JSON values');
hello: "world",
}, "Should extract JSON values");
deepEqual(data.binary(), Array.from(payload),
'Should extract raw binary data');
equal(data.text(), textData, 'Should extract text data');
"Should extract raw binary data");
equal(data.text(), textData, "Should extract text data");
});
add_task(async function test_empty_notifyWithData() {
let notifyPromise =
promiseObserverNotification(PushServiceComponent.pushTopic);
pushNotifier.notifyPushWithData('chrome://notify-test', systemPrincipal,
'' /* messageId */, 0, null);
pushNotifier.notifyPushWithData("chrome://notify-test", systemPrincipal,
"" /* messageId */, 0, null);
let data = (await notifyPromise).subject.QueryInterface(
Ci.nsIPushMessage).data;
throws(_ => data.json(),
/InvalidStateError/,
'Should throw an error when parsing an empty string as JSON');
strictEqual(data.text(), '', 'Should return an empty string');
deepEqual(data.binary(), [], 'Should return an empty array');
"Should throw an error when parsing an empty string as JSON");
strictEqual(data.text(), "", "Should return an empty string");
deepEqual(data.binary(), [], "Should return an empty array");
});

Просмотреть файл

@ -1,6 +1,6 @@
'use strict';
"use strict";
const pushNotifier = Cc['@mozilla.org/push/Notifier;1']
const pushNotifier = Cc["@mozilla.org/push/Notifier;1"]
.getService(Ci.nsIPushNotifier);
add_task(async function test_observer_remoting() {
@ -13,12 +13,12 @@ add_task(async function test_observer_remoting() {
});
const childTests = [{
text: 'Hello from child!',
text: "Hello from child!",
principal: Services.scriptSecurityManager.getSystemPrincipal(),
}];
const parentTests = [{
text: 'Hello from parent!',
text: "Hello from parent!",
principal: Services.scriptSecurityManager.getSystemPrincipal(),
}];
@ -30,11 +30,11 @@ async function testInParent() {
(p, test) => p.then(_ => waitForNotifierObservers(test, /* shouldNotify = */ false)),
Promise.resolve()
);
let promiseFinished = run_test_in_child('./test_observer_remoting.js');
let promiseFinished = run_test_in_child("./test_observer_remoting.js");
await promiseNotifications;
// Wait until the child is listening for notifications from the parent.
await do_await_remote_message('push_test_observer_remoting_child_ready');
await do_await_remote_message("push_test_observer_remoting_child_ready");
// Fire an observer notification in the parent that should be forwarded to
// the child.
@ -61,7 +61,7 @@ async function testInChild() {
(p, test) => p.then(_ => waitForNotifierObservers(test, /* shouldNotify = */ false)),
Promise.resolve()
);
do_send_remote_message('push_test_observer_remoting_child_ready');
do_send_remote_message("push_test_observer_remoting_child_ready");
await promiseNotifierObservers;
}
@ -73,11 +73,11 @@ var waitForNotifierObservers = async function({ text, principal }, shouldNotify
let subModifiedPromise = promiseObserverNotification(
PushServiceComponent.subscriptionModifiedTopic);
let scope = 'chrome://test-scope';
let data = new TextEncoder('utf-8').encode(text);
let scope = "chrome://test-scope";
let data = new TextEncoder("utf-8").encode(text);
if (shouldNotify) {
pushNotifier.notifyPushWithData(scope, principal, '', data.length, data);
pushNotifier.notifyPushWithData(scope, principal, "", data.length, data);
pushNotifier.notifySubscriptionChange(scope, principal);
pushNotifier.notifySubscriptionModified(scope, principal);
}
@ -87,27 +87,27 @@ var waitForNotifierObservers = async function({ text, principal }, shouldNotify
subject: notifySubject,
} = await notifyPromise;
equal(notifyScope, scope,
'Should fire push notifications with the correct scope');
"Should fire push notifications with the correct scope");
let message = notifySubject.QueryInterface(Ci.nsIPushMessage);
equal(message.principal, principal,
'Should include the principal in the push message');
strictEqual(message.data.text(), text, 'Should include data');
"Should include the principal in the push message");
strictEqual(message.data.text(), text, "Should include data");
let {
data: subChangeScope,
subject: subChangePrincipal,
} = await subChangePromise;
equal(subChangeScope, scope,
'Should fire subscription change notifications with the correct scope');
"Should fire subscription change notifications with the correct scope");
equal(subChangePrincipal, principal,
'Should pass the principal as the subject of a change notification');
"Should pass the principal as the subject of a change notification");
let {
data: subModifiedScope,
subject: subModifiedPrincipal,
} = await subModifiedPromise;
equal(subModifiedScope, scope,
'Should fire subscription modified notifications with the correct scope');
"Should fire subscription modified notifications with the correct scope");
equal(subModifiedPrincipal, principal,
'Should pass the principal as the subject of a modified notification');
"Should pass the principal as the subject of a modified notification");
};

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '2c43af06-ab6e-476a-adc4-16cbda54fb89';
const userAgentID = "2c43af06-ab6e-476a-adc4-16cbda54fb89";
let db;
@ -16,7 +16,7 @@ function run_test() {
});
db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
run_next_test();
}
@ -36,7 +36,7 @@ function makePushPermission(url, capability) {
principal: Services.scriptSecurityManager.createCodebasePrincipal(
Services.io.newURI(url), {}
),
type: 'desktop-notification',
type: "desktop-notification",
};
}
@ -70,43 +70,43 @@ function allExpired(...keyIDs) {
add_task(async function setUp() {
// Active registration; quota should be reset to 16. Since the quota isn't
// exposed to content, we shouldn't receive a subscription change event.
await putTestRecord(db, 'active-allow', 'https://example.info/page/1', 8);
await putTestRecord(db, "active-allow", "https://example.info/page/1", 8);
// Expired registration; should be dropped.
await putTestRecord(db, 'expired-allow', 'https://example.info/page/2', 0);
await putTestRecord(db, "expired-allow", "https://example.info/page/2", 0);
// Active registration; should be expired when we change the permission
// to "deny".
await putTestRecord(db, 'active-deny-changed', 'https://example.xyz/page/1', 16);
await putTestRecord(db, "active-deny-changed", "https://example.xyz/page/1", 16);
// Two active registrations for a visited site. These will expire when we
// add a "deny" permission.
await putTestRecord(db, 'active-deny-added-1', 'https://example.net/ham', 16);
await putTestRecord(db, 'active-deny-added-2', 'https://example.net/green', 8);
await putTestRecord(db, "active-deny-added-1", "https://example.net/ham", 16);
await putTestRecord(db, "active-deny-added-2", "https://example.net/green", 8);
// An already-expired registration for a visited site. We shouldn't send an
// `unregister` request for this one, but still receive an observer
// notification when we restore permissions.
await putTestRecord(db, 'expired-deny-added', 'https://example.net/eggs', 0);
await putTestRecord(db, "expired-deny-added", "https://example.net/eggs", 0);
// A registration that should not be affected by permission list changes
// because its quota is set to `Infinity`.
await putTestRecord(db, 'never-expires', 'app://chrome/only', Infinity);
await putTestRecord(db, "never-expires", "app://chrome/only", Infinity);
// A registration that should be dropped when we clear the permission
// list.
await putTestRecord(db, 'drop-on-clear', 'https://example.edu/lonely', 16);
await putTestRecord(db, "drop-on-clear", "https://example.edu/lonely", 16);
let handshakeDone;
let handshakePromise = new Promise(resolve => handshakeDone = resolve);
PushService.init({
serverURI: 'wss://push.example.org/',
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
@ -114,21 +114,21 @@ add_task(async function setUp() {
},
onUnregister(request) {
let resolve = unregisterDefers[request.channelID];
equal(typeof resolve, 'function',
'Dropped unexpected channel ID ' + request.channelID);
equal(typeof resolve, "function",
"Dropped unexpected channel ID " + request.channelID);
delete unregisterDefers[request.channelID];
equal(request.code, 202,
'Expected permission revoked unregister reason');
"Expected permission revoked unregister reason");
resolve();
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
status: 200,
channelID: request.channelID,
}));
},
onACK(request) {},
});
}
},
});
await handshakePromise;
});
@ -137,160 +137,160 @@ add_task(async function test_permissions_allow_added() {
let subChangePromise = promiseSubscriptionChanges(1);
await PushService._onPermissionChange(
makePushPermission('https://example.info', 'ALLOW_ACTION'),
'added'
makePushPermission("https://example.info", "ALLOW_ACTION"),
"added"
);
let notifiedScopes = await subChangePromise;
deepEqual(notifiedScopes, [
'https://example.info/page/2',
], 'Wrong scopes after adding allow');
"https://example.info/page/2",
], "Wrong scopes after adding allow");
let record = await db.getByKeyID('active-allow');
let record = await db.getByKeyID("active-allow");
equal(record.quota, 16,
'Should reset quota for active records after adding allow');
"Should reset quota for active records after adding allow");
record = await db.getByKeyID('expired-allow');
ok(!record, 'Should drop expired records after adding allow');
record = await db.getByKeyID("expired-allow");
ok(!record, "Should drop expired records after adding allow");
});
add_task(async function test_permissions_allow_deleted() {
let subModifiedPromise = promiseSubscriptionModifications(1);
let unregisterPromise = promiseUnregister('active-allow');
let unregisterPromise = promiseUnregister("active-allow");
await PushService._onPermissionChange(
makePushPermission('https://example.info', 'ALLOW_ACTION'),
'deleted'
makePushPermission("https://example.info", "ALLOW_ACTION"),
"deleted"
);
await unregisterPromise;
let notifiedScopes = await subModifiedPromise;
deepEqual(notifiedScopes, [
'https://example.info/page/1',
], 'Wrong scopes modified after deleting allow');
"https://example.info/page/1",
], "Wrong scopes modified after deleting allow");
let record = await db.getByKeyID('active-allow');
let record = await db.getByKeyID("active-allow");
ok(record.isExpired(),
'Should expire active record after deleting allow');
"Should expire active record after deleting allow");
});
add_task(async function test_permissions_deny_added() {
let subModifiedPromise = promiseSubscriptionModifications(2);
let unregisterPromise = Promise.all([
promiseUnregister('active-deny-added-1'),
promiseUnregister('active-deny-added-2'),
promiseUnregister("active-deny-added-1"),
promiseUnregister("active-deny-added-2"),
]);
await PushService._onPermissionChange(
makePushPermission('https://example.net', 'DENY_ACTION'),
'added'
makePushPermission("https://example.net", "DENY_ACTION"),
"added"
);
await unregisterPromise;
let notifiedScopes = await subModifiedPromise;
deepEqual(notifiedScopes, [
'https://example.net/green',
'https://example.net/ham',
], 'Wrong scopes modified after adding deny');
"https://example.net/green",
"https://example.net/ham",
], "Wrong scopes modified after adding deny");
let isExpired = await allExpired(
'active-deny-added-1',
'expired-deny-added'
"active-deny-added-1",
"expired-deny-added"
);
ok(isExpired, 'Should expire all registrations after adding deny');
ok(isExpired, "Should expire all registrations after adding deny");
});
add_task(async function test_permissions_deny_deleted() {
await PushService._onPermissionChange(
makePushPermission('https://example.net', 'DENY_ACTION'),
'deleted'
makePushPermission("https://example.net", "DENY_ACTION"),
"deleted"
);
let isExpired = await allExpired(
'active-deny-added-1',
'expired-deny-added'
"active-deny-added-1",
"expired-deny-added"
);
ok(isExpired, 'Should retain expired registrations after deleting deny');
ok(isExpired, "Should retain expired registrations after deleting deny");
});
add_task(async function test_permissions_allow_changed() {
let subChangePromise = promiseSubscriptionChanges(3);
await PushService._onPermissionChange(
makePushPermission('https://example.net', 'ALLOW_ACTION'),
'changed'
makePushPermission("https://example.net", "ALLOW_ACTION"),
"changed"
);
let notifiedScopes = await subChangePromise;
deepEqual(notifiedScopes, [
'https://example.net/eggs',
'https://example.net/green',
'https://example.net/ham'
], 'Wrong scopes after changing to allow');
"https://example.net/eggs",
"https://example.net/green",
"https://example.net/ham",
], "Wrong scopes after changing to allow");
let droppedRecords = await Promise.all([
db.getByKeyID('active-deny-added-1'),
db.getByKeyID('active-deny-added-2'),
db.getByKeyID('expired-deny-added'),
db.getByKeyID("active-deny-added-1"),
db.getByKeyID("active-deny-added-2"),
db.getByKeyID("expired-deny-added"),
]);
ok(!droppedRecords.some(Boolean),
'Should drop all expired registrations after changing to allow');
"Should drop all expired registrations after changing to allow");
});
add_task(async function test_permissions_deny_changed() {
let subModifiedPromise = promiseSubscriptionModifications(1);
let unregisterPromise = promiseUnregister('active-deny-changed');
let unregisterPromise = promiseUnregister("active-deny-changed");
await PushService._onPermissionChange(
makePushPermission('https://example.xyz', 'DENY_ACTION'),
'changed'
makePushPermission("https://example.xyz", "DENY_ACTION"),
"changed"
);
await unregisterPromise;
let notifiedScopes = await subModifiedPromise;
deepEqual(notifiedScopes, [
'https://example.xyz/page/1',
], 'Wrong scopes modified after changing to deny');
"https://example.xyz/page/1",
], "Wrong scopes modified after changing to deny");
let record = await db.getByKeyID('active-deny-changed');
let record = await db.getByKeyID("active-deny-changed");
ok(record.isExpired(),
'Should expire active record after changing to deny');
"Should expire active record after changing to deny");
});
add_task(async function test_permissions_clear() {
let subModifiedPromise = promiseSubscriptionModifications(3);
deepEqual(await getAllKeyIDs(db), [
'active-allow',
'active-deny-changed',
'drop-on-clear',
'never-expires',
], 'Wrong records in database before clearing');
"active-allow",
"active-deny-changed",
"drop-on-clear",
"never-expires",
], "Wrong records in database before clearing");
let unregisterPromise = Promise.all([
promiseUnregister('active-allow'),
promiseUnregister('active-deny-changed'),
promiseUnregister('drop-on-clear'),
promiseUnregister("active-allow"),
promiseUnregister("active-deny-changed"),
promiseUnregister("drop-on-clear"),
]);
await PushService._onPermissionChange(null, 'cleared');
await PushService._onPermissionChange(null, "cleared");
await unregisterPromise;
let notifiedScopes = await subModifiedPromise;
deepEqual(notifiedScopes, [
'https://example.edu/lonely',
'https://example.info/page/1',
'https://example.xyz/page/1',
], 'Wrong scopes modified after clearing registrations');
"https://example.edu/lonely",
"https://example.info/page/1",
"https://example.xyz/page/1",
], "Wrong scopes modified after clearing registrations");
deepEqual(await getAllKeyIDs(db), [
'never-expires',
], 'Unrestricted registrations should not be dropped');
"never-expires",
], "Unrestricted registrations should not be dropped");
});

Просмотреть файл

@ -1,18 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '7eb873f9-8d47-4218-804b-fff78dc04e88';
const userAgentID = "7eb873f9-8d47-4218-804b-fff78dc04e88";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
'testing.ignorePermission': true,
"testing.ignorePermission": true,
});
run_next_test();
}
@ -22,23 +22,23 @@ add_task(async function test_expiration_origin_threshold() {
registerCleanupFunction(() => db.drop().then(_ => db.close()));
await db.put({
channelID: 'eb33fc90-c883-4267-b5cb-613969e8e349',
pushEndpoint: 'https://example.org/push/1',
scope: 'https://example.com/auctions',
channelID: "eb33fc90-c883-4267-b5cb-613969e8e349",
pushEndpoint: "https://example.org/push/1",
scope: "https://example.com/auctions",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 16,
});
await db.put({
channelID: '46cc6f6a-c106-4ffa-bb7c-55c60bd50c41',
pushEndpoint: 'https://example.org/push/2',
scope: 'https://example.com/deals',
channelID: "46cc6f6a-c106-4ffa-bb7c-55c60bd50c41",
pushEndpoint: "https://example.org/push/2",
scope: "https://example.com/deals",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 16,
});
@ -46,31 +46,31 @@ add_task(async function test_expiration_origin_threshold() {
// workers for different scopes.
await PlacesTestUtils.addVisits([
{
uri: 'https://example.com/login',
title: 'Sign in to see your auctions',
uri: "https://example.com/login",
title: "Sign in to see your auctions",
visitDate: (Date.now() - 7 * 24 * 60 * 60 * 1000) * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
},
// We'll always use your most recent visit to an origin.
{
uri: 'https://example.com/auctions',
title: 'Your auctions',
uri: "https://example.com/auctions",
title: "Your auctions",
visitDate: (Date.now() - 2 * 24 * 60 * 60 * 1000) * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
},
// ...But we won't count downloads or embeds.
{
uri: 'https://example.com/invoices/invoice.pdf',
title: 'Invoice #123',
uri: "https://example.com/invoices/invoice.pdf",
title: "Invoice #123",
visitDate: (Date.now() - 1 * 24 * 60 * 60 * 1000) * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_EMBED
transition: Ci.nsINavHistoryService.TRANSITION_EMBED,
},
{
uri: 'https://example.com/invoices/invoice.pdf',
title: 'Invoice #123',
uri: "https://example.com/invoices/invoice.pdf",
title: "Invoice #123",
visitDate: Date.now() * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD
}
transition: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
},
]);
// We expect to receive 6 notifications: 5 on the `auctions` channel,
@ -87,13 +87,13 @@ add_task(async function test_expiration_origin_threshold() {
let unregisterPromise = new Promise(resolve => unregisterDone = resolve);
PushService.init({
serverURI: 'wss://push.example.org/',
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
@ -102,9 +102,9 @@ add_task(async function test_expiration_origin_threshold() {
// drop the registration.
for (let version = 1; version <= 6; version++) {
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: 'eb33fc90-c883-4267-b5cb-613969e8e349',
channelID: "eb33fc90-c883-4267-b5cb-613969e8e349",
version,
}],
}));
@ -112,16 +112,16 @@ add_task(async function test_expiration_origin_threshold() {
// But the limits are per-channel, so we can send 5 more
// notifications on a different channel.
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: '46cc6f6a-c106-4ffa-bb7c-55c60bd50c41',
channelID: "46cc6f6a-c106-4ffa-bb7c-55c60bd50c41",
version: 1,
}],
}));
},
onUnregister(request) {
equal(request.channelID, 'eb33fc90-c883-4267-b5cb-613969e8e349', 'Unregistered wrong channel ID');
equal(request.code, 201, 'Expected quota exceeded unregister reason');
equal(request.channelID, "eb33fc90-c883-4267-b5cb-613969e8e349", "Unregistered wrong channel ID");
equal(request.code, 201, "Expected quota exceeded unregister reason");
unregisterDone();
},
// We expect to receive acks, but don't care about their
@ -135,6 +135,6 @@ add_task(async function test_expiration_origin_threshold() {
await notifyPromise;
let expiredRecord = await db.getByKeyID('eb33fc90-c883-4267-b5cb-613969e8e349');
strictEqual(expiredRecord.quota, 0, 'Expired record not updated');
let expiredRecord = await db.getByKeyID("eb33fc90-c883-4267-b5cb-613969e8e349");
strictEqual(expiredRecord.quota, 0, "Expired record not updated");
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '28cd09e2-7506-42d8-9e50-b02785adc7ef';
const userAgentID = "28cd09e2-7506-42d8-9e50-b02785adc7ef";
var db;
@ -20,10 +20,10 @@ function run_test() {
let putRecord = async function(perm, record) {
let uri = Services.io.newURI(record.scope);
Services.perms.add(uri, 'desktop-notification',
Services.perms.add(uri, "desktop-notification",
Ci.nsIPermissionManager[perm]);
registerCleanupFunction(() => {
Services.perms.remove(uri, 'desktop-notification');
Services.perms.remove(uri, "desktop-notification");
});
await db.put(record);
@ -34,75 +34,75 @@ add_task(async function test_expiration_history_observer() {
registerCleanupFunction(() => db.drop().then(_ => db.close()));
// A registration that we'll expire...
await putRecord('ALLOW_ACTION', {
channelID: '379c0668-8323-44d2-a315-4ee83f1a9ee9',
pushEndpoint: 'https://example.org/push/1',
scope: 'https://example.com/deals',
await putRecord("ALLOW_ACTION", {
channelID: "379c0668-8323-44d2-a315-4ee83f1a9ee9",
pushEndpoint: "https://example.org/push/1",
scope: "https://example.com/deals",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 16,
});
// ...And a registration that we'll evict on startup.
await putRecord('ALLOW_ACTION', {
channelID: '4cb6e454-37cf-41c4-a013-4e3a7fdd0bf1',
pushEndpoint: 'https://example.org/push/3',
scope: 'https://example.com/stuff',
await putRecord("ALLOW_ACTION", {
channelID: "4cb6e454-37cf-41c4-a013-4e3a7fdd0bf1",
pushEndpoint: "https://example.org/push/3",
scope: "https://example.com/stuff",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 0,
});
await PlacesTestUtils.addVisits({
uri: 'https://example.com/infrequent',
title: 'Infrequently-visited page',
uri: "https://example.com/infrequent",
title: "Infrequently-visited page",
visitDate: (Date.now() - 14 * 24 * 60 * 60 * 1000) * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
});
let unregisterDone;
let unregisterPromise = new Promise(resolve => unregisterDone = resolve);
let subChangePromise = promiseObserverNotification(PushServiceComponent.subscriptionChangeTopic, (subject, data) =>
data == 'https://example.com/stuff');
data == "https://example.com/stuff");
PushService.init({
serverURI: 'wss://push.example.org/',
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: '379c0668-8323-44d2-a315-4ee83f1a9ee9',
channelID: "379c0668-8323-44d2-a315-4ee83f1a9ee9",
version: 2,
}],
}));
},
onUnregister(request) {
equal(request.channelID, '379c0668-8323-44d2-a315-4ee83f1a9ee9', 'Dropped wrong channel ID');
equal(request.code, 201, 'Expected quota exceeded unregister reason');
equal(request.channelID, "379c0668-8323-44d2-a315-4ee83f1a9ee9", "Dropped wrong channel ID");
equal(request.code, 201, "Expected quota exceeded unregister reason");
unregisterDone();
},
onACK(request) {},
});
}
},
});
await subChangePromise;
await unregisterPromise;
let expiredRecord = await db.getByKeyID('379c0668-8323-44d2-a315-4ee83f1a9ee9');
strictEqual(expiredRecord.quota, 0, 'Expired record not updated');
let expiredRecord = await db.getByKeyID("379c0668-8323-44d2-a315-4ee83f1a9ee9");
strictEqual(expiredRecord.quota, 0, "Expired record not updated");
let notifiedScopes = [];
subChangePromise = promiseObserverNotification(PushServiceComponent.subscriptionChangeTopic, (subject, data) => {
@ -112,72 +112,73 @@ add_task(async function test_expiration_history_observer() {
// Add an expired registration that we'll revive later using the idle
// observer.
await putRecord('ALLOW_ACTION', {
channelID: 'eb33fc90-c883-4267-b5cb-613969e8e349',
pushEndpoint: 'https://example.org/push/2',
scope: 'https://example.com/auctions',
await putRecord("ALLOW_ACTION", {
channelID: "eb33fc90-c883-4267-b5cb-613969e8e349",
pushEndpoint: "https://example.org/push/2",
scope: "https://example.com/auctions",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 0,
});
// ...And an expired registration that we'll revive on fetch.
await putRecord('ALLOW_ACTION', {
channelID: '6b2d13fe-d848-4c5f-bdda-e9fc89727dca',
pushEndpoint: 'https://example.org/push/4',
scope: 'https://example.net/sales',
await putRecord("ALLOW_ACTION", {
channelID: "6b2d13fe-d848-4c5f-bdda-e9fc89727dca",
pushEndpoint: "https://example.org/push/4",
scope: "https://example.net/sales",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 0,
});
// Now visit the site...
await PlacesTestUtils.addVisits({
uri: 'https://example.com/another-page',
title: 'Infrequently-visited page',
uri: "https://example.com/another-page",
title: "Infrequently-visited page",
visitDate: Date.now() * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
});
Services.obs.notifyObservers(null, 'idle-daily');
Services.obs.notifyObservers(null, "idle-daily");
// And we should receive notifications for both scopes.
await subChangePromise;
deepEqual(notifiedScopes.sort(), [
'https://example.com/auctions',
'https://example.com/deals'
], 'Wrong scopes for subscription changes');
"https://example.com/auctions",
"https://example.com/deals",
], "Wrong scopes for subscription changes");
let aRecord = await db.getByKeyID('379c0668-8323-44d2-a315-4ee83f1a9ee9');
ok(!aRecord, 'Should drop expired record');
let aRecord = await db.getByKeyID("379c0668-8323-44d2-a315-4ee83f1a9ee9");
ok(!aRecord, "Should drop expired record");
let bRecord = await db.getByKeyID('eb33fc90-c883-4267-b5cb-613969e8e349');
ok(!bRecord, 'Should drop evicted record');
let bRecord = await db.getByKeyID("eb33fc90-c883-4267-b5cb-613969e8e349");
ok(!bRecord, "Should drop evicted record");
// Simulate a visit to a site with an expired registration, then fetch the
// record. This should drop the expired record and fire an observer
// notification.
await PlacesTestUtils.addVisits({
uri: 'https://example.net/sales',
title: 'Firefox plushies, 99% off',
uri: "https://example.net/sales",
title: "Firefox plushies, 99% off",
visitDate: Date.now() * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
});
subChangePromise = promiseObserverNotification(PushServiceComponent.subscriptionChangeTopic, (subject, data) => {
if (data == 'https://example.net/sales') {
if (data == "https://example.net/sales") {
ok(subject.isCodebasePrincipal,
'Should pass subscription principal as the subject');
"Should pass subscription principal as the subject");
return true;
}
return false;
});
let record = await PushService.registration({
scope: 'https://example.net/sales',
originAttributes: '',
scope: "https://example.net/sales",
originAttributes: "",
});
ok(!record, 'Should not return evicted record');
ok(!(await db.getByKeyID('6b2d13fe-d848-4c5f-bdda-e9fc89727dca')),
'Should drop evicted record on fetch');
ok(!record, "Should not return evicted record");
ok(!(await db.getByKeyID("6b2d13fe-d848-4c5f-bdda-e9fc89727dca")),
"Should drop evicted record on fetch");
await subChangePromise;
});

Просмотреть файл

@ -1,19 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'aaabf1f8-2f68-44f1-a920-b88e9e7d7559';
const userAgentID = "aaabf1f8-2f68-44f1-a920-b88e9e7d7559";
const nsIPushQuotaManager = Ci.nsIPushQuotaManager;
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
'testing.ignorePermission': true,
"testing.ignorePermission": true,
});
run_next_test();
}
@ -31,22 +31,22 @@ add_task(async function test_expiration_origin_threshold() {
PushService.notificationForOriginShown("https://example.com");
await db.put({
channelID: 'f56645a9-1f32-4655-92ad-ddc37f6d54fb',
pushEndpoint: 'https://example.org/push/1',
scope: 'https://example.com/quota',
channelID: "f56645a9-1f32-4655-92ad-ddc37f6d54fb",
pushEndpoint: "https://example.org/push/1",
scope: "https://example.com/quota",
pushCount: 0,
lastPush: 0,
version: null,
originAttributes: '',
originAttributes: "",
quota: 16,
});
// A visit one day ago should provide a quota of 8 messages.
await PlacesTestUtils.addVisits({
uri: 'https://example.com/login',
title: 'Sign in to see your auctions',
uri: "https://example.com/login",
title: "Sign in to see your auctions",
visitDate: (Date.now() - MS_IN_ONE_DAY) * 1000,
transition: Ci.nsINavHistoryService.TRANSITION_LINK
transition: Ci.nsINavHistoryService.TRANSITION_LINK,
});
let numMessages = 10;
@ -76,13 +76,13 @@ add_task(async function test_expiration_origin_threshold() {
});
PushService.init({
serverURI: 'wss://push.example.org/',
serverURI: "wss://push.example.org/",
db,
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
@ -91,9 +91,9 @@ add_task(async function test_expiration_origin_threshold() {
// message should not affect quota.
for (let version = 1; version <= 10; version++) {
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: 'f56645a9-1f32-4655-92ad-ddc37f6d54fb',
channelID: "f56645a9-1f32-4655-92ad-ddc37f6d54fb",
version,
}],
}));
@ -114,6 +114,6 @@ add_task(async function test_expiration_origin_threshold() {
await updateQuotaPromise;
await modifiedPromise;
let expiredRecord = await db.getByKeyID('f56645a9-1f32-4655-92ad-ddc37f6d54fb');
notStrictEqual(expiredRecord.quota, 0, 'Expired record not updated');
let expiredRecord = await db.getByKeyID("f56645a9-1f32-4655-92ad-ddc37f6d54fb");
notStrictEqual(expiredRecord.quota, 0, "Expired record not updated");
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
@ -9,14 +9,14 @@ function run_test() {
do_get_profile();
setPrefs({
requestTimeout: 10000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_reconnect_retry() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let registers = 0;
let channelID;
@ -27,9 +27,9 @@ add_task(async function test_reconnect_retry() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: '083e6c17-1063-4677-8638-ab705aebebc2'
uaid: "083e6c17-1063-4677-8638-ab705aebebc2",
}));
},
onRegister(request) {
@ -41,33 +41,33 @@ add_task(async function test_reconnect_retry() {
}
if (registers == 2) {
equal(request.channelID, channelID,
'Should retry registers after reconnect');
"Should retry registers after reconnect");
}
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
channelID: request.channelID,
pushEndpoint: 'https://example.org/push/' + request.channelID,
pushEndpoint: "https://example.org/push/" + request.channelID,
status: 200,
}));
}
},
});
}
},
});
let registration = await PushService.register({
scope: 'https://example.com/page/1',
scope: "https://example.com/page/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
let retryEndpoint = 'https://example.org/push/' + channelID;
equal(registration.endpoint, retryEndpoint, 'Wrong endpoint for retried request');
let retryEndpoint = "https://example.org/push/" + channelID;
equal(registration.endpoint, retryEndpoint, "Wrong endpoint for retried request");
registration = await PushService.register({
scope: 'https://example.com/page/2',
scope: "https://example.com/page/2",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
notEqual(registration.endpoint, retryEndpoint, 'Wrong endpoint for new request');
notEqual(registration.endpoint, retryEndpoint, "Wrong endpoint for new request");
equal(registers, 3, 'Wrong registration count');
equal(registers, 3, "Wrong registration count");
});

Просмотреть файл

@ -1,11 +1,7 @@
'use strict';
"use strict";
const {PushRecord} = ChromeUtils.import("resource://gre/modules/PushRecord.jsm");
function run_test() {
run_next_test();
}
add_task(async function test_updateQuota() {
let record = new PushRecord({
quota: 8,
@ -14,26 +10,26 @@ add_task(async function test_updateQuota() {
record.updateQuota(Date.now() - 2 * MS_IN_ONE_DAY);
equal(record.quota, 8,
'Should not update quota if last visit is older than last push');
"Should not update quota if last visit is older than last push");
record.updateQuota(Date.now());
equal(record.quota, 16,
'Should reset quota if last visit is newer than last push');
"Should reset quota if last visit is newer than last push");
record.reduceQuota();
equal(record.quota, 15, 'Should reduce quota');
equal(record.quota, 15, "Should reduce quota");
// Make sure we calculate the quota correctly for visit dates in the
// future (bug 1206424).
record.updateQuota(Date.now() + 1 * MS_IN_ONE_DAY);
equal(record.quota, 16,
'Should reset quota to maximum if last visit is in the future');
"Should reset quota to maximum if last visit is in the future");
record.updateQuota(-1);
strictEqual(record.quota, 0, 'Should set quota to 0 if history was cleared');
ok(record.isExpired(), 'Should expire records once the quota reaches 0');
strictEqual(record.quota, 0, "Should set quota to 0 if history was cleared");
ok(record.isExpired(), "Should expire records once the quota reaches 0");
record.reduceQuota();
strictEqual(record.quota, 0, 'Quota should never be negative');
strictEqual(record.quota, 0, "Quota should never be negative");
});
add_task(async function test_systemRecord_updateQuota() {
@ -43,13 +39,13 @@ add_task(async function test_systemRecord_updateQuota() {
});
systemRecord.updateQuota(Date.now() - 3 * MS_IN_ONE_DAY);
equal(systemRecord.quota, Infinity,
'System subscriptions should ignore quota updates');
"System subscriptions should ignore quota updates");
systemRecord.updateQuota(-1);
equal(systemRecord.quota, Infinity,
'System subscriptions should ignore the last visit time');
"System subscriptions should ignore the last visit time");
systemRecord.reduceQuota();
equal(systemRecord.quota, Infinity,
'System subscriptions should ignore quota reductions');
"System subscriptions should ignore quota reductions");
});
function testPermissionCheck(props) {
@ -65,27 +61,27 @@ function testPermissionCheck(props) {
ok(!record.hasPermission(), `Record ${
JSON.stringify(props)} should not have permission yet`);
let permURI = Services.io.newURI(props.scope);
Services.perms.add(permURI, 'desktop-notification',
Services.perms.add(permURI, "desktop-notification",
Ci.nsIPermissionManager.ALLOW_ACTION);
try {
ok(record.hasPermission(), `Record ${
JSON.stringify(props)} should have permission`);
} finally {
Services.perms.remove(permURI, 'desktop-notification');
Services.perms.remove(permURI, "desktop-notification");
}
}
add_task(async function test_principal_permissions() {
let testProps = [{
scope: 'https://example.com/',
scope: "https://example.com/",
}, {
scope: 'https://example.com/',
originAttributes: '^userContextId=1',
scope: "https://example.com/",
originAttributes: "^userContextId=1",
}, {
scope: 'https://xn--90aexm.xn--80ag3aejvc.xn--p1ai/',
scope: "https://xn--90aexm.xn--80ag3aejvc.xn--p1ai/",
}, {
scope: 'https://xn--90aexm.xn--80ag3aejvc.xn--p1ai/',
originAttributes: '^userContextId=1',
scope: "https://xn--90aexm.xn--80ag3aejvc.xn--p1ai/",
originAttributes: "^userContextId=1",
}];
for (let props of testProps) {
testPermissionCheck(props);

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
@ -13,19 +13,19 @@ XPCOMUtils.defineLazyGetter(this, "serverPort", function() {
return httpServer.identity.primaryPort;
});
var retries = 0
var retries = 0;
function subscribe5xxCodeHandler(metadata, response) {
if (retries == 0) {
ok(true, "Subscribe 5xx code");
do_test_finished();
response.setHeader("Retry-After", '1');
response.setHeader("Retry-After", "1");
response.setStatusLine(metadata.httpVersion, 500, "Retry");
} else {
ok(true, "Subscribed");
do_test_finished();
response.setHeader("Location",
'http://localhost:' + serverPort + '/subscription')
"http://localhost:" + serverPort + "/subscription");
response.setHeader("Link",
'</pushEndpoint>; rel="urn:ietf:params:push", ' +
'</receiptPushEndpoint>; rel="urn:ietf:params:push:receipt"');
@ -38,7 +38,7 @@ function listenSuccessHandler(metadata, response) {
Assert.ok(true, "New listener point");
ok(retries == 2, "Should try 2 times.");
do_test_finished();
response.setHeader("Retry-After", '10');
response.setHeader("Retry-After", "10");
response.setStatusLine(metadata.httpVersion, 500, "Retry");
}
@ -49,19 +49,17 @@ httpServer.registerPathHandler("/subscription", listenSuccessHandler);
httpServer.start(-1);
function run_test() {
do_get_profile();
setPrefs({
'testing.allowInsecureServerURL': true,
'http2.retryInterval': 1000,
'http2.maxRetries': 2
"testing.allowInsecureServerURL": true,
"http2.retryInterval": 1000,
"http2.maxRetries": 2,
});
run_next_test();
}
add_task(async function test1() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -76,7 +74,7 @@ add_task(async function test1() {
PushService.init({
serverURI: serverURL + "/subscribe5xxCode",
db
db,
});
let originAttributes = ChromeUtils.originAttributesToSuffix({
@ -84,28 +82,28 @@ add_task(async function test1() {
inIsolatedMozBrowser: false,
});
let newRecord = await PushService.register({
scope: 'https://example.com/retry5xxCode',
originAttributes: originAttributes,
scope: "https://example.com/retry5xxCode",
originAttributes,
});
var subscriptionUri = serverURL + '/subscription';
var pushEndpoint = serverURL + '/pushEndpoint';
var pushReceiptEndpoint = serverURL + '/receiptPushEndpoint';
var subscriptionUri = serverURL + "/subscription";
var pushEndpoint = serverURL + "/pushEndpoint";
var pushReceiptEndpoint = serverURL + "/receiptPushEndpoint";
equal(newRecord.endpoint, pushEndpoint,
'Wrong push endpoint in registration record');
"Wrong push endpoint in registration record");
equal(newRecord.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in registration record');
"Wrong push endpoint receipt in registration record");
let record = await db.getByKeyID(subscriptionUri);
equal(record.subscriptionUri, subscriptionUri,
'Wrong subscription ID in database record');
"Wrong subscription ID in database record");
equal(record.pushEndpoint, pushEndpoint,
'Wrong push endpoint in database record');
"Wrong push endpoint in database record");
equal(record.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in database record');
equal(record.scope, 'https://example.com/retry5xxCode',
'Wrong scope in database record');
"Wrong push endpoint receipt in database record");
equal(record.scope, "https://example.com/retry5xxCode",
"Wrong scope in database record");
httpServer.stop(do_test_finished);
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '1760b1f5-c3ba-40e3-9344-adef7c18ab12';
const userAgentID = "1760b1f5-c3ba-40e3-9344-adef7c18ab12";
function run_test() {
do_get_profile();
@ -15,7 +15,7 @@ function run_test() {
add_task(async function test_register_case() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushService.init({
serverURI: "wss://push.example.org/",
@ -24,33 +24,33 @@ add_task(async function test_register_case() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'HELLO',
messageType: "HELLO",
uaid: userAgentID,
status: 200
status: 200,
}));
},
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'ReGiStEr',
messageType: "ReGiStEr",
uaid: userAgentID,
channelID: request.channelID,
status: 200,
pushEndpoint: 'https://example.com/update/case'
pushEndpoint: "https://example.com/update/case",
}));
}
},
});
}
},
});
let newRecord = await PushService.register({
scope: 'https://example.net/case',
scope: "https://example.net/case",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
equal(newRecord.endpoint, 'https://example.com/update/case',
'Wrong push endpoint in registration record');
equal(newRecord.endpoint, "https://example.com/update/case",
"Wrong push endpoint in registration record");
let record = await db.getByPushEndpoint('https://example.com/update/case');
equal(record.scope, 'https://example.net/case',
'Wrong scope in database record');
let record = await db.getByPushEndpoint("https://example.com/update/case");
equal(record.scope, "https://example.net/case",
"Wrong scope in database record");
});

Просмотреть файл

@ -1,11 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var prefs;
var serverURL;
var serverPort = -1;
@ -14,7 +13,6 @@ function run_test() {
serverPort = getTestServerPort();
do_get_profile();
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
serverURL = "https://localhost:" + serverPort;
@ -23,7 +21,6 @@ function run_test() {
// Connection will fail because of the certificates.
add_task(async function test_pushSubscriptionNoConnection() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -31,17 +28,17 @@ add_task(async function test_pushSubscriptionNoConnection() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionNoConnection/subscribe",
db
db,
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-response',
scope: "https://example.net/page/invalid-response",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for not being able to establish connecion.'
"Expected error for not being able to establish connecion."
);
let record = await db.getAllKeyIDs();
@ -51,16 +48,15 @@ add_task(async function test_pushSubscriptionNoConnection() {
add_task(async function test_TLS() {
// Set to allow the cert presented by our H2 server
var oldPref = prefs.getIntPref("network.http.speculative-parallel-limit");
prefs.setIntPref("network.http.speculative-parallel-limit", 0);
var oldPref = Services.prefs.getIntPref("network.http.speculative-parallel-limit");
Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
trustHttp2CA();
prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
Services.prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
});
add_task(async function test_pushSubscriptionMissingLocation() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -68,26 +64,25 @@ add_task(async function test_pushSubscriptionMissingLocation() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionMissingLocation/subscribe",
db
db,
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-response',
scope: "https://example.net/page/invalid-response",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for the missing location header.'
"Expected error for the missing location header."
);
let record = await db.getAllKeyIDs();
ok(record.length === 0, 'Should not store records when the location header is missing.');
ok(record.length === 0, "Should not store records when the location header is missing.");
PushService.uninit();
});
add_task(async function test_pushSubscriptionMissingLink() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -95,26 +90,25 @@ add_task(async function test_pushSubscriptionMissingLink() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionMissingLink/subscribe",
db
db,
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-response',
scope: "https://example.net/page/invalid-response",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for the missing link header.'
"Expected error for the missing link header."
);
let record = await db.getAllKeyIDs();
ok(record.length === 0, 'Should not store records when a link header is missing.');
ok(record.length === 0, "Should not store records when a link header is missing.");
PushService.uninit();
});
add_task(async function test_pushSubscriptionMissingLink1() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -122,26 +116,25 @@ add_task(async function test_pushSubscriptionMissingLink1() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionMissingLink1/subscribe",
db
db,
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-response',
scope: "https://example.net/page/invalid-response",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for the missing push endpoint.'
"Expected error for the missing push endpoint."
);
let record = await db.getAllKeyIDs();
ok(record.length === 0, 'Should not store records when the push endpoint is missing.');
ok(record.length === 0, "Should not store records when the push endpoint is missing.");
PushService.uninit();
});
add_task(async function test_pushSubscriptionLocationBogus() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -149,26 +142,25 @@ add_task(async function test_pushSubscriptionLocationBogus() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionLocationBogus/subscribe",
db
db,
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-response',
scope: "https://example.net/page/invalid-response",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for the bogus location'
"Expected error for the bogus location"
);
let record = await db.getAllKeyIDs();
ok(record.length === 0, 'Should not store records when location header is bogus.');
ok(record.length === 0, "Should not store records when location header is bogus.");
PushService.uninit();
});
add_task(async function test_pushSubscriptionNot2xxCode() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -176,19 +168,19 @@ add_task(async function test_pushSubscriptionNot2xxCode() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionNot201Code/subscribe",
db
db,
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-response',
scope: "https://example.net/page/invalid-response",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for not 201 responce code.'
"Expected error for not 201 responce code."
);
let record = await db.getAllKeyIDs();
ok(record.length === 0, 'Should not store records when respons code is not 201.');
ok(record.length === 0, "Should not store records when respons code is not 201.");
});

Просмотреть файл

@ -1,31 +1,31 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '9ce1e6d3-7bdb-4fe9-90a5-def1d64716f1';
const channelID = 'c26892c5-6e08-4c16-9f0c-0044697b4d85';
const userAgentID = "9ce1e6d3-7bdb-4fe9-90a5-def1d64716f1";
const channelID = "c26892c5-6e08-4c16-9f0c-0044697b4d85";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_register_flush() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let record = {
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
pushEndpoint: 'https://example.org/update/1',
scope: 'https://example.com/page/1',
originAttributes: '',
channelID: "9bcc7efb-86c7-4457-93ea-e24e6eb59b74",
pushEndpoint: "https://example.org/update/1",
scope: "https://example.com/page/1",
originAttributes: "",
version: 2,
quota: Infinity,
systemRecord: true,
@ -43,54 +43,54 @@ add_task(async function test_register_flush() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
},
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'notification',
messageType: "notification",
updates: [{
channelID: request.channelID,
version: 2
version: 2,
}, {
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
version: 3
}]
channelID: "9bcc7efb-86c7-4457-93ea-e24e6eb59b74",
version: 3,
}],
}));
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
channelID: request.channelID,
uaid: userAgentID,
pushEndpoint: 'https://example.org/update/2'
pushEndpoint: "https://example.org/update/2",
}));
},
onACK: ackDone
onACK: ackDone,
});
}
},
});
let newRecord = await PushService.register({
scope: 'https://example.com/page/2',
originAttributes: '',
scope: "https://example.com/page/2",
originAttributes: "",
});
equal(newRecord.endpoint, 'https://example.org/update/2',
'Wrong push endpoint in record');
equal(newRecord.endpoint, "https://example.org/update/2",
"Wrong push endpoint in record");
let {data: scope} = await notifyPromise;
equal(scope, 'https://example.com/page/1', 'Wrong notification scope');
equal(scope, "https://example.com/page/1", "Wrong notification scope");
await ackPromise;
let prevRecord = await db.getByKeyID(
'9bcc7efb-86c7-4457-93ea-e24e6eb59b74');
equal(prevRecord.pushEndpoint, 'https://example.org/update/1',
'Wrong existing push endpoint');
"9bcc7efb-86c7-4457-93ea-e24e6eb59b74");
equal(prevRecord.pushEndpoint, "https://example.org/update/1",
"Wrong existing push endpoint");
strictEqual(prevRecord.version, 3,
'Should record version updates sent before register responses');
"Should record version updates sent before register responses");
let registeredRecord = await db.getByPushEndpoint('https://example.org/update/2');
ok(!registeredRecord.version, 'Should not record premature updates');
let registeredRecord = await db.getByPushEndpoint("https://example.org/update/2");
ok(!registeredRecord.version, "Should not record premature updates");
});

Просмотреть файл

@ -1,12 +1,12 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '52b2b04c-b6cc-42c6-abdf-bef9cbdbea00';
const channelID = 'cafed00d';
const userAgentID = "52b2b04c-b6cc-42c6-abdf-bef9cbdbea00";
const channelID = "cafed00d";
function run_test() {
do_get_profile();
@ -16,7 +16,7 @@ function run_test() {
add_task(async function test_register_invalid_channel() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushServiceWebSocket._generateID = () => channelID;
PushService.init({
@ -26,33 +26,33 @@ add_task(async function test_register_invalid_channel() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
uaid: userAgentID,
status: 200
status: 200,
}));
},
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 403,
channelID,
error: 'Invalid channel ID'
error: "Invalid channel ID",
}));
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.com/invalid-channel',
scope: "https://example.com/invalid-channel",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for invalid channel ID'
"Expected error for invalid channel ID"
);
let record = await db.getByKeyID(channelID);
ok(!record, 'Should not store records for error responses');
ok(!record, "Should not store records for error responses");
});

Просмотреть файл

@ -1,12 +1,12 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'c9a12e81-ea5e-40f9-8bf4-acee34621671';
const channelID = 'c0660af8-b532-4931-81f0-9fd27a12d6ab';
const userAgentID = "c9a12e81-ea5e-40f9-8bf4-acee34621671";
const channelID = "c0660af8-b532-4931-81f0-9fd27a12d6ab";
function run_test() {
do_get_profile();
@ -16,7 +16,7 @@ function run_test() {
add_task(async function test_register_invalid_endpoint() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushServiceWebSocket._generateID = () => channelID;
PushService.init({
@ -26,34 +26,34 @@ add_task(async function test_register_invalid_endpoint() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
},
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
channelID,
uaid: userAgentID,
pushEndpoint: '!@#$%^&*'
pushEndpoint: "!@#$%^&*",
}));
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-endpoint',
scope: "https://example.net/page/invalid-endpoint",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for invalid endpoint'
"Expected error for invalid endpoint"
);
let record = await db.getByKeyID(channelID);
ok(!record, 'Should not store records with invalid endpoints');
ok(!record, "Should not store records with invalid endpoints");
});

Просмотреть файл

@ -1,18 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '8271186b-8073-43a3-adf6-225bd44a8b0a';
const channelID = '2d08571e-feab-48a0-9f05-8254c3c7e61f';
const userAgentID = "8271186b-8073-43a3-adf6-225bd44a8b0a";
const channelID = "2d08571e-feab-48a0-9f05-8254c3c7e61f";
function run_test() {
do_get_profile();
setPrefs({
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
@ -29,31 +29,31 @@ add_task(async function test_register_invalid_json() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
helloDone();
},
onRegister(request) {
equal(request.channelID, channelID, 'Register: wrong channel ID');
this.serverSendMsg(');alert(1);(');
equal(request.channelID, channelID, "Register: wrong channel ID");
this.serverSendMsg(");alert(1);(");
registers++;
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/invalid-json',
scope: "https://example.net/page/invalid-json",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for invalid JSON response'
"Expected error for invalid JSON response"
);
await helloPromise;
equal(registers, 1, 'Wrong register count');
equal(registers, 1, "Wrong register count");
});

Просмотреть файл

@ -1,19 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
var userAgentID = '9a2f9efe-2ebb-4bcb-a5d9-9e2b73d30afe';
var channelID = '264c2ba0-f6db-4e84-acdb-bd225b62d9e3';
var userAgentID = "9a2f9efe-2ebb-4bcb-a5d9-9e2b73d30afe";
var channelID = "264c2ba0-f6db-4e84-acdb-bd225b62d9e3";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
@ -30,34 +30,34 @@ add_task(async function test_register_no_id() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
helloDone();
},
onRegister(request) {
registers++;
equal(request.channelID, channelID, 'Register: wrong channel ID');
equal(request.channelID, channelID, "Register: wrong channel ID");
this.serverSendMsg(JSON.stringify({
messageType: 'register',
status: 200
messageType: "register",
status: 200,
}));
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.com/incomplete',
scope: "https://example.com/incomplete",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for incomplete register response'
"Expected error for incomplete register response"
);
await helloPromise;
equal(registers, 1, 'Wrong register count');
equal(registers, 1, "Wrong register count");
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
@ -9,21 +9,21 @@ function run_test() {
do_get_profile();
setPrefs({
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_register_request_queue() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let onHello;
let helloPromise = new Promise(resolve => onHello = after(2, function onHello(request) {
let helloPromise = new Promise(resolve => onHello = after(2, function onHelloReceived(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: '54b08a9e-59c6-4ed7-bb54-f4fd60d6f606'
uaid: "54b08a9e-59c6-4ed7-bb54-f4fd60d6f606",
}));
resolve();
}));
@ -35,26 +35,28 @@ add_task(async function test_register_request_queue() {
return new MockWebSocket(uri, {
onHello,
onRegister() {
ok(false, 'Should cancel timed-out requests');
}
ok(false, "Should cancel timed-out requests");
},
});
}
},
});
let firstRegister = PushService.register({
scope: 'https://example.com/page/1',
scope: "https://example.com/page/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
let secondRegister = PushService.register({
scope: 'https://example.com/page/1',
scope: "https://example.com/page/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
await Promise.all([
rejects(firstRegister, /Registration error/, 'Should time out the first request'),
rejects(secondRegister, /Registration error/, 'Should time out the second request')
// eslint-disable-next-line mozilla/rejects-requires-await
Assert.rejects(firstRegister, /Registration error/, "Should time out the first request"),
// eslint-disable-next-line mozilla/rejects-requires-await
Assert.rejects(secondRegister, /Registration error/, "Should time out the second request"),
]);
await helloPromise;

Просмотреть файл

@ -1,26 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'b2546987-4f63-49b1-99f7-739cd3c40e44';
const channelID = '35a820f7-d7dd-43b3-af21-d65352212ae3';
const userAgentID = "b2546987-4f63-49b1-99f7-739cd3c40e44";
const channelID = "35a820f7-d7dd-43b3-af21-d65352212ae3";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_register_rollback() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let handshakes = 0;
let registers = 0;
@ -31,58 +31,58 @@ add_task(async function test_register_rollback() {
serverURI: "wss://push.example.org/",
db: makeStub(db, {
put(prev, record) {
return Promise.reject('universe has imploded');
}
return Promise.reject("universe has imploded");
},
}),
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
handshakes++;
equal(request.uaid, userAgentID, 'Handshake: wrong device ID');
equal(request.uaid, userAgentID, "Handshake: wrong device ID");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
},
onRegister(request) {
equal(request.channelID, channelID, 'Register: wrong channel ID');
equal(request.channelID, channelID, "Register: wrong channel ID");
registers++;
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
uaid: userAgentID,
channelID,
pushEndpoint: 'https://example.com/update/rollback'
pushEndpoint: "https://example.com/update/rollback",
}));
},
onUnregister(request) {
equal(request.channelID, channelID, 'Unregister: wrong channel ID');
equal(request.code, 200, 'Expected manual unregister reason');
equal(request.channelID, channelID, "Unregister: wrong channel ID");
equal(request.code, 200, "Expected manual unregister reason");
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
status: 200,
channelID
channelID,
}));
unregisterDone();
}
},
});
}
},
});
// Should return a rejected promise if storage fails.
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.com/storage-error',
scope: "https://example.com/storage-error",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/universe has imploded/,
'Expected error for unregister database failure'
"Expected error for unregister database failure"
);
// Should send an out-of-band unregister request.
await unregisterPromise;
equal(handshakes, 1, 'Wrong handshake count');
equal(registers, 1, 'Wrong register count');
equal(handshakes, 1, "Wrong handshake count");
equal(registers, 1, "Wrong register count");
});

Просмотреть файл

@ -1,26 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
const channelID = '0ef2ad4a-6c49-41ad-af6e-95d2425276bf';
const userAgentID = "bd744428-f125-436a-b6d0-dd0c9845837f";
const channelID = "0ef2ad4a-6c49-41ad-af6e-95d2425276bf";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_register_success() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushServiceWebSocket._generateID = () => channelID;
PushService.init({
@ -29,49 +29,49 @@ add_task(async function test_register_success() {
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(data) {
equal(data.messageType, 'hello', 'Handshake: wrong message type');
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
equal(data.messageType, "hello", "Handshake: wrong message type");
equal(data.uaid, userAgentID, "Handshake: wrong device ID");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
},
onRegister(data) {
equal(data.messageType, 'register', 'Register: wrong message type');
equal(data.channelID, channelID, 'Register: wrong channel ID');
equal(data.messageType, "register", "Register: wrong message type");
equal(data.channelID, channelID, "Register: wrong channel ID");
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
channelID: channelID,
channelID,
uaid: userAgentID,
pushEndpoint: 'https://example.com/update/1',
pushEndpoint: "https://example.com/update/1",
}));
}
},
});
}
},
});
let subModifiedPromise = promiseObserverNotification(
PushServiceComponent.subscriptionModifiedTopic);
let newRecord = await PushService.register({
scope: 'https://example.org/1',
scope: "https://example.org/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
equal(newRecord.endpoint, 'https://example.com/update/1',
'Wrong push endpoint in registration record');
equal(newRecord.endpoint, "https://example.com/update/1",
"Wrong push endpoint in registration record");
let {data: subModifiedScope} = await subModifiedPromise;
equal(subModifiedScope, 'https://example.org/1',
'Should fire a subscription modified event after subscribing');
equal(subModifiedScope, "https://example.org/1",
"Should fire a subscription modified event after subscribing");
let record = await db.getByKeyID(channelID);
equal(record.channelID, channelID,
'Wrong channel ID in database record');
equal(record.pushEndpoint, 'https://example.com/update/1',
'Wrong push endpoint in database record');
"Wrong channel ID in database record");
equal(record.pushEndpoint, "https://example.com/update/1",
"Wrong push endpoint in database record");
equal(record.quota, 16,
'Wrong quota in database record');
"Wrong quota in database record");
});

Просмотреть файл

@ -1,11 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var prefs;
var serverURL;
var serverPort = -1;
var pushEnabled;
@ -16,20 +15,18 @@ function run_test() {
serverPort = getTestServerPort();
do_get_profile();
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
pushEnabled = prefs.getBoolPref("dom.push.enabled");
pushConnectionEnabled = prefs.getBoolPref("dom.push.connection.enabled");
pushEnabled = Services.prefs.getBoolPref("dom.push.enabled");
pushConnectionEnabled = Services.prefs.getBoolPref("dom.push.connection.enabled");
// Set to allow the cert presented by our H2 server
var oldPref = prefs.getIntPref("network.http.speculative-parallel-limit");
prefs.setIntPref("network.http.speculative-parallel-limit", 0);
prefs.setBoolPref("dom.push.enabled", true);
prefs.setBoolPref("dom.push.connection.enabled", true);
var oldPref = Services.prefs.getIntPref("network.http.speculative-parallel-limit");
Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
Services.prefs.setBoolPref("dom.push.enabled", true);
Services.prefs.setBoolPref("dom.push.connection.enabled", true);
trustHttp2CA();
prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
Services.prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
serverURL = "https://localhost:" + serverPort;
@ -37,83 +34,79 @@ function run_test() {
}
add_task(async function test_setup() {
db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
});
});
add_task(async function test_pushSubscriptionSuccess() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionSuccess/subscribe",
db
db,
});
let newRecord = await PushService.register({
scope: 'https://example.org/1',
scope: "https://example.org/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
var subscriptionUri = serverURL + '/pushSubscriptionSuccesss';
var pushEndpoint = serverURL + '/pushEndpointSuccess';
var pushReceiptEndpoint = serverURL + '/receiptPushEndpointSuccess';
var subscriptionUri = serverURL + "/pushSubscriptionSuccesss";
var pushEndpoint = serverURL + "/pushEndpointSuccess";
var pushReceiptEndpoint = serverURL + "/receiptPushEndpointSuccess";
equal(newRecord.endpoint, pushEndpoint,
'Wrong push endpoint in registration record');
"Wrong push endpoint in registration record");
equal(newRecord.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in registration record');
"Wrong push endpoint receipt in registration record");
let record = await db.getByKeyID(subscriptionUri);
equal(record.subscriptionUri, subscriptionUri,
'Wrong subscription ID in database record');
"Wrong subscription ID in database record");
equal(record.pushEndpoint, pushEndpoint,
'Wrong push endpoint in database record');
"Wrong push endpoint in database record");
equal(record.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in database record');
equal(record.scope, 'https://example.org/1',
'Wrong scope in database record');
"Wrong push endpoint receipt in database record");
equal(record.scope, "https://example.org/1",
"Wrong scope in database record");
PushService.uninit()
PushService.uninit();
});
add_task(async function test_pushSubscriptionMissingLink2() {
PushService.init({
serverURI: serverURL + "/pushSubscriptionMissingLink2/subscribe",
db
db,
});
let newRecord = await PushService.register({
scope: 'https://example.org/no_receiptEndpoint',
scope: "https://example.org/no_receiptEndpoint",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
var subscriptionUri = serverURL + '/subscriptionMissingLink2';
var pushEndpoint = serverURL + '/pushEndpointMissingLink2';
var pushReceiptEndpoint = '';
var subscriptionUri = serverURL + "/subscriptionMissingLink2";
var pushEndpoint = serverURL + "/pushEndpointMissingLink2";
var pushReceiptEndpoint = "";
equal(newRecord.endpoint, pushEndpoint,
'Wrong push endpoint in registration record');
"Wrong push endpoint in registration record");
equal(newRecord.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in registration record');
"Wrong push endpoint receipt in registration record");
let record = await db.getByKeyID(subscriptionUri);
equal(record.subscriptionUri, subscriptionUri,
'Wrong subscription ID in database record');
"Wrong subscription ID in database record");
equal(record.pushEndpoint, pushEndpoint,
'Wrong push endpoint in database record');
"Wrong push endpoint in database record");
equal(record.pushReceiptEndpoint, pushReceiptEndpoint,
'Wrong push endpoint receipt in database record');
equal(record.scope, 'https://example.org/no_receiptEndpoint',
'Wrong scope in database record');
"Wrong push endpoint receipt in database record");
equal(record.scope, "https://example.org/no_receiptEndpoint",
"Wrong scope in database record");
});
add_task(async function test_complete() {
prefs.setBoolPref("dom.push.enabled", pushEnabled);
prefs.setBoolPref("dom.push.connection.enabled", pushConnectionEnabled);
Services.prefs.setBoolPref("dom.push.enabled", pushEnabled);
Services.prefs.setBoolPref("dom.push.connection.enabled", pushConnectionEnabled);
});

Просмотреть файл

@ -1,18 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'a4be0df9-b16d-4b5f-8f58-0f93b6f1e23d';
const channelID = 'e1944e0b-48df-45e7-bdc0-d1fbaa7986d3';
const userAgentID = "a4be0df9-b16d-4b5f-8f58-0f93b6f1e23d";
const channelID = "e1944e0b-48df-45e7-bdc0-d1fbaa7986d3";
function run_test() {
do_get_profile();
setPrefs({
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
@ -24,7 +24,7 @@ add_task(async function test_register_timeout() {
let registers = 0;
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushServiceWebSocket._generateID = () => channelID;
PushService.init({
@ -34,55 +34,56 @@ add_task(async function test_register_timeout() {
return new MockWebSocket(uri, {
onHello(request) {
if (handshakes === 0) {
equal(request.uaid, null, 'Should not include device ID');
equal(request.uaid, null, "Should not include device ID");
} else if (handshakes === 1) {
// Should use the previously-issued device ID when reconnecting,
// but should not include the timed-out channel ID.
equal(request.uaid, userAgentID,
'Should include device ID on reconnect');
"Should include device ID on reconnect");
} else {
ok(false, 'Unexpected reconnect attempt ' + handshakes);
ok(false, "Unexpected reconnect attempt " + handshakes);
}
handshakes++;
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));
},
onRegister(request) {
equal(request.channelID, channelID,
'Wrong channel ID in register request');
"Wrong channel ID in register request");
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
// Should ignore replies for timed-out requests.
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
channelID: channelID,
channelID,
uaid: userAgentID,
pushEndpoint: 'https://example.com/update/timeout',
pushEndpoint: "https://example.com/update/timeout",
}));
timeoutDone();
}, 2000);
registers++;
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.net/page/timeout',
scope: "https://example.net/page/timeout",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for request timeout'
"Expected error for request timeout"
);
let record = await db.getByKeyID(channelID);
ok(!record, 'Should not store records for timed-out responses');
ok(!record, "Should not store records for timed-out responses");
await timeoutPromise;
equal(registers, 1, 'Should not handle timed-out register requests');
equal(registers, 1, "Should not handle timed-out register requests");
});

Просмотреть файл

@ -1,20 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '84afc774-6995-40d1-9c90-8c34ddcd0cb4';
const clientChannelID = '4b42a681c99e4dfbbb166a7e01a09b8b';
const serverChannelID = '3f5aeb89c6e8405a9569619522783436';
const userAgentID = "84afc774-6995-40d1-9c90-8c34ddcd0cb4";
const clientChannelID = "4b42a681c99e4dfbbb166a7e01a09b8b";
const serverChannelID = "3f5aeb89c6e8405a9569619522783436";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
@ -32,38 +32,38 @@ add_task(async function test_register_wrong_id() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
helloDone();
},
onRegister(request) {
equal(request.channelID, clientChannelID,
'Register: wrong channel ID');
"Register: wrong channel ID");
registers++;
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
// Reply with a different channel ID. Since the ID is used as a
// nonce, the registration request will time out.
channelID: serverChannelID
channelID: serverChannelID,
}));
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.com/mismatched',
scope: "https://example.com/mismatched",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for mismatched register reply'
"Expected error for mismatched register reply"
);
await helloPromise;
equal(registers, 1, 'Wrong register count');
equal(registers, 1, "Wrong register count");
});

Просмотреть файл

@ -1,17 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService} = serviceExports;
const userAgentID = 'c293fdc5-a75e-4eb1-af88-a203991c0787';
const userAgentID = "c293fdc5-a75e-4eb1-af88-a203991c0787";
function run_test() {
do_get_profile();
setPrefs({
requestTimeout: 1000,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
@ -21,43 +21,43 @@ add_task(async function test_register_wrong_type() {
let helloDone;
let helloPromise = new Promise(resolve => helloDone = after(2, resolve));
PushService._generateID = () => '1234';
PushService._generateID = () => "1234";
PushService.init({
serverURI: "wss://push.example.org/",
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
helloDone();
},
onRegister(request) {
registers++;
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
channelID: 1234,
uaid: userAgentID,
pushEndpoint: 'https://example.org/update/wrong-type'
pushEndpoint: "https://example.org/update/wrong-type",
}));
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.register({
scope: 'https://example.com/mistyped',
scope: "https://example.com/mistyped",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Registration error/,
'Expected error for non-string channel ID'
"Expected error for non-string channel ID"
);
await helloPromise;
equal(registers, 1, 'Wrong register count');
equal(registers, 1, "Wrong register count");
});

Просмотреть файл

@ -1,43 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
function run_test() {
do_get_profile();
setPrefs({
userAgentID: '6faed1f0-1439-4aac-a978-db21c81cd5eb'
userAgentID: "6faed1f0-1439-4aac-a978-db21c81cd5eb",
});
run_next_test();
}
add_task(async function test_registrations_error() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushService.init({
serverURI: "wss://push.example.org/",
db: makeStub(db, {
getByIdentifiers(prev, scope) {
return Promise.reject('Database error');
}
return Promise.reject("Database error");
},
}),
makeWebSocket(uri) {
return new MockWebSocket(uri);
}
},
});
await rejects(
await Assert.rejects(
PushService.registration({
scope: 'https://example.net/1',
scope: "https://example.net/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
function(error) {
return error == 'Database error';
return error == "Database error";
},
'Wrong message'
"Wrong message"
);
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
@ -12,26 +12,26 @@ function run_test() {
add_task(async function test_registrations_error() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
PushService.init({
serverURI: "https://push.example.org/",
db: makeStub(db, {
getByIdentifiers() {
return Promise.reject('Database error');
}
return Promise.reject("Database error");
},
}),
});
await rejects(
await Assert.rejects(
PushService.registration({
scope: 'https://example.net/1',
scope: "https://example.net/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
function(error) {
return error == 'Database error';
return error == "Database error";
},
'Wrong message'
"Wrong message"
);
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService} = serviceExports;
@ -16,11 +16,11 @@ add_task(async function test_registration_missing_scope() {
serverURI: "wss://push.example.org/",
makeWebSocket(uri) {
return new MockWebSocket(uri);
}
},
});
await rejects(
PushService.registration({ scope: '', originAttributes: '' }),
await Assert.rejects(
PushService.registration({ scope: "", originAttributes: "" }),
/Invalid page record/,
'Record missing page and manifest URLs'
"Record missing page and manifest URLs"
);
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService} = serviceExports;
const userAgentID = 'a722e448-c481-4c48-aea0-fc411cb7c9ed';
const userAgentID = "a722e448-c481-4c48-aea0-fc411cb7c9ed";
function run_test() {
do_get_profile();
@ -19,13 +19,13 @@ add_task(async function test_registration_none() {
serverURI: "wss://push.example.org/",
makeWebSocket(uri) {
return new MockWebSocket(uri);
}
},
});
let registration = await PushService.registration({
scope: 'https://example.net/1',
scope: "https://example.net/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
ok(!registration, 'Should not open a connection without registration');
ok(!registration, "Should not open a connection without registration");
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '997ee7ba-36b1-4526-ae9e-2d3f38d6efe8';
const userAgentID = "997ee7ba-36b1-4526-ae9e-2d3f38d6efe8";
function run_test() {
do_get_profile();
@ -15,26 +15,26 @@ function run_test() {
add_task(async function test_registration_success() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let records = [{
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
pushEndpoint: 'https://example.com/update/same-manifest/1',
scope: 'https://example.net/a',
originAttributes: '',
channelID: "bf001fe0-2684-42f2-bc4d-a3e14b11dd5b",
pushEndpoint: "https://example.com/update/same-manifest/1",
scope: "https://example.net/a",
originAttributes: "",
version: 5,
quota: Infinity,
}, {
channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
pushEndpoint: 'https://example.com/update/same-manifest/2',
scope: 'https://example.net/b',
channelID: "f6edfbcd-79d6-49b8-9766-48b9dcfeff0f",
pushEndpoint: "https://example.com/update/same-manifest/2",
scope: "https://example.net/b",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: 42 }),
version: 10,
quota: Infinity,
}, {
channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
pushEndpoint: 'https://example.org/update/different-manifest',
scope: 'https://example.org/c',
channelID: "b1cf38c9-6836-4d29-8a30-a3e98d59b728",
pushEndpoint: "https://example.org/update/different-manifest",
scope: "https://example.org/c",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: 42, inIsolatedMozBrowser: true }),
version: 15,
@ -51,28 +51,28 @@ add_task(async function test_registration_success() {
makeWebSocket(uri) {
return new MockWebSocket(uri, {
onHello(request) {
equal(request.uaid, userAgentID, 'Wrong device ID in handshake');
equal(request.uaid, userAgentID, "Wrong device ID in handshake");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID
uaid: userAgentID,
}));
handshakeDone();
}
},
});
}
},
});
await handshakePromise;
let registration = await PushService.registration({
scope: 'https://example.net/a',
originAttributes: '',
scope: "https://example.net/a",
originAttributes: "",
});
equal(
registration.endpoint,
'https://example.com/update/same-manifest/1',
'Wrong push endpoint for scope'
"https://example.com/update/same-manifest/1",
"Wrong push endpoint for scope"
);
equal(registration.version, 5, 'Wrong version for scope');
equal(registration.version, 5, "Wrong version for scope");
});

Просмотреть файл

@ -1,25 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var prefs;
var serverPort = -1;
function run_test() {
serverPort = getTestServerPort();
do_get_profile();
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
run_next_test();
}
add_task(async function test_pushNotifications() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -28,26 +24,26 @@ add_task(async function test_pushNotifications() {
var serverURL = "https://localhost:" + serverPort;
let records = [{
subscriptionUri: serverURL + '/subscriptionA',
pushEndpoint: serverURL + '/pushEndpointA',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointA',
scope: 'https://example.net/a',
subscriptionUri: serverURL + "/subscriptionA",
pushEndpoint: serverURL + "/pushEndpointA",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpointA",
scope: "https://example.net/a",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
}, {
subscriptionUri: serverURL + '/subscriptionB',
pushEndpoint: serverURL + '/pushEndpointB',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointB',
scope: 'https://example.net/b',
subscriptionUri: serverURL + "/subscriptionB",
pushEndpoint: serverURL + "/pushEndpointB",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpointB",
scope: "https://example.net/b",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
}, {
subscriptionUri: serverURL + '/subscriptionC',
pushEndpoint: serverURL + '/pushEndpointC',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointC',
scope: 'https://example.net/c',
subscriptionUri: serverURL + "/subscriptionC",
pushEndpoint: serverURL + "/pushEndpointC",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpointC",
scope: "https://example.net/c",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
@ -59,17 +55,17 @@ add_task(async function test_pushNotifications() {
PushService.init({
serverURI: serverURL,
db
db,
});
let registration = await PushService.registration({
scope: 'https://example.net/a',
scope: "https://example.net/a",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
equal(
registration.endpoint,
serverURL + '/pushEndpointA',
'Wrong push endpoint for scope'
serverURL + "/pushEndpointA",
"Wrong push endpoint for scope"
);
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
@ -17,7 +17,7 @@ var handlerDone;
var handlerPromise = new Promise(r => handlerDone = after(3, r));
function listen4xxCodeHandler(metadata, response) {
ok(true, "Listener point error")
ok(true, "Listener point error");
handlerDone();
response.setStatusLine(metadata.httpVersion, 410, "GONE");
}
@ -26,7 +26,7 @@ function resubscribeHandler(metadata, response) {
ok(true, "Ask for new subscription");
handlerDone();
response.setHeader("Location",
'http://localhost:' + serverPort + '/newSubscription')
"http://localhost:" + serverPort + "/newSubscription");
response.setHeader("Link",
'</newPushEndpoint>; rel="urn:ietf:params:push", ' +
'</newReceiptPushEndpoint>; rel="urn:ietf:params:push:receipt"');
@ -47,20 +47,18 @@ httpServer.registerPathHandler("/newSubscription", listenSuccessHandler);
httpServer.start(-1);
function run_test() {
do_get_profile();
setPrefs({
'testing.allowInsecureServerURL': true,
'testing.notifyWorkers': false,
'testing.notifyAllObservers': true,
"testing.allowInsecureServerURL": true,
"testing.notifyWorkers": false,
"testing.notifyAllObservers": true,
});
run_next_test();
}
add_task(async function test1() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -69,11 +67,11 @@ add_task(async function test1() {
var serverURL = "http://localhost:" + httpServer.identity.primaryPort;
let records = [{
subscriptionUri: serverURL + '/subscription4xxCode',
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
originAttributes: '',
subscriptionUri: serverURL + "/subscription4xxCode",
pushEndpoint: serverURL + "/pushEndpoint",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint",
scope: "https://example.com/page",
originAttributes: "",
quota: Infinity,
}];
@ -83,20 +81,19 @@ add_task(async function test1() {
PushService.init({
serverURI: serverURL + "/subscribe",
db
db,
});
await handlerPromise;
let record = await db.getByIdentifiers({
scope: 'https://example.com/page',
originAttributes: '',
scope: "https://example.com/page",
originAttributes: "",
});
equal(record.keyID, serverURL + '/newSubscription',
'Should update subscription URL');
equal(record.pushEndpoint, serverURL + '/newPushEndpoint',
'Should update push endpoint');
equal(record.pushReceiptEndpoint, serverURL + '/newReceiptPushEndpoint',
'Should update push receipt endpoint');
equal(record.keyID, serverURL + "/newSubscription",
"Should update subscription URL");
equal(record.pushEndpoint, serverURL + "/newPushEndpoint",
"Should update push endpoint");
equal(record.pushReceiptEndpoint, serverURL + "/newReceiptPushEndpoint",
"Should update push receipt endpoint");
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
@ -21,7 +21,7 @@ function listen5xxCodeHandler(metadata, response) {
ok(true, "Listener 5xx code");
handlerDone();
retries++;
response.setHeader("Retry-After", '1');
response.setHeader("Retry-After", "1");
response.setStatusLine(metadata.httpVersion, 500, "Retry");
}
@ -30,7 +30,7 @@ function resubscribeHandler(metadata, response) {
ok(retries == 3, "Should retry 2 times.");
handlerDone();
response.setHeader("Location",
'http://localhost:' + serverPort + '/newSubscription')
"http://localhost:" + serverPort + "/newSubscription");
response.setHeader("Link",
'</newPushEndpoint>; rel="urn:ietf:params:push", ' +
'</newReceiptPushEndpoint>; rel="urn:ietf:params:push:receipt"');
@ -51,19 +51,17 @@ httpServer.registerPathHandler("/newSubscription", listenSuccessHandler);
httpServer.start(-1);
function run_test() {
do_get_profile();
setPrefs({
'testing.allowInsecureServerURL': true,
'http2.retryInterval': 1000,
'http2.maxRetries': 2
"testing.allowInsecureServerURL": true,
"http2.retryInterval": 1000,
"http2.maxRetries": 2,
});
run_next_test();
}
add_task(async function test1() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -72,11 +70,11 @@ add_task(async function test1() {
var serverURL = "http://localhost:" + httpServer.identity.primaryPort;
let records = [{
subscriptionUri: serverURL + '/subscription5xxCode',
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
originAttributes: '',
subscriptionUri: serverURL + "/subscription5xxCode",
pushEndpoint: serverURL + "/pushEndpoint",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint",
scope: "https://example.com/page",
originAttributes: "",
quota: Infinity,
}];
@ -86,20 +84,19 @@ add_task(async function test1() {
PushService.init({
serverURI: serverURL + "/subscribe",
db
db,
});
await handlerPromise;
let record = await db.getByIdentifiers({
scope: 'https://example.com/page',
originAttributes: '',
scope: "https://example.com/page",
originAttributes: "",
});
equal(record.keyID, serverURL + '/newSubscription',
'Should update subscription URL');
equal(record.pushEndpoint, serverURL + '/newPushEndpoint',
'Should update push endpoint');
equal(record.pushReceiptEndpoint, serverURL + '/newReceiptPushEndpoint',
'Should update push receipt endpoint');
equal(record.keyID, serverURL + "/newSubscription",
"Should update subscription URL");
equal(record.pushEndpoint, serverURL + "/newPushEndpoint",
"Should update push endpoint");
equal(record.pushReceiptEndpoint, serverURL + "/newReceiptPushEndpoint",
"Should update push receipt endpoint");
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
@ -20,7 +20,7 @@ function resubscribeHandler(metadata, response) {
ok(true, "Ask for new subscription");
handlerDone();
response.setHeader("Location",
'http://localhost:' + serverPort + '/newSubscription')
"http://localhost:" + serverPort + "/newSubscription");
response.setHeader("Link",
'</newPushEndpoint>; rel="urn:ietf:params:push", ' +
'</newReceiptPushEndpoint>; rel="urn:ietf:params:push:receipt"');
@ -40,19 +40,17 @@ httpServer.registerPathHandler("/newSubscription", listenSuccessHandler);
httpServer.start(-1);
function run_test() {
do_get_profile();
setPrefs({
'testing.allowInsecureServerURL': true,
'http2.retryInterval': 1000,
'http2.maxRetries': 2
"testing.allowInsecureServerURL": true,
"http2.retryInterval": 1000,
"http2.maxRetries": 2,
});
run_next_test();
}
add_task(async function test1() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(() => {
return db.drop().then(_ => db.close());
@ -61,21 +59,21 @@ add_task(async function test1() {
var serverURL = "http://localhost:" + httpServer.identity.primaryPort;
let records = [{
subscriptionUri: 'http://localhost/subscriptionNotExist',
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
p256dhPublicKey: 'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA',
subscriptionUri: "http://localhost/subscriptionNotExist",
pushEndpoint: serverURL + "/pushEndpoint",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint",
scope: "https://example.com/page",
p256dhPublicKey: "BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA",
p256dhPrivateKey: {
crv: 'P-256',
d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM',
crv: "P-256",
d: "1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM",
ext: true,
key_ops: ["deriveBits"],
kty: "EC",
x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
x: "8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM",
y: "26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA",
},
originAttributes: '',
originAttributes: "",
quota: Infinity,
}];
@ -85,20 +83,19 @@ add_task(async function test1() {
PushService.init({
serverURI: serverURL + "/subscribe",
db
db,
});
await handlerPromise;
let record = await db.getByIdentifiers({
scope: 'https://example.com/page',
originAttributes: '',
scope: "https://example.com/page",
originAttributes: "",
});
equal(record.keyID, serverURL + '/newSubscription',
'Should update subscription URL');
equal(record.pushEndpoint, serverURL + '/newPushEndpoint',
'Should update push endpoint');
equal(record.pushReceiptEndpoint, serverURL + '/newReceiptPushEndpoint',
'Should update push receipt endpoint');
equal(record.keyID, serverURL + "/newSubscription",
"Should update subscription URL");
equal(record.pushEndpoint, serverURL + "/newPushEndpoint",
"Should update push endpoint");
equal(record.pushReceiptEndpoint, serverURL + "/newReceiptPushEndpoint",
"Should update push receipt endpoint");
});

Просмотреть файл

@ -1,16 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '05f7b940-51b6-4b6f-8032-b83ebb577ded';
const userAgentID = "05f7b940-51b6-4b6f-8032-b83ebb577ded";
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
pingInterval: 2000,
retryBaseInterval: 25,
});
@ -19,14 +19,14 @@ function run_test() {
add_task(async function test_ws_retry() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await db.put({
channelID: '61770ba9-2d57-4134-b949-d40404630d5b',
pushEndpoint: 'https://example.org/push/1',
scope: 'https://example.net/push/1',
channelID: "61770ba9-2d57-4134-b949-d40404630d5b",
pushEndpoint: "https://example.org/push/1",
scope: "https://example.net/push/1",
version: 1,
originAttributes: '',
originAttributes: "",
quota: Infinity,
});
@ -52,7 +52,7 @@ add_task(async function test_ws_retry() {
onHello(request) {
if (reconnects == 10) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
}));

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
Cu.importGlobalProperties(["crypto"]);
@ -33,7 +33,7 @@ function run_test() {
if (isParent) {
add_test(function setUp() {
db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
setUpServiceInParent(PushService, db).then(run_next_test, run_next_test);
});
}
@ -41,15 +41,15 @@ if (isParent) {
add_test(function test_subscribe_success() {
do_test_pending();
PushServiceComponent.subscribe(
'https://example.com/sub/ok',
"https://example.com/sub/ok",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(Components.isSuccessCode(result), 'Error creating subscription');
ok(subscription.isSystemSubscription, 'Expected system subscription');
ok(subscription.endpoint.startsWith('https://example.org/push'), 'Wrong endpoint prefix');
equal(subscription.pushCount, 0, 'Wrong push count');
equal(subscription.lastPush, 0, 'Wrong last push time');
equal(subscription.quota, -1, 'Wrong quota for system subscription');
ok(Components.isSuccessCode(result), "Error creating subscription");
ok(subscription.isSystemSubscription, "Expected system subscription");
ok(subscription.endpoint.startsWith("https://example.org/push"), "Wrong endpoint prefix");
equal(subscription.pushCount, 0, "Wrong push count");
equal(subscription.lastPush, 0, "Wrong last push time");
equal(subscription.quota, -1, "Wrong quota for system subscription");
do_test_finished();
run_next_test();
@ -62,14 +62,14 @@ add_test(function test_subscribeWithKey_error() {
let invalidKey = [0, 1];
PushServiceComponent.subscribeWithKey(
'https://example.com/sub-key/invalid',
"https://example.com/sub-key/invalid",
Services.scriptSecurityManager.getSystemPrincipal(),
invalidKey.length,
invalidKey,
(result, subscription) => {
ok(!Components.isSuccessCode(result), 'Expected error creating subscription with invalid key');
equal(result, Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR, 'Wrong error code for invalid key');
strictEqual(subscription, null, 'Unexpected subscription');
ok(!Components.isSuccessCode(result), "Expected error creating subscription with invalid key");
equal(result, Cr.NS_ERROR_DOM_PUSH_INVALID_KEY_ERR, "Wrong error code for invalid key");
strictEqual(subscription, null, "Unexpected subscription");
do_test_finished();
run_next_test();
@ -82,13 +82,13 @@ add_test(function test_subscribeWithKey_success() {
generateKey().then(key => {
PushServiceComponent.subscribeWithKey(
'https://example.com/sub-key/ok',
"https://example.com/sub-key/ok",
Services.scriptSecurityManager.getSystemPrincipal(),
key.length,
key,
(result, subscription) => {
ok(Components.isSuccessCode(result), 'Error creating subscription with key');
notStrictEqual(subscription, null, 'Expected subscription');
ok(Components.isSuccessCode(result), "Error creating subscription with key");
notStrictEqual(subscription, null, "Expected subscription");
done();
}
);
@ -103,14 +103,14 @@ add_test(function test_subscribeWithKey_conflict() {
generateKey().then(differentKey => {
PushServiceComponent.subscribeWithKey(
'https://example.com/sub-key/ok',
"https://example.com/sub-key/ok",
Services.scriptSecurityManager.getSystemPrincipal(),
differentKey.length,
differentKey,
(result, subscription) => {
ok(!Components.isSuccessCode(result), 'Expected error creating subscription with conflicting key');
equal(result, Cr.NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR, 'Wrong error code for mismatched key');
strictEqual(subscription, null, 'Unexpected subscription');
ok(!Components.isSuccessCode(result), "Expected error creating subscription with conflicting key");
equal(result, Cr.NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR, "Wrong error code for mismatched key");
strictEqual(subscription, null, "Unexpected subscription");
done();
}
);
@ -123,11 +123,11 @@ add_test(function test_subscribeWithKey_conflict() {
add_test(function test_subscribe_error() {
do_test_pending();
PushServiceComponent.subscribe(
'https://example.com/sub/fail',
"https://example.com/sub/fail",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(!Components.isSuccessCode(result), 'Expected error creating subscription');
strictEqual(subscription, null, 'Unexpected subscription');
ok(!Components.isSuccessCode(result), "Expected error creating subscription");
strictEqual(subscription, null, "Unexpected subscription");
do_test_finished();
run_next_test();
@ -138,15 +138,15 @@ add_test(function test_subscribe_error() {
add_test(function test_getSubscription_exists() {
do_test_pending();
PushServiceComponent.getSubscription(
'https://example.com/get/ok',
"https://example.com/get/ok",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(Components.isSuccessCode(result), 'Error getting subscription');
ok(Components.isSuccessCode(result), "Error getting subscription");
equal(subscription.endpoint, 'https://example.org/push/get', 'Wrong endpoint');
equal(subscription.pushCount, 10, 'Wrong push count');
equal(subscription.lastPush, 1438360548322, 'Wrong last push');
equal(subscription.quota, 16, 'Wrong quota for subscription');
equal(subscription.endpoint, "https://example.org/push/get", "Wrong endpoint");
equal(subscription.pushCount, 10, "Wrong push count");
equal(subscription.lastPush, 1438360548322, "Wrong last push");
equal(subscription.quota, 16, "Wrong quota for subscription");
do_test_finished();
run_next_test();
@ -157,11 +157,11 @@ add_test(function test_getSubscription_exists() {
add_test(function test_getSubscription_missing() {
do_test_pending();
PushServiceComponent.getSubscription(
'https://example.com/get/missing',
"https://example.com/get/missing",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(Components.isSuccessCode(result), 'Error getting nonexistent subscription');
strictEqual(subscription, null, 'Nonexistent subscriptions should return null');
ok(Components.isSuccessCode(result), "Error getting nonexistent subscription");
strictEqual(subscription, null, "Nonexistent subscriptions should return null");
do_test_finished();
run_next_test();
@ -172,11 +172,11 @@ add_test(function test_getSubscription_missing() {
add_test(function test_getSubscription_error() {
do_test_pending();
PushServiceComponent.getSubscription(
'https://example.com/get/fail',
"https://example.com/get/fail",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, subscription) => {
ok(!Components.isSuccessCode(result), 'Expected error getting subscription');
strictEqual(subscription, null, 'Unexpected subscription');
ok(!Components.isSuccessCode(result), "Expected error getting subscription");
strictEqual(subscription, null, "Unexpected subscription");
do_test_finished();
run_next_test();
@ -187,11 +187,11 @@ add_test(function test_getSubscription_error() {
add_test(function test_unsubscribe_success() {
do_test_pending();
PushServiceComponent.unsubscribe(
'https://example.com/unsub/ok',
"https://example.com/unsub/ok",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, success) => {
ok(Components.isSuccessCode(result), 'Error unsubscribing');
strictEqual(success, true, 'Expected successful unsubscribe');
ok(Components.isSuccessCode(result), "Error unsubscribing");
strictEqual(success, true, "Expected successful unsubscribe");
do_test_finished();
run_next_test();
@ -202,11 +202,11 @@ add_test(function test_unsubscribe_success() {
add_test(function test_unsubscribe_nonexistent() {
do_test_pending();
PushServiceComponent.unsubscribe(
'https://example.com/unsub/ok',
"https://example.com/unsub/ok",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, success) => {
ok(Components.isSuccessCode(result), 'Error removing nonexistent subscription');
strictEqual(success, false, 'Nonexistent subscriptions should return false');
ok(Components.isSuccessCode(result), "Error removing nonexistent subscription");
strictEqual(success, false, "Nonexistent subscriptions should return false");
do_test_finished();
run_next_test();
@ -217,11 +217,11 @@ add_test(function test_unsubscribe_nonexistent() {
add_test(function test_unsubscribe_error() {
do_test_pending();
PushServiceComponent.unsubscribe(
'https://example.com/unsub/fail',
"https://example.com/unsub/fail",
Services.scriptSecurityManager.getSystemPrincipal(),
(result, success) => {
ok(!Components.isSuccessCode(result), 'Expected error unsubscribing');
strictEqual(success, false, 'Unexpected successful unsubscribe');
ok(!Components.isSuccessCode(result), "Expected error unsubscribing");
strictEqual(success, false, "Unexpected successful unsubscribe");
do_test_finished();
run_next_test();
@ -230,17 +230,17 @@ add_test(function test_unsubscribe_error() {
});
add_test(function test_subscribe_origin_principal() {
let scope = 'https://example.net/origin-principal';
let scope = "https://example.net/origin-principal";
let principal =
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(scope);
do_test_pending();
PushServiceComponent.subscribe(scope, principal, (result, subscription) => {
ok(Components.isSuccessCode(result),
'Expected error creating subscription with origin principal');
"Expected error creating subscription with origin principal");
ok(!subscription.isSystemSubscription,
'Unexpected system subscription for origin principal');
equal(subscription.quota, 16, 'Wrong quota for origin subscription');
"Unexpected system subscription for origin principal");
equal(subscription.quota, 16, "Wrong quota for origin subscription");
do_test_finished();
run_next_test();
@ -250,13 +250,13 @@ add_test(function test_subscribe_origin_principal() {
add_test(function test_subscribe_null_principal() {
do_test_pending();
PushServiceComponent.subscribe(
'chrome://push/null-principal',
"chrome://push/null-principal",
Services.scriptSecurityManager.createNullPrincipal({}),
(result, subscription) => {
ok(!Components.isSuccessCode(result),
'Expected error creating subscription with null principal');
"Expected error creating subscription with null principal");
strictEqual(subscription, null,
'Unexpected subscription with null principal');
"Unexpected subscription with null principal");
do_test_finished();
run_next_test();
@ -266,12 +266,12 @@ add_test(function test_subscribe_null_principal() {
add_test(function test_subscribe_missing_principal() {
do_test_pending();
PushServiceComponent.subscribe('chrome://push/missing-principal', null,
PushServiceComponent.subscribe("chrome://push/missing-principal", null,
(result, subscription) => {
ok(!Components.isSuccessCode(result),
'Expected error creating subscription without principal');
"Expected error creating subscription without principal");
strictEqual(subscription, null,
'Unexpected subscription without principal');
"Unexpected subscription without principal");
do_test_finished();
run_next_test();

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
@ -13,7 +13,7 @@ function run_test() {
add_task(async function test_service_parent() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(() => db.close()); });
await setUpServiceInParent(PushService, db);
// Accessing the lazy service getter will start the service in the main
@ -23,7 +23,7 @@ add_task(async function test_service_parent() {
equal(PushServiceComponent.subscriptionChangeTopic,
"push-subscription-change", "Wrong subscription change observer topic");
await run_test_in_child('./test_service_child.js');
await run_test_in_child("./test_service_child.js");
await tearDownServiceInParent(db);
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService} = serviceExports;
@ -18,22 +18,22 @@ add_task(async function test_unregister_empty_scope() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: '5619557c-86fe-4711-8078-d1fd6987aef7'
uaid: "5619557c-86fe-4711-8078-d1fd6987aef7",
}));
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.unregister({
scope: '',
scope: "",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Invalid page record/,
'Expected error for empty endpoint'
"Expected error for empty endpoint"
);
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const channelID = '00c7fa13-7b71-447d-bd27-a91abc09d1b2';
const channelID = "00c7fa13-7b71-447d-bd27-a91abc09d1b2";
function run_test() {
do_get_profile();
@ -15,12 +15,12 @@ function run_test() {
add_task(async function test_unregister_error() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await db.put({
channelID: channelID,
pushEndpoint: 'https://example.org/update/failure',
scope: 'https://example.net/page/failure',
originAttributes: '',
channelID,
pushEndpoint: "https://example.org/update/failure",
scope: "https://example.net/page/failure",
originAttributes: "",
version: 1,
quota: Infinity,
});
@ -34,34 +34,34 @@ add_task(async function test_unregister_error() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: '083e6c17-1063-4677-8638-ab705aebebc2'
uaid: "083e6c17-1063-4677-8638-ab705aebebc2",
}));
},
onUnregister(request) {
// The server is notified out-of-band. Since channels may be pruned,
// any failures are swallowed.
equal(request.channelID, channelID, 'Unregister: wrong channel ID');
equal(request.channelID, channelID, "Unregister: wrong channel ID");
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
status: 500,
error: 'omg, everything is exploding',
channelID
error: "omg, everything is exploding",
channelID,
}));
unregisterDone();
}
},
});
}
},
});
await PushService.unregister({
scope: 'https://example.net/page/failure',
originAttributes: '',
scope: "https://example.net/page/failure",
originAttributes: "",
});
let result = await db.getByKeyID(channelID);
ok(!result, 'Deleted push record exists');
ok(!result, "Deleted push record exists");
// Make sure we send a request to the server.
await unregisterPromise;

Просмотреть файл

@ -1,37 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = '7f0af1bb-7e1f-4fb8-8e4a-e8de434abde3';
const userAgentID = "7f0af1bb-7e1f-4fb8-8e4a-e8de434abde3";
function run_test() {
do_get_profile();
setPrefs({
userAgentID,
requestTimeout: 150,
retryBaseInterval: 150
retryBaseInterval: 150,
});
run_next_test();
}
add_task(async function test_unregister_invalid_json() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let records = [{
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
pushEndpoint: 'https://example.org/update/1',
scope: 'https://example.edu/page/1',
originAttributes: '',
channelID: "87902e90-c57e-4d18-8354-013f4a556559",
pushEndpoint: "https://example.org/update/1",
scope: "https://example.edu/page/1",
originAttributes: "",
version: 1,
quota: Infinity,
}, {
channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
pushEndpoint: 'https://example.com/update/2',
scope: 'https://example.net/page/1',
originAttributes: '',
channelID: "057caa8f-9b99-47ff-891c-adad18ce603e",
pushEndpoint: "https://example.com/update/2",
scope: "https://example.net/page/1",
originAttributes: "",
version: 1,
quota: Infinity,
}];
@ -48,47 +48,47 @@ add_task(async function test_unregister_invalid_json() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
use_webpush: true,
}));
},
onUnregister(request) {
this.serverSendMsg(');alert(1);(');
this.serverSendMsg(");alert(1);(");
unregisterDone();
}
},
});
}
},
});
await rejects(
await Assert.rejects(
PushService.unregister({
scope: 'https://example.edu/page/1',
originAttributes: '',
scope: "https://example.edu/page/1",
originAttributes: "",
}),
/Request timed out/,
'Expected error for first invalid JSON response'
"Expected error for first invalid JSON response"
);
let record = await db.getByKeyID(
'87902e90-c57e-4d18-8354-013f4a556559');
ok(!record, 'Failed to delete unregistered record');
"87902e90-c57e-4d18-8354-013f4a556559");
ok(!record, "Failed to delete unregistered record");
await rejects(
await Assert.rejects(
PushService.unregister({
scope: 'https://example.net/page/1',
scope: "https://example.net/page/1",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
}),
/Request timed out/,
'Expected error for second invalid JSON response'
"Expected error for second invalid JSON response"
);
record = await db.getByKeyID(
'057caa8f-9b99-47ff-891c-adad18ce603e');
"057caa8f-9b99-47ff-891c-adad18ce603e");
ok(!record,
'Failed to delete unregistered record after receiving invalid JSON');
"Failed to delete unregistered record after receiving invalid JSON");
await unregisterPromise;
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService} = serviceExports;
@ -18,17 +18,17 @@ add_task(async function test_unregister_not_found() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: 'f074ed80-d479-44fa-ba65-792104a79ea9'
uaid: "f074ed80-d479-44fa-ba65-792104a79ea9",
}));
}
},
});
}
},
});
let result = await PushService.unregister({
scope: 'https://example.net/nonexistent',
scope: "https://example.net/nonexistent",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});

Просмотреть файл

@ -1,29 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
const userAgentID = 'fbe865a6-aeb8-446f-873c-aeebdb8d493c';
const channelID = 'db0a7021-ec2d-4bd3-8802-7a6966f10ed8';
const userAgentID = "fbe865a6-aeb8-446f-873c-aeebdb8d493c";
const channelID = "db0a7021-ec2d-4bd3-8802-7a6966f10ed8";
function run_test() {
do_get_profile();
setPrefs({
userAgentID: userAgentID,
userAgentID,
});
run_next_test();
}
add_task(async function test_unregister_success() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
await db.put({
channelID,
pushEndpoint: 'https://example.org/update/unregister-success',
scope: 'https://example.com/page/unregister-success',
originAttributes: '',
pushEndpoint: "https://example.org/update/unregister-success",
scope: "https://example.com/page/unregister-success",
originAttributes: "",
version: 1,
quota: Infinity,
});
@ -37,40 +37,40 @@ add_task(async function test_unregister_success() {
return new MockWebSocket(uri, {
onHello(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: userAgentID,
use_webpush: true,
}));
},
onUnregister(request) {
equal(request.channelID, channelID, 'Should include the channel ID');
equal(request.code, 200, 'Expected manual unregister reason');
equal(request.channelID, channelID, "Should include the channel ID");
equal(request.code, 200, "Expected manual unregister reason");
this.serverSendMsg(JSON.stringify({
messageType: 'unregister',
messageType: "unregister",
status: 200,
channelID
channelID,
}));
unregisterDone();
}
},
});
}
},
});
let subModifiedPromise = promiseObserverNotification(
PushServiceComponent.subscriptionModifiedTopic);
await PushService.unregister({
scope: 'https://example.com/page/unregister-success',
originAttributes: '',
scope: "https://example.com/page/unregister-success",
originAttributes: "",
});
let {data: subModifiedScope} = await subModifiedPromise;
equal(subModifiedScope, 'https://example.com/page/unregister-success',
'Should fire a subscription modified event after unsubscribing');
equal(subModifiedScope, "https://example.com/page/unregister-success",
"Should fire a subscription modified event after unsubscribing");
let record = await db.getByKeyID(channelID);
ok(!record, 'Unregister did not remove record');
ok(!record, "Unregister did not remove record");
await unregisterPromise;
});

Просмотреть файл

@ -1,11 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var prefs;
var pushEnabled;
var pushConnectionEnabled;
@ -15,20 +14,18 @@ function run_test() {
serverPort = getTestServerPort();
do_get_profile();
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
pushEnabled = prefs.getBoolPref("dom.push.enabled");
pushConnectionEnabled = prefs.getBoolPref("dom.push.connection.enabled");
pushEnabled = Services.prefs.getBoolPref("dom.push.enabled");
pushConnectionEnabled = Services.prefs.getBoolPref("dom.push.connection.enabled");
// Set to allow the cert presented by our H2 server
var oldPref = prefs.getIntPref("network.http.speculative-parallel-limit");
prefs.setIntPref("network.http.speculative-parallel-limit", 0);
prefs.setBoolPref("dom.push.enabled", true);
prefs.setBoolPref("dom.push.connection.enabled", true);
var oldPref = Services.prefs.getIntPref("network.http.speculative-parallel-limit");
Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
Services.prefs.setBoolPref("dom.push.enabled", true);
Services.prefs.setBoolPref("dom.push.connection.enabled", true);
trustHttp2CA();
prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
Services.prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
run_next_test();
}
@ -42,10 +39,10 @@ add_task(async function test_pushUnsubscriptionSuccess() {
var serverURL = "https://localhost:" + serverPort;
await db.put({
subscriptionUri: serverURL + '/subscriptionUnsubscriptionSuccess',
pushEndpoint: serverURL + '/pushEndpointUnsubscriptionSuccess',
pushReceiptEndpoint: serverURL + '/receiptPushEndpointUnsubscriptionSuccess',
scope: 'https://example.com/page/unregister-success',
subscriptionUri: serverURL + "/subscriptionUnsubscriptionSuccess",
pushEndpoint: serverURL + "/pushEndpointUnsubscriptionSuccess",
pushReceiptEndpoint: serverURL + "/receiptPushEndpointUnsubscriptionSuccess",
scope: "https://example.com/page/unregister-success",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
quota: Infinity,
@ -53,20 +50,19 @@ add_task(async function test_pushUnsubscriptionSuccess() {
PushService.init({
serverURI: serverURL,
db
db,
});
await PushService.unregister({
scope: 'https://example.com/page/unregister-success',
scope: "https://example.com/page/unregister-success",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
let record = await db.getByKeyID(serverURL + '/subscriptionUnsubscriptionSuccess');
ok(!record, 'Unregister did not remove record');
let record = await db.getByKeyID(serverURL + "/subscriptionUnsubscriptionSuccess");
ok(!record, "Unregister did not remove record");
});
add_task(async function test_complete() {
prefs.setBoolPref("dom.push.enabled", pushEnabled);
prefs.setBoolPref("dom.push.connection.enabled", pushConnectionEnabled);
Services.prefs.setBoolPref("dom.push.enabled", pushEnabled);
Services.prefs.setBoolPref("dom.push.connection.enabled", pushConnectionEnabled);
});

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
@ -25,22 +25,20 @@ httpServer.registerPathHandler("/subscriptionNoKey", listenHandler);
httpServer.start(-1);
function run_test() {
do_get_profile();
setPrefs({
'testing.allowInsecureServerURL': true,
'http2.retryInterval': 1000,
'http2.maxRetries': 2
"testing.allowInsecureServerURL": true,
"http2.retryInterval": 1000,
"http2.maxRetries": 2,
});
run_next_test();
}
add_task(async function test1() {
let db = PushServiceHttp2.newPushDB();
registerCleanupFunction(_ => {
return db.drop().then(_ => db.close());
registerCleanupFunction(() => {
return db.drop().then(() => db.close());
});
do_test_pending();
@ -48,11 +46,11 @@ add_task(async function test1() {
var serverURL = "http://localhost:" + httpServer.identity.primaryPort;
let record = {
subscriptionUri: serverURL + '/subscriptionNoKey',
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
originAttributes: '',
subscriptionUri: serverURL + "/subscriptionNoKey",
pushEndpoint: serverURL + "/pushEndpoint",
pushReceiptEndpoint: serverURL + "/pushReceiptEndpoint",
scope: "https://example.com/page",
originAttributes: "",
quota: Infinity,
systemRecord: true,
};
@ -64,13 +62,13 @@ add_task(async function test1() {
PushService.init({
serverURI: serverURL + "/subscribe",
db
db,
});
await notifyPromise;
let aRecord = await db.getByKeyID(serverURL + '/subscriptionNoKey');
ok(aRecord, 'The record should still be there');
ok(aRecord.p256dhPublicKey, 'There should be a public key');
ok(aRecord.p256dhPrivateKey, 'There should be a private key');
let aRecord = await db.getByKeyID(serverURL + "/subscriptionNoKey");
ok(aRecord, "The record should still be there");
ok(aRecord.p256dhPublicKey, "There should be a public key");
ok(aRecord.p256dhPrivateKey, "There should be a private key");
});

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const {PushDB, PushService, PushServiceWebSocket, PushCrypto} = serviceExports;
const userAgentID = '4dffd396-6582-471d-8c0c-84f394e9f7db';
const userAgentID = "4dffd396-6582-471d-8c0c-84f394e9f7db";
function run_test() {
do_get_profile();
@ -17,20 +17,20 @@ function run_test() {
add_task(async function test_with_data_enabled() {
let db = PushServiceWebSocket.newPushDB();
registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
registerCleanupFunction(() => { return db.drop().then(_ => db.close()); });
let [publicKey, privateKey] = await PushCrypto.generateKeys();
let records = [{
channelID: 'eb18f12a-cc42-4f14-accb-3bfc1227f1aa',
pushEndpoint: 'https://example.org/push/no-key/1',
scope: 'https://example.com/page/1',
originAttributes: '',
channelID: "eb18f12a-cc42-4f14-accb-3bfc1227f1aa",
pushEndpoint: "https://example.org/push/no-key/1",
scope: "https://example.com/page/1",
originAttributes: "",
quota: Infinity,
}, {
channelID: '0d8886b9-8da1-4778-8f5d-1cf93a877ed6',
pushEndpoint: 'https://example.org/push/key',
scope: 'https://example.com/page/2',
originAttributes: '',
channelID: "0d8886b9-8da1-4778-8f5d-1cf93a877ed6",
pushEndpoint: "https://example.org/push/key",
scope: "https://example.com/page/2",
originAttributes: "",
p256dhPublicKey: publicKey,
p256dhPrivateKey: privateKey,
quota: Infinity,
@ -46,9 +46,9 @@ add_task(async function test_with_data_enabled() {
return new MockWebSocket(uri, {
onHello(request) {
ok(request.use_webpush,
'Should use Web Push if data delivery is enabled');
"Should use Web Push if data delivery is enabled");
this.serverSendMsg(JSON.stringify({
messageType: 'hello',
messageType: "hello",
status: 200,
uaid: request.uaid,
use_webpush: true,
@ -56,31 +56,31 @@ add_task(async function test_with_data_enabled() {
},
onRegister(request) {
this.serverSendMsg(JSON.stringify({
messageType: 'register',
messageType: "register",
status: 200,
uaid: userAgentID,
channelID: request.channelID,
pushEndpoint: 'https://example.org/push/new',
pushEndpoint: "https://example.org/push/new",
}));
}
},
});
},
});
let newRecord = await PushService.register({
scope: 'https://example.com/page/3',
scope: "https://example.com/page/3",
originAttributes: ChromeUtils.originAttributesToSuffix(
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
});
ok(newRecord.p256dhKey, 'Should generate public keys for new records');
ok(newRecord.p256dhKey, "Should generate public keys for new records");
let record = await db.getByKeyID('eb18f12a-cc42-4f14-accb-3bfc1227f1aa');
ok(record.p256dhPublicKey, 'Should add public key to partial record');
ok(record.p256dhPrivateKey, 'Should add private key to partial record');
let record = await db.getByKeyID("eb18f12a-cc42-4f14-accb-3bfc1227f1aa");
ok(record.p256dhPublicKey, "Should add public key to partial record");
ok(record.p256dhPrivateKey, "Should add private key to partial record");
record = await db.getByKeyID('0d8886b9-8da1-4778-8f5d-1cf93a877ed6');
record = await db.getByKeyID("0d8886b9-8da1-4778-8f5d-1cf93a877ed6");
deepEqual(record.p256dhPublicKey, publicKey,
'Should leave existing public key');
"Should leave existing public key");
deepEqual(record.p256dhPrivateKey, privateKey,
'Should leave existing private key');
"Should leave existing private key");
});