You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2016/08/05 14:19:33 UTC

[06/37] incubator-milagro-mfa-js-lib git commit: Add mobile authentication flow

Add mobile authentication flow


Project: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/commit/f84d8c7b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/f84d8c7b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/f84d8c7b

Branch: refs/heads/add-documentation
Commit: f84d8c7b790c79ef9be6b8aff149b04d5e663e02
Parents: f27fba9
Author: Boyan Bakov <bo...@certivox.com>
Authored: Thu Dec 10 17:17:13 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:25 2015 +0200

----------------------------------------------------------------------
 lib/mpin.js | 236 ++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 174 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f84d8c7b/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 143916b..879b461 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -8,6 +8,7 @@ var mpinjs = (function () {
   Errors[4] = "IDENTITY_MISSING";
   Errors[5] = "WRONG_PIN";
   Errors[6] = "WRONG_FLOW";
+  Errors[7] = "TIMEOUT_FINISH";
 
   ///
   Status.invalid = "INVALID";
@@ -22,6 +23,8 @@ var mpinjs = (function () {
     }
 
     this.opts = options;
+
+    this.recover();
   };
 
   Mpin.prototype.storageKey = "mpinLib";
@@ -46,11 +49,7 @@ var mpinjs = (function () {
       return {code: 0, type: Errors[0]};
     }
 
-    Users[userId] = {
-      userId: userId,
-      deviceId: deviceId || "",
-      status: Status.invalid
-    };
+    this.addToUser(userId, {userId: userId, deviceId: deviceId, status: Status.invalid});
 
     return this;
   };
@@ -77,8 +76,6 @@ var mpinjs = (function () {
         return cb(err, null);
       }
 
-      self.identity = data.mpinId;
-
       self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId, status: Status.start});
 
       //force activate
@@ -90,7 +87,6 @@ var mpinjs = (function () {
     });
   };
 
-
   //request cs1 + cs2
   Mpin.prototype.confirmRegistration = function (userId, cb) {
     var _cs1Url = "", self = this, _userStatus;
@@ -100,7 +96,7 @@ var mpinjs = (function () {
     } else if (!this.checkUser(userId)) {
       return cb({code: 1, type: Errors[1]}, null);
     } else if (!this.opts.signatureURL) {
-      return cb({code: 2, type: Errors[2], message: "Missing signatureURL"}, null);
+      return cb({code: 2, type: Errors[2], message: "Missing signatureURL option."}, null);
     }
 
     //started || activated
@@ -109,7 +105,12 @@ var mpinjs = (function () {
       return cb({code: 3, type: Errors[3]}, null);
     }
 
-    _cs1Url = this.generateUrl('signature', userId);
+    //already set.
+    if (Users[userId].csHex) {
+      return cb(null, true);
+    }
+
+    _cs1Url = this.generateUrl('signature', {userId: userId});
     //req cs1
     this.request({url: _cs1Url}, function (err, cs1Data) {
       var _cs2Url = "";
@@ -156,7 +157,7 @@ var mpinjs = (function () {
     tokenHex = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
     this.addToUser(userId, {tokenHex: tokenHex, status: Status.register});
 
-    return tokenHex;
+    return true;
   };
 
   //Put user / mpinId
@@ -168,11 +169,26 @@ var mpinjs = (function () {
 
 
   Mpin.prototype.startAuthentication = function (userId, cb) {
-    var _tp1Url, self = this;
+    var _tp1Url, self = this, _userStatus;
+
+    if (!userId || typeof userId !== "string") {
+      return cb ? cb({code: 0, type: Errors[0]}, null) : {error: 0, type: Errors[0]};
+    } else if (!this.checkUser(userId)) {
+      return cb({code: 1, type: Errors[1]}, null);
+    } else if (!this.opts.timePermitsURL || !this.opts.certivoxURL) {
+      return cb({code: 2, type: Errors[2], message: "Missing timePermitsURL or/and certivoxURL option."}, null);
+    }
+
+    //registered
+    _userStatus = this.getUser(userId, "status");
+    if (_userStatus !== Status.register) {
+      return cb({code: 3, type: Errors[3]}, null);
+    }
 
+    //checkUser
     _tp1Url = this.generateUrl('permit1');
     this.request({url: _tp1Url}, function (err, data) {
-      var _signature, _tp2Url, _timePermit1;
+      var _signature, _tp2Url, _timePermit1, _storageUrl;
       _signature = data["signature"];
       _timePermit1 = data["timePermit"];
 
@@ -181,20 +197,51 @@ var mpinjs = (function () {
       _tp2Url = self.generateUrl('permit2');
       _tp2Url += "&signature=" + _signature;
 
-
-      self.request({url: _tp2Url}, function (err2, data2) {
-        var _timePermit2, timePermitHex;
-        _timePermit2 = data2["timePermit"];
-        timePermitHex = MPINAuth.addShares(_timePermit1, _timePermit2);
+      //check cache if exist 
+      if (Users[userId].timePermitCache && Users[userId].timePermitCache.date === data.date) {
+        var _timePermit2 = Users[userId].timePermitCache.timePermit;
+        var timePermitHex = MPINAuth.addShares(_timePermit1, _timePermit2);
 
         self.addToUser(userId, {timePermitHex: timePermitHex});
+        cb && cb(null, true); //exit with cache permit2
+        return;
+      } else {
+        _storageUrl = self.generateUrl("storage", {date: data.date, storageId: data.storageId});
+
+        self.request({url: _storageUrl}, function (storErr, storData) {
+          if (storErr) {
+            self._getTimePermit2({userId: userId, permit1: _timePermit1, permit2Url: _tp2Url, date: data.date}, cb); //continue
+            return;
+          }
 
-        cb && cb(null, true);
-      });
+          var _timePermit2 = storData;
+          var timePermitHex = MPINAuth.addShares(_timePermit1, _timePermit2);
+
+          self.addToUser(userId, {timePermitHex: timePermitHex, timePermitCache: {date: data.date, timePermit: _timePermit2}});
+
+          cb && cb(null, true); //exit with storage permit2
+        }, false);
+      }
+    });
+  };
 
+  Mpin.prototype._getTimePermit2 = function (options, cb) {
+    var self = this, _timePermit1 = options.permit1;
+    this.request({url: options.permit2Url}, function (err2, data2) {
+      var _timePermit2, timePermitHex, _permitCache = {};
+      _timePermit2 = data2["timePermit"];
+      timePermitHex = MPINAuth.addShares(_timePermit1, _timePermit2);
+
+      _permitCache.date = options.date;
+      _permitCache.timePermit = data2["timePermit"];
+
+      self.addToUser(options.userId, {timePermitHex: timePermitHex, timePermitCache: _permitCache});
+
+      cb && cb(null, true);
     });
   };
 
+
   Mpin.prototype.finishAuthentication = function (userId, aPin, cb) {
     var self = this, _reqData = {};
 
@@ -230,7 +277,7 @@ var mpinjs = (function () {
             }
           }
 
-          console.log("auth Data :::", authData);
+          cb && cb(null, true);
         });
       });
     });
@@ -239,7 +286,7 @@ var mpinjs = (function () {
   Mpin.prototype.getAuthData = function (userId, aPin) {
     var _auth = {};
 
-    _auth.mpin = this.identity;
+    _auth.mpin = this.getIdentity();
     _auth.token = Users[userId].tokenHex;
     _auth.timePermit = Users[userId].timePermitHex;
     _auth.date = Users[userId].currentDate;
@@ -273,56 +320,54 @@ var mpinjs = (function () {
       if (err) {
         return cb(err, null);
       }
-      console.log("OTT :::", data.webOTT);
       self.webOTT = data.webOTT;
-      cb(null, {accessNumber: data.accessNumber});
 
+      cb && cb(null, {accessNumber: data.accessNumber});
     });
   };
 
-  Mpin.prototype.getAccess = function (cb) {
+  Mpin.prototype.waitForMobileAuth = function (timeoutSeconds, cb) {
     var self = this, _reqData = {};
-
     if (!this.webOTT) {
       return cb({code: 6, type: Errors[6], message: "Need to call getAccessNumber method before this."}, null);
+    } else if (!timeoutPeriod) {
+      return cb({code: 2, type: Errors[2], message: "Missing timeout/expiration period(in seconds)."}, null);
     }
 
+
+
+    this.timeoutPeriod || (this.timeoutPeriod = timeoutSeconds * 1000);
+
     _reqData.url = this.generateUrl("getaccess");
     _reqData.type = "POST";
     _reqData.data = {webOTT: this.webOTT};
 
     this.request(_reqData, function (err, data) {
       if (err) {
-        if (err.status === 401) {
+        if (err.status === 401 && self.timeoutPeriod > 0) {
+          self.timeoutPeriod -= 3000;
           self.intervalID2 = setTimeout(function () {
-            self.getAccess.call(self, cb);
+            self.waitForMobileAuth.call(self, timeoutSeconds, cb);
           }, 3000);
           return;
+        } else if (self.timeoutPeriod <= 0) {
+          cb && cb({code: 7, type: Errors[7]}, null);
+          return;
         }
       }
 
-      /*
-       * 					self.intervalID2 = setTimeout(function () {
-       self.getAccess.call(self);
-       }, 3000);
-       * 
-       */
-      console.log("data :::", err, data);
-      
-      cb(null, true);
-
-
+      cb && cb(null, true);
     });
   };
 
-  Mpin.prototype.stopAccess = function () {
+  Mpin.prototype.cancelMobileAuth = function () {
     if (this.intervalID2) {
       clearInterval(this.intervalID2);
     }
   };
 
 
-  Mpin.prototype.generateUrl = function (type, userId) {
+  Mpin.prototype.generateUrl = function (type, options) {
     var url, mpData, mpin_id_bytes, hash_mpin_id_bytes = [], hash_mpin_id_hex;
 
     switch (type) {
@@ -331,15 +376,15 @@ var mpinjs = (function () {
         break;
       case "signature":
         url = this.opts.signatureURL + "/";
-        url += Users[userId].mpinId;
-        url += "?regOTT=" + Users[userId].regOTT;
+        url += Users[options.userId].mpinId;
+        url += "?regOTT=" + Users[options.userId].regOTT;
         break;
       case "permit1":
         url = this.opts.timePermitsURL + "/";
-        url += this.identity;
+        url += this.getIdentity();
         break;
       case "permit2":
-        mpData = this.fromHex(this.identity);
+        mpData = this.fromHex(this.getIdentity());
         mpin_id_bytes = MPIN.stringtobytes(mpData);
         hash_mpin_id_bytes = MPIN.HASH_ID(mpin_id_bytes);
         hash_mpin_id_hex = MPIN.bytestostring(hash_mpin_id_bytes);
@@ -363,19 +408,23 @@ var mpinjs = (function () {
       case "getaccess":
         url = this.opts.accessNumberURL;
         break;
+      case "storage":
+        url = this.opts.timePermitsStorageURL + "/" + this.opts.appID + "/";
+        url += options.date + "/" + options.storageId;
+        //return that.opts.timePermitsStorageURL + "/" + that.opts.appID + "/" + date + "/" + storageId;
+        break;
     }
 
     return url;
   };
 
-
   Mpin.prototype.listUsers = function () {
     var listUsers = {};
     for (var uKey in Users) {
       listUsers[uKey] = {
         userId: Users[uKey].userId,
-        deviceId: Users[uKey].deviceId,
-        status: Users[uKey].status
+        deviceId: Users[uKey].deviceId || "",
+        status: Users[uKey].status || ""
       };
     }
     return listUsers;
@@ -395,7 +444,7 @@ var mpinjs = (function () {
 
     _user = {
       userId: Users[userId].userId,
-      deviceId: Users[userId].deviceId,
+      deviceId: Users[userId].deviceId || "",
       status: Users[userId].status
     };
 
@@ -406,16 +455,30 @@ var mpinjs = (function () {
     }
   };
 
-  Mpin.prototype.addToUser = function (userId, userProps) {
-    if (!this.checkUser(userId)) {
+  //remove this
+  Mpin.prototype.getUsers = function () {
+    return Users;
+  };
+
+  Mpin.prototype.addToUser = function (userId, userProps, skipSave) {
+    var _save;
+    if (!this.checkUser(userId) && !userProps.userId) {
       return false;
     }
+    _save = !skipSave;
+
+    //create
+    if (userProps.userId) {
+      Users[userId] = {};
+    }
 
     for (var uKey in userProps) {
-      Users[userId][uKey] = userProps[uKey];
+      if (userProps[uKey]) {
+        Users[userId][uKey] = userProps[uKey];
+      }
     }
 
-    this.setData(userId, userProps);
+    _save && this.setData(userId, userProps);
   };
 
   Mpin.prototype.restore = function () {
@@ -423,8 +486,7 @@ var mpinjs = (function () {
   };
 
   Mpin.prototype.setData = function (userId, upData) {
-    var mpinData;
-    mpinData = JSON.parse(localStorage.getItem(this.storageKey));
+    var mpinData = this.getData();
 
     if (!mpinData) {
       mpinData = {
@@ -454,33 +516,83 @@ var mpinjs = (function () {
       mpinData.accounts[mpinId].token = upData.tokenHex;
     }
 
+    if (upData.status && Users[userId].mpinId) {
+      var mpinId = Users[userId].mpinId;
+      mpinData.accounts[mpinId].status = upData.status;
+    }
+
+    //cache cache
+    if (upData.timePermitCache) {
+      var mpinId = Users[userId].mpinId;
+      mpinData.accounts[mpinId].timePermitCache = upData.timePermitCache;
+    }
+
     localStorage.setItem(this.storageKey, JSON.stringify(mpinData));
   };
 
+  Mpin.prototype.getIdentity = function () {
+    var mpinData = this.getData();
+    return mpinData.defaultIdentity;
+  };
+
+  Mpin.prototype.recover = function () {
+    var userId, userData = {}, mpinData = this.getData();
+
+    if (mpinData && "accounts" in mpinData) {
+      for (var mpinId in mpinData.accounts) {
+        userId = (JSON.parse(this.fromHex(mpinId))).userID;
+
+        userData = {};
+        userData.userId = userId;
+        userData.mpinId = mpinId;
+
+        mpinData.accounts[mpinId].regOTT && (userData.regOTT = mpinData.accounts[mpinId].regOTT);
+        mpinData.accounts[mpinId].token && (userData.token = mpinData.accounts[mpinId].token);
+        mpinData.accounts[mpinId].MPinPermit && (userData.MPinPermit = mpinData.accounts[mpinId].MPinPermit);
+        mpinData.accounts[mpinId].timePermitCache && (userData.timePermitCache = mpinData.accounts[mpinId].timePermitCache);
+
+        mpinData.accounts[mpinId].status && (userData.status = mpinData.accounts[mpinId].status);
+
+        //call add To user & skip Save
+        this.addToUser(userId, userData, true);
+      }
+    }
+  };
+
   Mpin.prototype.getData = function () {
     var mpinData;
-    mpinData = JSON.parse(localStorage.getItem(this.storageKey));
+    mpinData = localStorage.getItem(this.storageKey);
+    mpinData = JSON.parse(mpinData);
     return mpinData;
   };
 
 //{url: url, type: "get post put", data: data}
-  Mpin.prototype.request = function (options, cb) {
-    var _request = new XMLHttpRequest(), _url, _type, _data;
+  Mpin.prototype.request = function (options, cb, jsonResponse) {
+    var _request = new XMLHttpRequest(), _url, _type, _parseJson;
     _url = options.url || "";
     _type = options.type || "GET";
-    _data = options.data || "";
+
+    _parseJson = jsonResponse || true;
 
     _request.onreadystatechange = function () {
       if (_request.readyState === 4 && _request.status === 200) {
-        cb(null, JSON.parse(_request.responseText));
+        if (_parseJson) {
+          cb(null, JSON.parse(_request.responseText));
+        } else {
+          cb(null, _request.responseText);
+        }
       } else if (_request.readyState === 4) {
         cb({status: _request.status}, null);
       }
     };
 
     _request.open(_type, _url, true);
-    _request.setRequestHeader("Content-Type", "application/json");
-    _request.send(JSON.stringify(_data || ""));
+    if (options.data) {
+      _request.setRequestHeader("Content-Type", "application/json");
+      _request.send(JSON.stringify(options.data));
+    } else {
+      _request.send();
+    }
   };
 
   return Mpin;