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:28 UTC

[01/37] incubator-milagro-mfa-js-lib git commit: Initial commit

Repository: incubator-milagro-mfa-js-lib
Updated Branches:
  refs/heads/add-documentation [created] 3f1d170c0


Initial commit


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/10266af0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/10266af0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/10266af0

Branch: refs/heads/add-documentation
Commit: 10266af0f9fea2eb0b7406e2faff9fae64832ba7
Parents: 
Author: Boyan Bakov <bo...@certivox.com>
Authored: Thu Nov 19 15:51:33 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:22 2015 +0200

----------------------------------------------------------------------
 README.md | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/10266af0/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c437278
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+# MPIN frontend library
+
+
+
+## Installation
+```bash
+$ git clone
+$ cd project_folder
+$ npm install
+```
+
+## Example
+
+- Registration
+- Authentication
+
+## Running Tests
+
+Install development dependencies:
+
+```bash
+$ npm install
+```
+
+Then:
+
+```bash
+$ npm test
+```
+
+Actively tested with node:
+
+  - 0.10.4
+
+## Authors
+
+  * MIRACL Ltd.
+
+## License 
+
+(The MIT License)
+


[16/37] incubator-milagro-mfa-js-lib git commit: Add more error handling for authenticate

Posted by sa...@apache.org.
Add more error handling for authenticate


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/9b77baca
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/9b77baca
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/9b77baca

Branch: refs/heads/add-documentation
Commit: 9b77baca7b8aa13d2a9f8450e13c89e07e16d422
Parents: d0cbb29
Author: Boyan Bakov <bo...@certivox.com>
Authored: Tue Feb 2 13:22:45 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Tue Feb 2 13:22:45 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 9 +++++++++
 1 file changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/9b77baca/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index f548cdf..3d09851 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -29,6 +29,9 @@ var mpinjs = (function () {
   Errors.wrongFlow = {code: 6, type: "WRONG_FLOW"};
   Errors.userRevoked = {code: 7, type: "USER_REVOKED"};
   Errors.timeoutFinish = {code: 8, type: "TIMEOUT_FINISH"};
+  Errors.requestExpired = {code: 9, type: "REQUEST_EXPIRED"};
+  Errors.identityNotAuthorized = {code: 10, type: "IDENTITY_NOT_AUTHORIZED"};
+  Errors.incorrectAccessNumber = {code: 11, type: "INCORRECT_ACCESS_NUMBER"};
 
   States.invalid = "INVALID";
   States.start = "STARTED";
@@ -422,9 +425,15 @@ var mpinjs = (function () {
       if (authErr) {
         if (authErr.status === 401) {
           return cb(Errors.wrongPin, null);
+        } else if (authErr.status === 403) {
+          return cb(Errors.identityNotAuthorized, null);
+        } else if (authErr.status === 408) {
+          return cb(Errors.requestExpired, null);
         } else if (authErr.status === 410) {
           opts.userId && self.addToUser(opts.userId, {state: States.block});
           return cb(Errors.wrongPin, null);
+        } else if (authErr.status === 412) {
+          return cb(Errors.incorrectAccessNumber, null);
         } else {
           return cb(Errors.wrongPin, null);
         }


[24/37] incubator-milagro-mfa-js-lib git commit: Check exist data in recover

Posted by sa...@apache.org.
Check exist data in recover


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/38fd0ed6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/38fd0ed6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/38fd0ed6

Branch: refs/heads/add-documentation
Commit: 38fd0ed6055a8400d96d981b6fb2faebedf8f32f
Parents: 0f359a3
Author: Boyan Bakov <bo...@certivox.com>
Authored: Wed Mar 2 17:03:25 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Wed Mar 2 17:03:25 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/38fd0ed6/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index d23d32f..b6e9f5a 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -756,7 +756,7 @@ var mpinjs = (function () {
       isOldData = true;
     }
 
-    if ("accounts" in mpinData) {
+    if (mpinData && "accounts" in mpinData) {
       for (var mpinId in mpinData.accounts) {
         userId = (JSON.parse(this.fromHex(mpinId))).userID;
 


[09/37] incubator-milagro-mfa-js-lib git commit: Removing unnecessarily stored cs shares.

Posted by sa...@apache.org.
Removing unnecessarily stored cs shares.


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/166b07b7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/166b07b7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/166b07b7

Branch: refs/heads/add-documentation
Commit: 166b07b72646a111a694eeb851c97d4737164278
Parents: 11db839
Author: Simeon Aladjem <si...@certivox.com>
Authored: Tue Dec 22 15:42:45 2015 +0200
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Tue Dec 22 15:42:45 2015 +0200

----------------------------------------------------------------------
 lib/mpin.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/166b07b7/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 7ae1e67..c087f8c 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -147,17 +147,15 @@ var mpinjs = (function () {
         }
       }
 
-      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, state: State.active});
       _cs2Url = self.opts.certivoxURL + "clientSecret?" + cs1Data.params;
 
       //req cs2
       self.request({url: _cs2Url}, function (err, cs2Data) {
         var csHex;
 
-        self.addToUser(userId, {cs2: cs2Data.clientSecret});
         csHex = MPINAuth.addShares(cs2Data.clientSecret, cs1Data.clientSecretShare);
 
-        self.addToUser(userId, {csHex: csHex});
+        self.addToUser(userId, {csHex: csHex, state: State.active});
 
         cb(null, true);
       });


[11/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #3 in MPIN/mpinjs from mony_rename_status to master

Posted by sa...@apache.org.
Merge pull request #3 in MPIN/mpinjs from mony_rename_status to master

* commit '6d46a672022a270811b41914b8e0c980561ca1d2':
  Adding USER_REVOKED error.
  Removing unnecessarily stored cs shares.
  Tightening up naming conventions.


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/3495d12d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/3495d12d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/3495d12d

Branch: refs/heads/add-documentation
Commit: 3495d12d81c7ef5a71855673ccc064e020903a34
Parents: f272668 6d46a67
Author: Simeon Aladjem <si...@certivox.com>
Authored: Tue Dec 22 16:16:31 2015 +0100
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Tue Dec 22 16:16:31 2015 +0100

----------------------------------------------------------------------
 example/exampleJquery.html |  16 ++---
 lib/mpin.js                | 143 ++++++++++++++++++++--------------------
 2 files changed, 79 insertions(+), 80 deletions(-)
----------------------------------------------------------------------



[13/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #4 in MPIN/mpinjs from mony_fixes to master

Posted by sa...@apache.org.
Merge pull request #4 in MPIN/mpinjs from mony_fixes to master

* commit '4231d4890fe028eaf013a8df98a3ff7a205a8229':
  Adding missing functionality and fixing bugs


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/451dce66
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/451dce66
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/451dce66

Branch: refs/heads/add-documentation
Commit: 451dce66a0f4011503da7b9818c23aee140d7fe7
Parents: 3495d12 4231d48
Author: Simeon Aladjem <si...@certivox.com>
Authored: Wed Dec 23 15:02:40 2015 +0100
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Wed Dec 23 15:02:40 2015 +0100

----------------------------------------------------------------------
 lib/mpin.js   | 190 ++++++++++++++++++++++++++++++-----------------------
 test/index.js |   8 +--
 2 files changed, 111 insertions(+), 87 deletions(-)
----------------------------------------------------------------------



[20/37] incubator-milagro-mfa-js-lib git commit: Add bamboo reporter & mock Localstorage in tests

Posted by sa...@apache.org.
Add bamboo reporter & mock Localstorage in tests


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/70a031a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/70a031a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/70a031a9

Branch: refs/heads/add-documentation
Commit: 70a031a912721470257a4e025a75b670f8bf580f
Parents: 262d472
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Feb 29 16:00:25 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Feb 29 16:23:23 2016 +0200

----------------------------------------------------------------------
 .gitignore    |  1 +
 package.json  |  5 +++--
 test/index.js | 34 ++++++++++++++++++++++++++++------
 3 files changed, 32 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/70a031a9/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 18e0abb..2cc3e2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ npm-debug.log
 bower_components/
 nbproject/
 test/coverage.html
+mocha.json

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/70a031a9/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index d3c1a1b..cbe0d8a 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "description": "Mpin frontend library.",
   "main": "index.js",
   "scripts": {
-    "test": "mocha",
+    "test": "mocha -R mocha-bamboo-reporter",
     "test2": "mocha test --require blanket --reporter html-cov > test/coverage.html"
   },
   "repository": {
@@ -36,6 +36,7 @@
     "bower": "^1.6.5",
     "grunt": "^0.4.5",
     "grunt-bg-shell": "^2.3.1",
-    "grunt-contrib-concat": "^0.5.1"
+    "grunt-contrib-concat": "^0.5.1",
+    "mocha-bamboo-reporter": "^1.1.0"
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/70a031a9/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
index 0bb83b8..afa7924 100644
--- a/test/index.js
+++ b/test/index.js
@@ -7,7 +7,7 @@ to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at
 
-  http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
@@ -22,8 +22,9 @@ if (typeof require !== 'undefined') {
   var expect = require('chai').expect;
   var sinon = require('sinon');
   var sinonChai = require('sinon-chai');
-  var mpinjs = require('../index');
-//  var mpinjs = require('../dist/mpinjs');
+  //used to generate test coverage with blanket
+  //  var mpinjs = require('../index');
+  var mpinjs = require('../dist/mpinjs');
 }
 
 var Errors = [];
@@ -32,6 +33,15 @@ Errors[1] = "INVALID_USERID";
 Errors[2] = "MISSING_PARAMETERS";
 Errors[3] = "IDENTITY_NOT_VERIFIED";
 
+var testLocalstorage = {
+  "accounts": {
+    "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
+      "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
+      "state": "STARTED"
+    }
+  }
+};
+
 describe('# Constructor initialization without server Url.', function () {
   it('should throw Error', function () {
     var mpin = new mpinjs();
@@ -48,6 +58,9 @@ describe('# Normal iniatilization.', function () {
     spy = sinon.spy();
 
     mpin.request = spy;
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
   });
 
   it('should call request method once', function () {
@@ -72,6 +85,9 @@ describe('# Init method > clientSettings request.', function () {
       mpinAuthServerURL: "http://192.168.10.63:8011/rps",
       registerUrl: "http://192.168.10.63:8011/rps/user"
     };
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
   });
 
 //restore request
@@ -103,6 +119,9 @@ describe('# makeNewUser checks.', function () {
 
   before(function () {
     mpin = new mpinjs({server: serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
   });
 
   after(function () {
@@ -132,6 +151,9 @@ describe('# startRegistration.', function () {
       mpinAuthServerURL: "http://192.168.10.63:8011/rps",
       registerURL: "http://192.168.10.63:8011/rps/user"
     };
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
   });
 
   after(function () {
@@ -178,9 +200,6 @@ describe('# startRegistration.', function () {
       });
     });
   });
-
-
-
 });
 
 
@@ -205,6 +224,9 @@ describe('# confirmRegistration.', function () {
     this.fakeCs2 = {
       clientSecret: "0409ba1a247561ab16c35df3ad0ca9846db9968fa28757005335dc2ca35188b4f51521ac97d45bbdb3a8d1c0fdfe79ab29031054534df8b7cbac12e67e4e99d685"
     };
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
   });
 
   afterEach(function () {


[02/37] incubator-milagro-mfa-js-lib git commit: Add otp auth flow

Posted by sa...@apache.org.
Add otp auth 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/f2726680
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/f2726680
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/f2726680

Branch: refs/heads/add-documentation
Commit: f272668080dc8fe4878ae667b56593fda1e02a53
Parents: b376277
Author: Boyan Bakov <bo...@certivox.com>
Authored: Fri Dec 18 15:45:16 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:25 2015 +0200

----------------------------------------------------------------------
 example/exampleJquery.html |   2 +-
 lib/mpin.js                | 126 ++++++++++++++++++++++++++++------------
 2 files changed, 90 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f2726680/example/exampleJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleJquery.html b/example/exampleJquery.html
index b8826cb..de1b29e 100644
--- a/example/exampleJquery.html
+++ b/example/exampleJquery.html
@@ -33,7 +33,7 @@ and open the template in the editor.
 
         //// MPIN init
         window.mpin = mpin = new mpinjs({
-          server: "http://192.168.10.63:8005"
+          server: "http://ssodemo.certivox.com"
         });
 
         mpin.init(function (err, data) {

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f2726680/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 39e73bf..7db5fd7 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -6,9 +6,9 @@
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at
- 
+
  http://www.apache.org/licenses/LICENSE-2.0
- 
+
  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -50,8 +50,13 @@ var mpinjs = (function () {
   Mpin.prototype.init = function (cb) {
     var self = this, _initUrl;
 
-    _initUrl = this.opts.server;
-    _initUrl += this.opts.rpsPrefix || "/rps/clientSettings";
+    if (this.opts.server.slice(-1) === "/") {
+      _initUrl = this.opts.server;
+    } else {
+      _initUrl = this.opts.server + "/";
+    }
+    _initUrl += this.opts.rpsPrefix || "rps";
+    _initUrl += "/clientSettings";
 
     this.request({url: _initUrl}, function (err, data) {
       if (err && cb) {
@@ -175,6 +180,8 @@ var mpinjs = (function () {
     }
 
     token = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
+    delete Users[userId].csHex;
+
     this.addToUser(userId, {token: token, status: Status.register});
 
     return true;
@@ -217,7 +224,7 @@ var mpinjs = (function () {
       _tp2Url = self.generateUrl('permit2', {userId: userId});
       _tp2Url += "&signature=" + _signature;
 
-      //check cache if exist 
+      //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);
@@ -263,7 +270,7 @@ var mpinjs = (function () {
 
 
   Mpin.prototype.finishAuthentication = function (userId, aPin, cb) {
-    var self = this, _reqData = {}, _userStatus;
+    var _userStatus;
 
     //registered
     _userStatus = this.getUser(userId, "status");
@@ -273,6 +280,44 @@ var mpinjs = (function () {
       return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
+    this._passRequests({userId: userId, aPin: aPin}, cb);
+  };
+
+  Mpin.prototype.finishAuthenticationOtp = function (userId, aPin, cb) {
+    var _userStatus;
+
+    //registered
+    _userStatus = this.getUser(userId, "status");
+    if (_userStatus !== Status.register) {
+      return cb(Errors.wrongFlow, null);
+    } else if (!Users[userId].timePermitHex) {
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+    }
+
+    this._passRequests({userId: userId, aPin: aPin, otp: true}, function (err, data) {
+      if (err) {
+        return cb(err, null);
+      }
+
+      if (!data.expireTime || !data.ttlSeconds || !data.nowTime) {
+        return cb(null, null);
+      }
+
+      data.expireTime = data.expireTime / 1000;
+      data.nowTime = data.nowTime / 1000;
+
+      cb(null, data);
+    });
+
+  };
+
+  Mpin.prototype._passRequests = function (opts, cb) {
+    var userId, aPin, otp, self = this, _reqData = {};
+    userId = opts.userId;
+    aPin = opts.aPin;
+
+    otp = opts.otp || false;
+
     _reqData.url = this.generateUrl("pass1");
     _reqData.type = "POST";
     _reqData.data = this.getAuthData(userId, aPin);
@@ -283,42 +328,57 @@ var mpinjs = (function () {
       _req2Data.url = self.generateUrl("pass2");
       _req2Data.type = "POST";
 
-      _req2Data.data = MPINAuth.pass2Request(pass1Data.y, false, "0");
+      _req2Data.data = MPINAuth.pass2Request(pass1Data.y, otp, "0");
+
       _req2Data.data.mpin_id = Users[userId].mpinId;
 
       // pass 2
       self.request(_req2Data, function (pass2Err, pass2Data) {
-        var _req3Data = {};
+        var otpCode;
         if (pass2Err) {
           return cb(pass2Err, null);
         }
 
+        otpCode = pass2Data["OTP"] || false;
+
         if (pass2Data && pass2Data["OTP"]) {
           delete pass2Data["OTP"];
         }
 
-        _req3Data.url = self.generateUrl("auth");
-        _req3Data.type = "POST";
-        _req3Data.data = {mpinResponse: pass2Data};
-
-        self.request(_req3Data, function (authErr, authData) {
-          if (authErr) {
-            if (authErr.status === 401) {
-              return cb(Errors.wrongPin, null);
-            } else if (authErr.status === 410) {
-              self.addToUser(userId, {status: Status.block});
-              return cb(Errors.wrongPin, null);
-            } else {
-              return cb(Errors.wrongPin, null);
-            }
-          }
-
-          cb && cb(null, authData || {});
-        });
+        self._authenticate({userId: userId, mpinResponse: pass2Data, otpCode: otpCode}, cb);
       });
     });
+
+  };
+
+  Mpin.prototype._authenticate = function (opts, cb) {
+    var _authData = {}, self = this;
+
+    _authData.url = this.generateUrl("auth");
+    _authData.type = "POST";
+    _authData.data = {mpinResponse: opts.mpinResponse};
+
+    this.request(_authData, function (authErr, authData) {
+      if (authErr) {
+        if (authErr.status === 401) {
+          return cb(Errors.wrongPin, null);
+        } else if (authErr.status === 410) {
+          opts.userId && self.addToUser(opts.userId, {status: Status.block});
+          return cb(Errors.wrongPin, null);
+        } else {
+          return cb(Errors.wrongPin, null);
+        }
+      }
+
+      if (opts.otpCode && authData) {
+        authData.otp = opts.otpCode;
+      }
+
+      cb && cb(null, authData || null);
+    });
   };
 
+
   Mpin.prototype.getAuthData = function (userId, aPin) {
     var _auth = {};
 
@@ -396,7 +456,7 @@ var mpinjs = (function () {
         }
       }
 
-      cb && cb(null, true);
+      self._authenticate({mpinResponse: data}, cb);
     });
   };
 
@@ -513,12 +573,6 @@ var mpinjs = (function () {
     //store
     delete mpinData.accounts[delMpinId];
 
-    //change default Identity
-    for (var mpinId in mpinData.accounts) {
-      mpinData.defaultIdentity = mpinId;
-      break;
-    }
-
     this.storeData(mpinData);
   };
 
@@ -552,7 +606,6 @@ var mpinjs = (function () {
 
     if (!mpinData) {
       mpinData = {
-        defaultIdentity: "",
         version: "0.3",
         accounts: {}
       };
@@ -560,7 +613,6 @@ var mpinjs = (function () {
 
     //update Default Identity
     if (upData.mpinId) {
-      mpinData.defaultIdentity = upData.mpinId;
       mpinData.accounts[upData.mpinId] = {};
     }
 
@@ -633,7 +685,7 @@ var mpinjs = (function () {
     _url = options.url || "";
     _type = options.type || "GET";
 
-    _parseJson = jsonResponse || true;
+    _parseJson = (typeof jsonResponse !== "undefined") ? jsonResponse : true;
 
     _request.onreadystatechange = function () {
       if (_request.readyState === 4 && _request.status === 200) {
@@ -665,4 +717,4 @@ var mpinjs = (function () {
 if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
   module.exports = mpinjs;
 else
-  window.mpinjs = mpinjs;
\ No newline at end of file
+  window.mpinjs = mpinjs;


[07/37] incubator-milagro-mfa-js-lib git commit: Add auth flow

Posted by sa...@apache.org.
Add auth flow

Add persistent storage.


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/f27fba99
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/f27fba99
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/f27fba99

Branch: refs/heads/add-documentation
Commit: f27fba9930db5358259b56a9737b1c6b89c209e8
Parents: 67ed8eb
Author: Boyan Bakov <bo...@certivox.com>
Authored: Wed Dec 2 11:57:51 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:25 2015 +0200

----------------------------------------------------------------------
 .gitignore         |   1 +
 index.js           |   2 +-
 lib/mpin.js        | 341 ++++++++++++++++++++++++++++++++++++++++-----
 test/coverage.html | 360 ------------------------------------------------
 test/index.js      | 150 ++++++++++++++++++--
 test/mocha.opts    |   2 +-
 6 files changed, 454 insertions(+), 402 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f27fba99/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 727ae60..eb737b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ npm-debug.log
 bower_components/
 nbproject/
 index.html
+test/coverage.html

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f27fba99/index.js
----------------------------------------------------------------------
diff --git a/index.js b/index.js
index 3a12526..e7cdcee 100644
--- a/index.js
+++ b/index.js
@@ -1 +1 @@
-\ufeffmodule.exports = require('./lib/mpin');
\ No newline at end of file
+module.exports = require('./lib/mpin');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f27fba99/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 285d749..143916b 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -1,11 +1,20 @@
 var mpinjs = (function () {
-  var Mpin, Users = {}, Errors = [];
-
-  Errors[1] = "Invalid userId.";
-  Errors[2] = "UserId does not exist.";
-  Errors[3] = "Missing parameter.";
-
-  Errors[4] = "UserId are not verified.";
+  var Mpin, Users = {}, Errors = [], Status = {};
+
+  Errors[0] = "MISSING_USERID";
+  Errors[1] = "INVALID_USERID";
+  Errors[2] = "MISSING_PARAMETERS";
+  Errors[3] = "IDENTITY_NOT_VERIFIED";
+  Errors[4] = "IDENTITY_MISSING";
+  Errors[5] = "WRONG_PIN";
+  Errors[6] = "WRONG_FLOW";
+
+  ///
+  Status.invalid = "INVALID";
+  Status.start = "STARTED";
+  Status.active = "ACTIVATED";
+  Status.register = "REGISTERED";
+  Status.block = "BLOCKED";
 
   Mpin = function (options) {
     if (!options || !options.settingsUrl) {
@@ -15,7 +24,7 @@ var mpinjs = (function () {
     this.opts = options;
   };
 
-  Mpin.prototype.debug = true;
+  Mpin.prototype.storageKey = "mpinLib";
 
   Mpin.prototype.init = function (cb) {
     var self = this;
@@ -34,13 +43,13 @@ var mpinjs = (function () {
 
   Mpin.prototype.makeNewUser = function (userId, deviceId) {
     if (!userId) {
-      return {error: 1};
+      return {code: 0, type: Errors[0]};
     }
 
     Users[userId] = {
       userId: userId,
       deviceId: deviceId || "",
-      status: "INVALID"
+      status: Status.invalid
     };
 
     return this;
@@ -48,15 +57,15 @@ var mpinjs = (function () {
 
   Mpin.prototype.startRegistration = function (userId, cb) {
     var _reqData = {}, self = this;
-    if (!userId || typeof userId != "string") {
-      return cb ? cb({error: 1}, null) : {error: 1};
+    if (!userId || typeof userId !== "string") {
+      return cb ? cb({code: 0, type: Errors[0]}, null) : {error: 1};
     } else if (!this.checkUser(userId)) {
-      return cb({error: 2}, null);
+      return cb({code: 1, type: Errors[1]}, null);
     } else if (!this.opts.registerURL) {
-      return cb({error: 3, message: "Missing registerURL"}, null);
+      return cb({code: 2, type: Errors[2], message: "Missing registerURL"}, null);
     }
 
-    _reqData.url = this.opts.registerURL;
+    _reqData.url = this.generateUrl("register");
     _reqData.type = "PUT";
     _reqData.data = {
       userId: userId,
@@ -68,11 +77,13 @@ var mpinjs = (function () {
         return cb(err, null);
       }
 
-      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId,status: "STARTED"});
+      self.identity = data.mpinId;
+
+      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId, status: Status.start});
 
       //force activate
       if (data.active) {
-        self.addToUser(userId, {status: "ACTIVATED"});
+        self.addToUser(userId, {status: Status.active});
       }
 
       cb && cb(null, true);
@@ -82,27 +93,41 @@ var mpinjs = (function () {
 
   //request cs1 + cs2
   Mpin.prototype.confirmRegistration = function (userId, cb) {
-    var _cs1Url = "", self = this;
+    var _cs1Url = "", 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.signatureURL) {
+      return cb({code: 2, type: Errors[2], message: "Missing signatureURL"}, null);
+    }
 
-    _cs1Url = this.opts.signatureURL + "/";
-    _cs1Url += Users[userId].mpinId; //identity
-    _cs1Url += "?regOTT=" + Users[userId].regOTT;
+    //started || activated
+    _userStatus = this.getUser(userId, "status");
+    if (_userStatus !== Status.start && _userStatus !== Status.active) {
+      return cb({code: 3, type: Errors[3]}, null);
+    }
 
+    _cs1Url = this.generateUrl('signature', userId);
     //req cs1
     this.request({url: _cs1Url}, function (err, cs1Data) {
       var _cs2Url = "";
       if (err) {
         if (err.status == 401) {
-          return cb({error: 4, message: "Identity not activate."}, null);
+          return cb({code: 3, type: Errors[3], message: "Identity not activate."}, null);
+        } else if (err.status == 400) {
+          return cb({code: 4, type: Errors[4]}, null);
         }
       }
 
-      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, status: "ACTIVATED"});
+      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, status: Status.active});
       _cs2Url = self.opts.certivoxURL + "clientSecret?" + cs1Data.params;
 
       //req cs2
       self.request({url: _cs2Url}, function (err, cs2Data) {
         var csHex;
+
         self.addToUser(userId, {cs2: cs2Data.clientSecret});
         csHex = MPINAuth.addShares(cs2Data.clientSecret, cs1Data.clientSecretShare);
 
@@ -118,14 +143,18 @@ var mpinjs = (function () {
   Mpin.prototype.finishRegistration = function (userId, pin) {
     var _user, tokenHex;
 
+    if (!userId || typeof userId !== "string") {
+      return {error: 0, type: Errors[0]};
+    }
+
     _user = this.getUser(userId);
 
-    if (_user.status !== "ACTIVATED") {
-      return {error: 3};
+    if (_user.status !== Status.active) {
+      return {code: 3, type: Errors[3]};
     }
 
     tokenHex = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
-    this.addToUser(userId, {tokenHex: tokenHex, status: "REGISTER"});
+    this.addToUser(userId, {tokenHex: tokenHex, status: Status.register});
 
     return tokenHex;
   };
@@ -137,6 +166,209 @@ var mpinjs = (function () {
   };
 
 
+
+  Mpin.prototype.startAuthentication = function (userId, cb) {
+    var _tp1Url, self = this;
+
+    _tp1Url = this.generateUrl('permit1');
+    this.request({url: _tp1Url}, function (err, data) {
+      var _signature, _tp2Url, _timePermit1;
+      _signature = data["signature"];
+      _timePermit1 = data["timePermit"];
+
+      self.addToUser(userId, {currentDate: data['date']});
+
+      _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);
+
+        self.addToUser(userId, {timePermitHex: timePermitHex});
+
+        cb && cb(null, true);
+      });
+
+    });
+  };
+
+  Mpin.prototype.finishAuthentication = function (userId, aPin, cb) {
+    var self = this, _reqData = {};
+
+    _reqData.url = this.generateUrl("pass1");
+    _reqData.type = "POST";
+    _reqData.data = this.getAuthData(userId, aPin);
+
+    //  pass1
+    this.request(_reqData, function (pass1Err, pass1Data) {
+      var _req2Data = {};
+      _req2Data.url = self.generateUrl("pass2");
+      _req2Data.type = "POST";
+
+      _req2Data.data = MPINAuth.pass2Request(pass1Data.y, false, "0");
+      _req2Data.data.mpin_id = Users[userId].mpinId;
+
+      // pass 2
+      self.request(_req2Data, function (pass2Err, pass2Data) {
+        var _req3Data = {};
+
+        if (pass2Data["OTP"]) {
+          delete pass2Data["OTP"];
+        }
+
+        _req3Data.url = self.generateUrl("auth");
+        _req3Data.type = "POST";
+        _req3Data.data = {mpinResponse: pass2Data};
+
+        self.request(_req3Data, function (authErr, authData) {
+          if (authErr) {
+            if (authErr.status === 401) {
+              return cb({code: 5, type: Errors[5]}, null);
+            }
+          }
+
+          console.log("auth Data :::", authData);
+        });
+      });
+    });
+  };
+
+  Mpin.prototype.getAuthData = function (userId, aPin) {
+    var _auth = {};
+
+    _auth.mpin = this.identity;
+    _auth.token = Users[userId].tokenHex;
+    _auth.timePermit = Users[userId].timePermitHex;
+    _auth.date = Users[userId].currentDate;
+
+    return MPINAuth.pass1Request(_auth.mpin, _auth.token, _auth.timePermit, aPin, _auth.date, null);
+  };
+
+  Mpin.prototype.fromHex = function (strData) {
+    if (!strData || strData.length % 2 != 0)
+      return '';
+    strData = strData.toLowerCase();
+    var digits = '0123456789abcdef';
+    var result = '';
+    for (var i = 0; i < strData.length; ) {
+      var a = digits.indexOf(strData.charAt(i++));
+      var b = digits.indexOf(strData.charAt(i++));
+      if (a < 0 || b < 0)
+        return '';
+      result += String.fromCharCode(a * 16 + b);
+    }
+    return result;
+  };
+
+  Mpin.prototype.getAccessNumber = function (cb) {
+    var self = this, _reqData = {};
+
+    _reqData.url = this.generateUrl("getnumber");
+    _reqData.type = "POST";
+
+    this.request(_reqData, function (err, data) {
+      if (err) {
+        return cb(err, null);
+      }
+      console.log("OTT :::", data.webOTT);
+      self.webOTT = data.webOTT;
+      cb(null, {accessNumber: data.accessNumber});
+
+    });
+  };
+
+  Mpin.prototype.getAccess = function (cb) {
+    var self = this, _reqData = {};
+
+    if (!this.webOTT) {
+      return cb({code: 6, type: Errors[6], message: "Need to call getAccessNumber method before this."}, null);
+    }
+
+    _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) {
+          self.intervalID2 = setTimeout(function () {
+            self.getAccess.call(self, cb);
+          }, 3000);
+          return;
+        }
+      }
+
+      /*
+       * 					self.intervalID2 = setTimeout(function () {
+       self.getAccess.call(self);
+       }, 3000);
+       * 
+       */
+      console.log("data :::", err, data);
+      
+      cb(null, true);
+
+
+    });
+  };
+
+  Mpin.prototype.stopAccess = function () {
+    if (this.intervalID2) {
+      clearInterval(this.intervalID2);
+    }
+  };
+
+
+  Mpin.prototype.generateUrl = function (type, userId) {
+    var url, mpData, mpin_id_bytes, hash_mpin_id_bytes = [], hash_mpin_id_hex;
+
+    switch (type) {
+      case "register":
+        url = this.opts.registerURL;
+        break;
+      case "signature":
+        url = this.opts.signatureURL + "/";
+        url += Users[userId].mpinId;
+        url += "?regOTT=" + Users[userId].regOTT;
+        break;
+      case "permit1":
+        url = this.opts.timePermitsURL + "/";
+        url += this.identity;
+        break;
+      case "permit2":
+        mpData = this.fromHex(this.identity);
+        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);
+        url = this.opts.certivoxURL + "timePermit";
+        url += "?app_id=" + this.opts.appID;
+        url += "&mobile=0";
+        url += "&hash_mpin_id=" + hash_mpin_id_hex;
+        break;
+      case "pass1":
+        url = this.opts.mpinAuthServerURL + "/pass1";
+        break;
+      case "pass2":
+        url = this.opts.mpinAuthServerURL + "/pass2";
+        break;
+      case "auth":
+        url = this.opts.authenticateURL;
+        break;
+      case "getnumber":
+        url = this.opts.getAccessNumberURL;
+        break;
+      case "getaccess":
+        url = this.opts.accessNumberURL;
+        break;
+    }
+
+    return url;
+  };
+
+
   Mpin.prototype.listUsers = function () {
     var listUsers = {};
     for (var uKey in Users) {
@@ -153,13 +385,12 @@ var mpinjs = (function () {
     return (Users[userId]) ? true : false;
   };
 
-
-  Mpin.prototype.getUser = function (userId) {
+  Mpin.prototype.getUser = function (userId, property) {
     var _user = {};
     if (!userId) {
-      return {error: 0};
+      return {code: 0, type: Errors[0]};
     } else if (!this.checkUser(userId)) {
-      return {error: 2};
+      return {code: 1, type: Errors[1]};
     }
 
     _user = {
@@ -168,7 +399,11 @@ var mpinjs = (function () {
       status: Users[userId].status
     };
 
-    return _user;
+    if (!property) {
+      return _user;
+    } else if (property && _user[property]) {
+      return _user[property];
+    }
   };
 
   Mpin.prototype.addToUser = function (userId, userProps) {
@@ -179,12 +414,55 @@ var mpinjs = (function () {
     for (var uKey in userProps) {
       Users[userId][uKey] = userProps[uKey];
     }
+
+    this.setData(userId, userProps);
   };
 
   Mpin.prototype.restore = function () {
     Users = {};
   };
 
+  Mpin.prototype.setData = function (userId, upData) {
+    var mpinData;
+    mpinData = JSON.parse(localStorage.getItem(this.storageKey));
+
+    if (!mpinData) {
+      mpinData = {
+        defaultIdentity: "",
+        version: "0.3",
+        accounts: {}
+      };
+    }
+
+    //update Default Identity
+    if (upData.mpinId) {
+      mpinData.defaultIdentity = upData.mpinId;
+      mpinData.accounts[upData.mpinId] = {};
+    }
+
+    if (upData.regOTT) {
+      mpinData.accounts[upData.mpinId].regOTT = upData.regOTT;
+    }
+
+    if (upData.timePermitHex) {
+      var mpinId = Users[userId].mpinId;
+      mpinData.accounts[mpinId].MPinPermit = upData.timePermitHex;
+    }
+
+    if (upData.tokenHex) {
+      var mpinId = Users[userId].mpinId;
+      mpinData.accounts[mpinId].token = upData.tokenHex;
+    }
+
+    localStorage.setItem(this.storageKey, JSON.stringify(mpinData));
+  };
+
+  Mpin.prototype.getData = function () {
+    var mpinData;
+    mpinData = JSON.parse(localStorage.getItem(this.storageKey));
+    return mpinData;
+  };
+
 //{url: url, type: "get post put", data: data}
   Mpin.prototype.request = function (options, cb) {
     var _request = new XMLHttpRequest(), _url, _type, _data;
@@ -201,6 +479,7 @@ var mpinjs = (function () {
     };
 
     _request.open(_type, _url, true);
+    _request.setRequestHeader("Content-Type", "application/json");
     _request.send(JSON.stringify(_data || ""));
   };
 

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f27fba99/test/coverage.html
----------------------------------------------------------------------
diff --git a/test/coverage.html b/test/coverage.html
deleted file mode 100644
index 8d6f974..0000000
--- a/test/coverage.html
+++ /dev/null
@@ -1,360 +0,0 @@
-err  { error: 3, message: 'Missing registerURL' } null
-<!DOCTYPE html><html><head><title>Coverage</title><meta charset="utf-8"><script>
-
-headings = [];
-
-onload = function(){
-  headings = document.querySelectorAll('h2');
-};
-
-onscroll = function(e){
-  var heading = find(window.scrollY);
-  if (!heading) return;
-  var links = document.querySelectorAll('#menu a')
-    , link;
-
-  for (var i = 0, len = links.length; i < len; ++i) {
-    link = links[i];
-    link.className = link.getAttribute('href') == '#' + heading.id
-      ? 'active'
-      : '';
-  }
-};
-
-function find(y) {
-  var i = headings.length
-    , heading;
-
-  while (i--) {
-    heading = headings[i];
-    if (y >= heading.offsetTop) {
-      return heading;
-    }
-  }
-}
-</script>
-<style>
-
-body {
-  font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
-  margin: 0;
-  color: #2C2C2C;
-  border-top: 2px solid #ddd;
-}
-
-#coverage {
-  padding: 60px 400px 60px 60px;
-}
-
-h1 a {
-  color: inherit;
-  font-weight: inherit;
-}
-
-h1 a:hover {
-  text-decoration: none;
-}
-
-.onload h1 {
-  opacity: 1;
-}
-
-h2 {
-  width: 80%;
-  margin-top: 80px;
-  margin-bottom: 0;
-  font-weight: 100;
-  letter-spacing: 1px;
-  border-bottom: 1px solid #eee;
-}
-
-a {
-  color: #8A6343;
-  font-weight: bold;
-  text-decoration: none;
-}
-
-a:hover {
-  text-decoration: underline;
-}
-
-ul {
-  margin-top: 20px;
-  padding: 0 15px;
-  width: 100%;
-}
-
-ul li {
-  float: left;
-  width: 40%;
-  margin-top: 5px;
-  margin-right: 60px;
-  list-style: none;
-  border-bottom: 1px solid #eee;
-  padding: 5px 0;
-  font-size: 12px;
-}
-
-ul::after {
-  content: '.';
-  height: 0;
-  display: block;
-  visibility: hidden;
-  clear: both;
-}
-
-code {
-  font: 12px monaco, monospace;
-}
-
-pre {
-  margin: 30px;
-  padding: 30px;
-  border: 1px solid #eee;
-  border-bottom-color: #ddd;
-  -webkit-border-radius: 2px;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
-  -webkit-box-shadow: inset 0 0 10px #eee;
-  -moz-box-shadow: inset 0 0 10px #eee;
-  box-shadow: inset 0 0 10px #eee;
-  overflow-x: auto;
-}
-
-img {
-  margin: 30px;
-  padding: 1px;
-  -webkit-border-radius: 3px;
-  -moz-border-radius: 3px;
-  border-radius: 3px;
-  -webkit-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
-  -moz-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
-  box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
-  max-width: 100%;
-}
-
-footer {
-  background: #eee;
-  width: 100%;
-  padding: 50px 0;
-  text-align: right;
-  border-top: 1px solid #ddd;
-}
-
-footer span {
-  display: block;
-  margin-right: 30px;
-  color: #888;
-  font-size: 12px;
-}
-
-#menu {
-  position: fixed;
-  font-size: 12px;
-  overflow-y: auto;
-  top: 0;
-  right: 0;
-  margin: 0;
-  height: 100%;
-  padding: 15px 0;
-  text-align: right;
-  border-left: 1px solid #eee;
-  max-width: 400px;
-  overflow: auto;
-  white-space: nowrap;
-  
-  -moz-box-shadow: 0 0 2px #888
-     , inset 5px 0 20px rgba(0,0,0,.5)
-     , inset 5px 0 3px rgba(0,0,0,.3);
-  -webkit-box-shadow: 0 0 2px #888
-     , inset 5px 0 20px rgba(0,0,0,.5)
-     , inset 5px 0 3px rgba(0,0,0,.3);
-  box-shadow: 0 0 2px #888
-     , inset 5px 0 20px rgba(0,0,0,.5)
-     , inset 5px 0 3px rgba(0,0,0,.3);
-  -webkit-font-smoothing: antialiased;
-  background: url("data:image/png;base64,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");
-}
-
-#menu::after {
-  display: block;
-  content: '';
-  padding-top: 80px;
-}
-
-#logo {
-  position: fixed;
-  bottom: 10px;
-  right: 10px;
-  background: rgba(255,255,255,.1);
-  font-size: 11px;
-  display: block;
-  width: 20px;
-  height: 20px;
-  line-height: 20px;
-  text-align: center;
-  -webkit-border-radius: 20px;
-  -moz-border-radius: 20px;
-  border-radius: 20px;
-  -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
-  -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
-  box-shadow: 0 0 3px rgba(0,0,0,.2);
-  color: inherit;
-}
-
-#menu li a {
-  display: block;
-  color: white;
-  padding: 0 35px 0 25px;
-  -webkit-transition: background 300ms;
-  -moz-transition: background 300ms;
-}
-
-#menu li {
-  position: relative;
-  list-style: none;
-}
-
-#menu a:hover,
-#menu a.active {
-  text-decoration: none;
-  background: rgba(255,255,255,.1);
-}
-
-#menu li:hover .cov {
-  opacity: 1;
-}
-
-#menu li .dirname {
-  opacity: .60;
-  padding-right: 2px;
-}
-
-#menu li .basename {
-  opacity: 1;
-}
-
-#menu .cov {
-  background: rgba(0,0,0,.4);
-  position: absolute;
-  top: 0;
-  right: 8px;
-  font-size: 9px;
-  opacity: .6;
-  text-align: left;
-  width: 17px;
-  -webkit-border-radius: 10px;
-  -moz-border-radius: 10px;
-  border-radius: 10px;
-  padding: 2px 3px;
-  text-align: center;
-}
-
-#stats:nth-child(2n) {
-  display: inline-block;
-  margin-top: 15px;
-  border: 1px solid #eee;
-  padding: 10px;
-  -webkit-box-shadow: inset 0 0 2px #eee;
-  -moz-box-shadow: inset 0 0 2px #eee;
-  box-shadow: inset 0 0 2px #eee;
-  -webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  border-radius: 5px;
-}
-
-#stats div {
-  float: left;
-  padding: 0 5px;
-}
-
-#stats::after {
-  display: block;
-  content: '';
-  clear: both;
-}
-
-#stats .sloc::after {
-  content: ' SLOC';
-  color: #b6b6b6;
-}
-
-#stats .percentage::after {
-  content: ' coverage';
-  color: #b6b6b6;
-}
-
-#stats .hits,
-#stats .misses {
-  display: none;
-}
-
-.high {
-  color: #00d4b4;
-}
-.medium {
-  color: #e87d0d;
-}
-.low {
-  color: #d4081a;
-}
-.terrible {
-  color: #d4081a;
-  font-weight: bold;
-}
-
-table {
-  width: 80%;
-  margin-top: 10px;
-  border-collapse: collapse;
-  border: 1px solid #cbcbcb;
-  color: #363636;
-  -webkit-border-radius: 3px;
-  -moz-border-radius: 3px;
-  border-radius: 3px;
-}
-
-table thead {
-  display: none;
-}
-
-table td.line,
-table td.hits {
-  width: 20px;
-  background: #eaeaea;
-  text-align: center;
-  font-size: 11px;
-  padding: 0 10px;
-  color: #949494;
-}
-
-table td.hits {
-  width: 10px;
-  padding: 2px 5px;
-  color: rgba(0,0,0,.2);
-  background: #f0f0f0;
-}
-
-tr.miss td.line,
-tr.miss td.hits {
-  background: #e6c3c7;
-}
-
-tr.miss td {
-  background: #f8d5d8;
-}
-
-td.source {
-  padding-left: 15px;
-  line-height: 15px;
-  white-space: pre;
-  font: 12px monaco, monospace;
-}
-
-code .comment { color: #ddd }
-code .init { color: #2F6FAD }
-code .string { color: #5890AD }
-code .keyword { color: #8A6343 }
-code .number { color: #2F6FAD }
-</style>
-</head><body><div id="coverage"><h1 id="overview">Coverage</h1><div id="menu"><li><a href="#overview">overview</a></li><li><span class="cov medium">52</span><a href="#/var/www/mpinjs/lib/mpin.js"><span class="dirname">/var/www/mpinjs/lib/</span><span class="basename">mpin.js</span></a></li><a id="logo" href="http://mochajs.org/">m</a></div><div id="stats" class="medium"><div class="percentage">52%</div><div class="sloc">109</div><div class="hits">57</div><div class="misses">52</div></div><div id="files"><div class="file"><h2 id="/var/www/mpinjs/lib/mpin.js">/var/www/mpinjs/lib/mpin.js</h2><div id="stats" class="medium"><div class="percentage">52%</div><div class="sloc">109</div><div class="hits">57</div><div class="misses">52</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr class="hit"><td class="line">1</td><td class="hits">1</td><td class="source">var mpinjs = (function () {</td></tr><tr class="hit"><td class="line">2</td><t
 d class="hits">1</td><td class="source">  var Mpin, Users = {}, Errors = [];</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">4</td><td class="hits">1</td><td class="source">  Errors[1] = &quot;Invalid userId.&quot;;</td></tr><tr class="hit"><td class="line">5</td><td class="hits">1</td><td class="source">  Errors[2] = &quot;UserId does not exist.&quot;;</td></tr><tr class="hit"><td class="line">6</td><td class="hits">1</td><td class="source">  Errors[3] = &quot;Missing parameter.&quot;;</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">8</td><td class="hits">1</td><td class="source">  Errors[4] = &quot;UserId are not verified.&quot;;</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">10</td><td class="hits">1</td><td class="source">  Mpin = function (options) {</td></tr><t
 r class="hit"><td class="line">11</td><td class="hits">5</td><td class="source">    if (!options || !options.settingsUrl) {</td></tr><tr class="hit"><td class="line">12</td><td class="hits">1</td><td class="source">      return new Error(&quot;Missing settings URL&quot;);</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">15</td><td class="hits">4</td><td class="source">    this.opts = options;</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">  Mpin.prototype.debug = true;</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">20</td><td class="hits">1</td><td cla
 ss="source">  Mpin.prototype.init = function (cb) {</td></tr><tr class="hit"><td class="line">21</td><td class="hits">5</td><td class="source">    var self = this;</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">23</td><td class="hits">5</td><td class="source">    this.request({url: this.opts.settingsUrl}, function (err, data) {</td></tr><tr class="hit"><td class="line">24</td><td class="hits">3</td><td class="source">      if (err &amp;&amp; cb) {</td></tr><tr class="hit"><td class="line">25</td><td class="hits">1</td><td class="source">        return cb(err, null);</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">28</td><td class="hits">2</td><td class="source">      self.ready = true;</td></tr><tr class="hit"><td class="line">29</td><td class="hits">2
 </td><td class="source">      self.opts = data;</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">31</td><td class="hits">2</td><td class="source">      cb &amp;&amp; cb(null, data);</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">35</td><td class="hits">1</td><td class="source">  Mpin.prototype.makeNewUser = function (userId, deviceId) {</td></tr><tr class="hit"><td class="line">36</td><td class="hits">4</td><td class="source">    if (!userId) {</td></tr><tr class="hit"><td class="line">37</td><td class="hits">1</td><td class="source">      return {error: 1};</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">3
 9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">40</td><td class="hits">3</td><td class="source">    Users[userId] = {</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">      userId: userId,</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">      deviceId: deviceId || &quot;&quot;,</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">      status: &quot;STARTED&quot;</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">46</td><td class="hits">3</td><td class="source">    return this;</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">49</td><td class="hits">1
 </td><td class="source">  Mpin.prototype.startRegistration = function (userId, cb) {</td></tr><tr class="hit"><td class="line">50</td><td class="hits">4</td><td class="source">    var _reqData = {}, self = this;</td></tr><tr class="hit"><td class="line">51</td><td class="hits">4</td><td class="source">    if (!userId || typeof userId != &quot;string&quot;) {</td></tr><tr class="hit"><td class="line">52</td><td class="hits">1</td><td class="source">      return cb ? cb({error: 1}, null) : {error: 1};</td></tr><tr class="hit"><td class="line">53</td><td class="hits">3</td><td class="source">    } else if (!this.checkUser(userId)) {</td></tr><tr class="hit"><td class="line">54</td><td class="hits">1</td><td class="source">      return cb({error: 2}, null);</td></tr><tr class="hit"><td class="line">55</td><td class="hits">2</td><td class="source">    } else if (!this.opts.registerURL) {</td></tr><tr class="hit"><td class="line">56</td><td class="hits">1</td><td class="source">      retu
 rn cb({error: 3, message: &quot;Missing registerURL&quot;}, null);</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">59</td><td class="hits">1</td><td class="source">    _reqData.url = this.opts.registerURL;</td></tr><tr class="hit"><td class="line">60</td><td class="hits">1</td><td class="source">    _reqData.type = &quot;PUT&quot;;</td></tr><tr class="hit"><td class="line">61</td><td class="hits">1</td><td class="source">    _reqData.data = {</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">      userId: userId,</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">      mobile: 0</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td clas
 s="line">66</td><td class="hits">1</td><td class="source">    this.request(_reqData, function (err, data) {</td></tr><tr class="hit"><td class="line">67</td><td class="hits">1</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">68</td><td class="hits">0</td><td class="source">        return cb(err, null);</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">71</td><td class="hits">1</td><td class="source">      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId});</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">      //force activate</td></tr><tr class="hit"><td class="line">74</td><td class="hits">1</td><td class="source">      if (data.active) {</td></tr><tr class="miss"><td c
 lass="line">75</td><td class="hits">0</td><td class="source">        self.addToUser(userId, {status: &quot;ACTIVATED&quot;});</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">78</td><td class="hits">1</td><td class="source">      cb &amp;&amp; cb(null, true);</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">  //request cs1 + cs2</td></tr><tr class="hit"><td class="line">84</td><td class="hits">1</td><td class="source">  Mpin.prototype.confirmRegistration = function (userId, c
 b) {</td></tr><tr class="miss"><td class="line">85</td><td class="hits">0</td><td class="source">    var _cs1Url = &quot;&quot;, self = this;</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">87</td><td class="hits">0</td><td class="source">    _cs1Url = this.opts.signatureURL + &quot;/&quot;;</td></tr><tr class="miss"><td class="line">88</td><td class="hits">0</td><td class="source">    _cs1Url += Users[userId].mpinId; //identity</td></tr><tr class="miss"><td class="line">89</td><td class="hits">0</td><td class="source">    _cs1Url += &quot;?regOTT=&quot; + Users[userId].regOTT;</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">    //req cs1</td></tr><tr class="miss"><td class="line">92</td><td class="hits">0</td><td class="source">    this.request({url: _cs1Url}, function (err, cs1Data) {</td></tr><tr c
 lass="miss"><td class="line">93</td><td class="hits">0</td><td class="source">      var _cs2Url = &quot;&quot;;</td></tr><tr class="miss"><td class="line">94</td><td class="hits">0</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">95</td><td class="hits">0</td><td class="source">        if (err.status == 401) {</td></tr><tr class="miss"><td class="line">96</td><td class="hits">0</td><td class="source">          return cb({error: 2, message: &quot;Identity not activate.&quot;}, null);</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">100</td><td class="hits">0</td><td class="source">      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, status: &quot;ACTIVATED&quot;});</td></t
 r><tr class="miss"><td class="line">101</td><td class="hits">0</td><td class="source">      _cs2Url = self.opts.certivoxURL + &quot;clientSecret?&quot; + cs1Data.params;</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">      //req cs2</td></tr><tr class="miss"><td class="line">104</td><td class="hits">0</td><td class="source">      self.request({url: _cs2Url}, function (err, cs2Data) {</td></tr><tr class="miss"><td class="line">105</td><td class="hits">0</td><td class="source">        var csHex;</td></tr><tr class="miss"><td class="line">106</td><td class="hits">0</td><td class="source">        self.addToUser(userId, {cs2: cs2Data.clientSecret});</td></tr><tr class="miss"><td class="line">107</td><td class="hits">0</td><td class="source">        csHex = MPINAuth.addShares(cs2Data.clientSecret, cs1Data.clientSecretShare);</td></tr><tr><td class="line">108</td><td class="hits
 "></td><td class="source"> </td></tr><tr class="miss"><td class="line">109</td><td class="hits">0</td><td class="source">        self.addToUser(userId, {csHex: csHex});</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">111</td><td class="hits">0</td><td class="source">        cb(null, true);</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">118</td><td class="hits">1</td><td class="source">  Mpin.prototype.finishRegistration
  = function (userId, pin) {</td></tr><tr class="miss"><td class="line">119</td><td class="hits">0</td><td class="source">    var _user, tokenHex;</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">121</td><td class="hits">0</td><td class="source">    _user = this.getUser(userId);</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">123</td><td class="hits">0</td><td class="source">    if (_user.status !== &quot;ACTIVATED&quot;) {</td></tr><tr class="miss"><td class="line">124</td><td class="hits">0</td><td class="source">      return {error: 3};</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">127</td><td class="hits">0</td><td class="source">    tokenHex = MPINAuth.calculateMPinToken
 (Users[userId].mpinId, pin, Users[userId].csHex);</td></tr><tr class="miss"><td class="line">128</td><td class="hits">0</td><td class="source">    this.addToUser(userId, {tokenHex: tokenHex, status: &quot;REGISTER&quot;});</td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">130</td><td class="hits">0</td><td class="source">    return tokenHex;</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">  //Put user / mpinId</td></tr><tr class="hit"><td class="line">134</td><td class="hits">1</td><td class="source">  Mpin.prototype.restartRegistration = function (userId, deviceId, cb) {</td></tr><tr class="miss"><td class="line">135</td><td class="hits">0</td><td class="source">    var err = null, data = {};</td></tr><tr class="miss
 "><td class="line">136</td><td class="hits">0</td><td class="source">    cb(err, data);</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">140</td><td class="hits">1</td><td class="source">  Mpin.prototype.listUsers = function () {</td></tr><tr class="miss"><td class="line">141</td><td class="hits">0</td><td class="source">    var listUsers = {};</td></tr><tr class="miss"><td class="line">142</td><td class="hits">0</td><td class="source">    for (var uKey in Users) {</td></tr><tr class="miss"><td class="line">143</td><td class="hits">0</td><td class="source">      listUsers[uKey] = {</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source">        userId: Users[uKey].userId,</td></tr><tr><td class="line">145</td><td class="hits"
 ></td><td class="source">        deviceId: Users[uKey].deviceId,</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source">        status: Users[uKey].status</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">149</td><td class="hits">0</td><td class="source">    return listUsers;</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">152</td><td class="hits">1</td><td class="source">  Mpin.prototype.checkUser = function (userId) {</td></tr><tr class="hit"><td class="line">153</td><td class="hits">5</td><td class="source">    return (Users[userId]) ? true : false;</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">  };</td><
 /tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">157</td><td class="hits">1</td><td class="source">  Mpin.prototype.getUser = function (userId) {</td></tr><tr class="miss"><td class="line">158</td><td class="hits">0</td><td class="source">    var _user = {};</td></tr><tr class="miss"><td class="line">159</td><td class="hits">0</td><td class="source">    if (!userId) {</td></tr><tr class="miss"><td class="line">160</td><td class="hits">0</td><td class="source">      return {error: 4};</td></tr><tr class="miss"><td class="line">161</td><td class="hits">0</td><td class="source">    } else if (!this.checkUser(userId)) {</td></tr><tr class="miss"><td class="line">162</td><td class="hits">0</td><td class="source">      return {error: 2};</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">    }</td></tr><tr><td cla
 ss="line">164</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">165</td><td class="hits">0</td><td class="source">    _user = {</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">      userId: Users[userId].userId,</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">      deviceId: Users[userId].deviceId,</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">      status: Users[userId].status</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">171</td><td class="hits">0</td><td class="source">    return _user;</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="li
 ne">174</td><td class="hits">1</td><td class="source">  Mpin.prototype.addToUser = function (userId, userProps) {</td></tr><tr class="hit"><td class="line">175</td><td class="hits">1</td><td class="source">    if (!this.checkUser(userId)) {</td></tr><tr class="miss"><td class="line">176</td><td class="hits">0</td><td class="source">      return false;</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">179</td><td class="hits">1</td><td class="source">    for (var uKey in userProps) {</td></tr><tr class="hit"><td class="line">180</td><td class="hits">2</td><td class="source">      Users[userId][uKey] = userProps[uKey];</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">183</td><td cla
 ss="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">184</td><td class="hits">1</td><td class="source">  Mpin.prototype.restore = function () {</td></tr><tr class="hit"><td class="line">185</td><td class="hits">1</td><td class="source">    Users = {};</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">//{url: url, type: &quot;get post put&quot;, data: data}</td></tr><tr class="hit"><td class="line">189</td><td class="hits">1</td><td class="source">  Mpin.prototype.request = function (options, cb) {</td></tr><tr class="miss"><td class="line">190</td><td class="hits">0</td><td class="source">    var _request = new XMLHttpRequest(), _url, _type, _data;</td></tr><tr class="miss"><td class="line">191</td><td class="hits">0</td><td class="source">    _url = options.url || &q
 uot;&quot;;</td></tr><tr class="miss"><td class="line">192</td><td class="hits">0</td><td class="source">    _type = options.type || &quot;GET&quot;;</td></tr><tr class="miss"><td class="line">193</td><td class="hits">0</td><td class="source">    _data = options.data || &quot;&quot;;</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">195</td><td class="hits">0</td><td class="source">    _request.onreadystatechange = function () {</td></tr><tr class="miss"><td class="line">196</td><td class="hits">0</td><td class="source">      if (_request.readyState === 4 &amp;&amp; _request.status === 200) {</td></tr><tr class="miss"><td class="line">197</td><td class="hits">0</td><td class="source">        cb(null, JSON.parse(_request.responseText));</td></tr><tr class="miss"><td class="line">198</td><td class="hits">0</td><td class="source">      } else if (_request.readyState === 4) {</td></tr><tr class="miss"><td class="l
 ine">199</td><td class="hits">0</td><td class="source">        cb({status: _request.status}, null);</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">203</td><td class="hits">0</td><td class="source">    _request.open(_type, _url, true);</td></tr><tr class="miss"><td class="line">204</td><td class="hits">0</td><td class="source">    _request.send(JSON.stringify(_data || &quot;&quot;));</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">207</td><td class="hits">1</td><td class="source">  return Mpin;</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">})();</td>
 </tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source">//module.exports = mpinjs;</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">//http://www.matteoagosti.com/blog/2013/02/24/writing-javascript-modules-for-both-browser-and-node/</td></tr><tr class="hit"><td class="line">213</td><td class="hits">1</td><td class="source">if (typeof module !== 'undefined' &amp;&amp; typeof module.exports !== 'undefined')</td></tr><tr class="hit"><td class="line">214</td><td class="hits">1</td><td class="source">  module.exports = mpinjs;</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">else</td></tr><tr class="miss"><td class="line">216</td><td class="hits">0</td><td class="source">  window.mpinjs = mpinjs;</td></tr></tbody></table></div></div></div></body></html
 >
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f27fba99/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
index 55ea634..818368f 100644
--- a/test/index.js
+++ b/test/index.js
@@ -1,11 +1,18 @@
 //if browser
 if (typeof require !== 'undefined') {
   var expect = require('chai').expect;
-  var mpinjs = require('../index');
   var sinon = require('sinon');
   var sinonChai = require('sinon-chai');
+  var mpinjs = require('../index');
+//  var mpinjs = require('../dist/mpinjs');
 }
 
+var Errors = [];
+Errors[0] = "MISSING_USERID";
+Errors[1] = "INVALID_USERID";
+Errors[2] = "MISSING_PARAMETERS";
+Errors[3] = "IDENTITY_NOT_VERIFIED";
+
 describe('# Constructor initialization without settingsUrl.', function () {
   it('should throw Error', function () {
     var mpin = new mpinjs();
@@ -83,9 +90,9 @@ describe('# makeNewUser checks.', function () {
     mpin.restore();
   });
 
-  it('should makeNewUser return error when call without userId', function () {
+  it('should makeNewUser return error type ' + Errors[0] + ' when call without userId', function () {
     var user = mpin.makeNewUser();
-    expect(user).to.deep.equal({error: 1});
+    expect(user).to.deep.equal({code: 0, type: Errors[0]});
   });
 
   it('should store user into internal list', function () {
@@ -108,22 +115,27 @@ describe('# startRegistration.', function () {
     };
   });
 
-  it('should return error 1, call without userId', function (done) {
+  after(function () {
+    mpin.restore();
+  });
+
+
+  it('should return error type ' + Errors[0] + ', call without userId', function (done) {
     mpin.startRegistration(null, function (err, data) {
-      expect(err).to.deep.equal({error: 1});
+      expect(err).to.deep.equal({code: 0, type: Errors[0]});
       done();
     });
   });
 
-  it('should return error 2 if skip makeNewUser method.', function (done) {
+  it('should return error type ' + Errors[1] + ' if skip makeNewUser method.', function (done) {
     var userId = "test@user.id";
     mpin.startRegistration(userId, function (err, data) {
-      expect(err).to.deep.equal({error: 2});
+      expect(err).to.deep.equal({code: 1, type: Errors[1]});
       done();
     });
   });
 
-  it('should return error 3 if skip init method.', function (done) {
+  it('should return error type ' + Errors[2] + ' if skip init method.', function (done) {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     mpin.startRegistration(userId, function (err, data) {
@@ -134,7 +146,7 @@ describe('# startRegistration.', function () {
 
   it('should return OK.', function (done) {
     var userId = "test@user.id";
-    
+
     //mock for init method
     sinon.stub(mpin, 'request').yields(null, this.fakeRes);
 
@@ -150,4 +162,124 @@ describe('# startRegistration.', function () {
 
 
 
+});
+
+
+describe('# confirmRegistration.', function () {
+  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+
+  before(function () {
+    mpin = new mpinjs({settingsUrl: settingsUrl});
+
+    this.fakeRes = {
+      requestOTP: false,
+      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
+      registerURL: "http://192.168.10.63:8011/rps/user",
+      signatureURL: "http://192.168.10.63:8011/rps/signature",
+      certivoxURL: "https://community-api.certivox.net/v3/"
+    };
+
+    this.fakeCs1 = {
+      clientSecretShare: "0421e379eb45e56ce699f0a7a83b683e84944b63fcc93a2834a4769ea40a28dc3f2064cd9d64846304999e00008b0838e246d3ea06d0013f1080c1027d54630ca9",
+      params: "mobile=0&expires=2015-12-03T12%3A47%3A23Z&app_id=e340a9f240e011e5b23b06df5546c0ed&hash_mpin_id=07a9af5af89d66b969be31d3d4e29c2a0a5ad4d3e30432eed9b3915dbf52230a&signature=33e8e987b07a2d9c9f3d98f68268870ef104cd0e0b9e02ba2c55e8bbf5190913&hash_user_id="
+    };
+    this.fakeCs2 = {
+      clientSecret: "0409ba1a247561ab16c35df3ad0ca9846db9968fa28757005335dc2ca35188b4f51521ac97d45bbdb3a8d1c0fdfe79ab29031054534df8b7cbac12e67e4e99d685"
+    };
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+
+  it('should return error type ' + Errors[0] + ' call without userId', function (done) {
+    mpin.confirmRegistration(null, function (err, data) {
+      expect(err).to.deep.equal({code: 0, type: Errors[0]});
+      done();
+    });
+  });
+
+  it('should return error type ' + Errors[1] + '  if skip makeNewUser method.', function (done) {
+    var userId = "test@user.id";
+    mpin.confirmRegistration(userId, function (err, data) {
+      expect(err).to.have.deep.property('type', Errors[1]);
+      done();
+    });
+  });
+
+  it('should return error type ' + Errors[2] + ' if skip init method.', function (done) {
+    var userId = "test@user.id";
+    mpin.makeNewUser(userId);
+    mpin.confirmRegistration(userId, function (err, data) {
+      expect(err).to.have.deep.property('type', Errors[2]);
+      done();
+    });
+  });
+  /*
+   //start REGISTRATION >>>
+   it('should return error 4 if skip init method.', function (done) {
+   var userId = "test@user.id";
+   
+   sinon.stub(mpin, 'request').yields(null, this.fakeRes);
+   mpin.init(function (err, data) {
+   mpin.makeNewUser(userId);
+   //      sinon.stub(mpin, 'request').yields({status: 401}, null);
+   mpin.confirmRegistration(userId, function (err, data) {
+   console.log("err", err);
+   expect(err).to.have.deep.property('error', 4);
+   done();
+   });
+   });
+   });
+   */
+
+  it('should return error type ' + Errors[3] + ' identity not verify.', function (done) {
+    var userId = "test@user.id", stub;
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, this.fakeRes);
+    stub.onCall(1).yields(null, {});
+    stub.onCall(2).yields({status: 401}, null);
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data3) {
+          expect(err2).to.have.deep.property('type', Errors[3]);
+          done();
+        });
+      });
+    });
+  });
+
+  //start REGISTRATION >>> OK
+  it('should return OK', function (done) {
+    var userId = "test@user.id", stub;
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, this.fakeRes);
+    stub.onCall(1).yields(null, {});//mpinId
+    stub.onCall(2).yields(null, this.fakeCs1);//cs1
+    stub.onCall(3).yields(null, this.fakeCs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data3) {
+          expect(data3).to.exist;
+          done();
+        });
+      });
+    });
+  });
+  
+  
+
+});
+
+
+describe('# confirmRegistration.', function () { 
+  
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/f27fba99/test/mocha.opts
----------------------------------------------------------------------
diff --git a/test/mocha.opts b/test/mocha.opts
index 7179157..47d63c7 100644
--- a/test/mocha.opts
+++ b/test/mocha.opts
@@ -1,2 +1,2 @@
-\ufeff--recursive
+--recursive
 --timeout 5000
\ No newline at end of file


[12/37] incubator-milagro-mfa-js-lib git commit: Adding missing functionality and fixing bugs

Posted by sa...@apache.org.
Adding missing functionality and fixing bugs


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/4231d489
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/4231d489
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/4231d489

Branch: refs/heads/add-documentation
Commit: 4231d4890fe028eaf013a8df98a3ff7a205a8229
Parents: 3495d12
Author: Simeon Aladjem <si...@miracl.com>
Authored: Wed Dec 23 15:53:13 2015 +0200
Committer: Simeon Aladjem <si...@miracl.com>
Committed: Wed Dec 23 15:53:13 2015 +0200

----------------------------------------------------------------------
 lib/mpin.js   | 190 ++++++++++++++++++++++++++++++-----------------------
 test/index.js |   8 +--
 2 files changed, 111 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4231d489/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 86a110e..865d057 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -18,23 +18,23 @@
  */
 
 var mpinjs = (function () {
-  var Mpin, Users = {}, Error = {}, State = {};
-
-  Error.missingUserId = {code: 0, type: "MISSING_USERID"};
-  Error.invalidUserId = {code: 1, type: "INVALID_USERID"};
-  Error.missingParams = {code: 2, type: "MISSING_PARAMETERS"};
-  Error.identityNotVerified = {code: 3, type: "IDENTITY_NOT_VERIFIED"};
-  Error.identityMissing = {code: 4, type: "IDENTITY_MISSING"};
-  Error.wrongPin = {code: 5, type: "WRONG_PIN"};
-  Error.wrongFlow = {code: 6, type: "WRONG_FLOW"};
-  Error.userRevoked = {code: 7, type: "USER_REVOKED"};
-  Error.timeoutFinish = {code: 8, type: "TIMEOUT_FINISH"};
-
-  State.invalid = "INVALID";
-  State.start = "STARTED";
-  State.active = "ACTIVATED";
-  State.register = "REGISTERED";
-  State.block = "BLOCKED";
+  var Mpin, Users = {}, Errors = {}, States = {};
+
+  Errors.missingUserId = {code: 0, type: "MISSING_USERID"};
+  Errors.invalidUserId = {code: 1, type: "INVALID_USERID"};
+  Errors.missingParams = {code: 2, type: "MISSING_PARAMETERS"};
+  Errors.identityNotVerified = {code: 3, type: "IDENTITY_NOT_VERIFIED"};
+  Errors.identityMissing = {code: 4, type: "IDENTITY_MISSING"};
+  Errors.wrongPin = {code: 5, type: "WRONG_PIN"};
+  Errors.wrongFlow = {code: 6, type: "WRONG_FLOW"};
+  Errors.userRevoked = {code: 7, type: "USER_REVOKED"};
+  Errors.timeoutFinish = {code: 8, type: "TIMEOUT_FINISH"};
+
+  States.invalid = "INVALID";
+  States.start = "STARTED";
+  States.active = "ACTIVATED";
+  States.register = "REGISTERED";
+  States.block = "BLOCKED";
 
   Mpin = function (options) {
     if (!options || !options.server) {
@@ -42,6 +42,7 @@ var mpinjs = (function () {
     }
 
     this.opts = options;
+	this.settings = {};
 
     this.recover();
   };
@@ -65,18 +66,18 @@ var mpinjs = (function () {
       }
 
       self.ready = true;
-      self.opts = data;
+      self.settings = data;
 
-      cb && cb(null, data);
+      cb && cb(null, true);
     });
   };
 
   Mpin.prototype.makeNewUser = function (userId, deviceId) {
     if (!userId) {
-      return Error.missingUserId;
+      return Errors.missingUserId;
     }
 
-    this.addToUser(userId, {userId: userId, deviceId: deviceId, state: State.invalid});
+    this.addToUser(userId, {userId: userId, deviceId: deviceId, state: States.invalid});
 
     return this;
   };
@@ -84,11 +85,11 @@ var mpinjs = (function () {
   Mpin.prototype.startRegistration = function (userId, cb) {
     var _reqData = {}, self = this;
     if (!userId) {
-      return cb ? cb(Error.missingUserId, null) : {error: 1};
+      return cb ? cb(Errors.missingUserId, null) : {error: 1};
     } else if (!this.checkUser(userId)) {
-      return cb(Error.invalidUserId, null);
-    } else if (!this.opts.registerURL) {
-      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing registerURL"}, null);
+      return cb(Errors.invalidUserId, null);
+    } else if (!this.settings.registerURL) {
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
     }
 
     _reqData.url = this.generateUrl("register");
@@ -103,11 +104,11 @@ var mpinjs = (function () {
         return cb(err, null);
       }
 
-      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId, state: State.start});
+      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId, state: States.start});
 
       //force activate
       if (data.active) {
-        self.addToUser(userId, {state: State.active});
+        self.addToUser(userId, {state: States.active});
       }
 
       cb && cb(null, true);
@@ -118,17 +119,17 @@ var mpinjs = (function () {
   Mpin.prototype.confirmRegistration = function (userId, cb) {
     var _cs1Url = "", self = this, _userState;
     if (!userId) {
-      return cb ? cb(Error.missingUserId, null) : Error.missingUserId;
+      return cb ? cb(Errors.missingUserId, null) : Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return cb(Error.invalidUserId, null);
-    } else if (!this.opts.signatureURL) {
-      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing signatureURL option."}, null);
+      return cb(Errors.invalidUserId, null);
+    } else if (!this.settings.signatureURL) {
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing signatureURL option."}, null);
     }
 
     //started || activated
     _userState = this.getUser(userId, "state");
-    if (_userState !== State.start && _userState !== State.active) {
-      return cb(Error.wrongFlow, null);
+    if (_userState !== States.start && _userState !== States.active) {
+      return cb(Errors.wrongFlow, null);
     }
 
     //already set.
@@ -142,13 +143,13 @@ var mpinjs = (function () {
       var _cs2Url = "";
       if (err) {
         if (err.status == 401) {
-          return cb(Error.identityNotVerified, null);
+          return cb(Errors.identityNotVerified, null);
         } else if (err.status == 400) {
-          return cb(Error.wrongFlow, null);
+          return cb(Errors.wrongFlow, null);
         }
       }
 
-      _cs2Url = self.opts.certivoxURL + "clientSecret?" + cs1Data.params;
+      _cs2Url = self.settings.certivoxURL + "clientSecret?" + cs1Data.params;
 
       //req cs2
       self.request({url: _cs2Url}, function (err, cs2Data) {
@@ -156,7 +157,7 @@ var mpinjs = (function () {
 
         csHex = MPINAuth.addShares(cs2Data.clientSecret, cs1Data.clientSecretShare);
 
-        self.addToUser(userId, {csHex: csHex, state: State.active});
+        self.addToUser(userId, {csHex: csHex, state: States.active});
 
         cb(null, true);
       });
@@ -169,19 +170,19 @@ var mpinjs = (function () {
     var _user, token;
 
     if (!userId) {
-      return Error.missingUserId;
+      return Errors.missingUserId;
     }
 
     _user = this.getUser(userId);
 
-    if (_user.state !== State.active) {
-      return Error.wrongFlow;
+    if (_user.state !== States.active || !Users[userId].csHex) {
+      return Errors.wrongFlow;
     }
 
     token = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
     delete Users[userId].csHex;
 
-    this.addToUser(userId, {token: token, state: State.register});
+    this.addToUser(userId, {token: token, state: States.register});
 
     return true;
   };
@@ -198,31 +199,35 @@ var mpinjs = (function () {
     var _tp1Url, self = this, _userState;
 
     if (!userId) {
-      return cb ? cb(Error.missingUserId, null) : Error.missingUserId;
+      return cb ? cb(Errors.missingUserId, null) : Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return cb(Error.invalidUserId, null);
-    } else if (!this.opts.timePermitsURL || !this.opts.certivoxURL) {
-      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing timePermitsURL or/and certivoxURL option."}, null);
+      return cb(Errors.invalidUserId, null);
+    } else if (!this.settings.timePermitsURL || !this.settings.certivoxURL) {
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing timePermitsURL or/and certivoxURL option."}, null);
     }
 
     //registered
     _userState = this.getUser(userId, "state");
-    if (_userState !== State.register) {
-      return cb(Error.wrongFlow, null);
+    if (_userState !== States.register) {
+      return cb(Errors.wrongFlow, null);
     }
 
     //checkUser
     _tp1Url = this.generateUrl('permit1', {userId: userId});
     this.request({url: _tp1Url}, function (err, data) {
+      if (err) {
+        if (err.status === 401 || err.status === 403 || err.status === 410) {
+          return cb(Errors.userRevoked, null);        
+        }
+		
+        return cb(err, null);
+      }
       var _signature, _tp2Url, _timePermit1, _storageUrl;
       _signature = data["signature"];
       _timePermit1 = data["timePermit"];
 
       self.addToUser(userId, {currentDate: data['date']});
 
-      _tp2Url = self.generateUrl('permit2', {userId: userId});
-      _tp2Url += "&signature=" + _signature;
-
       //check cache if exist
       if (Users[userId].timePermitCache && Users[userId].timePermitCache.date === data.date) {
         var _timePermit2 = Users[userId].timePermitCache.timePermit;
@@ -236,7 +241,11 @@ var mpinjs = (function () {
 
         self.request({url: _storageUrl}, function (storErr, storData) {
           if (storErr) {
+            _tp2Url = self.generateUrl('permit2', {userId: userId});
+            _tp2Url += "&signature=" + _signature;
+			  
             self._getTimePermit2({userId: userId, permit1: _timePermit1, permit2Url: _tp2Url, date: data.date}, cb); //continue
+			
             return;
           }
 
@@ -253,7 +262,16 @@ var mpinjs = (function () {
 
   Mpin.prototype._getTimePermit2 = function (options, cb) {
     var self = this, _timePermit1 = options.permit1;
+
     this.request({url: options.permit2Url}, function (err2, data2) {
+      if (err2) {
+        if (err2.status === 401 || err2.status === 403 || err2.status === 410) {
+          return cb(Errors.userRevoked, null);
+        }
+		
+        return cb(err2, null);
+      }
+
       var _timePermit2, timePermitHex, _permitCache = {};
       _timePermit2 = data2["timePermit"];
       timePermitHex = MPINAuth.addShares(_timePermit1, _timePermit2);
@@ -273,10 +291,10 @@ var mpinjs = (function () {
 
     //registered
     _userState = this.getUser(userId, "state");
-    if (_userState !== State.register) {
-      return cb(Error.wrongFlow, null);
+    if (_userState !== States.register) {
+      return cb(Errors.wrongFlow, null);
     } else if (!Users[userId].timePermitHex) {
-      return cb({code: Error.wrongFlow.code, type: Error.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
     this._passRequests({userId: userId, aPin: aPin}, cb);
@@ -287,10 +305,10 @@ var mpinjs = (function () {
 
     //registered
     _userState = this.getUser(userId, "state");
-    if (_userState !== State.register) {
-      return cb(Error.wrongFlow, null);
+    if (_userState !== States.register) {
+      return cb(Errors.wrongFlow, null);
     } else if (!Users[userId].timePermitHex) {
-      return cb({code: Error.wrongFlow.code, type: Error.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
     this._passRequests({userId: userId, aPin: aPin, otp: true}, function (err, data) {
@@ -360,12 +378,12 @@ var mpinjs = (function () {
     this.request(_authData, function (authErr, authData) {
       if (authErr) {
         if (authErr.status === 401) {
-          return cb(Error.wrongPin, null);
+          return cb(Errors.wrongPin, null);
         } else if (authErr.status === 410) {
-          opts.userId && self.addToUser(opts.userId, {state: State.block});
-          return cb(Error.wrongPin, null);
+          opts.userId && self.addToUser(opts.userId, {state: States.block});
+          return cb(Errors.wrongPin, null);
         } else {
-          return cb(Error.wrongPin, null);
+          return cb(Errors.wrongPin, null);
         }
       }
 
@@ -417,16 +435,23 @@ var mpinjs = (function () {
       }
       self.webOTT = data.webOTT;
 
-      cb && cb(null, {accessNumber: data.accessNumber});
+      returnData = {
+        accessNumber: data.accessNumber,
+        ttlSeconds: data.ttlSeconds,
+        localTimeStart: data.localTimeStart/1000,
+        localTimeEnd: data.localTimeEnd/1000
+      };
+	  
+      cb && cb(null, returnData);
     });
   };
 
   Mpin.prototype.waitForMobileAuth = function (timeoutSeconds, requestSeconds, cb) {
     var self = this, _reqData = {};
     if (!this.webOTT) {
-      return cb({code: Error.wrongFlow.code, type: Error.wrongFlow.type, message: "Need to call getAccessNumber method before this."}, null);
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call getAccessNumber method before this."}, null);
     } else if (!timeoutSeconds) {
-      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing timeout/expiration period(in seconds)."}, null);
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing timeout/expiration period(in seconds)."}, null);
     }
 
 
@@ -450,7 +475,7 @@ var mpinjs = (function () {
           }, _requestPeriod);
           return;
         } else if (self.timeoutPeriod <= 0) {
-          cb && cb(Error.timeoutFinish, null);
+          cb && cb(Errors.timeoutFinish, null);
           return;
         }
       }
@@ -471,15 +496,15 @@ var mpinjs = (function () {
 
     switch (type) {
       case "register":
-        url = this.opts.registerURL;
+        url = this.settings.registerURL;
         break;
       case "signature":
-        url = this.opts.signatureURL + "/";
+        url = this.settings.signatureURL + "/";
         url += Users[options.userId].mpinId;
         url += "?regOTT=" + Users[options.userId].regOTT;
         break;
       case "permit1":
-        url = this.opts.timePermitsURL + "/";
+        url = this.settings.timePermitsURL + "/";
         url += Users[options.userId].mpinId;
         break;
       case "permit2":
@@ -487,30 +512,29 @@ var mpinjs = (function () {
         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);
-        url = this.opts.certivoxURL + "timePermit";
-        url += "?app_id=" + this.opts.appID;
+        url = this.settings.certivoxURL + "timePermit";
+        url += "?app_id=" + this.settings.appID;
         url += "&mobile=0";
         url += "&hash_mpin_id=" + hash_mpin_id_hex;
         break;
       case "pass1":
-        url = this.opts.mpinAuthServerURL + "/pass1";
+        url = this.settings.mpinAuthServerURL + "/pass1";
         break;
       case "pass2":
-        url = this.opts.mpinAuthServerURL + "/pass2";
+        url = this.settings.mpinAuthServerURL + "/pass2";
         break;
       case "auth":
-        url = this.opts.authenticateURL;
+        url = this.settings.authenticateURL;
         break;
       case "getnumber":
-        url = this.opts.getAccessNumberURL;
+        url = this.settings.getAccessNumberURL;
         break;
       case "getaccess":
-        url = this.opts.accessNumberURL;
+        url = this.settings.accessNumberURL;
         break;
       case "storage":
-        url = this.opts.timePermitsStorageURL + "/" + this.opts.appID + "/";
+        url = this.settings.timePermitsStorageURL + "/" + this.settings.appID + "/";
         url += options.date + "/" + options.storageId;
-        //return that.opts.timePermitsStorageURL + "/" + that.opts.appID + "/" + date + "/" + storageId;
         break;
     }
 
@@ -518,13 +542,13 @@ var mpinjs = (function () {
   };
 
   Mpin.prototype.listUsers = function () {
-    var listUsers = {};
+    var listUsers = [];
     for (var uKey in Users) {
-      listUsers[uKey] = {
+      listUsers.push({
         userId: Users[uKey].userId,
         deviceId: Users[uKey].deviceId || "",
         state: Users[uKey].state || ""
-      };
+      });
     }
     return listUsers;
   };
@@ -536,9 +560,9 @@ var mpinjs = (function () {
   Mpin.prototype.getUser = function (userId, property) {
     var _user = {};
     if (!userId) {
-      return Error.missingUserId;
+      return Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return Error.invalidUserId;
+      return Errors.invalidUserId;
     }
 
     _user = {
@@ -559,9 +583,9 @@ var mpinjs = (function () {
     var mpinData = this.getData(), delMpinId;
 
     if (!userId) {
-      return Error.missingUserId;
+      return Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return Error.invalidUserId;
+      return Errors.invalidUserId;
     }
 
     delMpinId = Users[userId].mpinId;

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4231d489/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
index b5e311e..0bb83b8 100644
--- a/test/index.js
+++ b/test/index.js
@@ -91,7 +91,7 @@ describe('# Init method > clientSettings request.', function () {
   it('should store init response into internal property', function (done) {
     sinon.stub(mpin, 'request').yields(null, JSON.stringify(this.fakeRes));
     mpin.init(function (err, data) {
-      expect(mpin.opts).to.deep.equal(data);
+      expect(data).to.be.true;
       done();
     });
   });
@@ -265,7 +265,7 @@ describe('# confirmRegistration.', function () {
     mpin.init(function (err, data) {
       mpin.makeNewUser(userId);
       mpin.startRegistration(userId, function (err1, data1) {
-        mpin.confirmRegistration(userId, function (err2, data3) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
           expect(err2).to.have.deep.property('type', Errors[3]);
           done();
         });
@@ -286,8 +286,8 @@ describe('# confirmRegistration.', function () {
     mpin.init(function (err, data) {
       mpin.makeNewUser(userId);
       mpin.startRegistration(userId, function (err1, data1) {
-        mpin.confirmRegistration(userId, function (err2, data3) {
-          expect(data3).to.exist;
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          expect(data2).to.exist;
           done();
         });
       });


[05/37] incubator-milagro-mfa-js-lib git commit: Add setup flow

Posted by sa...@apache.org.
Add setup 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/67ed8ebe
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/67ed8ebe
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/67ed8ebe

Branch: refs/heads/add-documentation
Commit: 67ed8ebe81139f677f3038c03fb21d761e2c51e3
Parents: 10266af
Author: Boyan Bakov <bo...@certivox.com>
Authored: Fri Nov 20 17:45:56 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:25 2015 +0200

----------------------------------------------------------------------
 .gitignore         |   6 +
 Gruntfile.js       |  48 +++++++
 bower.json         |  14 ++
 index.js           |   1 +
 lib/mpin.js        | 216 +++++++++++++++++++++++++++++
 package.json       |  41 ++++++
 test/coverage.html | 360 ++++++++++++++++++++++++++++++++++++++++++++++++
 test/index.js      | 153 ++++++++++++++++++++
 test/mocha.opts    |   2 +
 9 files changed, 841 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..727ae60
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules/
+dist/
+npm-debug.log
+bower_components/
+nbproject/
+index.html

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/Gruntfile.js
----------------------------------------------------------------------
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..78d9edb
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,48 @@
+module.exports = function(grunt) {
+	grunt.initConfig({
+		pkg: grunt.file.readJSON('package.json'),
+		concat: {
+		    options: {
+				separator: ';'
+			},
+			mergeJs: {
+				src: ['bower_components/clint/DBIG.js','bower_components/clint/BIG.js', 'bower_components/clint/FP.js', 'bower_components/clint/ROM.js', 'bower_components/clint/HASH.js', 'bower_components/clint/RAND.js', 'bower_components/clint/AES.js', 'bower_components/clint/GPM.js', 'bower_components/clint/ECP.js', 'bower_components/clint/FP2.js', 'bower_components/clint/ECP2.js', 'bower_components/clint/FP4.js', 'bower_components/clint/FP12.js', 'bower_components/clint/PAIR.js', 'bower_components/clint/MPIN.js', 'bower_components/clint/MPINAuth.js', 'lib/mpin.js'],
+				dest: './dist/mpinjs.js'
+			}
+		},
+		bgShell: {
+			createDir: {
+				cmd: "mkdir -p ./dist",
+				options: {
+	            	stdout: true
+				}
+			},
+			test: {
+				cmd: 'mocha',
+				options: {
+					stdout: true
+				}
+			},
+			testCoverage: {
+				cmd: 'mocha test --require blanket --reporter html-cov > test/coverage.html',
+				options: {
+					stdout: true
+				}
+			},
+			bowerInstall: {
+				cmd: 'bower install --allow-root',
+				options: {
+					stdout: true
+				}
+			}
+		}
+	});
+	
+	grunt.loadNpmTasks('grunt-bg-shell');
+	grunt.loadNpmTasks('grunt-contrib-concat');
+
+	grunt.registerTask('build',  ['bgShell:createDir', 'bgShell:bowerInstall', 'concat']);
+	grunt.registerTask('chk',  ['bgShell:createDir', 'bgShell:bowerInstall', 'concat']);
+	grunt.registerTask('test',  ['bgShell:test']);
+	grunt.registerTask('testCover',  ['bgShell:testCoverage']);
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/bower.json
----------------------------------------------------------------------
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..bf93c48
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,14 @@
+{
+	"name": "Mpin lib",
+	"version": "1.0.0",
+	"description": "Mpin lib front-end project",
+	"authors": [
+		"Miracl ltd."
+	],
+	"dependencies": {
+		"clint": "https://builds.certivox.com/mpin_libs/js/latest/js.tar.gz"
+	},
+	"moduleType": "globals",
+	"main": "lib/mpin.js",
+	"homepage": "http://miracl.com"
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/index.js
----------------------------------------------------------------------
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..3a12526
--- /dev/null
+++ b/index.js
@@ -0,0 +1 @@
+\ufeffmodule.exports = require('./lib/mpin');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
new file mode 100644
index 0000000..285d749
--- /dev/null
+++ b/lib/mpin.js
@@ -0,0 +1,216 @@
+var mpinjs = (function () {
+  var Mpin, Users = {}, Errors = [];
+
+  Errors[1] = "Invalid userId.";
+  Errors[2] = "UserId does not exist.";
+  Errors[3] = "Missing parameter.";
+
+  Errors[4] = "UserId are not verified.";
+
+  Mpin = function (options) {
+    if (!options || !options.settingsUrl) {
+      return new Error("Missing settings URL");
+    }
+
+    this.opts = options;
+  };
+
+  Mpin.prototype.debug = true;
+
+  Mpin.prototype.init = function (cb) {
+    var self = this;
+
+    this.request({url: this.opts.settingsUrl}, function (err, data) {
+      if (err && cb) {
+        return cb(err, null);
+      }
+
+      self.ready = true;
+      self.opts = data;
+
+      cb && cb(null, data);
+    });
+  };
+
+  Mpin.prototype.makeNewUser = function (userId, deviceId) {
+    if (!userId) {
+      return {error: 1};
+    }
+
+    Users[userId] = {
+      userId: userId,
+      deviceId: deviceId || "",
+      status: "INVALID"
+    };
+
+    return this;
+  };
+
+  Mpin.prototype.startRegistration = function (userId, cb) {
+    var _reqData = {}, self = this;
+    if (!userId || typeof userId != "string") {
+      return cb ? cb({error: 1}, null) : {error: 1};
+    } else if (!this.checkUser(userId)) {
+      return cb({error: 2}, null);
+    } else if (!this.opts.registerURL) {
+      return cb({error: 3, message: "Missing registerURL"}, null);
+    }
+
+    _reqData.url = this.opts.registerURL;
+    _reqData.type = "PUT";
+    _reqData.data = {
+      userId: userId,
+      mobile: 0
+    };
+
+    this.request(_reqData, function (err, data) {
+      if (err) {
+        return cb(err, null);
+      }
+
+      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId,status: "STARTED"});
+
+      //force activate
+      if (data.active) {
+        self.addToUser(userId, {status: "ACTIVATED"});
+      }
+
+      cb && cb(null, true);
+    });
+  };
+
+
+  //request cs1 + cs2
+  Mpin.prototype.confirmRegistration = function (userId, cb) {
+    var _cs1Url = "", self = this;
+
+    _cs1Url = this.opts.signatureURL + "/";
+    _cs1Url += Users[userId].mpinId; //identity
+    _cs1Url += "?regOTT=" + Users[userId].regOTT;
+
+    //req cs1
+    this.request({url: _cs1Url}, function (err, cs1Data) {
+      var _cs2Url = "";
+      if (err) {
+        if (err.status == 401) {
+          return cb({error: 4, message: "Identity not activate."}, null);
+        }
+      }
+
+      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, status: "ACTIVATED"});
+      _cs2Url = self.opts.certivoxURL + "clientSecret?" + cs1Data.params;
+
+      //req cs2
+      self.request({url: _cs2Url}, function (err, cs2Data) {
+        var csHex;
+        self.addToUser(userId, {cs2: cs2Data.clientSecret});
+        csHex = MPINAuth.addShares(cs2Data.clientSecret, cs1Data.clientSecretShare);
+
+        self.addToUser(userId, {csHex: csHex});
+
+        cb(null, true);
+      });
+    });
+  };
+
+
+
+  Mpin.prototype.finishRegistration = function (userId, pin) {
+    var _user, tokenHex;
+
+    _user = this.getUser(userId);
+
+    if (_user.status !== "ACTIVATED") {
+      return {error: 3};
+    }
+
+    tokenHex = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
+    this.addToUser(userId, {tokenHex: tokenHex, status: "REGISTER"});
+
+    return tokenHex;
+  };
+
+  //Put user / mpinId
+  Mpin.prototype.restartRegistration = function (userId, deviceId, cb) {
+    var err = null, data = {};
+    cb(err, data);
+  };
+
+
+  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
+      };
+    }
+    return listUsers;
+  };
+
+  Mpin.prototype.checkUser = function (userId) {
+    return (Users[userId]) ? true : false;
+  };
+
+
+  Mpin.prototype.getUser = function (userId) {
+    var _user = {};
+    if (!userId) {
+      return {error: 0};
+    } else if (!this.checkUser(userId)) {
+      return {error: 2};
+    }
+
+    _user = {
+      userId: Users[userId].userId,
+      deviceId: Users[userId].deviceId,
+      status: Users[userId].status
+    };
+
+    return _user;
+  };
+
+  Mpin.prototype.addToUser = function (userId, userProps) {
+    if (!this.checkUser(userId)) {
+      return false;
+    }
+
+    for (var uKey in userProps) {
+      Users[userId][uKey] = userProps[uKey];
+    }
+  };
+
+  Mpin.prototype.restore = function () {
+    Users = {};
+  };
+
+//{url: url, type: "get post put", data: data}
+  Mpin.prototype.request = function (options, cb) {
+    var _request = new XMLHttpRequest(), _url, _type, _data;
+    _url = options.url || "";
+    _type = options.type || "GET";
+    _data = options.data || "";
+
+    _request.onreadystatechange = function () {
+      if (_request.readyState === 4 && _request.status === 200) {
+        cb(null, JSON.parse(_request.responseText));
+      } else if (_request.readyState === 4) {
+        cb({status: _request.status}, null);
+      }
+    };
+
+    _request.open(_type, _url, true);
+    _request.send(JSON.stringify(_data || ""));
+  };
+
+  return Mpin;
+})();
+
+
+//module.exports = mpinjs;
+//http://www.matteoagosti.com/blog/2013/02/24/writing-javascript-modules-for-both-browser-and-node/
+if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
+  module.exports = mpinjs;
+else
+  window.mpinjs = mpinjs;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d3c1a1b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "mpinjs",
+  "version": "1.0.0",
+  "description": "Mpin frontend library.",
+  "main": "index.js",
+  "scripts": {
+    "test": "mocha",
+    "test2": "mocha test --require blanket --reporter html-cov > test/coverage.html"
+  },
+  "repository": {
+    "type": "git",
+    "url": "http://10.10.23.8:7990/scm/mpin/mpinjs.git"
+  },
+  "keywords": [
+    "Mpin",
+    "frontend"
+  ],
+  "author": "Mpin",
+  "license": "ISC",
+  "devDependencies": {
+    "blanket": "^1.2.1",
+    "chai": "^3.4.1",
+    "mocha": "^2.3.4",
+    "sinon": "^1.17.2",
+    "sinon-chai": "^2.8.0"
+  },
+  "config": {
+    "blanket": {
+      "pattern": [
+        "mpin.js"
+      ],
+      "data-cover-never": "node_modules"
+    }
+  },
+  "dependencies": {
+    "bower": "^1.6.5",
+    "grunt": "^0.4.5",
+    "grunt-bg-shell": "^2.3.1",
+    "grunt-contrib-concat": "^0.5.1"
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/test/coverage.html
----------------------------------------------------------------------
diff --git a/test/coverage.html b/test/coverage.html
new file mode 100644
index 0000000..8d6f974
--- /dev/null
+++ b/test/coverage.html
@@ -0,0 +1,360 @@
+err  { error: 3, message: 'Missing registerURL' } null
+<!DOCTYPE html><html><head><title>Coverage</title><meta charset="utf-8"><script>
+
+headings = [];
+
+onload = function(){
+  headings = document.querySelectorAll('h2');
+};
+
+onscroll = function(e){
+  var heading = find(window.scrollY);
+  if (!heading) return;
+  var links = document.querySelectorAll('#menu a')
+    , link;
+
+  for (var i = 0, len = links.length; i < len; ++i) {
+    link = links[i];
+    link.className = link.getAttribute('href') == '#' + heading.id
+      ? 'active'
+      : '';
+  }
+};
+
+function find(y) {
+  var i = headings.length
+    , heading;
+
+  while (i--) {
+    heading = headings[i];
+    if (y >= heading.offsetTop) {
+      return heading;
+    }
+  }
+}
+</script>
+<style>
+
+body {
+  font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
+  margin: 0;
+  color: #2C2C2C;
+  border-top: 2px solid #ddd;
+}
+
+#coverage {
+  padding: 60px 400px 60px 60px;
+}
+
+h1 a {
+  color: inherit;
+  font-weight: inherit;
+}
+
+h1 a:hover {
+  text-decoration: none;
+}
+
+.onload h1 {
+  opacity: 1;
+}
+
+h2 {
+  width: 80%;
+  margin-top: 80px;
+  margin-bottom: 0;
+  font-weight: 100;
+  letter-spacing: 1px;
+  border-bottom: 1px solid #eee;
+}
+
+a {
+  color: #8A6343;
+  font-weight: bold;
+  text-decoration: none;
+}
+
+a:hover {
+  text-decoration: underline;
+}
+
+ul {
+  margin-top: 20px;
+  padding: 0 15px;
+  width: 100%;
+}
+
+ul li {
+  float: left;
+  width: 40%;
+  margin-top: 5px;
+  margin-right: 60px;
+  list-style: none;
+  border-bottom: 1px solid #eee;
+  padding: 5px 0;
+  font-size: 12px;
+}
+
+ul::after {
+  content: '.';
+  height: 0;
+  display: block;
+  visibility: hidden;
+  clear: both;
+}
+
+code {
+  font: 12px monaco, monospace;
+}
+
+pre {
+  margin: 30px;
+  padding: 30px;
+  border: 1px solid #eee;
+  border-bottom-color: #ddd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  -webkit-box-shadow: inset 0 0 10px #eee;
+  -moz-box-shadow: inset 0 0 10px #eee;
+  box-shadow: inset 0 0 10px #eee;
+  overflow-x: auto;
+}
+
+img {
+  margin: 30px;
+  padding: 1px;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  -webkit-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+  -moz-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+  box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+  max-width: 100%;
+}
+
+footer {
+  background: #eee;
+  width: 100%;
+  padding: 50px 0;
+  text-align: right;
+  border-top: 1px solid #ddd;
+}
+
+footer span {
+  display: block;
+  margin-right: 30px;
+  color: #888;
+  font-size: 12px;
+}
+
+#menu {
+  position: fixed;
+  font-size: 12px;
+  overflow-y: auto;
+  top: 0;
+  right: 0;
+  margin: 0;
+  height: 100%;
+  padding: 15px 0;
+  text-align: right;
+  border-left: 1px solid #eee;
+  max-width: 400px;
+  overflow: auto;
+  white-space: nowrap;
+  
+  -moz-box-shadow: 0 0 2px #888
+     , inset 5px 0 20px rgba(0,0,0,.5)
+     , inset 5px 0 3px rgba(0,0,0,.3);
+  -webkit-box-shadow: 0 0 2px #888
+     , inset 5px 0 20px rgba(0,0,0,.5)
+     , inset 5px 0 3px rgba(0,0,0,.3);
+  box-shadow: 0 0 2px #888
+     , inset 5px 0 20px rgba(0,0,0,.5)
+     , inset 5px 0 3px rgba(0,0,0,.3);
+  -webkit-font-smoothing: antialiased;
+  background: url("data:image/png;base64,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");
+}
+
+#menu::after {
+  display: block;
+  content: '';
+  padding-top: 80px;
+}
+
+#logo {
+  position: fixed;
+  bottom: 10px;
+  right: 10px;
+  background: rgba(255,255,255,.1);
+  font-size: 11px;
+  display: block;
+  width: 20px;
+  height: 20px;
+  line-height: 20px;
+  text-align: center;
+  -webkit-border-radius: 20px;
+  -moz-border-radius: 20px;
+  border-radius: 20px;
+  -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
+  -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
+  box-shadow: 0 0 3px rgba(0,0,0,.2);
+  color: inherit;
+}
+
+#menu li a {
+  display: block;
+  color: white;
+  padding: 0 35px 0 25px;
+  -webkit-transition: background 300ms;
+  -moz-transition: background 300ms;
+}
+
+#menu li {
+  position: relative;
+  list-style: none;
+}
+
+#menu a:hover,
+#menu a.active {
+  text-decoration: none;
+  background: rgba(255,255,255,.1);
+}
+
+#menu li:hover .cov {
+  opacity: 1;
+}
+
+#menu li .dirname {
+  opacity: .60;
+  padding-right: 2px;
+}
+
+#menu li .basename {
+  opacity: 1;
+}
+
+#menu .cov {
+  background: rgba(0,0,0,.4);
+  position: absolute;
+  top: 0;
+  right: 8px;
+  font-size: 9px;
+  opacity: .6;
+  text-align: left;
+  width: 17px;
+  -webkit-border-radius: 10px;
+  -moz-border-radius: 10px;
+  border-radius: 10px;
+  padding: 2px 3px;
+  text-align: center;
+}
+
+#stats:nth-child(2n) {
+  display: inline-block;
+  margin-top: 15px;
+  border: 1px solid #eee;
+  padding: 10px;
+  -webkit-box-shadow: inset 0 0 2px #eee;
+  -moz-box-shadow: inset 0 0 2px #eee;
+  box-shadow: inset 0 0 2px #eee;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+}
+
+#stats div {
+  float: left;
+  padding: 0 5px;
+}
+
+#stats::after {
+  display: block;
+  content: '';
+  clear: both;
+}
+
+#stats .sloc::after {
+  content: ' SLOC';
+  color: #b6b6b6;
+}
+
+#stats .percentage::after {
+  content: ' coverage';
+  color: #b6b6b6;
+}
+
+#stats .hits,
+#stats .misses {
+  display: none;
+}
+
+.high {
+  color: #00d4b4;
+}
+.medium {
+  color: #e87d0d;
+}
+.low {
+  color: #d4081a;
+}
+.terrible {
+  color: #d4081a;
+  font-weight: bold;
+}
+
+table {
+  width: 80%;
+  margin-top: 10px;
+  border-collapse: collapse;
+  border: 1px solid #cbcbcb;
+  color: #363636;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+}
+
+table thead {
+  display: none;
+}
+
+table td.line,
+table td.hits {
+  width: 20px;
+  background: #eaeaea;
+  text-align: center;
+  font-size: 11px;
+  padding: 0 10px;
+  color: #949494;
+}
+
+table td.hits {
+  width: 10px;
+  padding: 2px 5px;
+  color: rgba(0,0,0,.2);
+  background: #f0f0f0;
+}
+
+tr.miss td.line,
+tr.miss td.hits {
+  background: #e6c3c7;
+}
+
+tr.miss td {
+  background: #f8d5d8;
+}
+
+td.source {
+  padding-left: 15px;
+  line-height: 15px;
+  white-space: pre;
+  font: 12px monaco, monospace;
+}
+
+code .comment { color: #ddd }
+code .init { color: #2F6FAD }
+code .string { color: #5890AD }
+code .keyword { color: #8A6343 }
+code .number { color: #2F6FAD }
+</style>
+</head><body><div id="coverage"><h1 id="overview">Coverage</h1><div id="menu"><li><a href="#overview">overview</a></li><li><span class="cov medium">52</span><a href="#/var/www/mpinjs/lib/mpin.js"><span class="dirname">/var/www/mpinjs/lib/</span><span class="basename">mpin.js</span></a></li><a id="logo" href="http://mochajs.org/">m</a></div><div id="stats" class="medium"><div class="percentage">52%</div><div class="sloc">109</div><div class="hits">57</div><div class="misses">52</div></div><div id="files"><div class="file"><h2 id="/var/www/mpinjs/lib/mpin.js">/var/www/mpinjs/lib/mpin.js</h2><div id="stats" class="medium"><div class="percentage">52%</div><div class="sloc">109</div><div class="hits">57</div><div class="misses">52</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr class="hit"><td class="line">1</td><td class="hits">1</td><td class="source">var mpinjs = (function () {</td></tr><tr class="hit"><td class="line">2</td><t
 d class="hits">1</td><td class="source">  var Mpin, Users = {}, Errors = [];</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">4</td><td class="hits">1</td><td class="source">  Errors[1] = &quot;Invalid userId.&quot;;</td></tr><tr class="hit"><td class="line">5</td><td class="hits">1</td><td class="source">  Errors[2] = &quot;UserId does not exist.&quot;;</td></tr><tr class="hit"><td class="line">6</td><td class="hits">1</td><td class="source">  Errors[3] = &quot;Missing parameter.&quot;;</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">8</td><td class="hits">1</td><td class="source">  Errors[4] = &quot;UserId are not verified.&quot;;</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">10</td><td class="hits">1</td><td class="source">  Mpin = function (options) {</td></tr><t
 r class="hit"><td class="line">11</td><td class="hits">5</td><td class="source">    if (!options || !options.settingsUrl) {</td></tr><tr class="hit"><td class="line">12</td><td class="hits">1</td><td class="source">      return new Error(&quot;Missing settings URL&quot;);</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">15</td><td class="hits">4</td><td class="source">    this.opts = options;</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">  Mpin.prototype.debug = true;</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">20</td><td class="hits">1</td><td cla
 ss="source">  Mpin.prototype.init = function (cb) {</td></tr><tr class="hit"><td class="line">21</td><td class="hits">5</td><td class="source">    var self = this;</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">23</td><td class="hits">5</td><td class="source">    this.request({url: this.opts.settingsUrl}, function (err, data) {</td></tr><tr class="hit"><td class="line">24</td><td class="hits">3</td><td class="source">      if (err &amp;&amp; cb) {</td></tr><tr class="hit"><td class="line">25</td><td class="hits">1</td><td class="source">        return cb(err, null);</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">28</td><td class="hits">2</td><td class="source">      self.ready = true;</td></tr><tr class="hit"><td class="line">29</td><td class="hits">2
 </td><td class="source">      self.opts = data;</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">31</td><td class="hits">2</td><td class="source">      cb &amp;&amp; cb(null, data);</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">35</td><td class="hits">1</td><td class="source">  Mpin.prototype.makeNewUser = function (userId, deviceId) {</td></tr><tr class="hit"><td class="line">36</td><td class="hits">4</td><td class="source">    if (!userId) {</td></tr><tr class="hit"><td class="line">37</td><td class="hits">1</td><td class="source">      return {error: 1};</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">3
 9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">40</td><td class="hits">3</td><td class="source">    Users[userId] = {</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">      userId: userId,</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">      deviceId: deviceId || &quot;&quot;,</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">      status: &quot;STARTED&quot;</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">46</td><td class="hits">3</td><td class="source">    return this;</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">49</td><td class="hits">1
 </td><td class="source">  Mpin.prototype.startRegistration = function (userId, cb) {</td></tr><tr class="hit"><td class="line">50</td><td class="hits">4</td><td class="source">    var _reqData = {}, self = this;</td></tr><tr class="hit"><td class="line">51</td><td class="hits">4</td><td class="source">    if (!userId || typeof userId != &quot;string&quot;) {</td></tr><tr class="hit"><td class="line">52</td><td class="hits">1</td><td class="source">      return cb ? cb({error: 1}, null) : {error: 1};</td></tr><tr class="hit"><td class="line">53</td><td class="hits">3</td><td class="source">    } else if (!this.checkUser(userId)) {</td></tr><tr class="hit"><td class="line">54</td><td class="hits">1</td><td class="source">      return cb({error: 2}, null);</td></tr><tr class="hit"><td class="line">55</td><td class="hits">2</td><td class="source">    } else if (!this.opts.registerURL) {</td></tr><tr class="hit"><td class="line">56</td><td class="hits">1</td><td class="source">      retu
 rn cb({error: 3, message: &quot;Missing registerURL&quot;}, null);</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">59</td><td class="hits">1</td><td class="source">    _reqData.url = this.opts.registerURL;</td></tr><tr class="hit"><td class="line">60</td><td class="hits">1</td><td class="source">    _reqData.type = &quot;PUT&quot;;</td></tr><tr class="hit"><td class="line">61</td><td class="hits">1</td><td class="source">    _reqData.data = {</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">      userId: userId,</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">      mobile: 0</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td clas
 s="line">66</td><td class="hits">1</td><td class="source">    this.request(_reqData, function (err, data) {</td></tr><tr class="hit"><td class="line">67</td><td class="hits">1</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">68</td><td class="hits">0</td><td class="source">        return cb(err, null);</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">71</td><td class="hits">1</td><td class="source">      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId});</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">      //force activate</td></tr><tr class="hit"><td class="line">74</td><td class="hits">1</td><td class="source">      if (data.active) {</td></tr><tr class="miss"><td c
 lass="line">75</td><td class="hits">0</td><td class="source">        self.addToUser(userId, {status: &quot;ACTIVATED&quot;});</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">78</td><td class="hits">1</td><td class="source">      cb &amp;&amp; cb(null, true);</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">  //request cs1 + cs2</td></tr><tr class="hit"><td class="line">84</td><td class="hits">1</td><td class="source">  Mpin.prototype.confirmRegistration = function (userId, c
 b) {</td></tr><tr class="miss"><td class="line">85</td><td class="hits">0</td><td class="source">    var _cs1Url = &quot;&quot;, self = this;</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">87</td><td class="hits">0</td><td class="source">    _cs1Url = this.opts.signatureURL + &quot;/&quot;;</td></tr><tr class="miss"><td class="line">88</td><td class="hits">0</td><td class="source">    _cs1Url += Users[userId].mpinId; //identity</td></tr><tr class="miss"><td class="line">89</td><td class="hits">0</td><td class="source">    _cs1Url += &quot;?regOTT=&quot; + Users[userId].regOTT;</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">    //req cs1</td></tr><tr class="miss"><td class="line">92</td><td class="hits">0</td><td class="source">    this.request({url: _cs1Url}, function (err, cs1Data) {</td></tr><tr c
 lass="miss"><td class="line">93</td><td class="hits">0</td><td class="source">      var _cs2Url = &quot;&quot;;</td></tr><tr class="miss"><td class="line">94</td><td class="hits">0</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">95</td><td class="hits">0</td><td class="source">        if (err.status == 401) {</td></tr><tr class="miss"><td class="line">96</td><td class="hits">0</td><td class="source">          return cb({error: 2, message: &quot;Identity not activate.&quot;}, null);</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">100</td><td class="hits">0</td><td class="source">      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, status: &quot;ACTIVATED&quot;});</td></t
 r><tr class="miss"><td class="line">101</td><td class="hits">0</td><td class="source">      _cs2Url = self.opts.certivoxURL + &quot;clientSecret?&quot; + cs1Data.params;</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">      //req cs2</td></tr><tr class="miss"><td class="line">104</td><td class="hits">0</td><td class="source">      self.request({url: _cs2Url}, function (err, cs2Data) {</td></tr><tr class="miss"><td class="line">105</td><td class="hits">0</td><td class="source">        var csHex;</td></tr><tr class="miss"><td class="line">106</td><td class="hits">0</td><td class="source">        self.addToUser(userId, {cs2: cs2Data.clientSecret});</td></tr><tr class="miss"><td class="line">107</td><td class="hits">0</td><td class="source">        csHex = MPINAuth.addShares(cs2Data.clientSecret, cs1Data.clientSecretShare);</td></tr><tr><td class="line">108</td><td class="hits
 "></td><td class="source"> </td></tr><tr class="miss"><td class="line">109</td><td class="hits">0</td><td class="source">        self.addToUser(userId, {csHex: csHex});</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">111</td><td class="hits">0</td><td class="source">        cb(null, true);</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">118</td><td class="hits">1</td><td class="source">  Mpin.prototype.finishRegistration
  = function (userId, pin) {</td></tr><tr class="miss"><td class="line">119</td><td class="hits">0</td><td class="source">    var _user, tokenHex;</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">121</td><td class="hits">0</td><td class="source">    _user = this.getUser(userId);</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">123</td><td class="hits">0</td><td class="source">    if (_user.status !== &quot;ACTIVATED&quot;) {</td></tr><tr class="miss"><td class="line">124</td><td class="hits">0</td><td class="source">      return {error: 3};</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">127</td><td class="hits">0</td><td class="source">    tokenHex = MPINAuth.calculateMPinToken
 (Users[userId].mpinId, pin, Users[userId].csHex);</td></tr><tr class="miss"><td class="line">128</td><td class="hits">0</td><td class="source">    this.addToUser(userId, {tokenHex: tokenHex, status: &quot;REGISTER&quot;});</td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">130</td><td class="hits">0</td><td class="source">    return tokenHex;</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">  //Put user / mpinId</td></tr><tr class="hit"><td class="line">134</td><td class="hits">1</td><td class="source">  Mpin.prototype.restartRegistration = function (userId, deviceId, cb) {</td></tr><tr class="miss"><td class="line">135</td><td class="hits">0</td><td class="source">    var err = null, data = {};</td></tr><tr class="miss
 "><td class="line">136</td><td class="hits">0</td><td class="source">    cb(err, data);</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">140</td><td class="hits">1</td><td class="source">  Mpin.prototype.listUsers = function () {</td></tr><tr class="miss"><td class="line">141</td><td class="hits">0</td><td class="source">    var listUsers = {};</td></tr><tr class="miss"><td class="line">142</td><td class="hits">0</td><td class="source">    for (var uKey in Users) {</td></tr><tr class="miss"><td class="line">143</td><td class="hits">0</td><td class="source">      listUsers[uKey] = {</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source">        userId: Users[uKey].userId,</td></tr><tr><td class="line">145</td><td class="hits"
 ></td><td class="source">        deviceId: Users[uKey].deviceId,</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source">        status: Users[uKey].status</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">149</td><td class="hits">0</td><td class="source">    return listUsers;</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">152</td><td class="hits">1</td><td class="source">  Mpin.prototype.checkUser = function (userId) {</td></tr><tr class="hit"><td class="line">153</td><td class="hits">5</td><td class="source">    return (Users[userId]) ? true : false;</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">  };</td><
 /tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">157</td><td class="hits">1</td><td class="source">  Mpin.prototype.getUser = function (userId) {</td></tr><tr class="miss"><td class="line">158</td><td class="hits">0</td><td class="source">    var _user = {};</td></tr><tr class="miss"><td class="line">159</td><td class="hits">0</td><td class="source">    if (!userId) {</td></tr><tr class="miss"><td class="line">160</td><td class="hits">0</td><td class="source">      return {error: 4};</td></tr><tr class="miss"><td class="line">161</td><td class="hits">0</td><td class="source">    } else if (!this.checkUser(userId)) {</td></tr><tr class="miss"><td class="line">162</td><td class="hits">0</td><td class="source">      return {error: 2};</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">    }</td></tr><tr><td cla
 ss="line">164</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">165</td><td class="hits">0</td><td class="source">    _user = {</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">      userId: Users[userId].userId,</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">      deviceId: Users[userId].deviceId,</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">      status: Users[userId].status</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">171</td><td class="hits">0</td><td class="source">    return _user;</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="li
 ne">174</td><td class="hits">1</td><td class="source">  Mpin.prototype.addToUser = function (userId, userProps) {</td></tr><tr class="hit"><td class="line">175</td><td class="hits">1</td><td class="source">    if (!this.checkUser(userId)) {</td></tr><tr class="miss"><td class="line">176</td><td class="hits">0</td><td class="source">      return false;</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">179</td><td class="hits">1</td><td class="source">    for (var uKey in userProps) {</td></tr><tr class="hit"><td class="line">180</td><td class="hits">2</td><td class="source">      Users[userId][uKey] = userProps[uKey];</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">183</td><td cla
 ss="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">184</td><td class="hits">1</td><td class="source">  Mpin.prototype.restore = function () {</td></tr><tr class="hit"><td class="line">185</td><td class="hits">1</td><td class="source">    Users = {};</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">//{url: url, type: &quot;get post put&quot;, data: data}</td></tr><tr class="hit"><td class="line">189</td><td class="hits">1</td><td class="source">  Mpin.prototype.request = function (options, cb) {</td></tr><tr class="miss"><td class="line">190</td><td class="hits">0</td><td class="source">    var _request = new XMLHttpRequest(), _url, _type, _data;</td></tr><tr class="miss"><td class="line">191</td><td class="hits">0</td><td class="source">    _url = options.url || &q
 uot;&quot;;</td></tr><tr class="miss"><td class="line">192</td><td class="hits">0</td><td class="source">    _type = options.type || &quot;GET&quot;;</td></tr><tr class="miss"><td class="line">193</td><td class="hits">0</td><td class="source">    _data = options.data || &quot;&quot;;</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">195</td><td class="hits">0</td><td class="source">    _request.onreadystatechange = function () {</td></tr><tr class="miss"><td class="line">196</td><td class="hits">0</td><td class="source">      if (_request.readyState === 4 &amp;&amp; _request.status === 200) {</td></tr><tr class="miss"><td class="line">197</td><td class="hits">0</td><td class="source">        cb(null, JSON.parse(_request.responseText));</td></tr><tr class="miss"><td class="line">198</td><td class="hits">0</td><td class="source">      } else if (_request.readyState === 4) {</td></tr><tr class="miss"><td class="l
 ine">199</td><td class="hits">0</td><td class="source">        cb({status: _request.status}, null);</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">203</td><td class="hits">0</td><td class="source">    _request.open(_type, _url, true);</td></tr><tr class="miss"><td class="line">204</td><td class="hits">0</td><td class="source">    _request.send(JSON.stringify(_data || &quot;&quot;));</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">207</td><td class="hits">1</td><td class="source">  return Mpin;</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">})();</td>
 </tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source">//module.exports = mpinjs;</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">//http://www.matteoagosti.com/blog/2013/02/24/writing-javascript-modules-for-both-browser-and-node/</td></tr><tr class="hit"><td class="line">213</td><td class="hits">1</td><td class="source">if (typeof module !== 'undefined' &amp;&amp; typeof module.exports !== 'undefined')</td></tr><tr class="hit"><td class="line">214</td><td class="hits">1</td><td class="source">  module.exports = mpinjs;</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">else</td></tr><tr class="miss"><td class="line">216</td><td class="hits">0</td><td class="source">  window.mpinjs = mpinjs;</td></tr></tbody></table></div></div></div></body></html
 >
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
new file mode 100644
index 0000000..55ea634
--- /dev/null
+++ b/test/index.js
@@ -0,0 +1,153 @@
+//if browser
+if (typeof require !== 'undefined') {
+  var expect = require('chai').expect;
+  var mpinjs = require('../index');
+  var sinon = require('sinon');
+  var sinonChai = require('sinon-chai');
+}
+
+describe('# Constructor initialization without settingsUrl.', function () {
+  it('should throw Error', function () {
+    var mpin = new mpinjs();
+    expect(mpin).to.be.an.instanceof(Error);
+  });
+});
+
+//spy cases
+describe('# Normal iniatilization.', function () {
+  var mpin, spy, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+
+  before(function () {
+    mpin = new mpinjs({settingsUrl: settingsUrl});
+    spy = sinon.spy();
+
+    mpin.request = spy;
+  });
+
+  it('should call request method once', function () {
+    mpin.init();
+    expect(spy.calledOnce).to.be.true;
+  });
+
+  it('should call request method with settingsUrl params', function () {
+    mpin.init();
+    expect(spy.calledWith({url: settingsUrl})).to.be.true;
+  });
+});
+
+describe('# Init method > clientSettings request.', function () {
+  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+
+  before(function () {
+    mpin = new mpinjs({settingsUrl: settingsUrl});
+
+    this.fakeRes = {
+      requestOTP: false,
+      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
+      registerUrl: "http://192.168.10.63:8011/rps/user"
+    };
+  });
+
+//restore request
+  afterEach(function (done) {
+    mpin.request.restore();
+    done();
+  });
+
+  it('should return error if init response is wrong', function (done) {
+    sinon.stub(mpin, 'request').yields({}, null);
+    mpin.init(function (err, data) {
+      expect(err).to.exist;
+      done();
+    });
+  });
+
+  it('should store init response into internal property', function (done) {
+    sinon.stub(mpin, 'request').yields(null, JSON.stringify(this.fakeRes));
+    mpin.init(function (err, data) {
+      expect(mpin.opts).to.deep.equal(data);
+      done();
+    });
+  });
+
+});
+
+describe('# makeNewUser checks.', function () {
+  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+
+  before(function () {
+    mpin = new mpinjs({settingsUrl: settingsUrl});
+  });
+
+  after(function () {
+    mpin.restore();
+  });
+
+  it('should makeNewUser return error when call without userId', function () {
+    var user = mpin.makeNewUser();
+    expect(user).to.deep.equal({error: 1});
+  });
+
+  it('should store user into internal list', function () {
+    var userId = "test@user.id";
+    mpin.makeNewUser(userId);
+    expect(mpin.checkUser(userId)).to.be.true;
+  });
+});
+
+describe('# startRegistration.', function () {
+  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+
+  before(function () {
+    mpin = new mpinjs({settingsUrl: settingsUrl});
+
+    this.fakeRes = {
+      requestOTP: false,
+      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
+      registerURL: "http://192.168.10.63:8011/rps/user"
+    };
+  });
+
+  it('should return error 1, call without userId', function (done) {
+    mpin.startRegistration(null, function (err, data) {
+      expect(err).to.deep.equal({error: 1});
+      done();
+    });
+  });
+
+  it('should return error 2 if skip makeNewUser method.', function (done) {
+    var userId = "test@user.id";
+    mpin.startRegistration(userId, function (err, data) {
+      expect(err).to.deep.equal({error: 2});
+      done();
+    });
+  });
+
+  it('should return error 3 if skip init method.', function (done) {
+    var userId = "test@user.id";
+    mpin.makeNewUser(userId);
+    mpin.startRegistration(userId, function (err, data) {
+      expect(err).to.exist;
+      done();
+    });
+  });
+
+  it('should return OK.', function (done) {
+    var userId = "test@user.id";
+    
+    //mock for init method
+    sinon.stub(mpin, 'request').yields(null, this.fakeRes);
+
+    mpin.init(function (err, data) {
+
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        expect(data).to.exist;
+        done();
+      });
+    });
+  });
+
+
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/67ed8ebe/test/mocha.opts
----------------------------------------------------------------------
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 0000000..7179157
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,2 @@
+\ufeff--recursive
+--timeout 5000
\ No newline at end of file


[35/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #12 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #12 in MPIN/mpinjs from develop to master

* commit '4f0e481a0cb99976ad0d5327435cc2dfd2a93185':
  Increase test coverage


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/0a3dc9cc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/0a3dc9cc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/0a3dc9cc

Branch: refs/heads/add-documentation
Commit: 0a3dc9cc18d8778b66e3c837f031ba67142462cd
Parents: 4804d16 4f0e481
Author: Boyan Bakov <bo...@certivox.com>
Authored: Wed Mar 23 10:07:39 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Wed Mar 23 10:07:39 2016 +0100

----------------------------------------------------------------------
 example/exampleJquery.html |   2 +-
 test/auth.js               | 266 ++++++++++++++++++++++++++++++
 test/index.html            |   4 +-
 test/index.js              | 346 ++++++++++++++++++++++++++--------------
 test/init.js               | 142 +++++++++++++++++
 5 files changed, 642 insertions(+), 118 deletions(-)
----------------------------------------------------------------------



[34/37] incubator-milagro-mfa-js-lib git commit: Increase test coverage

Posted by sa...@apache.org.
Increase test coverage


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/4f0e481a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/4f0e481a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/4f0e481a

Branch: refs/heads/add-documentation
Commit: 4f0e481a0cb99976ad0d5327435cc2dfd2a93185
Parents: 0712ac9
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 21 15:49:17 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 21 18:00:04 2016 +0200

----------------------------------------------------------------------
 example/exampleJquery.html |   2 +-
 test/auth.js               | 266 ++++++++++++++++++++++++++++++
 test/index.html            |   4 +-
 test/index.js              | 346 ++++++++++++++++++++++++++--------------
 test/init.js               | 142 +++++++++++++++++
 5 files changed, 642 insertions(+), 118 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/example/exampleJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleJquery.html b/example/exampleJquery.html
index c9459c1..5db8efe 100644
--- a/example/exampleJquery.html
+++ b/example/exampleJquery.html
@@ -122,7 +122,7 @@ and open the template in the editor.
         $(document).on('click', ".auth-accnumber", function (ev) {
           var userId, userPin, userAN;
           userId = $(ev.currentTarget).data('userid');
-					userPin = $(ev.currentTarget).parent("li").find("input.userPin").val();
+					userPin = $(ev.currentTarget).parents("li").find("input.userPin").val();
 					userAN = $(ev.currentTarget).prev("input.userAN").val();
 					
 					if (!mpin.checkAccessNumber(userAN)) {

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/auth.js
----------------------------------------------------------------------
diff --git a/test/auth.js b/test/auth.js
new file mode 100644
index 0000000..ab22fe3
--- /dev/null
+++ b/test/auth.js
@@ -0,0 +1,266 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+//if browser
+if (typeof require !== 'undefined') {
+  var expect = require('chai').expect;
+  var sinon = require('sinon');
+  var sinonChai = require('sinon-chai');
+  var mpinjs = require('../index');
+  var inits = require("./init");
+}
+var Errors, testData, testLocalstorage;
+
+Errors = inits.Errors;
+MPINAuth = inits.MPINAuth;
+MPIN = inits.MPIN;
+testData = inits.testData;
+testLocalstorage = inits.testLocalStorage;
+
+////////////////////////////////////////////////////////////authentication
+describe("# startAuthentication", function () {
+  var mpin, spy, serverUrl = "http://192.168.10.63:8005";
+
+  var testLocalstorage = {
+    "accounts": {
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
+        "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
+        "state": "STARTED"
+      }
+    }
+  };
+
+
+  var userId = "test@user.id";
+
+  beforeEach(function (done) {
+    var userPin = "userSecret";
+
+    mpin = new mpinjs({server: testData.serverUrl});
+    spy = sinon.spy();
+
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
+    sinon.stub(mpin, "storeData");
+
+    spy = sinon.spy(mpin, "toHash");
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          mpin.finishRegistration(userId, userPin);
+          expect(spy.calledOnce).to.be.true;
+          expect(spy.calledWith(userPin)).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+
+  it("should return error type " + Errors.missingUserId + " call without userId", function () {
+    var err = mpin.startAuthentication();
+    expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
+  });
+
+  it("should return error type " + Errors.userRevoked + " when timePermit1 request return status:401", function (done) {
+    var errData = {status: 500};
+    stub.onCall(4).yields({status: 401}, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(errData, null); //tp2 - return status 401 user Revoke
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(err).to.deep.equal({code: 7, type: Errors.userRevoked});
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.userRevoked + " when timePermit2 request return status:401", function (done) {
+    var errData = {status: 500};
+
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(errData, null); //tp2 - return status 401 user Revoke
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(err).to.deep.equal(errData);
+      done();
+    });
+  });
+
+  it("should return error if have any other errors", function (done) {
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields({status: 401}, null); //tp2 - return status 401 user Revoke
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(err).to.deep.equal({code: 7, type: Errors.userRevoked});
+      done();
+    });
+  });
+
+  it("should be ok ", function (done) {
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    mpin.startAuthentication(userId, function (err, data) {
+      expect(data).to.be.true;
+      done();
+    });
+  });
+});
+
+describe("# finishAuthentication", function () {
+  var mpin, spy, userId = "test@user.id", userPin = "userPIN";
+
+  beforeEach(function (done) {
+    mpin = new mpinjs({server: testData.serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
+    sinon.stub(mpin, "storeData");
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+    done();
+    this.setupFlow = function (cb) {
+      mpin.init(function (err, data) {
+        mpin.makeNewUser(userId);
+        mpin.startRegistration(userId, function (err1, data1) {
+          mpin.confirmRegistration(userId, function (err2, data2) {
+            mpin.finishRegistration(userId, userPin);
+            cb();
+          });
+        });
+      });
+    };
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when call finish Authentication w/o setupFlow", function (done) {
+    mpin.finishAuthentication(userId, "test", function (err, data) {
+      expect(err).to.deep.equal({code: 6, type: Errors.wrongFlow});
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when call finish Authentication w/o startAuthentication", function (done) {
+    this.setupFlow(function () {
+      mpin.finishAuthentication(userId, "test", function (err, data) {
+        expect(err).to.have.deep.property("type", Errors.wrongFlow);
+        done();
+      });
+    });
+  });
+
+  it("should return error type " + Errors.wrongPin + " when auth request fail with 401", function (done) {
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields({status: 401}, null); //auth
+    this.setupFlow(function () {
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, "test", function (err2, data2) {
+          expect(err2).to.have.deep.property("type", Errors.wrongPin);
+          done();
+        });
+      });
+    });
+  });
+
+  it("should return error type " + Errors.wrongPin + " when auth request fail with 410", function (done) {
+    var authOut = null;
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields({status: 410}, null); //auth
+    this.setupFlow(function () {
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, "test", function (err2, data2) {
+          expect(err2).to.have.deep.property("type", Errors.wrongPin);
+          done();
+        });
+      });
+    });
+  });
+
+  it("should hash pin if PIN is not an number", function (done) {
+    var authOut = null, spyHash, userPass = "testPass";
+
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields(null, authOut); //auth
+    this.setupFlow(function () {
+      spyHash = sinon.spy(mpin, "toHash");
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, userPass, function (err2, data2) {
+          expect(spyHash.calledOnce).to.be.true;
+          expect(spyHash.calledWith(userPass)).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+
+  it("should return ok without data when response did not return such", function (done) {
+    var authOut = null;
+    stub.onCall(4).yields(null, testData.tp1);//tp1
+    stub.onCall(5).yields({status: 404}, null);//timePermitStorage
+    stub.onCall(6).yields(null, testData.tp2); //tp2
+    stub.onCall(7).yields(null, testData.pass1); //pass1
+    stub.onCall(8).yields(null, testData.pass2); //pass2
+
+    stub.onCall(9).yields(null, authOut); //auth
+    this.setupFlow(function () {
+      mpin.startAuthentication(userId, function (err, data) {
+        mpin.finishAuthentication(userId, "test", function (err2, data2) {
+          expect(err2).to.be.a('null');
+          expect(data2).to.be.a('null');
+          done();
+        });
+      });
+    });
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/index.html
----------------------------------------------------------------------
diff --git a/test/index.html b/test/index.html
index eba574f..1708549 100644
--- a/test/index.html
+++ b/test/index.html
@@ -32,7 +32,9 @@ and open the template in the editor.
 
 		</script>
 
-		<script src="index.js"></script> 
+		<script src="init.js"></script>
+		<script src="index.js"></script>
+		<script src="auth.js"></script>
 		<script>
 
       mocha.run();

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
index afa7924..1e836bb 100644
--- a/test/index.js
+++ b/test/index.js
@@ -22,39 +22,32 @@ if (typeof require !== 'undefined') {
   var expect = require('chai').expect;
   var sinon = require('sinon');
   var sinonChai = require('sinon-chai');
-  //used to generate test coverage with blanket
-  //  var mpinjs = require('../index');
-  var mpinjs = require('../dist/mpinjs');
+  var mpinjs = require('../index');
+  var inits = require("./init");
 }
+var Errors, testData, testLocalstorage, testLocalStorage2;
 
-var Errors = [];
-Errors[0] = "MISSING_USERID";
-Errors[1] = "INVALID_USERID";
-Errors[2] = "MISSING_PARAMETERS";
-Errors[3] = "IDENTITY_NOT_VERIFIED";
-
-var testLocalstorage = {
-  "accounts": {
-    "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
-      "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
-      "state": "STARTED"
-    }
-  }
-};
-
-describe('# Constructor initialization without server Url.', function () {
-  it('should throw Error', function () {
+Errors = inits.Errors;
+MPINAuth = inits.MPINAuth;
+MPIN = inits.MPIN;
+testData = inits.testData;
+testLocalstorage = inits.testLocalStorage;
+testLocalStorage2 = inits.testLocalStorage2;
+
+
+describe("# Constructor initialization without sever Url.", function () {
+  it("should throw Error", function () {
     var mpin = new mpinjs();
     expect(mpin).to.be.an.instanceof(Error);
   });
 });
 
 //spy cases
-describe('# Normal iniatilization.', function () {
-  var mpin, spy, serverUrl = "http://192.168.10.63:8005";
+describe("# Normal initialization.", function () {
+  var mpin, spy;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
+    mpin = new mpinjs({server: testData.serverUrl});
     spy = sinon.spy();
 
     mpin.request = spy;
@@ -63,28 +56,23 @@ describe('# Normal iniatilization.', function () {
     });
   });
 
-  it('should call request method once', function () {
+  it("should call request method once", function () {
     mpin.init();
     expect(spy.calledOnce).to.be.true;
   });
 
-  it('should call request method with settingsUrl params', function () {
+  it("should call request method with settingsUrl params", function () {
     mpin.init();
-    expect(spy.calledWith({url: serverUrl + "/rps/clientSettings"})).to.be.true;
+    expect(spy.calledWith({url: testData.serverUrl + "/rps/clientSettings"})).to.be.true;
   });
 });
 
-describe('# Init method > clientSettings request.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
+describe("# Init method > clientSettings request.", function () {
+  var mpin;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
+    mpin = new mpinjs({server: testData.serverUrl});
 
-    this.fakeRes = {
-      requestOTP: false,
-      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
-      registerUrl: "http://192.168.10.63:8011/rps/user"
-    };
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
@@ -96,7 +84,7 @@ describe('# Init method > clientSettings request.', function () {
     done();
   });
 
-  it('should return error if init response is wrong', function (done) {
+  it("should return error if init response is wrong", function (done) {
     sinon.stub(mpin, 'request').yields({}, null);
     mpin.init(function (err, data) {
       expect(err).to.exist;
@@ -104,8 +92,8 @@ describe('# Init method > clientSettings request.', function () {
     });
   });
 
-  it('should store init response into internal property', function (done) {
-    sinon.stub(mpin, 'request').yields(null, JSON.stringify(this.fakeRes));
+  it("should store init response into internal property", function (done) {
+    sinon.stub(mpin, 'request').yields(null, testData.clientSettings);
     mpin.init(function (err, data) {
       expect(data).to.be.true;
       done();
@@ -114,43 +102,39 @@ describe('# Init method > clientSettings request.', function () {
 
 });
 
-describe('# makeNewUser checks.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
+describe("# makeNewUser checks.", function () {
+  var mpin;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
+    mpin = new mpinjs({server: testData.serverUrl});
+
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
+//    sinon.stub(mpin, "addToUser");
   });
 
   after(function () {
     mpin.restore();
   });
 
-  it('should makeNewUser return error type ' + Errors[0] + ' when call without userId', function () {
+  it("should makeNewUser return error type " + Errors.missingUserId + " when call without userId", function () {
     var user = mpin.makeNewUser();
-    expect(user).to.deep.equal({code: 0, type: Errors[0]});
+    expect(user).to.deep.equal({code: 0, type: Errors.missingUserId});
   });
 
-  it('should store user into internal list', function () {
+  it("should store user into internal list", function () {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     expect(mpin.checkUser(userId)).to.be.true;
   });
 });
 
-describe('# startRegistration.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
+describe("# startRegistration.", function () {
+  var mpin;
 
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
-
-    this.fakeRes = {
-      requestOTP: false,
-      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
-      registerURL: "http://192.168.10.63:8011/rps/user"
-    };
+    mpin = new mpinjs({server: testData.serverUrl});
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
@@ -160,23 +144,22 @@ describe('# startRegistration.', function () {
     mpin.restore();
   });
 
-
-  it('should return error type ' + Errors[0] + ', call without userId', function (done) {
+  it("should return error type " + Errors.missingUserId + ", call without userId", function (done) {
     mpin.startRegistration(null, function (err, data) {
-      expect(err).to.deep.equal({code: 0, type: Errors[0]});
+      expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
       done();
     });
   });
 
-  it('should return error type ' + Errors[1] + ' if skip makeNewUser method.', function (done) {
+  it("should return error type " + Errors.invalidUserId + " if skip makeNewUser method.", function (done) {
     var userId = "test@user.id";
     mpin.startRegistration(userId, function (err, data) {
-      expect(err).to.deep.equal({code: 1, type: Errors[1]});
+      expect(err).to.deep.equal({code: 1, type: Errors.invalidUserId});
       done();
     });
   });
 
-  it('should return error type ' + Errors[2] + ' if skip init method.', function (done) {
+  it("should return error type " + Errors.missingParams + " if skip init method.", function (done) {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     mpin.startRegistration(userId, function (err, data) {
@@ -185,14 +168,12 @@ describe('# startRegistration.', function () {
     });
   });
 
-  it('should return OK.', function (done) {
+  it("should return OK.", function (done) {
     var userId = "test@user.id";
 
     //mock for init method
-    sinon.stub(mpin, 'request').yields(null, this.fakeRes);
-
+    sinon.stub(mpin, 'request').yields(null, testData.clientSettings);
     mpin.init(function (err, data) {
-
       mpin.makeNewUser(userId);
       mpin.startRegistration(userId, function (err1, data1) {
         expect(data).to.exist;
@@ -203,27 +184,10 @@ describe('# startRegistration.', function () {
 });
 
 
-describe('# confirmRegistration.', function () {
-  var mpin, serverUrl = "http://192.168.10.63:8005";
-
+describe("# confirmRegistration.", function () {
+  var mpin;
   before(function () {
-    mpin = new mpinjs({server: serverUrl});
-
-    this.fakeRes = {
-      requestOTP: false,
-      mpinAuthServerURL: "http://192.168.10.63:8011/rps",
-      registerURL: "http://192.168.10.63:8011/rps/user",
-      signatureURL: "http://192.168.10.63:8011/rps/signature",
-      certivoxURL: "https://community-api.certivox.net/v3/"
-    };
-
-    this.fakeCs1 = {
-      clientSecretShare: "0421e379eb45e56ce699f0a7a83b683e84944b63fcc93a2834a4769ea40a28dc3f2064cd9d64846304999e00008b0838e246d3ea06d0013f1080c1027d54630ca9",
-      params: "mobile=0&expires=2015-12-03T12%3A47%3A23Z&app_id=e340a9f240e011e5b23b06df5546c0ed&hash_mpin_id=07a9af5af89d66b969be31d3d4e29c2a0a5ad4d3e30432eed9b3915dbf52230a&signature=33e8e987b07a2d9c9f3d98f68268870ef104cd0e0b9e02ba2c55e8bbf5190913&hash_user_id="
-    };
-    this.fakeCs2 = {
-      clientSecret: "0409ba1a247561ab16c35df3ad0ca9846db9968fa28757005335dc2ca35188b4f51521ac97d45bbdb3a8d1c0fdfe79ab29031054534df8b7cbac12e67e4e99d685"
-    };
+    mpin = new mpinjs({server: testData.serverUrl});
     sinon.stub(mpin, "getData", function () {
       return testLocalstorage;
     });
@@ -234,53 +198,35 @@ describe('# confirmRegistration.', function () {
     mpin.request.restore && mpin.request.restore();
   });
 
-
-  it('should return error type ' + Errors[0] + ' call without userId', function (done) {
+  it("should return error type " + Errors.missingUserId + " call without userId", function (done) {
     mpin.confirmRegistration(null, function (err, data) {
-      expect(err).to.deep.equal({code: 0, type: Errors[0]});
+      expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
       done();
     });
   });
 
-  it('should return error type ' + Errors[1] + '  if skip makeNewUser method.', function (done) {
+  it("should return error type " + Errors.invalidUserId + " if skip makeNewUser method.", function (done) {
     var userId = "test@user.id";
     mpin.confirmRegistration(userId, function (err, data) {
-      expect(err).to.have.deep.property('type', Errors[1]);
+      expect(err).to.have.deep.property('type', Errors.invalidUserId);
       done();
     });
   });
 
-  it('should return error type ' + Errors[2] + ' if skip init method.', function (done) {
+  it("should return error type " + Errors.missingParams + " if skip init method.", function (done) {
     var userId = "test@user.id";
     mpin.makeNewUser(userId);
     mpin.confirmRegistration(userId, function (err, data) {
-      expect(err).to.have.deep.property('type', Errors[2]);
+      expect(err).to.have.deep.property('type', Errors.missingParams);
       done();
     });
   });
-  /*
-   //start REGISTRATION >>>
-   it('should return error 4 if skip init method.', function (done) {
-   var userId = "test@user.id";
-   
-   sinon.stub(mpin, 'request').yields(null, this.fakeRes);
-   mpin.init(function (err, data) {
-   mpin.makeNewUser(userId);
-   //      sinon.stub(mpin, 'request').yields({status: 401}, null);
-   mpin.confirmRegistration(userId, function (err, data) {
-   console.log("err", err);
-   expect(err).to.have.deep.property('error', 4);
-   done();
-   });
-   });
-   });
-   */
-
-  it('should return error type ' + Errors[3] + ' identity not verify.', function (done) {
+
+  it("should return error type " + Errors.identityNotVerified + " identity not verify.", function (done) {
     var userId = "test@user.id", stub;
 
     stub = sinon.stub(mpin, 'request');
-    stub.onCall(0).yields(null, this.fakeRes);
+    stub.onCall(0).yields(null, testData.clientSettings);
     stub.onCall(1).yields(null, {});
     stub.onCall(2).yields({status: 401}, null);
 
@@ -288,7 +234,7 @@ describe('# confirmRegistration.', function () {
       mpin.makeNewUser(userId);
       mpin.startRegistration(userId, function (err1, data1) {
         mpin.confirmRegistration(userId, function (err2, data2) {
-          expect(err2).to.have.deep.property('type', Errors[3]);
+          expect(err2).to.have.deep.property('type', Errors.identityNotVerified);
           done();
         });
       });
@@ -296,14 +242,15 @@ describe('# confirmRegistration.', function () {
   });
 
   //start REGISTRATION >>> OK
-  it('should return OK', function (done) {
+  it("should return OK", function (done) {
     var userId = "test@user.id", stub;
+    //define global cripto
 
     stub = sinon.stub(mpin, 'request');
-    stub.onCall(0).yields(null, this.fakeRes);
+    stub.onCall(0).yields(null, testData.clientSettings);
     stub.onCall(1).yields(null, {});//mpinId
-    stub.onCall(2).yields(null, this.fakeCs1);//cs1
-    stub.onCall(3).yields(null, this.fakeCs2);//cs2
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
 
     mpin.init(function (err, data) {
       mpin.makeNewUser(userId);
@@ -315,12 +262,179 @@ describe('# confirmRegistration.', function () {
       });
     });
   });
+});
+
+
+describe("# finishRegistration", function () {
+  var mpin, spy, userId = "test@user.id";
+
+  beforeEach(function () {
+    mpin = new mpinjs({server: testData.serverUrl});
+
+    sinon.stub(mpin, "getData", function () {
+      return testLocalstorage;
+    });
+
+    sinon.stub(mpin, "storeData");
+  });
+
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+  it("should return error type " + Errors.missingUserId + " call without userId", function () {
+    var err = mpin.finishRegistration();
+    expect(err).to.deep.equal({code: 0, type: Errors.missingUserId});
+  });
+
+  it("should call getUser (with userId arguments) to validate user state", function () {
+    spy = sinon.spy(mpin, "getUser");
+    mpin.finishRegistration(userId);
+    expect(spy.calledOnce).to.be.true;
+    expect(spy.calledWith(userId)).to.be.true;
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when didn't activate identity", function () {
+    mpin.makeNewUser(userId);
+    var err2 = mpin.finishRegistration(userId);
+    expect(err2).to.have.deep.property('type', Errors.wrongFlow);
+  });
+
+  it("should hash pin if PIN is not an number", function (done) {
+    var userPin = "userSecret";
+    spy = sinon.spy(mpin, "toHash");
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          mpin.finishRegistration(userId, userPin);
+          expect(spy.calledOnce).to.be.true;
+          expect(spy.calledWith(userPin)).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+
+  it("should save user state register", function (done) {
+    var userPin = "userSecret";
+
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);
+    stub.onCall(1).yields(null, testData.mpin);//mpinId
+    stub.onCall(2).yields(null, testData.cs1);//cs1
+    stub.onCall(3).yields(null, testData.cs2);//cs2
+
+    mpin.init(function (err, data) {
+      mpin.makeNewUser(userId);
+      mpin.startRegistration(userId, function (err1, data1) {
+        mpin.confirmRegistration(userId, function (err2, data2) {
+          spy = sinon.spy(mpin, "addToUser");
+          mpin.finishRegistration(userId, userPin);
+          expect(spy.calledOnce).to.be.true;
+//          expect(spy.calledWith(userId, {token: "token", state: "REGISTERED"})).to.be.true;
+          done();
+        });
+      });
+    });
+  });
+});
 
 
 
+
+
+
+describe("# backward compatibility", function () {
+  var mpin;
+  beforeEach(function (done) {
+    mpin = new mpinjs({server: testData.serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalStorage2;
+    });
+    sinon.stub(mpin, 'request').yields(null, testData.clientSettings);
+
+    mpin.init(function (err, data) {
+      done();
+    });
+  });
+
+  it("read all identities and setup proper state", function () {
+    var users;
+    users = mpin.listUsers();
+    expect(users).to.have.length(2);
+    expect(users[0]).to.have.deep.property("state", "STARTED");
+    expect(users[1]).to.have.deep.property("state", "REGISTERED");
+  });
 });
 
+describe("# restartRegistration", function () {
+  var mpin;
+  beforeEach(function (done) {
+    mpin = new mpinjs({server: testData.serverUrl});
+    sinon.stub(mpin, "getData", function () {
+      return testLocalStorage2;
+    });
+    stub = sinon.stub(mpin, 'request');
+    stub.onCall(0).yields(null, testData.clientSettings);//put user
+    
+    mpin.init(function (err, data) {
+      done();
+    });
+  });
 
-describe('# confirmRegistration.', function () {
+  afterEach(function () {
+    mpin.restore();
+    mpin.request.restore && mpin.request.restore();
+  });
+
+  it("should return error type " + Errors.missingUserId + " when call w/o user", function (done) {
+    mpin.restartRegistration(null, function (err, data) {
+      expect(err).to.have.deep.property("type", Errors.missingUserId);
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.invalidUserId + " when call with unexisting user", function (done) {
+    mpin.restartRegistration("nonExistUser", function (err, data) {
+      expect(err).to.have.deep.property("type", Errors.invalidUserId);
+      done();
+    });
+  });
+
+  it("should return error type " + Errors.wrongFlow + " when call userId different state from started", function (done) {
+    mpin.restartRegistration("dddsre@mailinator.com", function (err, data) {
+      expect(err).to.have.deep.property("type", Errors.wrongFlow);
+      done();
+    });
+  });
+
+  it("should return error if request fail", function (done) {
+    sinon.stub(mpin, "storeData");
+
+    stub.onCall(1).yields({status: 401}, null);//put user
+    mpin.restartRegistration("aaa@bbb.com", function (err, data) {
+      expect(err).to.have.deep.property("status", 401);
+      done();
+    });
+  });
+
+  it("should return ok when request is ok", function (done) {
+    sinon.stub(mpin, "storeData");
+
+    stub.onCall(1).yields(null, true);//put user
+    mpin.restartRegistration("aaa@bbb.com", function (err, data) {
+      expect(data).to.be.ok;
+      done();
+    });
+  });
+});
 
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/4f0e481a/test/init.js
----------------------------------------------------------------------
diff --git a/test/init.js b/test/init.js
new file mode 100644
index 0000000..4848170
--- /dev/null
+++ b/test/init.js
@@ -0,0 +1,142 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+//if browser
+var inits = function () {
+  var Errors, MPINAuth, MPIN, testData, testLocalStorage, testLocalStorage2;
+
+  Errors = [];
+  Errors.missingUserId = "MISSING_USERID";
+  Errors.invalidUserId = "INVALID_USERID";
+  Errors.missingParams = "MISSING_PARAMETERS";
+  Errors.identityNotVerified = "IDENTITY_NOT_VERIFIED";
+  Errors.identityMissing = "IDENTITY_MISSING";
+  Errors.wrongPin = "WRONG_PIN";
+  Errors.wrongFlow = "WRONG_FLOW";
+  Errors.userRevoked = "USER_REVOKED";
+
+  //overwrite global crypto function
+  MPINAuth = {};
+  MPINAuth.addShares = function () {
+    return "040a23a7e6d381a6dbd8b806013f07d40be36b42723ad3b1d986e4bbbe9ece83f421c504a4258cf87251af4ea7e847e4da46730034fc880f92d885c419716cb944";
+  };
+  MPINAuth.calculateMPinToken = function () {
+    return "04236eb28be98764e379049a2c4371752e7e3adc99a844800b9de2c34d2c70d95b07354c556276cbf79cee9e601807e6166d9bffedc3c1b1909ab5bf63330e2131";
+  };
+  MPINAuth.pass1Request = function () {
+    return {};
+  };
+  MPINAuth.pass2Request = function () {
+    return {};
+  };
+
+  MPIN = {};
+  MPIN.stringtobytes = function () {
+    return "";
+  }
+  MPIN.HASH_ID = function () {
+    return "";
+  }
+  MPIN.bytestostring = function () {
+    return "";
+  }
+
+  testData = {};
+  testData.serverUrl = "http://192.168.10.63:8005";
+  testData.clientSettings = {
+    requestOTP: false,
+    mpinAuthServerURL: "http://192.168.10.63:8011/rps",
+    registerURL: "http://192.168.10.63:8011/rps/user",
+    signatureURL: "http://192.168.10.63:8011/rps/signature",
+    certivoxURL: "https://community-api.certivox.net/v3/",
+    timePermitsURL: "http://192.168.10.63:8011/rps/timePermit"
+  };
+  testData.mpin = {
+    mpinId: "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30332d31352031333a34323a33362e393437303338222c2022757365724944223a20226d70696e4444222c202273616c74223a20226437373831313162633762653537323662666162633930353435396631643230227d"
+  };
+  testData.cs1 = {
+    clientSecretShare: "0421e379eb45e56ce699f0a7a83b683e84944b63fcc93a2834a4769ea40a28dc3f2064cd9d64846304999e00008b0838e246d3ea06d0013f1080c1027d54630ca9",
+    params: "mobile=0&expires=2015-12-03T12%3A47%3A23Z&app_id=e340a9f240e011e5b23b06df5546c0ed&hash_mpin_id=07a9af5af89d66b969be31d3d4e29c2a0a5ad4d3e30432eed9b3915dbf52230a&signature=33e8e987b07a2d9c9f3d98f68268870ef104cd0e0b9e02ba2c55e8bbf5190913&hash_user_id="
+  };
+  testData.cs2 = {
+    clientSecret: "0409ba1a247561ab16c35df3ad0ca9846db9968fa28757005335dc2ca35188b4f51521ac97d45bbdb3a8d1c0fdfe79ab29031054534df8b7cbac12e67e4e99d685"
+  };
+  testData.tp1 = {
+    "timePermit": "04145085669aa20607c0da730c01c707010e546bb81cf17abc29cacfef8e162b0f097b547c7058f6bd88e55cadc721b5721ee9730bfb10fa239c5bfacdb62fa3f4",
+    "signature": "39f9e16201d05dd3e369d43bd73cf0249e5bac01d5ff2975640d988e4a37b7f5",
+    "date": 16876
+  };
+  testData.tp2 = {
+    "timePermit": "040ff870574cb3c923410fdf33681beacd6ca6eeeb8858150efbf1241da9202c5604977ae285410df0d86a9976611b255a6fcbeeaf22bb398e4859ff3348bb4d87"
+  };
+  testData.pass1 = {
+    "y": "1dacb1f6830de09c0697485159da2ba4ed2908a8e24a85b886ff284306738b31"
+  };
+  testData.pass2 = {
+    "authOTT": "b0784ab9b6759953a3c6da85bdbdbaf3"
+  };
+  testData.auth = {
+    "authOTT": "b0784ab9b6759953a3c6da85bdbdbaf3"
+  };
+
+  testLocalStorage = {
+    "accounts": {
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d32332031363a34393a31302e313039363734222c2022757365724944223a20227465737440746573742e636f6d222c202273616c74223a20223162396336353564343665323238373661333631373033353138616636363037227d": {
+        "regOTT": "4ac1cca55c09f6d4e47a253d8cd503b5",
+        "state": "STARTED"
+      }
+    }
+  };
+
+  testLocalStorage2 = {
+    "defaultIdentity": "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d30332031363a31333a32362e333030393938222c2022757365724944223a2022616161406262622e636f6d222c202273616c74223a20223237386166373433663465373034363764323334313936323262316333616231227d",
+    "version": "0.3",
+    "accounts": {
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d30332031363a31333a32362e333030393938222c2022757365724944223a2022616161406262622e636f6d222c202273616c74223a20223237386166373433663465373034363764323334313936323262316333616231227d": {
+        "MPinPermit": "",
+        "token": "",
+        "regOTT": "b6216da7e3224e07eb4791815bcfcaa6"
+      },
+      "7b226d6f62696c65223a20302c2022697373756564223a2022323031362d30322d30382030383a35383a34302e373737373130222c2022757365724944223a2022646464737265406d61696c696e61746f722e636f6d222c202273616c74223a20223831373539623463313032363666646431616337323231326530643839393932227d": {
+        "MPinPermit": "042235a80c4c24f25a8a61758d3dac87d72b693c989ef95704c2ba51c7f4d98a631c912c9dc48435d9dd1af3dc17fa7d9e2af9beb16cc77bd38150c4697efdf232",
+        "token": "0412e48b124199f683e0ea6b8a1f1b073013dce21610de4b54cac74696e02003b1147d3ad7b4cef542c6ef61726dc4ffba039c90f7edd17cbeafb7c0737b41fc82",
+        "regOTT": "11adb574045ffe27e718d8b4dc665887",
+        "timePermitCache": {
+          "date": 16867,
+          "timePermit": "041c990c4087b5eeb7f4c2dbe5869794c208a22f63f6485a8905b35f542b2136a91cccf0696a6c60b2208ff1d3178da8fa661f7a52dda7db2738bfb1fe8b6cfa4b"
+        }
+      }
+    },
+    "deviceName": "winChrome"
+  };
+
+  return {
+    Errors: Errors,
+    MPINAuth: MPINAuth,
+    MPIN: MPIN,
+    testData: testData,
+    testLocalStorage: testLocalStorage,
+    testLocalStorage2: testLocalStorage2
+  };
+}();
+
+if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
+  module.exports = inits;
+else
+  window.inits = inits;



[08/37] incubator-milagro-mfa-js-lib git commit: Tightening up naming conventions.

Posted by sa...@apache.org.
Tightening up naming conventions.


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/11db8398
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/11db8398
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/11db8398

Branch: refs/heads/add-documentation
Commit: 11db83982824506f4c8979300591935983f2344f
Parents: f272668
Author: Simeon Aladjem <si...@certivox.com>
Authored: Tue Dec 22 14:18:49 2015 +0200
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Tue Dec 22 14:18:49 2015 +0200

----------------------------------------------------------------------
 example/exampleJquery.html |  16 ++---
 lib/mpin.js                | 140 ++++++++++++++++++++--------------------
 2 files changed, 78 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/11db8398/example/exampleJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleJquery.html b/example/exampleJquery.html
index de1b29e..cf86013 100644
--- a/example/exampleJquery.html
+++ b/example/exampleJquery.html
@@ -51,10 +51,10 @@ and open the template in the editor.
           for (var i in mpinUsers) {
             htmlList += "<li>" + mpinUsers[i].userId + "&nbsp;&nbsp;&nbsp;";
             htmlList += "<input type='text' placeholder='PIN' size='10'>&nbsp;&nbsp;&nbsp;";
-            if (mpinUsers[i].status === "REGISTERED") {
-              htmlList += "<span class='registered' data-userid='" + mpinUsers[i].userId + "' data-status='" + mpinUsers[i].status + "'>Authenticate</span>";
+            if (mpinUsers[i].state === "REGISTERED") {
+              htmlList += "<span class='registered' data-userid='" + mpinUsers[i].userId + "' data-state='" + mpinUsers[i].state + "'>Authenticate</span>";
             } else {
-              htmlList += "<span class='setup' data-userid='" + mpinUsers[i].userId + "' data-status='" + mpinUsers[i].status + "'>Setup</span>";
+              htmlList += "<span class='setup' data-userid='" + mpinUsers[i].userId + "' data-state='" + mpinUsers[i].state + "'>Setup</span>";
             }
             htmlList += "</span></li>";
           }
@@ -65,12 +65,12 @@ and open the template in the editor.
 
 
         $(document).on('click', ".setup", function (ev) {
-          var thisElem, userId, userPin, status;
+          var thisElem, userId, userPin, state;
 
           thisElem = $(ev.currentTarget);
           userId = thisElem.data('userid');
           userPin = thisElem.prev("input").val();
-          status = thisElem.data('status');
+          state = thisElem.data('state');
 
           mpin.startRegistration(userId, function (err3, data3) {
             mpin.confirmRegistration(userId, function (err, data) {
@@ -94,10 +94,10 @@ and open the template in the editor.
 
 
         $(document).on('click', ".registered", function (ev) {
-          var userId, userPin, status;
+          var userId, userPin, state;
           userId = $(ev.currentTarget).data('userid');
           userPin = $(ev.currentTarget).prev("input").val();
-          status = $(ev.currentTarget).data('status');
+          state = $(ev.currentTarget).data('state');
 
           mpin.startAuthentication(userId, function (err, data) {
             if (err) {
@@ -137,7 +137,7 @@ and open the template in the editor.
 
 
         function chkUser (userId) {
-          var userStatus = mpin.getUser(userId, "status");
+          var userState = mpin.getUser(userId, "state");
 
           mpin.confirmRegistration(userId, function (err, data) {
             //not Active Identity

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/11db8398/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 7db5fd7..7ae1e67 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -18,22 +18,22 @@
  */
 
 var mpinjs = (function () {
-  var Mpin, Users = {}, Errors = {}, Status = {};
-
-  Errors.missingUserId = {code: 0, type: "MISSING_USERID"};
-  Errors.invalidUserId = {code: 1, type: "INVALID_USERID"};
-  Errors.missingParams = {code: 2, type: "MISSING_PARAMETERS"};
-  Errors.identityNotVerified = {code: 3, type: "IDENTITY_NOT_VERIFIED"};
-  Errors.identityMissing = {code: 4, type: "IDENTITY_MISSING"};
-  Errors.wrongPin = {code: 5, type: "WRONG_PIN"};
-  Errors.wrongFlow = {code: 6, type: "WRONG_FLOW"};
-  Errors.timeoutFinish = {code: 7, type: "TIMEOUT_FINISH"};
-
-  Status.invalid = "INVALID";
-  Status.start = "STARTED";
-  Status.active = "ACTIVATED";
-  Status.register = "REGISTERED";
-  Status.block = "BLOCKED";
+  var Mpin, Users = {}, Error = {}, State = {};
+
+  Error.missingUserId = {code: 0, type: "MISSING_USERID"};
+  Error.invalidUserId = {code: 1, type: "INVALID_USERID"};
+  Error.missingParams = {code: 2, type: "MISSING_PARAMETERS"};
+  Error.identityNotVerified = {code: 3, type: "IDENTITY_NOT_VERIFIED"};
+  Error.identityMissing = {code: 4, type: "IDENTITY_MISSING"};
+  Error.wrongPin = {code: 5, type: "WRONG_PIN"};
+  Error.wrongFlow = {code: 6, type: "WRONG_FLOW"};
+  Error.timeoutFinish = {code: 7, type: "TIMEOUT_FINISH"};
+
+  State.invalid = "INVALID";
+  State.start = "STARTED";
+  State.active = "ACTIVATED";
+  State.register = "REGISTERED";
+  State.block = "BLOCKED";
 
   Mpin = function (options) {
     if (!options || !options.server) {
@@ -72,10 +72,10 @@ var mpinjs = (function () {
 
   Mpin.prototype.makeNewUser = function (userId, deviceId) {
     if (!userId) {
-      return Errors.missingUserId;
+      return Error.missingUserId;
     }
 
-    this.addToUser(userId, {userId: userId, deviceId: deviceId, status: Status.invalid});
+    this.addToUser(userId, {userId: userId, deviceId: deviceId, state: State.invalid});
 
     return this;
   };
@@ -83,11 +83,11 @@ var mpinjs = (function () {
   Mpin.prototype.startRegistration = function (userId, cb) {
     var _reqData = {}, self = this;
     if (!userId) {
-      return cb ? cb(Errors.missingUserId, null) : {error: 1};
+      return cb ? cb(Error.missingUserId, null) : {error: 1};
     } else if (!this.checkUser(userId)) {
-      return cb(Errors.invalidUserId, null);
+      return cb(Error.invalidUserId, null);
     } else if (!this.opts.registerURL) {
-      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
+      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing registerURL"}, null);
     }
 
     _reqData.url = this.generateUrl("register");
@@ -102,11 +102,11 @@ var mpinjs = (function () {
         return cb(err, null);
       }
 
-      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId, status: Status.start});
+      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId, state: State.start});
 
       //force activate
       if (data.active) {
-        self.addToUser(userId, {status: Status.active});
+        self.addToUser(userId, {state: State.active});
       }
 
       cb && cb(null, true);
@@ -115,19 +115,19 @@ var mpinjs = (function () {
 
   //request cs1 + cs2
   Mpin.prototype.confirmRegistration = function (userId, cb) {
-    var _cs1Url = "", self = this, _userStatus;
+    var _cs1Url = "", self = this, _userState;
     if (!userId) {
-      return cb ? cb(Errors.missingUserId, null) : Errors.missingUserId;
+      return cb ? cb(Error.missingUserId, null) : Error.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return cb(Errors.invalidUserId, null);
+      return cb(Error.invalidUserId, null);
     } else if (!this.opts.signatureURL) {
-      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing signatureURL option."}, null);
+      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing signatureURL option."}, null);
     }
 
     //started || activated
-    _userStatus = this.getUser(userId, "status");
-    if (_userStatus !== Status.start && _userStatus !== Status.active) {
-      return cb(Errors.wrongFlow, null);
+    _userState = this.getUser(userId, "state");
+    if (_userState !== State.start && _userState !== State.active) {
+      return cb(Error.wrongFlow, null);
     }
 
     //already set.
@@ -141,13 +141,13 @@ var mpinjs = (function () {
       var _cs2Url = "";
       if (err) {
         if (err.status == 401) {
-          return cb(Errors.identityNotVerified, null);
+          return cb(Error.identityNotVerified, null);
         } else if (err.status == 400) {
-          return cb(Errors.wrongFlow, null);
+          return cb(Error.wrongFlow, null);
         }
       }
 
-      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, status: Status.active});
+      self.addToUser(userId, {cs1: cs1Data.clientSecretShare, csParams: cs1Data.params, state: State.active});
       _cs2Url = self.opts.certivoxURL + "clientSecret?" + cs1Data.params;
 
       //req cs2
@@ -170,19 +170,19 @@ var mpinjs = (function () {
     var _user, token;
 
     if (!userId) {
-      return Errors.missingUserId;
+      return Error.missingUserId;
     }
 
     _user = this.getUser(userId);
 
-    if (_user.status !== Status.active) {
-      return Errors.wrongFlow;
+    if (_user.state !== State.active) {
+      return Error.wrongFlow;
     }
 
     token = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
     delete Users[userId].csHex;
 
-    this.addToUser(userId, {token: token, status: Status.register});
+    this.addToUser(userId, {token: token, state: State.register});
 
     return true;
   };
@@ -196,20 +196,20 @@ var mpinjs = (function () {
 
 
   Mpin.prototype.startAuthentication = function (userId, cb) {
-    var _tp1Url, self = this, _userStatus;
+    var _tp1Url, self = this, _userState;
 
     if (!userId) {
-      return cb ? cb(Errors.missingUserId, null) : Errors.missingUserId;
+      return cb ? cb(Error.missingUserId, null) : Error.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return cb(Errors.invalidUserId, null);
+      return cb(Error.invalidUserId, null);
     } else if (!this.opts.timePermitsURL || !this.opts.certivoxURL) {
-      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing timePermitsURL or/and certivoxURL option."}, null);
+      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing timePermitsURL or/and certivoxURL option."}, null);
     }
 
     //registered
-    _userStatus = this.getUser(userId, "status");
-    if (_userStatus !== Status.register) {
-      return cb(Errors.wrongFlow, null);
+    _userState = this.getUser(userId, "state");
+    if (_userState !== State.register) {
+      return cb(Error.wrongFlow, null);
     }
 
     //checkUser
@@ -270,28 +270,28 @@ var mpinjs = (function () {
 
 
   Mpin.prototype.finishAuthentication = function (userId, aPin, cb) {
-    var _userStatus;
+    var _userState;
 
     //registered
-    _userStatus = this.getUser(userId, "status");
-    if (_userStatus !== Status.register) {
-      return cb(Errors.wrongFlow, null);
+    _userState = this.getUser(userId, "state");
+    if (_userState !== State.register) {
+      return cb(Error.wrongFlow, null);
     } else if (!Users[userId].timePermitHex) {
-      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+      return cb({code: Error.wrongFlow.code, type: Error.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
     this._passRequests({userId: userId, aPin: aPin}, cb);
   };
 
   Mpin.prototype.finishAuthenticationOtp = function (userId, aPin, cb) {
-    var _userStatus;
+    var _userState;
 
     //registered
-    _userStatus = this.getUser(userId, "status");
-    if (_userStatus !== Status.register) {
-      return cb(Errors.wrongFlow, null);
+    _userState = this.getUser(userId, "state");
+    if (_userState !== State.register) {
+      return cb(Error.wrongFlow, null);
     } else if (!Users[userId].timePermitHex) {
-      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+      return cb({code: Error.wrongFlow.code, type: Error.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
     this._passRequests({userId: userId, aPin: aPin, otp: true}, function (err, data) {
@@ -361,12 +361,12 @@ var mpinjs = (function () {
     this.request(_authData, function (authErr, authData) {
       if (authErr) {
         if (authErr.status === 401) {
-          return cb(Errors.wrongPin, null);
+          return cb(Error.wrongPin, null);
         } else if (authErr.status === 410) {
-          opts.userId && self.addToUser(opts.userId, {status: Status.block});
-          return cb(Errors.wrongPin, null);
+          opts.userId && self.addToUser(opts.userId, {state: State.block});
+          return cb(Error.wrongPin, null);
         } else {
-          return cb(Errors.wrongPin, null);
+          return cb(Error.wrongPin, null);
         }
       }
 
@@ -425,9 +425,9 @@ var mpinjs = (function () {
   Mpin.prototype.waitForMobileAuth = function (timeoutSeconds, requestSeconds, cb) {
     var self = this, _reqData = {};
     if (!this.webOTT) {
-      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call getAccessNumber method before this."}, null);
+      return cb({code: Error.wrongFlow.code, type: Error.wrongFlow.type, message: "Need to call getAccessNumber method before this."}, null);
     } else if (!timeoutSeconds) {
-      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing timeout/expiration period(in seconds)."}, null);
+      return cb({code: Error.missingParams.code, type: Error.missingParams.type, message: "Missing timeout/expiration period(in seconds)."}, null);
     }
 
 
@@ -451,7 +451,7 @@ var mpinjs = (function () {
           }, _requestPeriod);
           return;
         } else if (self.timeoutPeriod <= 0) {
-          cb && cb(Errors.timeoutFinish, null);
+          cb && cb(Error.timeoutFinish, null);
           return;
         }
       }
@@ -524,7 +524,7 @@ var mpinjs = (function () {
       listUsers[uKey] = {
         userId: Users[uKey].userId,
         deviceId: Users[uKey].deviceId || "",
-        status: Users[uKey].status || ""
+        state: Users[uKey].state || ""
       };
     }
     return listUsers;
@@ -537,15 +537,15 @@ var mpinjs = (function () {
   Mpin.prototype.getUser = function (userId, property) {
     var _user = {};
     if (!userId) {
-      return Errors.missingUserId;
+      return Error.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return Errors.invalidUserId;
+      return Error.invalidUserId;
     }
 
     _user = {
       userId: Users[userId].userId,
       deviceId: Users[userId].deviceId || "",
-      status: Users[userId].status
+      state: Users[userId].state
     };
 
     if (!property) {
@@ -560,9 +560,9 @@ var mpinjs = (function () {
     var mpinData = this.getData(), delMpinId;
 
     if (!userId) {
-      return Errors.missingUserId;
+      return Error.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return Errors.invalidUserId;
+      return Error.invalidUserId;
     }
 
     delMpinId = Users[userId].mpinId;
@@ -630,9 +630,9 @@ var mpinjs = (function () {
       mpinData.accounts[mpinId].token = upData.token;
     }
 
-    if (upData.status && Users[userId].mpinId) {
+    if (upData.state && Users[userId].mpinId) {
       var mpinId = Users[userId].mpinId;
-      mpinData.accounts[mpinId].status = upData.status;
+      mpinData.accounts[mpinId].state = upData.state;
     }
 
     //cache cache
@@ -664,7 +664,7 @@ var mpinjs = (function () {
         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);
+        mpinData.accounts[mpinId].state && (userData.state = mpinData.accounts[mpinId].state);
 
         //call add To user & skip Save
         this.addToUser(userId, userData, true);


[36/37] incubator-milagro-mfa-js-lib git commit: Merge remote-tracking branch 'github/master'

Posted by sa...@apache.org.
Merge remote-tracking branch 'github/master'


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/a745f8e8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/a745f8e8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/a745f8e8

Branch: refs/heads/add-documentation
Commit: a745f8e80883630b2e105b3b9a859e8f4a1eb363
Parents: 0a3dc9c 344133d
Author: Simeon Aladjem <si...@certivox.com>
Authored: Tue Mar 29 10:10:53 2016 +0300
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Tue Mar 29 10:10:53 2016 +0300

----------------------------------------------------------------------
 Gruntfile.js | 2 +-
 NOTICE       | 4 ++--
 bower.json   | 6 +++---
 3 files changed, 6 insertions(+), 6 deletions(-)
----------------------------------------------------------------------



[04/37] incubator-milagro-mfa-js-lib git commit: Add examples

Posted by sa...@apache.org.
Add examples


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/c86c030e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/c86c030e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/c86c030e

Branch: refs/heads/add-documentation
Commit: c86c030e8f7041e893c9067bd1fae326f28bce61
Parents: f84d8c7
Author: Boyan Bakov <bo...@certivox.com>
Authored: Fri Dec 11 14:37:10 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:25 2015 +0200

----------------------------------------------------------------------
 .gitignore                   |   1 -
 LICENSE                      | 202 +++++++++++++++++++++++++++++++++
 NOTICE                       |   5 +
 README.md                    |  37 +++++-
 example/exampleJquery.html   | 232 ++++++++++++++++++++++++++++++++++++++
 example/exampleNoJquery.html |  53 +++++++++
 lib/mpin.js                  | 203 +++++++++++++++++++++------------
 test/index.html              |  41 +++++++
 test/index.js                |  51 ++++++---
 9 files changed, 731 insertions(+), 94 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index eb737b3..18e0abb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,4 @@ dist/
 npm-debug.log
 bower_components/
 nbproject/
-index.html
 test/coverage.html

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2f3fee9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2015 MIRACL UK Ltd.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. 

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..111f042
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,5 @@
+Apache Open MIRACL M-Pin Clients
+Copyright 2015 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index c437278..337a5ce 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,49 @@
 # MPIN frontend library
 
 
+## Requirement for build & testing
+
+1. Nodejs
+2. Grunt
+3. Mocha
+4. bower
 
 ## Installation
 ```bash
 $ git clone
 $ cd project_folder
 $ npm install
+$ grunt build
 ```
 
-## Example
+## Example simple usage:
 
 - Registration
+
+```js
+var mpin = mpinjs({server: serverIP_port});
+
+mpin.init(callback);
+
+mpin.makeNewUser(userId);
+
+mpin.startRegistration(usrId, callback);
+
+mpin.confirmRegistration(userId, callback);
+
+mpin.finishRegistration(userId, userPin);
+
+```
 - Authentication
 
+```js
+mpin.startAuthentication(userId, callback);
+
+mpin.finishAuthentication(userId, userPin, callback);
+
+```
+
+
 ## Running Tests
 
 Install development dependencies:
@@ -35,8 +65,3 @@ Actively tested with node:
 ## Authors
 
   * MIRACL Ltd.
-
-## License 
-
-(The MIT License)
-

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/example/exampleJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleJquery.html b/example/exampleJquery.html
new file mode 100644
index 0000000..b8826cb
--- /dev/null
+++ b/example/exampleJquery.html
@@ -0,0 +1,232 @@
+<!DOCTYPE html>
+<!--
+To change this license header, choose License Headers in Project Properties.
+To change this template file, choose Tools | Templates
+and open the template in the editor.
+-->
+<html>
+  <head>
+    <title>Mpin JS SDK</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+		<script src="../dist/mpinjs.js" type="text/javascript"></script>
+		<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js" type="text/javascript"></script>
+	
+		<style>
+			fieldset {
+				margin: 0 auto;
+				width: 30%;
+			}
+
+			.notActivate {
+				color: red;
+				cursor: pointer;
+			}
+
+			.smallInput {
+				width: 100px;
+			}
+		</style>
+
+		<script type="text/javascript">
+      $(document).ready(function () {
+
+        //// MPIN init
+        window.mpin = mpin = new mpinjs({
+          server: "http://192.168.10.63:8005"
+        });
+
+        mpin.init(function (err, data) {
+          if (err) {
+            console.error("Wrong setup : ", err);
+          }
+
+          listUsers();
+        });
+
+        function listUsers () {
+          var mpinUsers = mpin.listUsers(), htmlList;
+
+          htmlList = "<ul>";
+          for (var i in mpinUsers) {
+            htmlList += "<li>" + mpinUsers[i].userId + "&nbsp;&nbsp;&nbsp;";
+            htmlList += "<input type='text' placeholder='PIN' size='10'>&nbsp;&nbsp;&nbsp;";
+            if (mpinUsers[i].status === "REGISTERED") {
+              htmlList += "<span class='registered' data-userid='" + mpinUsers[i].userId + "' data-status='" + mpinUsers[i].status + "'>Authenticate</span>";
+            } else {
+              htmlList += "<span class='setup' data-userid='" + mpinUsers[i].userId + "' data-status='" + mpinUsers[i].status + "'>Setup</span>";
+            }
+            htmlList += "</span></li>";
+          }
+          htmlList += "<ul>";
+
+          $("#mpinUsers").html(htmlList);
+        }
+
+
+        $(document).on('click', ".setup", function (ev) {
+          var thisElem, userId, userPin, status;
+
+          thisElem = $(ev.currentTarget);
+          userId = thisElem.data('userid');
+          userPin = thisElem.prev("input").val();
+          status = thisElem.data('status');
+
+          mpin.startRegistration(userId, function (err3, data3) {
+            mpin.confirmRegistration(userId, function (err, data) {
+              if (err) {
+                console.error("Error :1::", err);
+                return;
+              }
+
+              var finish = mpin.finishRegistration(userId, userPin);
+              if (finish.error) {
+                console.error("Error :::", finish.error);
+                return;
+              }
+
+              thisElem.append(" :: Successful");
+            });
+
+          });
+
+        });
+
+
+        $(document).on('click', ".registered", function (ev) {
+          var userId, userPin, status;
+          userId = $(ev.currentTarget).data('userid');
+          userPin = $(ev.currentTarget).prev("input").val();
+          status = $(ev.currentTarget).data('status');
+
+          mpin.startAuthentication(userId, function (err, data) {
+            if (err) {
+              console.error("Error :::", err);
+              return;
+            }
+
+            mpin.finishAuthentication(userId, userPin, function (err2, data2) {
+              if (err2) {
+                console.error("Error :::", err2);
+                return;
+              }
+
+              $(ev.currentTarget).append(" :: Successful");
+            });
+          });
+        });
+
+
+        $("#regButton").click(function (ev) {
+          var usrId;
+          usrId = $("#mpinUsrId").val();
+
+          if (usrId) {
+            mpin.makeNewUser(usrId);
+            mpin.startRegistration(usrId, function (err, data) {
+              if (err) {
+                return console.error("startRegistration error :::", err);
+              }
+              chkUser(usrId);
+            });
+          }
+
+          ev.stopPropagation();
+        });
+
+
+
+        function chkUser (userId) {
+          var userStatus = mpin.getUser(userId, "status");
+
+          mpin.confirmRegistration(userId, function (err, data) {
+            //not Active Identity
+            var userElem = $(".usrId[data-userid='" + userId + "']");
+            if (err) {
+              if (userElem.length === 0) {
+                $("#mpinUsersList").append("<li><span class='usrId notActivate' data-userid='" + userId + "'>" + userId + "</span>&nbsp;&nbsp;&nbsp;<input class='smallInput' type='text' placeholder='user Pin'></li>");
+              }
+              return;
+            }
+
+            if (userElem.length === 0) {
+              $("#mpinUsersList").append("<li><span class='usrId notActivate' data-userid='" + userId + "'>" + userId + "</span>&nbsp;&nbsp;&nbsp;<input class='smallInput' type='text' placeholder='user Pin'></li>");
+            }
+
+            var usrPin = userElem.next("input").val();
+            console.log("usrPin :::", usrPin);
+            if (usrPin) {
+              var finish = mpin.finishRegistration(userId, usrPin);
+              if (!finish.error) {
+                userElem.removeClass("notActivate");
+
+                userElem.next("input").remove();
+                userElem.append("&nbsp;&nbsp;&nbsp;>> SETUP DONE");
+
+              } else {
+                console.error("::: OPs something goes wrong.", finish.error);
+              }
+            }
+//						var final = mpin.finishRegistration(userId, 1234);
+            console.log(".: done CONFIRM registration. NOW FINISH");
+          });
+        }
+
+        //live bind click for setup user
+        $(document).on('click', '.usrId', function (ev) {
+          var usrId;
+          usrId = $(this).data('userid');
+
+          chkUser(usrId);
+
+          ev.stopPropagation();
+        });
+
+
+        //// Mobile auth
+        $("#waitMobile").click(function () {
+          var totalTime, requestTime;
+          totalTime = $("#totalTime").val() || 30;
+          requestTime = $("#requestTime").val();
+
+          mpin.getAccessNumber(function (err, data) {
+            $("#mobileStatus").append("Access number: &nbsp;" + data.accessNumber + "<br>");
+            mpin.waitForMobileAuth(totalTime, requestTime, function (err, data) {
+              if (err) {
+                $("#mobileStatus").append(" Pending mobile authentication finish with " + err.type + "<br>");
+                return;
+              }
+              $("#mobileStatus").append(" Login successful");
+            });
+          });
+        });
+
+      });
+		</script>
+
+  </head>
+  <body>
+		<div>Mpin JS SDK </div>
+		<fieldset>
+			<legend>Mpin form:</legend>
+			<input type="text" id="mpinUsrId" placeholder="user id" >
+			<input type="submit" value="Register" id="regButton" style="float:right">
+
+			<h2>Registered users:</h2>
+
+			<div id="mpinUsers"></div>
+			<ul id="mpinUsersList"></ul>
+			<div class="mpinErrors"></div>
+		</fieldset>
+		<br><br>
+		<div style="border: 1px solid grey; margin: 0px auto; width: 50%;">
+
+			Mobile Authentication:<br>
+			<input type="text" id="totalTime" placeholder="Total time in seconds" ><br>
+			<input type="text" id="requestTime" placeholder="per request in seconds" ><br>
+
+			<input type="submit" value="Call" id="waitMobile">
+			<div id="mobileStatus"></div>
+		</div>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/example/exampleNoJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleNoJquery.html b/example/exampleNoJquery.html
new file mode 100644
index 0000000..7aab9ce
--- /dev/null
+++ b/example/exampleNoJquery.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Mpinjs example</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+		<script src="../dist/mpinjs.js" type="text/javascript"></script>
+  </head>
+  <body>
+		<div>Mpinjs example:</div>
+
+		<span>Setup flow only</span>
+
+		<script type="text/javascript">
+      function step1 () {
+        var usrId = "test@user.de";
+        mpin.makeNewUser(usrId);
+        mpin.startRegistration(usrId, function (err, data) {
+					if (err) {
+						return ;
+					}
+          step2(usrId);
+        });
+      }
+
+      function step2 (userId) {
+        mpin.confirmRegistration(userId, function (err, data) {
+					if (err) {
+						//activate Identity error
+						return ;
+					}
+          step3(userId);
+        });
+      }
+
+      function step3 (userId) {
+        var final = mpin.finishRegistration(userId, 1234);
+				
+      }
+
+      var mpin = new mpinjs({
+        server: "http://192.168.10.63:8005"
+      });
+
+      mpin.init(function (err, data) {
+        step1();
+      });
+
+		</script>
+
+
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 879b461..39e73bf 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -1,16 +1,34 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
 var mpinjs = (function () {
-  var Mpin, Users = {}, Errors = [], Status = {};
-
-  Errors[0] = "MISSING_USERID";
-  Errors[1] = "INVALID_USERID";
-  Errors[2] = "MISSING_PARAMETERS";
-  Errors[3] = "IDENTITY_NOT_VERIFIED";
-  Errors[4] = "IDENTITY_MISSING";
-  Errors[5] = "WRONG_PIN";
-  Errors[6] = "WRONG_FLOW";
-  Errors[7] = "TIMEOUT_FINISH";
-
-  ///
+  var Mpin, Users = {}, Errors = {}, Status = {};
+
+  Errors.missingUserId = {code: 0, type: "MISSING_USERID"};
+  Errors.invalidUserId = {code: 1, type: "INVALID_USERID"};
+  Errors.missingParams = {code: 2, type: "MISSING_PARAMETERS"};
+  Errors.identityNotVerified = {code: 3, type: "IDENTITY_NOT_VERIFIED"};
+  Errors.identityMissing = {code: 4, type: "IDENTITY_MISSING"};
+  Errors.wrongPin = {code: 5, type: "WRONG_PIN"};
+  Errors.wrongFlow = {code: 6, type: "WRONG_FLOW"};
+  Errors.timeoutFinish = {code: 7, type: "TIMEOUT_FINISH"};
+
   Status.invalid = "INVALID";
   Status.start = "STARTED";
   Status.active = "ACTIVATED";
@@ -18,8 +36,8 @@ var mpinjs = (function () {
   Status.block = "BLOCKED";
 
   Mpin = function (options) {
-    if (!options || !options.settingsUrl) {
-      return new Error("Missing settings URL");
+    if (!options || !options.server) {
+      return new Error("Missing server URL");
     }
 
     this.opts = options;
@@ -30,9 +48,12 @@ var mpinjs = (function () {
   Mpin.prototype.storageKey = "mpinLib";
 
   Mpin.prototype.init = function (cb) {
-    var self = this;
+    var self = this, _initUrl;
 
-    this.request({url: this.opts.settingsUrl}, function (err, data) {
+    _initUrl = this.opts.server;
+    _initUrl += this.opts.rpsPrefix || "/rps/clientSettings";
+
+    this.request({url: _initUrl}, function (err, data) {
       if (err && cb) {
         return cb(err, null);
       }
@@ -46,7 +67,7 @@ var mpinjs = (function () {
 
   Mpin.prototype.makeNewUser = function (userId, deviceId) {
     if (!userId) {
-      return {code: 0, type: Errors[0]};
+      return Errors.missingUserId;
     }
 
     this.addToUser(userId, {userId: userId, deviceId: deviceId, status: Status.invalid});
@@ -56,12 +77,12 @@ var mpinjs = (function () {
 
   Mpin.prototype.startRegistration = function (userId, cb) {
     var _reqData = {}, self = this;
-    if (!userId || typeof userId !== "string") {
-      return cb ? cb({code: 0, type: Errors[0]}, null) : {error: 1};
+    if (!userId) {
+      return cb ? cb(Errors.missingUserId, null) : {error: 1};
     } else if (!this.checkUser(userId)) {
-      return cb({code: 1, type: Errors[1]}, null);
+      return cb(Errors.invalidUserId, null);
     } else if (!this.opts.registerURL) {
-      return cb({code: 2, type: Errors[2], message: "Missing registerURL"}, null);
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
     }
 
     _reqData.url = this.generateUrl("register");
@@ -90,19 +111,18 @@ var mpinjs = (function () {
   //request cs1 + cs2
   Mpin.prototype.confirmRegistration = function (userId, cb) {
     var _cs1Url = "", self = this, _userStatus;
-
-    if (!userId || typeof userId !== "string") {
-      return cb ? cb({code: 0, type: Errors[0]}, null) : {error: 0, type: Errors[0]};
+    if (!userId) {
+      return cb ? cb(Errors.missingUserId, null) : Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return cb({code: 1, type: Errors[1]}, null);
+      return cb(Errors.invalidUserId, null);
     } else if (!this.opts.signatureURL) {
-      return cb({code: 2, type: Errors[2], message: "Missing signatureURL option."}, null);
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing signatureURL option."}, null);
     }
 
     //started || activated
     _userStatus = this.getUser(userId, "status");
     if (_userStatus !== Status.start && _userStatus !== Status.active) {
-      return cb({code: 3, type: Errors[3]}, null);
+      return cb(Errors.wrongFlow, null);
     }
 
     //already set.
@@ -116,9 +136,9 @@ var mpinjs = (function () {
       var _cs2Url = "";
       if (err) {
         if (err.status == 401) {
-          return cb({code: 3, type: Errors[3], message: "Identity not activate."}, null);
+          return cb(Errors.identityNotVerified, null);
         } else if (err.status == 400) {
-          return cb({code: 4, type: Errors[4]}, null);
+          return cb(Errors.wrongFlow, null);
         }
       }
 
@@ -142,20 +162,20 @@ var mpinjs = (function () {
 
 
   Mpin.prototype.finishRegistration = function (userId, pin) {
-    var _user, tokenHex;
+    var _user, token;
 
-    if (!userId || typeof userId !== "string") {
-      return {error: 0, type: Errors[0]};
+    if (!userId) {
+      return Errors.missingUserId;
     }
 
     _user = this.getUser(userId);
 
     if (_user.status !== Status.active) {
-      return {code: 3, type: Errors[3]};
+      return Errors.wrongFlow;
     }
 
-    tokenHex = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
-    this.addToUser(userId, {tokenHex: tokenHex, status: Status.register});
+    token = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
+    this.addToUser(userId, {token: token, status: Status.register});
 
     return true;
   };
@@ -171,22 +191,22 @@ var mpinjs = (function () {
   Mpin.prototype.startAuthentication = function (userId, cb) {
     var _tp1Url, self = this, _userStatus;
 
-    if (!userId || typeof userId !== "string") {
-      return cb ? cb({code: 0, type: Errors[0]}, null) : {error: 0, type: Errors[0]};
+    if (!userId) {
+      return cb ? cb(Errors.missingUserId, null) : Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return cb({code: 1, type: Errors[1]}, null);
+      return cb(Errors.invalidUserId, null);
     } else if (!this.opts.timePermitsURL || !this.opts.certivoxURL) {
-      return cb({code: 2, type: Errors[2], message: "Missing timePermitsURL or/and certivoxURL option."}, null);
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, 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);
+      return cb(Errors.wrongFlow, null);
     }
 
     //checkUser
-    _tp1Url = this.generateUrl('permit1');
+    _tp1Url = this.generateUrl('permit1', {userId: userId});
     this.request({url: _tp1Url}, function (err, data) {
       var _signature, _tp2Url, _timePermit1, _storageUrl;
       _signature = data["signature"];
@@ -194,7 +214,7 @@ var mpinjs = (function () {
 
       self.addToUser(userId, {currentDate: data['date']});
 
-      _tp2Url = self.generateUrl('permit2');
+      _tp2Url = self.generateUrl('permit2', {userId: userId});
       _tp2Url += "&signature=" + _signature;
 
       //check cache if exist 
@@ -243,7 +263,15 @@ var mpinjs = (function () {
 
 
   Mpin.prototype.finishAuthentication = function (userId, aPin, cb) {
-    var self = this, _reqData = {};
+    var self = this, _reqData = {}, _userStatus;
+
+    //registered
+    _userStatus = this.getUser(userId, "status");
+    if (_userStatus !== Status.register) {
+      return cb(Errors.wrongFlow, null);
+    } else if (!Users[userId].timePermitHex) {
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+    }
 
     _reqData.url = this.generateUrl("pass1");
     _reqData.type = "POST";
@@ -261,8 +289,11 @@ var mpinjs = (function () {
       // pass 2
       self.request(_req2Data, function (pass2Err, pass2Data) {
         var _req3Data = {};
+        if (pass2Err) {
+          return cb(pass2Err, null);
+        }
 
-        if (pass2Data["OTP"]) {
+        if (pass2Data && pass2Data["OTP"]) {
           delete pass2Data["OTP"];
         }
 
@@ -273,11 +304,16 @@ var mpinjs = (function () {
         self.request(_req3Data, function (authErr, authData) {
           if (authErr) {
             if (authErr.status === 401) {
-              return cb({code: 5, type: Errors[5]}, null);
+              return cb(Errors.wrongPin, null);
+            } else if (authErr.status === 410) {
+              self.addToUser(userId, {status: Status.block});
+              return cb(Errors.wrongPin, null);
+            } else {
+              return cb(Errors.wrongPin, null);
             }
           }
 
-          cb && cb(null, true);
+          cb && cb(null, authData || {});
         });
       });
     });
@@ -286,8 +322,8 @@ var mpinjs = (function () {
   Mpin.prototype.getAuthData = function (userId, aPin) {
     var _auth = {};
 
-    _auth.mpin = this.getIdentity();
-    _auth.token = Users[userId].tokenHex;
+    _auth.mpin = Users[userId].mpinId;
+    _auth.token = Users[userId].token;
     _auth.timePermit = Users[userId].timePermitHex;
     _auth.date = Users[userId].currentDate;
 
@@ -326,32 +362,36 @@ var mpinjs = (function () {
     });
   };
 
-  Mpin.prototype.waitForMobileAuth = function (timeoutSeconds, cb) {
+  Mpin.prototype.waitForMobileAuth = function (timeoutSeconds, requestSeconds, 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);
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call getAccessNumber method before this."}, null);
+    } else if (!timeoutSeconds) {
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing timeout/expiration period(in seconds)."}, null);
     }
 
 
-
-    this.timeoutPeriod || (this.timeoutPeriod = timeoutSeconds * 1000);
+    if (typeof this.timeoutPeriod === "undefined") {
+      this.timeoutPeriod = timeoutSeconds * 1000;
+    }
 
     _reqData.url = this.generateUrl("getaccess");
     _reqData.type = "POST";
     _reqData.data = {webOTT: this.webOTT};
 
     this.request(_reqData, function (err, data) {
+      var _requestPeriod;
       if (err) {
         if (err.status === 401 && self.timeoutPeriod > 0) {
-          self.timeoutPeriod -= 3000;
+          _requestPeriod = requestSeconds ? requestSeconds * 1000 : 3000;
+          self.timeoutPeriod -= _requestPeriod;
+
           self.intervalID2 = setTimeout(function () {
-            self.waitForMobileAuth.call(self, timeoutSeconds, cb);
-          }, 3000);
+            self.waitForMobileAuth.call(self, timeoutSeconds, requestSeconds, cb);
+          }, _requestPeriod);
           return;
         } else if (self.timeoutPeriod <= 0) {
-          cb && cb({code: 7, type: Errors[7]}, null);
+          cb && cb(Errors.timeoutFinish, null);
           return;
         }
       }
@@ -381,10 +421,10 @@ var mpinjs = (function () {
         break;
       case "permit1":
         url = this.opts.timePermitsURL + "/";
-        url += this.getIdentity();
+        url += Users[options.userId].mpinId;
         break;
       case "permit2":
-        mpData = this.fromHex(this.getIdentity());
+        mpData = this.fromHex(Users[options.userId].mpinId);
         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);
@@ -437,9 +477,9 @@ var mpinjs = (function () {
   Mpin.prototype.getUser = function (userId, property) {
     var _user = {};
     if (!userId) {
-      return {code: 0, type: Errors[0]};
+      return Errors.missingUserId;
     } else if (!this.checkUser(userId)) {
-      return {code: 1, type: Errors[1]};
+      return Errors.invalidUserId;
     }
 
     _user = {
@@ -455,9 +495,31 @@ var mpinjs = (function () {
     }
   };
 
-  //remove this
-  Mpin.prototype.getUsers = function () {
-    return Users;
+
+  Mpin.prototype.deleteUser = function (userId) {
+    var mpinData = this.getData(), delMpinId;
+
+    if (!userId) {
+      return Errors.missingUserId;
+    } else if (!this.checkUser(userId)) {
+      return Errors.invalidUserId;
+    }
+
+    delMpinId = Users[userId].mpinId;
+
+    //memory
+    delete Users[userId];
+
+    //store
+    delete mpinData.accounts[delMpinId];
+
+    //change default Identity
+    for (var mpinId in mpinData.accounts) {
+      mpinData.defaultIdentity = mpinId;
+      break;
+    }
+
+    this.storeData(mpinData);
   };
 
   Mpin.prototype.addToUser = function (userId, userProps, skipSave) {
@@ -511,9 +573,9 @@ var mpinjs = (function () {
       mpinData.accounts[mpinId].MPinPermit = upData.timePermitHex;
     }
 
-    if (upData.tokenHex) {
+    if (upData.token) {
       var mpinId = Users[userId].mpinId;
-      mpinData.accounts[mpinId].token = upData.tokenHex;
+      mpinData.accounts[mpinId].token = upData.token;
     }
 
     if (upData.status && Users[userId].mpinId) {
@@ -527,12 +589,11 @@ var mpinjs = (function () {
       mpinData.accounts[mpinId].timePermitCache = upData.timePermitCache;
     }
 
-    localStorage.setItem(this.storageKey, JSON.stringify(mpinData));
+    this.storeData(mpinData);
   };
 
-  Mpin.prototype.getIdentity = function () {
-    var mpinData = this.getData();
-    return mpinData.defaultIdentity;
+  Mpin.prototype.storeData = function (mpinData) {
+    localStorage.setItem(this.storageKey, JSON.stringify(mpinData));
   };
 
   Mpin.prototype.recover = function () {

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/test/index.html
----------------------------------------------------------------------
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..eba574f
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<!--
+To change this license header, choose License Headers in Project Properties.
+To change this template file, choose Tools | Templates
+and open the template in the editor.
+-->
+<html>
+  <head>
+    <title>MPin js Browser tests</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+		<link rel="stylesheet" media="all" href="../node_modules/mocha/mocha.css">
+		<script src="../node_modules/chai/chai.js"></script>
+		<script src="../node_modules/sinon-chai/lib/sinon-chai.js"></script>
+		<script src="../node_modules/mocha/mocha.js"></script>
+		<script src="../node_modules/sinon/pkg/sinon.js"></script>
+		<script src="../dist/mpinjs.js"></script> 
+  </head>
+  <body>
+		<!-- This is where mocha inserts the test results that are styled with the css file above -->
+		<div id="mocha"></div>
+		<!-- This is where any fixtures we need for the test will be inserted into. Naturally, we won't want to cover the mocha test results so we position this bad boy off screen. -->
+		<div id="test" style="position: fixed; top: 0; left: -99999px;"></div>
+
+		<script>
+      mocha.setup('bdd');
+
+      mocha.ui('bdd');
+      mocha.reporter('html');
+      expect = chai.expect;
+
+
+		</script>
+
+		<script src="index.js"></script> 
+		<script>
+
+      mocha.run();
+		</script>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/c86c030e/test/index.js
----------------------------------------------------------------------
diff --git a/test/index.js b/test/index.js
index 818368f..b5e311e 100644
--- a/test/index.js
+++ b/test/index.js
@@ -1,3 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
 //if browser
 if (typeof require !== 'undefined') {
   var expect = require('chai').expect;
@@ -13,7 +32,7 @@ Errors[1] = "INVALID_USERID";
 Errors[2] = "MISSING_PARAMETERS";
 Errors[3] = "IDENTITY_NOT_VERIFIED";
 
-describe('# Constructor initialization without settingsUrl.', function () {
+describe('# Constructor initialization without server Url.', function () {
   it('should throw Error', function () {
     var mpin = new mpinjs();
     expect(mpin).to.be.an.instanceof(Error);
@@ -22,10 +41,10 @@ describe('# Constructor initialization without settingsUrl.', function () {
 
 //spy cases
 describe('# Normal iniatilization.', function () {
-  var mpin, spy, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+  var mpin, spy, serverUrl = "http://192.168.10.63:8005";
 
   before(function () {
-    mpin = new mpinjs({settingsUrl: settingsUrl});
+    mpin = new mpinjs({server: serverUrl});
     spy = sinon.spy();
 
     mpin.request = spy;
@@ -38,15 +57,15 @@ describe('# Normal iniatilization.', function () {
 
   it('should call request method with settingsUrl params', function () {
     mpin.init();
-    expect(spy.calledWith({url: settingsUrl})).to.be.true;
+    expect(spy.calledWith({url: serverUrl + "/rps/clientSettings"})).to.be.true;
   });
 });
 
 describe('# Init method > clientSettings request.', function () {
-  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+  var mpin, serverUrl = "http://192.168.10.63:8005";
 
   before(function () {
-    mpin = new mpinjs({settingsUrl: settingsUrl});
+    mpin = new mpinjs({server: serverUrl});
 
     this.fakeRes = {
       requestOTP: false,
@@ -80,10 +99,10 @@ describe('# Init method > clientSettings request.', function () {
 });
 
 describe('# makeNewUser checks.', function () {
-  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+  var mpin, serverUrl = "http://192.168.10.63:8005";
 
   before(function () {
-    mpin = new mpinjs({settingsUrl: settingsUrl});
+    mpin = new mpinjs({server: serverUrl});
   });
 
   after(function () {
@@ -103,10 +122,10 @@ describe('# makeNewUser checks.', function () {
 });
 
 describe('# startRegistration.', function () {
-  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+  var mpin, serverUrl = "http://192.168.10.63:8005";
 
   before(function () {
-    mpin = new mpinjs({settingsUrl: settingsUrl});
+    mpin = new mpinjs({server: serverUrl});
 
     this.fakeRes = {
       requestOTP: false,
@@ -166,10 +185,10 @@ describe('# startRegistration.', function () {
 
 
 describe('# confirmRegistration.', function () {
-  var mpin, settingsUrl = "http://192.168.10.63:8005/rps/clientSettings";
+  var mpin, serverUrl = "http://192.168.10.63:8005";
 
   before(function () {
-    mpin = new mpinjs({settingsUrl: settingsUrl});
+    mpin = new mpinjs({server: serverUrl});
 
     this.fakeRes = {
       requestOTP: false,
@@ -274,12 +293,12 @@ describe('# confirmRegistration.', function () {
       });
     });
   });
-  
-  
+
+
 
 });
 
 
-describe('# confirmRegistration.', function () { 
-  
+describe('# confirmRegistration.', function () {
+
 });
\ No newline at end of file



[23/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #7 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #7 in MPIN/mpinjs from develop to master

* commit '0f359a36280abe8305c470d7c1e3009e5a74d136':
  Move recover to init function


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/505fafc2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/505fafc2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/505fafc2

Branch: refs/heads/add-documentation
Commit: 505fafc28f69daca26b76a4dadcbc75783f9317f
Parents: d3fe0ac 0f359a3
Author: Boyan Bakov <bo...@certivox.com>
Authored: Tue Mar 1 16:23:34 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Tue Mar 1 16:23:34 2016 +0100

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[29/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #10 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #10 in MPIN/mpinjs from develop to master

* commit 'aad05593a02d76c3eedfa64d1d679f51ac37e2ef':
  Add authenticate with access number and example


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/56b891b7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/56b891b7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/56b891b7

Branch: refs/heads/add-documentation
Commit: 56b891b798c621aafbe61a0809d343bb86c4d89e
Parents: 2fee833 aad0559
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 14 13:12:46 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 14 13:12:46 2016 +0100

----------------------------------------------------------------------
 example/exampleJquery.html |  41 +++++++++++++--
 lib/mpin.js                | 111 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 135 insertions(+), 17 deletions(-)
----------------------------------------------------------------------



[33/37] incubator-milagro-mfa-js-lib git commit: Update NOTICE

Posted by sa...@apache.org.
Update NOTICE


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/344133d9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/344133d9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/344133d9

Branch: refs/heads/add-documentation
Commit: 344133d9bf78e63bc9225b085cdc614484778e42
Parents: ab97096
Author: Vladislav Mitov <vl...@gmail.com>
Authored: Mon Mar 14 18:14:40 2016 +0200
Committer: Vladislav Mitov <vl...@gmail.com>
Committed: Mon Mar 14 20:00:21 2016 +0200

----------------------------------------------------------------------
 NOTICE | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/344133d9/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
index 111f042..d393a26 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
-Apache Open MIRACL M-Pin Clients
+Apache Milagro M-Pin JavaScript Client Library
 Copyright 2015 The Apache Software Foundation
 
 This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
+The Apache Software Foundation (http://www.apache.org/).


[37/37] incubator-milagro-mfa-js-lib git commit: Add documentation

Posted by sa...@apache.org.
Add documentation


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/3f1d170c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/3f1d170c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/3f1d170c

Branch: refs/heads/add-documentation
Commit: 3f1d170c0f99bd9725b5720f590be40954ef6e27
Parents: a745f8e
Author: Simeon Aladjem <si...@miracl.com>
Authored: Fri Aug 5 17:18:12 2016 +0300
Committer: Simeon Aladjem <si...@miracl.com>
Committed: Fri Aug 5 17:18:12 2016 +0300

----------------------------------------------------------------------
 M-Pin SDK - Authentication flow.png | Bin 0 -> 34457 bytes
 M-Pin SDK - Authentication flow.xml |   2 +
 M-Pin SDK - Registration flow.png   | Bin 0 -> 36643 bytes
 M-Pin SDK - Registration flow.xml   |   2 +
 README.md                           | 268 ++++++++++++++++++++++++++++++-
 5 files changed, 270 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/3f1d170c/M-Pin SDK - Authentication flow.png
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Authentication flow.png b/M-Pin SDK - Authentication flow.png
new file mode 100644
index 0000000..c386255
Binary files /dev/null and b/M-Pin SDK - Authentication flow.png differ

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/3f1d170c/M-Pin SDK - Authentication flow.xml
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Authentication flow.xml b/M-Pin SDK - Authentication flow.xml
new file mode 100644
index 0000000..4bf06c0
--- /dev/null
+++ b/M-Pin SDK - Authentication flow.xml	
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mxGraphModel dx="1050" dy="636" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" background="#ffffff" math="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="3" target="5" edge="1"><mxGeometry x="414" y="130" as="geometry"/></mxCell><mxCell id="3" value="Start" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="379" y="90" width="70" height="40" as="geometry"/></mxCell><mxCell id="25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" parent="1" source="5" target="23" edge="1"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="5" value="&lt;font face=&quot;Lucida Console&quot;&gt;StartAuthentication&lt;/font&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="342" y="180" wid
 th="144" height="40" as="geometry"/></mxCell><mxCell id="9" value="&lt;code&gt;&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;&lt;/code&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;" parent="1" source="23" target="19" edge="1"><mxGeometry as="geometry"><mxPoint y="3" as="offset"/><mxPoint x="414" y="449.6715328467153" as="sourcePoint"/><mxPoint x="414" y="371" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="18" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;exitX=0.5;exitY=1;" parent="1" source="19" target="21" edge="1"><mxGeometry x="414" y="763" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="19" value="Read Secret (PIN)&lt;div&gt;from end user&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="354" y="383" width="120" height="40" as="geometry"/></mxCell><mxCell id="37" value="" style="edgeStyle=orthogonalEdg
 eStyle;rounded=0;html=1;" parent="1" source="21" target="36" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="21" value="&lt;p&gt;&lt;code&gt;&lt;font face=&quot;Lucida Console&quot; style=&quot;font-size: 12px&quot;&gt;FinishAuthentication&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="330" y="483" width="168" height="40" as="geometry"/></mxCell><mxCell id="22" value="End" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="379" y="759.5999999999999" width="70" height="40" as="geometry"/></mxCell><mxCell id="27" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;REVOKED&lt;/font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;" parent="1" source="23" target="28" edge="1"><mxGeometry x="-0.04" y="15" relative="1" as="geometry"><mxPoint x="582" y="315" as="targetPoint"/><Array as="points"/><mxPoint as="offset"/></mxGeometry><
 /mxCell><mxCell id="23" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="265" width="95" height="60" as="geometry"/></mxCell><mxCell id="30" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=1;entryY=0.5;exitX=0.5;exitY=1;" parent="1" source="28" target="22" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="637" y="435" as="targetPoint"/><Array as="points"><mxPoint x="637" y="780"/></Array></mxGeometry></mxCell><mxCell id="28" value="User is Revoked" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="580" y="275" width="114" height="40" as="geometry"/></mxCell><mxCell id="39" value="&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="36" target="22" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;INCORRECT_PIN&lt;/
 font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="36" target="40" edge="1"><mxGeometry x="-0.08" y="-12" relative="1" as="geometry"><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="36" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="573" width="95" height="65" as="geometry"/></mxCell><mxCell id="43" value="&lt;font face=&quot;Lucida Console&quot;&gt;REGISTERED&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;exitX=0.5;exitY=0;" parent="1" source="40" target="19" edge="1"><mxGeometry x="-0.5393" relative="1" as="geometry"><mxPoint x="218.5" y="733" as="targetPoint"/><Array as="points"><mxPoint x="219" y="403"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="48" value="&lt;font face=&quot;Lucida Console&quot;&gt;BLOCKED&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" parent="1" sourc
 e="40" target="46" edge="1"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="40" value="User State?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="171" y="573" width="95" height="65" as="geometry"/></mxCell><mxCell id="50" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;exitX=0.5;exitY=1;" parent="1" source="46" target="22" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="219" y="1090" as="targetPoint"/><Array as="points"><mxPoint x="219" y="780"/></Array></mxGeometry></mxCell><mxCell id="46" value="User is Blocked&lt;div&gt;(need to re-register)&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="159" y="690" width="120" height="40" as="geometry"/></mxCell></root></mxGraphModel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/3f1d170c/M-Pin SDK - Registration flow.png
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Registration flow.png b/M-Pin SDK - Registration flow.png
new file mode 100644
index 0000000..460f6f9
Binary files /dev/null and b/M-Pin SDK - Registration flow.png differ

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/3f1d170c/M-Pin SDK - Registration flow.xml
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Registration flow.xml b/M-Pin SDK - Registration flow.xml
new file mode 100644
index 0000000..fdf50b7
--- /dev/null
+++ b/M-Pin SDK - Registration flow.xml	
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mxGraphModel dx="1050" dy="636" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" background="#ffffff" math="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="41519c7962ced28-4" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-1" target="41519c7962ced28-2"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-1" value="Start" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="379" y="90" width="70" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" edge="1" parent="1" source="41519c7962ced28-2" target="41519c7962ced28-6"><mxGeometry relative="1" as="geometry"><mxPoint x="405.5" y="330" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-2" va
 lue="&lt;font face=&quot;Lucida Console&quot;&gt;MakeNewUser&lt;/font&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="366" y="180" width="95" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-6" target="41519c7962ced28-9"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-6" value="&lt;font face=&quot;Lucida Console&quot;&gt;StartRegistration&lt;/font&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="347" y="270" width="133" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-13" value="&lt;div&gt;&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;STARTED_REGISTRATION&lt;/font&gt;&lt;/span&gt;&lt;br&gt;&lt;/div&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" edge="1" parent="1" source="41519c7962ced28-9" target="41519c7962ced28-11"><m
 xGeometry x="-0.1333" y="15" relative="1" as="geometry"><mxPoint x="582" y="405" as="targetPoint"/><Array as="points"><mxPoint x="617" y="405"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-16" value="&lt;code&gt;&lt;font face=&quot;Lucida Console&quot;&gt;ACTIVATED&lt;/font&gt;&lt;/code&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-9" target="41519c7962ced28-15"><mxGeometry x="0.0139" y="-18" relative="1" as="geometry"><mxPoint x="18" y="-18" as="offset"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-9" value="If returned&lt;div&gt;Status is OK,&amp;nbsp;&lt;span style=&quot;line-height: 1.2&quot;&gt;Check&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;line-height: 1.2&quot;&gt;User State&lt;/span&gt;&lt;/div&gt;" style="rhombus;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="345" y="360" width="137" height="90" as="geometry"/></mxCell><mxCell id="41519c7962ced28-
 18" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.75;entryY=0;exitX=0.5;exitY=1;" edge="1" parent="1" source="41519c7962ced28-11" target="41519c7962ced28-15"><mxGeometry relative="1" as="geometry"><mxPoint x="617" y="590" as="targetPoint"/><Array as="points"><mxPoint x="617" y="520"/><mxPoint x="450" y="520"/></Array></mxGeometry></mxCell><mxCell id="41519c7962ced28-11" value="Wait for user to confirm identity" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="560" y="450" width="114" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-20" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-15" target="41519c7962ced28-19"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-15" value="&lt;font face=&quot;Lucida Console&quot;&gt;ConfirmRegistration&lt;/font&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="342" y="545" width
 ="144" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-22" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;IDENTITY_NOT_VERIFIED&lt;/font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.75;entryY=0;exitX=1;exitY=0.5;" edge="1" parent="1" source="41519c7962ced28-19" target="41519c7962ced28-11"><mxGeometry x="-0.6526" y="15" relative="1" as="geometry"><mxPoint x="583" y="695" as="targetPoint"/><Array as="points"><mxPoint x="710" y="660"/><mxPoint x="710" y="410"/><mxPoint x="646" y="410"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-19" target="41519c7962ced28-23"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-19" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="345" y="615" width="137" height="90" as="g
 eometry"/></mxCell><mxCell id="41519c7962ced28-26" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;exitX=0.5;exitY=1;" edge="1" parent="1" source="41519c7962ced28-23" target="41519c7962ced28-25"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-23" value="Read Secret (PIN)&lt;div&gt;from end user&lt;/div&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="354" y="750" width="120" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" edge="1" parent="1" source="41519c7962ced28-25" target="41519c7962ced28-27"><mxGeometry relative="1" as="geometry"><mxPoint x="413.5" y="1000" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-25" value="&lt;font face=&quot;Lucida Console&quot;&gt;FinishRegistration&lt;/font&gt;" style="whiteSpace=wrap;htm
 l=1;" vertex="1" parent="1"><mxGeometry x="342" y="848" width="143" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-27" value="End" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="379" y="944.5999999999999" width="70" height="40" as="geometry"/></mxCell></root></mxGraphModel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/3f1d170c/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 7bdcacf..bd567ae 100644
--- a/README.md
+++ b/README.md
@@ -58,8 +58,8 @@ mpin.getAccessNumber(<callback>);
 mpin.waitForMobileAuth(<timeout-sec>, <retry-period-sec>, <callback>);
 
 /*
-   If successfull - Authentication completed
-   If exits with timeout, then no successfull authentication from mobile device was completed
+   If successful - Authentication completed
+   If exits with timeout, then no successful authentication from mobile device was completed
    If one needs to cancel the waiting for authentication from the mobile device, call cancelMobileAuth()
 */
 ```
@@ -81,3 +81,267 @@ $ npm test
 Actively tested with node:
 
   - 0.10.4
+
+## mpinjs API Reference
+
+### Errors
+
+Errors are returned as objects in callback functions where such are available, and they have the general structure:
+```js
+{
+   code: <error-code>,
+   type: <error-desc>,
+   message: <optional-message>
+}
+```
+as:
+
+| Field | Type | Notes | Description |
+|:----- |:---- |:----- |:----------- |
+| `code` | `Number` | Mandatory | Internal error code |
+| `type` | `String` | Mandatory | Predefined error description |
+| `message` | `String` | Optional | Additional error message where applicable |
+
+The list of errors is:
+
+| Error code | Error desc | Explanation |
+|:---------- |:---------- |:----------- |
+| `0` | `"MISSING_USERID"` | User ID was not proceeded to the API, while it was required |
+| `1` | `"INVALID_USERID"` | The user ID that was provided to the API is not valid or not existing |
+| `2` | `"MISSING_PARAMETERS"` | A required parameter was not provided to the API. Usually an additional explanation _message_ will be provided with this error |
+| `3` | `"IDENTITY_NOT_VERIFIED"` | `confirmRegistration()` was called while the identity is still not verified |
+| `4` | `"IDENTITY_MISSING"` | No user with the provided user ID has been created |
+| `5` | `"WRONG_PIN"` | The provided user secret (PIN or password) is wrong and authentication failed |
+| `6` | `"WRONG_FLOW"` | The API method was called not according to the correct flow and the provided user has the wrong state  |
+| `7` | `"USER_REVOKED"` | A time permit for the user couldn't be retrieved and the user is considered "revoked" by the system |
+| `8` | `"TIMEOUT_FINISH"` | The call `waitForMobileAuth()` has ended with timeout and no successful authentication has been done during that time from a mobile device |
+
+### The User object
+
+For each user an object needs to be created. The key to the user object is its identity, which is supposed to be unique. The user object has a _State_ which basically indicates what can be done with the user. For instance, if a user has not been registered, it cannot be authenticated, obviously. The different user states are:
+
+| State | Description |
+| ----- | ----------- |
+| `"INVALID"` | A user that has just been created and no registration process has been started for it |
+| `"STARTED"` | The registration process for this user has been started, but the identity is still not verified |
+| `"ACTIVATED"` | A user which has been made active without a need of extra identity verification step |
+| `"REGISTERED"` | The user registration process has been completed and its secret (password or PIN) has been successfully set. Such a user can be authenticated |
+| `"BLOCKED"` | A user which authentication failed several time in a row and has been blocked by the server. Such user cannot authenticate anymore and need to re-register |
+
+### mpinjs API
+
+#### Callbacks
+
+Some of the API methods have a `callback` parameter. The convention for the callback function is:
+```js
+function(error, data)
+```
+as:
+* `error` is an error object as described above, or `null` if no error has occurred.
+* `data` is the returned data for the API method. In some cases it might be just 'true' to indicate that the method succeeded, while in others it could be an object carrying some result.
+
+The standard error handling would be as follows:
+```js
+<some-api-method>( userId, function(err, data) {
+    if (err) {
+        // Method failed with some error
+    } else {
+        // Method succeeded, proceed with handling data
+    }
+});
+```
+
+##### `mpinjs(options)`
+
+An `mpinjs` instance is constructed as follows:
+```js
+mpin = new mpinjs({
+    server: "http://ec2-54-77-232-113.eu-west-1.compute.amazonaws.com",
+    rpsPrefix: "rps"
+})
+```
+A key/value list of parameters is passed to the constructor as the currently recognized parameters are:
+* `server` - _Mandatory_. The address at which the M-Pin Service is accessible. This is usually the address of the Relying Party Application. For instance if the backend is an M-Pin SSO server this would be the address of that server.
+* `rpsPrefix` - _Optional_. This parameter could be specified in case `rpsPrefix` parameter in the RPS configuration has been changed and is not the default one. If this option is not specified, then the default `"rps"` is used.
+
+##### `init(callback)`
+
+This method will attempt to initialize the `mpinjs` instance according the provided options and retrieve users from the storage. It makes a request to retrieve the _Client Settings_ from the server. If the method succeeds, it will return the retrieved client settings as the `data` in the callback function.
+ 
+#### User management API
+
+##### `makeNewUser(userId, deviceId)`
+
+This method will create a new user object in the internal user storage. The new user will be initialized with the _state_ `"INVALID"`. The received parameters are:
+* `userId` - _Mandatory_, String - The identity of the new user. It should be a unique for the given server / application. The user object could later on be referred to using this user identity. 
+* `deviceId` - _Optional_, String - Some description of the local device. This Device ID is passed to the RPA, which might store it and use it later to determine which M-Pin ID is associated with this device.
+
+##### `listUsers()`
+
+This method will return a list of all the user objects that `mpinjs` has in its storage. The user objects are of the form:
+```js
+{
+    userId: <user-identity>,
+    deviceId: <device-id>,
+    state: <user-state>
+}
+```
+##### `checkUser(userId)`
+
+This method will return `true` is a user object with the given `userId` exists, or `false` if not.
+
+##### `getUser(userId, property)`
+
+This method will return either the user object that is associated with the given `userId`, or id `property` is specified it will return just the value of that property of the user object.
+* `userId` - _Mandatory_, String - The user identity associated with the user object
+* `property` - _Optional_, String - One of `"deviceId"`, `"state"` or `"userId"`. If specified, only the value of the specified property will be returned. Otherwise the whole user object will be returned, according to the specification in `listUsers()`.
+
+##### `deleteUser(userId)`
+
+This function will delete the user object associated with the given `userId` from the internal storage
+
+#### Registration API
+
+##### `startRegistration(userId, callback)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user that has to be registered.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the registration has been started. This parameter complies to the convention explained above.
+
+This method will start the registration process for the user with the identity `userId`. Such a user should be previously created with the `makeNewUser()` method and should be in _state_ `"INVALID"`. 
+
+After successful completion of this call the user should be in one of two states - `"STARTED"` or `"ACTIVATED"`. If the user is in state `"STARTED"`, then its identity needs to be verified according to the process chosen by the RPA. When this process is complete the method `confirmRegistration()` should be called to proceed with the registration process. If the user is in state `"ACTIVATED"`, then it was instantly made active by the RPA and `confirmRegistration()` could be called right away to continue with the registration process.
+
+##### `restartRegistration(userId, callback)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user that has to be registered.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the registration has been started. This parameter complies to the convention explained above.
+
+This method will restart the registration process for the user with the identity `userId`. The registration process for the user should have been previously started with `startRegistration()` and the user object should be in _state_ `"STARTED"`. This method will cause the user identity verification to be restarted, i.e. if the verification is done by sending an e-mail, then a new e-mail will be sent.
+
+After successful completion of this call the user should stay in state `"STARTED"`, awaiting for the identity to be verified. After it is done, `confirmRegistration()` should be called to proceed with the registration process.
+
+##### `confirmRegistration(userId, callback)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user which identity needs to be confirmed.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+
+This method attempts to retrieve the _Client Key_ for the user associated with the identity `userId`. The user is expected to be in one of two states - `"STARTED"` or `"ACTIVATED"`. If this is not the case, `"WRONG_FLOW"` error will be returned through the callback. If the user identity has not been verified and the _Client Key_ cannot be retrieved, `"IDENTITY_NOT_VERIFIED"` error will be returned through the callback. If the method has been completed successfully, then the user state is set to `"ACTIVATED"`. Afterwards, the desired secret (PIN or password) should be read from the end user and then `finishRegistration()` should be called to complete the user registration.
+
+##### `finishRegistration(userId, pin)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user which registration process should be finalized.
+* `pin` - _Mandatory_, String - The user secret (PIN or password) that should be used while generating the _M-Pin Token_.
+
+This method will generate the and store the _M-Pin Token_ using the _Client Key_ retrieved during `confirmRegistration()` and the provided `pin`. The users' state has to be `"ACTIVATED"` and its _Client Key_ has to be previously retrieved. If those conditions are not met, the function will fail, returning a `"WRONG_FLOW"` error. If successful the method will return `true` and the user state will be set to `"REGISTERED"`.
+
+#### Authentication API
+
+##### `startAuthentication(userId, callback)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user that needs to be authenticated.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+
+This method will attempt to retrieve _Time Permits_ for the given user, as a first step in the authentication process. The user has to be in state `"REGISTERED"`. If this is not the case, `"WRONG_FLOW"` error will be returned through the callback. If the time permit cannot be retrieved for some reason, `"USER_REVOKED"` error will be returned.
+
+##### `finishAuthentication(userId, pin, callback)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user that needs to be authenticated.
+* `pin` - _Mandatory_, String - the user secret (PIN or password) that should be used for the user authentication.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+
+This method will attempt to authenticate the user against the M-Pin Server, using the provided `pin`. The user needs to have a valid time permit, previously retrieved via the `startAuthentication()` method. If the user authentication fails, `"WRONG_PIN"` error will be returned through the callback. If the authentication failed several times sequentially (usually 3), the user might become "blocked". When this happens the users' state will be set to `"BLOCKED"` and this user will no longer be able to authenticate. If the authentication was successful, the returned `error` through the callback will be `null` and any data that was passed back by the RPA in the authentication response, will be returned through the callbacks' `data` parameter. Note that this data is not mandatory and might also be `null` or empty.
+
+##### `finishAuthenticationOtp(userId, pin, callback)`
+
+Parameters:
+* `userId` - _Mandatory_, String - the user identity associated with the user that needs to be authenticated.
+* `pin` - _Mandatory_, String - the user secret (PIN or password) that should be used for the user authentication.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+
+This method is very similar to `finishAuthentication()`, but it is intended to be used when a _One Time Password_ (OTP) is intended to be generated by the server. Note that not all of the servers support that functionality and currently this time of authentication could only be used against M-Pin SSO servers. The authentication process is the same, but as a result the `data` provided in the callback will carry the OTP information as follows:
+```js
+{
+    otp: <otp>,
+    ttlSeconds: <time-to-live-sec>,
+    nowTime: <current-time-sec>,
+    expireTime: <expire-time-sec>
+}
+```
+* `otp` - String - the OTP returned by the server
+* `ttlSeconds` - Number - the OTP expiration period in seconds.
+* `nowTime` - Number - Current M-Pin system time in seconds since the Epoch
+* `expireTime` - Number - The M-Pin system time in seconds since the Epoch when the OTP will expire.
+
+##### `getAccessNumber(callback)`
+
+Parameters:
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+
+This method should be used when the authentication is about to be carried out from a remote/mobile device. For this reason an _Access Number_ should be displayed to the end user, and this number should be used on the mobile device to authenticate the user and then associate the local browser session with the mobile authentication event. The Access Number has an expiration period, which also should be displayed to the user, normally in a count-down fashion. Upon successful completion, this method will return through the callback the following `data`:
+```js
+{
+    accessNumber: <access-number>,
+    ttlSeconds: <time-to-live-sec>,
+    localTimeStart: <current-time-sec>,
+    localTimeEnd: <expire-time-sec>
+}
+```
+
+##### `getQrUrl(prerollId, callback)`
+
+Parameters:
+* `prerollId` - _Optional_, String - an optional end-user ID that will be "embedded" into the QA code and will be pre-sed to the Mobile App reading the QR code.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+
+This method should be used when the authentication is about to be carried out from a remote/mobile device. This is an alternative to the _Access Number_ explained above and thus is very similar to it.
+The retrieved URL should be encoded and displayed to the end-user in the form of a QR code, which could be scanned by a Mobile App. The QR code carries information regarding that associates the local browser session with the mobile authentication event.
+The QR Code URL has an expiration period, which also should be displayed to the user, normally in a count-down fashion. Upon successful completion, this method will return through the callback the following `data`:
+ 
+```js
+{
+    qrUrl: <qrcode-url>,
+    ttlSeconds: <time-to-live-sec>,
+    localTimeStart: <current-time-sec>,
+    localTimeEnd: <expire-time-sec>
+}
+```
+
+##### `waitForMobileAuth(timeoutSeconds, requestSeconds, callback, callbackStatus)`
+
+Parameters:
+* `timeoutSeconds` - _Mandatory_, Number - The whole period after which the waiting will time-out
+* `requestSeconds` - _Optional_, Number - The period for re-attempting to poll for valid authentication from a mobile device. If not specified, the default value will be 3 seconds.
+* `callback` - _Mandatory_, function(error,data) - The callback that will be called after the method has been completed. This parameter complies to the convention explained above.
+* `callbackStatus` - _Optional_, function(data) - A status callback that is called by this method in order to update the caller about any change of waiting status.
+
+This method should be used when the authentication is about to be carried out from a remote/mobile device. After an _Access Number_ or a _QR Code URL_ has been retrieved and displayed to the end user, the client should wait for an authentication from a remote/mobile device. Calling this method will initiate such an awaiting. The method will poll for a successful authentication each `requestSeconds` and if no such authentication happened will finally fail after `timeoutSeconds`. When this happens, the `error` returned through the callback will be `"TIMEOUT_FINISH"`. If successful, the function will return through the callback the same values expected after successful `finishAuthentication()`.
+This method will also call `callbackStatus`, if provided, to update for any change of the waiting status. `callbackStatus` should exit normally, so the control returns back to `waitForMobileAuth`, which will continue waiting.
+The data provided to `callbackStatus` has the form:
+```js
+{
+  status: <status>,
+  statusCode: <statis-code>,
+  userId: <user-id>
+}
+```
+* `status` - either `"wid"` or `"user"`. Status `"wid"` means that the QR code has been scanned, while `"user"` means that the user ID that attempts to authenticate has been provided.
+* `statusCode` - a numeric code for the current status. It would normally be 0 meaning that no errors had occurred.
+* `userId` - would be empty when the `status` is `"wid"` and if the `status` is `"user"` it will be the identity of the user that is attempting to authenticate.       
+
+##### `cancelMobileAuth()`
+
+This method should be used when the authentication is about to be carried out from a remote/mobile device. This method will prematurely cause the `waitForMobileAuth()` to stop and exit. This might be necessary if the end user decides to navigate away from the UI page where the waiting for mobile authentication has been initiated. this method always succeeds.
+
+### Main Flows
+
+##### User Registration
+![*](./M-Pin SDK - Registration flow.png)
+
+##### User Authentication
+![*](./M-Pin SDK - Authentication flow.png)
\ No newline at end of file


[31/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #11 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #11 in MPIN/mpinjs from develop to master

* commit '0712ac9f305cf64a5ef5c273dafc804f2de62844':
  Support for password


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/4804d16a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/4804d16a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/4804d16a

Branch: refs/heads/add-documentation
Commit: 4804d16a19254420b75697b2dd95cbbbce5a3d25
Parents: 56b891b 0712ac9
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 14 16:27:45 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 14 16:27:45 2016 +0100

----------------------------------------------------------------------
 lib/mpin.js | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)
----------------------------------------------------------------------



[28/37] incubator-milagro-mfa-js-lib git commit: Add authenticate with access number and example

Posted by sa...@apache.org.
Add authenticate with access number and example


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/aad05593
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/aad05593
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/aad05593

Branch: refs/heads/add-documentation
Commit: aad05593a02d76c3eedfa64d1d679f51ac37e2ef
Parents: 181a7fe
Author: Boyan Bakov <bo...@certivox.com>
Authored: Fri Mar 11 16:13:13 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 14 11:59:08 2016 +0200

----------------------------------------------------------------------
 example/exampleJquery.html |  41 +++++++++++++--
 lib/mpin.js                | 111 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 135 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/aad05593/example/exampleJquery.html
----------------------------------------------------------------------
diff --git a/example/exampleJquery.html b/example/exampleJquery.html
index cf86013..c9459c1 100644
--- a/example/exampleJquery.html
+++ b/example/exampleJquery.html
@@ -11,11 +11,11 @@ and open the template in the editor.
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 		<script src="../dist/mpinjs.js" type="text/javascript"></script>
 		<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js" type="text/javascript"></script>
-	
+
 		<style>
 			fieldset {
 				margin: 0 auto;
-				width: 30%;
+				width: 50%;
 			}
 
 			.notActivate {
@@ -50,9 +50,11 @@ and open the template in the editor.
           htmlList = "<ul>";
           for (var i in mpinUsers) {
             htmlList += "<li>" + mpinUsers[i].userId + "&nbsp;&nbsp;&nbsp;";
-            htmlList += "<input type='text' placeholder='PIN' size='10'>&nbsp;&nbsp;&nbsp;";
+            htmlList += "<input type='text' placeholder='PIN' size='10' class='userPin'>&nbsp;&nbsp;&nbsp;";
             if (mpinUsers[i].state === "REGISTERED") {
               htmlList += "<span class='registered' data-userid='" + mpinUsers[i].userId + "' data-state='" + mpinUsers[i].state + "'>Authenticate</span>";
+              htmlList += "<div style='float: right'><input type='text' placeholder='Access Number' size='10' class='userAN'>&nbsp;&nbsp;&nbsp;";
+              htmlList += "<span class='auth-accnumber' data-userid='" + mpinUsers[i].userId + "'>Authenticate(AN)</span></div>";
             } else {
               htmlList += "<span class='setup' data-userid='" + mpinUsers[i].userId + "' data-state='" + mpinUsers[i].state + "'>Setup</span>";
             }
@@ -96,7 +98,7 @@ and open the template in the editor.
         $(document).on('click', ".registered", function (ev) {
           var userId, userPin, state;
           userId = $(ev.currentTarget).data('userid');
-          userPin = $(ev.currentTarget).prev("input").val();
+          userPin = $(ev.currentTarget).prev("input.userPin").val();
           state = $(ev.currentTarget).data('state');
 
           mpin.startAuthentication(userId, function (err, data) {
@@ -117,6 +119,37 @@ and open the template in the editor.
         });
 
 
+        $(document).on('click', ".auth-accnumber", function (ev) {
+          var userId, userPin, userAN;
+          userId = $(ev.currentTarget).data('userid');
+					userPin = $(ev.currentTarget).parent("li").find("input.userPin").val();
+					userAN = $(ev.currentTarget).prev("input.userAN").val();
+					
+					if (!mpin.checkAccessNumber(userAN)) {
+						$(".errAccessNumber").remove();
+						$(ev.currentTarget).prepend("<span style='color: red' class='errAccessNumber'>Invalid Access Number</span>");
+						return;
+					}
+					
+          mpin.startAuthentication(userId, function (err, data) {
+            if (err) {
+              console.error("Error :::", err);
+              return;
+            }
+             mpin.finishAuthenticationAN(userId, userPin, userAN, function (err2, data2) {
+             if (err2) {
+             console.error("Error :::", err2);
+             return;
+             }
+             
+             $(ev.currentTarget).append(" :: Successful");
+             });
+          });
+        });
+
+
+
+
         $("#regButton").click(function (ev) {
           var usrId;
           usrId = $("#mpinUsrId").val();

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/aad05593/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 0b9db1f..e2c2433 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -332,7 +332,7 @@ var mpinjs = (function () {
   };
 
 
-  Mpin.prototype.finishAuthentication = function (userId, aPin, cb) {
+  Mpin.prototype.finishAuthentication = function (userId, pin, cb) {
     var _userState;
 
     //registered
@@ -343,10 +343,10 @@ var mpinjs = (function () {
       return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
-    this._passRequests({userId: userId, aPin: aPin}, cb);
+    this._passRequests({userId: userId, pin: pin}, cb);
   };
 
-  Mpin.prototype.finishAuthenticationOtp = function (userId, aPin, cb) {
+  Mpin.prototype.finishAuthenticationOtp = function (userId, pin, cb) {
     var _userState;
 
     //registered
@@ -357,7 +357,35 @@ var mpinjs = (function () {
       return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
     }
 
-    this._passRequests({userId: userId, aPin: aPin, otp: true}, function (err, data) {
+    this._passRequests({userId: userId, pin: pin, otp: true}, function (err, data) {
+      if (err) {
+        return cb(err, null);
+      }
+
+      if (!data.expireTime || !data.ttlSeconds || !data.nowTime) {
+        return cb(null, null);
+      }
+
+      data.expireTime = data.expireTime / 1000;
+      data.nowTime = data.nowTime / 1000;
+
+      cb(null, data);
+    });
+
+  };
+
+  Mpin.prototype.finishAuthenticationAN = function (userId, pin, accessNumber, cb) {
+    var _userState;
+
+    //registered
+    _userState = this.getUser(userId, "state");
+    if (_userState !== States.register) {
+      return cb(Errors.wrongFlow, null);
+    } else if (!Users[userId].timePermitHex) {
+      return cb({code: Errors.wrongFlow.code, type: Errors.wrongFlow.type, message: "Need to call startAuthentication method before this."}, null);
+    }
+
+    this._passRequests({userId: userId, pin: pin, accessNumber: accessNumber.toString()}, function (err, data) {
       if (err) {
         return cb(err, null);
       }
@@ -375,23 +403,25 @@ var mpinjs = (function () {
   };
 
   Mpin.prototype._passRequests = function (opts, cb) {
-    var userId, aPin, otp, self = this, _reqData = {};
+    var userId, pin, otp, accessNumber, self = this, _reqData = {};
     userId = opts.userId;
-    aPin = opts.aPin;
+    pin = opts.pin;
 
     otp = opts.otp || false;
+    accessNumber = opts.accessNumber || false;
 
     _reqData.url = this.generateUrl("pass1");
     _reqData.type = "POST";
-    _reqData.data = this.getAuthData(userId, aPin);
+    _reqData.data = this.getAuthData(userId, pin);
 
     //  pass1
     this.request(_reqData, function (pass1Err, pass1Data) {
-      var _req2Data = {};
+      var _req2Data = {}, wid = "0";
       _req2Data.url = self.generateUrl("pass2");
       _req2Data.type = "POST";
 
-      _req2Data.data = MPINAuth.pass2Request(pass1Data.y, otp, "0");
+      accessNumber && (wid = accessNumber);
+      _req2Data.data = MPINAuth.pass2Request(pass1Data.y, otp, wid);
 
       _req2Data.data.mpin_id = Users[userId].mpinId;
 
@@ -408,7 +438,7 @@ var mpinjs = (function () {
           delete pass2Data["OTP"];
         }
 
-        self._authenticate({userId: userId, mpinResponse: pass2Data, otpCode: otpCode}, cb);
+        self._authenticate({userId: userId, mpinResponse: pass2Data, otpCode: otpCode, accessNumber: accessNumber}, cb);
       });
     });
 
@@ -417,7 +447,12 @@ var mpinjs = (function () {
   Mpin.prototype._authenticate = function (opts, cb) {
     var _authData = {}, self = this;
 
-    _authData.url = this.generateUrl("auth");
+    if (opts.accessNumber) {
+      _authData.url = this.generateUrl("mobileauth");
+    } else {
+      _authData.url = this.generateUrl("auth");
+    }
+
     _authData.type = "POST";
     _authData.data = {mpinResponse: opts.mpinResponse};
 
@@ -447,8 +482,55 @@ var mpinjs = (function () {
     });
   };
 
+  Mpin.prototype.checkAccessNumber = function (accessNumber) {
+    accessNumber = accessNumber.toString();
+    if (!this.settings.accessNumberUseCheckSum || accessNumber.length != this.settings.accessNumberDigits) {
+      return true;
+    } else {
+      if (this.settings.cSum === 1) {
+        return this.checkAccessNumberSum2(accessNumber, 6);
+      } else {
+        return this.checkAccessNumberSum(accessNumber);
+      }
+    }
+  };
+
+  Mpin.prototype.checkAccessNumberSum = function (accNumber, accLen) {
+    accLen || (accLen = 1);
+
+    var n = parseInt(accNumber.slice(0, accNumber.length - accLen), 10);
+    var cSum = parseInt(accNumber.slice(accNumber.length - accLen, accNumber.length), 10);
+
+    var p = 99991;
+    var g = 11;
+    var checkSum = ((n * g) % p) % Math.pow(10, accLen);
 
-  Mpin.prototype.getAuthData = function (userId, aPin) {
+    return (checkSum === cSum);
+  };
+
+  Mpin.prototype.checkAccessNumberSum2 = function (accNumber, accLen) {
+    var cSum, checksum, x, w, wid, wid_len, g = 11, sum_d = 0;
+    wid = accNumber.toString();
+    wid = wid.substring(0, accNumber.toString().length - 1);
+    w = accLen + 1;
+    sum_d = 0;
+    wid_len = wid.length;
+
+    for (var i = 0; i < wid_len; i++) {
+      x = parseInt(wid[i]);
+      sum_d += (x * w);
+      w -= 1;
+    }
+    checksum = (g - (sum_d % g)) % g;
+    checksum = (checksum === 10) ? 0 : checksum;
+
+    //get last one digit and compare with checksum result
+    cSum = accNumber.substr(-1);
+    cSum = parseInt(cSum);
+    return (cSum === checksum);
+  };
+
+  Mpin.prototype.getAuthData = function (userId, pin) {
     var _auth = {};
 
     _auth.mpin = Users[userId].mpinId;
@@ -456,7 +538,7 @@ var mpinjs = (function () {
     _auth.timePermit = Users[userId].timePermitHex;
     _auth.date = Users[userId].currentDate;
 
-    return MPINAuth.pass1Request(_auth.mpin, _auth.token, _auth.timePermit, aPin, _auth.date, null);
+    return MPINAuth.pass1Request(_auth.mpin, _auth.token, _auth.timePermit, pin, _auth.date, null);
   };
 
   Mpin.prototype.fromHex = function (strData) {
@@ -587,6 +669,9 @@ var mpinjs = (function () {
       case "auth":
         url = this.settings.authenticateURL;
         break;
+      case "mobileauth":
+        url = this.settings.mobileAuthenticateURL;
+        break;
       case "getnumber":
         url = this.settings.getAccessNumberURL;
         break;


[27/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #9 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #9 in MPIN/mpinjs from develop to master

* commit '181a7fe52fc031626c7f8e22fd12725325d1f1f4':
  Check data before store


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/2fee8339
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/2fee8339
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/2fee8339

Branch: refs/heads/add-documentation
Commit: 2fee83396892f05b4530634ecf363c396a879e54
Parents: 61a14f2 181a7fe
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 7 12:45:45 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 7 12:45:45 2016 +0100

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[19/37] incubator-milagro-mfa-js-lib git commit: Add recover identities from previous version

Posted by sa...@apache.org.
Add recover identities from previous version


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/262d4726
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/262d4726
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/262d4726

Branch: refs/heads/add-documentation
Commit: 262d4726f77ff1471ac0809f165bb1518381c29e
Parents: 47feeca
Author: Boyan Bakov <bo...@certivox.com>
Authored: Fri Feb 26 11:23:22 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Fri Feb 26 11:23:22 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 66 +++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 44 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/262d4726/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index cebf804..6250dce 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -50,7 +50,7 @@ var mpinjs = (function () {
     this.recover();
   };
 
-  Mpin.prototype.storageKey = "mpinLib";
+  Mpin.prototype.storageKey = "mpinjs";
 
   Mpin.prototype.init = function (cb) {
     var self = this, _initUrl;
@@ -94,7 +94,7 @@ var mpinjs = (function () {
     } else if (!this.settings.registerURL) {
       return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
     }
-    
+
     //invalid
     _userState = this.getUser(userId, "state");
     if (_userState !== States.invalid) {
@@ -211,7 +211,7 @@ var mpinjs = (function () {
     } else if (!this.settings.registerURL) {
       return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
     }
-    
+
     _userState = this.getUser(userId, "state");
     if (_userState !== States.start) {
       return cb(Errors.wrongFlow, null);
@@ -664,13 +664,13 @@ var mpinjs = (function () {
     if (!this.checkUser(userId)) {
       //create
       Users[userId] = {};
-    }    
+    }
 
     //If mpinId has changed, we need to delete the object withthe previous one
     if (Users[userId].mpinId && userProps.mpinId && Users[userId].mpinId != userProps.mpinId) {
-       this.deleteData(userId);
+      this.deleteData(userId);
     }
-    
+
     for (var uKey in userProps) {
       if (userProps[uKey]) {
         Users[userId][uKey] = userProps[uKey];
@@ -692,28 +692,28 @@ var mpinjs = (function () {
     if (!mpinData || !mpinData.accounts[mpinId]) {
       return;
     }
-    
+
     delete mpinData.accounts[mpinId];
-    
-    this.storeData(mpinData);    
+
+    this.storeData(mpinData);
   };
-  
+
   Mpin.prototype.setData = function (userId, upData) {
     var mpinData = this.getData();
 
     if (!mpinData) {
       mpinData = {
-        version: "0.3",
+        version: "4",
         accounts: {}
       };
     }
 
     var mpinId = upData.mpinId || Users[userId].mpinId;
-    
+
     if (!mpinId) {
       return false;
     }
-    
+
     //update Default Identity
     if (!mpinData.accounts[mpinId]) {
       mpinData.accounts[mpinId] = {};
@@ -743,14 +743,20 @@ var mpinjs = (function () {
     this.storeData(mpinData);
   };
 
-  Mpin.prototype.storeData = function (mpinData) {
-    localStorage.setItem(this.storageKey, JSON.stringify(mpinData));
+  Mpin.prototype.storeData = function (mpinData, key) {
+    var storageKey = key || this.storageKey;
+    localStorage.setItem(storageKey, JSON.stringify(mpinData));
   };
 
   Mpin.prototype.recover = function () {
-    var userId, userData = {}, mpinData = this.getData();
+    var userId, userData = {}, mpinData = this.getData(), isOldData = false;
 
-    if (mpinData && "accounts" in mpinData) {
+    if (!mpinData) {
+      mpinData = this.getData("mpin");
+      isOldData = true;
+    }
+
+    if ("accounts" in mpinData) {
       for (var mpinId in mpinData.accounts) {
         userId = (JSON.parse(this.fromHex(mpinId))).userID;
 
@@ -763,17 +769,33 @@ var mpinjs = (function () {
         mpinData.accounts[mpinId].MPinPermit && (userData.MPinPermit = mpinData.accounts[mpinId].MPinPermit);
         mpinData.accounts[mpinId].timePermitCache && (userData.timePermitCache = mpinData.accounts[mpinId].timePermitCache);
 
-        mpinData.accounts[mpinId].state && (userData.state = mpinData.accounts[mpinId].state);
+        if (isOldData || !mpinData.accounts[mpinId].state) {
+          if (mpinData.accounts[mpinId].token) {
+            userData.state = States.register;
+          } else if (mpinData.accounts[mpinId].regOTT) {
+            userData.state = States.start;
+          } else {
+            userData.state = States.invalid;
+          }
+        } else {
+          userData.state = mpinData.accounts[mpinId].state;
+        }
 
         //call add To user & skip Save
-        this.addToUser(userId, userData, true);
+        this.addToUser(userId, userData, !isOldData);
       }
     }
+
+    if (isOldData) {
+      delete mpinData.accounts;
+      this.storeData(mpinData, "mpin");
+    }
   };
 
-  Mpin.prototype.getData = function () {
-    var mpinData;
-    mpinData = localStorage.getItem(this.storageKey);
+  Mpin.prototype.getData = function (getKey) {
+    var localKey, mpinData;
+    localKey = getKey || this.storageKey;
+    mpinData = localStorage.getItem(localKey);
     mpinData = JSON.parse(mpinData);
     return mpinData;
   };


[03/37] incubator-milagro-mfa-js-lib git commit: Update instructions

Posted by sa...@apache.org.
Update instructions


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/b3762779
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/b3762779
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/b3762779

Branch: refs/heads/add-documentation
Commit: b3762779ac7c2ba0ea055e5f139aec0f4468977b
Parents: c86c030
Author: Simeon Aladjem <si...@certivox.com>
Authored: Wed Dec 16 17:57:48 2015 +0200
Committer: Vladislav Mitov <vl...@certivox.com>
Committed: Fri Dec 18 18:55:25 2015 +0200

----------------------------------------------------------------------
 README.md | 48 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/b3762779/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 337a5ce..7bdcacf 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
-# MPIN frontend library
-
+# Headless M-Pin Client Library
 
 ## Requirement for build & testing
 
 1. Nodejs
 2. Grunt
 3. Mocha
-4. bower
+4. Bower
 
 ## Installation
+
 ```bash
 $ git clone
 $ cd project_folder
@@ -16,33 +16,53 @@ $ npm install
 $ grunt build
 ```
 
-## Example simple usage:
+## Simple usage example
 
 - Registration
 
 ```js
-var mpin = mpinjs({server: serverIP_port});
+var mpin = mpinjs({server: <serverIP-and-port>});
+
+mpin.init(<callback>);
 
-mpin.init(callback);
+mpin.makeNewUser(<userId>);
 
-mpin.makeNewUser(userId);
+mpin.startRegistration(<userId>, <callback>);
 
-mpin.startRegistration(usrId, callback);
+/* Wait for end-user to confirm identity */
 
-mpin.confirmRegistration(userId, callback);
+mpin.confirmRegistration(<userId>, <callback>);
 
-mpin.finishRegistration(userId, userPin);
+/* If successful, read desired user secret (PIN or password) */
+
+mpin.finishRegistration(<userId>, <user-secret>);
 
 ```
 - Authentication
 
 ```js
-mpin.startAuthentication(userId, callback);
+mpin.startAuthentication(<userId>, <callback>);
 
-mpin.finishAuthentication(userId, userPin, callback);
+/* If successful, read user secret (PIN or password) */
 
+mpin.finishAuthentication(<userId>, <user-secret>, <callback>);
 ```
 
+- Authentication with a mobile device
+
+```js
+mpin.getAccessNumber(<callback>);
+
+/* Display Access number to end user */
+
+mpin.waitForMobileAuth(<timeout-sec>, <retry-period-sec>, <callback>);
+
+/*
+   If successfull - Authentication completed
+   If exits with timeout, then no successfull authentication from mobile device was completed
+   If one needs to cancel the waiting for authentication from the mobile device, call cancelMobileAuth()
+*/
+```
 
 ## Running Tests
 
@@ -61,7 +81,3 @@ $ npm test
 Actively tested with node:
 
   - 0.10.4
-
-## Authors
-
-  * MIRACL Ltd.


[17/37] incubator-milagro-mfa-js-lib git commit: Fix addToUser function

Posted by sa...@apache.org.
Fix addToUser function


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/d4defcc4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/d4defcc4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/d4defcc4

Branch: refs/heads/add-documentation
Commit: d4defcc40b14b524179ba3f65bff187eb569c2a1
Parents: 9b77bac
Author: Boyan Bakov <bo...@certivox.com>
Authored: Wed Feb 3 15:42:08 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Wed Feb 10 13:39:56 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 47 +++++++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/d4defcc4/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 3d09851..0ae1be3 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -661,23 +661,23 @@ var mpinjs = (function () {
   };
 
   Mpin.prototype.addToUser = function (userId, userProps, skipSave) {
-    var _save;
-    if (!this.checkUser(userId) && !userProps.userId) {
-      return false;
-    }
-    _save = !skipSave;
-
-    //create
-    if (userProps.userId) {
+    if (!this.checkUser(userId)) {
+      //create
       Users[userId] = {};
-    }
+    }    
 
+    //If mpinId has changed, we need to delete the object withthe previous one
+    if (Users[userId].mpinId && userProps.mpinId && Users[userId].mpinId != userProps.mpinId) {
+       this.deleteData(userId);
+    }
+    
     for (var uKey in userProps) {
       if (userProps[uKey]) {
         Users[userId][uKey] = userProps[uKey];
       }
     }
 
+    var _save = !skipSave;
     _save && this.setData(userId, userProps);
   };
 
@@ -685,6 +685,19 @@ var mpinjs = (function () {
     Users = {};
   };
 
+  Mpin.prototype.deleteData = function (userId) {
+    var mpinData = this.getData();
+
+    var mpinId = Users[userId].mpinId;
+    if (!mpinData || !mpinData.accounts[mpinId]) {
+      return;
+    }
+    
+    delete mpinData.accounts[mpinId];
+    
+    this.storeData(mpinData);    
+  };
+  
   Mpin.prototype.setData = function (userId, upData) {
     var mpinData = this.getData();
 
@@ -695,33 +708,35 @@ var mpinjs = (function () {
       };
     }
 
+    var mpinId = upData.mpinId || Users[userId].mpinId;
+    
+    if (!mpinId) {
+      return false;
+    }
+    
     //update Default Identity
-    if (upData.mpinId) {
-      mpinData.accounts[upData.mpinId] = {};
+    if (!mpinData.accounts[mpinId]) {
+      mpinData.accounts[mpinId] = {};
     }
 
     if (upData.regOTT) {
-      mpinData.accounts[upData.mpinId].regOTT = upData.regOTT;
+      mpinData.accounts[mpinId].regOTT = upData.regOTT;
     }
 
     if (upData.timePermitHex) {
-      var mpinId = Users[userId].mpinId;
       mpinData.accounts[mpinId].MPinPermit = upData.timePermitHex;
     }
 
     if (upData.token) {
-      var mpinId = Users[userId].mpinId;
       mpinData.accounts[mpinId].token = upData.token;
     }
 
     if (upData.state && Users[userId].mpinId) {
-      var mpinId = Users[userId].mpinId;
       mpinData.accounts[mpinId].state = upData.state;
     }
 
     //cache cache
     if (upData.timePermitCache) {
-      var mpinId = Users[userId].mpinId;
       mpinData.accounts[mpinId].timePermitCache = upData.timePermitCache;
     }
 


[25/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #8 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #8 in MPIN/mpinjs from develop to master

* commit '38fd0ed6055a8400d96d981b6fb2faebedf8f32f':
  Check exist data in recover


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/61a14f27
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/61a14f27
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/61a14f27

Branch: refs/heads/add-documentation
Commit: 61a14f27bc4c5989c1d1590e09d9472a8178f9d3
Parents: 505fafc 38fd0ed
Author: Boyan Bakov <bo...@certivox.com>
Authored: Wed Mar 2 16:16:47 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Wed Mar 2 16:16:47 2016 +0100

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[21/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #6 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #6 in MPIN/mpinjs from develop to master

* commit '70a031a912721470257a4e025a75b670f8bf580f':
  Add bamboo reporter & mock Localstorage in tests
  Add recover identities from previous version
  Fix empty response handler
  Fix addToUser function
  Add more error handling for authenticate


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/d3fe0ace
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/d3fe0ace
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/d3fe0ace

Branch: refs/heads/add-documentation
Commit: d3fe0aced1d414de2b1f7a0544f09a2ef6729c12
Parents: a196cfb 70a031a
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Feb 29 16:39:43 2016 +0100
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Feb 29 16:39:43 2016 +0100

----------------------------------------------------------------------
 .gitignore    |   1 +
 lib/mpin.js   | 102 ++++++++++++++++++++++++++++++++++++++---------------
 package.json  |   5 +--
 test/index.js |  34 ++++++++++++++----
 4 files changed, 106 insertions(+), 36 deletions(-)
----------------------------------------------------------------------



[18/37] incubator-milagro-mfa-js-lib git commit: Fix empty response handler

Posted by sa...@apache.org.
Fix empty response handler


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/47feecaf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/47feecaf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/47feecaf

Branch: refs/heads/add-documentation
Commit: 47feecaf10b094182df8c5a2d5ce03a4dee3fdce
Parents: d4defcc
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Feb 15 15:42:46 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Feb 15 15:42:46 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/47feecaf/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 0ae1be3..cebf804 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -788,7 +788,7 @@ var mpinjs = (function () {
 
     _request.onreadystatechange = function () {
       if (_request.readyState === 4 && _request.status === 200) {
-        if (_parseJson) {
+        if (_parseJson && _request.responseText) {
           cb(null, JSON.parse(_request.responseText));
         } else {
           cb(null, _request.responseText);


[14/37] incubator-milagro-mfa-js-lib git commit: Change bower package name.

Posted by sa...@apache.org.
Change bower package name.


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/d0cbb296
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/d0cbb296
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/d0cbb296

Branch: refs/heads/add-documentation
Commit: d0cbb2965b4768ca96f64f8854848584dfb01072
Parents: 451dce6
Author: Boyan Bakov <bo...@certivox.com>
Authored: Tue Jan 5 14:38:40 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Wed Jan 13 16:35:48 2016 +0200

----------------------------------------------------------------------
 bower.json  | 32 ++++++++++++---------
 lib/mpin.js | 88 ++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 88 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/d0cbb296/bower.json
----------------------------------------------------------------------
diff --git a/bower.json b/bower.json
index bf93c48..3e69a9c 100644
--- a/bower.json
+++ b/bower.json
@@ -1,14 +1,18 @@
-{
-	"name": "Mpin lib",
-	"version": "1.0.0",
-	"description": "Mpin lib front-end project",
-	"authors": [
-		"Miracl ltd."
-	],
-	"dependencies": {
-		"clint": "https://builds.certivox.com/mpin_libs/js/latest/js.tar.gz"
-	},
-	"moduleType": "globals",
-	"main": "lib/mpin.js",
-	"homepage": "http://miracl.com"
-}
+{
+	"name": "mpinjs",
+	"version": "1.0.0",
+	"description": "Mpin lib front-end project",
+	"authors": [
+		"Miracl ltd."
+	],
+	"dependencies": {
+		"clint": "https://builds.certivox.com/mpin_libs/js/latest/js.tar.gz"
+	},
+	"ignore": [
+		"**/*",
+		"!lib/mpin.js"
+	],
+	"moduleType": "globals",
+	"main": "lib/mpin.js",
+	"homepage": "http://miracl.com"
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/d0cbb296/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 865d057..f548cdf 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -6,9 +6,9 @@
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at
-
+ 
  http://www.apache.org/licenses/LICENSE-2.0
-
+ 
  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -42,7 +42,7 @@ var mpinjs = (function () {
     }
 
     this.opts = options;
-	this.settings = {};
+    this.settings = {};
 
     this.recover();
   };
@@ -83,7 +83,7 @@ var mpinjs = (function () {
   };
 
   Mpin.prototype.startRegistration = function (userId, cb) {
-    var _reqData = {}, self = this;
+    var _reqData = {}, self = this, _userState;
     if (!userId) {
       return cb ? cb(Errors.missingUserId, null) : {error: 1};
     } else if (!this.checkUser(userId)) {
@@ -91,6 +91,12 @@ var mpinjs = (function () {
     } else if (!this.settings.registerURL) {
       return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
     }
+    
+    //invalid
+    _userState = this.getUser(userId, "state");
+    if (_userState !== States.invalid) {
+      return cb(Errors.wrongFlow, null);
+    }
 
     _reqData.url = this.generateUrl("register");
     _reqData.type = "PUT";
@@ -99,6 +105,10 @@ var mpinjs = (function () {
       mobile: 0
     };
 
+    if (Users[userId].deviceId) {
+      _reqData.data.deviceName = Users[userId].deviceId;
+    }
+
     this.request(_reqData, function (err, data) {
       if (err) {
         return cb(err, null);
@@ -188,12 +198,45 @@ var mpinjs = (function () {
   };
 
   //Put user / mpinId
-  Mpin.prototype.restartRegistration = function (userId, deviceId, cb) {
-    var err = null, data = {};
-    cb(err, data);
-  };
+  Mpin.prototype.restartRegistration = function (userId, cb) {
+    var _reqData = {}, self = this, _userState;
 
+    if (!userId) {
+      return cb ? cb(Errors.missingUserId, null) : {error: 1};
+    } else if (!this.checkUser(userId)) {
+      return cb(Errors.invalidUserId, null);
+    } else if (!this.settings.registerURL) {
+      return cb({code: Errors.missingParams.code, type: Errors.missingParams.type, message: "Missing registerURL"}, null);
+    }
+    
+    _userState = this.getUser(userId, "state");
+    if (_userState !== States.start) {
+      return cb(Errors.wrongFlow, null);
+    }
 
+    _reqData.url = this.generateUrl("restart", {userId: userId});
+    _reqData.type = "PUT";
+    _reqData.data = {
+      userId: userId,
+      mobile: 0,
+      regOTT: Users[userId].regOTT
+    };
+
+    this.request(_reqData, function (err, data) {
+      if (err) {
+        return cb(err, null);
+      }
+
+      self.addToUser(userId, {regOTT: data.regOTT, mpinId: data.mpinId});
+
+      //force activate
+      if (data.active) {
+        self.addToUser(userId, {state: States.active});
+      }
+
+      cb && cb(null, true);
+    });
+  };
 
   Mpin.prototype.startAuthentication = function (userId, cb) {
     var _tp1Url, self = this, _userState;
@@ -217,9 +260,9 @@ var mpinjs = (function () {
     this.request({url: _tp1Url}, function (err, data) {
       if (err) {
         if (err.status === 401 || err.status === 403 || err.status === 410) {
-          return cb(Errors.userRevoked, null);        
+          return cb(Errors.userRevoked, null);
         }
-		
+
         return cb(err, null);
       }
       var _signature, _tp2Url, _timePermit1, _storageUrl;
@@ -243,9 +286,9 @@ var mpinjs = (function () {
           if (storErr) {
             _tp2Url = self.generateUrl('permit2', {userId: userId});
             _tp2Url += "&signature=" + _signature;
-			  
+
             self._getTimePermit2({userId: userId, permit1: _timePermit1, permit2Url: _tp2Url, date: data.date}, cb); //continue
-			
+
             return;
           }
 
@@ -268,7 +311,7 @@ var mpinjs = (function () {
         if (err2.status === 401 || err2.status === 403 || err2.status === 410) {
           return cb(Errors.userRevoked, null);
         }
-		
+
         return cb(err2, null);
       }
 
@@ -438,10 +481,10 @@ var mpinjs = (function () {
       returnData = {
         accessNumber: data.accessNumber,
         ttlSeconds: data.ttlSeconds,
-        localTimeStart: data.localTimeStart/1000,
-        localTimeEnd: data.localTimeEnd/1000
+        localTimeStart: data.localTimeStart / 1000,
+        localTimeEnd: data.localTimeEnd / 1000
       };
-	  
+
       cb && cb(null, returnData);
     });
   };
@@ -475,12 +518,13 @@ var mpinjs = (function () {
           }, _requestPeriod);
           return;
         } else if (self.timeoutPeriod <= 0) {
+          delete self.timeoutPeriod;
           cb && cb(Errors.timeoutFinish, null);
           return;
         }
+      } else {
+        self._authenticate({mpinResponse: data}, cb);
       }
-
-      self._authenticate({mpinResponse: data}, cb);
     });
   };
 
@@ -488,6 +532,10 @@ var mpinjs = (function () {
     if (this.intervalID2) {
       clearInterval(this.intervalID2);
     }
+
+    if (this.timeoutPeriod) {
+      delete this.timeoutPeriod;
+    }
   };
 
 
@@ -498,6 +546,10 @@ var mpinjs = (function () {
       case "register":
         url = this.settings.registerURL;
         break;
+      case "restart":
+        url = this.settings.registerURL + "/";
+        url += Users[options.userId].mpinId;
+        break;
       case "signature":
         url = this.settings.signatureURL + "/";
         url += Users[options.userId].mpinId;


[22/37] incubator-milagro-mfa-js-lib git commit: Move recover to init function

Posted by sa...@apache.org.
Move recover to init function


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/0f359a36
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/0f359a36
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/0f359a36

Branch: refs/heads/add-documentation
Commit: 0f359a36280abe8305c470d7c1e3009e5a74d136
Parents: 70a031a
Author: Boyan Bakov <bo...@certivox.com>
Authored: Tue Mar 1 16:42:51 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Tue Mar 1 16:44:55 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/0f359a36/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index 6250dce..d23d32f 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -47,7 +47,6 @@ var mpinjs = (function () {
     this.opts = options;
     this.settings = {};
 
-    this.recover();
   };
 
   Mpin.prototype.storageKey = "mpinjs";
@@ -55,6 +54,7 @@ var mpinjs = (function () {
   Mpin.prototype.init = function (cb) {
     var self = this, _initUrl;
 
+    this.recover();
     if (this.opts.server.slice(-1) === "/") {
       _initUrl = this.opts.server;
     } else {


[15/37] incubator-milagro-mfa-js-lib git commit: Merge pull request #5 in MPIN/mpinjs from develop to master

Posted by sa...@apache.org.
Merge pull request #5 in MPIN/mpinjs from develop to master

* commit 'd0cbb2965b4768ca96f64f8854848584dfb01072':
  Change bower package name.


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/a196cfbd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/a196cfbd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/a196cfbd

Branch: refs/heads/add-documentation
Commit: a196cfbd4ad4a261b2a985533326cf2240437d38
Parents: 451dce6 d0cbb29
Author: Simeon Aladjem <si...@certivox.com>
Authored: Fri Jan 22 12:03:37 2016 +0100
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Fri Jan 22 12:03:37 2016 +0100

----------------------------------------------------------------------
 bower.json  | 32 ++++++++++++---------
 lib/mpin.js | 88 ++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 88 insertions(+), 32 deletions(-)
----------------------------------------------------------------------



[32/37] incubator-milagro-mfa-js-lib git commit: Update bower dependency

Posted by sa...@apache.org.
Update bower dependency


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/ab970966
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/ab970966
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/ab970966

Branch: refs/heads/add-documentation
Commit: ab970966edbc070be4ecc8d44385450b6d10d763
Parents: 4804d16
Author: Vladislav Mitov <vl...@gmail.com>
Authored: Mon Mar 14 18:00:58 2016 +0200
Committer: Vladislav Mitov <vl...@gmail.com>
Committed: Mon Mar 14 20:00:17 2016 +0200

----------------------------------------------------------------------
 Gruntfile.js | 2 +-
 bower.json   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/ab970966/Gruntfile.js
----------------------------------------------------------------------
diff --git a/Gruntfile.js b/Gruntfile.js
index 78d9edb..8562817 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -6,7 +6,7 @@ module.exports = function(grunt) {
 				separator: ';'
 			},
 			mergeJs: {
-				src: ['bower_components/clint/DBIG.js','bower_components/clint/BIG.js', 'bower_components/clint/FP.js', 'bower_components/clint/ROM.js', 'bower_components/clint/HASH.js', 'bower_components/clint/RAND.js', 'bower_components/clint/AES.js', 'bower_components/clint/GPM.js', 'bower_components/clint/ECP.js', 'bower_components/clint/FP2.js', 'bower_components/clint/ECP2.js', 'bower_components/clint/FP4.js', 'bower_components/clint/FP12.js', 'bower_components/clint/PAIR.js', 'bower_components/clint/MPIN.js', 'bower_components/clint/MPINAuth.js', 'lib/mpin.js'],
+				src: ['bower_components/amcl/js/DBIG.js','bower_components/amcl/js/BIG.js', 'bower_components/amcl/js/FP.js', 'bower_components/amcl/js/ROM.js', 'bower_components/amcl/js/HASH.js', 'bower_components/amcl/js/RAND.js', 'bower_components/amcl/js/AES.js', 'bower_components/amcl/js/GPM.js', 'bower_components/amcl/js/ECP.js', 'bower_components/amcl/js/FP2.js', 'bower_components/amcl/js/ECP2.js', 'bower_components/amcl/js/FP4.js', 'bower_components/amcl/js/FP12.js', 'bower_components/amcl/js/PAIR.js', 'bower_components/amcl/js/MPIN.js', 'bower_components/amcl/js/MPINAuth.js', 'lib/mpin.js'],
 				dest: './dist/mpinjs.js'
 			}
 		},

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/ab970966/bower.json
----------------------------------------------------------------------
diff --git a/bower.json b/bower.json
index 3e69a9c..57b92b0 100644
--- a/bower.json
+++ b/bower.json
@@ -3,10 +3,10 @@
 	"version": "1.0.0",
 	"description": "Mpin lib front-end project",
 	"authors": [
-		"Miracl ltd."
+		"MIRACL"
 	],
 	"dependencies": {
-		"clint": "https://builds.certivox.com/mpin_libs/js/latest/js.tar.gz"
+		"amcl": "https://github.com/miracl/mpin-crypto.git"
 	},
 	"ignore": [
 		"**/*",
@@ -14,5 +14,5 @@
 	],
 	"moduleType": "globals",
 	"main": "lib/mpin.js",
-	"homepage": "http://miracl.com"
+	"homepage": "www.miracl.com"
 }


[10/37] incubator-milagro-mfa-js-lib git commit: Adding USER_REVOKED error.

Posted by sa...@apache.org.
Adding USER_REVOKED error.


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/6d46a672
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/6d46a672
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/6d46a672

Branch: refs/heads/add-documentation
Commit: 6d46a672022a270811b41914b8e0c980561ca1d2
Parents: 166b07b
Author: Simeon Aladjem <si...@certivox.com>
Authored: Tue Dec 22 15:43:37 2015 +0200
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Tue Dec 22 15:43:37 2015 +0200

----------------------------------------------------------------------
 lib/mpin.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/6d46a672/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index c087f8c..86a110e 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -27,7 +27,8 @@ var mpinjs = (function () {
   Error.identityMissing = {code: 4, type: "IDENTITY_MISSING"};
   Error.wrongPin = {code: 5, type: "WRONG_PIN"};
   Error.wrongFlow = {code: 6, type: "WRONG_FLOW"};
-  Error.timeoutFinish = {code: 7, type: "TIMEOUT_FINISH"};
+  Error.userRevoked = {code: 7, type: "USER_REVOKED"};
+  Error.timeoutFinish = {code: 8, type: "TIMEOUT_FINISH"};
 
   State.invalid = "INVALID";
   State.start = "STARTED";


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

Posted by sa...@apache.org.
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;


[26/37] incubator-milagro-mfa-js-lib git commit: Check data before store

Posted by sa...@apache.org.
Check data before store


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/181a7fe5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/181a7fe5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/181a7fe5

Branch: refs/heads/add-documentation
Commit: 181a7fe52fc031626c7f8e22fd12725325d1f1f4
Parents: 38fd0ed
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 7 13:38:39 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 7 13:38:39 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/181a7fe5/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index b6e9f5a..0b9db1f 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -786,7 +786,7 @@ var mpinjs = (function () {
       }
     }
 
-    if (isOldData) {
+    if (isOldData && mpinData && "accounts" in mpinData) {
       delete mpinData.accounts;
       this.storeData(mpinData, "mpin");
     }


[30/37] incubator-milagro-mfa-js-lib git commit: Support for password

Posted by sa...@apache.org.
Support for password


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/0712ac9f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/tree/0712ac9f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/diff/0712ac9f

Branch: refs/heads/add-documentation
Commit: 0712ac9f305cf64a5ef5c273dafc804f2de62844
Parents: aad0559
Author: Boyan Bakov <bo...@certivox.com>
Authored: Mon Mar 14 17:18:33 2016 +0200
Committer: Boyan Bakov <bo...@certivox.com>
Committed: Mon Mar 14 17:18:33 2016 +0200

----------------------------------------------------------------------
 lib/mpin.js | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-js-lib/blob/0712ac9f/lib/mpin.js
----------------------------------------------------------------------
diff --git a/lib/mpin.js b/lib/mpin.js
index e2c2433..70cb32c 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -177,8 +177,6 @@ var mpinjs = (function () {
     });
   };
 
-
-
   Mpin.prototype.finishRegistration = function (userId, pin) {
     var _user, token;
 
@@ -192,6 +190,10 @@ var mpinjs = (function () {
       return Errors.wrongFlow;
     }
 
+    if (isNaN(pin)) {
+      pin = this.toHash(pin);
+    }
+
     token = MPINAuth.calculateMPinToken(Users[userId].mpinId, pin, Users[userId].csHex);
     delete Users[userId].csHex;
 
@@ -405,7 +407,7 @@ var mpinjs = (function () {
   Mpin.prototype._passRequests = function (opts, cb) {
     var userId, pin, otp, accessNumber, self = this, _reqData = {};
     userId = opts.userId;
-    pin = opts.pin;
+    pin = isNaN(opts.pin) ? this.toHash(opts.pin) : opts.pin;
 
     otp = opts.otp || false;
     accessNumber = opts.accessNumber || false;
@@ -557,6 +559,14 @@ var mpinjs = (function () {
     return result;
   };
 
+  Mpin.prototype.toHash = function (strData) {
+    var hash = 0;
+    for (var i = 0; i < strData.length; i++) {
+      hash = ((hash << 5) - hash) + strData.charCodeAt(i);
+    }
+    return hash;
+  };
+
   Mpin.prototype.getAccessNumber = function (cb) {
     var self = this, _reqData = {};