Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-04-19 09:42:27 +08:00
commit 838b5e4e48
569 changed files with 1183 additions and 62621 deletions

View file

@ -202,7 +202,7 @@ this.LoginHelper = {
return true;
}
} catch (ex) {
// newURI will throw for some values e.g. chrome://FirefoxAccounts
// newURI will throw for some values
return false;
}
}
@ -406,7 +406,7 @@ this.LoginHelper = {
try {
preferredOriginScheme = Services.io.newURI(preferredOrigin, null, null).scheme;
} catch (ex) {
// Handle strings that aren't valid URIs e.g. chrome://FirefoxAccounts
// Handle strings that aren't valid URIs
}
}
@ -457,7 +457,7 @@ this.LoginHelper = {
return loginURI.scheme == preferredOriginScheme;
} catch (ex) {
// Some URLs aren't valid nsIURI (e.g. chrome://FirefoxAccounts)
// Some URLs aren't valid nsIURI
log.debug("dedupeLogins/shouldReplaceExisting: Error comparing schemes:",
existingLogin.hostname, login.hostname,
"preferredOrigin:", preferredOrigin, ex);

View file

@ -471,7 +471,7 @@ LoginManagerStorage_mozStorage.prototype = {
params["http" + field] = "http://" + valueURI.hostPort;
}
} catch (ex) {
// newURI will throw for some values (e.g. chrome://FirefoxAccounts)
// newURI will throw for some values
// but those URLs wouldn't support upgrades anyways.
}
break;

View file

@ -1,313 +0,0 @@
/* 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";
this.EXPORTED_SYMBOLS = ["FirefoxAccounts"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/identity/LogUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
"resource://gre/modules/identity/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "makeMessageObject",
"resource://gre/modules/identity/IdentityUtils.jsm");
// loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO",
// "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by
// default.
const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel";
try {
this.LOG_LEVEL =
Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING
&& Services.prefs.getCharPref(PREF_LOG_LEVEL);
} catch (e) {
this.LOG_LEVEL = Log.Level.Error;
}
var log = Log.repository.getLogger("Identity.FxAccounts");
log.level = LOG_LEVEL;
log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
log.warn("The FxAccountsManager has been removed.");
var FxAccountsManager = null;
var ONVERIFIED_NOTIFICATION = null;
var ONLOGIN_NOTIFICATION = null;
var ONLOGOUT_NOTIFICATION = null;
function FxAccountsService() {
Services.obs.addObserver(this, "quit-application-granted", false);
if (ONVERIFIED_NOTIFICATION) {
Services.obs.addObserver(this, ONVERIFIED_NOTIFICATION, false);
Services.obs.addObserver(this, ONLOGIN_NOTIFICATION, false);
Services.obs.addObserver(this, ONLOGOUT_NOTIFICATION, false);
}
// Maintain interface parity with Identity.jsm and MinimalIdentity.jsm
this.RP = this;
this._rpFlows = new Map();
// Enable us to mock FxAccountsManager service in testing
this.fxAccountsManager = FxAccountsManager;
}
FxAccountsService.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
observe: function observe(aSubject, aTopic, aData) {
switch (aTopic) {
case null:
// Guard against matching null ON*_NOTIFICATION
break;
case ONVERIFIED_NOTIFICATION:
log.debug("Received " + ONVERIFIED_NOTIFICATION + "; firing request()s");
for (let [rpId,] of this._rpFlows) {
this.request(rpId);
}
break;
case ONLOGIN_NOTIFICATION:
log.debug("Received " + ONLOGIN_NOTIFICATION + "; doLogin()s fired");
for (let [rpId,] of this._rpFlows) {
this.request(rpId);
}
break;
case ONLOGOUT_NOTIFICATION:
log.debug("Received " + ONLOGOUT_NOTIFICATION + "; doLogout()s fired");
for (let [rpId,] of this._rpFlows) {
this.doLogout(rpId);
}
break;
case "quit-application-granted":
Services.obs.removeObserver(this, "quit-application-granted");
if (ONVERIFIED_NOTIFICATION) {
Services.obs.removeObserver(this, ONVERIFIED_NOTIFICATION);
Services.obs.removeObserver(this, ONLOGIN_NOTIFICATION);
Services.obs.removeObserver(this, ONLOGOUT_NOTIFICATION);
}
break;
}
},
cleanupRPRequest: function(aRp) {
aRp.pendingRequest = false;
this._rpFlows.set(aRp.id, aRp);
},
/**
* Register a listener for a given windowID as a result of a call to
* navigator.id.watch().
*
* @param aRPCaller
* (Object) an object that represents the caller document, and
* is expected to have properties:
* - id (unique, e.g. uuid)
* - origin (string)
*
* and a bunch of callbacks
* - doReady()
* - doLogin()
* - doLogout()
* - doError()
* - doCancel()
*
*/
watch: function watch(aRpCaller) {
this._rpFlows.set(aRpCaller.id, aRpCaller);
log.debug("watch: " + aRpCaller.id);
log.debug("Current rp flows: " + this._rpFlows.size);
// Log the user in, if possible, and then call ready().
let runnable = {
run: () => {
this.fxAccountsManager.getAssertion(aRpCaller.audience,
aRpCaller.principal,
{ silent:true }).then(
data => {
if (data) {
this.doLogin(aRpCaller.id, data);
} else {
this.doLogout(aRpCaller.id);
}
this.doReady(aRpCaller.id);
},
error => {
log.error("get silent assertion failed: " + JSON.stringify(error));
this.doError(aRpCaller.id, error);
}
);
}
};
Services.tm.currentThread.dispatch(runnable,
Ci.nsIThread.DISPATCH_NORMAL);
},
/**
* Delete the flow when the screen is unloaded
*/
unwatch: function(aRpCallerId, aTargetMM) {
log.debug("unwatching: " + aRpCallerId);
this._rpFlows.delete(aRpCallerId);
},
/**
* Initiate a login with user interaction as a result of a call to
* navigator.id.request().
*
* @param aRPId
* (integer) the id of the doc object obtained in .watch()
*
* @param aOptions
* (Object) options including privacyPolicy, termsOfService
*/
request: function request(aRPId, aOptions) {
aOptions = aOptions || {};
let rp = this._rpFlows.get(aRPId);
if (!rp) {
log.error("request() called before watch()");
return;
}
// We check if we already have a pending request for this RP and in that
// case we just bail out. We don't want duplicated onlogin or oncancel
// events.
if (rp.pendingRequest) {
log.debug("request() already called");
return;
}
// Otherwise, we set the RP flow with the pending request flag.
rp.pendingRequest = true;
this._rpFlows.set(rp.id, rp);
let options = makeMessageObject(rp);
objectCopy(aOptions, options);
log.debug("get assertion for " + rp.audience);
this.fxAccountsManager.getAssertion(rp.audience, rp.principal, options)
.then(
data => {
log.debug("got assertion for " + rp.audience + ": " + data);
this.doLogin(aRPId, data);
},
error => {
log.debug("get assertion failed: " + JSON.stringify(error));
// Cancellation is passed through an error channel; here we reroute.
if ((error.error && (error.error.details == "DIALOG_CLOSED_BY_USER")) ||
(error.details == "DIALOG_CLOSED_BY_USER")) {
return this.doCancel(aRPId);
}
this.doError(aRPId, error);
}
)
.then(
() => {
this.cleanupRPRequest(rp);
}
)
.catch(
() => {
this.cleanupRPRequest(rp);
}
);
},
/**
* Invoked when a user wishes to logout of a site (for instance, when clicking
* on an in-content logout button).
*
* @param aRpCallerId
* (integer) the id of the doc object obtained in .watch()
*
*/
logout: function logout(aRpCallerId) {
// XXX Bug 945363 - Resolve the SSO story for FXA and implement
// logout accordingly.
//
// For now, it makes no sense to logout from a specific RP in
// Firefox Accounts, so just directly call the logout callback.
if (!this._rpFlows.has(aRpCallerId)) {
log.error("logout() called before watch()");
return;
}
// Call logout() on the next tick
let runnable = {
run: () => {
this.fxAccountsManager.signOut().then(() => {
this.doLogout(aRpCallerId);
});
}
};
Services.tm.currentThread.dispatch(runnable,
Ci.nsIThread.DISPATCH_NORMAL);
},
childProcessShutdown: function childProcessShutdown(messageManager) {
for (let [key,] of this._rpFlows) {
if (this._rpFlows.get(key)._mm === messageManager) {
this._rpFlows.delete(key);
}
}
},
doLogin: function doLogin(aRpCallerId, aAssertion) {
let rp = this._rpFlows.get(aRpCallerId);
if (!rp) {
log.warn("doLogin found no rp to go with callerId " + aRpCallerId);
return;
}
rp.doLogin(aAssertion);
},
doLogout: function doLogout(aRpCallerId) {
let rp = this._rpFlows.get(aRpCallerId);
if (!rp) {
log.warn("doLogout found no rp to go with callerId " + aRpCallerId);
return;
}
rp.doLogout();
},
doReady: function doReady(aRpCallerId) {
let rp = this._rpFlows.get(aRpCallerId);
if (!rp) {
log.warn("doReady found no rp to go with callerId " + aRpCallerId);
return;
}
rp.doReady();
},
doCancel: function doCancel(aRpCallerId) {
let rp = this._rpFlows.get(aRpCallerId);
if (!rp) {
log.warn("doCancel found no rp to go with callerId " + aRpCallerId);
return;
}
rp.doCancel();
},
doError: function doError(aRpCallerId, aError) {
let rp = this._rpFlows.get(aRpCallerId);
if (!rp) {
log.warn("doError found no rp to go with callerId " + aRpCallerId);
return;
}
rp.doError(aError);
}
};
this.FirefoxAccounts = new FxAccountsService();

View file

@ -29,8 +29,4 @@ EXTRA_JS_MODULES.identity += [
'Sandbox.jsm',
]
EXTRA_PP_JS_MODULES.identity += [
'FirefoxAccounts.jsm',
]
FINAL_LIBRARY = 'xul'

View file

@ -239,18 +239,10 @@ try {
} catch (noPref) {}
Services.prefs.setBoolPref("toolkit.identity.debug", true);
// Switch on firefox accounts
var initialPrefFXAValue = false;
try {
initialPrefFXAValue = Services.prefs.getBoolPref("identity.fxaccounts.enabled");
} catch (noPref) {}
Services.prefs.setBoolPref("identity.fxaccounts.enabled", true);
// after execution, restore prefs
do_register_cleanup(function() {
log("restoring prefs to their initial values");
Services.prefs.setBoolPref("toolkit.identity.debug", initialPrefDebugValue);
Services.prefs.setBoolPref("identity.fxaccounts.enabled", initialPrefFXAValue);
});

View file

@ -1,270 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/DOMIdentity.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAccounts",
"resource://gre/modules/identity/FirefoxAccounts.jsm");
// Make the profile dir available; this is necessary so that
// services/fxaccounts/FxAccounts.jsm can read and write its signed-in user
// data.
do_get_profile();
function MockFXAManager() {
this.signedInUser = true;
}
MockFXAManager.prototype = {
getAssertion: function(audience) {
let result = this.signedInUser ? TEST_ASSERTION : null;
return Promise.resolve(result);
},
signOut: function() {
this.signedInUser = false;
return Promise.resolve(null);
},
signIn: function(user) {
this.signedInUser = user;
return Promise.resolve(user);
},
}
var originalManager = FirefoxAccounts.fxAccountsManager;
FirefoxAccounts.fxAccountsManager = new MockFXAManager();
do_register_cleanup(() => {
log("restoring fxaccountsmanager");
FirefoxAccounts.fxAccountsManager = originalManager;
});
function withNobodySignedIn() {
return FirefoxAccounts.fxAccountsManager.signOut();
}
function withSomebodySignedIn() {
return FirefoxAccounts.fxAccountsManager.signIn('Pertelote');
}
function test_overall() {
do_check_neq(FirefoxAccounts, null);
run_next_test();
}
function test_mock() {
do_test_pending();
withSomebodySignedIn().then(() => {
FirefoxAccounts.fxAccountsManager.getAssertion().then(assertion => {
do_check_eq(assertion, TEST_ASSERTION);
do_test_finished();
run_next_test();
});
});
}
function test_watch_signed_in() {
do_test_pending();
let received = [];
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, data) {
received.push([method, data]);
if (method == "ready") {
// confirm that we were signed in and then ready was called
do_check_eq(received.length, 2);
do_check_eq(received[0][0], "login");
do_check_eq(received[0][1], TEST_ASSERTION);
do_check_eq(received[1][0], "ready");
do_test_finished();
run_next_test();
}
});
withSomebodySignedIn().then(() => {
FirefoxAccounts.RP.watch(mockedRP);
});
}
function test_watch_signed_out() {
do_test_pending();
let received = [];
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method) {
received.push(method);
if (method == "ready") {
// confirm that we were signed out and then ready was called
do_check_eq(received.length, 2);
do_check_eq(received[0], "logout");
do_check_eq(received[1], "ready");
do_test_finished();
run_next_test();
}
});
withNobodySignedIn().then(() => {
FirefoxAccounts.RP.watch(mockedRP);
});
}
function test_request() {
do_test_pending();
let received = [];
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, data) {
received.push([method, data]);
// On watch(), we are signed out. Then we call request().
if (received.length === 2) {
do_check_eq(received[0][0], "logout");
do_check_eq(received[1][0], "ready");
// Pretend request() showed ux and the user signed in
withSomebodySignedIn().then(() => {
FirefoxAccounts.RP.request(mockedRP.id);
});
}
if (received.length === 3) {
do_check_eq(received[2][0], "login");
do_check_eq(received[2][1], TEST_ASSERTION);
do_test_finished();
run_next_test();
}
});
// First, call watch() with nobody signed in
withNobodySignedIn().then(() => {
FirefoxAccounts.RP.watch(mockedRP);
});
}
function test_logout() {
do_test_pending();
let received = [];
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method) {
received.push(method);
// At first, watch() signs us in automatically. Then we sign out.
if (received.length === 2) {
do_check_eq(received[0], "login");
do_check_eq(received[1], "ready");
FirefoxAccounts.RP.logout(mockedRP.id);
}
if (received.length === 3) {
do_check_eq(received[2], "logout");
do_test_finished();
run_next_test();
}
});
// First, call watch()
withSomebodySignedIn().then(() => {
FirefoxAccounts.RP.watch(mockedRP);
});
}
function test_error() {
do_test_pending();
let received = [];
// Mock the fxAccountsManager so that getAssertion rejects its promise and
// triggers our onerror handler. (This is the method that's used internally
// by FirefoxAccounts.RP.request().)
let originalGetAssertion = FirefoxAccounts.fxAccountsManager.getAssertion;
FirefoxAccounts.fxAccountsManager.getAssertion = function(audience) {
return Promise.reject(new Error("barf!"));
};
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, message) {
// We will immediately receive an error, due to watch()'s attempt
// to getAssertion().
do_check_eq(method, "error");
do_check_true(/barf/.test(message));
// Put things back the way they were
FirefoxAccounts.fxAccountsManager.getAssertion = originalGetAssertion;
do_test_finished();
run_next_test();
});
// First, call watch()
withSomebodySignedIn().then(() => {
FirefoxAccounts.RP.watch(mockedRP);
});
}
function test_child_process_shutdown() {
do_test_pending();
let rpCount = FirefoxAccounts.RP._rpFlows.size;
makeObserver("identity-child-process-shutdown", (aTopic, aSubject, aData) => {
// Last of all, the shutdown observer message will be fired.
// This takes place after the RP has a chance to delete flows
// and clean up.
do_check_eq(FirefoxAccounts.RP._rpFlows.size, rpCount);
do_test_finished();
run_next_test();
});
let mockedRP = mock_fxa_rp(null, TEST_URL, (method) => {
// We should enter this function for 'ready' and 'child-process-shutdown'.
// After we have a chance to do our thing, the shutdown observer message
// will fire and be caught by the function above.
do_check_eq(FirefoxAccounts.RP._rpFlows.size, rpCount + 1);
switch (method) {
case "ready":
DOMIdentity._childProcessShutdown("my message manager");
break;
case "child-process-shutdown":
// We have to call this explicitly because there's no real
// dom window here.
FirefoxAccounts.RP.childProcessShutdown(mockedRP._mm);
break;
default:
break;
}
});
mockedRP._mm = "my message manager";
withSomebodySignedIn().then(() => {
FirefoxAccounts.RP.watch(mockedRP);
});
// fake a dom window context
DOMIdentity.newContext(mockedRP, mockedRP._mm);
}
var TESTS = [
test_overall,
test_mock,
test_watch_signed_in,
test_watch_signed_out,
test_request,
test_logout,
test_error,
test_child_process_shutdown,
];
TESTS.forEach(add_test);
function run_test() {
run_next_test();
}

View file

@ -9,7 +9,6 @@ support-files =
# Test load modules first so syntax failures are caught early.
[test_load_modules.js]
[test_minimalidentity.js]
[test_firefox_accounts.js]
[test_identity_utils.js]
[test_log_utils.js]

View file

@ -102,13 +102,6 @@ MOZ_SAFE_BROWSING:
false,
#endif
MOZ_SERVICES_CLOUDSYNC:
#ifdef MOZ_SERVICES_CLOUDSYNC
true,
#else
false,
#endif
MOZ_UPDATER:
#ifdef MOZ_UPDATER
true,

View file

@ -153,8 +153,7 @@ for var in ('ANDROID_PACKAGE_NAME',
for var in ('MOZ_TOOLKIT_SEARCH',
'MOZ_SYSTEM_NSS',
'MOZ_UPDATER',
'MOZ_SWITCHBOARD',
'MOZ_SERVICES_CLOUDSYNC'):
'MOZ_SWITCHBOARD'):
if CONFIG[var]:
DEFINES[var] = True

View file

@ -2463,7 +2463,7 @@ RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
if (!file)
return false;
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
#define PLATFORM_FASL_SUFFIX ".mfasl"
#elif defined(XP_WIN)
#define PLATFORM_FASL_SUFFIX ".mfl"