LogonController.js

1       var utils = sap.logon.Utils;
2       var TIMEOUT = 2000;
3       
4       var _oLogonCore;
5       var _oLogonView;
6       var _hasLogonSuccessEventFired = false;
7       
8       var _providedContext;
9       var flowqueue;
10      
11      var init = function (successCallback, errorCallback, applicationId, context, customView) {
12          
13          document.addEventListener("resume",
14                                    function(){
15                                    resume(
16                                           function() { fireEvent('onSapResumeSuccess', arguments);},
17                                           function() { fireEvent('onSapResumeError', arguments);}
18                                           );
19                                    },
20                                    false);
21          
22          // The success callback used for the call to _oLogonCore.initLogon(...)
23          var initSuccess = function(){
24              utils.log('LogonController: LogonCore successfully initialized.');
25              
26              // Now that Logon is initialized, registerOrUnlock is automatically called.
27              registerOrUnlock( successCallback, errorCallback );
28          }
29          
30          var initError = function(error){
31              // If a parameter describing the error is given, pass it along.
32              // Otherwise, construct something to call the error callback with.
33              if( error ) {
34                  errorCallback( error );
35              } else {
36                  errorCallback( utils.Error('ERR_INIT_FAILED') );
37              }
38          }
39          
40          
41          utils.log('LogonController.init enter');
42          utils.log(applicationId);
43          module.exports.applicationId = applicationId;
44          
45          // Make note of the context given (if any)
46          if( context ){
47              _providedContext = context;
48          }
49          
50          _oLogonView = customView;
51          if (!_oLogonView) {
52              _oLogonView = sap.logon.IabUi;
53          }
54      
55          flowqueue = new FlowRunnerQueue();
56          
57          //coLogonCore.cordova.require("com.sap.mp.cordova.plugins.logon.LogonCore");
58          _oLogonCore = sap.logon.Core;
59          _oLogonCore.initLogon(initSuccess, initError, applicationId);
60          
61          //update exports definition
62          module.exports.core = _oLogonCore;
63      }
64      
65      var fireEvent = function (eventId, args) {
66          if (typeof eventId === 'string') {
67              //var event = document.createEvent('Events');
68              //event.initEvent(eventId, false, false);
69              
70              if (!window.CustomEvent) {
71                  window.CustomEvent = function(type, eventInitDict) {
72                      var newEvent = document.createEvent('CustomEvent');
73                      newEvent.initCustomEvent(
74                                               type,
75                                               !!(eventInitDict && eventInitDict.bubbles),
76                                               !!(eventInitDict && eventInitDict.cancelable),
77                                               (eventInitDict ? eventInitDict.detail : null));
78                      return newEvent;
79                  };
80              }
81              
82              var event = new CustomEvent(eventId, { 'detail':{ 'id': eventId, 'args': args }});
83              
84              setTimeout(function() {
85                         document.dispatchEvent(event);
86                         }, 0);
87          } else {
88              throw 'Invalid eventId: ' + JSON.stringify(event);
89          }
90      }
91      
92      var FlowRunner = function(callbacks, pLogonView, pLogonCore, flowClass) {
93          
94          var onFlowSuccess;
95          var onFlowError;
96          var onFlowCancel;
97          
98          var logonView;
99          var logonCore;
100         var flow;
101         
102         var onsuccess = callbacks.onsuccess;
103         var onerror = callbacks.onerror;
104         
105         
106         
107         logonView = pLogonView;
108         logonCore = pLogonCore;
109         
110         onFlowSuccess = function onFlowSuccess() {
111             utils.logJSON('onFlowSuccess');
112             logonView.close();
113             onsuccess.apply(this, arguments);
114         }
115         
116         onFlowError = function onFlowError() {
117             utils.logJSON('onFlowError');
118             logonView.close();
119             onerror.apply(this, arguments);
120         }
121         
122         onFlowCancel = function onFlowCancel(){
123             utils.logJSON('onFlowCancel');
124             //logonView.close();
125             onFlowError(new utils.Error('ERR_USER_CANCELLED'));
126         }
127         
128         var handleCoreStateOnly = function(currentState){
129             handleCoreResult(null, currentState);
130         }
131         
132         var handleCoreResult = function (currentContext, currentState) {
133             if (typeof currentContext === undefined) currentContext = null;
134             
135             //workaround for defaultPasscodeAllowed
136             if (currentState) {
137                 if (currentContext && currentContext.policyContext && currentContext.policyContext.defaultAllowed){
138                     currentState.defaultPasscodeAllowed = true;
139                 }
140                 else {
141                     currentState.defaultPasscodeAllowed = false;
142                 }
143             }
144             
145             utils.logJSON(currentContext, 'handleCoreResult currentContext');
146             utils.logJSON(currentState, 'handleCoreResult currentState');
147             
148             
149             utils.logJSON(flow.name);
150             var matchFound = false;
151             var rules = flow.stateTransitions;
152             
153             
154         ruleMatching:
155             for (key in rules){
156                 
157                 var rule = flow.stateTransitions[key];
158                 //utils.logJSON(rule, 'rule');
159                 
160                 //utils.logJSON(rule.condition, 'rule.condition');
161                 if (typeof rule.condition === 'undefined') {
162                     throw 'undefined condition in state transition rule';
163                 }
164                 
165                 
166                 if (rule.condition.state === null) {
167                     if (currentState)
168                     {
169                         continue ruleMatching; // non-null state (and rule) mismatch
170                     }
171                     //else {
172                     //	// match:
173                     //	// rule.condition.state === null &&
174                     //	// (typeof currentState === 'undefined') // null or undefined
175                     //}
176                 }
177                 else if (rule.condition.state !== 'undefined' && currentState){
178                     utils.log('stateMatching');
179                     
180                 stateMatching:
181                     for (field in rule.condition.state) {
182                         utils.log(field);
183                         if (rule.condition.state[field] === currentState[field])
184                         {
185                             utils.log('field matching ' + field);
186                             continue stateMatching; // state field match
187                         }
188                         else {
189                             utils.log('field mismatching ' + field);
190                             continue ruleMatching; // state field (and rule) mismatch
191                         };
192                     }
193                 }
194                 
195                 if (rule.condition.context === null) {
196                     if (currentContext)
197                     {
198                         continue ruleMatching; // non-null context (and rule) mismatch
199                     }
200                     //else {
201                     //	// match:
202                     //	// rule.condition.context === null &&
203                     //	// (typeof currentContext === 'undefined') // null or undefined
204                     //}
205                 }
206                 else if (rule.condition.context !== 'undefined' && currentContext){
207                     
208                     utils.log('contextMatching');
209                 contextMatching:
210                     for (field in rule.condition.context) {
211                         utils.log(field);
212                         if (rule.condition.context[field] === currentContext[field])
213                         {
214                             utils.log('field matching ' + field);
215                             continue contextMatching;  // context field match
216                         }
217                         else {
218                             utils.log('field mismatching ' + field);
219                             continue ruleMatching;  // context field (and rule) mismatch
220                         };
221                     }
222                 }
223                 utils.log('match found');
224                 utils.logJSON(rule, 'rule');
225                 
226                 if (typeof rule.action === 'function') {
227                     rule.action(currentContext);
228                 }
229                 else if (typeof rule.action === 'string') {
230                     // the action is a screenId
231                     var screenId = rule.action;
232                     utils.log('handleCoreResult: ' + screenId);
233                     utils.logKeys(flow.screenEvents[screenId]);
234                     if(!currentContext){
235                         currentContext = {};
236                     }
237                     
238                     if( !currentContext.registrationContext && _providedContext ){
239                         // The current registrationContext is null, and we have been given a context when initialized,
240                         // so use the one we were given.
241                         currentContext.registrationContext = _providedContext;
242                     } else if (currentContext.registrationContext && _providedContext && !currentContext.registrationReadOnly && !(currentState.stateAfaria=='initializationSuccessful')){
243                         for (key in _providedContext) {
244                             //if (!currentContext.registrationContext[key]){
245                             currentContext.registrationContext[key] = _providedContext[key];
246                             //}
247                         }
248                     }
249                     
250                     logonView.showScreen(screenId, flow.screenEvents[screenId], currentContext);
251                     
252                 }
253                 else {
254                     onFlowError(new utils.Error('ERR_INVALID_ACTION'));
255                 }
256                 
257                 matchFound = true;
258                 break ruleMatching;
259             }
260             
261             if (!matchFound) {
262                 onFlowError(new utils.Error('ERR_INVALID_STATE'));
263             }
264         }
265         
266         flow = new flowClass(logonCore, logonView, handleCoreResult, onFlowSuccess, onFlowError, onFlowCancel);
267         
268         this.run = function() {
269             utils.log('FlowRunner.run '  + flowClass.name);
270             utils.logKeys(flow , 'new flow ');
271             logonCore.getState(handleCoreStateOnly, onFlowError);
272         }
273     }
274     
275     var FlowRunnerQueue = function() {
276         var isRunning = false;
277         var innerQueue = [];
278         
279         this.add = function(flowRunner) {
280             innerQueue.push(flowRunner);
281             if (isRunning == false) {
282                 isRunning = true;
283                 process();
284             }
285         }
286         
287        this.runNextFlow = function() {
288         	innerQueue.shift();
289             if (innerQueue.length == 0) {
290                 isRunning = false;
291             }
292             else {
293                 process();
294             }
295         }
296         
297         var process = function() {
298             if (innerQueue.length > 0) {
299                 var flowRunner = innerQueue[0];
300                 flowRunner.run();
301             }
302             else {
303                 isRunning = false;
304             }
305         }
306     }
307     
308     
309     var MockFlow = function MockFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
310         //wrapped into a function to defer evaluation of the references to flow callbacks
311         //var flow = {};
312         
313         this.name = 'mockFlowBuilder';
314         
315         this.stateTransitions = [
316                                  {
317                                  condition: {
318                                  state: {
319                                  secureStoreOpen: false,
320                                  }
321                                  },
322                                  action: 'SCR_MOCKSCREEN'
323                                  },
324                                  {
325                                  condition: {
326                                  state: {
327                                  secureStoreOpen: true,
328                                  }
329                                  },
330                                  action: 'SCR_MOCKSCREEN'
331                                  },
332                                  
333                                  ];
334         
335         this.screenEvents = {
336             'SCR_TURN_PASSCODE_ON': {
337             onsubmit: onFlowSuccess,
338             oncancel: onFlowCancel,
339             onerror: onFlowError,
340             }
341         };
342         
343         utils.log('flow constructor return');
344         //return flow;
345     }
346     
347     var RegistrationFlow = function RegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
348         //wrapped into a function to defer evaluation of the references to flow callbacks
349         
350         this.name = 'registrationFlowBuilder';
351         
352         var registrationInProgress = false;
353         
354         var onCancelSSOPin = function() {
355             onFlowError(errorWithDomainCodeDescription("MAFLogon","0","SSO Passcode set screen was cancelled"));
356         }
357         
358         var onCancelRegistration = function() {
359             onFlowError(errorWithDomainCodeDescription("MAFLogon","1","Registration screen was cancelled"));
360         }
361         
362         // internal methods
363         var showScreen = function(screenId) {
364             return function(coreContext) {
365                 logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
366             }.bind(this);
367         }.bind(this);
368         
369         var onUnlockSubmit = function(context){
370             utils.logJSON(context, 'logonCore.unlockSecureStore');
371             logonCore.unlockSecureStore(onCoreResult, onUnlockError, context)
372         }
373         
374         var onUnlockError = function(error) {
375             utils.logJSON("onUnlockError: " + JSON.stringify(error));
376             
377             // TODO switch case according to the error codes
378             if (error 
379                     && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain"
380                     && error.errorCode && error.errorCode === "16") {
381                     // Too many attempts --> DV deleted
382                     logonView.showNotification("ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE")
383             }
384             else {
385                     logonView.showNotification("ERR_UNLOCK_FAILED");
386             }
387     
388         }
389         
390         var onSetAfariaCredentialError = function(error) {
391             utils.logJSON("onSetAfariaCredentialError: " + JSON.stringify(error));
392             
393             logonView.showNotification("ERR_SET_AFARIA_CREDENTIAL_FAILED");
394         }
395         
396         var noOp = function() { }
397     
398         var onErrorAck = function(ack) {
399             if (ack.key === 'ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE') {
400                 	onFlowError(new utils.Error('ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE'));
401             }
402         }
403     
404         
405         var onRegistrationBackButton = function() {
406             if (registrationInProgress == true) {
407                 utils.log('back button pushed, no operation is required as registration is running');
408             }
409             else {
410                 onCancelRegistration();
411             }
412         }
413         
414         var onUnlockVaultWithDefaultPasscode = function(){
415             utils.log('logonCore.unlockSecureStore - default passcode');
416             var unlockContext = {"unlockPasscode":null};
417             logonCore.unlockSecureStore(onCoreResult, onFlowError, unlockContext)
418         }
419         
420         var onRegSucceeded = function(context, state) {
421             onCoreResult(context, state);
422             registrationInProgress = false;
423         }
424         
425         var onRegError = function(error){
426             utils.logJSON(error, 'registration failed');
427             logonView.showNotification(getRegistrationErrorText(error));
428             registrationInProgress = false;
429         }
430         
431         var onRegSubmit = function(context){
432             utils.logJSON(context, 'logonCore.startRegistration');
433             registrationInProgress = true;
434             logonCore.startRegistration(onRegSucceeded, onRegError, context)
435         }
436         
437         var onCreatePasscodeSubmit = function(context){
438             utils.logJSON(context, 'logonCore.persistRegistration');
439             logonCore.persistRegistration(onCoreResult, onCreatePasscodeError, context);
440         }
441         
442         var onCancelRegistrationError = function(error){
443             utils.logJSON("onCancelRegistrationError: " + JSON.stringify(error));
444             logonView.showNotification(getRegistrationCancelError(error));
445         }
446         
447         var onCreatePasscodeError = function(error) {
448             utils.logJSON("onCreatePasscodeError: " + JSON.stringify(error));
449             logonView.showNotification(getSecureStoreErrorText(error));
450         }
451         
452         var onSSOPasscodeSetError = function(error) {
453             utils.logJSON("onSSOPasscodeSetError: " + JSON.stringify(error));
454             logonView.showNotification(getSSOPasscodeSetErrorText(error));
455         }
456         
457         var callGetContext = function(){
458             utils.log('logonCore.getContext');
459             logonCore.getContext(onCoreResult, onFlowError);
460         }
461         
462         var onFullRegistered = function()
463         {
464             var getContextSuccessCallback = function(result){
465                 
466                 if(!_hasLogonSuccessEventFired) {
467                     fireEvent("onSapLogonSuccess", arguments);
468                     _hasLogonSuccessEventFired = true;
469                 }
470                 
471                 onFlowSuccess(result);
472             }
473             utils.log('logonCore.getContext');
474             logonCore.getContext(getContextSuccessCallback, onFlowError);
475         }
476         
477         var onForgotAppPasscode = function(){
478             utils.log('logonCore.deleteRegistration');
479             logonCore.deleteRegistration(onFlowError, onFlowError);
480         }
481         
482         var onForgotSsoPin = function(){
483             utils.log('forgotSSOPin');
484             logonView.showNotification("ERR_FORGOT_SSO_PIN");
485         }
486         
487         var onSkipSsoPin = function(){
488             utils.logJSON('logonCore.skipClientHub');
489             logonCore.skipClientHub(onCoreResult, onFlowError);
490         }
491         
492         var callPersistWithDefaultPasscode = function(context){
493             utils.logJSON(context, 'logonCore.persistRegistration');
494             context.passcode = null;
495             logonCore.persistRegistration(
496                                           onCoreResult,
497                                           onFlowError,
498                                           context)
499         }
500         
501         // exported properties
502         this.stateTransitions = [
503                                  {
504                                  condition: {
505                                  state: {
506                                  secureStoreOpen: false,
507                                  status: 'fullRegistered',
508                                  defaultPasscodeUsed: true
509                                  }
510                                  },
511                                  action: onUnlockVaultWithDefaultPasscode
512                                  },
513                                  
514                                  {
515                                  condition: {
516                                  state: {
517                                  secureStoreOpen: false,
518                                  status: 'fullRegistered'
519                                  }
520                                  },
521                                  action: 'SCR_UNLOCK'
522                                  },
523                                  
524                                  
525                                  {
526                                  condition: {
527                                  state: {
528                                  //secureStoreOpen: false, //TODO clarify
529                                  status: 'fullRegistered',
530                                  stateClientHub: 'availableNoSSOPin'
531                                  }
532                                  },
533                                  action: 'SCR_SSOPIN_SET'
534                                  },
535                                  {
536                                  condition: {
537                                  state: {
538                                  status: 'new'
539                                  },
540                                  context: null
541                                  },
542                                  action: callGetContext
543                                  },
544                                  
545                                  {
546                                  condition: {
547                                  state: {
548                                  status: 'new',
549                                  stateClientHub: 'availableNoSSOPin'
550                                  }
551                                  },
552                                  action: 'SCR_SSOPIN_SET'
553                                  },
554                                  
555                                  {
556                                  condition: {
557                                  state: {
558                                  status: 'new',
559                                  stateClientHub: 'availableInvalidSSOPin'
560                                  }
561                                  },
562                                  action: 'SCR_SSOPIN_SET'
563                                  },
564                                  {
565                                  condition: {
566                                  state: {
567                                  status: 'new',
568                                  stateClientHub: 'availableValidSSOPin',
569                                  stateAfaria: 'credentialNeeded'
570                                  },
571                                  context : {
572                                  afariaRegistration: 'certificate'
573                                  }
574                                  },
575                                  action: 'SCR_ENTER_AFARIA_CREDENTIAL'
576                                  },
577                                  {
578                                  condition: {
579                                  state: {
580                                  status: 'new',
581                                  stateClientHub: 'notAvailable',
582                                  stateAfaria: 'credentialNeeded'
583                                  }
584                                  },
585                                  action: 'SCR_ENTER_AFARIA_CREDENTIAL'
586                                  },
587                                  {
588                                  condition: {
589                                  state: {
590                                  status: 'new',
591                                  isAfariaCredentialsProvided: false
592                                  },
593                                  context : {
594                                  afariaRegistration: 'certificate'
595                                  }
596                                  },
597                                  action: 'SCR_ENTER_AFARIA_CREDENTIAL'
598                                  },
599                                  {
600                                  condition: {
601                                  state: {
602                                  status: 'new',
603                                  stateClientHub: 'availableValidSSOPin'
604                                  },
605                                  context : {
606                                  credentialsByClientHub : true,
607                                  registrationReadOnly : true
608                                  }
609                                  },
610                                  action: function(context){
611                                  utils.logJSON(context, 'logonCore.startRegistration');
612                                  logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
613                                  }
614                                  },
615                                  {
616                                  condition: {
617                                  state: {
618                                  status: 'new',
619                                  stateClientHub: 'availableValidSSOPin',
620                                  isAfariaCredentialsProvided: true
621                                  },
622                                  context : {
623                                  afariaRegistration: 'certificate',
624                                  registrationReadOnly : true
625                                  }
626                                  },
627                                  action: function(context){
628                                  utils.logJSON(context, 'logonCore.startRegistration');
629                                  logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
630                                  }
631                                  },
632                                  {
633                                  condition: {
634                                  state: {
635                                  status: 'new',
636                                  stateClientHub: 'availableValidSSOPin',
637                                  stateAfaria: 'initializationSuccessful'
638                                  },
639                                  context : {
640                                  registrationReadOnly : true,
641                                  afariaRegistration: 'certificate'
642                                  }
643                                  },
644                                  action: function(context){
645                                  utils.logJSON(context, 'logonCore.startRegistration');
646                                  logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
647                                  }
648                                  },
649                                  {
650                                  condition: {
651                                  state: {
652                                  status: 'new',
653                                  stateClientHub: 'notAvailable',
654                                  stateAfaria: 'initializationSuccessful'
655                                  },
656                                  context : {
657                                  afariaRegistration: 'certificate'
658                                  }
659                                  },
660                                  action: function(context){
661                                  utils.logJSON(context, 'logonCore.startRegistration');
662                                  logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
663                                  }
664                                  },
665                                  {
666                                  condition: {
667                                  state: {
668                                  status: 'new',
669                                  stateAfaria: 'initializationSuccessful'
670                                  }
671                                  },
672                                  action: 'SCR_ENTER_CREDENTIALS'
673                                  },
674                                  {
675                                  condition: {
676                                  state: {
677                                  status: 'new',
678                                  stateClientHub: 'availableValidSSOPin'
679                                  },
680                                  context : {
681                                  registrationReadOnly :true,
682                                  credentialsByClientHub : false
683                                  }
684                                  },
685                                  action: 'SCR_ENTER_CREDENTIALS'
686                                  },
687                                  
688                                  
689                                  {
690                                  condition: {
691                                  state: {
692                                  status: 'new',
693                                  //stateClientHub: 'notAvailable' | 'availableValidSSOPin' | 'skipped' | 'error'
694                                  stateAfaria: 'initializationFailed'
695                                  }
696                                  },
697                                  action: 'SCR_REGISTRATION'
698                                  },
699                                  
700                                  {
701                                  condition: {
702                                  state: {
703                                  status: 'new',
704                                  //stateClientHub: 'notAvailable' | 'availableValidSSOPin' | 'skipped' | 'error'
705                                  }
706                                  },
707                                  action: 'SCR_REGISTRATION'
708                                  },
709                                  
710                                  {
711                                  condition: {
712                                  state: {
713                                  status: 'new',
714                                  //stateClientHub: 'notAvailable' | 'availableValidSSOPin' | 'skipped' | 'error'
715                                  stateAfaria: 'initializationFailed'
716                                  }
717                                  },
718                                  action: 'SCR_REGISTRATION'
719                                  },
720                                  
721                                  {
722                                  condition: {
723                                  state: {
724                                  secureStoreOpen: false,
725                                  status: 'registered',
726                                  defaultPasscodeUsed: true,
727                                  //                        defaultPasscodeAllowed: true,
728                                  }
729                                  },
730                                  action: 'SCR_SET_PASSCODE_OPT_OFF'
731                                  },
732                                  {
733                                  condition: {
734                                  state: {
735                                  secureStoreOpen: false,
736                                  status: 'registered',
737                                  defaultPasscodeUsed: false,
738                                  defaultPasscodeAllowed: true,
739                                  }
740                                  },
741                                  action: 'SCR_SET_PASSCODE_OPT_ON'
742                                  },
743                                  {
744                                  condition: {
745                                  state: {
746                                  secureStoreOpen: false,
747                                  status: 'registered',
748                                  //                        defaultPasscodeAllowed: false,
749                                  }
750                                  },
751                                  action: 'SCR_SET_PASSCODE_MANDATORY'
752                                  },
753                                  
754                                  
755                                  {
756                                  condition: {
757                                  state: {
758                                  //secureStoreOpen: false, //TODO clarify
759                                  status: 'fullRegistered',
760                                  stateClientHub: 'availableInvalidSSOPin'
761                                  }
762                                  },
763                                  action: 'SCR_SSOPIN_CHANGE'
764                                  },
765                                  {
766                                  condition: {
767                                  state: {
768                                  secureStoreOpen: true,
769                                  status: 'fullRegistered',
770                                  stateClientHub: 'notAvailable'
771                                  }
772                                  },
773                                  action: onFullRegistered
774                                  },
775                                  {
776                                  condition: {
777                                  state: {
778                                  secureStoreOpen: true,
779                                  status: 'fullRegistered',
780                                  stateClientHub: 'availableValidSSOPin'
781                                  }
782                                  },
783                                  action: onFullRegistered
784                                  },
785                                  {
786                                  condition: {
787                                  state: {
788                                  secureStoreOpen: true,
789                                  status: 'fullRegistered',
790                                  stateClientHub: 'skipped'
791                                  }
792                                  },
793                                  action: onFullRegistered
794                                  },
795                                  
796                                  
797                                  
798                                  ];
799         
800         this.screenEvents = {
801             'SCR_SSOPIN_SET': {
802             onsubmit: function(context){
803                 utils.logJSON(context, 'logonCore.setSSOPasscode');
804                 logonCore.setSSOPasscode(onCoreResult, onSSOPasscodeSetError, context);
805             },
806             oncancel: onCancelSSOPin,
807             onerror: onFlowError,
808             onforgot: onForgotSsoPin,
809             onskip: onSkipSsoPin
810             },
811             
812             'SCR_ENTER_AFARIA_CREDENTIAL' : {
813             onsubmit: function(context){
814                 utils.logJSON(context, 'logonCore.setAfariaCredential');
815                 logonCore.setAfariaCredential(onCoreResult, onSetAfariaCredentialError, context);
816             }
817             },
818             
819             'SCR_SSOPIN_CHANGE': {
820             onsubmit: function(context){
821                 utils.logJSON(context, 'logonCore.setSSOPasscode');
822                 logonCore.setSSOPasscode(onCoreResult, onSSOPasscodeSetError, context);
823             },
824             oncancel: onSkipSsoPin,
825             onerror: onFlowError,
826             onforgot: onForgotSsoPin
827             },
828             
829             'SCR_UNLOCK': {
830             onsubmit: onUnlockSubmit,
831             oncancel: noOp,
832             onerror: onFlowError,
833             onforgot: onForgotAppPasscode,
834             onerrorack: onErrorAck
835             },
836             
837             'SCR_REGISTRATION':  {
838             onsubmit: onRegSubmit,
839             oncancel: onCancelRegistration,
840             onerror: onFlowError,
841             onbackbutton: onRegistrationBackButton
842             },
843             
844             'SCR_ENTER_CREDENTIALS' : {
845             onsubmit: onRegSubmit,
846             oncancel: onCancelRegistration,
847             onerror: onFlowError
848             },
849             'SCR_SET_PASSCODE_OPT_ON': {
850             onsubmit: onCreatePasscodeSubmit,
851             oncancel: noOp,
852             onerror: onFlowError,
853             ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
854             onerrorack: noOp
855             },
856             'SCR_SET_PASSCODE_OPT_OFF': {
857             onsubmit: callPersistWithDefaultPasscode,
858             oncancel: noOp,
859             onerror: onFlowError,
860             onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
861             onerrorack: noOp
862             },
863             'SCR_SET_PASSCODE_MANDATORY': {
864             onsubmit: onCreatePasscodeSubmit,
865             oncancel: noOp,
866             onerror: onFlowError,
867             onerrorack: noOp
868             },
869             
870             
871             
872         };
873         
874         
875         utils.log('flow constructor return');
876     }
877     
878     
879     
880     var ChangePasswordFlow = function ChangePasswordFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
881         //wrapped into a function to defer evaluation of the references to flow callbacks
882         
883         this.name = 'changePasswordFlowBuilder';
884         
885         
886         // internal methods
887         
888         var callUnlockFlow = function(){
889             utils.log(this.name + ' triggered unlock');
890             registerOrUnlock(onCoreResult,onFlowError);
891         }
892         
893         var onChangePasswordSubmit = function(context){
894             utils.logJSON(context, 'logonCore.changePassword');
895             // this logonCore call does not return with context
896             logonCore.changePassword(onPasswordChanged, onFlowError, context);
897         }
898         
899         
900         var onPasswordChanged = function(){
901             utils.log('onPasswordChanged');
902             logonCore.getContext(onFlowSuccess, onFlowError);
903         }
904         
905         // exported properties
906         this.stateTransitions = [
907                                  {
908                                  condition: {
909                                  state: {
910                                  secureStoreOpen: false,
911                                  }
912                                  },
913                                  action: callUnlockFlow,
914                                  },
915                                  {
916                                  condition: {
917                                  state: {
918                                  secureStoreOpen: true,
919                                  }
920                                  },
921                                  action: 'SCR_CHANGE_PASSWORD'
922                                  },
923                                  
924                                  ];
925         
926         this.screenEvents = {
927             'SCR_CHANGE_PASSWORD': {
928             onsubmit: onChangePasswordSubmit,
929             oncancel: onFlowCancel,
930             onerror: onFlowError
931             }
932         };
933         
934         
935         utils.log('flow constructor return');
936     }
937     
938     var ManagePasscodeFlow = function ManagePasscodeFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
939         //wrapped into a function to defer evaluation of the references to flow callbacks
940         
941         this.name = 'managePasscodeFlowBuilder';
942         
943         // internal methods
944         var showScreen = function(screenId) {
945             return function(coreContext) {
946                 logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
947             }.bind(this);
948         }.bind(this);
949         
950      
951         var callSetPasscode = function(context){
952             utils.logJSON(context, 'logonCore.changePasscode');
953             logonCore.changePasscode(
954                                      onCoreResult,
955                                      onChangePasscodeError,
956                                      context)
957         }
958         
959         var callChangePasscode = function(context){
960             utils.logJSON(context, 'logonCore.changePasscode');
961             context.passcode = context.newPasscode;
962             logonCore.changePasscode(
963                                      onCoreResult,
964                                      onChangePasscodeError,
965                                      context)
966         }
967         
968         var onChangePasscodeError = function(error) {
969             utils.logJSON("onChangePasscodeError: " + JSON.stringify(error));
970             logonView.showNotification(getSecureStoreErrorText(error));
971         }
972         
973         var noOp = function() { }
974         
975         var callDisablePasscode = function(context){
976             utils.logJSON(context, 'logonCore.disablePasscode');
977             context.passcode = null;
978             logonCore.changePasscode(
979                                      onCoreResult,
980                                      onFlowError,
981                                      context)
982         }
983         
984         var callGetContext = function(){
985             utils.log('logonCore.getContext');
986             logonCore.getContext(onCoreResult, onFlowError);
987         }
988         
989         var onPasscodeEnable = function(context){
990             utils.logJSON(context, this.name + ' onPasscodeEnable: ');
991             //logonCore.changePasscode(onFlowSuccess, onFlowError, context);
992             onFlowError();
993         }
994         
995         // exported properties
996         this.stateTransitions = [
997                                  {
998                                  condition: {
999                                  state: {
1000                                 secureStoreOpen: true,
1001                                 },
1002                                 context: null
1003                                 },
1004                                 action: callGetContext
1005                                 },
1006                                 {
1007                                 condition: {
1008                                 state: {
1009                                 secureStoreOpen: false,
1010                                 }
1011                                 },
1012                                 action: onFlowError
1013                                 },
1014                                 {
1015                                 condition: {
1016                                 state: {
1017                                 secureStoreOpen: true,
1018                                 defaultPasscodeUsed: true,
1019                                 //                        defaultPasscodeAllowed: true,
1020                                 }
1021                                 },
1022                                 action: 'SCR_MANAGE_PASSCODE_OPT_OFF'
1023                                 },
1024                                 {
1025                                 condition: {
1026                                 state: {
1027                                 secureStoreOpen: true,
1028                                 defaultPasscodeUsed: false,
1029                                 defaultPasscodeAllowed: true,
1030                                 }
1031                                 },
1032                                 action: 'SCR_MANAGE_PASSCODE_OPT_ON'
1033                                 },
1034                                 {
1035                                 condition: {
1036                                 state: {
1037                                 secureStoreOpen: true,
1038                                 //defaultPasscodeUsed: [DONTCARE],
1039                                 defaultPasscodeAllowed: false,
1040                                 }
1041                                 },
1042                                 action: 'SCR_MANAGE_PASSCODE_MANDATORY'
1043                                 },
1044                                 
1045                                 
1046                                 ];
1047        
1048        this.screenEvents = {
1049            'SCR_MANAGE_PASSCODE_OPT_ON': {
1050            onsubmit: onFlowSuccess,
1051            oncancel: onFlowSuccess,
1052            onerror: onFlowError,
1053            ondisable: showScreen('SCR_CHANGE_PASSCODE_OPT_OFF'),
1054            onchange: showScreen('SCR_CHANGE_PASSCODE_OPT_ON')
1055            },
1056            'SCR_MANAGE_PASSCODE_OPT_OFF': {
1057            onsubmit: onFlowSuccess,
1058            oncancel: onFlowSuccess,
1059            onerror: onFlowError,
1060            onenable: showScreen('SCR_SET_PASSCODE_OPT_ON')
1061            },
1062            'SCR_MANAGE_PASSCODE_MANDATORY': {
1063            onsubmit: onFlowSuccess,
1064            oncancel: onFlowSuccess,
1065            onerror: onFlowError,
1066            onchange: showScreen('SCR_CHANGE_PASSCODE_MANDATORY')
1067            },
1068            
1069            
1070            'SCR_SET_PASSCODE_OPT_ON': {
1071            onsubmit: callSetPasscode,
1072            oncancel: onFlowCancel,
1073            onerror: onFlowError,
1074            ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
1075            onerrorack: noOp
1076            },
1077            'SCR_SET_PASSCODE_OPT_OFF': {
1078            onsubmit: callDisablePasscode,
1079            oncancel: onFlowCancel,
1080            onerror: onFlowError,
1081            onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
1082            onerrorack: noOp
1083            },
1084            'SCR_CHANGE_PASSCODE_OPT_ON': {
1085            onsubmit: callChangePasscode,
1086            oncancel: onFlowCancel,
1087            onerror: onFlowError,
1088            ondisable: showScreen('SCR_CHANGE_PASSCODE_OPT_OFF'),
1089            onerrorack: noOp
1090            },
1091            'SCR_CHANGE_PASSCODE_OPT_OFF': {
1092            onsubmit: callDisablePasscode,
1093            oncancel: onFlowCancel,
1094            onerror: onFlowError,
1095            onenable: showScreen('SCR_CHANGE_PASSCODE_OPT_ON'),
1096            onerrorack: noOp
1097            },
1098            'SCR_CHANGE_PASSCODE_MANDATORY': {
1099            onsubmit: callChangePasscode,
1100            oncancel: onFlowCancel,
1101            onerror: onFlowError,
1102            onerrorack: noOp
1103            },
1104            
1105        };
1106        
1107        
1108        utils.log('flow constructor return');
1109    }
1110    
1111    var ShowRegistrationFlow = function ShowRegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
1112        //wrapped into a function to defer evaluation of the references to flow callbacks
1113        
1114        this.name = 'showRegistrationFlowBuilder';
1115        
1116        var showRegistrationInfo = function(context) {
1117            logonView.showScreen('SCR_SHOW_REGISTRATION', this.screenEvents['SCR_SHOW_REGISTRATION'], context);
1118        }.bind(this);
1119        
1120        var callGetContext = function(){
1121            utils.log('logonCore.getContext');
1122            logonCore.getContext(onCoreResult, onFlowError);
1123        }
1124        
1125        // exported properties
1126        this.stateTransitions = [
1127                                 {
1128                                 condition: {
1129                                 state: {
1130                                 secureStoreOpen: true,
1131                                 
1132                                 },
1133                                 context: null
1134                                 },
1135                                 action: callGetContext
1136                                 },
1137                                 {
1138                                 condition: {
1139                                 secureStoreOpen: true,
1140                                 },
1141                                 action: showRegistrationInfo
1142                                 }
1143                                 
1144                                 ];
1145        
1146        this.screenEvents = {
1147            'SCR_SHOW_REGISTRATION': {
1148            oncancel: onFlowSuccess,
1149            onerror: onFlowError
1150            }
1151        };
1152        
1153        
1154        utils.log('flow constructor return');
1155    }
1156    
1157    // === flow launcher methods =====================================
1158    
1159    
1160    var resume = function (onsuccess, onerror) {
1161        
1162        if(!_oLogonCore) {
1163            utils.log('FlowRunner.run MAFLogon is not initialized');
1164            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1165            return;
1166        }
1167        
1168        var onUnlockSuccess = function(){
1169            _oLogonCore.onEvent(onsuccess, onerror, 'RESUME');
1170        }
1171        
1172        var onGetStateSuccess = function(state) {
1173            //call registration flow only if the status is fullregistered in case of resume, so logon screen will not loose its input values
1174            if (state.status == 'fullRegistered') {
1175                registerOrUnlock(onUnlockSuccess, onerror);
1176            }
1177        }
1178        
1179        getState(onGetStateSuccess, onerror);
1180    }
1181    
1182    
1183    var get = function (onsuccess, onerror, key) {
1184        
1185        if(!_oLogonCore) {
1186            utils.log('FlowRunner.run MAFLogon is not initialized');
1187            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1188            return;
1189        }
1190        
1191        var onUnlockSuccess = function(){
1192            _oLogonCore.getSecureStoreObject(onsuccess, onerror, key);
1193        }
1194        
1195        registerOrUnlock(onUnlockSuccess, onerror);
1196    }
1197    
1198    
1199    
1200    var set = function (onsuccess, onerror, key, value) {
1201        
1202        if(!_oLogonCore) {
1203            utils.log('FlowRunner.run MAFLogon is not initialized');
1204            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1205            return;
1206        }
1207        
1208        var onUnlockSuccess = function(){
1209            _oLogonCore.setSecureStoreObject(onsuccess, onerror, key, value);
1210        }
1211        
1212        registerOrUnlock(onUnlockSuccess, onerror);
1213    }
1214    
1215    
1216    
1217    var lock = function (onsuccess, onerror) {
1218        if(!_oLogonCore) {
1219            utils.log('FlowRunner.run MAFLogon is not initialized');
1220            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1221            return;
1222        }
1223        
1224        _oLogonCore.lockSecureStore(onsuccess, onerror);
1225    }
1226    
1227    var getState = function (onsuccess, onerror) {
1228        if(!_oLogonCore) {
1229            utils.log('FlowRunner.run MAFLogon is not initialized');
1230            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1231            return;
1232        }
1233        
1234        _oLogonCore.getState(onsuccess, onerror);
1235    }
1236    
1237    var wrapCallbackWithQueueNext = function(callback) {
1238        return function() { 
1239            callback.apply(this, arguments);
1240         	if (flowqueue) {
1241                flowqueue.runNextFlow();
1242            }
1243        }
1244    }
1245    
1246    
1247    var registerOrUnlock = function(onsuccess, onerror) {
1248        if(!_oLogonCore) {
1249            utils.log('FlowRunner.run MAFLogon is not initialized');
1250            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1251            return;
1252        }
1253        
1254        var callbacks = {
1255            "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1256            "onerror" : wrapCallbackWithQueueNext(onerror)
1257        }
1258        var flowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, RegistrationFlow);
1259    
1260        
1261        if (flowqueue) {
1262            flowqueue.add(flowRunner);
1263        }
1264        else {
1265            flowRunner.run();
1266        }
1267    }
1268    
1269    var changePassword = function(onsuccess, onerror) {
1270        if(!_oLogonCore) {
1271            utils.log('FlowRunner.run MAFLogon is not initialized');
1272            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1273            return;
1274        }
1275        
1276        var onUnlockSuccess = function(){
1277            var callbacks = {
1278                "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1279                "onerror" : wrapCallbackWithQueueNext(onerror)
1280            }
1281            var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ChangePasswordFlow);
1282    
1283            if (flowqueue) {
1284                flowqueue.add(innerFlowRunner);
1285            }
1286            else {
1287                innerFlowRunner.run();
1288            }
1289        }
1290        
1291        registerOrUnlock(onUnlockSuccess, onerror);
1292    }
1293    
1294    
1295    var forgottenPasscode = function(onsuccess, onerror) {
1296        if(!_oLogonCore) {
1297            utils.log('FlowRunner.run MAFLogon is not initialized');
1298            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1299            return;
1300        }
1301        
1302        var onUnlockSuccess = function(){
1303    	var callbacks = {
1304                "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1305                "onerror" : wrapCallbackWithQueueNext(onerror)
1306            }
1307            var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, MockFlow);
1308            if (flowqueue) {
1309                flowqueue.add(innerFlowRunner);
1310            }
1311            else {
1312                innerFlowRunner.run();
1313            }
1314        }
1315        
1316        registerOrUnlock(onUnlockSuccess, onerror);
1317    }
1318    
1319    var managePasscode = function(onsuccess, onerror) {
1320        if(!_oLogonCore) {
1321            utils.log('FlowRunner.run MAFLogon is not initialized');
1322            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1323            return;
1324        }
1325        
1326        var onUnlockSuccess = function(){
1327    	var callbacks = {
1328                "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1329                "onerror" : wrapCallbackWithQueueNext(onerror)
1330            }
1331            var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ManagePasscodeFlow);
1332            if (flowqueue) {
1333                flowqueue.add(innerFlowRunner);
1334            }
1335            else {
1336                innerFlowRunner.run();
1337            }
1338        }
1339        
1340        registerOrUnlock(onUnlockSuccess, onerror);
1341    }
1342    
1343    var showRegistrationData = function(onsuccess, onerror) {
1344        if(!_oLogonCore) {
1345            utils.log('FlowRunner.run MAFLogon is not initialized');
1346            onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1347            return;
1348        }
1349        
1350        var onUnlockSuccess = function(){
1351    	var callbacks = {
1352                "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1353                "onerror" : wrapCallbackWithQueueNext(onerror)
1354            }
1355            var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ShowRegistrationFlow);
1356            if (flowqueue) {
1357                flowqueue.add(innerFlowRunner);
1358            }
1359            else {
1360                innerFlowRunner.run();
1361            }
1362        }
1363        
1364        registerOrUnlock(onUnlockSuccess, onerror);
1365    }
1366    
1367    var getSecureStoreErrorText = function(error) {
1368        utils.logJSON('LogonController.getSecureStoreErrorText: ' + JSON.stringify(error));
1369        
1370        var errorText;
1371        
1372        if(error.errorCode === '14' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1373            errorText = "ERR_PASSCODE_TOO_SHORT";
1374        else if(error.errorCode === '10' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1375            errorText = "ERR_PASSCODE_REQUIRES_DIGIT";
1376        else if(error.errorCode === '13' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1377            errorText = "ERR_PASSCODE_REQUIRES_UPPER";
1378        else if(error.errorCode === '11' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1379            errorText = "ERR_PASSCODE_REQUIRES_LOWER";
1380        else if(error.errorCode === '12' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1381            errorText = "ERR_PASSCODE_REQUIRES_SPECIAL";
1382        else if(error.errorCode === '15' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1383            errorText = "ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS";
1384        else {
1385            errorText = "ERR_SETPASSCODE_FAILED";
1386        }
1387        
1388        return errorText;
1389    }
1390    
1391    var getSSOPasscodeSetErrorText = function(error) {
1392        utils.logJSON('LogonController.getSSOPasscodeSetErrorText: ' + JSON.stringify(error));
1393        
1394        var errorText;
1395        
1396        if (error.errorDomain === 'MAFLogonCoreErrorDomain') {
1397            if (error.errorCode === '16') {
1398                errorText = "ERR_SSO_PASSCODE_SET_ERROR";
1399            }
1400        }
1401        
1402        return errorText;
1403    }
1404    
1405    var getRegistrationErrorText = function(error) {
1406        utils.logJSON('LogonController.getRegistrationErrorText: ' + JSON.stringify(error));
1407        
1408        var errorText;
1409        
1410        if (error.errorDomain === 'MAFLogonCoreErrorDomain') {
1411            if (error.errorCode === '80003') {
1412                errorText = "ERR_REG_FAILED_WRONG_SERVER";
1413            }
1414            //in case of wrong application id
1415            else if (error.errorCode === '404') {
1416                errorText = "ERR_REG_FAILED";
1417            }
1418            else if (error.errorCode === '401') {
1419                errorText = "ERR_REG_FAILED_UNATHORIZED";
1420            }
1421            else {
1422                errorText = "ERR_REG_FAILED";
1423            }
1424        }
1425        
1426        return errorText;
1427    }
1428    
1429    var getRegistrationCancelError = function(error) {
1430        utils.logJSON('LogonController.getRegistrationCancelError: ' + JSON.stringify(error));
1431        
1432        var errorText;
1433        
1434        errorText = "ERR_REGISTRATION_CANCEL";
1435        
1436        return errorText;
1437    }
1438    
1439    var errorWithDomainCodeDescription = function(domain, code, description) {
1440        var error = {
1441        errorDomain: domain,
1442        errorCode: code,
1443        errorMessage: description
1444        };
1445        
1446        return error;
1447    }
1448    
1449    
1450    // =================== exported (public) members ====================
1451    
1452    /**
1453     * The Logon plugin provides screen flows to register an app with an SAP Mobile Platform server.<br/>
1454     * <br/>
1455     * The logon plugin is a component of the SAP Mobile Application Framework (MAF), exposed as a Cordova plugin. The basic
1456     * idea is that it provides screen flows where the user can enter the values needed to connect to an SAP Mobile Platform 3.0 server and
1457     * stores those values in its own secure data vault. This data vault is separate from the one provided with the
1458     * encrypted storage plugin. In an OData based SAP Mobile Platform 3.0 application, a client must onboard or register with the SAP Mobile Platform 3.0
1459     * server to receive an application connection ID for a particular app. The application connection ID must be sent
1460     * along with each request that is proxied through the SAP Mobile Platform 3.0 server to the OData producer.<br/>
1461     * <br/>
1462     * <b>Adding and Removing the Logon Plugin</b><br/>
1463     * The Logon plugin is added and removed using the
1464     * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>.<br/>
1465     * <br/>
1466     * To add the Logon plugin to your project, use the following command:<br/>
1467     * cordova plugin add <full path to directory containing Kapsel plugins>\logon<br/>
1468     * <br/>
1469     * To remove the Logon plugin from your project, use the following command:<br/>
1470     * cordova plugin rm com.sap.mp.cordova.plugins.logon
1471     *
1472     * @namespace
1473     * @alias Logon
1474     * @memberof sap
1475     */
1476    module.exports = {
1477        
1478        /**
1479         * Initialization method to set up the Logon plugin.  This will register the application with the SMP server and also authenticate the user
1480         * with servers on the network.  This step must be done first prior to any attempt to communicate with the SMP server.
1481         *
1482         * @method
1483         * @param {sap.Logon~successCallback} successCallback The function that is invoked if initialization is successful.  The current
1484         * context is passed to this function as the parameter.
1485         * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
1486         * @param {string} applicationId The unique ID of the application.  Must match the application ID on the SAP Mobile Platform server.
1487         * @param {object} [context] The context with default values for application registration.  See {@link sap.Logon~successCallback} for the structure
1488         * of the context object.  Note that all properties of the context object are optional, and you only need to specify the properties
1489         * for which you want to provide default values for.  The values will be presented to the application users during the registration process and given them
1490         * a chance to override these values during runtime.
1491         * @param {string} [logonView="com/sap/mp/logon/iabui"] The cordova module ID of a custom renderer for the logon,
1492         * implementing the [showScreen(), close()] interface.  Please use the defaul module unless you are absolutely sure that you can provide your own
1493         * custom implementation.  Please refer to JavaScript files inside your Kapsel project's plugins\logon\www\common\modules\ folder as example.
1494         * @example
1495         * // a custom UI can be loaded here
1496         * var logonView = sap.logon.IabUi;
1497         *
1498         * // The app ID
1499         * var applicationId = "someAppID";
1500         *
1501         * // You only need to specify the fields for which you want to set the default.   These values are optional because they will be
1502         * // used to prefill the fields on Logon's UI screen.
1503         * var defaultContext = {
1504         *  "serverHost" : "defaultServerHost.com"
1505         *	"https" : false,
1506         *	"serverPort" : "8080",
1507         *	"user" : "user1",
1508         *	"password" : "Zzzzzz123",
1509         *	"communicatorId" : "REST",
1510         *	"securityConfig" : "sec1",
1511         *	"passcode" : "Aaaaaa123",
1512         *	"unlockPasscode" : "Aaaaaa123"
1513         * };
1514         *
1515         * var app_context;
1516         *
1517         * var successCallback = function(context){
1518         *     app_context = context;
1519         * }
1520         *
1521         * var errorCallback = function(errorInfo){
1522         *     alert("error: " + JSON.stringify(errorInfo));
1523         * }
1524         * sap.Logon.init(successCallback, errorCallback, applicationId, defaultContext, logonView);
1525         */
1526    init: init,
1527        
1528        /**
1529         * The application ID with which {@link sap.Logon.init} was called.  It is available here so it is easy to access later.
1530         * @example
1531         * // After calling the init function
1532         * alert("The app ID for this app is: " + sap.Logon.applicationId);
1533         */
1534    applicationId: null,
1535        /**
1536         * Direct reference to the logon core object used by the Logon plugin.  This is needed to perform more complex operations that
1537         * are not generally needed by applications. <br/>
1538         * There are several functions that can be accessed on the core object:<br/>
1539         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getState(successCallback,errorCallback) returns the state object of the application to the success callback in the form of a JavaScript object.<br/>
1540         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getContext(successCallback,errorCallback) returns the context object of the application to the success callback in the form of a JavaScript object.<br/>
1541         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deleteRegistration(successCallback,errorCallback) deletes the application's registration from the SAP Mobile Platform server and removes<br/>
1542         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; application data on device.<br/>
1543         * @example
1544         * var successCallback = function(result){
1545         *     alert("Result: " + JSON.stringify(result));
1546         * }
1547         * var errorCallback = function(errorInfo){
1548         *     alert("Error: " + JSON.stringify(errorInfo));
1549         * }
1550         * sap.Logon.core.getState(successCallback,errorCallback);
1551         * sap.Logon.core.getContext(successCallback,errorCallback);
1552         * sap.Logon.core.deleteRegistration(successCallback,errorCallback);
1553         */
1554    core: _oLogonCore, //Must be updated after init
1555        
1556        /**
1557         * Get an  (JSON serializable) object from the DataVault for a given key.
1558         * @method
1559         * @param {sap.Logon~getSuccessCallback} onsuccess The function that is invoked
1560         * upon success.  It is called with the resulting object as a single parameter.
1561         * This can be null or undefined, if no object is defined for the given key.
1562         * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
1563         * @param {string} key The key with which to query the DataVault.
1564         * @example
1565         * var errorCallback = function(errorInfo){
1566         *     alert("Error: " + JSON.stringify(errorInfo));
1567         * }
1568         * var getSuccess = function(value){
1569         *     alert("value retrieved from the store: " + JSON.stringify(value));
1570         * }
1571         * var setSuccess = function(){
1572         *     sap.Logon.get(getSuccess,errorCallback,'someKey');
1573         * }
1574         * sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');
1575         */
1576    get: get,
1577        
1578        /**
1579         * Set an (JSON serializable) object in the DataVault.
1580         * @method
1581         * @param {sap.Logon~successCallbackNoParameters} onsuccess The function to invoke upon success.
1582         * onsuccess will be called without parameters for this method.
1583         * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
1584         * @param {string} key The key to store the provided object on.
1585         * @param {object} value The object to be set on the given key.  Must be JSON serializable (ie:
1586         * cannot contain circular references).
1587         * @example
1588         * var errorCallback = function(errorInfo){
1589         *     alert("Error: " + JSON.stringify(errorInfo));
1590         * }
1591         * var getSuccess = function(value){
1592         *     alert("value retrieved from the store: " + JSON.stringify(value));
1593         * }
1594         * var setSuccess = function(){
1595         *     sap.Logon.get(getSuccess,errorCallback,'someKey');
1596         * }
1597         * sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');
1598         */
1599    set: set,
1600        
1601        /**
1602         * Locks the Logon plugin's secure data vault.
1603         * @method
1604         * @param {sap.Logon~successCallbackNoParameters} onsuccess The function to invoke upon success.
1605         * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
1606         * @example
1607         * var errorCallback = function(errorInfo){
1608         *     alert("Error: " + JSON.stringify(errorInfo));
1609         * }
1610         * var successCallback = function(){
1611         *     alert("Locked!");
1612         * }
1613         * sap.Logon.lock(successCallback,errorCallback);
1614         */
1615    lock: lock,
1616        
1617        /**
1618         * Unlock the Logon plugin's secure data vault if it has been locked (due to being inactive, or
1619         * {@link sap.Logon.lock} being called), then the user is prompted for the passcode to unlock the
1620         * application.<br/>
1621         * If the application is already unlocked, then nothing will be done.<br/>
1622         * If the application has passcode disabled, then passcode prompt will not be necessary.
1623         * In all cases if an error does not occur, the success callback is invoked with the current logon context
1624         * as the parameter.
1625         * @method
1626         * @param {sap.Logon~successCallback} onsuccess - The callback to call if the screen flow succeeds.
1627         * onsuccess will be called with the current logon context as a single parameter.
1628         * @param {sap.Logon~errorCallback} onerror - The callback to call if the screen flow fails.
1629         * @example
1630         * var errorCallback = function(errorInfo){
1631         *     alert("Error: " + JSON.stringify(errorInfo));
1632         * }
1633         * var successCallback = function(context){
1634         *     alert("Registered and unlocked.  Context: " + JSON.stringify(context));
1635         * }
1636         * sap.Logon.unlock(successCallback,errorCallback);
1637         */
1638    unlock: registerOrUnlock,
1639        
1640        /**
1641         * This is an alias for registerOrUnlock.  Calling this function is equivalent
1642         * to calling {@link sap.Logon.unlock} since both of them are alias to registerOrUnlock.
1643         * @method
1644         * @private
1645         */
1646    registerUser: registerOrUnlock,
1647        
1648        /**
1649         * This function registers the user and creates a new unlocked DataVault to store the registration
1650         * information.<br/>
1651         * If the user has already been registered, but the application is locked (due to being inactive, or
1652         * {@link sap.Logon.lock} being called), then the user is prompted for the passcode to unlock the
1653         * application.<br/>
1654         * If the application is already unlocked, then nothing will be done.<br/>
1655         * In all cases if an error does not occur, the success callback is invoked with the current logon context
1656         * as the parameter.
1657         * @method
1658         * @param {sap.Logon~successCallback} onsuccess - The callback to call if the screen flow succeeds.
1659         * onsuccess will be called with the current logon context as a single parameter.
1660         * @param {sap.Logon~errorCallback} onerror - The callback to call if the screen flow fails.
1661         * @example
1662         * var errorCallback = function(errorInfo){
1663         *     alert("Error: " + JSON.stringify(errorInfo));
1664         * }
1665         * var successCallback = function(context){
1666         *     alert("Registered and unlocked.  Context: " + JSON.stringify(context));
1667         * }
1668         * sap.Logon.registerOrUnlock(successCallback,errorCallback);
1669         * @private
1670         */
1671    registerOrUnlock: registerOrUnlock,
1672        
1673        /**
1674         * This method will launch the UI screen for application users to manage and update the data vault passcode or,
1675         * if the SMP server's Client Passcode Policy allows it, enable or disable the passcode to the data vault.
1676         *
1677         * @method
1678         * @param {sap.Logon~successCallbackNoParameters} onsuccess - The function to invoke upon success.
1679         * @param {sap.Logon~errorCallback} onerror - The function to invoke in case of error.
1680         * @example
1681         * var errorCallback = function(errorInfo){
1682         *     alert("Error: " + JSON.stringify(errorInfo));
1683         * }
1684         * var successCallback = function(context){
1685         *     alert("Passcode successfully managed.");
1686         * }
1687         * sap.Logon.managePasscode(successCallback,errorCallback);
1688         */
1689    managePasscode: managePasscode,
1690        
1691        /**
1692         * This method will launch the UI screen for application users to manage and update the back-end passcode that Logon stores in the
1693         * data vault that is used to authenticate the client to the server.
1694         *
1695         * @method
1696         * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
1697         * onsuccess will be called without parameters for this method.
1698         * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
1699         * @example
1700         * var errorCallback = function(errorInfo){
1701         *     alert("Error: " + JSON.stringify(errorInfo));
1702         * }
1703         * var successCallback = function(context){
1704         *     alert("Password successfully changed.");
1705         * }
1706         * sap.Logon.changePassword(successCallback,errorCallback);
1707         */
1708    changePassword: changePassword,
1709        
1710        /**
1711         * Calling this method will show a screen which displays the current registration settings for the application.
1712         * @method
1713         * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
1714         * onsuccess will be called without parameters for this method.
1715         * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
1716         * @example
1717         * var errorCallback = function(errorInfo){
1718         *     alert("Error: " + JSON.stringify(errorInfo));
1719         * }
1720         * var successCallback = function(context){
1721         *     alert("The showRegistrationData screenflow was successful.");
1722         * }
1723         * sap.Logon.showRegistrationData(successCallback,errorCallback);
1724         */
1725    showRegistrationData: showRegistrationData
1726    };
1727    
1728    /**
1729     * Callback function that is invoked in case of an error.
1730     *
1731     * @callback sap.Logon~errorCallback
1732     *
1733     * @param {Object} errorObject Depending on the origin of the error the object can take several forms.
1734     * (Unfortunately the error object structure and content is not uniform among the platforms, this will
1735     * probably change in the future.)
1736     *
1737     * Errors originating from the logon plugin have only an 'errorKey' property.
1738     * The possible values for 'errorKey':
1739     *
1740     * ERR_CHANGE_TIMEOUT_FAILED
1741     * ERR_FORGOT_SSO_PIN
1742     * ERR_INIT_FAILED
1743     * ERR_INVALID_ACTION
1744     * ERR_INVALID_STATE
1745     * ERR_PASSCODE_REQUIRES_DIGIT
1746     * ERR_PASSCODE_REQUIRES_LOWER
1747     * ERR_PASSCODE_REQUIRES_SPECIAL
1748     * ERR_PASSCODE_REQUIRES_UPPER
1749     * ERR_PASSCODE_TOO_SHORT
1750     * ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS
1751     * ERR_REGISTRATION_CANCEL
1752     * ERR_REG_FAILED
1753     * ERR_REG_FAILED_UNATHORIZED
1754     * ERR_REG_FAILED_WRONG_SERVER
1755     * ERR_SETPASSCODE_FAILED
1756     * ERR_SET_AFARIA_CREDENTIAL_FAILED
1757     * ERR_SSO_PASSCODE_SET_ERROR
1758     * ERR_UNKNOWN_SCREEN_ID
1759     * ERR_UNLOCK_FAILED
1760     * ERR_USER_CANCELLED
1761     *
1762     * Errors originating in the logon core (either iOS or Android) have the following properties: 'errorCode',
1763     * 'errorMessage', and 'errorDomain'.
1764     * The 'errorCode' is just a number uniquely identifying the error.  The 'errorMessage'
1765     * property is a string with more detailed information of what went wrong.  The 'errorDomain' property specifies
1766     * the domain that the error occurred in.
1767     *
1768     * On iOS the 'errorDomain' property of the core errors can take the following values: MAFLogonCoreErrorDomain, MAFSecureStoreManagerErrorDomain, and MAFLogonCoreCDVPluginErrorDomain.
1769     *
1770     * In the MAFLogonCoreErrorDomain the following errors are thrown (throwing methods in paren):
1771     *
1772     *  3   errMAFLogonErrorCommunicationManagerError       (register, update settings, delete, change backend password)
1773     *  9   errMAFLogonErrorCouldNotDecideCommunicator      (register)
1774     *  11  errMAFLogonErrorOperationNotAllowed             (all)
1775     *  12  errMAFLogonErrorInvalidServerHost               (register)
1776     *  13  errMAFLogonErrorInvalidBackendPassword          (changeBackendPassword)
1777     *  15  errMAFLogonErrorUploadTraceFailed               (uploadTrace)
1778     *  16  errMAFLogonErrorInvalidMCIMSSOPin               (setMCIMSSOPin)
1779     *  18  errMAFLogonErrorCertificateKeyError             (register)
1780     *  19  errMAFLogonErrorCertificateError                (register)
1781     *  20  errMAFLogonErrorAfariaInvalidCredentials        (setAfariaCredentialWithUser)
1782     *
1783     * In the MAFSecureStoreManagerErrorDomain the following errors are thrown (throwing methods in paren):
1784     *
1785     *  0   errMAFSecureStoreManagerErrorUnknown    (persist, unlock, changePasscode, delete, getContext)
1786     *  1   errMAFSecureStoreManagerErrorAlreadyExists  (persist)
1787     *  2   errMAFSecureStoreManagerErrorDataTypeError  (unlock, getContext)
1788     *  3   errMAFSecureStoreManagerErrorDoesNotExist   (unlock, persist, getContext)
1789     *  4   errMAFSecureStoreManagerErrorInvalidArg unlock, (persist, getContext)
1790     *  5   errMAFSecureStoreManagerErrorInvalidPassword    (unlock)
1791     *  6   errMAFSecureStoreManagerErrorLocked     (getContext)
1792     *  7   errMAFSecureStoreManagerErrorOutOfMemory    (persist, unlock, changePasscode, delete, getContext)
1793     *  8   errMAFSecureStoreManagerErrorPasswordExpired    (unlock, getContext)
1794     *  9   errMAFSecureStoreManagerErrorPasswordRequired   (persist, changePasscode)
1795     *  10  errMAFSecureStoreManagerErrorPasswordRequiresDigit  (persist, changePasscode)
1796     *  11  errMAFSecureStoreManagerErrorPasswordRequiresLower  (persist, changePasscode)
1797     *  12  errMAFSecureStoreManagerErrorPasswordRequiresSpecial    (persist, changePasscode)
1798     *  13  errMAFSecureStoreManagerErrorPasswordRequiresUpper  (persist, changePasscode)
1799     *  14  errMAFSecureStoreManagerErrorPasswordUnderMinLength (persist, changePasscode)
1800     *  15  errMAFSecureStoreManagerErrorPasswordUnderMinUniqueChars    (persist, changePasscode)
1801     *  16  errMAFSecureStoreManagerErrorDeleted    (unlock)
1802     *
1803     * In the MAFLogonCoreCDVPluginErrorDomain the following errors are thrown:
1804     *
1805     *  1 (init failed)
1806     *  2 (plugin not initialized)
1807     *  3 (no input provided)
1808     *
1809     * On Android the 'errorDomain' property of the core errors can take the following values: MAFLogonCoreErrorDomain and MAFLogonCoreCDVPluginErrorDomain.
1810     * There are no logon specific error codes, the 'errorCode' property only wraps the error values from the underlying libraries.
1811     */
1812    
1813    /**
1814     * Callback function that is invoked upon successfully registering or unlocking or retrieving the context.
1815     *
1816     * @callback sap.Logon~successCallback
1817     *
1818     * @param {Object} context An object containing the current logon context.  Two properties of particular importance
1819     * are applicationEndpointURL, and applicationConnectionId.
1820     * The context object contains the following properties:<br/>
1821     * "registrationContext": {<br/>
1822     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"serverHost": Host of the server.<br/>
1823     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"domain": Domain for server. Can be used in case of SAP Mobile Platform communication.<br/>
1824     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"resourcePath": Resource path on the server. The path is used mainly for path based reverse proxy but can contain a custom relay server path as well.<br/>
1825     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"https": Marks whether the server should be accessed in a secure way.<br/>
1826     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"serverPort": Port of the server.<br/>
1827     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"user": Username in the backend.<br/>
1828     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"password": Password for the backend user.<br/>
1829     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"farmId": FarmId of the server. Can be nil. Used in case of Relay server or SiteMinder.<br/>
1830     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"communicatorId": Id of the communicator manager that will be used for performing the logon. Possible values: IMO / GATEWAY / REST<br/>
1831     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"securityConfig": Security configuration. If nil, the default configuration is used.<br/>
1832     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"mobileUser": Mobile User. Used in case of IMO manual user creation.<br/>
1833     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"activationCode": Activation Code. Used in case of IMO manual user creation.<br/>
1834     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"gatewayClient": The key string that identifies the client on the gateway. Used in Gateway only registration mode. The value will be used as adding the parameter: sap-client=<gateway client><br/>
1835     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"gatewayPingPath": The custom path of the ping URL on the gateway. Used in case of Gateway only registration mode.<br/>
1836     * }<br/>
1837     * "applicationEndpointURL": Contains the application endpoint URL after a successful registration.<br/>
1838     * "applicationConnectionId": ID to get after a successful SUP REST registration. Needs to be set in the download request header with key X-SUP-APPCID<br/>
1839     * "afariaRegistration": manual / automatic / certificate<br/>
1840     * "policyContext": Contains the password policy for the secure store {<br/>
1841     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"alwaysOn":<br/>
1842     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"alwaysOff":<br/>
1843     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaultOn":<br/>
1844     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasDigits":<br/>
1845     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasLowerCaseLetters":<br/>
1846     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasSpecialLetters":<br/>
1847     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasUpperCaseLetters":<br/>
1848     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaultAllowed":<br/>
1849     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"expirationDays":<br/>
1850     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"lockTimeout":<br/>
1851     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"minLength":<br/>
1852     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"minUniqueChars":<br/>
1853     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"retryLimit":<br/>
1854     * }<br/>
1855     * "registrationReadOnly": specifies whether context values are coming from clientHub / afaria<br/>
1856     * "policyReadOnly": specifies whether passcode policy is coming from afaria<br/>
1857     * "credentialsByClientHub": specifies whether credentials are coming from clientHub
1858     */
1859    
1860    /**
1861     * Callback function that will be invoked with no parameters.
1862     *
1863     * @callback sap.Logon~successCallbackNoParameters
1864     */
1865    
1866    /**
1867     * Callback function that is invoked upon successfully retrieving an object from the DataVault.
1868     *
1869     * @callback sap.Logon~getSuccessCallback
1870     *
1871     * @param {Object} value The object that was stored with the given key.  Can be null or undefined if no object was stored
1872     * with the given key.
1873     */
1874    
1875