Bug 1296767 part 2 - Remove Sync UserApi. r?markh draft
authorEdouard Oger <eoger@fastmail.com>
Fri, 13 Jan 2017 15:54:46 -0500
changeset 467362 be5e97383698de0eb0d5fbba66510681e13a344e
parent 467361 5c5b1abda02c2f3468dc03222ac2621b9ac54b75
child 467363 16b22133316d18203f3e2155aeacaba9f9dae808
push id43155
push userbmo:eoger@fastmail.com
push dateFri, 27 Jan 2017 18:31:15 +0000
reviewersmarkh
bugs1296767
milestone54.0a1
Bug 1296767 part 2 - Remove Sync UserApi. r?markh MozReview-Commit-ID: CdgLxCN52Os
services/sync/modules/constants.js
services/sync/modules/service.js
services/sync/modules/userapi.js
services/sync/moz.build
services/sync/services-sync.js
services/sync/tests/unit/test_load_modules.js
services/sync/tests/unit/test_service_attributes.js
services/sync/tests/unit/test_service_createAccount.js
services/sync/tests/unit/xpcshell.ini
tools/lint/eslint/modules.json
--- a/services/sync/modules/constants.js
+++ b/services/sync/modules/constants.js
@@ -6,17 +6,16 @@
 // Process each item in the "constants hash" to add to "global" and give a name
 this.EXPORTED_SYMBOLS = [];
 for (let [key, val] of Object.entries({
 
 WEAVE_VERSION:                         "@weave_version@",
 
 // Sync Server API version that the client supports.
 SYNC_API_VERSION:                      "1.1",
-USER_API_VERSION:                      "1.0",
 MISC_API_VERSION:                      "1.0",
 
 // Version of the data format this client supports. The data format describes
 // how records are packaged; this is separate from the Server API version and
 // the per-engine cleartext formats.
 STORAGE_VERSION:                       5,
 PREFS_BRANCH:                          "services.sync.",
 
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -28,17 +28,16 @@ Cu.import("resource://services-sync/iden
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/stages/enginesync.js");
 Cu.import("resource://services-sync/stages/declined.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/telemetry.js");
-Cu.import("resource://services-sync/userapi.js");
 Cu.import("resource://services-sync/util.js");
 
 const ENGINE_MODULES = {
   Addons: "addons.js",
   Bookmarks: "bookmarks.js",
   Form: "forms.js",
   History: "history.js",
   Password: "passwords.js",
@@ -101,33 +100,16 @@ Sync11Service.prototype = {
   get miscAPI() {
     // Append to the serverURL if it's a relative fragment
     let misc = Svc.Prefs.get("miscURL");
     if (misc.indexOf(":") == -1)
       misc = this.serverURL + misc;
     return misc + MISC_API_VERSION + "/";
   },
 
-  /**
-   * The URI of the User API service.
-   *
-   * This is the base URI of the service as applicable to all users up to
-   * and including the server version path component, complete with trailing
-   * forward slash.
-   */
-  get userAPIURI() {
-    // Append to the serverURL if it's a relative fragment.
-    let url = Svc.Prefs.get("userURL");
-    if (!url.includes(":")) {
-      url = this.serverURL + url;
-    }
-
-    return url + USER_API_VERSION + "/";
-  },
-
   get pwResetURL() {
     return this.serverURL + "weave-password-reset";
   },
 
   get syncID() {
     // Generate a random syncID id we don't have one
     let syncID = Svc.Prefs.get("client.syncID", "");
     return syncID == "" ? this.syncID = Utils.makeGUID() : syncID;
@@ -820,35 +802,16 @@ Sync11Service.prototype = {
     }
     let keysChanged = this.handleFetchedKeys(this.identity.syncKeyBundle,
                                              cryptoKeys, true);
     if (keysChanged) {
       this._log.info("Downloaded keys differed, as expected.");
     }
   },
 
-  changePassword: function changePassword(newPassword) {
-    let client = new UserAPI10Client(this.userAPIURI);
-    let cb = Async.makeSpinningCallback();
-    client.changePassword(this.identity.username,
-                          this.identity.basicPassword, newPassword, cb);
-
-    try {
-      cb.wait();
-    } catch (ex) {
-      this._log.debug("Password change failed", ex);
-      return false;
-    }
-
-    // Save the new password for requests and login manager.
-    this.identity.basicPassword = newPassword;
-    this.persistLogin();
-    return true;
-  },
-
   changePassphrase: function changePassphrase(newphrase) {
     return this._catch(function doChangePasphrase() {
       /* Wipe. */
       this.wipeServer();
 
       this.logout();
 
       /* Set this so UI is updated on next run. */
@@ -1012,55 +975,16 @@ Sync11Service.prototype = {
     // reuse any old credentials next time we sync.
     this._log.info("Logging out");
     this.identity.logout();
     this._loggedIn = false;
 
     Svc.Obs.notify("weave:service:logout:finish");
   },
 
-  checkAccount: function checkAccount(account) {
-    let client = new UserAPI10Client(this.userAPIURI);
-    let cb = Async.makeSpinningCallback();
-
-    let username = this.identity.usernameFromAccount(account);
-    client.usernameExists(username, cb);
-
-    try {
-      let exists = cb.wait();
-      return exists ? "notAvailable" : "available";
-    } catch (ex) {
-      // TODO fix API convention.
-      return this.errorHandler.errorStr(ex);
-    }
-  },
-
-  createAccount: function createAccount(email, password,
-                                        captchaChallenge, captchaResponse) {
-    let client = new UserAPI10Client(this.userAPIURI);
-
-    // Hint to server to allow scripted user creation or otherwise
-    // ignore captcha.
-    if (Svc.Prefs.isSet("admin-secret")) {
-      client.adminSecret = Svc.Prefs.get("admin-secret", "");
-    }
-
-    let cb = Async.makeSpinningCallback();
-
-    client.createAccount(email, password, captchaChallenge, captchaResponse,
-                         cb);
-
-    try {
-      cb.wait();
-      return null;
-    } catch (ex) {
-      return this.errorHandler.errorStr(ex.body);
-    }
-  },
-
   // Note: returns false if we failed for a reason other than the server not yet
   // supporting the api.
   _fetchServerConfiguration() {
     // This is similar to _fetchInfo, but with different error handling.
 
     let infoURL = this.userBaseURL + "info/configuration";
     this._log.debug("Fetching server configuration", infoURL);
     let configResponse;
deleted file mode 100644
--- a/services/sync/modules/userapi.js
+++ /dev/null
@@ -1,219 +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 = [
-  "UserAPI10Client",
-];
-
-var {utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-common/rest.js");
-Cu.import("resource://services-common/utils.js");
-Cu.import("resource://services-sync/identity.js");
-Cu.import("resource://services-sync/util.js");
-
-/**
- * A generic client for the user API 1.0 service.
- *
- * http://docs.services.mozilla.com/reg/apis.html
- *
- * Instances are constructed with the base URI of the service.
- */
-this.UserAPI10Client = function UserAPI10Client(baseURI) {
-  this._log = Log.repository.getLogger("Sync.UserAPI");
-  this._log.level = Log.Level[Svc.Prefs.get("log.logger.userapi")];
-
-  this.baseURI = baseURI;
-}
-UserAPI10Client.prototype = {
-  USER_CREATE_ERROR_CODES: {
-    2: "Incorrect or missing captcha.",
-    4: "User exists.",
-    6: "JSON parse failure.",
-    7: "Missing password field.",
-    9: "Requested password not strong enough.",
-    12: "No email address on file.",
-  },
-
-  /**
-   * Determine whether a specified username exists.
-   *
-   * Callback receives the following arguments:
-   *
-   *   (Error) Describes error that occurred or null if request was
-   *           successful.
-   *   (boolean) True if user exists. False if not. null if there was an error.
-   */
-  usernameExists: function usernameExists(username, cb) {
-    if (typeof(cb) != "function") {
-      throw new Error("cb must be a function.");
-    }
-
-    let url = this.baseURI + username;
-    let request = new RESTRequest(url);
-    request.get(this._onUsername.bind(this, cb, request));
-  },
-
-  /**
-   * Obtain the Weave (Sync) node for a specified user.
-   *
-   * The callback receives the following arguments:
-   *
-   *   (Error)  Describes error that occurred or null if request was successful.
-   *   (string) Username request is for.
-   *   (string) URL of user's node. If null and there is no error, no node could
-   *            be assigned at the time of the request.
-   */
-  getWeaveNode: function getWeaveNode(username, password, cb) {
-    if (typeof(cb) != "function") {
-      throw new Error("cb must be a function.");
-    }
-
-    let request = this._getRequest(username, "/node/weave", password);
-    request.get(this._onWeaveNode.bind(this, cb, request));
-  },
-
-  /**
-   * Change a password for the specified user.
-   *
-   * @param username
-   *        (string) The username whose password to change.
-   * @param oldPassword
-   *        (string) The old, current password.
-   * @param newPassword
-   *        (string) The new password to switch to.
-   */
-  changePassword: function changePassword(username, oldPassword, newPassword, cb) {
-    let request = this._getRequest(username, "/password", oldPassword);
-    request.onComplete = this._onChangePassword.bind(this, cb, request);
-    request.post(CommonUtils.encodeUTF8(newPassword));
-  },
-
-  createAccount: function createAccount(email, password, captchaChallenge,
-                                        captchaResponse, cb) {
-    let username = IdentityManager.prototype.usernameFromAccount(email);
-    let body = JSON.stringify({
-      "email":             email,
-      "password":          Utils.encodeUTF8(password),
-      "captcha-challenge": captchaChallenge,
-      "captcha-response":  captchaResponse
-    });
-
-    let url = this.baseURI + username;
-    let request = new RESTRequest(url);
-
-    if (this.adminSecret) {
-      request.setHeader("X-Weave-Secret", this.adminSecret);
-    }
-
-    request.onComplete = this._onCreateAccount.bind(this, cb, request);
-    request.put(body);
-  },
-
-  _getRequest: function _getRequest(username, path, password = null) {
-    let url = this.baseURI + username + path;
-    let request = new RESTRequest(url);
-
-    if (password) {
-      let up = username + ":" + password;
-      request.setHeader("authorization", "Basic " + btoa(up));
-    }
-
-    return request;
-  },
-
-  _onUsername: function _onUsername(cb, request, error) {
-    if (error) {
-      cb(error, null);
-      return;
-    }
-
-    let body = request.response.body;
-    if (body == "0") {
-      cb(null, false);
-    } else if (body == "1") {
-      cb(null, true);
-    } else {
-      cb(new Error("Unknown response from server: " + body), null);
-    }
-  },
-
-  _onWeaveNode: function _onWeaveNode(cb, request, error) {
-    if (error) {
-      cb.network = true;
-      cb(error, null);
-      return;
-    }
-
-    let response = request.response;
-
-    if (response.status == 200) {
-      let body = response.body;
-      if (body == "null") {
-        cb(null, null);
-        return;
-      }
-
-      cb(null, body);
-      return;
-    }
-
-    error = new Error("Sync node retrieval failed.");
-    switch (response.status) {
-      case 400:
-        error.denied = true;
-        break;
-      case 404:
-        error.notFound = true;
-        break;
-      default:
-        error.message = "Unexpected response code: " + response.status;
-    }
-
-    cb(error, null);
-  },
-
-  _onChangePassword: function _onChangePassword(cb, request, error) {
-    this._log.info("Password change response received: " +
-                   request.response.status);
-    if (error) {
-      cb(error);
-      return;
-    }
-
-    let response = request.response;
-    if (response.status != 200) {
-      cb(new Error("Password changed failed: " + response.body));
-      return;
-    }
-
-    cb(null);
-  },
-
-  _onCreateAccount: function _onCreateAccount(cb, request, error) {
-    let response = request.response;
-
-    this._log.info("Create account response: " + response.status + " " +
-                   response.body);
-
-    if (error) {
-      cb(new Error("HTTP transport error."), null);
-      return;
-    }
-
-    if (response.status == 200) {
-      cb(null, response.body);
-      return;
-    }
-
-    error = new Error("Could not create user.");
-    error.body = response.body;
-
-    cb(error, null);
-  },
-};
-Object.freeze(UserAPI10Client.prototype);
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -30,17 +30,16 @@ EXTRA_JS_MODULES['services-sync'] += [
     'modules/policies.js',
     'modules/record.js',
     'modules/resource.js',
     'modules/rest.js',
     'modules/service.js',
     'modules/status.js',
     'modules/SyncedTabs.jsm',
     'modules/telemetry.js',
-    'modules/userapi.js',
     'modules/util.js',
 ]
 
 EXTRA_PP_JS_MODULES['services-sync'] += [
     'modules/constants.js',
 ]
 
 # Definitions used by constants.js
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -1,14 +1,13 @@
 /* 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/. */
 
 pref("services.sync.serverURL", "https://auth.services.mozilla.com/");
-pref("services.sync.userURL", "user/");
 pref("services.sync.miscURL", "misc/");
 pref("services.sync.termsURL", "https://services.mozilla.com/tos/");
 pref("services.sync.privacyURL", "https://services.mozilla.com/privacy-policy/");
 pref("services.sync.statusURL", "https://services.mozilla.com/status/");
 pref("services.sync.syncKeyHelpURL", "https://services.mozilla.com/help/synckey");
 
 pref("services.sync.lastversion", "firstrun");
 pref("services.sync.sendVersionInfo", true);
@@ -59,17 +58,16 @@ pref("services.sync.log.logger.engine.fo
 pref("services.sync.log.logger.engine.history", "Debug");
 pref("services.sync.log.logger.engine.passwords", "Debug");
 pref("services.sync.log.logger.engine.prefs", "Debug");
 pref("services.sync.log.logger.engine.tabs", "Debug");
 pref("services.sync.log.logger.engine.addons", "Debug");
 pref("services.sync.log.logger.engine.extension-storage", "Debug");
 pref("services.sync.log.logger.engine.apps", "Debug");
 pref("services.sync.log.logger.identity", "Debug");
-pref("services.sync.log.logger.userapi", "Debug");
 pref("services.sync.log.cryptoDebug", false);
 
 pref("services.sync.fxa.termsURL", "https://accounts.firefox.com/legal/terms");
 pref("services.sync.fxa.privacyURL", "https://accounts.firefox.com/legal/privacy");
 
 pref("services.sync.telemetry.submissionInterval", 43200); // 12 hours in seconds
 pref("services.sync.telemetry.maxPayloadCount", 500);
 
--- a/services/sync/tests/unit/test_load_modules.js
+++ b/services/sync/tests/unit/test_load_modules.js
@@ -23,17 +23,16 @@ const modules = [
   "record.js",
   "resource.js",
   "rest.js",
   "service.js",
   "stages/cluster.js",
   "stages/declined.js",
   "stages/enginesync.js",
   "status.js",
-  "userapi.js",
   "util.js",
 ];
 
 const testingModules = [
   "fakeservices.js",
   "rotaryengine.js",
   "utils.js",
   "fxa_utils.js",
--- a/services/sync/tests/unit/test_service_attributes.js
+++ b/services/sync/tests/unit/test_service_attributes.js
@@ -32,28 +32,23 @@ add_task(async function test_urls() {
     do_check_eq(Service.userBaseURL, "http://weave.cluster/1.1/johndoe/");
     do_check_eq(Service.infoURL,
                 "http://weave.cluster/1.1/johndoe/info/collections");
     do_check_eq(Service.storageURL,
                 "http://weave.cluster/1.1/johndoe/storage/");
     do_check_eq(Service.metaURL,
                 "http://weave.cluster/1.1/johndoe/storage/meta/global");
 
-    _("The 'miscURL' and 'userURL' attributes can be relative to 'serverURL' or absolute.");
+    _("The 'miscURL' attribute can be relative to 'serverURL' or absolute.");
     Svc.Prefs.set("miscURL", "relative/misc/");
-    Svc.Prefs.set("userURL", "relative/user/");
     do_check_eq(Service.miscAPI,
                 "http://weave.server/relative/misc/1.0/");
-    do_check_eq(Service.userAPIURI,
-                "http://weave.server/relative/user/1.0/");
 
     Svc.Prefs.set("miscURL", "http://weave.misc.services/");
-    Svc.Prefs.set("userURL", "http://weave.user.services/");
     do_check_eq(Service.miscAPI, "http://weave.misc.services/1.0/");
-    do_check_eq(Service.userAPIURI, "http://weave.user.services/1.0/");
 
     do_check_eq(Service.pwResetURL,
                 "http://weave.server/weave-password-reset");
 
     _("Empty/false value for 'username' resets preference.");
     Service.identity.username = "";
     do_check_eq(Svc.Prefs.get("username"), undefined);
     do_check_eq(Service.identity.username, null);
deleted file mode 100644
--- a/services/sync/tests/unit/test_service_createAccount.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-function run_test() {
-  initTestLogging("Trace");
-
-  let requestBody;
-  let secretHeader;
-  function send(statusCode, status, body) {
-    return function(request, response) {
-      requestBody = readBytesFromInputStream(request.bodyInputStream);
-      if (request.hasHeader("X-Weave-Secret")) {
-        secretHeader = request.getHeader("X-Weave-Secret");
-      }
-
-      response.setStatusLine(request.httpVersion, statusCode, status);
-      response.bodyOutputStream.write(body, body.length);
-    };
-  }
-
-  do_test_pending();
-  let server = httpd_setup({
-    // john@doe.com
-    "/user/1.0/7wohs32cngzuqt466q3ge7indszva4of": send(200, "OK", "0"),
-    // jane@doe.com
-    "/user/1.0/vuuf3eqgloxpxmzph27f5a6ve7gzlrms": send(400, "Bad Request", "2"),
-    // jim@doe.com
-    "/user/1.0/vz6fhecgw5t3sgx3a4cektoiokyczkqd": send(500, "Server Error", "Server Error")
-  });
-  try {
-    Service.serverURL = server.baseURI;
-
-    _("Create an account.");
-    let res = Service.createAccount("john@doe.com", "mysecretpw",
-                                    "challenge", "response");
-    do_check_eq(res, null);
-    let payload = JSON.parse(requestBody);
-    do_check_eq(payload.password, "mysecretpw");
-    do_check_eq(payload.email, "john@doe.com");
-    do_check_eq(payload["captcha-challenge"], "challenge");
-    do_check_eq(payload["captcha-response"], "response");
-
-    _("A non-ASCII password is UTF-8 encoded.");
-    const moneyPassword = "moneyislike$£¥";
-    res = Service.createAccount("john@doe.com", moneyPassword,
-                                "challenge", "response");
-    do_check_eq(res, null);
-    payload = JSON.parse(requestBody);
-    do_check_eq(payload.password, Utils.encodeUTF8(moneyPassword));
-
-    _("Invalid captcha or other user-friendly error.");
-    res = Service.createAccount("jane@doe.com", "anothersecretpw",
-                                "challenge", "response");
-    do_check_eq(res, "invalid-captcha");
-
-    _("Generic server error.");
-    res = Service.createAccount("jim@doe.com", "preciousss",
-                                "challenge", "response");
-    do_check_eq(res, "generic-server-error");
-
-    _("Admin secret preference is passed as HTTP header token.");
-    Svc.Prefs.set("admin-secret", "my-server-secret");
-    res = Service.createAccount("john@doe.com", "mysecretpw",
-                                "challenge", "response");
-    do_check_eq(secretHeader, "my-server-secret");
-
-  } finally {
-    Svc.Prefs.resetBranch("");
-    server.stop(do_test_finished);
-  }
-}
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -71,19 +71,16 @@ skip-if = os == "android"
 
 # Service semantics.
 [test_service_attributes.js]
 [test_service_changePassword.js]
 # Bug 752243: Profile cleanup frequently fails
 skip-if = os == "mac" || os == "linux"
 [test_service_checkAccount.js]
 [test_service_cluster.js]
-[test_service_createAccount.js]
-# Bug 752243: Profile cleanup frequently fails
-skip-if = os == "mac" || os == "linux"
 [test_service_detect_upgrade.js]
 [test_service_getStorageInfo.js]
 [test_service_login.js]
 [test_service_migratePrefs.js]
 [test_service_passwordUTF8.js]
 [test_service_persistLogin.js]
 [test_service_set_serverURL.js]
 [test_service_startOver.js]
--- a/tools/lint/eslint/modules.json
+++ b/tools/lint/eslint/modules.json
@@ -217,17 +217,16 @@
   "test_bug883784.jsm": ["Test"],
   "Timer.jsm": ["setTimeout", "clearTimeout", "setInterval", "clearInterval"],
   "tokenserverclient.js": ["TokenServerClient", "TokenServerClientError", "TokenServerClientNetworkError", "TokenServerClientServerError"],
   "ToolboxProcess.jsm": ["BrowserToolboxProcess"],
   "tps.jsm": ["ACTIONS", "TPS"],
   "Translation.jsm": ["Translation", "TranslationTelemetry"],
   "Traversal.jsm": ["TraversalRules", "TraversalHelper"],
   "UpdateTelemetry.jsm": ["AUSTLMY"],
-  "userapi.js": ["UserAPI10Client"],
   "util.js": ["getChromeWindow", "XPCOMUtils", "Services", "Utils", "Async", "Svc", "Str"],
   "utils.js": ["applicationName", "assert", "Copy", "getBrowserObject", "getChromeWindow", "getWindows", "getWindowByTitle", "getWindowByType", "getWindowId", "getMethodInWindows", "getPreference", "saveDataURL", "setPreference", "sleep", "startTimer", "stopTimer", "takeScreenshot", "unwrapNode", "waitFor", "btoa", "encryptPayload", "isConfiguredWithLegacyIdentity", "ensureLegacyIdentityManager", "setBasicCredentials", "makeIdentityConfig", "makeFxAccountsInternalMock", "configureFxAccountIdentity", "configureIdentity", "SyncTestingInfrastructure", "waitForZeroTimer", "Promise", "add_identity_test", "MockFxaStorageManager", "AccountState", "sumHistogram", "CommonUtils", "CryptoUtils", "TestingUtils"],
   "Utils.jsm": ["Utils", "Logger", "PivotContext", "PrefCache"],
   "VariablesView.jsm": ["VariablesView", "escapeHTML"],
   "VariablesViewController.jsm": ["VariablesViewController", "StackFrameUtils"],
   "version.jsm": ["VERSION"],
   "vtt.jsm": ["WebVTT"],
   "WebChannel.jsm": ["WebChannel", "WebChannelBroker"],