services/fxaccounts/FxAccountsConfig.jsm
author Nick Fitzgerald <fitzgen@gmail.com>
Mon, 27 Nov 2017 15:58:00 -0500
changeset 393916 bd70c8874a80aa2968f9c2e6275b2837f5bc6aae
parent 393784 db88252d490fec2c67c0051172419b46e03cf9ee
child 394362 932a77d8fbaec3422da1104c060a40b490917a79
permissions -rw-r--r--
Bug 1421056 - Changes to the js Rust crate needed for Starling. r=till Changes include: whitelisting more things in `bindgen`, exposing the builtin micro-task queue, and more conversion implementations.

/* 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");

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.settings.devices.uri",
  "identity.fxaccounts.remote.signup.uri",
  "identity.fxaccounts.remote.signin.uri",
  "identity.fxaccounts.remote.email.uri",
  "identity.fxaccounts.remote.force_auth.uri",
];

this.FxAccountsConfig = {

  async _getPrefURL(prefName) {
    await this.ensureConfigured();
    let url = Services.urlFormatter.formatURLPref(prefName);
    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.
  promiseAccountsSignUpURI() {
    return this._getPrefURL("identity.fxaccounts.remote.signup.uri");
  },

  // Returns a promise that resolves with the URI of the remote UI flows.
  promiseAccountsSignInURI() {
    return this._getPrefURL("identity.fxaccounts.remote.signin.uri");
  },

  promiseAccountsEmailURI() {
    return this._getPrefURL("identity.fxaccounts.remote.email.uri");
  },

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

  getAutoConfigURL() {
    let pref = Services.prefs.getCharPref("identity.fxaccounts.autoconfig.uri", "");
    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;
  },

  async ensureConfigured() {
    let isSignedIn = !!(await fxAccounts.getSignedInUser());
    if (!isSignedIn) {
      await 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.
  async fetchConfigURLs() {
    let rootURL = this.getAutoConfigURL();
    if (!rootURL) {
      return;
    }
    let configURL = rootURL + "/.well-known/fxa-client-configuration";
    let jsonStr = await 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);
          reject(error);
          return;
        }
        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);
          }
          reject(request.response.status);
          return;
        }
        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.settings.devices.uri", rootURL + "/settings/clients?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.email.uri", rootURL + "/?service=sync&context=" + contextParam + "&action=email");
      Services.prefs.setCharPref("identity.fxaccounts.remote.force_auth.uri", rootURL + "/force_auth?service=sync&context=" + contextParam);

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

};