Odyssey
admSecurity.prg
1 <?php
2 
3 /**
4  * @package AdmUsrMaint.prg.v2 -- Contains all the code to save users through the administration screen and through security screens.
5  * This replaces AdmUsrMaint.prg, AdmSecure.prg, AdmSetCfg.prg, AdmSettings.prg, AdmUsrRpt.prg, pwdRules.html
6  */
7 
8 $self = "$menu_link?ft=$ft";
9 
10 $operation = trim($operation);
11 $showSQL = $SYSENV["devmode"];
12 
13 $string = array("filter" => FILTER_SANITIZE_STRING);
14 $parameters = array("a" => array("tab" => "", "password" => "", "message" => "", "status" => "", "usernames" => ""));
15 HCU_ImportVars($parameters, "a", array("tab" => $string, "password" => $string, "message" => $string, "status" => $string,
16  "usernames" => $string, "authval" => $string, "isSkip" => $string, "page" => $string));
17 extract($parameters["a"]);
18 
19 $tab = isset($tab) ? trim($tab) : "";
20 $password = isset($password) ? trim($password) : "";
21 $message = isset($message) ? trim($message) : "";
22 $status = isset($status) ? trim($status) : "";
23 $usernames = isset($usernames) ? trim($usernames) : "";
24 $authval = isset($authval) ? trim($authval) : "";
25 $isSkip = isset($isSkip) ? trim($isSkip) == "Y" : false;
26 $page = isset($page) ? trim($page) : "";
27 
28 define( "MUSTDOIT_FT", 31);
29 
30 if ($operation != "")
31 {
32  try
33  {
34  switch($operation)
35  {
36  case "readUserCombined":
37  if ($ft == MUSTDOIT_FT)
38  $returnArray = readUserBasicSecurity($dbh, $Cu, $Cn, true);
39  else
40  $returnArray = readUserCombinedSecurity($dbh, $Cu, $Cn);
41  break;
42  case "readUserSetup":
43  $returnArray = readUserSetup($dbh, $Cu, $Cn);
44  break;
45  case "saveUserCombined":
46  $is31 = $ft == MUSTDOIT_FT;
47  $returnArray = saveUserCombinedSecurity($SYSENV, $dbh, $Cu, $Cn, $is31, $is31 && $isSkip);
48  break;
49  case "saveUserSetup":
50  $returnArray = saveUserSetup($SYSENV, $dbh, $Cu, $Cn);
51  break;
52  default: $returnArray = array("sql" => array(), "error" => array("Operation not recognized: $operation."), "record" => array());
53  break;
54  }
55  }
56  catch(exception $e)
57  {
58  $returnArray = array("sql" => array(), "error" => array($e->getMessage()));
59  }
60 
61  header('Content-type: application/json');
62  if (!$showSQL)
63  unset($returnArray["sql"]);
64  print HCU_JsonEncode($returnArray);
65 }
66 else
67 {
68  try
69  {
70  switch($ft)
71  {
72  case 29:
73  if ($password == "")
74  printVerifyPassword($self, "");
75  else if (!validatePassword($dbh, $password, $Cu, $Cn))
76  printVerifyPassword($self, "Password is invalid.");
77  else
78  printSecurityCombined($self, $ft, $Cn, $Cu, trim($message));
79  break;
80  case 31:
81  printSecurityCombined($self, $ft, $Cn, $Cu);
82  break;
83  case 35:
84  printSecuritySetup($self, $Ffchg == "Y", $Cn, $Cu);
85  break;
86  }
87  }
88  catch(exception $e)
89  {
90  print $e->getMessage();
91  }
92 }
93 
94 /**
95  * validatePassword($dbh, $password, $Cu, $Cn)
96  * Validates that the password entered is the same as what is in the database.
97  *
98  * @param integer $dbh -- database connection
99  * @param string $password -- entered password
100  * @param string $Cu -- the credit union
101  * @param string $Cn -- the logged in user
102  *
103  * @return true if password equals what is in the database, false otherwise.
104  */
105 function validatePassword($dbh, $password, $Cu, $Cn)
106 {
107  $sql = "select passwd from cuadminusers where user_name= '$Cn' and cu= '$Cu'";
108  $sqls[] = $sql;
109  $sth = db_query($sql, $dbh);
110  if (!$sth)
111  {
112  return false;
113  }
114 
115  $row = db_fetch_row($sth);
116  $currentPassword = trim($row[0]);
117 
118  $password = trim($password);
119 
120  $comparison = password_verify($password, $currentPassword);
121  return $comparison;
122 }
123 
124 function readUserCombinedSecurity($dbh, $cuCode, $loggedInUser)
125 {
126  $results = ReadUser($dbh, $cuCode, $loggedInUser, false, true, true, false, null);
127  $results["record"] = $results["record"][0];
128  return $results;
129 }
130 
131 /**
132  * function readUserBasicSecurity($dbh, $cuCode, $loggedInUser)
133  * Read user from the first page in "change user security"
134  *
135  * @param integer $dbh -- the database connection
136  * @param string $cuCode -- the credit union code
137  * @param string $loggedInUser -- the logged in user
138  *
139  * @return ReadUser contents
140  */
141 function readUserBasicSecurity($dbh, $cuCode, $loggedInUser)
142 {
143  $results = ReadUser($dbh, $cuCode, $loggedInUser, false, false, false, false, null);
144  $results["record"] = $results["record"][0];
145  return $results;
146 }
147 
148 /**
149  * function readUserSetup($dbh, $cuCode, $loggedInUser)
150  * Read user for the purpose of the page when user logs in without any challenge questions set.
151  *
152  * @param integer $dbh -- the database connection
153  * @param string $cuCode -- the credit union code
154  * @param string $loggedInUser -- the logged in user
155  *
156  * @return ReadUser contents
157  */
158 function readUserSetup($dbh, $cuCode, $loggedInUser)
159 {
160  $results = ReadUser($dbh, $cuCode, $loggedInUser, false, true, true, false, null);
161  $returnArray = array("sql" => $results["sql"], "code" => $results["code"], "error" => $results["error"]);
162  $record = $results["record"][0];
163  $newRecord = array("confidence" => $record["confidence"], "mfaquest" => $record["mfaquest"], "mfaddl" => $record["mfaddl"], "pwdconfig" => $record["pwdconfig"],
164  "email" => $record["email"], "forcechange"=>$record['booleanForceChange'], "forcesecurity"=>$record['booleanForceSecurity']);
165  $returnArray["record"] = $newRecord;
166  return $returnArray;
167 }
168 
169 function saveUserCombinedSecurity($pSysEnv, $dbh, $Cu, $Cn, $is31=false, $isSkip=false)
170 {
171  $string = array("filter" => FILTER_SANITIZE_STRING);
172  $array = array("filter" => FILTER_DEFAULT);
173  $parameters = array("a" => array("password" => "", "email" => "", "ipAddress" => "", "smsNumber" => "", "phoneProvider" => "", "oldPassword" => "", "remoteAccess" => "",
174  "confidence" => "", "questIds" => "", "questResponses" => "", "usersms" => "", "providersms" => "", "ipAddress" => "", "masterIpAddress" => ""));
175 
176  HCU_ImportVars($parameters, "a", array("password" => $string, "email" => $string, "ipAddress" => $string, "smsNumber" => $string, "phoneProvider" => $string, "masterIpAddress" => $string,
177  "oldPassword" => $string, "remoteAccess" => $string, "confidence" => $string, "questIds" => $array, "questResponses" => $array,
178  "usersms" => $string, "providersms" => $string, "ipAddress" => $string));
179 
180  $parameters["a"]["emailAddress"] = $parameters["a"]["email"];
181  unset($parameters["a"]["email"]);
182 
183  $parameters["a"]["phoneProvider"] = $parameters["a"]["providersms"];
184  $parameters["a"]["smsNumber"] = $parameters["a"]["usersms"];
185  unset($parameters["a"]["providersms"]);
186  unset($parameters["a"]["usersms"]);
187 
188  $parameters["a"]["chksecure"] = "Y"; // It is implicit when forcing a password change because they have already been given the option to save login information.
189 
190  return saveUser($pSysEnv, $dbh, $Cu, $parameters["a"], $Cn, "combined", $is31, $isSkip);
191 }
192 
193 /**
194  * function saveUserSetup($dbh, $Cu, $Cn)
195  * Saves an user from page that occurs when you log in without the challenge questions set up
196  *
197  * @param array $pSysEnv -- The System Environment variable from main
198  * with the settings for this environment (production/development)
199  * @param integer $dbh -- the database connection
200  * @param string $Cu -- the credit union
201  * @param string $Cn -- the logged in user
202  *
203  * @return saveUser contents
204  */
205 function saveUserSetup($pSysEnv, $dbh, $Cu, $Cn)
206 {
207  $Ffchg = HCU_array_key_value("Ffchg", $pSysEnv);
208  $Ffchg = $Ffchg === false ? "" : trim($Ffchg);
209  $parameters= array("a" => array("confidence" => "", "questIds" => "", "questResponses" => "", "password" => "", "emailAddress" => "", "oldPassword" => "", "chksecure" => "",
210  "passwordRequired" => ""));
211 
212  $string = array("filter" => FILTER_SANITIZE_STRING);
213  $array = array("filter" => FILTER_DEFAULT);
214  HCU_ImportVars($parameters, "a", array("confidence" => $string, "questIds" => $array, "questResponses" => $array, "password" => $string,
215  "emailAddress" => $string, "oldPassword" => $string, "chksecure" => $string, "passwordRequired" => $string));
216  $parameters["a"]["forcechange"] = $Ffchg;
217 
218  return saveUser($pSysEnv, $dbh, $Cu, $parameters["a"], $Cn, "setup", true, false, $parameters["a"]["passwordRequired"] == "Y");
219 }
220 
221 /**
222  * function printValidateSMS()
223  * This prints out the validation for phone numbers.
224  */
225 function printValidateSMS()
226 { ?>
227  validatesms: function(input)
228  {
229  if (!input.is("[name='smsNumber']"))
230  return true;
231  if ($(input).val().trim() != "" && !$(input).val().match(/\([0-9]{3}\) [0-9]{3}-[0-9]{4}/))
232  {
233  $(input).attr("data-validatesms-msg", "Phone number is invalid.");
234  return false;
235  }
236  return true;
237  }
238 <?php }
239 
240 /**
241  * function printMatchOriginalPassword()
242  * This prints out the validation that the password and the original password do not match. The original password doesn't exist on the page.
243  * Checking if the original password is correct is done totally on the server side so there is a case where this fires but the original password isn't correct.
244  */
245 function printMatchOriginalPassword()
246 { ?>
247  matchoriginalpassword: function(input)
248  {
249  if (!input.is("[name='password']") || $(input).val().trim() == "")
250  return true;
251  if ($(input).val().trim() == $("[name='oldPassword']").val().trim())
252  {
253  $(input).attr("data-matchoriginalpassword-msg", "Password cannot be original password.");
254  return false;
255  }
256  return true;
257  }
258 <?php }
259 
260 /**
261  * function printInitRemoteAccess($isMaster)
262  * Prints the logic to initialize the remote access controls.
263  *
264  * @param boolean $isMaster -- if true, then it is the master user.
265  */
266 function printInitRemoteAccess($isMaster)
267 { ?>
268  function initRemoteAccess(record)
269  {
270  $("[name='remoteAccess']").click(function() {
271  $(this).prop("checked") ? $(".remoteAccessDiv").show() : $(".remoteAccessDiv").hide();
272  });
273 
274  var smsNumber= $("[name='notifySMS']").kendoMaskedTextBox({
275  mask: "(000) 000-0000",
276  clearPromptChar: true
277  }).data("kendoMaskedTextBox");
278 
279  }
280 <?php }
281 
282 /**
283  * function printRemoteAccessTemplate($isMaster)
284  * Prints the logic for remote access.
285  *
286  * @param boolean $isMaster -- if true, then it is the master user.
287  */
288 function printRemoteAccessTemplate($isMaster)
289 { ?>
290  # if (booleanRemotePrivileges) { #
291  <div class="row form-group hcuSpacer">
292  <h4 class="h4 hcuSpacerx col-xs-12">Personal Remote Access</h4>
293  </div>
294 
295  <div class="row hcuSecondary hcuSpacer"><div class="vsgSecondary col-xs-12">
296  If accessing HomeCU Admin from an unknown IP address, you will be prompted for an access code the first time you access from that IP address.
297  <br>You can get this access code through email and <i>optionally</i> through text message if your SMS information is set.
298  </div></div>
299 
300  <?php loginPrintInputLine("Notify SMS", "#: smsNumber #", "notifySMS", 0, false, true, "text");
301  ?>
302 
303  # } #
304 <?php }
305 
306 /**
307  * function printSecurityBasic($self)
308  * Prints out the basic security page
309  *
310  * @param string $self -- url to this script
311  */
312 function printSecurityCombined($self, $ft, $username="", $cu="")
313 {
314  $isMaster = strtolower($cu) == strtolower($username);
315  printCommonStyle(); ?>
316  <style>
317  <?php printTopCenterCss(450); ?>
318  </style>
319  <script type="text/javascript">
320  //# sourceURL=admSecurity.js
321  <?php // Library javascript functions
322  getShowWaitFunctions(); ?>
323 
324  var challengeData = [];
325  var challengeMap = {};
326  var previousParameters = null;
327  function init()
328  {
329  $.homecuValidator.setup({formValidate:'form', formStatusField: 'formValidateDiv', homecuCustomRules: {
330  <?php printCheckip(); ?>,
331  <?php printValidatePassword($ft == MUSTDOIT_FT); ?>,
332  <?php printMatchPasswords(); ?>,
333  <?php printValidateSMS(); ?>,
334  <?php printMatchOriginalPassword(); ?>,
335  }});
336 
337  <?php printInitPassword();
338  printInitChallenge();
339  ?>
340 
341  var parameters = {};
342  <?php if ($ft == MUSTDOIT_FT) { ?>
343  parameters.username= "<?php echo $username; ?>";
344  parameters.cu= "<?php echo $cu; ?>";
345  <?php } ?>
346  showWaitWindow();
347  $.post("<?php echo $self; ?>&operation=readUserCombined", parameters, function(data) {
348  hideWaitWindow();
349  if (data.error.length > 0)
350  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
351  else
352  {
353  $("[name='emailAddress']").val(data.record.email);
354 
355  <?php if ($ft != MUSTDOIT_FT) { ?>
356  if (data.record.booleanRemotePrivileges) {
357  var remoteTemplate= kendo.template($("#ratTemplate").html());
358  $(".remoteInsertion").html(remoteTemplate(data.record));
359  initRemoteAccess(data.record);
360  } else {
361  $(".remoteInsertion").remove();
362  }
363 
364  <?php printAfterReadChallenge(); }
365 
366  printAfterReadPassword(); ?>
367  previousParameters= savePrevious(true);
368  }
369  });
370  $("#statusSaveBtn,#skipBtn").click(function(e) {
371  e.preventDefault();
372  $("#formValidateDiv").hide();
373  var isSkip = $(this).attr("id").trim() == "skipBtn";
374 
375  if (isSkip || $.homecuValidator.validate())
376  {
377  var saveParameters = {};
378 
379  if (!isSkip)
380  {
381  var currentParameters = savePrevious(true);
382 
383  for (var prop in currentParameters)
384  {
385  if (!currentParameters.hasOwnProperty(prop))
386  continue;
387 
388  if (previousParameters[prop] === undefined || previousParameters[prop] != currentParameters[prop])
389  saveParameters[prop] = currentParameters[prop];
390  }
391 
392  if (currentParameters.usersms != previousParameters.usersms || currentParameters.providersms != previousParameters.providersms) {
393  <?php // SMS and phone provider are together. ?>
394  saveParameters.usersms = currentParameters.usersms;
395  saveParameters.providersms = currentParameters.providersms == "" ? "NONE" : currentParameters.providersms;
396  }
397 
398  if (saveParameters.questIds != null)
399  saveParameters.questResponses = currentParameters.questResponses;
400  else if (saveParameters.questResponses != null)
401  saveParameters.questIds = currentParameters.questIds;
402 
403  }
404 
405  saveParameters.username = "<?php echo $username; ?>";
406  saveParameters.cu = "<?php echo $cu; ?>";
407  saveParameters.isSkip = isSkip ? "Y" : "N";
408 
409  showWaitWindow();
410  $.post("<?php echo $self; ?>&operation=saveUserCombined", saveParameters, function(data) {
411  hideWaitWindow();
412  <?php if ($ft == MUSTDOIT_FT) { ?>
413  if (data.error.length > 0)
414  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
415  else {
416  window.location.href= "<?php echo empty($_COOKIE['Tx_aURI']) ? $menu_link : urldecode($_COOKIE['Tx_aURI']); ?>";
417  }
418  <?php } else { ?>
419  $("#formSuccessDiv").hide();
420  $("#formSuccessDiv").empty();
421  if (data.error.length > 0)
422  {
423  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
424  restorePrevious();
425  }
426  else {
427  $.homecuValidator.displayMessage("Settings were saved successfully!", $.homecuValidator.settings.statusSuccess);
428  savePrevious(false);
429  }
430 
431  $("[name='oldPassword']").val(null);
432  $("[name='password']").val(null);
433  $("[name='confirm']").val(null);
434 
435  if ($("#deleteAllowedAccess").text().trim() == "Cancel Delete")
436  $("#allowedAccess").remove();
437 
438  saveParameter = {};
439  <?php } ?>
440  });
441  }
442 
443  return false;
444  });
445  }
446 
447  <?php if ($ft != MUSTDOIT_FT){ printUpdateDDLsChallenge(); printInitRemoteAccess($isMaster); }
448 
449  /**
450  * function savePrevious()
451  * This saves the values so that if the save fails, we can go back.
452  */
453  ?>
454  function savePrevious(doStringify)
455  {
456  var parameters = {};
457  <?php if ($ft != MUSTDOIT_FT) { printSavePreviousChallenge(); } ?>
458  var smsControl = $("[name='notifySMS']").data("kendoMaskedTextBox");
459  var ipControl = $("#ipAddressGrid").data("kendoGrid");
460 
461  parameters.usersms = smsControl == null ? null : smsControl.raw();
462  parameters.remoteip = ipControl == null ? null : ipControl.dataSource.data().slice(0);
463 
464  parameters.email = $("[name='emailAddress']").val();
465 
466  parameters.oldPassword = $("[name='oldPassword']").val();
467  parameters.password = $("[name='password']").val();
468 
469  if ($("#deleteAllowedAccess").text().trim() == "Cancel Delete")
470  parameters.ipAddress = "NONE";
471 
472 
473  if (doStringify)
474  {
475  <?php if ($ft != MUSTDOIT_FT) { ?>
476  parameters.questIds = kendo.stringify(questIds);
477  parameters.questResponses = kendo.stringify(questResponses);
478  <?php } ?>
479  }
480  else
481  $("#form").data("previousRecord", parameters);
482  return parameters;
483  }
484 
485  <?php
486  /**
487  * function restorePrevious()
488  * On a failed save, this will revert the changes.
489  */
490  ?>
491  function restorePrevious()
492  {
493  var previousRecord = $("#form").data("previousRecord");
494  var smsControl = $("[name='smsNumber']").data("kendoMaskedTextBox");
495  var ipControl = $("#ipAddressGrid").data("kendoGrid");
496 
497  if (smsControl != null)
498  smsControl.value(previousRecord.usersms);
499  if (ipControl != null)
500  ipControl.dataSource.data(previousRecord.remoteip);
501  if (providerControl != null)
502  providerControl.value(previousRecord.providersms);
503 
504  $("[name='emailAddress']").val(previousRecord.email);
505  <?php if ($ft != MUSTDOIT_FT) { printRestorePreviousChallenge(); } ?>
506  }
507 
508  var activeWindows = [];
509  $(document).ready(function(){
510  init();
511  <?php printClickOverlayEvent(); ?>
512  });
513  </script>
514  <?php if ($ft != MUSTDOIT_FT) { ?>
515  <script type="text/x-kendo-template" id="ratTemplate">
516  <?php printRemoteAccessTemplate($isMaster); ?>
517  </script>
518 <?php }
519 printShowHelpTemplate(); ?>
520 
521  <div class="container-fluid"><div>
522  <form id="form" method="post" action="<?php echo $self; ?>" role="form" data-role="validator" novalidate="novalidate">
523 
524  <div class="col-xs-12">
525  <div id="formValidateDiv" class="k-block k-error-colored formValidateDiv" style="display:none;"></div>
526  </div>
527  <div class="form-horizontal form-widgets">
528  <?php if ($ft != MUSTDOIT_FT) { ?>
529  <div class="well well-sm">
530  <?php printHeader("My Contact Info");
531  loginPrintInputLine("Email", "", "emailAddress", 50, true); ?>
532  </div>
533  <div class="remoteInsertion well well-sm"></div>
534  <?php }
535  printPasswordTemplate(); ?>
536  </div>
537  <?php if ($ft != MUSTDOIT_FT) { ?>
538  <div class="form-horizontal form-widgets">
539  <?php printChallengeTemplate(); ?>
540  </div>
541  <?php } ?>
542  <div class="form-horizontal form-widgets">
543  <?php $array= array(array("text" => "Save", "id" => "statusSaveBtn", "primary" => true));
544  if ($ft == MUSTDOIT_FT)
545  $array[]= array("text" => "Skip", "id" => "skipBtn");
546  printButtons($array);
547  ?>
548  </div>
549  </form>
550  </div></div>
551 <?php }
552 
553 /**
554  * function printAfterReadPassword()
555  * I saw an opportunity to not copy four lines of code. Used in the security basic and security setup screens.
556  */
557 function printAfterReadPassword()
558 { ?>
559 
560  $("#oldPassword").val(null);
561  $("#password").val(null);
562  $("#confirm").val(null);
563 
564  $.homecuValidator.passwordRules = data.record.pwdconfig;
565 
566  var pwdRequirements= [];
567 
568  <?php // set up the messages regarding what is being checked ?>
569  var len = Number(data.record.pwdconfig.len);
570  var upper = Number(data.record.pwdconfig.upper);
571  var lower = Number(data.record.pwdconfig.lower);
572  var letter = Number(data.record.pwdconfig.letter);
573  var spec = Number(data.record.pwdconfig.spec);
574  var digit = Number(data.record.pwdconfig.digit);
575 
576  if (len > 0) {
577  var text= len + " Character" + (len > 1 ? "s" : "");
578  pwdRequirements.push({which: "len", text: text});
579  }
580 
581  if (upper > 0) {
582  var text = upper + " UPPER case letter" + (upper > 1 ? "s" : "");
583  pwdRequirements.push({which: "upper", text: text});
584  }
585  if (lower > 0) {
586  var text = lower + " lower case letter" + (lower > 1 ? "s" : "");
587  pwdRequirements.push({which: "lower", text: text});
588  }
589  if (letter > 0) {
590  var text = letter + " Letter" + (letter > 1 ? "s" : "");
591  pwdRequirements.push({which: "letter", text: text});
592  }
593  if (spec > 0) {
594  var text = spec + " Special character" + (spec > 1 ? "s" : "");
595  pwdRequirements.push({which: "spec", text: text});
596  }
597  if (digit > 0) {
598  var text = digit + " Number" + (digit > 1 ? "s" : "");
599  pwdRequirements.push({which: "digit", text: text});
600  }
601 
602  var template= kendo.template($("#passwordRequirementTemplate").html());
603 
604  $(".passwordReqInsertion").html(template({pwdRequirements: pwdRequirements}));
605 <?php }
606 
607 /**
608  * function printInitPassword($alwaysRequired=false)
609  * This prints out common initialization for the password. Used in the security basic and security setup screens.
610  *
611  * @param boolean $alwaysRequired -- on the security setup, password is required.
612  */
613 function printInitPassword($alwaysRequired=false)
614 { ?>
615  $("#showHelpLink").click(function() {
616  var dialog = $("#showHelpDialog").data("kendoWindow");
617  if (dialog == null)
618  {
619  dialog= $("<div id='showHelpDialog'></div>").appendTo("body").kendoWindow({
620  content: {
621  template: kendo.template($("#showHelpTemplate").html())
622  },
623  modal: true,
624  title: "Choosing a Safe Password",
625  visible: false,
626  resizable: false,
627  width: 900,
628  height: 550,
629  close: function()
630  {
631  $("#showHelpChk").prop("checked", true);
632  $("#showHelpChk").blur(); <?php // Force validation to clear ?>
633  activeWindows.pop();
634  }
635  }).data("kendoWindow");
636  }
637 
638  dialog.open();
639  activeWindows.push(dialog);
640  return false;
641  });
642 
643  <?php // Do it this way because it isn't initialized yet. ?>
644  $("body").on("click", "#showHelpOk", function() {
645  $("#showHelpDialog").data("kendoWindow").close();
646  return false;
647  });
648 
649  <?php // To mimic hcuProfileRequire, I need to validate on keyup to check the password requirements. ?>
650  $("[name='password']").keyup(function() {
651  $.homecuValidator.homecuKendoValidator.validateInput($(this));
652  });
653 <?php }
654 
655 /**
656  * function printVerifyPassword($self, $message)
657  * Prints out a simple page for entering the user's password again. Needed before the advanced security page.
658  *
659  * @param string $self -- the url to this script
660  * @param string $message -- the error message. (empty for no error message.)
661  */
662 function printVerifyPassword($self, $message)
663 {
664  printCommonStyle();
665  ?>
666  <script type="text/javascript">
667  function init()
668  {
669  $.homecuValidator.setup({formValidate:'form', formStatusField: 'formValidateDiv'});
670 
671  <?php if ($message !== null && trim($message) !== ""): ?>
672  $.homecuValidator.displayMessage("<?php echo $message; ?>", $.homecuValidator.settings.statusError);
673  <?php endif; ?>
674 
675  if ($("#formValidateDiv").text().trim() != "")
676  $("#formValidateDiv").show();
677 
678  $("#continueBtn").click(function() {
679  if ($.homecuValidator.validate())
680  $("#form").submit();
681  return false;
682  });
683  }
684  $(document).ready(function() {
685  init();
686  });
687  </script>
688  <div class="container-fluid"><div>
689  <form id="form" method="post" action="<?php echo $self; ?>" role="form" data-role="validator" novalidate="novalidate">
690  <div class="col-xs-12">
691  <div id="formValidateDiv" class="k-block k-error-colored formValidateDiv"></div>
692  </div>
693  <div class="form-horizontal form-widgets">
694  <?php loginPrintInputLine("Password", "", "password", 255, true, false, "password", "Password is required"); ?>
695  </div>
696  <div class="form-horizontal form-widgets">
697  <?php printButtons(array(array("text" => "Continue", "id" => "continueBtn", "primary" => true))); ?>
698  </div>
699  </form>
700  </div></div>
701 <?php }
702 
703 /**
704  * function printInitChallenge()
705  * print out the initalization of the challenge questions
706  */
707 function printInitChallenge()
708 { ?>
709  for(var i=1;i <= 3; i++)
710  {
711  $("#challengeQuestDDL"+i).kendoDropDownList({
712  dataSource: {
713  data: [],
714  schema: {
715  model: {
716  id: "quest_id",
717  fields: {
718  quest_id: {type: "number"},
719  quest_text: {type: "string"},
720  example_text: {type: "string"}
721  }
722  }
723  }
724  },
725  autoBind: true,
726  dataTextField: "quest_text",
727  dataValueField: "quest_id",
728  change: function()
729  {
730  var dataItem= this.dataItem();
731  var index= $(this.element).data("index");
732  if (dataItem != null)
733  {
734  if (Number(this.value()) != 0)
735  {
736  $("[name=challengeValidate"+index+"]").val(this.value());
737  $("#challengeExample"+index).text("E.g. " + dataItem.example_text);
738  }
739  else
740  {
741  $("[name=challengeValidate"+index+"]").val("");
742  $("#challengeExample"+index).html("&nbsp;"); <?php // Make sure that invalid thingy lines up ?>
743  }
744  }
745  else
746  {
747  $("[name=challengeValidate"+index+"]").val("");
748  $("#challengeExample"+index).html("&nbsp;"); <?php // Make sure that invalid thingy lines up ?>
749  }
750  updateDDLs();
751  $("[name=challengeValidate"+index+"]").blur(); <?php // Trigger validation ?>
752  }
753  }).data("kendoDropDownList");
754  }
755 <?php }
756 
757 /**
758  * function printRestorePreviousChallenge()
759  * prints out the contents of the restorePrevious function. For the advanced security page, it is just this. For the setup page, there is a little bit more code.
760  */
761 function printRestorePreviousChallenge($fromAdmUser=false)
762 { ?>
763  $("[name='confidenceWord']").val(previousRecord.confidence);
764 
765  for(var i=0; i < 3; i++)
766  {
767  var index= i+1;
768  $("#challengeQuestDDL"+index).data("kendoDropDownList").value(previousRecord.questIds[i]);
769  $("[name=challengeResponse"+index+"]").val(previousRecord.questResponses[i]);
770  }
771  updateDDLs();
772 <?php }
773 
774 /**
775  * function printAfterReadChallenge()
776  * prints out the code after a read for the challenge page.
777  */
778 function printAfterReadChallenge($dontFillValues=false)
779 {
780  if (!$dontFillValues) { ?>
781  $("[name='confidenceWord']").val(data.record.confidence);
782  <?php } ?>
783 
784  var thisData = data.record.mfaddl;
785  thisData.splice(0,0, {quest_id: 0, quest_text: "", example_text: "", used: -1});
786  challengeData = thisData;
787  challengeMap[0] = 0;
788  var length = data.record.mfaquest.length;
789  for(var i=0; i < 3; i++)
790  {
791  var index = i+1;
792  var ddl = $("#challengeQuestDDL"+index).data("kendoDropDownList");
793  ddl.dataSource.data(challengeData);
794 
795  <?php if (!$dontFillValues) { ?>
796  var thisRecord = data.record.mfaquest[i];
797  if (thisRecord != null)
798  {
799  $("[name=challengeResponse"+index+"]").val(thisRecord.answer);
800  $("[name=challengeValidate"+index+"]").val(thisRecord.quest_id);
801  ddl.value(thisRecord.quest_id);
802  }
803  <?php } ?>
804  }
805  savePrevious(false);
806  updateDDLs();
807 <?php }
808 
809 /**
810  * function printSavePreviousChallenge()
811  * prints out the contents of the savePrevious function for the challenge page.
812  */
813 function printSavePreviousChallenge($fromAdmUser=false)
814 {
815  if (!$fromAdmUser) { ?>
816  var parameters = {};
817  <?php } ?>
818  var questIds = [];
819  var questResponses = [];
820  $(".challengeValidate").each(function() {
821  questIds.push(Number($(this).val()));
822  });
823  $(".challengeResponse").each(function() {
824  questResponses.push($(this).val());
825  });
826  parameters.confidence = $("[name='confidenceWord']").val();
827  parameters.questIds = questIds;
828  parameters.questResponses = questResponses;
829 <?php }
830 
831 /**
832  * function printUpdateDDLsChallenge()
833  * prints out the updateDDLs function which updates the data of each challenge question ddl to not contain the questions in the other challenge questions.
834  */
835 function printUpdateDDLsChallenge()
836 { ?>
837  function updateDDLs()
838  {
839  var check= [];
840  $(".challengeValidate").each(function() {
841  check.push($(this).val());
842  });
843  for(var j=0; j < 3; j++)
844  {
845  var index= j+1;
846  var thisCheck= check.slice(0);
847  thisCheck.splice(j,1);
848 
849  $("#challengeQuestDDL"+index).data("kendoDropDownList").dataSource.data($.grep(challengeData, function(n,i) {
850  return thisCheck.indexOf(n.quest_id) == -1;
851  }));
852  }
853  }
854 <?php }
855 
856 /**
857  * function printSecuritySetup($self, $showPassword=false)
858  * prints out the page for setting up security. It is a hybrid of the security pages. Thus there is a lot of additional functions to take advantage of shared functions versus copy and paste.
859  *
860  * @param string $self -- the url of this script
861  * @param boolean $showPassword -- if $fChange is set, then the password part of the template will be included. Otherwise, it will not be printed.
862  */
863 function printSecuritySetup($self, $showPassword=false, $username, $cu)
864 {
865  printCommonStyle(); ?>
866  <style>
867  .k-notification-wrap {
868  white-space: normal !important;
869  }
870 
871  .hcu-login-block {
872  max-width: 307px;
873  }
874  </style>
875  <script type="text/javascript">
876  <?php // Library javascript functions
877  getShowWaitFunctions(); ?>
878 
879  var challengeData = [];
880  var challengeMap = {};
881  var saveParameter = {};
882  function init()
883  {
884  $("#login-entry").data("previousRecord", {});
885  $.homecuValidator.setup({formValidate:'login-entry', formStatusField: 'formValidateDiv', homecuCustomRules: {
886  <?php if ($showPassword) { printValidatePassword(true); ?>,
887  <?php printMatchPasswords(); ?>,<?php } ?>
888  <?php printValidateSMS(); ?>,
889  <?php printMatchOriginalPassword(); ?>
890  }});
891 
892  <?php printInitPassword(true); ?>
893  <?php printInitChallenge(); ?>
894 
895  <?php loginPrintPublicNote(); ?>
896 
897  $("#submitBtn").click(function() {
898  if ($.homecuValidator.validate())
899  {
900  var parameters = savePrevious(true);
901  parameters.cu = "<?php echo $cu; ?>";
902  parameters.username = "<?php echo $username; ?>";
903  parameters.passwordRequired = "<?php echo $showPassword ? 'Y' : 'N';?>";
904 
905  showWaitWindow();
906  $.post("<?php echo $self; ?>&operation=saveUserSetup", parameters, function(data) {
907  hideWaitWindow();
908  if (data.error.length > 0)
909  {
910  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
911  restorePrevious();
912  }
913  else
914  window.location.href= "<?php echo urldecode($_COOKIE['Tx_aURI']); ?>";
915 
916  <?php if ($showPassword) { ?>$("[name='oldPassword']").val(null);
917  $("[name='password']").val(null);
918  $("[name='confirm']").val(null);<?php } ?>
919  saveParameter= {};
920  });
921  }
922  return false;
923  });
924 
925  showWaitWindow();
926  var parameters= {cu: "<?php echo $cu; ?>", username: "<?php echo $username; ?>"};
927  $.post("<?php echo $self; ?>&operation=readUserSetup", parameters, function(data) {
928  hideWaitWindow();
929  if (data.error.length > 0)
930  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
931  else
932  {
933  <?php printAfterReadChallenge(true); ?>
934  <?php if ($showPassword)
935  printAfterReadPassword();
936  ?>
937  $("[name='email']").val(data.record.email);
938  }
939  });
940  }
941 
942  <?php printUpdateDDLsChallenge(); ?>
943 
944  function restorePrevious()
945  {
946  var previousRecord = $("#login-entry").data("previousRecord");
947  <?php printRestorePreviousChallenge(); ?>
948  $("[name='email']").val(previousRecord.email);
949  $("[name='confidenceWord']").val(previousRecord.confidence);
950 
951  <?php if ($showPassword) { ?>
952  $("[name='oldPassword']").val(null);
953  $("[name='password']").val(null);
954  <?php } ?>
955  }
956 
957  function savePrevious(doStringify)
958  {
959  var parameters = {};
960  <?php printSavePreviousChallenge(); ?>
961  parameters.emailAddress = $("[name='email']").val();
962  parameters.chksecure = $("[name='chksecure']:checked").val();
963  parameters.confidence = $("[name='confidenceWord']").val();
964 
965  <?php if ($showPassword) { ?>
966  parameters.oldPassword = $("[name='oldPassword']").val();
967  parameters.password = $("[name='password']").val();
968  <?php } ?>
969 
970  if (doStringify)
971  {
972  parameters.questIds = kendo.stringify(questIds);
973  parameters.questResponses = kendo.stringify(questResponses);
974  }
975  else
976  {
977  $("#login-entry").data("previousRecord", parameters);
978  }
979  return parameters;
980  }
981 
982  $(document).ready(function() {
983  init();
984  });
985  </script>
986  <?php printShowHelpTemplate(); ?>
987 
988  <div class="container-fluid"><div>
989  <form id="login-entry" method="post" role="form" data-role="validator" novalidate="novalidate">
990  <div id="formValidateDiv" class="homecu-formStatus k-block k-error-colored formValidateDiv" style="display:none;"></div>
991  <div class="well well-sm ">
992  <div class="form-horizontal form-widgets">
993  <?php if ($showPassword)
994  printPasswordTemplate();
995  printChallengeTemplate($showPassword);
996  loginPrintInputLine("Please enter email", "", "email", 50, true, true, "text", "Email is required"); ?>
997  </div>
998  </div>
999  <div class="form-horizontal form-widgets">
1000  <?php loginPrintButtons(false, false); ?>
1001  </div>
1002  <?php loginPrintSaveToken(); ?>
1003  </div>
1004  </form>
1005  </div></div>
1006 <?php }
1007 
1008 /**
1009  * function printPasswordTemplate()
1010  * prints out the shared password template in security basic and setup
1011  */
1012 function printPasswordTemplate()
1013 { ?>
1014  <div class="well well-sm">
1015  <?php printPasswordRequirementTemplate ();
1016  printHeader("Password");
1017  ?>
1018  <div class="form-group hcuSpacer">
1019  <label class="col-xs-12 col-md-8">Please Read&nbsp;</label>
1020  <div class="col-xs-12 col-md-8">
1021  <a href="#" id="showHelpLink">The Recommended Password Guidelines</a> &nbsp;<input type="checkbox" id="showHelpChk" name='showHelp'>
1022  </div>
1023  </div>
1024  <div class="row form-group">
1025  <label class="col-xs-12 col-md-8">Original Password&nbsp;</label>
1026  <div class="col-xs-12 col-md-8">
1027  <input name="oldPassword" class="hcu-all-100 k-input k-textbox" type="password" maxlength="255">
1028  </div>
1029  </div>
1030  <div class="row form-group">
1031  <div class="col-xs-12 col-md-8">
1032  <div class="col-xs-12 col-md-6 hcu-no-padding">
1033  <div class="col-xs-12 hcu-no-padding hcuSpacer">
1034  <label class="col-xs-12 extendPasswordToFit">New Password&nbsp;</label>
1035  <div class="col-xs-12 extendPasswordToFit">
1036  <input name="password" class="hcu-all-100 k-input k-textbox matchPasswords" type="password" maxlength="255">
1037  </div>
1038  </div>
1039 
1040  <div class="col-xs-12 hcu-no-padding hcuSpacer">
1041  <label class="col-xs-12 extendPasswordToFit">Confirm&nbsp;</label>
1042  <div class="col-xs-12 extendPasswordToFit">
1043  <input name="confirm" class="hcu-all-100 k-input k-textbox matchPasswords" type="password" maxlength="255">
1044  </div>
1045  </div>
1046  </div>
1047  <div class="col-xs-12 col-md-6 passwordReqInsertion"></div>
1048  </div>
1049  </div>
1050  </div>
1051  <?php }
1052 
1053 /**
1054  * function printChallengeTemplate($separator=false)
1055  * prints out the shared challenge question template in security advanced and setup
1056  *
1057  * @param boolean $separator -- if true, there is now hr on the top and bottom.
1058  */
1059 function printChallengeTemplate($separator=false)
1060 { ?>
1061  <div class="well well-sm">
1062  <?php loginPrintInputLine("Confidence Word", "", "confidenceWord", 20, true, true, false, "Confidence Word is required");
1063  printHeader("Challenge Questions");
1064 
1065  for($i=0; $i < 3; $i++)
1066  {
1067  $plusOne= $i+1; ?>
1068  <input type="hidden" name="challengeValidate<?php echo $plusOne; ?>" class="challengeValidate" required data-required-msg="Challenge Question <?php echo $plusOne; ?> is required">
1069  <div class="form-group hcuSpacer">
1070  <label class="col-xs-12 col-md-8">Question <?php echo $plusOne; ?>&nbsp;</label>
1071  <div class="col-xs-12 col-md-8">
1072  <div id="challengeQuestDDL<?php echo $plusOne; ?>" data-index="<?php echo $plusOne; ?>" class="challengeQuestDDL hcu-all-100"></div>
1073  </div>
1074  <div class="col-xs-1 col-sm-1 col-lg-1">
1075  <span data-for='challengeValidate<?php echo $plusOne; ?>' class='k-invalid-msg'></span>
1076  </div>
1077  </div>
1078  <?php loginPrintInputLine("Response $plusOne", "", "challengeResponse$plusOne", 0, true, false, "text", "Challenge Response $plusOne is required", "challengeResponse");
1079  } ?>
1080  </div>
1081  <?php }
1082 
1083  /**
1084  * function printCommonStyle()
1085  * prints out styling common to a majority of the pages.
1086  */
1087  function printCommonStyle()
1088  { ?>
1089  <style>
1090  .grid_12 {
1091  margin-bottom: 5px;
1092  }
1093 
1094  /* Give same styling as if type="text" */
1095  input[type="email"], input[type="password"] {
1096  border-style: solid;
1097  border-width: 1px;
1098  font-family: inherit;
1099  font-size: 100%;
1100  }
1101 
1102  #showHelpDialog {
1103  text-align: left;
1104  }
1105 
1106  #login-entry {
1107  margin-left: auto;
1108  margin-right: auto;
1109  }
1110 
1111  .extendPasswordToFit {
1112  padding-left: 0;
1113  }
1114 
1115  @media (max-width: 991px) {
1116  .extendPasswordToFit {
1117  padding-right: 0;
1118  }
1119  }
1120  </style>
1121  <?php }
1122 
1123  /**
1124  * function printShowHelpTemplate()
1125  * prints out the template from pwdRules.html
1126  */
1127  function printShowHelpTemplate()
1128  { ?>
1129  <script type="text/x-kendo-template" id="showHelpTemplate">
1130  <p>In General, a password should be a long as possible, while still being EASY ENOUGH TO REMEMBER without writing it down.</p>
1131  <p>One way to do this is create a password based on an easy-to-remember phrase. For example, the phrase might be: "This Is One Way I Remember My Password"
1132  and the password could be: "Ti1wIrmp". </p>
1133  <p>Use a different password for every system: Take the above example a step further and include the site name it in your password somehow:
1134  "This Is One Way I Remember My Internet Banking Password" and the result would be "Ti1wirmibp". Take it a step further and include the number of letters in the site name
1135  somewhere in the password: (e.g. 4 for ebay, 8 for facebook, 6 for paypal, etc.)</p>
1136  <p><B>NOTE: Do not use examples given here as your password!</b></p>
1137  <p>The password <b>SHOULD NOT</b> be:
1138  <ul>
1139  <li>A derivative of the login account</li>
1140  <li>A word found in a dictionary (English or foreign)</li>
1141  <li>A dictionary word spelled backwards</li>
1142  <li>A dictionary word (forward or backwards) preceded and/or followed by any other single character (e.g., secret1, 1secret, secret?, secret!)</li>
1143  <li>A dictionary word (forward or backwards) using common numeric replacements for letters (e.g., 3 for e, 1 for the letter L, 9 for g, etc)</li>
1144  <li>A password easily guessed by a friend or family member:
1145  <ul>
1146  <li>Names of family, friends, pets, coworkers, etc.</li>
1147  <li>Birthdays and other personal information such as addresses and phone numbers.</li>
1148  </li>
1149  </ul>
1150  <li>Word or number patterns like Abcd1234, qwerty, asdfjkl, 1233454321, etc.</li>
1151  </ul>
1152  </p>
1153  <p>For general password safety, you should:
1154  <ul>
1155  <li>Keep your password safe. Never write it down, store it online, or email it.</li>
1156  <li>Change ALL your passwords any time you suspect any of your online accounts have been compromised or tampered with.</li>
1157  <li>Run current anti-virus, anti-spyware, anti-malware AND keep your computer operating system up-to-date. </li>
1158  <li>Limit the amount of personal information you post on sites like twitter, myspace and facebook.
1159  All your followers and friends or others with access to the same list could easily use this information for hacking attempts.</li>
1160  <li>Be especially careful with your email password. In fact, your email account should be the most protected account you have. If a hacker has access to your email account,
1161  he can reset your password at ebay, paypal, amazon, etc. Also, email (pop3, smtp, imap) should be run under SSL especially if you use public wifi.
1162  You should not use public wifi unless you are running a personal firewall on your computer.</li>
1163  </ul>
1164  </p>
1165  <p><a href="\\#" class="k-button" id="showHelpOk">Okay</a>
1166  </script>
1167  <?php }
1168 
1169 /**
1170  * function printAdmUsrMaintLabelBlock($labelArray)
1171  * Prints out a label block
1172  *
1173  * @param array $labelArray -- the label block to display
1174  */
1175 function printAdmUsrMaintLabelBlock($labelArray)
1176 { ?>
1177  <div class="row form-group col-xs-12"><div class="k-block col-xs-12">
1178  <?php foreach($labelArray as $label => $value) { ?>
1179  <div class="col-xs-12 col-sm-6 hcuSpacer">
1180  <label class="col-xs-12"><?php echo $label; ?>&nbsp;</label>
1181  <div class="col-xs-12 admIndent"><?php echo trim(str_replace('\\', '\\\\', $value)); ?></div>
1182  </div>
1183  <?php } ?>
1184  </div></div>
1185 <?php }