forked from mirrors/gecko-dev
Backed out changeset 17d4c013ed92 (bug 1817183) Backed out changeset cfed8d9c23f3 (bug 1817183) Backed out changeset 62fe2f589efe (bug 1817182) Backed out changeset 557bd773fb85 (bug 1817179) Backed out changeset 7f8a7865868b (bug 1816934) Backed out changeset d6c1d4c0d2a0 (bug 1816934)
1356 lines
36 KiB
JavaScript
1356 lines
36 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const {
|
|
ON_PROFILE_CHANGE_NOTIFICATION,
|
|
WEBCHANNEL_ID,
|
|
log,
|
|
} = ChromeUtils.import("resource://gre/modules/FxAccountsCommon.js");
|
|
const { CryptoUtils } = ChromeUtils.import(
|
|
"resource://services-crypto/utils.js"
|
|
);
|
|
const {
|
|
FxAccountsWebChannel,
|
|
FxAccountsWebChannelHelpers,
|
|
} = ChromeUtils.import("resource://gre/modules/FxAccountsWebChannel.jsm");
|
|
|
|
const URL_STRING = "https://example.com";
|
|
|
|
const mockSendingContext = {
|
|
browsingContext: { top: { embedderElement: {} } },
|
|
principal: {},
|
|
eventTarget: {},
|
|
};
|
|
|
|
add_test(function() {
|
|
validationHelper(undefined, "Error: Missing configuration options");
|
|
|
|
validationHelper(
|
|
{
|
|
channel_id: WEBCHANNEL_ID,
|
|
},
|
|
"Error: Missing 'content_uri' option"
|
|
);
|
|
|
|
validationHelper(
|
|
{
|
|
content_uri: "bad uri",
|
|
channel_id: WEBCHANNEL_ID,
|
|
},
|
|
/NS_ERROR_MALFORMED_URI/
|
|
);
|
|
|
|
validationHelper(
|
|
{
|
|
content_uri: URL_STRING,
|
|
},
|
|
"Error: Missing 'channel_id' option"
|
|
);
|
|
|
|
run_next_test();
|
|
});
|
|
|
|
add_task(async function test_rejection_reporting() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:login",
|
|
messageId: "1234",
|
|
data: { email: "testuser@testuser.com" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
login(accountData) {
|
|
equal(
|
|
accountData.email,
|
|
"testuser@testuser.com",
|
|
"Should forward incoming message data to the helper"
|
|
);
|
|
return Promise.reject(new Error("oops"));
|
|
},
|
|
},
|
|
});
|
|
|
|
let promiseSend = new Promise(resolve => {
|
|
channel._channel.send = (message, context) => {
|
|
resolve({ message, context });
|
|
};
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
|
|
let { message, context } = await promiseSend;
|
|
|
|
equal(context, mockSendingContext, "Should forward the original context");
|
|
equal(
|
|
message.command,
|
|
"fxaccounts:login",
|
|
"Should include the incoming command"
|
|
);
|
|
equal(message.messageId, "1234", "Should include the message ID");
|
|
equal(
|
|
message.data.error.message,
|
|
"Error: oops",
|
|
"Should convert the error message to a string"
|
|
);
|
|
notStrictEqual(
|
|
message.data.error.stack,
|
|
null,
|
|
"Should include the stack for JS error rejections"
|
|
);
|
|
});
|
|
|
|
add_test(function test_exception_reporting() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:sync_preferences",
|
|
messageId: "5678",
|
|
data: { entryPoint: "fxa:verification_complete" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
openSyncPreferences(browser, entryPoint) {
|
|
equal(
|
|
entryPoint,
|
|
"fxa:verification_complete",
|
|
"Should forward incoming message data to the helper"
|
|
);
|
|
throw new TypeError("splines not reticulated");
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channel.send = (message, context) => {
|
|
equal(context, mockSendingContext, "Should forward the original context");
|
|
equal(
|
|
message.command,
|
|
"fxaccounts:sync_preferences",
|
|
"Should include the incoming command"
|
|
);
|
|
equal(message.messageId, "5678", "Should include the message ID");
|
|
equal(
|
|
message.data.error.message,
|
|
"TypeError: splines not reticulated",
|
|
"Should convert the exception to a string"
|
|
);
|
|
notStrictEqual(
|
|
message.data.error.stack,
|
|
null,
|
|
"Should include the stack for JS exceptions"
|
|
);
|
|
|
|
run_next_test();
|
|
};
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_error_message_remove_profile_path() {
|
|
const errors = {
|
|
windows: {
|
|
err: new Error(
|
|
"Win error 183 during operation rename on file C:\\Users\\Some Computer\\AppData\\Roaming\\" +
|
|
"Mozilla\\Firefox\\Profiles\\dbzjmzxa.default\\signedInUser.json (Cannot create a file)"
|
|
),
|
|
expected:
|
|
"Error: Win error 183 during operation rename on file C:[REDACTED]signedInUser.json (Cannot create a file)",
|
|
},
|
|
unix: {
|
|
err: new Error(
|
|
"Unix error 28 during operation write on file /Users/someuser/Library/Application Support/" +
|
|
"Firefox/Profiles/dbzjmzxa.default-release-7/signedInUser.json (No space left on device)"
|
|
),
|
|
expected:
|
|
"Error: Unix error 28 during operation write on file [REDACTED]signedInUser.json (No space left on device)",
|
|
},
|
|
netpath: {
|
|
err: new Error(
|
|
"Win error 32 during operation rename on file \\\\SVC.LOC\\HOMEDIRS$\\USERNAME\\Mozilla\\" +
|
|
"Firefox\\Profiles\\dbzjmzxa.default-release-7\\signedInUser.json (No space left on device)"
|
|
),
|
|
expected:
|
|
"Error: Win error 32 during operation rename on file [REDACTED]signedInUser.json (No space left on device)",
|
|
},
|
|
mount: {
|
|
err: new Error(
|
|
"Win error 649 during operation rename on file C:\\SnapVolumes\\MountPoints\\" +
|
|
"{9e399ec5-0000-0000-0000-100000000000}\\SVROOT\\Users\\username\\AppData\\Roaming\\Mozilla\\Firefox\\" +
|
|
"Profiles\\dbzjmzxa.default-release\\signedInUser.json (The create operation failed)"
|
|
),
|
|
expected:
|
|
"Error: Win error 649 during operation rename on file C:[REDACTED]signedInUser.json " +
|
|
"(The create operation failed)",
|
|
},
|
|
};
|
|
const mockMessage = {
|
|
command: "fxaccounts:sync_preferences",
|
|
messageId: "1234",
|
|
};
|
|
const channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
});
|
|
|
|
let testNum = 0;
|
|
const toTest = Object.keys(errors).length;
|
|
for (const key in errors) {
|
|
let error = errors[key];
|
|
channel._channel.send = (message, context) => {
|
|
equal(
|
|
message.data.error.message,
|
|
error.expected,
|
|
"Should remove the profile path from the error message"
|
|
);
|
|
testNum++;
|
|
if (testNum === toTest) {
|
|
run_next_test();
|
|
}
|
|
};
|
|
channel._sendError(error.err, mockMessage, mockSendingContext);
|
|
}
|
|
});
|
|
|
|
add_test(function test_profile_image_change_message() {
|
|
var mockMessage = {
|
|
command: "profile:change",
|
|
data: { uid: "foo" },
|
|
};
|
|
|
|
makeObserver(ON_PROFILE_CHANGE_NOTIFICATION, function(subject, topic, data) {
|
|
Assert.equal(data, "foo");
|
|
run_next_test();
|
|
});
|
|
|
|
var channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_login_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:login",
|
|
data: { email: "testuser@testuser.com" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
login(accountData) {
|
|
Assert.equal(accountData.email, "testuser@testuser.com");
|
|
run_next_test();
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_logout_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:logout",
|
|
data: { uid: "foo" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
logout(uid) {
|
|
Assert.equal(uid, "foo");
|
|
run_next_test();
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_delete_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:delete",
|
|
data: { uid: "foo" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
logout(uid) {
|
|
Assert.equal(uid, "foo");
|
|
run_next_test();
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_can_link_account_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:can_link_account",
|
|
data: { email: "testuser@testuser.com" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
shouldAllowRelink(email) {
|
|
Assert.equal(email, "testuser@testuser.com");
|
|
run_next_test();
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_sync_preferences_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:sync_preferences",
|
|
data: { entryPoint: "fxa:verification_complete" },
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
openSyncPreferences(browser, entryPoint) {
|
|
Assert.equal(entryPoint, "fxa:verification_complete");
|
|
Assert.equal(
|
|
browser,
|
|
mockSendingContext.browsingContext.top.embedderElement
|
|
);
|
|
run_next_test();
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_fxa_status_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:fxa_status",
|
|
messageId: 123,
|
|
data: {
|
|
service: "sync",
|
|
context: "fx_desktop_v3",
|
|
},
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
helpers: {
|
|
async getFxaStatus(service, sendingContext, isPairing, context) {
|
|
Assert.equal(service, "sync");
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
Assert.ok(!isPairing);
|
|
Assert.equal(context, "fx_desktop_v3");
|
|
return {
|
|
signedInUser: {
|
|
email: "testuser@testuser.com",
|
|
sessionToken: "session-token",
|
|
uid: "uid",
|
|
verified: true,
|
|
},
|
|
capabilities: {
|
|
engines: ["creditcards", "addresses"],
|
|
},
|
|
};
|
|
},
|
|
},
|
|
});
|
|
|
|
channel._channel = {
|
|
send(response, sendingContext) {
|
|
Assert.equal(response.command, "fxaccounts:fxa_status");
|
|
Assert.equal(response.messageId, 123);
|
|
|
|
let signedInUser = response.data.signedInUser;
|
|
Assert.ok(!!signedInUser);
|
|
Assert.equal(signedInUser.email, "testuser@testuser.com");
|
|
Assert.equal(signedInUser.sessionToken, "session-token");
|
|
Assert.equal(signedInUser.uid, "uid");
|
|
Assert.equal(signedInUser.verified, true);
|
|
|
|
deepEqual(response.data.capabilities.engines, [
|
|
"creditcards",
|
|
"addresses",
|
|
]);
|
|
|
|
run_next_test();
|
|
},
|
|
};
|
|
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
});
|
|
|
|
add_test(function test_unrecognized_message() {
|
|
let mockMessage = {
|
|
command: "fxaccounts:unrecognized",
|
|
data: {},
|
|
};
|
|
|
|
let channel = new FxAccountsWebChannel({
|
|
channel_id: WEBCHANNEL_ID,
|
|
content_uri: URL_STRING,
|
|
});
|
|
|
|
// no error is expected.
|
|
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
|
|
run_next_test();
|
|
});
|
|
|
|
add_test(function test_helpers_should_allow_relink_same_email() {
|
|
let helpers = new FxAccountsWebChannelHelpers();
|
|
|
|
helpers.setPreviousAccountNameHashPref("testuser@testuser.com");
|
|
Assert.ok(helpers.shouldAllowRelink("testuser@testuser.com"));
|
|
|
|
run_next_test();
|
|
});
|
|
|
|
add_test(function test_helpers_should_allow_relink_different_email() {
|
|
let helpers = new FxAccountsWebChannelHelpers();
|
|
|
|
helpers.setPreviousAccountNameHashPref("testuser@testuser.com");
|
|
|
|
helpers._promptForRelink = acctName => {
|
|
return acctName === "allowed_to_relink@testuser.com";
|
|
};
|
|
|
|
Assert.ok(helpers.shouldAllowRelink("allowed_to_relink@testuser.com"));
|
|
Assert.ok(!helpers.shouldAllowRelink("not_allowed_to_relink@testuser.com"));
|
|
|
|
run_next_test();
|
|
});
|
|
|
|
add_task(async function test_helpers_login_without_customize_sync() {
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
setSignedInUser(accountData) {
|
|
return new Promise(resolve => {
|
|
// ensure fxAccounts is informed of the new user being signed in.
|
|
Assert.equal(accountData.email, "testuser@testuser.com");
|
|
|
|
// verifiedCanLinkAccount should be stripped in the data.
|
|
Assert.equal(false, "verifiedCanLinkAccount" in accountData);
|
|
|
|
resolve();
|
|
});
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection: sinon.spy(),
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// ensure the previous account pref is overwritten.
|
|
helpers.setPreviousAccountNameHashPref("lastuser@testuser.com");
|
|
|
|
await helpers.login({
|
|
email: "testuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
customizeSync: false,
|
|
});
|
|
Assert.ok(
|
|
helpers._fxAccounts.telemetry.recordConnection.calledWith([], "webchannel")
|
|
);
|
|
});
|
|
|
|
add_task(async function test_helpers_login_set_previous_account_name_hash() {
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
setSignedInUser(accountData) {
|
|
return new Promise(resolve => {
|
|
// previously signed in user preference is updated.
|
|
Assert.equal(
|
|
helpers.getPreviousAccountNameHashPref(),
|
|
CryptoUtils.sha256Base64("newuser@testuser.com")
|
|
);
|
|
resolve();
|
|
});
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection() {},
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// ensure the previous account pref is overwritten.
|
|
helpers.setPreviousAccountNameHashPref("lastuser@testuser.com");
|
|
|
|
await helpers.login({
|
|
email: "newuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
customizeSync: false,
|
|
verified: true,
|
|
});
|
|
});
|
|
|
|
add_task(
|
|
async function test_helpers_login_dont_set_previous_account_name_hash_for_unverified_emails() {
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
setSignedInUser(accountData) {
|
|
return new Promise(resolve => {
|
|
// previously signed in user preference should not be updated.
|
|
Assert.equal(
|
|
helpers.getPreviousAccountNameHashPref(),
|
|
CryptoUtils.sha256Base64("lastuser@testuser.com")
|
|
);
|
|
resolve();
|
|
});
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection() {},
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// ensure the previous account pref is overwritten.
|
|
helpers.setPreviousAccountNameHashPref("lastuser@testuser.com");
|
|
|
|
await helpers.login({
|
|
email: "newuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
customizeSync: false,
|
|
});
|
|
}
|
|
);
|
|
|
|
add_task(async function test_helpers_login_with_customize_sync() {
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
setSignedInUser(accountData) {
|
|
return new Promise(resolve => {
|
|
// ensure fxAccounts is informed of the new user being signed in.
|
|
Assert.equal(accountData.email, "testuser@testuser.com");
|
|
|
|
// customizeSync should be stripped in the data.
|
|
Assert.equal(false, "customizeSync" in accountData);
|
|
|
|
resolve();
|
|
});
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection: sinon.spy(),
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
await helpers.login({
|
|
email: "testuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
customizeSync: true,
|
|
});
|
|
Assert.ok(
|
|
helpers._fxAccounts.telemetry.recordConnection.calledWith([], "webchannel")
|
|
);
|
|
});
|
|
|
|
add_task(
|
|
async function test_helpers_login_with_customize_sync_and_declined_engines() {
|
|
let configured = false;
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
setSignedInUser(accountData) {
|
|
return new Promise(resolve => {
|
|
// ensure fxAccounts is informed of the new user being signed in.
|
|
Assert.equal(accountData.email, "testuser@testuser.com");
|
|
|
|
// customizeSync should be stripped in the data.
|
|
Assert.equal(false, "customizeSync" in accountData);
|
|
Assert.equal(false, "services" in accountData);
|
|
resolve();
|
|
});
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection: sinon.spy(),
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {
|
|
configured = true;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.addons"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.bookmarks"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.history"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.passwords"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.prefs"),
|
|
true
|
|
);
|
|
Assert.equal(Services.prefs.getBoolPref("services.sync.engine.tabs"), true);
|
|
await helpers.login({
|
|
email: "testuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
customizeSync: true,
|
|
services: {
|
|
sync: {
|
|
offeredEngines: [
|
|
"addons",
|
|
"bookmarks",
|
|
"history",
|
|
"passwords",
|
|
"prefs",
|
|
],
|
|
declinedEngines: ["addons", "prefs"],
|
|
},
|
|
},
|
|
});
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.addons"),
|
|
false
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.bookmarks"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.history"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.passwords"),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
Services.prefs.getBoolPref("services.sync.engine.prefs"),
|
|
false
|
|
);
|
|
Assert.equal(Services.prefs.getBoolPref("services.sync.engine.tabs"), true);
|
|
Assert.ok(configured, "sync was configured");
|
|
Assert.ok(
|
|
helpers._fxAccounts.telemetry.recordConnection.calledWith(
|
|
["sync"],
|
|
"webchannel"
|
|
)
|
|
);
|
|
}
|
|
);
|
|
|
|
add_task(async function test_helpers_login_with_offered_sync_engines() {
|
|
let helpers;
|
|
let configured = false;
|
|
const setSignedInUserCalled = new Promise(resolve => {
|
|
helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
async setSignedInUser(accountData) {
|
|
resolve(accountData);
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection() {},
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {
|
|
configured = true;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
Services.prefs.setBoolPref("services.sync.engine.creditcards", false);
|
|
Services.prefs.setBoolPref("services.sync.engine.addresses", false);
|
|
|
|
await helpers.login({
|
|
email: "testuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
customizeSync: true,
|
|
services: {
|
|
sync: {
|
|
declinedEngines: ["addresses"],
|
|
offeredEngines: ["creditcards", "addresses"],
|
|
},
|
|
},
|
|
});
|
|
|
|
const accountData = await setSignedInUserCalled;
|
|
|
|
// ensure fxAccounts is informed of the new user being signed in.
|
|
equal(accountData.email, "testuser@testuser.com");
|
|
|
|
// services should be stripped in the data.
|
|
ok(!("services" in accountData));
|
|
// credit cards was offered but not declined.
|
|
equal(Services.prefs.getBoolPref("services.sync.engine.creditcards"), true);
|
|
// addresses was offered and explicitely declined.
|
|
equal(Services.prefs.getBoolPref("services.sync.engine.addresses"), false);
|
|
ok(configured);
|
|
});
|
|
|
|
add_task(async function test_helpers_login_nothing_offered() {
|
|
let helpers;
|
|
let configured = false;
|
|
const setSignedInUserCalled = new Promise(resolve => {
|
|
helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
async setSignedInUser(accountData) {
|
|
resolve(accountData);
|
|
},
|
|
},
|
|
telemetry: {
|
|
recordConnection() {},
|
|
},
|
|
},
|
|
weaveXPCOM: {
|
|
whenLoaded() {},
|
|
Weave: {
|
|
Service: {
|
|
configure() {
|
|
configured = true;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
// doesn't really matter if it's *all* engines...
|
|
const allEngines = [
|
|
"addons",
|
|
"addresses",
|
|
"bookmarks",
|
|
"creditcards",
|
|
"history",
|
|
"passwords",
|
|
"prefs",
|
|
];
|
|
for (let name of allEngines) {
|
|
Services.prefs.clearUserPref("services.sync.engine." + name);
|
|
}
|
|
|
|
await helpers.login({
|
|
email: "testuser@testuser.com",
|
|
verifiedCanLinkAccount: true,
|
|
services: {
|
|
sync: {},
|
|
},
|
|
});
|
|
|
|
const accountData = await setSignedInUserCalled;
|
|
// ensure fxAccounts is informed of the new user being signed in.
|
|
equal(accountData.email, "testuser@testuser.com");
|
|
|
|
for (let name of allEngines) {
|
|
Assert.ok(!Services.prefs.prefHasUserValue("services.sync.engine." + name));
|
|
}
|
|
Assert.ok(configured);
|
|
});
|
|
|
|
add_test(function test_helpers_open_sync_preferences() {
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {},
|
|
});
|
|
|
|
let mockBrowser = {
|
|
loadURI(uri) {
|
|
Assert.equal(
|
|
uri.spec,
|
|
"about:preferences?entrypoint=fxa%3Averification_complete#sync"
|
|
);
|
|
run_next_test();
|
|
},
|
|
};
|
|
|
|
helpers.openSyncPreferences(mockBrowser, "fxa:verification_complete");
|
|
});
|
|
|
|
add_task(async function test_helpers_getFxAStatus_extra_engines() {
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
getUserAccountData() {
|
|
return Promise.resolve({
|
|
email: "testuser@testuser.com",
|
|
sessionToken: "sessionToken",
|
|
uid: "uid",
|
|
verified: true,
|
|
});
|
|
},
|
|
},
|
|
},
|
|
privateBrowsingUtils: {
|
|
isBrowserPrivate: () => true,
|
|
},
|
|
});
|
|
|
|
Services.prefs.setBoolPref(
|
|
"services.sync.engine.creditcards.available",
|
|
true
|
|
);
|
|
// Not defining "services.sync.engine.addresses.available" on purpose.
|
|
|
|
let fxaStatus = await helpers.getFxaStatus("sync", mockSendingContext);
|
|
ok(!!fxaStatus);
|
|
ok(!!fxaStatus.signedInUser);
|
|
deepEqual(fxaStatus.capabilities.engines, ["creditcards"]);
|
|
});
|
|
|
|
add_task(async function test_helpers_getFxaStatus_allowed_signedInUser() {
|
|
let wasCalled = {
|
|
getUserAccountData: false,
|
|
shouldAllowFxaStatus: false,
|
|
};
|
|
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
getUserAccountData() {
|
|
wasCalled.getUserAccountData = true;
|
|
return Promise.resolve({
|
|
email: "testuser@testuser.com",
|
|
sessionToken: "sessionToken",
|
|
uid: "uid",
|
|
verified: true,
|
|
});
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
helpers.shouldAllowFxaStatus = (service, sendingContext) => {
|
|
wasCalled.shouldAllowFxaStatus = true;
|
|
Assert.equal(service, "sync");
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
|
|
return true;
|
|
};
|
|
|
|
return helpers.getFxaStatus("sync", mockSendingContext).then(fxaStatus => {
|
|
Assert.ok(!!fxaStatus);
|
|
Assert.ok(wasCalled.getUserAccountData);
|
|
Assert.ok(wasCalled.shouldAllowFxaStatus);
|
|
|
|
Assert.ok(!!fxaStatus.signedInUser);
|
|
let { signedInUser } = fxaStatus;
|
|
|
|
Assert.equal(signedInUser.email, "testuser@testuser.com");
|
|
Assert.equal(signedInUser.sessionToken, "sessionToken");
|
|
Assert.equal(signedInUser.uid, "uid");
|
|
Assert.ok(signedInUser.verified);
|
|
|
|
// These properties are filtered and should not
|
|
// be returned to the requester.
|
|
Assert.equal(false, "kSync" in signedInUser);
|
|
Assert.equal(false, "kXCS" in signedInUser);
|
|
Assert.equal(false, "kExtSync" in signedInUser);
|
|
Assert.equal(false, "kExtKbHash" in signedInUser);
|
|
});
|
|
});
|
|
|
|
add_task(async function test_helpers_getFxaStatus_allowed_no_signedInUser() {
|
|
let wasCalled = {
|
|
getUserAccountData: false,
|
|
shouldAllowFxaStatus: false,
|
|
};
|
|
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
getUserAccountData() {
|
|
wasCalled.getUserAccountData = true;
|
|
return Promise.resolve(null);
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
helpers.shouldAllowFxaStatus = (service, sendingContext) => {
|
|
wasCalled.shouldAllowFxaStatus = true;
|
|
Assert.equal(service, "sync");
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
|
|
return true;
|
|
};
|
|
|
|
return helpers.getFxaStatus("sync", mockSendingContext).then(fxaStatus => {
|
|
Assert.ok(!!fxaStatus);
|
|
Assert.ok(wasCalled.getUserAccountData);
|
|
Assert.ok(wasCalled.shouldAllowFxaStatus);
|
|
|
|
Assert.equal(null, fxaStatus.signedInUser);
|
|
});
|
|
});
|
|
|
|
add_task(async function test_helpers_getFxaStatus_not_allowed() {
|
|
let wasCalled = {
|
|
getUserAccountData: false,
|
|
shouldAllowFxaStatus: false,
|
|
};
|
|
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
getUserAccountData() {
|
|
wasCalled.getUserAccountData = true;
|
|
return Promise.resolve(null);
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
helpers.shouldAllowFxaStatus = (
|
|
service,
|
|
sendingContext,
|
|
isPairing,
|
|
context
|
|
) => {
|
|
wasCalled.shouldAllowFxaStatus = true;
|
|
Assert.equal(service, "sync");
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
Assert.ok(!isPairing);
|
|
Assert.equal(context, "fx_desktop_v3");
|
|
|
|
return false;
|
|
};
|
|
|
|
return helpers
|
|
.getFxaStatus("sync", mockSendingContext, false, "fx_desktop_v3")
|
|
.then(fxaStatus => {
|
|
Assert.ok(!!fxaStatus);
|
|
Assert.ok(!wasCalled.getUserAccountData);
|
|
Assert.ok(wasCalled.shouldAllowFxaStatus);
|
|
|
|
Assert.equal(null, fxaStatus.signedInUser);
|
|
});
|
|
});
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_sync_service_not_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return false;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"sync",
|
|
mockSendingContext,
|
|
false
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_desktop_context_not_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return false;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"",
|
|
mockSendingContext,
|
|
false,
|
|
"fx_desktop_v3"
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_oauth_service_not_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return false;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"dcdb5ae7add825d2",
|
|
mockSendingContext,
|
|
false
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_no_service_not_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return false;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"",
|
|
mockSendingContext,
|
|
false
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_sync_service_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return true;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"sync",
|
|
mockSendingContext,
|
|
false
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_desktop_context_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return true;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"",
|
|
mockSendingContext,
|
|
false,
|
|
"fx_desktop_v3"
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_oauth_service_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return true;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"dcdb5ae7add825d2",
|
|
mockSendingContext,
|
|
false
|
|
);
|
|
Assert.ok(!shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_oauth_service_pairing_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return true;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"dcdb5ae7add825d2",
|
|
mockSendingContext,
|
|
true
|
|
);
|
|
Assert.ok(shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_helpers_shouldAllowFxaStatus_no_service_private_browsing() {
|
|
let wasCalled = {
|
|
isPrivateBrowsingMode: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({});
|
|
|
|
helpers.isPrivateBrowsingMode = sendingContext => {
|
|
wasCalled.isPrivateBrowsingMode = true;
|
|
Assert.equal(sendingContext, mockSendingContext);
|
|
return true;
|
|
};
|
|
|
|
let shouldAllowFxaStatus = helpers.shouldAllowFxaStatus(
|
|
"",
|
|
mockSendingContext,
|
|
false
|
|
);
|
|
Assert.ok(!shouldAllowFxaStatus);
|
|
Assert.ok(wasCalled.isPrivateBrowsingMode);
|
|
}
|
|
);
|
|
|
|
add_task(async function test_helpers_isPrivateBrowsingMode_private_browsing() {
|
|
let wasCalled = {
|
|
isBrowserPrivate: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
privateBrowsingUtils: {
|
|
isBrowserPrivate(browser) {
|
|
wasCalled.isBrowserPrivate = true;
|
|
Assert.equal(
|
|
browser,
|
|
mockSendingContext.browsingContext.top.embedderElement
|
|
);
|
|
return true;
|
|
},
|
|
},
|
|
});
|
|
|
|
let isPrivateBrowsingMode = helpers.isPrivateBrowsingMode(mockSendingContext);
|
|
Assert.ok(isPrivateBrowsingMode);
|
|
Assert.ok(wasCalled.isBrowserPrivate);
|
|
});
|
|
|
|
add_task(async function test_helpers_isPrivateBrowsingMode_private_browsing() {
|
|
let wasCalled = {
|
|
isBrowserPrivate: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
privateBrowsingUtils: {
|
|
isBrowserPrivate(browser) {
|
|
wasCalled.isBrowserPrivate = true;
|
|
Assert.equal(
|
|
browser,
|
|
mockSendingContext.browsingContext.top.embedderElement
|
|
);
|
|
return false;
|
|
},
|
|
},
|
|
});
|
|
|
|
let isPrivateBrowsingMode = helpers.isPrivateBrowsingMode(mockSendingContext);
|
|
Assert.ok(!isPrivateBrowsingMode);
|
|
Assert.ok(wasCalled.isBrowserPrivate);
|
|
});
|
|
|
|
add_task(async function test_helpers_change_password() {
|
|
let wasCalled = {
|
|
updateUserAccountData: false,
|
|
updateDeviceRegistration: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
updateUserAccountData(credentials) {
|
|
return new Promise(resolve => {
|
|
Assert.ok(credentials.hasOwnProperty("email"));
|
|
Assert.ok(credentials.hasOwnProperty("uid"));
|
|
Assert.ok(credentials.hasOwnProperty("unwrapBKey"));
|
|
Assert.ok(credentials.hasOwnProperty("device"));
|
|
Assert.equal(null, credentials.device);
|
|
Assert.equal(null, credentials.encryptedSendTabKeys);
|
|
// "foo" isn't a field known by storage, so should be dropped.
|
|
Assert.ok(!credentials.hasOwnProperty("foo"));
|
|
wasCalled.updateUserAccountData = true;
|
|
|
|
resolve();
|
|
});
|
|
},
|
|
|
|
updateDeviceRegistration() {
|
|
Assert.equal(arguments.length, 0);
|
|
wasCalled.updateDeviceRegistration = true;
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
},
|
|
});
|
|
await helpers.changePassword({
|
|
email: "email",
|
|
uid: "uid",
|
|
unwrapBKey: "unwrapBKey",
|
|
foo: "foo",
|
|
});
|
|
Assert.ok(wasCalled.updateUserAccountData);
|
|
Assert.ok(wasCalled.updateDeviceRegistration);
|
|
});
|
|
|
|
add_task(async function test_helpers_change_password_with_error() {
|
|
let wasCalled = {
|
|
updateUserAccountData: false,
|
|
updateDeviceRegistration: false,
|
|
};
|
|
let helpers = new FxAccountsWebChannelHelpers({
|
|
fxAccounts: {
|
|
_internal: {
|
|
updateUserAccountData() {
|
|
wasCalled.updateUserAccountData = true;
|
|
return Promise.reject();
|
|
},
|
|
|
|
updateDeviceRegistration() {
|
|
wasCalled.updateDeviceRegistration = true;
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
},
|
|
});
|
|
try {
|
|
await helpers.changePassword({});
|
|
Assert.equal(false, "changePassword should have rejected");
|
|
} catch (_) {
|
|
Assert.ok(wasCalled.updateUserAccountData);
|
|
Assert.ok(!wasCalled.updateDeviceRegistration);
|
|
}
|
|
});
|
|
|
|
function makeObserver(aObserveTopic, aObserveFunc) {
|
|
let callback = function(aSubject, aTopic, aData) {
|
|
log.debug("observed " + aTopic + " " + aData);
|
|
if (aTopic == aObserveTopic) {
|
|
removeMe();
|
|
aObserveFunc(aSubject, aTopic, aData);
|
|
}
|
|
};
|
|
|
|
function removeMe() {
|
|
log.debug("removing observer for " + aObserveTopic);
|
|
Services.obs.removeObserver(callback, aObserveTopic);
|
|
}
|
|
|
|
Services.obs.addObserver(callback, aObserveTopic);
|
|
return removeMe;
|
|
}
|
|
|
|
function validationHelper(params, expected) {
|
|
try {
|
|
new FxAccountsWebChannel(params);
|
|
} catch (e) {
|
|
if (typeof expected === "string") {
|
|
return Assert.equal(e.toString(), expected);
|
|
}
|
|
return Assert.ok(e.toString().match(expected));
|
|
}
|
|
throw new Error("Validation helper error");
|
|
}
|