gecko-dev/services/fxaccounts/FxAccountsConfig.jsm
Thom Chiovoloni a0412a141a Bug 1313731 - Append /v1 to fxaccount's autoconfig's auth_server_base_url if not present r=rfkelly
Currently the fxaccounts content server passes this through directly from its
configuration files, and accepts this as either containing the trailing /v1 or
not. On stage, it contains it, but on dev it does not.

In the near future, it should be possible to append the trailing /v1
unconditionally, as the FxA content server is being changed to never send it
down (which will be consistent with the other prefs), however it's done
conditionally as to not break autoconfig against stage in the mean time.

MozReview-Commit-ID: AStTm2hHVHQ

--HG--
extra : rebase_source : bf98cef357d5834e08a01b3c233a8ccb37243e64
2016-11-02 12:15:26 -04:00

180 lines
7.4 KiB
JavaScript

/* 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 = ["FxAccountsConfig"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://services-common/rest.js");
Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
"resource://gre/modules/FxAccounts.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "EnsureFxAccountsWebChannel",
"resource://gre/modules/FxAccountsWebChannel.jsm");
const CONFIG_PREFS = [
"identity.fxaccounts.auth.uri",
"identity.fxaccounts.remote.oauth.uri",
"identity.fxaccounts.remote.profile.uri",
"identity.sync.tokenserver.uri",
"identity.fxaccounts.remote.webchannel.uri",
"identity.fxaccounts.settings.uri",
"identity.fxaccounts.remote.signup.uri",
"identity.fxaccounts.remote.signin.uri",
"identity.fxaccounts.remote.force_auth.uri",
];
this.FxAccountsConfig = {
// Returns a promise that resolves with the URI of the remote UI flows.
promiseAccountsSignUpURI: Task.async(function*() {
yield this.ensureConfigured();
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.signup.uri");
if (fxAccounts.requiresHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}
return url;
}),
// Returns a promise that resolves with the URI of the remote UI flows.
promiseAccountsSignInURI: Task.async(function*() {
yield this.ensureConfigured();
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.signin.uri");
if (fxAccounts.requiresHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}
return url;
}),
resetConfigURLs() {
let autoconfigURL = this.getAutoConfigURL();
if (!autoconfigURL) {
return;
}
// They have the autoconfig uri pref set, so we clear all the prefs that we
// will have initialized, which will leave them pointing at production.
for (let pref of CONFIG_PREFS) {
Services.prefs.clearUserPref(pref);
}
// Reset the webchannel.
EnsureFxAccountsWebChannel();
if (!Services.prefs.prefHasUserValue("webchannel.allowObject.urlWhitelist")) {
return;
}
let whitelistValue = Services.prefs.getCharPref("webchannel.allowObject.urlWhitelist");
if (whitelistValue.startsWith(autoconfigURL + " ")) {
whitelistValue = whitelistValue.slice(autoconfigURL.length + 1);
// Check and see if the value will be the default, and just clear the pref if it would
// to avoid it showing up as changed in about:config.
let defaultWhitelist;
try {
defaultWhitelist = Services.prefs.getDefaultBranch("webchannel.allowObject.").getCharPref("urlWhitelist");
} catch (e) {
// No default value ...
}
if (defaultWhitelist === whitelistValue) {
Services.prefs.clearUserPref("webchannel.allowObject.urlWhitelist");
} else {
Services.prefs.setCharPref("webchannel.allowObject.urlWhitelist", whitelistValue);
}
}
},
getAutoConfigURL() {
let pref;
try {
pref = Services.prefs.getCharPref("identity.fxaccounts.autoconfig.uri");
} catch (e) { /* no pref */ }
if (!pref) {
// no pref / empty pref means we don't bother here.
return "";
}
let rootURL = Services.urlFormatter.formatURL(pref);
if (rootURL.endsWith("/")) {
rootURL.slice(0, -1);
}
return rootURL;
},
ensureConfigured: Task.async(function*() {
let isSignedIn = !!(yield fxAccounts.getSignedInUser());
if (!isSignedIn) {
yield this.fetchConfigURLs();
}
}),
// Read expected client configuration from the fxa auth server
// (from `identity.fxaccounts.autoconfig.uri`/.well-known/fxa-client-configuration)
// and replace all the relevant our prefs with the information found there.
// This is only done before sign-in and sign-up, and even then only if the
// `identity.fxaccounts.autoconfig.uri` preference is set.
fetchConfigURLs: Task.async(function*() {
let rootURL = this.getAutoConfigURL();
if (!rootURL) {
return;
}
let configURL = rootURL + "/.well-known/fxa-client-configuration";
let jsonStr = yield new Promise((resolve, reject) => {
let request = new RESTRequest(configURL);
request.setHeader("Accept", "application/json");
request.get(error => {
if (error) {
log.error(`Failed to get configuration object from "${configURL}"`, error);
return reject(error);
}
if (!request.response.success) {
log.error(`Received HTTP response code ${request.response.status} from configuration object request`);
if (request.response && request.response.body) {
log.debug("Got error response", request.response.body);
}
return reject(request.response.status);
}
resolve(request.response.body);
});
});
log.debug("Got successful configuration response", jsonStr);
try {
// Update the prefs directly specified by the config.
let config = JSON.parse(jsonStr)
let authServerBase = config.auth_server_base_url;
if (!authServerBase.endsWith("/v1")) {
authServerBase += "/v1";
}
Services.prefs.setCharPref("identity.fxaccounts.auth.uri", authServerBase);
Services.prefs.setCharPref("identity.fxaccounts.remote.oauth.uri", config.oauth_server_base_url + "/v1");
Services.prefs.setCharPref("identity.fxaccounts.remote.profile.uri", config.profile_server_base_url + "/v1");
Services.prefs.setCharPref("identity.sync.tokenserver.uri", config.sync_tokenserver_base_url + "/1.0/sync/1.5");
// Update the prefs that are based off of the autoconfig url
let contextParam = encodeURIComponent(
Services.prefs.getCharPref("identity.fxaccounts.contextParam"));
Services.prefs.setCharPref("identity.fxaccounts.remote.webchannel.uri", rootURL);
Services.prefs.setCharPref("identity.fxaccounts.settings.uri", rootURL + "/settings?service=sync&context=" + contextParam);
Services.prefs.setCharPref("identity.fxaccounts.remote.signup.uri", rootURL + "/signup?service=sync&context=" + contextParam);
Services.prefs.setCharPref("identity.fxaccounts.remote.signin.uri", rootURL + "/signin?service=sync&context=" + contextParam);
Services.prefs.setCharPref("identity.fxaccounts.remote.force_auth.uri", rootURL + "/force_auth?service=sync&context=" + contextParam);
let whitelistValue = Services.prefs.getCharPref("webchannel.allowObject.urlWhitelist");
if (!whitelistValue.includes(rootURL)) {
whitelistValue = `${rootURL} ${whitelistValue}`;
Services.prefs.setCharPref("webchannel.allowObject.urlWhitelist", whitelistValue);
}
// Ensure the webchannel is pointed at the correct uri
EnsureFxAccountsWebChannel();
} catch (e) {
log.error("Failed to initialize configuration preferences from autoconfig object", e);
throw e;
}
}),
};