gecko/services/mobileid/MobileIdentityClient.jsm

159 lines
4.9 KiB
JavaScript
Raw Normal View History

/* 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");
Cu.import("resource://services-common/hawkrequest.js");
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;
let forceHttps = true;
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);
}
this.hawk = new HawkClient(serverUrl);
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, {});
},
smsMtVerify: function(aSessionToken, aMsisdn, aMcc, aMnc,
aWantShortCode = false) {
let credentials = this._deriveHawkCredentials(aSessionToken);
return this._request(SMS_MT_VERIFY, "POST", credentials, {
msisdn: aMsisdn,
mcc: aMcc,
mnc: aMnc,
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) {
return deriveHawkCredentials(aSessionToken, CREDENTIALS_DERIVATION_INFO,
CREDENTIALS_DERIVATION_SIZE, true /*hexKey*/);
},
/**
* 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(
(response) => {
log.debug("MobileIdentityClient -> response.body " + response.body);
try {
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);
}
deferred.resolve(responseObj);
} 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;
},
};