2014-06-07 21:30:19 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
// REST client for
|
|
|
|
// https://github.com/mozilla-services/msisdn-gateway/blob/master/API.md
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
this.EXPORTED_SYMBOLS = ["MobileIdentityClient"];
|
|
|
|
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
|
|
|
|
|
|
Cu.import("resource://services-common/hawkclient.js");
|
2014-06-18 13:42:15 +04:00
|
|
|
Cu.import("resource://services-common/hawkrequest.js");
|
2014-06-07 21:30:19 +04:00
|
|
|
Cu.import("resource://services-common/utils.js");
|
|
|
|
Cu.import("resource://services-crypto/utils.js");
|
|
|
|
Cu.import("resource://gre/modules/MobileIdentityCommon.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Promise.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
|
|
|
|
this.MobileIdentityClient = function(aServerUrl) {
|
|
|
|
let serverUrl = aServerUrl || SERVER_URL;
|
2014-07-03 13:56:34 +04:00
|
|
|
let forceHttps = true;
|
2014-06-07 21:30:19 +04:00
|
|
|
try {
|
|
|
|
forceHttps = Services.prefs.getBoolPref(PREF_FORCE_HTTPS);
|
|
|
|
} catch(e) {
|
|
|
|
log.warn("Getting force HTTPS pref failed. If this was not intentional " +
|
|
|
|
"check that " + PREF_FORCE_HTTPS + " is defined");
|
|
|
|
}
|
|
|
|
|
|
|
|
log.debug("Force HTTPS " + forceHttps);
|
|
|
|
|
|
|
|
if (forceHttps && !/^https/.exec(serverUrl.toLowerCase())) {
|
|
|
|
throw new Error(ERROR_INTERNAL_HTTP_NOT_ALLOWED);
|
|
|
|
}
|
|
|
|
|
2014-09-03 18:21:41 +04:00
|
|
|
this.hawk = new HawkClient(serverUrl);
|
2014-06-07 21:30:19 +04:00
|
|
|
this.hawk.observerPrefix = "MobileId:hawk";
|
|
|
|
};
|
|
|
|
|
|
|
|
this.MobileIdentityClient.prototype = {
|
|
|
|
|
|
|
|
discover: function(aMsisdn, aMcc, aMnc, aRoaming) {
|
|
|
|
return this._request(DISCOVER, "POST", null, {
|
|
|
|
msisdn: aMsisdn || undefined,
|
|
|
|
mcc: aMcc,
|
|
|
|
mnc: aMnc,
|
|
|
|
roaming: aRoaming
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
register: function() {
|
|
|
|
return this._request(REGISTER, "POST", null, {});
|
|
|
|
},
|
|
|
|
|
2014-07-29 16:27:03 +04:00
|
|
|
smsMtVerify: function(aSessionToken, aMsisdn, aMcc, aMnc,
|
|
|
|
aWantShortCode = false) {
|
2014-06-07 21:30:19 +04:00
|
|
|
let credentials = this._deriveHawkCredentials(aSessionToken);
|
|
|
|
return this._request(SMS_MT_VERIFY, "POST", credentials, {
|
|
|
|
msisdn: aMsisdn,
|
2014-07-29 16:27:03 +04:00
|
|
|
mcc: aMcc,
|
|
|
|
mnc: aMnc,
|
2014-06-07 21:30:19 +04:00
|
|
|
shortVerificationCode: aWantShortCode
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
verifyCode: function(aSessionToken, aVerificationCode) {
|
|
|
|
log.debug("verificationCode " + aVerificationCode);
|
|
|
|
let credentials = this._deriveHawkCredentials(aSessionToken);
|
|
|
|
return this._request(SMS_VERIFY_CODE, "POST", credentials, {
|
|
|
|
code: aVerificationCode
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
sign: function(aSessionToken, aDuration, aPublicKey) {
|
|
|
|
let credentials = this._deriveHawkCredentials(aSessionToken);
|
|
|
|
return this._request(SIGN, "POST", credentials, {
|
|
|
|
duration: aDuration,
|
|
|
|
publicKey: aPublicKey
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
unregister: function(aSessionToken) {
|
|
|
|
let credentials = this._deriveHawkCredentials(aSessionToken);
|
|
|
|
return this._request(UNREGISTER, "POST", credentials, {});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The MobileID server expects requests to certain endpoints to be
|
|
|
|
* authorized using Hawk.
|
|
|
|
*
|
|
|
|
* Hawk credentials are derived using shared secrets.
|
|
|
|
*
|
|
|
|
* @param tokenHex
|
|
|
|
* The current session token encoded in hex
|
|
|
|
* @param context
|
|
|
|
* A context for the credentials
|
|
|
|
* @param size
|
|
|
|
* The size in bytes of the expected derived buffer
|
|
|
|
* @return credentials
|
|
|
|
* Returns an object:
|
|
|
|
* {
|
|
|
|
* algorithm: sha256
|
|
|
|
* id: the Hawk id (from the first 32 bytes derived)
|
|
|
|
* key: the Hawk key (from bytes 32 to 64)
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
_deriveHawkCredentials: function(aSessionToken) {
|
2014-06-18 13:42:15 +04:00
|
|
|
return deriveHawkCredentials(aSessionToken, CREDENTIALS_DERIVATION_INFO,
|
2014-06-21 10:43:39 +04:00
|
|
|
CREDENTIALS_DERIVATION_SIZE, true /*hexKey*/);
|
2014-06-07 21:30:19 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A general method for sending raw API calls to the mobile id verification
|
|
|
|
* server.
|
|
|
|
* All request bodies and responses are JSON.
|
|
|
|
*
|
|
|
|
* @param path
|
|
|
|
* API endpoint path
|
|
|
|
* @param method
|
|
|
|
* The HTTP request method
|
|
|
|
* @param credentials
|
|
|
|
* Hawk credentials
|
|
|
|
* @param jsonPayload
|
|
|
|
* A JSON payload
|
|
|
|
* @return Promise
|
|
|
|
* Returns a promise that resolves to the JSON response of the API
|
|
|
|
* call, or is rejected with an error.
|
|
|
|
*/
|
|
|
|
_request: function(path, method, credentials, jsonPayload) {
|
|
|
|
let deferred = Promise.defer();
|
|
|
|
|
|
|
|
this.hawk.request(path, method, credentials, jsonPayload).then(
|
2014-06-18 13:42:15 +04:00
|
|
|
(response) => {
|
|
|
|
log.debug("MobileIdentityClient -> response.body " + response.body);
|
2014-06-07 21:30:19 +04:00
|
|
|
try {
|
2014-09-03 18:21:41 +04:00
|
|
|
let responseObj;
|
|
|
|
// We parse the response body unless we are handling a 204 response,
|
|
|
|
// which MUST NOT include a message body.
|
|
|
|
if (response.status != 204) {
|
|
|
|
responseObj = JSON.parse(response.body);
|
|
|
|
}
|
2014-06-18 13:42:15 +04:00
|
|
|
deferred.resolve(responseObj);
|
2014-06-07 21:30:19 +04:00
|
|
|
} catch (err) {
|
|
|
|
deferred.reject({error: err});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(error) => {
|
|
|
|
log.error("MobileIdentityClient -> Error ${}", error);
|
|
|
|
deferred.reject(SERVER_ERRNO_TO_ERROR[error.errno] || ERROR_UNKNOWN);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|