services/sync/modules/userapi.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 "use strict";
     7 this.EXPORTED_SYMBOLS = [
     8   "UserAPI10Client",
     9 ];
    11 const {utils: Cu} = Components;
    13 Cu.import("resource://gre/modules/Log.jsm");
    14 Cu.import("resource://services-common/rest.js");
    15 Cu.import("resource://services-common/utils.js");
    16 Cu.import("resource://services-sync/identity.js");
    17 Cu.import("resource://services-sync/util.js");
    19 /**
    20  * A generic client for the user API 1.0 service.
    21  *
    22  * http://docs.services.mozilla.com/reg/apis.html
    23  *
    24  * Instances are constructed with the base URI of the service.
    25  */
    26 this.UserAPI10Client = function UserAPI10Client(baseURI) {
    27   this._log = Log.repository.getLogger("Sync.UserAPI");
    28   this._log.level = Log.Level[Svc.Prefs.get("log.logger.userapi")];
    30   this.baseURI = baseURI;
    31 }
    32 UserAPI10Client.prototype = {
    33   USER_CREATE_ERROR_CODES: {
    34     2: "Incorrect or missing captcha.",
    35     4: "User exists.",
    36     6: "JSON parse failure.",
    37     7: "Missing password field.",
    38     9: "Requested password not strong enough.",
    39     12: "No email address on file.",
    40   },
    42   /**
    43    * Determine whether a specified username exists.
    44    *
    45    * Callback receives the following arguments:
    46    *
    47    *   (Error) Describes error that occurred or null if request was
    48    *           successful.
    49    *   (boolean) True if user exists. False if not. null if there was an error.
    50    */
    51   usernameExists: function usernameExists(username, cb) {
    52     if (typeof(cb) != "function") {
    53       throw new Error("cb must be a function.");
    54     }
    56     let url = this.baseURI + username;
    57     let request = new RESTRequest(url);
    58     request.get(this._onUsername.bind(this, cb, request));
    59   },
    61   /**
    62    * Obtain the Weave (Sync) node for a specified user.
    63    *
    64    * The callback receives the following arguments:
    65    *
    66    *   (Error)  Describes error that occurred or null if request was successful.
    67    *   (string) Username request is for.
    68    *   (string) URL of user's node. If null and there is no error, no node could
    69    *            be assigned at the time of the request.
    70    */
    71   getWeaveNode: function getWeaveNode(username, password, cb) {
    72     if (typeof(cb) != "function") {
    73       throw new Error("cb must be a function.");
    74     }
    76     let request = this._getRequest(username, "/node/weave", password);
    77     request.get(this._onWeaveNode.bind(this, cb, request));
    78   },
    80   /**
    81    * Change a password for the specified user.
    82    *
    83    * @param username
    84    *        (string) The username whose password to change.
    85    * @param oldPassword
    86    *        (string) The old, current password.
    87    * @param newPassword
    88    *        (string) The new password to switch to.
    89    */
    90   changePassword: function changePassword(username, oldPassword, newPassword, cb) {
    91     let request = this._getRequest(username, "/password", oldPassword);
    92     request.onComplete = this._onChangePassword.bind(this, cb, request);
    93     request.post(CommonUtils.encodeUTF8(newPassword));
    94   },
    96   createAccount: function createAccount(email, password, captchaChallenge,
    97                                         captchaResponse, cb) {
    98     let username = IdentityManager.prototype.usernameFromAccount(email);
    99     let body = JSON.stringify({
   100       "email":             email,
   101       "password":          Utils.encodeUTF8(password),
   102       "captcha-challenge": captchaChallenge,
   103       "captcha-response":  captchaResponse
   104     });
   106     let url = this.baseURI + username;
   107     let request = new RESTRequest(url);
   109     if (this.adminSecret) {
   110       request.setHeader("X-Weave-Secret", this.adminSecret);
   111     }
   113     request.onComplete = this._onCreateAccount.bind(this, cb, request);
   114     request.put(body);
   115   },
   117   _getRequest: function _getRequest(username, path, password=null) {
   118     let url = this.baseURI + username + path;
   119     let request = new RESTRequest(url);
   121     if (password) {
   122       let up = username + ":" + password;
   123       request.setHeader("authorization", "Basic " + btoa(up));
   124     }
   126     return request;
   127   },
   129   _onUsername: function _onUsername(cb, request, error) {
   130     if (error) {
   131       cb(error, null);
   132       return;
   133     }
   135     let body = request.response.body;
   136     if (body == "0") {
   137       cb(null, false);
   138       return;
   139     } else if (body == "1") {
   140       cb(null, true);
   141       return;
   142     } else {
   143       cb(new Error("Unknown response from server: " + body), null);
   144       return;
   145     }
   146   },
   148   _onWeaveNode: function _onWeaveNode(cb, request, error) {
   149     if (error) {
   150       cb.network = true;
   151       cb(error, null);
   152       return;
   153     }
   155     let response = request.response;
   157     if (response.status == 200) {
   158       let body = response.body;
   159       if (body == "null") {
   160         cb(null, null);
   161         return;
   162       }
   164       cb(null, body);
   165       return;
   166     }
   168     let error = new Error("Sync node retrieval failed.");
   169     switch (response.status) {
   170       case 400:
   171         error.denied = true;
   172         break;
   173       case 404:
   174         error.notFound = true;
   175         break;
   176       default:
   177         error.message = "Unexpected response code: " + response.status;
   178     }
   180     cb(error, null);
   181     return;
   182   },
   184   _onChangePassword: function _onChangePassword(cb, request, error) {
   185     this._log.info("Password change response received: " +
   186                    request.response.status);
   187     if (error) {
   188       cb(error);
   189       return;
   190     }
   192     let response = request.response;
   193     if (response.status != 200) {
   194       cb(new Error("Password changed failed: " + response.body));
   195       return;
   196     }
   198     cb(null);
   199   },
   201   _onCreateAccount: function _onCreateAccount(cb, request, error) {
   202     let response = request.response;
   204     this._log.info("Create account response: " + response.status + " " +
   205                    response.body);
   207     if (error) {
   208       cb(new Error("HTTP transport error."), null);
   209       return;
   210     }
   212     if (response.status == 200) {
   213       cb(null, response.body);
   214       return;
   215     }
   217     let error = new Error("Could not create user.");
   218     error.body = response.body;
   220     cb(error, null);
   221     return;
   222   },
   223 };
   224 Object.freeze(UserAPI10Client.prototype);

mercurial