Merge pull request #6 from miracl/multiProtocols

Preparation for support multi authentication protocols
diff --git a/lib/mpin.js b/lib/mpin.js
index 1ee8159..12901c3 100644
--- a/lib/mpin.js
+++ b/lib/mpin.js
@@ -51,6 +51,16 @@
 
   Mpin.prototype.storageKey = "mpinjs";
 
+  //supportedProtocols
+  // temporary until extend with other portocols
+  // then supported should be object of objects
+  Mpin.prototype.cfg = {
+    protocols: {
+      supported: ["2pass"],
+      default: "2pass"
+    }
+  };
+
   Mpin.prototype.init = function (cb) {
     var self = this, _initUrl;
 
@@ -71,6 +81,7 @@
       self.ready = true;
       self.settings = data;
 
+      self.chooseAuthProtocol();
       cb && cb(null, true);
     });
   };
@@ -333,6 +344,36 @@
     });
   };
 
+  Mpin.prototype.chooseAuthProtocol = function () {
+    var self = this;
+    this.authProtocol = this.cfg.protocols.default;
+
+    // We have 3 arrays:
+    // 1. Ordered list of protocols sent from the server - this.settings.supportedProtocols
+    // 2. List of protocols supported by the library - self.cfg.protocols.supported
+    // 3. List of protocols that the library user would like to support - this.opts.authProtocols
+    // The goal is to select the first protocol from the server's list (1) that is supported by the library (2) and selected by the lib user (3).
+    // If the lib user didn't provide any preferences, then we select the first one from the server's list that is supported by the lib.
+    if (this.settings.supportedProtocols && this.settings.supportedProtocols instanceof Array) {
+      if (this.opts.authProtocols && this.opts.authProtocols instanceof Array) {
+
+        this.settings.supportedProtocols.some(function (value) {
+          if (self.opts.authProtocols.indexOf(value) !== -1 && self.cfg.protocols.supported.indexOf(value) !== -1) {
+            self.authProtocol = value;
+            return true;
+          }
+        });
+      } else {
+        this.settings.supportedProtocols.some(function (value) {
+          if (self.cfg.protocols.supported.indexOf(value) !== -1) {
+            self.authProtocol = value;
+            return true;
+          }
+        });
+      }
+    }
+  };
+
 
   Mpin.prototype.finishAuthentication = function (userId, pin, cb) {
     var _userState;
@@ -345,7 +386,11 @@
       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}, cb);
+    // The following checks that the authentication protocol is 2pass.
+    // This is temporary until the lib supports other protocols
+    if (this.authProtocol === this.cfg.protocols.default) {
+      this._pass2Requests({userId: userId, pin: pin}, cb);
+    }
   };
 
   Mpin.prototype.finishAuthenticationOtp = function (userId, pin, cb) {
@@ -359,21 +404,24 @@
       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, otp: true}, function (err, data) {
-      if (err) {
-        return cb(err, null);
-      }
+    // The following checks that the authentication protocol is 2pass.
+    // This is temporary until the lib supports other protocols
+    if (this.authProtocol === this.cfg.protocols.default) {
+      this._pass2Requests({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);
-      }
+        if (!data.expireTime || !data.ttlSeconds || !data.nowTime) {
+          return cb(null, null);
+        }
 
-      data.expireTime = data.expireTime / 1000;
-      data.nowTime = data.nowTime / 1000;
+        data.expireTime = data.expireTime / 1000;
+        data.nowTime = data.nowTime / 1000;
 
-      cb(null, data);
-    });
-
+        cb(null, data);
+      });
+    }
   };
 
   Mpin.prototype.finishAuthenticationAN = function (userId, pin, accessNumber, cb) {
@@ -387,24 +435,27 @@
       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);
-      }
+    // The following checks that the authentication protocol is 2pass.
+    // This is temporary until the lib supports other protocols
+    if (this.authProtocol === this.cfg.protocols.default) {
+      this._pass2Requests({userId: userId, pin: pin, accessNumber: accessNumber.toString()}, function (err, data) {
+        if (err) {
+          return cb(err, null);
+        }
 
-      if (!data.expireTime || !data.ttlSeconds || !data.nowTime) {
-        return cb(null, null);
-      }
+        if (!data.expireTime || !data.ttlSeconds || !data.nowTime) {
+          return cb(null, null);
+        }
 
-      data.expireTime = data.expireTime / 1000;
-      data.nowTime = data.nowTime / 1000;
+        data.expireTime = data.expireTime / 1000;
+        data.nowTime = data.nowTime / 1000;
 
-      cb(null, data);
-    });
-
+        cb(null, data);
+      });
+    }
   };
 
-  Mpin.prototype._passRequests = function (opts, cb) {
+  Mpin.prototype._pass2Requests = function (opts, cb) {
     var userId, pin, otp, accessNumber, self = this, _reqData = {};
     userId = opts.userId;
     pin = isNaN(opts.pin) ? this.toHash(opts.pin) : opts.pin;
@@ -643,7 +694,7 @@
         authOTT = data.authOTT
         delete data.authOTT
 
-        if(data.status === 'authenticate') {
+        if (data.status === 'authenticate') {
           cbStatus && cbStatus(data);
           self._authenticate({mpinResponse: {authOTT: authOTT}}, cb);
         } else {
@@ -651,8 +702,8 @@
             _requestPeriod = requestSeconds ? requestSeconds * 1000 : 3000;
             self.timeoutPeriod -= _requestPeriod;
             if (data.status !== self.mobileStatus) {
-                self.mobileStatus = data.status;
-                cbStatus && cbStatus(data);
+              self.mobileStatus = data.status;
+              cbStatus && cbStatus(data);
             }
             self.intervalID2 = setTimeout(function () {
               self.waitForMobileAuth.call(self, timeoutSeconds, requestSeconds, cb, cbStatus);