Odyssey
hcuConnect.prg
1 <?php
2 /* File: hcuConnect
3  * This file will contain the logic to connect to external vendors.
4  *
5  * Note: to throw an exception, use an error object to get the title and content:
6  * $error["title"] = "title";
7  * $error["content"] = "content";
8  * throw new Exception( json_encode( $error ) );
9  */
10 require_once('cutrusted.i');
11 require_once('LogSSO.i');
12 require_once('SSOEncryption.i');
13 require_once('hcuMIRhandler.i');
14 
15 // flag to use/not-use openssl based encryption functions for SSOs
16 $use_openssl_encryption = true;
17 
18 // ** SET HOMECU FLAGS - no menu, limited branding
19 $serviceShowInfo = false;
20 $serviceLoadMenu = false;
21 $serviceShowMenu = false;
22 
23  $serviceAllowReadonly = true;
24 /*
25  * Force logging
26  */
27 //$logSessionData = file_get_contents('php://input');
28 //$logheaders = apache_request_headers();
29 //# couldn't call LogSSO because no dbh yet; couldn't pconnect because no dbenv yet
30 //# couldn't call logger because no HB_ENV yet; and by the time any of those things
31 //# were present we already redirected to hcuLogin. So this is ugly, but answered the question
32 //
33 //print "Headers: " . print_r($logheaders, true) . "\n\nData: " . print_r($logSessionData,true) . "\n";exit;
34 /*
35  * End Force logging
36  */
37 
38  // ** INCLUDE MAIN GLOBAL SCRIPT -- Handles security / global variable values
39  require_once('hcuService.i');
40 
41  /******
42  * DEBUG
43  */
44  $debugMode = true;
45  $showurl = false;
46 
47  # default, don't include preContent and postContent files
48  $usePrePostcontent = false;
49 
50  $dms_ok = array('cu' => 'string', 'Flang' => 'string',
51  'mode' => 'string', 'debug' => 'digits', 'option' => 'string','vanilla' => 'digits',
52  "flavor" => "string", "platform" => "string" );
53  dms_import_v2($HB_ENV, "HCUPOST", $dms_ok);
54 //print_r( $HB_ENV["HCUPOST"] );
55 
56 /*
57  * ** CHECK BAM PERMISSIONS **
58  * NOTE: DOES NOT RETURN ON FAILURE
59  */
60 PermCheckBAM($dbh, $HB_ENV, $MC);
61 
62 try {
63  // $mode is actually coming in as a $_GET
64  // but get it from the dms_import array so it is sanitized
65  $mode = HCU_array_key_value('mode',$HB_ENV['HCUPOST']);
66  // and throw an error if it isn't set
67 if ( empty($mode) ) {
68  throw new Exception("Invalid Connection Mode");
69 }
70 
71 # 11/22/17 documented interfaces by type in arrays for possible use by the speedbump stuff
72 # bill pay interfaces
73 $bpifx = array('ALLIEDPAY_SSO', 'CERTEGY','CHKFREE','IPAY','IPAY_V3','MVANTE','MemberPay','PAYVERIS','PSCUPAY_SSO');
74 # credit card info interfaces (DREAMPOINTS never implemented)
75 $ccifx = array('DREAMPOINTS','FIS_EZCARD','GOTOMYCARD','HcuEZCARD','PSCUINFO','PSCU_ACCPT','FISERV_CPS');
76 # estatement interfaces
77 # SavvyMoney is only sort-of an estatement -- but I need the $accountToUse to be populated
78 $esifx = array('BDI','Bit','Digital','LASERTEC_ES','LKCS','ThinkDigital','WebShare','LASERPRINT_ES','IDS_ES','SavvyMo_SSO');
79 # mortgage info interfaces. DMI & HcuDMI are same except for location of key info
80 $mtgifx = array('DMI','FICS','HcuDMI');
81 # MoneyDesktop. both should be merged into MDesk3, but mx has to adjust config for MDesk3
82 # only MDesk3 ported for Odyssey
83 $pfmifx = array('MDesk3');
84 # desktop RDC.
85 $rdcifx = array('ENSENTA_BRDC','VSHO','VSOFT');
86 # ach origination MWI_LOANPAY changed to Amplify, but specs are much different
87 # chk DELUXE_OP check orders
88 # loan app interfaces. hcuLoanApp is our in-house stuff
89 $lnappifx = array('MeridianLink','hcuLoanApp', 'CUDIRECT_SSO');
90 
91 # these SSOs are linked through the history link, not a menu item.
92 # They expect the member & suffix to be provided on URL, not through speedbump
93 $skipSpeedBump = array('DMI', 'FIS_EZCARD', 'GOTOMYCARD');
94 
95  if ( !in_array($mode, $skipSpeedBump) && in_array($mode,array_merge($bpifx, $esifx, $rdcifx, $lnappifx)) ) {
96  /* See if there needs to be a speedbump or only one account to choose from.
97  * If return from this include, a variable will be added to $HB_ENV.
98  */
99  if ( in_array($mode,$bpifx) ) {
100  $SPEEDBUMP_FEATURE = "BP";
101  } else if ( in_array($mode,$esifx) ) {
102  $SPEEDBUMP_FEATURE = "ES";
103  } else if ( in_array($mode,$rdcifx) ) {
104  $SPEEDBUMP_FEATURE = "RDC";
105  } else if ( in_array($mode, $lnappifx) ) {
106  $SPEEDBUMP_FEATURE = "LOAN";
107  }
108  require_once(dirname(__FILE__) . '/../includes/hcuAccountSelector.i');
109  $accountToUse = $HB_ENV["selected_account"];
110 
111  } else if ( !in_array($mode, $skipSpeedBump) && in_array($mode, $ccifx) ) {
112  /*
113  * See if the speedbump requires a list of all member accounts the user can view/access.
114  * SSO's in the $ccifx list are not limited to eStatements, RDC or BillPay features.
115  */
116  require_once(dirname(__FILE__) . '/../includes/hcuMemberSelector.i');
117  $accountToUse = $HB_ENV["selected_account"];
118  } else {
119  $accountToUse = "";
120  }
121 
122  // give a page that does nothing so the other choices can be chosen
123  //
124  // ** INCLUDE PRE CONTENT SCRIPT
125  $viewportAllowed = true;
126 
127  // ** INSERT BUSINESS LOGIC FOR THIS FORM
128  $Cu = $HB_ENV["Cu"];
129  $Cn = $HB_ENV["Cn"]; # remember for Odyssey this is a user_name, not a member account
130  $Uid = $HB_ENV["Uid"]; # this is the unique user identifier
131  $chome = strtolower($HB_ENV["Cu"]);
132  $Flang = $HB_ENV["Flang"];
133  $Ml = $HB_ENV["Ml"];
134  $Uid = $HB_ENV['Uid'];
135 
136  $live = $HB_ENV["live"];
137 
138  // not all paths set a web page
139  $href = "";
140 
141 // $dbh = db_pconnect();
142 
143 
144  $sql = "select user_id, email
145  from {$Cu}user
146  where user_name='$Cn'";
147 
148  $sth = db_query($sql, $HB_ENV["dbh"]);
149  #$lasterr=db_last_error();
150  if (db_num_rows($sth) != 1) {
151  throw new Exception("Member Query failed");
152  }
153  $mbrow = db_fetch_array($sth, 0);
154 
155  // Add some member-specific info from the environment variable
156  $mbrow["rt"] = HCU_array_key_value('rt', $HB_ENV);
157  if (HCU_array_key_value('Ml', $HB_ENV)) {
158  $mbrow["email"] = HCU_array_key_value('Ml', $HB_ENV);
159  }
160 
161  if ( in_array($mode,$bpifx) ) {
162 
163  $sql = "SELECT billpayid FROM {$HB_ENV["HCUPOST"]["cu"]}memberacct WHERE accountnumber = '$accountToUse'";
164 
165  $sth = db_query($sql, $HB_ENV["dbh"]);
166  if (db_num_rows($sth) != 1) {
167  throw new Exception("Billpay Query failed");
168  }
169  $row = db_fetch_array($sth, 0);
170  $mbrow["billpayid"] = $row[0];
171  } else {
172  $mbrow["billpayid"] = "";
173  }
174 
175  $billpayid = $mbrow["billpayid"];
176 
177  $trusted = cutrusted_read($dbh, array('Cu' => $Cu, 'trustedid' => $mode));
178 
179  if ($trusted["status"]["Response"] == 'false') {
180  throw new Exception("Trusted Third-Party Query Failed.");
181  }
182 
183  $parms = $trusted["data"];
184 
185  $loggingFlag = trim( HCU_array_key_value('hcuLogging', $parms) );
186  if ( strlen( $loggingFlag ) > 0 ) {
187 
188  $enable = $loggingFlag == -1;
189 
190  if ( !$enable ) {
191  $loggingFlag = str_replace( " ", "", $loggingFlag );
192  $testArray = explode( ",", $loggingFlag );
193  $enable = in_array( $HB_ENV["Cn"], $testArray );
194  }
195 
196  // @todo shouldn't this if/else wrapper be eliminated? If ! $enable above, we set $enable
197  if ( $enable ) {
198  // these are used inside the plugin to test if logging and info to log.
199  $parms["logging"] = "enabled";
200  $parms["environment"] = array( "Cu" => $HB_ENV["Cu"], // credit union
201  "memberId" => $HB_ENV["Cn"], // member id
202  "SSOVendor" => $mode, // member id
203  "userIP" => $_SERVER['REMOTE_ADDR'], // user's ip address
204  "userAgent" => $_SERVER['HTTP_USER_AGENT'], // user's ip address
205  "platform" => "{$HB_ENV['HCUPOST']['vanilla']}-{$HB_ENV['HCUPOST']['platform']}",
206  "dbConn" => $dbh ); // database connection
207  } else {
208  $parms["logging"] = "";
209  }
210  }
211 
212  $isapp = (integer) in_array(strtoupper(HCU_array_key_value('platform', $HB_ENV['HCUPOST'])), array('APP', 'ADA'));
213 
214  if ($mode !== 'VSOFT' && !$isapp ) {
215  $usePrePostcontent = true;
216  }
217 
218  if ($mode == "PAYVERIS" && $HB_ENV['HCUPOST']['flavor'] == "PVWIDGET" ) {
219  $usePrePostcontent = true;
220  $serviceShowInfo = true;
221  }
222 
223  if ($mode == "PAYVERIS" && $HB_ENV['HCUPOST']['flavor'] == "PVUIR" ) {
224  // PAYVERIS UIR version will provide all branding and navigation
225  // but need the PrePostContent so the styling and divs work later
226  $usePrePostcontent = true;
227  $serviceShowInfo = ($isapp ? false : true);
228  }
229 
230  if ( $mode == 'WebShare' && !$isapp ) {
231  $serviceShowInfo = true;
232  $serviceLoadMenu = true;
233  $serviceShowMenu = true;
234  }
235  if ( $mode == 'MDesk3' && !$isapp ) { # MDesk3 but not app
236  # $usePrePostcontent set in block above, but trying to untangle the spaghetti...
237  $usePrePostcontent = true;
238  $parms['hcuInfo'] = (integer) HCU_array_key_value('hcuInfo', $parms);
239  $parms['hcuMenu'] = (integer) HCU_array_key_value('hcuMenu', $parms);
240  $parms['hcuClose'] = (integer) HCU_array_key_value('hcuClose', $parms);
241  $serviceShowInfo = ($parms['hcuInfo'] ? true : false); #login status box upper right
242  $serviceLoadMenu = ($parms['hcuMenu'] ? true : false); # load menu from cu directory
243  $serviceShowMenu = ($parms['hcuMenu'] ? true : false); # display the menu
244  }
245  if ($mode == "SavvyMo_SSO") {
246  $usePrePostcontent = false;
247  $serviceShowInfo = false;
248  }
249 
250  if ($mode == "DMI" || $mode == "HcuDMI") {
251  $usePrePostcontent = false;
252  $serviceShowInfo = false;
253  }
254 
255  if ($mode == 'ALLIEDPAY_SSO') {
256  /**
257  * on alliedpay_sso request, check which platform to determine
258  * when to display the menu and login status box.
259  *
260  * for version odyssey
261  *
262  * desktop: show status box;
263  * mobile web: do not show; vanilla = 1
264  * mobile app: do not show; platform = APP
265  *
266  * for mammoth
267  *
268  * desktop: show status box;
269  * mobile web / mobile app use mobileConnect script instead
270  */
271  list ($serviceLoadMenu, $serviceShowMenu, $serviceShowInfo) = AlliedSsoServiceFlags();
272 
273  }
274 
275  if ($usePrePostcontent) {
276  // this lets the PreContent still use the banner if called by the apps.
277  $preKeepBanner = true;
278 
279  require_once('hcuPreContent.i');
280  }
281 
282  /**** Switch ends line 4620 08/19 **/
283  switch ($mode) {
284 
285  case "ALLIEDPAY_SSO":
286 
287  if (!hcu_checkService($dbh, "ALLIEDPAY")) {
288  $omsg = hcu_checkServiceMsg($dbh, "ALLIEDPAY");
289  throw new Exception("$omsg");
290  }
291 
292  if ( $GLOBALS['viewportAllowed'] ) {
293  echo '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">';
294  }
295 
296  require_once(__DIR__ . '/../library/AlliedPay_API.i');
297 
298  // Modifies "$parms" byRef
299  apn_config($parms);
300 
301  $billpayid = (HCU_array_key_value('billpayid', $mbrow)) ? trim($mbrow['billpayid']) : $HB_ENV['Cn'];
302 
303  // This is only loaded from hcuService.i **if live.** If not LIVE devMode should be 1 in
304  // trusted details and you should be using one of the test members configured at the
305  // faux fetcher:
306  // https://int-apl0.homecu.net/hculive/xenia-homecu-faux.mp
307  //
308  // NOTE: GetMemberInfo does not work for batch clients, so don't try.
309  // the if($live) refers to clients on live interface vs. batch interface,
310  // NOT test vs. production
311  //
312  // if (! function_exists('GetMemberInfo')) {
313  // require_once(__DIR__ . '/../../shared/library/sAPIAppl.i');
314  // }
315  if ($live) {
316  $MIR = GetMemberInfo($HB_ENV, ["member" => $accountToUse]);
317  if (! isset($MIR['code']) || ($MIR['code'] !== '000')) {
318  $code = $MIR['code'] ?? 'no code';
319  throw new Exception("No Member Data ($code)");
320  }
321  } else {
322  # batch interface will need to figure out how to get MIR info */
323  $MIR["data"] = array();
324  }
325 
326  if (!HCU_array_key_exists('accountnumber', $MIR['data'])) {
327  throw new Exception("No Member Data (account number)");
328  }
329 
330  //(phone not required) per Allied 8/29/18 let 'em in, phone or not
331  // they will get an error if they try P2P w/o phone number
332  $reqMIR = [
333  'accountnumber' => 1,
334  'firstname' => 1,
335  'lastname' => 1,
336  'address1' => 1,
337  'city' => 1,
338  'state' => 1,
339  'zip' => 1
340  ];
341 
342  $config = FeatureGateConfig::GetInstance($dbh);
343  $MIRGate = new CreditUnionGate(CreditUnionGate::MIR_HANDLER, $config);
344  if ($MIRGate->WillPass($HB_ENV['Cu'],['username' => $HB_ENV['Cn']])) {
345  $parsedMIR = FormatMIR($MIR['data'], $Ml, $reqMIR, 'Y-m-d', 'shortname', true, 'pass');
346  } else {
347  $parsedMIR = apn_populateMIR($MIR, $Ml, $reqMIR, 'Y-m-d', 'named', true);
348  }
349  if (!HCU_array_key_value('response', $parsedMIR['status'])) {
350  $message = (HCU_array_key_value('message', $parsedMIR['status'])) ?
351  $parsedMIR['status']['message'] : "Member Info Not Found";
352  throw new Exception($message);
353  }
354 
355  $accounts = apn_selectAccounts($dbh, $HB_ENV['Cu'], $HB_ENV['Cn'], $parms);
356 
357  if (!HCU_array_key_value('response', $accounts['status'])) {
358  $message = (HCU_array_key_value('message', $accounts['status'])) ?
359  $accounts['status']['message'] : "Failed Retrieving Account list";
360  throw new Exception($message);
361  }
362 
363  $ssoPayload = apn_buildSSOPayload($parms['apnDomain'], $billpayid, $parsedMIR['data'], $accounts['data']);
364 
365  if (!HCU_array_key_value('response', $ssoPayload['status'])) {
366  $message = (HCU_array_key_value('message', $ssoPayload['status'])) ?
367  $ssoPayload['status']['message'] : "Failed building SSO Request";
368  throw new Exception($message);
369  }
370 
371  $ssoAuthHdr = apn_buildAuthHdr(
372  $parms['apnURL'],
373  $parms['apnDomain'],
374  $parms['apnPubkey'],
375  $parms['apnPrivkey'],
376  $billpayid
377  );
378 
379  if (!HCU_array_key_value('response', $ssoAuthHdr['status'])) {
380  $message = (HCU_array_key_value('message', $ssoAuthHdr['status'])) ?
381  $ssoAuthHdr['status']['message'] : "Failed building Authorization Header";
382  throw new Exception($message);
383  }
384 
385  $curl_params = [
386  'Authorization' => $ssoAuthHdr['data'],
387  'Content-Type' => 'Content-Type: application/json'
388  ];
389  $parms["environment"]["logPoint"] = "AlliedPay SSO";
390  $URI = apn_embcurl($parms, $parms['apnURL'], 'POST', $curl_params, $ssoPayload['data']);
391 
392  if (HCU_array_key_exists('error', $URI)) {
393  $message = HCU_array_key_value('status', $URI['error']) . " " . HCU_array_key_value('message', $URI['error']);
394  throw new Exception($message);
395  }
396 
397  // $URI comes back as
398  // { "$id": "1", "Uri": "https://homecu.demo.alliedpayment.com/billpay/sso?IV=Jm2zGzEBYnr6M4QTKyhEOA,,&ssoToken=7kyk40eN1Bt-5WU7nrXE6I82bvAHf1MrF22-2_rawTosKnVX_FDZhQ9_t3l-pWD0jskDRzJO2csIs_l3v2I2_oulUkv0WyCTMBUXU0ZluOlTzHSZewsl7AQHROBDrKdwWbiH2VgUm9jadVMAvBhXBA,,&signature=275F5189631F4AAC9028C0FF8D25BAC5128B2323" }
399  $uri = HCU_array_key_value('Uri', $URI);
400  if (empty($uri)) {
401  throw new Exception('Connection Failed Invalid Link');
402  }
403 
404  $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
405  $divclass = null;
406  if (stripos($ua, 'iPhone') !== false || stripos($ua, 'iPod') !== false || stripos($ua, 'iPad') !== false) {
407  $divclass = ' class="appledevice"';
408  }
409 
410  if (
411  ! HCU_array_key_value('vanilla',$HB_ENV['HCUPOST']) &&
412  ! in_array(strtoupper(HCU_array_key_value('platform',$HB_ENV['HCUPOST'])), ['MBL','APP','ADA'])
413  ) {
414 
415  $linkText = 'Return to Accounts';
416  $linkLoc = "{$HB_ENV['loginpath']}/hcuAccounts.prg?{$HB_ENV['cuquery']}";
417 
418  $return_to_accounts = "
419  <button type=\"button\" id=\"showAccounts\" name=\"btnOLB\" style=\"margin:6px\"
420  onclick=\"window.location='{$linkLoc}'\" class=\"k-button\">
421  <span class=\"fa fa-arrow-left\"></span>&nbsp;{$linkText}
422  </button>
423  ";
424  }
425 
426  // load content from $uri
427  print <<<EOF
428 
429  <script>
430  function showPage() {
431  var bp = document.getElementById("hcuBPframe"),
432  action = '$uri';
433  bp.src = action;
434  }
435 
436  $(window).resize(function() {
437  $('#billpay-scroll-wrapper').height($(window).innerHeight() - $('#workspace')[0].offsetTop - 150);
438  });
439 
440  $(window).load(function() {
441  $('#billpay-scroll-wrapper').height($(window).innerHeight() - $('#workspace')[0].offsetTop - 150);
442  });
443  </script>
444  <div id="backToHCU">
445  $return_to_accounts
446  </div>
447  <script>
448  $(document).ready(function() {
449  showPage('$uri');
450  });
451  </script>
452  <div id="billpay-scroll-wrapper"{$divclass}>
453  <iframe id="hcuBPframe" sandbox="allow-pointer-lock allow-popups allow-same-origin allow-top-navigation allow-scripts allow-forms"></iframe>
454  </div>
455 EOF;
456  // ALLIED_SSO
457  break;
458 
459  case "CUDIRECT_SSO":
460  /*
461  * SSO flow
462  * CuDir_config to set parameters
463  * populate mir
464  * *
465  * build sso payload
466  * call CuDir_embcurl to get URI
467  * redirect to URI
468  */
469  if (!hcu_checkService($dbh, "CUDIRECT")) {
470  $omsg = hcu_checkServiceMsg($dbh, "CUDIRECT");
471  throw new Exception("$omsg");
472  }
473 
474  // as of 5.3, dirname(__FILE__)) no longer required
475  // https://www.php.net/manual/en/language.constants.predefined.php#constant.dir
476  require_once(__DIR__ . '/../includes/CUDirect_API.i');
477  // This is only loaded from hcuService.i **if live.** If not LIVE devMode should be 1 in
478  // trusted details and you should be using one of the test members configured at the
479  // faux fetcher:
480  // https://int-apl0.homecu.net/hculive/xenia-homecu-faux.mp
481  //
482  // NOTE: GetMemberInfo does not work for batch clients, so don't try.
483  // the if($live) refers to clients on live interface vs. batch interface,
484  // NOT test vs. production
485  //
486  // if (! function_exists('GetMemberInfo')) {
487  // require_once(__DIR__ . '/../../shared/library/sAPIAppl.i');
488  // }
489 
490  try {
491  CuDir_config($parms);
492 
493  } catch (Exception $e) {
494  throw new Exception("Exception in CUDIRECT_SSO config: {$e->getMessage()}");
495  }
496  if ($live) {
497  $MIR = GetMemberInfo($HB_ENV, ["member" => $accountToUse]);
498  if (! isset($MIR['code']) || ($MIR['code'] !== '000')) {
499  $code = $MIR['code'] ?? 'no code';
500  throw new Exception("No Member Data ($code)");
501  }
502  } else {
503  # batch interface will need to figure out how to get MIR info */
504  $MIR["data"] = array();
505  }
506 
507  if (!HCU_array_key_exists('accountnumber', $MIR['data'])) {
508  throw new Exception("No Member Data (account number)");
509  }
510 
511  $reqMIR = [
512  'accountnumber' => 1,
513  'firstname' => 1,
514  'lastname' => 1,
515  'address1' => 1,
516  'city' => 1,
517  'state' => 1,
518  'zip' => 1,
519  'dob' => 1,
520  //'phonenumbers' => 1
521  ];
522 
523  $config = FeatureGateConfig::GetInstance($dbh);
524  $MIRGate = new CreditUnionGate(CreditUnionGate::MIR_HANDLER, $config);
525  if ($MIRGate->WillPass($HB_ENV['Cu'],['username' => $HB_ENV['Cn']])) {
526  $parsedMIR = FormatMIR($MIR['data'], $Ml, $reqMIR, 'Y-m-d', 'named', true, '');
527  } else {
528  try {
529  $parsedMIR = populateMIR($MIR['data'], $Ml, $reqMIR, 'Y-m-d', 'named', true);
530 
531  } catch (Exception $e) {
532  throw new Exception("Exception populating MIR: {$e->getMessage()}");
533  }
534  }
535 
536  if (! (HCU_array_key_value('response', $parsedMIR['status']) === true)) {
537 
538  $message = (HCU_array_key_value('message', $parsedMIR['status'])) ?
539  $parsedMIR['status']['message'] :
540  "Member Info Not Found";
541 
542  throw new Exception($message);
543  }
544 
545  $ssoPayload = CuDir_buildSSOPayload(
546  $parms['CuDirOrg'],
547  $parms['CuDirUser'],
548  $parms['CuDirPass'],
549  $HB_ENV['Cn'],
550  $parsedMIR['data']
551  );
552 
553  # throw error on failure
554  if (!HCU_array_key_value('response', $ssoPayload['status'])) {
555 
556  $message = (HCU_array_key_value('message', $ssoPayload['status'])) ?
557  $ssoPayload['status']['message'] :
558  "Failed building SSO Request";
559 
560  throw new Exception($message);
561  }
562 
563  $URI = CuDir_embcurl(
564  $parms,
565  $parms['CuDirURL'],
566  'POST',
567  [
568  'Content-Type' => 'Content-Type: text/xml; charset=utf-8;',
569  ],
570  $ssoPayload['data']
571  );
572 
573  if (HCU_array_key_exists('error', $URI)) {
574  // 07-19, previous one liner throwing notice for __toString()/mixed
575  $stat = HCU_array_key_value('status', $URI['error']);
576  $msg = HCU_array_key_value('message', $URI['error']);
577  throw new Exception("$stat $msg");
578 
579  } else {
580  $uri = HCU_array_key_value('BaseURL', $URI);
581  $token = HCU_array_key_value('Token', $URI);
582 
583  if (empty($uri) || empty($token)) {
584  throw new Exception('Invalid Link' . print_r($URI, true));
585  } else {
586  // load content from $uri and redirect
587  header('Location: '."$uri?SSOToken=$token&frame=no");
588  exit;
589  }
590  }
591 
592  break;
593 
594  case "DREAMPOINTS":
595 
596  function _saltMine($length) {
597  $pool = array_merge(range(0,9), range('a', 'z'),range('A', 'Z'));
598  $poolsize = count($pool) - 1;
599  $salt = '';
600 
601  for($i=0; $i < $length; $i++) {
602  $salt .= $pool[mt_rand(0, $poolsize)];
603  }
604  return $salt;
605  }
606 
607  if (!hcu_checkService($dbh, "DREAMPOINTS")) {
608  $omsg = hcu_checkServiceMsg($dbh, "DREAMPOINTS");
609  throw new Exception("$omsg");
610  }
611 
612  $pilot = HCU_array_key_value('pilot', $parms);
613  if ($pilot) {
614  $serviceurl = HCU_array_key_value('piloturl',$parms);
615  $key = HCU_array_key_value('pilotkey', $parms);
616  } else {
617  $serviceurl = HCU_array_key_value('produrl', $parms);
618  $key = HCU_array_key_value('prodkey', $parms);
619  }
620  $bnkid = HCU_array_key_value('bnkid', $parms);
621 # generate a random iv for each call
622  $cipher = 'des-ede3-cbc';
623  if (!in_array($cipher, openssl_get_cipher_methods())) {
624  throw new Exception("Invalid cipher method");
625  }
626 
627  $ivlen = openssl_cipher_iv_length($cipher);
628  $iv = openssl_random_pseudo_bytes($ivlen);
629  $iv = _saltMine($ivlen);
630  if (empty($serviceurl) || empty($bnkid) || empty($iv) || empty($key)) {
631  $msg = "Configuration Error ";
632  if (empty($serviceurl)) {
633  $msg .= 'ServiceURL ';
634  }
635  if (empty($bnkid)) {
636  $msg .= 'bnkid ';
637  }
638  if (empty($iv) || empty($key)) {
639  $msg .= 'Encrytpion_credentials ';
640  }
641 
642  throw new Exception($msg);
643  }
644  if ($live) {
645  $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
646  } else {
647  # batch interface will need to figure out how to get MIR info */
648  $MIR["data"] = array();
649  }
650  #GetMemberInfo returns array
651  # check for status other than 101 and give error
652  # currently accepting 101 and 201, but probably shouldn't accept 201
653 
654  /* Only using first name / last name
655  * check to see if we have enough valid data to make vendor happy
656  */
657  $reqMIR = array(
658  'accountnumber' => 1,
659  'lastname' => 1
660  );
661 
662 
663  $config = FeatureGateConfig::GetInstance($dbh);
664  $MIRGate = new CreditUnionGate(CreditUnionGate::MIR_HANDLER, $config);
665  if ($MIRGate->WillPass($HB_ENV['Cu'],['username' => $HB_ENV['Cn']])) {
666  $parsedMIR = FormatMIR($MIR['data'], $HB_ENV['Ml'], $reqMIR, 'mdY', 'flat', false, '');
667  } else {
668  $parsedMIR = populateMIR($MIR['data'], $HB_ENV['Ml'], $reqMIR, 'mdY', 'flat', false);
669  }
670  if (!$parsedMIR['status']['response']) {
671  throw new Exception($parsedMIR['status']['message']);
672  }
673  $msg = '';
674  if (empty($parsedMIR["data"]["accountnumber"]) ||
675  empty($parsedMIR["data"]["lastname"]) ||
676  empty($serviceurl) ||
677  empty($parms['bnkid']) ||
678  empty($iv) ||
679  empty($key)) {
680  throw new Exception("Not enough member info for Dreampoints ($msg)");
681  }
682 
683  $dispname = trim("{$parsedMIR['data']['firstname']} {$parsedMIR['data']['lastname']}");
684  $gmstamp = time();
685  $salt=_saltMine(12);
686 
687 /*
688  * Turns out the big development roadbloack was....
689  * Augeo configured for 16-digit account number, we were passing member number.
690  * We can't get 16-digit, they can't get member.
691  * We settled on DDA, which appears to be member number zero-padded to 10 digits.
692  *
693  * This really should come from trusted detail. Might need a function to get
694  * values from db as other trusted integrations do. For now, use 'UserCodeSize'
695  * setting similar to Payveris
696  */
697  $CodeSize = (integer)HCU_array_key_value('UserCodeSize', $parms);
698  if ( $CodeSize > 0) {
699  $memUnique = substr(str_repeat('0', $CodeSize) . $accountToUse, (-1 * $CodeSize), $CodeSize);
700  } else {
701  # default no padding
702  $memUnique = $accountToUse;
703  }
704 
705  $plaintext = "{$memUnique}|{$gmstamp}|{$dispname}|{$salt}";
706 
707  $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv);
708 
709  if ($parms["logging"] == "enabled") {
710  $logParms = $parms["environment"]; // get the environment info passed in
711  $logParms["token"] = ''; // the id used across all communications in session
712  $logParms["txnId"] = time(); // the id for this transaction
713  $logParms["logPoint"] = "DREAMPOINTS Redirect"; // this action in a readable form
714  $dpData = array('BNKID' => $bnkid,
715  'UID' => $ciphertext,
716  'IV' => $iv);
717 
718  $logParms["request"] = "cipher $cipher\nplainUID $plaintext\ncurl --request POST --data '" . urldecode(http_build_query($dpData)) . "' '$serviceurl'"; // the request
719  $logParms["reply"] = ''; // the response
720  LogSSOActivity($logParms);
721  }
722 
723  print <<<EOF
724  <html>
725  <body onload = "javascript:document.SSOform.submit();">
726  <form method="post" name="SSOform" action = "{$serviceurl}">
727  <input type="hidden" name="BNKID" value="{$bnkid}">
728  <input type="hidden" name="UID" value="$ciphertext">
729  <input type="hidden" name="IV" value="$iv">
730  </form>
731  </body>
732  </html>
733 EOF;
734  break;
735  case "HcuDMI": # same SSO, using key info stored at HomeCU ({cu}extkey table)
736  case "DMI":
737  # NOTE that DMI does not use the speedbump. Both accountToUse and
738  # loannumber are populated from the loan history settings in home banking.
739  # On Mammoth, only the loannumber was set with loannumber=#loan#
740  # For Odyssey, add a=#acctid#
741 
742  if (!hcu_checkService($dbh, "Dovenmuehle")) {
743  $omsg = hcu_checkServiceMsg($dbh, "Dovenmuehle");
744  throw new Exception("$omsg");
745  }
746  /*
747  * need to force test mode for certain testers
748  */
749  $forceTest = 0;
750  $testingFlag = str_replace( " ", "", HCU_array_key_value('testers', $parms ));
751  $testingArray = explode( ",", $testingFlag );
752  $forceTest = in_array( $HB_ENV["Cn"], $testingArray );
753 
754  $parms['pilot'] = HCU_array_key_value('pilot', $parms);
755  if ($parms['pilot'] || $forceTest ) {
756  $parms['GUID'] = HCU_array_key_value('testGUID',$parms);
757  $parms['AuthURL'] = HCU_array_key_value('testAuthURL', $parms);
758  $parms['SSOURL'] = HCU_array_key_value('testSSOURL', $parms);
759  } else {
760  $parms['GUID'] = HCU_array_key_value('prodGUID', $parms);
761  $parms['AuthURL'] = HCU_array_key_value('prodAuthURL', $parms);
762  $parms['SSOURL'] = HCU_array_key_value('prodSSOURL', $parms);
763  }
764  // print "<pre>" . print_r($parms,true) . "</pre>"; exit;
765 
766  $dms_ok = array('keyloc' => 'string');
767  dms_import($dms_ok);
768 
769  $Cu = $HB_ENV['Cu'];
770  $Cn = $HB_ENV['Cn'];
771 
772  if (empty($parms['GUID']) ||
773  empty($parms['AuthURL']) || empty($parms['SSOURL']) ||
774  !(HCU_array_key_value('hcuCert',$parms)) ||
775  !(HCU_array_key_value('hcuKey',$parms)) ||
776  empty($Ml) || empty($Cu) ) {
777  throw new Exception('Invalid or missing parameters');
778  }
779 
780  /** Load Cert file **/
781  // ** Get the Cert File Secrets ID from trusted details
782  $tdCertFileId = $parms['hcuCert'];
783 
784  /**
785  * Retrieve and decrypt the cert file -- use rdccert as return value to limit scope of changes
786  */
787  $hcuCertFile = GetAwsCertFile($tdCertFileId, HOMECU_ENC_CERT_DIR, HOMECU_DOCK_CERT_DIR);
788 
789  // ** Get the Key File Secrets ID from trusted details
790  $tdKeyFileId = $parms['hcuKey'];
791 
792  /**
793  * Retrieve and decrypt the key file -- use rdccert as return value to limit scope of changes
794  */
795  $hcuKeyFile = GetAwsCertFile($tdKeyFileId, HOMECU_ENC_CERT_DIR, HOMECU_DOCK_CERT_DIR);
796 
797  /** Did the files from trusted detail get created as expected? **/
798  if (($hcuCertFile == '' || !(is_readable($hcuCertFile))) || ($hcuKeyFile == '' || !(is_readable($hcuKeyFile)))) {
799 
800  throw new Exception("Security Files missing or unreadable");
801  }
802  $keyloc = (isset($keyloc) ? $keyloc : '');
803  if (strtoupper($keyloc) == 'EXTERNAL') {
804  # I think we lost something on the conversion to Odyssey here
805  # looks like accountToUse won't be set until after decrypt and
806  # split acctid below. That will need fixed to use external keys
807 
808  if (empty($accountToUse) ) {
809  throw new Exception('Missing Account Parameter');
810  }
811 
812  # get dmi account from {$CU}extkey table
813  # should only have one mortgage per loannumber, but
814  # just in case, limit 1
815  $sql = "select parms
816  from {$Cu}extkey where accountnumber='" . prep_save($accountToUse, 12) . "'
817  and accounttype = '" . prep_save($loannumber, 25) . "'
818  and providermode='$mode' limit 1;";
819  } else {
820  $dms_ok = array('a' => 'string');
821  dms_import($dms_ok);
822 
823  // a = acctid
824  // acctid is the string representation of the sub account
825  // D|6680|10|0
826  $acctID = HCU_PayloadDecode($Cu, $a);
827  $loannumber = $acctID[2];
828  $accountToUse = $acctID[1];
829 
830  // must restrict to the current user, check if the user
831  // actually has access to the loan account that was passed
832  // through.
833  $sql = "
834  SELECT * FROM {$Cu}useraccounts
835  WHERE accountnumber = '" . prep_save($accountToUse, 12) . "'
836  AND accounttype = '" . prep_save($loannumber, 25) . "'
837  AND recordtype = 'L'
838  AND user_id = $Uid";
839  $sth = db_query($sql, $dbh);
840  if (!($sth) || db_num_rows($sth) == 0) {
841  throw new Exception('No credit card found. Please contact the credit union.');
842  }
843 
844  # get card info from {$CU}loanbalance table
845  $sql = "select trim(misc1)
846  from {$Cu}loanbalance where accountnumber='" . prep_save($accountToUse, 12) . "'
847  and loannumber='" . prep_save($loannumber, 25) . "';";
848  }
849 
850  $sth = db_query($sql, $dbh);
851  if (!($sth) || db_num_rows($sth) == 0) {
852  throw new Exception('No mortgage loan found. Please contact the credit union.');
853  }
854  list($misc1) = db_fetch_array($sth, 0);
855  list($dmiloan) = explode(',', $misc1);
856 
857  # give error and die if missing values
858  if (empty($dmiloan) ) {
859  throw new Exception('Empty DMI Loan number');
860  }
861  $err_msg = "";
862 
863  $req = "-d 'loanno=$dmiloan'";
864  $req .= " -d 'Rset={$parms['GUID']}'";
865  $req .= " -d 'Email=" . urlencode($Ml) . "'";
866 
867 // $cmd = "/usr/bin/curl $req --cert '{$parms['hcuCert']}' --key '{$parms['hcuKey']}' --url '{$parms['AuthURL']}'";
868  $cmd = "/usr/bin/curl --cert '{$hcuCertFile}' --key '{$hcuKeyFile}' --url '{$parms['AuthURL']}?loanno=$dmiloan&Rset={$parms['GUID']}&Email=" . urlencode($Ml) . "'";
869 # $dmiauth = getcurl($cmd);
870 # try POSTFIELDS as array if urlencoded string does not work. Also not sure what CURLOPT_POST ought to be
871 # Passing an array to CURLOPT_POSTFIELDS will encode the data as multipart/form-data,
872 # Passing a URL-encoded string will encode the data as application/x-www-form-urlencoded.
873  $curlopts = array(
874  CURLOPT_RETURNTRANSFER => 1,
875  CURLOPT_SSLCERT => "{$hcuCertFile}",
876  CURLOPT_SSLKEY => "{$hcuKeyFile}",
877  CURLOPT_URL => "{$parms['AuthURL']}?loanno=$dmiloan&Rset={$parms['GUID']}&Email=" . urlencode($Ml));
878 
879  $dmiauth = "";
880  $ch = curl_init();
881  if ($ch) {
882  curl_setopt_array($ch, $curlopts);
883  $dmiauth = curl_exec($ch);
884  curl_close($ch);
885  }
886 
887  if ($parms["logging"] == "enabled") {
888  $logParms = $parms["environment"]; // get the environment info passed in
889  $logParms["token"] = ''; // the id used across all communications in session
890  $logParms["txnId"] = time(); // the id for this transaction
891  $logParms["logPoint"] = "DMI SSO"; // this action in a readable form
892  $logParms["request"] = $cmd; // the request
893  $logParms["reply"] = $dmiauth; // the response
894  LogSSOActivity($logParms);
895  }
896 # Good Response:
897 # KEY=B8DE9B1D-4051-4784-8E02-2B55C17B15B7
898 # Error Response:
899 # Error=5:Client server IP did not match, access denied
900 
901  if (trim($dmiauth) == '' || preg_match("/Error/i", "$dmiauth")) {
902  throw new Exception("Connection Failed ( $dmiauth ) ");
903  } else {
904  # get dmikey out of response
905  $dmikey=substr($dmiauth,4);
906  if (trim($dmikey) == '' ) {
907  throw new Exception("Missing Key ");
908  }
909  if ($parms["logging"] == "enabled") {
910  $logParms = $parms["environment"]; // get the environment info passed in
911  $logParms["token"] = ''; // the id used across all communications in session
912  $logParms["txnId"] = time(); // the id for this transaction
913  $logParms["logPoint"] = "DMI Redirect"; // this action in a readable form
914  $logParms["request"] = "SSO w/ key as $dmikey"; // the request
915  $logParms["reply"] = ''; // the response
916  LogSSOActivity($logParms);
917  }
918  print <<<EOF
919  <html>
920  <body onload = "javascript:document.SSOform.submit();">
921  <form method="post" name="SSOform" action = "{$parms['SSOURL']}">
922  <input type="hidden" name="KEY" value="{$dmikey}">
923  </form>
924  </body>
925  </html>
926 EOF;
927  }
928  break;
929  # begin Odyssey update 6/19/18
930 ######
931  case "ENSENTA_BRDC":
932 
933  if (!hcu_checkService($dbh, "ENSENTA")) {
934  $omsg = hcu_checkServiceMsg($dbh, "ENSENTA");
935  throw new Exception("$omsg");
936  }
937  include_once(dirname(__FILE__) . '/../library/rdcEnsenta.i');
938  include_once(dirname(__FILE__) . '/../library/rdcCommon.i');
939  # Ensneta_BRDC only works on IE
940  # use rt from trusteddetail if there is one, otherwise use the home banking value
941  $parms['rt'] = (HCU_array_key_value("rt", $parms) && !preg_match("/\D/",$parms['rt']) ? $parms['rt'] : $HB_ENV['rt']);
942  # and complain if it isn't valid
943  if (empty($parms['rt']) || preg_match("/\D/",$parms['rt'])) {
944  # routing number missing or contains non-digits
945  throw new Exception("Routing Number missing or invalid");
946  }
947  # NOTE this block changed for Odyssey, using code similar to rdcEnsenta.i
948  # tried to use rdcEnsenta functions so that we get display description a
949  # as configured, and we check permissions / user rights
950 
951  if ($parms['HomeCUAuth']) {
952  $mbr_rdc = Get_RDCSetting($dbh, $HB_ENV, 'RDCENSENTA', $accountToUse);
953  if ($mbr_rdc['status']['code'] != '000') {
954  throw new Exception($mbr_rdc['status']['message'], $mbr_rdc['status']['code']);
955  }
956  $dl = abs( intval( $mbr_rdc['rdcsetting'] ) );
957 
958  if ( isset( $parms['HomeCUAuthVal'] ) && strlen( $parms['HomeCUAuthVal'] ) > 0 ) {
959  // check to see if current setting is one of the allowed settings
960  $authVals = explode( ",", $parms['HomeCUAuthVal'] );
961  if ( !in_array( $dl, $authVals ) ) {
962  // treat it as if no setting
963  $dl = 0;
964  }
965  }
966 
967  if (abs(intval($dl)) == 0) {
968 ############# might need a different Get_NoticeInfo form
969  # 'M' device may need to be 'D' desktop instead
970  # but appears to have been working with mobile, so let sleeping dogs lie
971  $HB_Notices_ary = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'M', "bNoRDC", true);
972  if ($HB_Notices_ary['status']['code'] == '000') {
973  $noticeData = $HB_Notices_ary["notice"][0]["notice_text"];
974  } else {
975  $noticeData = "";
976  }
977  if (strlen($noticeData)) {
978  $message = $noticeData;
979  } else {
980  $message = "Account not permitted for Remote Deposit. Please contact the Credit Union for more information";
981  }
982  throw new Exception("$message");
983  }
984  }
985  $parms['UAT'] = HCU_array_key_value('UAT',$parms);
986  if ($parms['UAT']) {
987  $parms['certfile'] = HCU_array_key_value('UATCert', $parms);
988  $parms['ssourl'] = HCU_array_key_value('UATsso', $parms);
989  } else {
990  $parms['certfile'] = HCU_array_key_value('certfile', $parms);
991  $parms['ssourl'] = HCU_array_key_value('PRODsso', $parms);
992  }
993  if (!(is_readable($parms['certfile']))) {
994  throw new Exception("Security File missing");
995  }
996  $gmt = gmdate("Y-m-d H:i:s");
997 
998  $parms['Fset2'] = $HB_ENV['Fset2']; # HB_ENV
999  $parms['Fset3'] = $HB_ENV['Fset3']; # HB_ENV
1000  $hculist = RDCGetAccts($dbh, $parms);
1001 
1002  if ($hculist['status']['response'] == 'false') {
1003  throw new Exception($hculist['status']['message']);
1004  }
1005 
1006  # got a valid RDC account list
1007 
1008  $err_msg = "";
1009 
1010  $req = "-d rtn={$HB_ENV['rt']}";
1011  $req .= " -d user_fi_number=$accountToUse";
1012  $req .= " -d Username=" . urlencode($Cn); # for commercial this should be the user_name. Encoding anticipates non-digit values
1013  $req .= " -d gmt=" . urlencode($gmt);
1014  if (!empty($Ml) )
1015  $req .= " -d email=" . urlencode($Ml);
1016  $idx=0;
1017  foreach ($hculist['data'] as $key => $value) {
1018  $idx++;
1019  $req .= " -d ADSC$idx=" . urlencode($value['displaydesc']); # hcu description
1020  $req .= " -d type_name$idx=" . urlencode($value['rdcdesc']); # computed rdcdesc
1021  $req .= " -d ANUM$idx=" . urlencode($value['suffix']); # computed savingsql / checksql / loansql
1022  $req .= " -d account_number$idx=" . urlencode($value['suffix']); # hcu member=accounttype [suffix? rdcmember?]
1023  $req .= " -d ATYP$idx={$value['rdctype']}"; # calculated rdctype [rdctype]
1024  }
1025 
1026  $cmd = "/usr/bin/curl $req -E {$parms['certfile']} --url '{$parms['ssourl']}'";
1027 
1028  $ensenta = getcurl($cmd);
1029  if ($parms["logging"] == "enabled") {
1030  $logParms = $parms["environment"]; // get the environment info passed in
1031  $logParms["token"] = ''; // the id used across all communications in session
1032  $logParms["txnId"] = time(); // the id for this transaction
1033  $logParms["logPoint"] = "ENSENTA_BRDC SSO"; // this action in a readable form
1034  $logParms["request"] = $cmd; // the request
1035  $logParms["reply"] = $ensenta; // the response
1036  LogSSOActivity($logParms);
1037  }
1038 
1039 
1040  if (trim($ensenta) == '' || preg_match("/Error=/i", "$ensenta")) {
1041  throw new Exception("Connection Failed ( $ensenta ) ");
1042  } else {
1043  header("Location: $ensenta");
1044  exit;
1045  }
1046  break;
1047 
1048  case "CHKFREE":
1049 #
1050 # 6/20/2018 MRH
1051 # updated some of the MIR processing to call a function
1052 # corrected the path for the include
1053 # needs work for the pop-up Terms-of-Service acceptance
1054 # and functions in CHKFREE.i return string 'true' / 'false' instead of
1055 # actual booleen true / false. Will need to fix that in the include, and here,
1056 # and possibly in hcuAppFeed.
1057 # Only one CHKFREE client (CVFCU) and they aren't converting yet
1058 # so pushing this one down the list.
1059 #
1060  require_once(dirname(__FILE__) . '/../library/CHKFREE.i');
1061  if (!hcu_checkService($dbh, "CHKFREE")) {
1062  $omsg = hcu_checkServiceMsg($dbh, "CHKFREE");
1063  throw new Exception("$omsg");
1064  }
1065  #
1066 # if member is accepting terms, post that response
1067  $option = $HB_ENV["HCUPOST"]["option"];
1068 
1069 
1070  if ($option == "ACCEPT") {
1071  $dms_ok = array('cu' => 'string', 'Flang' => 'string',
1072  'mode' => 'string', 'debug' => 'digits', 'option' => 'string',
1073  'notice_type' => 'string', 'notice_device' => 'string', 'notice_id' => 'string', 'notice_response' => 'array');
1074 
1075  dms_import_v2($HB_ENV, "HCUPOST", $dms_ok);
1076 
1077  $retStatus_ary = Update_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC']);
1078  # check $retStatus_ary for errors? Ignore failures anyway?
1079  #clear the option so it will fall through to show accounts
1080  $option = '';
1081  }
1082 #
1083 # see if member has accepted the terms yet...
1084 #
1085  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], "D", "ChkFreeSSO_TOS", true);
1086  if (sizeof($noticeInfo['notice']) && $noticeInfo['notice'][0]['notice_popup'] == 1 && strlen($noticeInfo['notice'][0]['notice_text']) > 0) {
1087  # showing the popup so set the accept button
1088  $continueButtonText = $noticeInfo['notice'][0]['notice_positive_caption'];
1089  $continueButtonText = (trim($continueButtonText) == '' ? $HB_ENV['MC']->msg("Accept") : $continueButtonText);
1090  // if the button needs to trigger a check of the radio buttons to make sure one selected, it must call CkRadio()
1091  $continueButton = "<div style=\"margin: 10px; text-align: center;\"><button type='button' class='k-button' name='btnContinue' onClick='javascript:document.formSelectAccount.submit();'>$continueButtonText</button></div>";
1092 
1093  $noticeText = $noticeInfo['notice'][0]['notice_text'] . "$continueButton";
1094 
1095  $inputList = array(
1096  array("name" => "mode", "value" => "$mode"),
1097  array("name" => "option", "value" => "ACCEPT"),
1098  array("name" => "notice_type", "value" => "{$noticeInfo['notice'][0]['notice_type']}"),
1099  array("name" => "notice_device", "value" => "D"),
1100  array("name" => "notice_id", "value" => "{$noticeInfo['notice'][0]['notice_id']}"),
1101  );
1102  if (count($noticeInfo['notice'][0]['notice_answers']) > 0) {
1103  foreach ($noticeInfo['notice'][0]['notice_answers'] as $notice_answer_key => $notice_answer_array) {
1104  $inputList[] = array("name" => "notice_response[]", "value" => "{$notice_answer_array['answer_id']}");
1105  }
1106  }
1107  $checkMsg = "Please accept the terms to continue.";
1108  $radioGroupName = "";
1109  ShowUserNotice($noticeText, $inputList, $radioGroupName, $checkMsg);
1110 
1111  break; #
1112  }
1113  # Member has seen / accepted terms so format a link to display them on demand
1114  $pageTtl = "CheckFree Pay Bills Terms";
1115  $noticeText = $noticeInfo['notice'][0]['notice_text'];
1116 
1117 // $HB_Form_Notices = Return_PopupDisplay($dbh, $HB_ENV, $HB_ENV['MC'], $noticeText, $pageTtl);
1118 # set billpayid as external password -
1119  $parms['passwith']['billpayid'] = (trim($mbrow['billpayid']) == '' ? $accountToUse : trim($mbrow['billpayid']));
1120  $parms['passwith']['Token'] = gmdate("U");
1121 
1122  #
1123  # get HomeCU checking accounts
1124  # check how many valid checking accounts are available.
1125  # if no funding, throw the bum out
1126  #
1127  $accts = Get_PrimaryChecking($dbh, $HB_ENV);
1128 
1129  if ($accts['status']['code'] != '000') {
1130  throw new Exception("No Valid Accounts for bill pay service");
1131  }
1132 
1133  if ($live) {
1134  $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
1135  } else {
1136  # batch interface will need to figure out how to get MIR info */
1137  $MIR["data"] = array();
1138 // $MIR["data"] = array(
1139 // 'accountnumber' => '000062458',
1140 // 'lastname' => 'Test',
1141 // 'firstname' => 'HomeCU',
1142 // 'email' => 'test@homecu.net',
1143 // 'ssn' => '123-23-1234',
1144 // 'dob' => '1950-01-06',
1145 // 'workphone' => '2083841311',
1146 // 'address1' => '3380 Americana Terr STE 390',
1147 // 'city' => 'Boise',
1148 // 'state' => 'ID',
1149 // 'zip' => '83706'
1150 // );
1151  }
1152  $reqMIR = array(
1153  'accountnumber' => 1,
1154  'firstname' => 1,
1155  'lastname' => 1,
1156  'email' => 1,
1157  'ssn' => 1,
1158  'dob' => 1,
1159  'phone' => 1,
1160  'address1' => 1,
1161  'city' => 1,
1162  'state' => 1,
1163  'zip' => 1
1164  );
1165 
1166  $parsedMIR = populateMIR($MIR['data'], $Ml, $reqMIR, 'Y-m-d', 'flat', true);
1167  if (!$parsedMIR['status']['response']) {
1168  throw new Exception($parsedMIR['status']['message']);
1169  }
1170  $parms['MIR'] = $parsedMIR;
1171  /*
1172  * getSubscriberInfo
1173  */
1174 
1175  $enroll = bpsmInfoSub($HB_ENV, $parms);
1176  if ($enroll['status']['response'] == 'false') {
1177  throw new Exception("Subscriber Get Info failed (" . print_r($enroll[status]['message'], true) . ")");
1178  }
1179  # CheckFree returns error 301 when subscriber (member) is not found
1180  # try to enroll
1181  if ($enroll['data']['Result']['ResultInfo']['Code'] == '301') {
1182  /*
1183  * enroll using Mir & 1st checking account
1184  */
1185  $parms['passwith']['payaccounts'][] = current($accts['dp']); # get first entry
1186 // $tfile = fopen ("/tmp/checkfree_sso","a");
1187 // fwrite ($tfile, "Size AcctList: " . sizeof($accts['dp']) . "\n" . print_r($accts,true) . "\n");
1188 // fwrite ($tfile, "Parms: " . print_r($parms,true) . "\n");
1189 // fclose ($tfile);
1190  $enroll = bpsmEnrollSub($HB_ENV, $parms);
1191 
1192  if ($enroll['status']['response'] == 'false') {
1193  throw new Exception("Member Enrollment failed ({$enroll[status]['message']})");
1194 // throw new Exception("Member Enrollment failed (enroll returns " . print_r($enroll,true) . ")");
1195  }
1196  /*
1197  * for each checking #2 - #n
1198  * addBankAccount
1199  */
1200 
1201  if (sizeof($accts['dp']) > 1) {
1202  $parms['rt'] = $HB_ENV['rt'];
1203  for ($i = 1; $i < sizeof($accts['dp']); $i++) {
1204  $acctrow = next($accts['dp']);
1205  foreach ($acctrow as $akey => $aval) {
1206  $parms["payacct{$akey}"] = $aval;
1207  }
1208  $parms['acctNumber'] = $acctrow['micraccount'];
1209  $parms['acctDescription'] = $acctrow['displaydesc'];
1210  $enroll = bpsmAddAcct($HB_ENV, $parms);
1211 
1212 // $tfile = fopen ("/tmp/checkfree_sso","a");
1213 // fwrite ($tfile, "Parms: " . print_r($parms,true) . "\n");
1214 // fwrite ($tfile, "Response: " . print_r($response,true) . "\n");
1215 // fclose ($tfile);
1216 
1217  if ($enroll['status']['response'] == 'false') {
1218  throw new Exception("Bank Account Add for {$acctrow['description']} failed ({$enroll[status]['message']})");
1219  }
1220  }
1221  }
1222  } else {
1223  switch ($enroll['data']['Subscriber']['Status']) {
1224  case 'Active':
1225  /*
1226  * if enrolled & active
1227  */
1228  $enroll = bpsmModifySub($HB_ENV, $parms);
1229  if ($enroll['status']['response'] == 'false') {
1230  throw new Exception("Subscriber Modify failed ({$enroll[status]['message']})");
1231  }
1232  break;
1233  /*
1234  * cu accounts rarely change - just update the subscriber info and leave
1235  * it at that. If we had to sync accounts, this is where we'd do it
1236  * getBankAccounts
1237  * for each HomeCU in getBankAccounts modifyAccount
1238  * for each getBankAccounts not in HomeCU inactivateAccount
1239  * for each HomeCU not in getBankAccounts addAccount
1240  */
1241 
1242  case "Inactive":
1243  case "FrozenFraud":
1244  case "FrozenOther":
1245  case "CancelledFraud":
1246  case "CancelledOther":
1247  case "Unspecified":
1248  default:
1249  /*
1250  * Account not active and didn't get the 301 Not Found error -
1251  * CU has presumably inactivated account, make 'em call for help
1252  */
1253  throw new Exception("Service Unavailable<br>Please contact the credit union.<br>(Subscriber status: {$enroll['data']['Subscriber']['Status']})");
1254 // throw new Exception("Subscriber Ineligible (" . print_r($enroll,true) . ")");
1255  break;
1256  }
1257  }
1258 
1259  # otherwise fall through to send login
1260 
1261  if ($parms['pilot'] == 1) {
1262  $ssourl = $parms['certsso_url'];
1263  $ssoiv = $parms['certsso_iv'];
1264  $ssokey = $parms['certsso_key1'];
1265  $ssokey .= $parms['certsso_key2'];
1266  $ssokey .= $parms['certsso_key3'];
1267  } else {
1268  $ssourl = $parms['prodsso_url'];
1269  $ssoiv = $parms['prodsso_iv'];
1270  $ssokey = $parms['prodsso_key1'];
1271  $ssokey .= $parms['prodsso_key2'];
1272  $ssokey .= $parms['prodsso_key3'];
1273  }
1274  $key = "";
1275  for ($i = 0; $i < strlen($ssokey); $i+=2) {
1276  $key .= chr(hexdec(substr($ssokey, $i, 2)));
1277  }
1278  $iv = "";
1279  for ($i = 0; $i < strlen($ssoiv); $i+=2) {
1280  $iv .= chr(hexdec(substr($ssoiv, $i, 2)));
1281  }
1282  $subscriber = substr("000000000{$parms['passwith']['billpayid']}", -9, 9);
1283  list($msec, $sec) = explode(" ", microtime());
1284  $floatsec = sprintf("%03d", (float) $msec * 1000);
1285  $ts = (gmdate("YmdHis")) . $floatsec;
1286  $digeststr = "ts=$ts&ss={$subscriber}&pw={$parms['billpaypw']}";
1287  #$digest = base64_encode(sha1("ss={$subscriber}&pw={$parms['billpaypw']}&ts=$ts", true));
1288  $digest = base64_encode(sha1("$digeststr", true));
1289  $ticket = "$digeststr&dg=$digest";
1290 
1291  # encrypt ticket
1292  if($use_openssl_encryption) {
1293  list($tktvalue, $ticket) = encrypt_ticket_openssl($ticket, $key, $iv);
1294  } else {
1295  list($tktvalue, $ticket) = encrypt_ticket_mcrypt($ticket, $key, $iv);
1296  }
1297 
1298  $href = "$ssourl?rq=getlogin&sp={$parms['SponsorID']}&ticket=$tktvalue&autoresume=y";
1299 # $tfile = fopen ("/tmp/checkfree_sso","a");
1300 # fwrite ($tfile, "Ticket: $ticket\nURL: $href\n");
1301 # fwrite ($tfile,"Key1: {$parms['prodsso_key1']}\n");
1302 # fwrite ($tfile,"Key2: {$parms['prodsso_key2']}\n");
1303 # fwrite ($tfile,"Key3: {$parms['prodsso_key3']}\n");
1304 # fwrite ($tfile, "key: $ssokey\niv: $ssoiv\n");
1305 # fwrite ($tfile, "Parms: " . print_r($parms, true) . "\n");
1306 # fclose ($tfile);
1307 
1308  break;
1309  case "PAYVERIS":
1310  /*
1311  * 6/20/2018 MRH
1312  * Should be able to update MIR packet processing as noted inline below,
1313  * but leaving it alone for now because PAYVERIS is already working on Odyssey
1314  * and we have a lot of SSOs that are not
1315  *
1316  */
1317  // NOTE: The flavor PVWIDGET is how navigation is handled:
1318  // With PAYVERIS, Payveris delivers navigation; with PVWIDGET, we set up the dashboards.
1319  // as of January 2018 Payveris always delivers navigation
1320  // as of June 2019 adding flavor PVUIR for newer Payveris update
1321 # beginning of case "PAYVERIS":
1322  /*
1323  * 6/20/2018 MRH
1324  * update MIR packet processing as noted inline below,
1325  */
1326  // NOTE: The flavor PVWIDGET is how navigation is handled:
1327  // With PAYVERIS, Payveris delivers navigation; with PVWIDGET, we set up the dashboards.
1328  // as of January 2018 Payveris always delivers navigation
1329  require_once('PAYVERIS_API.i');
1330  if (!hcu_checkService($dbh, "PAYVERIS")) {
1331  $omsg = hcu_checkServiceMsg($dbh, "PAYVERIS");
1332  throw new Exception("$omsg");
1333  }
1334 
1335  if (isset($parms['UserCodeSize']) && $parms['UserCodeSize'] > 0) {
1336  $billpayid = substr(str_repeat('0', $parms['UserCodeSize']) . $accountToUse, (-1 * $parms['UserCodeSize']), $parms['UserCodeSize']);
1337  } else {
1338  # default no padding for backward compatibility
1339  $billpayid = $accountToUse;
1340  }
1341  # set what we pass to the CreateUserSession call
1342  # if billpayid was defined in memberaccount table, use it
1343  # otherwise use accountToUse which has been formatted if requested by the trusted detail config
1344  $parms['passwith']['BillpayId'] = (trim($mbrow['billpayid']) == '' ? $billpayid : trim($mbrow['billpayid']));
1345  $parms['passwith']['rt'] = (trim($mbrow['rt']) == '' ? $accountToUse : trim($mbrow['rt']));
1346  $parms['passwith']['Cn'] = $accountToUse;
1347  $parms['passwith']['Cu'] = $Cu;
1348  $parms['passwith']['showavailable'] = ($HB_ENV['Fset'] & $CU_SHOWAVAILABLE);
1349  $parms['passwith']['lastupdate'] = $HB_ENV['lastupdate'];
1350 
1351  #
1352  # get HomeCU deposit accounts
1353  # check how many valid accounts are available.
1354  # if no funding, throw the bum out
1355  #
1356 
1357  $accts = PV_getHCUAccts($dbh, $parms);
1358 
1359  if ($accts['status']['code'] != '000' ||
1360  ( HCU_array_key_value('CheckingRequired',$parms) && !( HCU_array_key_value('CheckingAccounts',$accts["status"]) ) ) ){
1361  throw new Exception("No Valid Accounts for bill pay service");
1362  }
1363 
1364  if ($live) {
1365  $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
1366  } else {
1367  # batch interface will need to figure out how to get MIR info */
1368  $localMir = '{"accountnumber" : "000333",
1369  "lastname" : "TheGrouch",
1370  "firstname" : "Oscar",
1371  "email" : "test@homecu.net",
1372  "workphone" : "2083841311",
1373  "homephone" : "2083765555",
1374  "address1" : "100 Sesame Rd",
1375  "city" : "Langhorne",
1376  "state" : "PA",
1377  "zip" : "19047",
1378  "cc" : "USA"}';
1379  $MIR["data"] = array();
1380  $MIR["data"] = json_decode($localMir, TRUE);
1381  }
1382  $reqMIR = array(
1383  'accountnumber' => 1,
1384  'lastname' => 1,
1385  'firstname' => 1,
1386  'address1' => 1,
1387  'city' => 1,
1388  'state' => 1,
1389  'zip' => 1,
1390  'cc' => 1
1391  );
1392  $parsedMIR = PV_populateMIR($MIR['data'], $Ml, $reqMIR, 'Y-m-d', 'split', true);
1393  if (!$parsedMIR['status']['response']) {
1394  throw new Exception($parsedMIR['status']['message']);
1395  }
1396 
1397  $parms['MIR'] = $parsedMIR['data'];
1398 
1399 # populate $parms['passwith']['Accounts']
1400  $parms['passwith']['Accounts'] = $accts['dp'];
1401 
1402 # fall through to send login
1403 
1404  if ($parms['pilot_sso'] == 1) {
1405  $parms['serviceurl'] = $parms['piloturl'];
1406  $parms['APIKey'] = $parms['pilotAPIKey'];
1407  $parms['ClientCode'] = $parms['pilotClientCode'];
1408  } else {
1409  $parms['serviceurl'] = $parms['produrl'];
1410  $parms['APIKey'] = $parms['prodAPIKey'];
1411  $parms['ClientCode'] = $parms['prodClientCode'];
1412  }
1413 
1414 # call PV_CreateSession & parse result
1415  $session = PV_createUserSession($parms);
1416  if (empty($session['data']['ArtifactId'])) {
1417  throw new Exception("Connection to Payveris service Failed<br>Could not create session");
1418  }
1419  if ($parms['pilot_sso'] == 1) {
1420  $parms['serviceurl'] = $parms['pilotssourl'];
1421  } else {
1422  $parms['serviceurl'] = $parms['prodssourl'];
1423  }
1424 
1425  // check the flavor to know how to set things up
1426  $flavor = $HB_ENV['HCUPOST']['flavor'];
1427 
1428  // right now (11/03/17) there is just "flavor=PVWIDGET" or not
1429  // June 2019 adding flavor=PVUIR for Payveris update to UIR gui
1430 
1431  if ( $flavor == "" ) { # no usage w/o flavor on Odyssey
1432  $href = "{$parms['serviceurl']}/ShowDashboard?artifactId=" . $session['data']['ArtifactId'];
1433  # January 2018 Payveris says this sessionType parameter does not work
1434  # Specs v.6.6 dated April 2019 indicate it does. Sent email 6/18/19 asking for clarification
1435  # Dan Caruthers confirms it still doesn't work - documentation is bogus 6/18/2019
1436 // if ($HB_ENV['HCUPOST']['mblsession']) {
1437 // $href .= "&sessionType=mobile";
1438 // }
1439  } elseif ($flavor == 'PVUIR' || $flavor == 'PVWIDGET') {
1440 
1441  print <<<EOF
1442 <style>
1443 .payverisNav {
1444  margin:10px;
1445 }
1446 </style>
1447 
1448  <script type="text/javascript">
1449  function showPage(target) {
1450  var pv = document.getElementById("hcuPVframe"),
1451  action = '{$parms['serviceurl']}/' + target + '?artifactId={$session['data']['ArtifactId']}';
1452  pv.src = action;
1453  }
1454  </script>
1455 EOF;
1456  print "<script>\n";
1457  print "$(document).ready(function() {\n";
1458 
1459  print "showPage( 'ShowDashboard' );\n";
1460  print "});\n";
1461  print "</script>\n";
1462  $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
1463  if (stripos($ua, 'iPhone') !== false || stripos($ua, 'iPod') !== false || stripos($ua, 'iPad') !== false) {
1464  $divclass = ' class="appledevice"';
1465  } else {
1466  $divclass = '';
1467  }
1468  print '<div id="billpay-scroll-wrapper"' . $divclass . '>';
1469  if ( !$isapp ) {
1470  $linkText = 'Return to Accounts';
1471  print <<<EOF
1472  <button type='button' id='chooseDashboard' name='btnOLB' style='margin:6px' onclick="window.location='{$HB_ENV['loginpath']}/hcuAccounts.prg?{$HB_ENV['cuquery']}'" class="k-button"><span class="fa fa-arrow-left"></span>&nbsp;{$linkText}</button>
1473 EOF;
1474  }
1475  print '<iframe id="hcuPVframe" sandbox="allow-pointer-lock allow-popups allow-same-origin allow-top-navigation allow-scripts allow-forms"></iframe>';
1476  print '</div>';
1477  }
1478 # falls through to connect to SSO URL
1479  break;
1480 
1481  case "SavvyMo_SSO":
1482  require_once('SavvyMoney.i');
1483  if (!hcu_checkService($dbh, "SavvyMoney")) {
1484  $omsg = hcu_checkServiceMsg($dbh, "SavvyMoney");
1485  throw new Exception("$omsg");
1486  }
1487  # call to get redirect URL needs to know if we are mobile
1488  $parms['platform'] = $HB_ENV['platform'];
1489 
1490 # call smo_config to set configuration
1491  smo_config($dbh, $accountToUse, $mbrow['email'], $parms);
1492 
1493  $parms['MIR'] = smo_getMIR($HB_ENV, $accountToUse, HCU_array_key_value('beta', $parms));
1494 
1495 # call smo_getToken to authenticate and get a token
1496  $authToken = smo_getAuthorization($parms);
1497  if (HCU_array_key_exists('error', $authToken['token'])) {
1498  $message = HCU_array_key_value('status', $authToken['token']['error']);
1499  $message .= " " . HCU_array_key_value('message', $authToken['token']['error']);
1500  throw new Exception("Connection to SavvyMoney service Failed! $message");
1501  }
1502 
1503  $smoToken = HCU_array_key_value('authCode', $authToken['token']);
1504  if (empty($smoToken)) {
1505  throw new Exception("Connection to SavvyMoney service Failed! No access token");
1506  }
1507  $parms['authparms']['smoToken'] = $smoToken;
1508  $redirect = smo_getRedirect($parms);
1509  if (HCU_array_key_exists('error', $redirect['redirect'])) {
1510  $message = HCU_array_key_value('status', $redirect['redirect']['error']);
1511  $message .= " " . HCU_array_key_value('message', $redirect['redirect']['error']);
1512  throw new Exception("Connection to SavvyMoney service Failed! $message");
1513  }
1514  $parms['authparms']['smoAddress'] = HCU_array_key_value('redirectUrl', $redirect['redirect']);
1515  $parms['authparms']['accessToken'] = HCU_array_key_value('accessToken', $redirect['redirect']);
1516  if (empty($parms['authparms']['smoAddress']) || empty($parms['authparms']['accessToken'])) {
1517  throw new Exception("Connection to SavvyMoney service Failed! No Redirect Info");
1518  }
1519  header("Location: {$parms['authparms']['smoAddress']}");
1520 
1521  break;
1522 
1523 
1524  case "IPAY_V3":
1525  /*
1526  * Mammoth flow is:
1527  * if ENROLL, handle enrollment
1528  * else try to log in
1529  * if response has -100 code (not enrolled), pop up an enrollment message
1530  * if member confirms, post back with 'ENROLL' form variable
1531  *
1532  * For Odyssey, we are dropping the 'confirm enroll' so
1533  * try to log in
1534  * if response -100
1535  * quietly enroll and try the log in again
1536  */
1537 
1538  $omsg = 'The bill pay website will be down for maintenance between 9:00AM EST on Saturday, October 4th through 6:00AM EST on Monday, October 6th. If you still experience bill pay website issues after this timeframe, please call the phone number listed for bill pay related questions.';
1539 
1540  if (!hcu_checkService($dbh, "IPAY")) {
1541  $omsg = hcu_checkServiceMsg($dbh, "IPAY");
1542  throw new Exception("$omsg");
1543  }
1544  require_once('IPAY_V3.i');
1545 
1546  $ipay_instid = HCU_array_key_value('ipay_instid', $parms);
1547  $moc = HCU_array_key_value('moc', $parms);
1548  if ($moc) {
1549  $ipay_session = HCU_array_key_value('moc_session', $parms);
1550  $ipay_login = HCU_array_key_value('moc_login', $parms);
1551  $ipay_key = HCU_array_key_value('moc_key', $parms);
1552  } else {
1553  $ipay_session = HCU_array_key_value('prod_session', $parms);
1554  $ipay_login = HCU_array_key_value('prod_login', $parms);
1555  $ipay_key = HCU_array_key_value('prod_key', $parms);
1556  }
1557  $ipay_iv = HCU_array_key_value('hcu_iv', $parms);
1558 
1559  if (empty($ipay_instid) || empty($ipay_session) ||
1560  empty($ipay_login) || empty($ipay_key)) {
1561  throw new Exception($HB_ENV['MC']->msg("Feature Not Set"));
1562  }
1563 
1564 
1565  $billpayid = HCU_array_key_value('billpayid', $mbrow);
1566 
1567  if (trim($billpayid) == '') {
1568  $billpayid = $accountToUse;
1569  }
1570 
1571  # if billpayid is less than 2 chars, left pad w/zero
1572  if (strlen($billpayid) < 2) {
1573  $billpayid = substr("00$billpayid", -2, 2);
1574  }
1575  $rdate = gmdate("Ymd H:i:s");
1576  $random = gmdate("U");
1577  list($ipay_token, $iv) = EncryptCredentials("{$ipay_instid};{$rdate}", $ipay_key, $ipay_iv);
1578 
1579  $skip_company = (HCU_array_key_exists('skip_company', $parms) ? $parms['skip_company'] : 0);
1580 
1581  $ipayXML = iPay_getSession($ipay_instid, $ipay_iv, $ipay_session, $ipay_token, $Cu, $billpayid, $skip_company, $parms, $random);
1582 
1583  if (!($ipayXML['status'])) {
1584  throw new Exception("Login Connection failed ({$ipayXML['code']} {$ipayXML['message']})");
1585  }
1586 
1587  list ($ipaysuccess, $sessionID, $respcode, $respmsg) = GetReqResponse($ipayXML['message']);
1588 
1589  if ($respcode == '-100') {
1590  # this was the 'if enroll' block, but now we are just going to enroll without asking
1591  # if (HCU_array_key_value('option', $HB_ENV["HCUPOST"]) == "ENROLL") {
1592  # got here with option set to ENROLL
1593  # get token
1594  # send enrollment request
1595  if ($live) {
1596  $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
1597  if (! HCU_array_key_exists('code', $MIR) || ($MIR['code'] !== '000')) {
1598  throw new Exception("No Member Data (code)");
1599  }
1600  } else {
1601  # batch interface will need to figure out how to get MIR info */
1602  $MIR["data"] = array();
1603  // # testing, dummy up a batch MIR
1604  // $MIR['data'] = ['accountnumber' => $accountToUse,
1605  // 'firstname' => 'Kevin', 'middlename' => 'O','lastname' => 'Williams',
1606  // 'email' => 'youngson@yahoo.com', 'homephone' => '208-555-0228',
1607  // 'workphone' => '', 'cellphone' => '', 'fax' => '', 'ssn' => '228-22-8228',
1608  // 'address1' => '373 Richland Ave', 'address2' => '',
1609  // 'city' => 'Shire', 'state' => 'ID', 'zip' => '83111', 'cc' => 'US',
1610  // 'dob' => '1991-02-28', 'class' => 'P'];
1611  }
1612  if (!HCU_array_key_exists('accountnumber', $MIR['data'])) {
1613  throw new Exception("No Member Data (account number)");
1614  }
1615  /**
1616  * Moved this code up a little so the code to be feature-gated
1617  * is all in one block
1618  */
1619 
1620  // make sure the member has at least 1 checking account with a MICR
1621  // 08-19: Only need MICR if EnrollMICR = 1
1622 
1623  $enrollmicr = (integer) HCU_array_key_value('EnrollMICR', $parms);
1624  $paymentAccts = iPay_getHCUAccounts($dbh, $HB_ENV, $accountToUse, $enrollmicr);
1625 
1626  if (!$paymentAccts['status']['response']) {
1627  throw new Exception($paymentAccts['status']['message']);
1628  }
1629  /** end moved block */
1630 
1631  /**
1632  * Start Feature Gate block
1633  */
1634 
1635  $config = FeatureGateConfig::GetInstance($dbh);
1636  $MIRGate = new CreditUnionGate(CreditUnionGate::MIR_HANDLER, $config);
1637  if ($MIRGate->WillPass($HB_ENV['Cu'],['username' => $HB_ENV['Cn']])) {
1638  /**
1639  * use this new method if feature gate is open
1640  */
1641 
1642  # Moving function parameters into arrays to simplify test-ability
1643  #
1644  # move ipay settings and config into IPAYcred array
1645  # from cutrusted detail [ipay_instid, ipay_iv, ipay_key, enrollmicr] and connection dependencies [ipay_token, random]
1646  # move HomeCU settings into HCUcred array
1647  # from selected user and account settings [ml, billpayid, micr]
1648  #
1649  $IPAYcred = ['ipay_instid' => $ipay_instid,
1650  'ipay_iv' => $ipay_iv,
1651  'ipay_key' => $ipay_key,
1652  'ipay_token' => $ipay_token,
1653  'random' => $random,
1654  'enrollmicr' => $enrollmicr
1655  ];
1656  $HCUcred = ['billpayid' => $billpayid,
1657  'ml' => $mbrow['email'],
1658  'micr' => $paymentAccts['data'][0]['micr']?? null
1659  ];
1660 
1661  $enroll = iPayV3EnrollXML($MIR, $IPAYcred, $HCUcred);
1662 
1663  if (!$enroll['status']) {
1664  throw new Exception($enroll['message']);
1665  }
1666  $enroll = $enroll['data'];
1667 
1668  } else {
1669 
1670  /**
1671  * use this legacy method if feature gate is closed
1672  */
1673  # identify the required elements expected in the MIR
1674  $reqMIR = array(
1675  "accountnumber" => 1,
1676  "firstname" => 1,
1677  "lastname" => 1,
1678  "address1" => 1,
1679  "city" => 1,
1680  "state" => 1,
1681  "zip" => 1
1682  );
1683 
1684  $parsedMIR = populateMIR($MIR['data'], $HB_ENV['Ml'], $reqMIR, 'mdY', 'flat', false);
1685  if (!$parsedMIR['status']['response']) {
1686  throw new Exception($parsedMIR['status']['message']);
1687  }
1688  $enroll = iPayEnrollXML($HB_ENV, $MIR, $ipay_instid, $ipay_iv, $ipay_key, $ipay_token, $random, $billpayid, $mbrow['email'], $enrollmicr, $paymentAccts['data'][0]['micr']?? null);
1689  }
1690  /**
1691  * End Feature Gate block
1692  */
1693 
1694  /**
1695  * check $enroll before we try to use it...
1696  */
1697  if (empty($enroll)) {
1698  throw new Exception('Failed building enrollment request');
1699  }
1700 
1701  # only difference between ipay_enroll and ipay_session was the the leading 'm' of messaging and messagehandler was capitalized. Trying with ipay_sesion to see if that works
1702  $cmd = "/usr/bin/curl --silent --request POST --data-binary '$enroll' -H 'Content-type: application/xml' '{$ipay_session}'";
1703 // $ipayXML = getcurl($cmd);
1704  $ipayHeaders = array();
1705  $ipayHeaders[] = "Content-type: application/xml";
1706 
1707  $parms["environment"]["logPoint"] = "V3_Enroll"; // this action in a readable form
1708  $parms["environment"]["request"] = "{$cmd}"; // the request
1709  $ipayXML = iPayEmbcurl($enroll, $ipayHeaders, $ipay_session, '', '', '', $parms);
1710  if (!($ipayXML['status'])) {
1711  throw new Exception("Enrollment Connection failed ({$ipayXML['code']} {$ipayXML['message']})");
1712  }
1713 
1714  list ($ipaysuccess, $respcode, $respmsg) = GetEnrollResponse($ipayXML['message']);
1715 
1716  # if not successfull show error and bail
1717  if ($ipaysuccess == 'false') {
1718  throw new Exception("Member Enrollment failed ($respcode $respmsg)");
1719  }
1720  # and try again to login now that we are enrolled
1721  #}
1722  $ipayXML = iPay_getSession($ipay_instid, $ipay_iv, $ipay_session, $ipay_token, $Cu, $billpayid, $skip_company, $parms, $random);
1723  if (!($ipayXML['status'])) {
1724  throw new Exception("Login Connection failed ({$ipayXML['code']} {$ipayXML['message']})");
1725  }
1726 
1727  list ($ipaysuccess, $sessionID, $respcode, $respmsg) = GetReqResponse($ipayXML['message']);
1728  if ($respcode == '-100') {
1729  # if we get a second 'must enroll' response, throw an error.
1730  throw new Exception("No Bill Pay Token after enroll");
1731  }
1732 
1733  }
1734  if ($sessionID == '' || preg_match("/\D/", "$sessionID")) {
1735  throw new Exception("No Bill Pay Token");
1736  } else {
1737 
1738  #print "This would login to {$ipay_login}?instid=$ipay_instid<BR>
1739  #using<br>
1740  #name='p1' value='$sessionID'<BR>
1741  #name='op' value='Login'<BR>
1742  #name='Method' value='Session'"; exit;
1743  # redirect to login URL
1744  $stremail = ("{$HB_ENV["Ml"]}" == "" ? "" : "<input type='hidden' name='strEmail' value='{$HB_ENV["Ml"]}'>");
1745  $request = "Onload post form with action = {$ipay_login}?instid=$ipay_instid\np1=$sessionID\nop=Login\nMethod=Session";
1746  $request .= "{$HB_ENV["Ml"]}" == "" ? "" : "\nstrEmail={$HB_ENV["Ml"]}\n";
1747 
1748  if ($parms["logging"] == "enabled") {
1749  $logParms = $parms["environment"]; // get the environment info passed in
1750  $logParms["token"] = ''; // the id used across all communications in session
1751  $logParms["txnId"] = time(); // the id for this transaction
1752  $logParms["logPoint"] = "V3 SSO"; // this action in a readable form
1753  $logParms["request"] = "$request"; // the request
1754  $logParms["reply"] = ''; // the response
1755  LogSSOActivity($logParms);
1756  }
1757 
1758 
1759  print <<<EOF
1760  <html>
1761  <body onload="javascript:document.SSOform.submit();">
1762  <form method="post" name="SSOform" action="{$ipay_login}?instid=$ipay_instid">
1763  <input type="hidden" name="p1" value="$sessionID">
1764  <input type="hidden" name="op" value="Login">
1765  <input type="hidden" name="Method" value="Session">
1766  $stremail
1767  </form>
1768  </body>
1769  </html>
1770 EOF;
1771  }
1772 
1773  break;
1774 
1775  case "PSCUPAY_SSO":
1776  if (!hcu_checkService($dbh, "PSCU")) {
1777  $omsg = hcu_checkServiceMsg($dbh, "PSCU");
1778  throw new Exception("$omsg");
1779  }
1780 
1781  $continueSignon = true;
1782  if ($HB_ENV["HCUPOST"]["option"] != 'SPEEDBUMP') {
1783  $saywhat = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'bpPSCUNotice');
1784 // $p = print_r($saywhat,true);
1785 // print "Saywhat: $p";exit;
1786  // Check if speedbump notice exists. Note that the notice_popup field is use to signify if showing it
1787  // because the text will always be returned.
1788  if (sizeof($saywhat['notice']) && strlen($saywhat['notice'][0]['notice_text']) > 0 &&
1789  $saywhat["notice"][0]["notice_popup"] == 1) {
1790  $descTtl = "";
1791  $pageTtl = $HB_ENV['MC']->msg("Terms of Use");
1792 
1793  $pscuNoticeText = "<div style='text-align:left; background-color:white; border-radius:4px; margin: 0px 10px 5px 10px; padding: 5px;'>
1794  <fieldset>
1795  {$saywhat['notice'][0]['notice_text']}
1796  </fieldset>
1797  </div>";
1798 
1799  $noticeArray = $saywhat["notice"][0];
1800  $noticeAnswers = "";
1801  $noticeType = ($noticeArray['notice_answertype'] == 'O' ? 'radio' : 'checkbox');
1802  if (count($noticeArray['notice_answers']) > 0) {
1803  foreach ($noticeArray['notice_answers'] as $notice_answer_key => $notice_answer_array) {
1804  $noticeAnswers .="<input type='{$noticeType}' name='notice_response[]' id='response{$notice_answer_array['answer_id']}' value='{$notice_answer_array['answer_id']}'/><label for='response{$notice_answer_array['answer_id']}'>{$notice_answer_array['answer_text']}</label>";
1805  }
1806  }
1807  // note: the notice answers are from the bpPSCUNotice, as that is what is being accepted
1808  $noticeAnswers = "<div style='text-align:center'>
1809  <fieldset>
1810  {$noticeAnswers}
1811  </fieldset>
1812  </div>";
1813 
1814  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Cancel")}</button>";
1815  $continueButtonText = $noticeArray["notice_positive_caption"];
1816  // if the button needs to trigger a check of the radio buttons to make sure one selected, it must call CkRadio()
1817  $continueButton = "<button type='submit' class='k-button' name='btnContinue'>$continueButtonText</button>";
1818  $buttons = "{$cancelButton} &nbsp; &nbsp; {$continueButton}";
1819 
1820  // set up the string substitution
1821  $noticeSubstitution = array(
1822  "#page_title#" => $pageTtl,
1823  "#description#" => $descTtl,
1824  "#content#" => $pscuNoticeText,
1825  "#acceptance#" => $noticeAnswers,
1826  "#buttons#" => $buttons
1827  );
1828 
1829  // get any notice text
1830  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
1831  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectSpeedbump');
1832 
1833  // make sure we got the notice
1834  if ($noticeInfo["status"]["code"] != "000" ||
1835  !count($noticeInfo["notice"]) ||
1836  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
1837  throw new Exception("Configuration Error: Custom Content (ConnectSpeedbump)");
1838  }
1839 
1840  $noticeText = $noticeInfo['notice'][0]['notice_text'];
1841 
1842  $inputList = array(array("name" => "mode", "value" => "$mode"),
1843  array("name" => "notice_type", "value" => "{$noticeArray['notice_type']}"),
1844  array("name" => "notice_id", "value" => "{$noticeArray['notice_id']}"),
1845  array("name" => "notice_device", "value" => "C"),
1846  array("name" => "option", "value" => "SPEEDBUMP")
1847  );
1848  $checkMsg = "";
1849  $radioGroupName = "";
1850  ShowUserNotice($noticeText, $inputList, $radioGroupName, $checkMsg);
1851 // Speedbump($saywhat);
1852  $continueSignon = false;
1853  }
1854  } else {
1855  $dms_ok = Array("cu" => "string", "Flang" => "string", "notice_type" => "string",
1856  "notice_id" => "string", "notice_device" => "string",
1857  "notice_response" => "array");
1858 
1859  dms_import_v2($HB_ENV, 'HCUPOST', $dms_ok);
1860 
1861  if (sizeof($HB_ENV['HCUPOST']['notice_response'])) {
1862  $retStatus_ary = Update_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC']);
1863  # check $retStatus_ary for errors? Ignore failures anyway?
1864  }
1865  }
1866 
1867  if ($continueSignon) {
1868  $cuid = HCU_array_key_value('cuid', $parms);
1869  $pilot = HCU_array_key_value('pilot', $parms);
1870  $rtno = HCU_array_key_value('rtno', $parms);
1871  $sendbal = HCU_array_key_value('sendbal', $parms); # send account balance to PSCU?
1872  $sendjoint = HCU_array_key_value('sendjoint', $parms); # send joint accounts (with @ in suffix) to PSCU?
1873  $sendextended = HCU_array_key_value('sendextended', $parms);
1874  if ($pilot) {
1875  $url = HCU_array_key_value('piloturl', $parms);
1876  } else {
1877  $url = HCU_array_key_value('produrl', $parms);
1878  }
1879  if (empty($cuid) || empty($url) || empty($rtno) || empty($accountToUse) ) {
1880  throw new Exception("Missing Settings");
1881  }
1882 
1883  if ($sendextended) {
1884 
1885  if ($live) {
1886  $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
1887  } else {
1888  # batch interface will need to figure out how to get MIR info */
1889  $MIR["data"] = array();
1890 
1891  # testing only - load mir info from file
1892  /*
1893  $mirname = "/home/ubuntu/miki/packet.mir.{$Cn}";
1894  if (!is_readable($mirname))
1895  $mirname = "/home/ubuntu/miki/packet.mir.anon";
1896  $packet = file_get_contents($mirname);
1897  $status = (preg_match("/<status>\n?(.*)\n?<\/status>/si", $packet, $pktpieces) ? $pktpieces[1] : "");
1898  list($mem, $statcode, $statdesc) = explode("\t", $status);
1899 
1900  preg_match("/<info>\n?(.*)<\/info>/si", $packet, $pktpieces);
1901  $info = explode("\n", $pktpieces[1]);
1902  $line = $info[0];
1903  $line = preg_replace("/ ?\t ?/", "\t", $line);
1904  $line = preg_replace("/ $/", "", $line);
1905  $line = preg_replace("/\\0/", " ", $line);
1906  list($AccountNumber, $FirstName, $MiddleName, $LastName, $Email, $HomePhone, $WorkPhone, $CellPhone, $Fax, $SSN, $Address1, $Address2, $City, $State, $Zip, $CC, $DOB) = explode("\t", $line);
1907 
1908  $MIR[status][status] = $statcode;
1909  $MIR[status][asofdate] = date("D M j Y H:i:s T");
1910  $MIR[status][reason] = $statdesc;
1911 
1912  $MIR["data"]['AccountNumber'] = $AccountNumber;
1913  $MIR["data"]['firstname'] = $FirstName;
1914  $MIR["data"]['middlename'] = $MiddleName;
1915  $MIR["data"]['lastname'] = $LastName;
1916  $MIR["data"]['email'] = $Email;
1917  $MIR["data"]['homephone'] = $HomePhone;
1918  $MIR["data"]['workphone'] = $WorkPhone;
1919  $MIR["data"]['cellphone'] = $CellPhone;
1920  $MIR["data"]['Fax'] = $Fax;
1921  $MIR["data"]['ssn'] = $SSN;
1922  $MIR["data"]['address1'] = $Address1;
1923  $MIR["data"]['address2'] = $Address2;
1924  $MIR["data"]['city'] = $City;
1925  $MIR["data"]['state'] = $State;
1926  $MIR["data"]['zip'] = $Zip;
1927  $MIR["data"]['cc'] = $CC;
1928  $MIR["data"]['dob'] = $DOB;
1929  print_r( $MIR );
1930  *
1931  */
1932  # end of testing
1933  }
1934  $reqMIR = array(
1935  "accountnumber" => 1,
1936  "lastname" => 1,
1937  "email" => 1,
1938  "ssn" => 1,
1939  "dob" => 1,
1940  "phone" => 1,
1941  "zip" => 1
1942  );
1943 
1944  $parsedMIR = populateMIR($MIR['data'], $HB_ENV['Ml'], $reqMIR, 'mdY', 'flat', false);
1945  if (!$parsedMIR['status']['response']) {
1946  throw new Exception($parsedMIR['status']['message']);
1947  }
1948  $EMAIL = ((empty($parsedMIR['data']['email']) || !validateEmail($parsedMIR['data']['email'])) ? $mbrow['email'] : $parsedMIR['data']['email']);
1949 
1950  } else {
1951 
1952  $EMAIL = $mbrow[email];
1953  $rmlist = array("#", "&", "/", "%", ",", ":", "=", "?", "'");
1954  $EMAIL = str_replace($rmlist, "", $EMAIL);
1955 
1956  }
1957  $paymentAccts = PSCU_getHCUAccounts($dbh, $HB_ENV, $accountToUse, $parms);
1958  if (!$paymentAccts['status']['response']) {
1959  throw new Exception($paymentAccts['status']['message']);
1960  }
1961 
1962  $unl = substr("000000000$accountToUse", -9, 9);
1963 
1964  $query = "&RQID=SINGLESIGNON&APPLICATION=PLE&MEMBERTYPE=9&ORGID=$cuid&USERNAMEL=$unl";
1965  if ($sendextended) {
1966  $query .= "&TAXID={$parsedMIR['data']['ssn']}";
1967  $query .= "&FIRSTNAME=" . urlencode(substr($parsedMIR["data"]["firstname"],0,32));
1968  $query .= "&LASTNAME=" . urlencode(substr($parsedMIR["data"]["lastname"],0,32));
1969  $query .= "&DOB={$parsedMIR['data']['dob']}";
1970  $query .= "&PHONENUMBER={$parsedMIR['data']['phone']}";
1971  $query .= "&ADDRESSLINE1=" . urlencode(substr($parsedMIR["data"]["address1"],0,32));
1972  if (trim($MIR["data"]["address2"]) <> '') {
1973  $query .= "&ADDRESSLINE2=" . urlencode(substr($parsedMIR["data"]["address2"],0,32));
1974  }
1975  $query .= "&CITY=" . urlencode(substr($parsedMIR["data"]["city"],0,32));
1976  $query .= "&STATE={$parsedMIR["data"]["state"]}";
1977  $query .= "&ZIP={$parsedMIR['data']['zip']}";
1978  if (empty($parsedMIR["data"]["firstname"])) {
1979  $query .= "&MISC1=CV_BUS_TO_NAME";
1980  }
1981  }
1982  $query .= "&EMAILADDRESS={$EMAIL}";
1983 
1984  $rmlist = array("#", "&", "/", "%", ",", ":", "=", "?", "'");
1985 
1986  foreach ($paymentAccts['data'] as $key => $row ) {
1987  if ($key == 7) {
1988  break;
1989  } # only 7 accounts acceptable at PSCU
1990  $qid = $key + 1;
1991  $desc = str_replace($rmlist, "", $row['description']);
1992  $desc = substr(urlencode($desc), 0, 30);
1993  if (substr($desc, 28, 1) == '%' || substr($desc, 29, 1) == '%') {
1994  $desc = substr($desc, 0, strrpos($desc, '%'));
1995  }
1996 
1997  $query .= "&BANK_RTN{$qid}=$rtno&ACCOUNTID{$qid}={$row['micr']}&ACCTDESC{$qid}=$desc";
1998  // urlencode(substr($desc,0,30));
1999  if ($sendbal) {
2000  # available is currency, should have to trim?
2001  $query .= "&BAL{$qid}=" . trim($row['available']);
2002  }
2003  }
2004 #
2005  $curlopts = array(
2006  CURLOPT_RETURNTRANSFER => 1,
2007  CURLOPT_SSL_VERIFYPEER => 0,
2008  CURLOPT_SSL_VERIFYHOST => 0,
2009  CURLOPT_HEADER => 0,
2010  CURLOPT_URL => "{$url}{$query}");
2011 
2012  $ch = @curl_init();
2013  @curl_setopt_array($ch, $curlopts);
2014 
2015  $infosession = @curl_exec($ch);
2016  $responseIP = curl_getinfo($ch,CURLINFO_PRIMARY_IP);
2017  if ( $parms["logging"] == "enabled" ) {
2018  $logParms = $parms["environment"]; // get the environment info passed in
2019  $logParms["token"] = ''; // the id used across all communications in session
2020  $logParms["txnId"] = time(); // the id for this transaction
2021  $logParms["SSOVendor"] = 'PSCUPAY_SSO';
2022  $logParms["logPoint"] = "PSCUPAY SSO"; // this action in a readable form
2023  $logParms["request"] = "{$url}{$query}"; // the request
2024  $logParms["reply"] = "$responseIP responded \n$infosession"; // the response
2025  LogSSOActivity( $logParms );
2026  }
2027 
2028  if (empty($infosession)) {
2029  throw new Exception("Connection to PSCU PayLynx service Failed<br>Error: No Response");
2030  } else {
2031 
2032  libxml_use_internal_errors(true);
2033  $xml = simplexml_load_string($infosession);
2034  if (!is_object($xml)) {
2035  libxml_clear_errors();
2036  throw new Exception("Connection to PSCU PayLynx service Failed<br>Error: XML parse failed");
2037  }
2038  $xmlx = $xml->xpath("FUNCTIONRS/STATUS/COMPLETION");
2039  $pscustat = $xmlx[0];
2040  $xmlx = $xml->xpath("FUNCTIONRS/STATUS/COMPLETIONSCRIPT");
2041  $pscudesc = $xmlx[0];
2042 
2043  # preg_match('/<COMPLETION>(.*)<\/COMPLETION>/',$infosession,$stat);
2044  # $pscustat = $stat[1];
2045  # preg_match('/<COMPLETIONSCRIPT>(.*)<\/COMPLETIONSCRIPT>/',$infosession,$stat);
2046  # $pscudesc = $stat[1];
2047  # print "Stat :$pscustat: Desc :$pscudesc:<br>$infosession";
2048  if ($pscustat <> '100') {
2049  throw new Exception("Connection to PSCU PayLynx service Failed<br>Error: $pscustat $pscudesc");
2050  } else {
2051  preg_match('/<URL>(.*)<\/URL>/', $infosession, $stat);
2052  $href = html_entity_decode($stat[1]);
2053  }
2054  }
2055  }
2056 
2057  break;
2058  case "PSCUINFO":
2059 // # PSCUINFO is obsolete. Use AccessPoint PSCU_ACCPT instead
2060 // trusted detail had these parameters:
2061 // OrgID 3274
2062 // pilot 0
2063 // piloturl https://pilot.epscu.com/servlet/raAppHtml?ServicePageName=com.invisiondev.JServer.xml.pscu.xmlLoginProxy&RQID=FUNCTIONRSURL&APPLICATION=ICC
2064 // produrl https://www.epscu.com/servlet/raAppHtml?ServicePageName=com.invisiondev.JServer.xml.pscu.xmlLoginProxy&RQID=FUNCTIONRSURL&APPLICATION=ICC
2065 // hcuLogging -1
2066 
2067  if (!hcu_checkService($dbh, "PSCU")) {
2068  $omsg = hcu_checkServiceMsg($dbh, "PSCU");
2069  throw new Exception("$omsg");
2070  exit;
2071  }
2072  # PSCU InfoLink Credit Card Info
2073  $pilot = HCU_array_key_value('pilot', $parms);
2074  $OrgID = HCU_array_key_value('OrgID', $parms);
2075 
2076  if ($pilot) {
2077  $url = HCU_array_key_value('piloturl', $parms);
2078  } else {
2079  $url = HCU_array_key_value('produrl', $parms);
2080  }
2081  if (empty($OrgID) || empty($url) || empty($accountToUse) ) {
2082  throw new Exception("Missing Settings");
2083  }
2084 
2085  $infosession = file_get_contents("{$url}&ORGID=$OrgID&USERNAMEL=$accountToUse");
2086 
2087  if ($parms["logging"] == "enabled") {
2088  $logParms = $parms["environment"]; // get the environment info passed in
2089  $logParms["SSOVendor"] = 'PSCU';
2090  $logParms["logPoint"] = "$mode SSO"; // this action in a readable form
2091  $logParms["token"] = ''; // the id used across all communications in session
2092  $logParms["txnId"] = time(); // the id for this transaction
2093  $logParms["request"] = "{$url}&ORGID=$OrgID&USERNAMEL=$accountToUse"; // the request
2094  $logParms["reply"] = "$infosession"; // the response
2095  LogSSOActivity($logParms);
2096  }
2097 
2098  if ($infosession == '' || preg_match("/^Error/i", "$infosession")) {
2099  throw new Exception("Connection to PSCU InfoLink service Failed $infosession");
2100  } else {
2101  $href = trim($infosession);
2102  }
2103  break;
2104 
2105  case "PSCU_ACCPT":
2106  if (!hcu_checkService($dbh, "PSCU")) {
2107  $omsg = hcu_checkServiceMsg($dbh, "PSCU");
2108  throw new Exception("$omsg");
2109  }
2110 
2111  $pilot = HCU_array_key_value('pilot', $parms);
2112  $cuid = HCU_array_key_value('cuid', $parms);
2113 
2114  if ($pilot) {
2115  $svs_url = HCU_array_key_value('piloturl', $parms);
2116  } else {
2117  $svs_url = HCU_array_key_value('produrl', $parms);
2118  }
2119  if (empty($cuid) || empty($svs_url) || empty($accountToUse) ) {
2120  throw new Exception("Missing Settings");
2121  }
2122 
2123  $unl = substr("000000000$accountToUse", -9, 9);
2124 
2125  $query = "-d RQID=FUNCTIONRS -d ORGID=$cuid -d USERNAMEL=$unl";
2126 
2127  $cmd = "/usr/bin/curl --silent --request POST $query '$svs_url'";
2128  // comment out next line and ........
2129 // $infosession = getcurl($cmd);
2130 
2131  // .... and enable next block to use embedded curl and enhanced logging
2132  $query = "RQID=FUNCTIONRS&ORGID=$cuid&USERNAMEL=$unl";
2133 
2134  $curlopts = array(
2135  CURLOPT_RETURNTRANSFER => 1,
2136  CURLOPT_SSL_VERIFYPEER => 0,
2137  CURLOPT_SSL_VERIFYHOST => 0,
2138  CURLOPT_POST => 1,
2139  CURLOPT_POSTFIELDS => $query,
2140  CURLOPT_HEADER => 0,
2141  CURLOPT_URL => "$svs_url");
2142 
2143  $ch = @curl_init();
2144  @curl_setopt_array($ch, $curlopts);
2145 
2146  $infosession = @curl_exec($ch);
2147  $responseIP = curl_getinfo($ch, CURLINFO_PRIMARY_IP);
2148 
2149  if (curl_errno($ch)) {
2150  $infosession = '';
2151  $curlerror = curl_error($ch);
2152  } else {
2153  $curlerror = '';
2154  }
2155  @curl_close($ch);
2156 
2157  if ($parms["logging"] == "enabled") {
2158  $logParms = $parms["environment"]; // get the environment info passed in
2159  $logParms["SSOVendor"] = 'PSCU';
2160  $logParms["logPoint"] = "$mode SSO"; // this action in a readable form
2161  $logParms["token"] = ''; // the id used across all communications in session
2162  $logParms["txnId"] = time(); // the id for this transaction
2163  $logParms["request"] = "$cmd"; // the request
2164 // $logParms["reply"] = "$responseIP responded \n$infosession"; // the response
2165  $logParms["reply"] = "$infosession"; // the response
2166  LogSSOActivity($logParms);
2167  }
2168 
2169  if (empty($infosession)) {
2170  throw new Exception("Connection to PSCU AccessPoint service Failed $curlerror");
2171  } else {
2172  libxml_use_internal_errors(true);
2173  $xml = simplexml_load_string($infosession);
2174  if (!is_object($xml)) {
2175  libxml_clear_errors();
2176  throw new Exception("Connection to PSCU AccessPoint service Failed<br>Error: XML parse failed");
2177  }
2178  $xmlx = $xml->xpath("FUNCTIONRS/STATUS/COMPLETION");
2179  $pscustat = $xmlx[0];
2180  $xmlx = $xml->xpath("FUNCTIONRS/STATUS/COMPLETIONSCRIPT");
2181  $pscudesc = $xmlx[0];
2182 
2183  #print "Stat :$pscustat: Desc :$pscudesc:<br>$infosession";
2184  if ($pscustat <> '100') {
2185  $error["content"] = "Connection to PSCU AccessPoint service Failed<br>Error: $pscustat $pscudesc";
2186  throw new Exception(json_encode($error));
2187  } else {
2188  preg_match('/<URL>(.*)<\/URL>/', $infosession, $stat);
2189  $href = html_entity_decode($stat[1]);
2190  }
2191  }
2192 
2193  break;
2194 
2195  case "MemberPay":
2196  if (!hcu_checkService($dbh, "MemberPay")) {
2197  $omsg = hcu_checkServiceMsg($dbh, "MemberPay");
2198  throw new Exception("$omsg");
2199  }
2200  $bp_cuid = $parms['CorpID'];
2201  $bp_secret = $parms['password'];
2202  $pilot = $parms['pilot'];
2203 
2204  $rt = $HB_ENV['rt'];
2205 
2206  if ("$rt" == "" || preg_match("/\D/", $rt)) {
2207  throw new Exception($HB_ENV['MC']->msg("Feature Not Set"));
2208  }
2209 
2210  if ($pilot) {
2211  $server = $parms["pilotURL"]; // 'https://staging1.memberpay.com/MemberBillPay/SingleSignOn.asmx';
2212  $mpaysvc = $parms["mpaypilot"]; //"https://staging1.memberpay.com/MemberBillPay/singlesignonrequest.aspx";
2213  } else {
2214  $server = $parms["serviceURL"]; // 'https://www.memberpay.com/MemberBillPay/SingleSignOn.asmx';
2215  $mpaysvc = $parms["mpaysvc"]; // "https://www.memberpay.com/MemberBillPay/singlesignonrequest.aspx";
2216  }
2217 
2218  $billpayid = $mbrow['billpayid'];
2219  if (trim($billpayid) == '') {
2220  $billpayid = $accountToUse;
2221  }
2222 
2223  $request = "&lt;SSORequest version=\"1.0\"&gt;\n";
2224  $request .= "&lt;MemberID&gt;{$billpayid}&lt;/MemberID&gt;\n";
2225  $request .= "&lt;CorpID&gt;{$bp_cuid}&lt;/CorpID&gt;\n";
2226  $request .= "&lt;RoutingNumber&gt;{$rt}&lt;/RoutingNumber&gt;\n";
2227  $request .= "&lt;Password&gt;{$bp_secret}&lt;/Password&gt;&lt;/SSORequest&gt;\n";
2228 
2229  $soapString = '<?xml version="1.0" encoding="utf-8"?>';
2230  $soapString .= "\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n";
2231  $soapString .= "<soap:Body>\n";
2232  $soapString .= "<AuthenticateMember xmlns=\"http://tempuri.org/\">\n";
2233  $soapString .= "<request>\n" . $request . "</request>\n";
2234  $soapString .= "</AuthenticateMember>\n";
2235  $soapString .= "</soap:Body>\n";
2236  $soapString .= "</soap:Envelope>\n";
2237 
2238  #$cmd="/usr/bin/curl --silent --data-binary '$soapString' -H 'Content-Type: text/xml; charset=utf-8' -H 'SOAPAction: \"http://tempuri.org/AuthenticateMember\"' $server";
2239 
2240  $curlopts = array(
2241  CURLOPT_RETURNTRANSFER => 1,
2242  CURLOPT_SSL_VERIFYPEER => 0,
2243  CURLOPT_SSL_VERIFYHOST => 0,
2244  CURLOPT_POST => 1,
2245  CURLOPT_POSTFIELDS => "$soapString",
2246  CURLOPT_URL => "$server");
2247 
2248  $header = array();
2249  $header[] = "Content-Type: text/xml; charset=utf-8";
2250  $header[] = 'SOAPAction: "http://tempuri.org/AuthenticateMember"';
2251 
2252  $response = "";
2253  $ch = curl_init();
2254  if ($ch) {
2255  curl_setopt_array($ch, $curlopts);
2256  curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
2257  $response = curl_exec($ch);
2258  curl_close($ch);
2259  }
2260 
2261  $mpaystat = "999"; # set a 'connection failed' status first
2262  $mpaydesc = "Connection Failed"; # set a 'connection failed' status first
2263 
2264  if ($response > '') {
2265  #print "<pre>$response</pre>";
2266  #exit;
2267  $response = html_entity_decode($response);
2268  preg_match('/<ErrorCode>(.*)<\/ErrorCode>/i', $response, $stat);
2269  $mpaystat = $stat[1];
2270  preg_match('/<Description>(.*)<\/Description>/i', $response, $stat);
2271  $mpaydesc = $stat[1];
2272  }
2273  if ($mpaystat == '0') {
2274  preg_match('/<Token>(.*)<\/Token>/i', $response, $stat);
2275  $discard = array("{", "}", "-");
2276  $token = html_entity_decode($stat[1]);
2277  $href = "{$mpaysvc}?token=$token";
2278  } else {
2279  // show the "Not Available" notice
2280  $title = 'Service Not Available';
2281 
2282  if ($HB_ENV['HCUPOST']['vanilla']) {
2283  $cancelButton = '';
2284  } else {
2285  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Close Window")}</button>";
2286  }
2287 
2288 
2289  if ($mpaystat == '2') {
2290  // use the default custom content which may have instructions on how to sign up
2291  $displayMessage = "";
2292  } else {
2293  // some kind of connection error
2294  $displayMessage = "Connection to Bill Pay Service Failed. Please try again later or contact the credit union to report this error.<br>Error: $mpaystat $mpaydesc";
2295  }
2296 
2297  // set up the string substitution
2298  $noticeSubstitution = array(
2299  "#title#" => $title,
2300  "#service_name#" => "MemberPay",
2301  "#service_type#" => "BillPay",
2302  "#vendor_name#" => "",
2303  "#display_content#" => $displayMessage,
2304  "#close_button#" => $cancelButton
2305  );
2306 
2307  // get any notice text
2308  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
2309  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectNoService');
2310 
2311  // make sure we got the notice
2312  if ($noticeInfo["status"]["code"] != "000" ||
2313  !count($noticeInfo["notice"]) ||
2314  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
2315  throw new Exception("Configuration Error: Custom Content ConnectNoService");
2316  }
2317 
2318  $noticeText = $noticeInfo['notice'][0]['notice_text'];
2319 
2320  ShowUserNotice($noticeText, array(), "", "");
2321  }
2322 
2323  break;
2324  case "FICS":
2325 
2326  # should recode to use embedded curl instead of rolling to
2327  # command line, but we have not clients as of 6/20/2018
2328  # so leaving it as is for now.
2329  #
2330  // Mortgage Info
2331  if (!hcu_checkService($dbh, "FICS")) {
2332  $omsg = hcu_checkServiceMsg($dbh, "FICS");
2333  throw new Exception("$omsg");
2334  }
2335 
2336  $APIKey = HCU_array_key_value('APIKey', $parms);
2337  $FICSidtype = HCU_array_key_value('FICSidtype', $parms);
2338  switch ($FICSidtype) {
2339  case 1: #loan number
2340  # not implemented -
2341  # would have to get info from mir
2342  break;
2343  case 2: # SSN
2344  # get mir
2345  # set FICSid = mir.ssn
2346  break;
2347  case 3: # CU member account number
2348  $FICSid = $accountToUse;
2349  break;
2350  case 4: # misc. id
2351  # not implemented -
2352  # would have to work w/CU to figure out where to get data
2353  # probably something in mir packet
2354  break;
2355  default:
2356  # default to member number
2357  # Odyssey default to member account selected in SpeedBump
2358  $FICSid = $accountToUse;
2359  break;
2360  }
2361  if (empty($APIKey) || empty($FICSidtype) || empty($FICSid)) {
2362  throw new Exception("Missing Settings");
2363  }
2364  # send login
2365  // $request = "{$parms['authurl']}?method=getauthenticationkey&APIKey=$APIKey&ID=$FICSid&TypeId=$FICSidtype";
2366  // $FICSXML = file_get_contents($request);
2367 
2368  $ficsreq = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservice\">
2369  <soapenv:Header/>
2370  <soapenv:Body>
2371  <web:getAuthenticationKey soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
2372  <APIKey xsi:type=\"xsd:string\">$APIKey</APIKey>
2373  <ID xsi:type=\"xsd:string\">$FICSid</ID>
2374  <TypeID xsi:type=\"xsd:double\">$FICSidtype</TypeID>
2375  </web:getAuthenticationKey>
2376  </soapenv:Body>
2377  </soapenv:Envelope>";
2378 
2379  $cmd = "/usr/bin/curl --silent --data-binary '$ficsreq' -H 'Content-Type: text/xml; charset=utf-8'";
2380  $cmd .= " -H 'SOAPAction: \"getAuthenticationKey\"' {$parms['authurl']}";
2381 
2382  $FICSXML = getcurl($cmd);
2383  // $tfile = fopen ("/tmp/fics","w");
2384  // fwrite ($tfile, "$cmd\n\n");
2385  // fwrite ($tfile, $FICSXML);
2386  // fclose ($tfile);
2387  # need to check first to make sure we got a response
2388  if (empty($FICSXML)) {
2389  throw new Exception("Connection to FICS Mortgage Info service Failed");
2390  }
2391  $xml = simplexml_load_string($FICSXML);
2392  if (!is_object($xml)) {
2393  libxml_clear_errors();
2394  throw new Exception("Connection to FICS Mortgage Info service Failed<br>Error: XML parse failed");
2395  }
2396 
2397  $xml->registerXPathNamespace('fics', 'http://webservice');
2398  $dataresponse = $xml->xpath("//fics:getAuthenticationKeyResponse/getAuthenticationKeyReturn"); #GetAuthenticationKeyReturn?
2399  $AuthKey = $dataresponse[0][0];
2400  $loadmsg = $HB_ENV['MC']->msg("Loading Data");
2401  print <<<EOF
2402  <html>
2403  <body onload = "javascript:document.SSOform.submit();">
2404  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
2405  Loading Data..... Please Wait
2406  </div>
2407  <form name="SSOform" method="post" action="{$parms['serviceurl']}">
2408  <input type="hidden" name="AuthenticationKey" value="$AuthKey">
2409  </form>
2410  </body>
2411  </html>
2412 EOF;
2413  break;
2414  case "FIS_EZCARD":
2415  case "HcuEZCARD": #fis_ezcard info maintained locally at HomeCU
2416 
2417  if (!hcu_checkService($dbh, "FIS")) {
2418  $omsg = hcu_checkServiceMsg($dbh, "FIS");
2419  throw new Exception("$omsg");
2420  }
2421  $clientid = HCU_array_key_value('clientid', $parms);
2422  $produrl = HCU_array_key_value('fisurl', $parms);
2423  $pilot = HCU_array_key_value('pilot', $parms);
2424  /*
2425  * keys and iv are provided as hex string, convert to binary before using
2426  */
2427  if ($pilot) {
2428  $pub = HCU_array_key_value('pilotpub',$parms);
2429  $priv = HCU_array_key_value('pilotpriv',$parms);
2430  $iv = HCU_array_key_value('pilotiv',$parms);
2431  } else {
2432  $pub = HCU_array_key_value('pubkey',$parms);
2433  $priv = HCU_array_key_value('privkey',$parms);
2434  $iv = HCU_array_key_value('priviv',$parms);
2435  }
2436  if ( empty($clientid) || empty($produrl) || empty($pub) ||
2437  empty($priv) || empty($iv) ) {
2438  throw new Exception('Missing EZCard Settings');
2439  }
2440  $pubkey = "";
2441  for ($i = 0; $i < strlen($pub); $i+=2) {
2442  $pubkey .= chr(hexdec(substr($pub, $i, 2)));
2443  }
2444  $privkey = "";
2445  for ($i = 0; $i < strlen($priv); $i+=2) {
2446  $privkey .= chr(hexdec(substr($priv, $i, 2)));
2447  }
2448  $priviv = "";
2449  for ($i = 0; $i < strlen($iv); $i+=2) {
2450  $priviv .= chr(hexdec(substr($iv, $i, 2)));
2451  }
2452 
2453 
2454  // if ($live) {
2455  // $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
2456 
2457  // } else {
2458  // /* batch interface will need to figure out how to get MIR info */
2459  // $MIR["data"] = array();
2460  // }
2461 
2462  # NOTE that EZCARD does not use the speedbump. Required parameters
2463  # are populated from the loan history settings in home banking.
2464  #
2465  # For EXTERNAL keys, set
2466  # accountToUse=#mbracct# and keyloc=EXTERNAL
2467  #
2468  # For keys in the data stream, set
2469  # accountToUse=#mbracct# and loannumber=#loan#
2470  #
2471  # On Mammoth, only the loannumber was set with loannumber=#loan#
2472  # For Odyssey, add a=#acctid#
2473 
2474  $dms_ok = array('keyloc' => 'string');
2475  dms_import($dms_ok);
2476 
2477  // for EXTERNAL, the accountToUse should be coming from the
2478  // speedbump account selector
2479  if (strtoupper($keyloc) == 'EXTERNAL') {
2480  if (empty($accountToUse) ) {
2481  throw new Exception('Missing Account Parameter');
2482  }
2483  # get card info from {$CU}extkey table
2484  # should only be one record, but just in case, limit 1
2485  $sql = "select parms
2486  from {$Cu}extkey where accountnumber='" . prep_save($accountToUse, 12) . "'
2487  and providermode='$mode' limit 1;";
2488 
2489  $sth = db_query($sql, $dbh);
2490  if (!($sth) || db_num_rows($sth) == 0) {
2491  throw new Exception('No credit card found. Please contact the credit union.');
2492  }
2493  list($misc1) = db_fetch_array($sth, 0);
2494  list($card4, $cardsig, $cardtype) = explode(',', $misc1);
2495  } else {
2496  $dms_ok = array('a' => 'string');
2497  dms_import($dms_ok);
2498 
2499  // a = acctid
2500  // acctid is the string representation of the sub account
2501  // D|6680|10|0
2502  $acctID = HCU_PayloadDecode($Cu, $a);
2503  $loannumber = $acctID[2];
2504  $accountToUse = $acctID[1];
2505 
2506  // must restrict to the current user, check if the user
2507  // actually has access to the loan account that was passed
2508  // through.
2509  $sql = "
2510  SELECT * FROM {$Cu}useraccounts
2511  WHERE accountnumber = '" . prep_save($accountToUse, 12) . "'
2512  AND accounttype = '" . prep_save($loannumber, 25) . "'
2513  AND recordtype = 'L'
2514  AND user_id = $Uid";
2515  $sth = db_query($sql, $dbh);
2516  if (!($sth) || db_num_rows($sth) == 0) {
2517  throw new Exception('No credit card found. Please contact the credit union.');
2518  }
2519  # get card info from {$CU}loanbalance table
2520  if (empty($loannumber)) {
2521  throw new Exception('Missing Loan Account');
2522  }
2523 
2524  # need to pass loannumber in link
2525  $sql = "select trim(misc1)
2526  from {$Cu}loanbalance where accountnumber='" . prep_save($accountToUse, 12) . "'
2527  and loannumber='" . prep_save($loannumber, 25) . "';";
2528 
2529  $sth = db_query($sql, $dbh);
2530  if (!($sth) || db_num_rows($sth) == 0) {
2531  throw new Exception('Invalid Loan Account');
2532  }
2533  list($misc1) = db_fetch_array($sth, 0);
2534  list($card4, $cardsig, $cardtype) = explode(',', $misc1);
2535  }
2536  # give error and die if missing values
2537  if (empty($card4) || empty($cardsig) || empty($cardtype)) {
2538  throw new Exception('Empty values');
2539  }
2540 
2541  # Implement PKCS5 / PKCS7 Padding (PKCS7 apparently extends PKCS5, but they
2542  # are the same for 8-byte blocks)
2543  # cipher algorithm needs 8-byte blocks, pad data with binary bytes
2544  # - 01 if you need 1 byte, 02 02 if you need 2 bytes, ...
2545  # 07 07 07 07 07 07 07 if you need 7 bytes, and if you have a multiple of 8,
2546  # pad with 8 bytes 08.
2547  $sv0 = substr('00000000' . strval(rand(1, 99999999)), -8);
2548  $edate = gmdate('m/d/y H:i:s', time() + 900); # sso expires after 15 minutes
2549  $salt = base64_encode(openssl_random_pseudo_bytes(6));
2550  $salt = str_replace(array("+", "/", "="), array("-", "_", "."), $salt);
2551 
2552  $ssoRequest = "<SSORequest AcctLast4=\"${card4}\" AcctSignature=\"${cardsig}\" CardType=\"${cardtype}\" EmailAddress=\"${Ml}\" ExpireDateTime=\"${edate}\" />";
2553 
2554  $clientId = $parms['clientid'];
2555  // ENCRYPTION
2556  if($use_openssl_encryption) {
2557  list($ssoRequest,
2558  $innerpkt,
2559  $ssoWrap,
2560  $outpkt) = encrypt_ezcard_sso($ssoRequest,
2561  $clientId,
2562  $privkey,
2563  $pubkey,
2564  $priviv,
2565  $salt);
2566  } else {
2567  list($ssoRequest,
2568  $innerpkt,
2569  $ssoWrap,
2570  $outpkt) = encrypt_ezcard_sso_mcrypt($ssoRequest,
2571  $clientId,
2572  $privkey,
2573  $pubkey,
2574  $priviv,
2575  $salt);
2576  }
2577 
2578  $href = "{$produrl}?SSOPacket=$outpkt";
2579  if ($parms["logging"] == "enabled") {
2580  $logParms = $parms["environment"]; // get the environment info passed in
2581  $logParms["token"] = ''; // the id used across all communications in session
2582  $logParms["txnId"] = time(); // the id for this transaction
2583  $logParms["logPoint"] = "$mode SSO"; // this action in a readable form
2584  $logParms["request"] = "href: $href \nssoRequest $ssoRequest \nssoWrap $ssoWrap"; // the request
2585  $logParms["reply"] = ""; // SSO - no response
2586  LogSSOActivity($logParms);
2587  }
2588  break;
2589 
2590  case "GOTOMYCARD":
2591  # NOTE that GOTOMYCARD does not use the speedbump. Both accountToUse and
2592  # loannumber are populated from the loan history settings in home banking.
2593  # On Mammoth, only the loannumber was set with loannumber=#loan#
2594  # For Odyssey, add accountToUse and loannumber set with a=#acctid#
2595  if (!hcu_checkService($dbh, "VANTIV")) {
2596  $omsg = hcu_checkServiceMsg($dbh, "VANTIV");
2597  throw new Exception("$omsg");
2598  }
2599  $CuNo = HCU_array_key_value('CuNo', $parms);
2600  $pilot = HCU_array_key_value('pilot', $parms);
2601  if ($pilot) {
2602  $gtmcurl = HCU_array_key_value('piloturl', $parms);
2603  $gtmccert = HCU_array_key_value('pilotcert', $parms);
2604  $gtmcpass = HCU_array_key_value('pilotpass', $parms);
2605  } else {
2606  $gtmcurl = HCU_array_key_value('produrl', $parms);
2607  $gtmccert = HCU_array_key_value('prodcert', $parms);
2608  $gtmcpass = HCU_array_key_value('prodpass', $parms);
2609  }
2610 
2611  $dms_ok = array('keyloc' => 'string', 'a' => 'string');
2612  dms_import($dms_ok);
2613 
2614  // a = acctid
2615  // acctid is the string representation of the sub account
2616  // D|6680|10|0
2617  $acctID = HCU_PayloadDecode($Cu, $a);
2618  $loannumber = $acctID[2];
2619  $accountToUse = $acctID[1];
2620 
2621  // must restrict to the current user, check if the user
2622  // actually has access to the loan account that was passed
2623  // through.
2624  $sql = "
2625  SELECT * FROM {$Cu}useraccounts
2626  WHERE accountnumber = '" . prep_save($accountToUse, 12) . "'
2627  AND accounttype = '" . prep_save($loannumber, 25) . "'
2628  AND recordtype = 'L'
2629  AND user_id = $Uid";
2630  $sth = db_query($sql, $dbh);
2631  if (!($sth) || db_num_rows($sth) == 0) {
2632  throw new Exception('No credit card found. Please contact the credit union.');
2633  }
2634 
2635  if (isset($keyloc) && strtoupper($keyloc) == 'EXTERNAL') {
2636  # get card info from {$CU}extkey table
2637  # should only be one record, but just in case, limit 1
2638  $sql = "select parms
2639  from {$Cu}extkey where accountnumber='" . prep_save($accountToUse, 12) . "'
2640  and providermode='$mode' limit 1;";
2641 
2642  $sth = db_query($sql, $dbh);
2643  if (!($sth) || db_num_rows($sth) == 0) {
2644  throw new Exception('No credit card found. Please contact the credit union.');
2645  }
2646  list($misc1) = db_fetch_array($sth, 0);
2647  list($card4, $cardsig, $cardtype) = explode(',', $misc1);
2648  } else {
2649  # get card info from {$CU}loanbalance table
2650  if (empty($loannumber) || empty($accountToUse) ) {
2651  throw new Exception('Invalid Account');
2652  }
2653 
2654  $sql = "select trim(misc1)
2655  from {$Cu}loanbalance where accountnumber='" . prep_save($accountToUse, 12) . "'
2656  and loannumber='" . prep_save($loannumber, 25) . "';";
2657  // and type='18';";
2658 
2659  $sth = db_query($sql, $dbh);
2660  if (!($sth) || db_num_rows($sth) == 0) {
2661  throw new Exception('No Valid Accounts');
2662  }
2663  list($misc1) = db_fetch_array($sth, 0);
2664  list($card4, $cardsig, $cardtype) = explode(',', $misc1);
2665  }
2666  # give error and die if missing values
2667  if (empty($card4)) {
2668  throw new Exception('Missing Card Info HomeCU');
2669  }
2670 
2671  /*
2672  * build the SSO request
2673  */
2674  if (!isset($parms['SavingsNoSize'])) {
2675  # default to 10 char length for backward compatibility
2676  $SavingsNo = substr("0000000000$accountToUse",-10,10);
2677  } elseif (isset($parms['SavingsNoSize']) && $parms['SavingsNoSize'] > 0) {
2678  $SavingsNo = substr(str_repeat('0', $parms['SavingsNoSize']) . $accountToUse, (-1 * $parms['SavingsNoSize']), $parms['SavingsNoSize']);
2679  } else {
2680  $SavingsNo = $accountToUse;
2681  }
2682 
2683  if ( getenv( "DEVMODE" ) == 1 ) {
2684  # devmode, send loopback
2685  $ipaddr = '127.0.0.1';
2686  } else {
2687  $ipaddr = $_SERVER['REMOTE_ADDR'];
2688  }
2689 
2690  $soapString = '<?xml version="1.0" encoding="utf-8"?>';
2691  $soapString .= "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:sso=\"https://sso.gotomycard.com/\">
2692 <soap:Body>
2693  <sso:SSORequest>
2694  <sso:CuNo>{$parms['CuNo']}</sso:CuNo>
2695  <sso:UserName>$accountToUse</sso:UserName>
2696  <sso:IpAddress>$ipaddr</sso:IpAddress>
2697  <sso:SavingsNo>$SavingsNo</sso:SavingsNo>
2698  <sso:Ssn></sso:Ssn>
2699  <sso:AcctNo>$card4</sso:AcctNo>
2700  </sso:SSORequest>
2701 </soap:Body>
2702 </soap:Envelope>";
2703 
2704  $curlopts = array(
2705  CURLOPT_RETURNTRANSFER => 1,
2706  CURLOPT_POST => 1,
2707  CURLOPT_POSTFIELDS => "$soapString",
2708  CURLOPT_URL => "$gtmcurl",
2709  CURLOPT_SSLCERT => "$gtmccert",
2710  CURLOPT_SSLCERTPASSWD => "$gtmcpass");
2711 
2712  $header = array();
2713  $header[] = "Content-Type: text/xml; charset=utf-8";
2714 // $header[] = 'SOAPAction: "SSORequest"';
2715  $response = "";
2716  $ch = curl_init();
2717  if ($ch) {
2718  curl_setopt_array($ch, $curlopts);
2719  curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
2720 //curl_setopt($ch, CURLOPT_VERBOSE, true);
2721 //$verbose = fopen('/home/cruisecu/tmp/gtmc_trace.txt', 'a+');
2722 //curl_setopt($ch, CURLOPT_STDERR, $verbose);
2723  $response = curl_exec($ch);
2724  $cerrno = curl_errno($ch);
2725  $cerr = curl_error($ch);
2726  curl_close($ch);
2727  }
2728  if ($parms["logging"] == "enabled") {
2729  $logParms = $parms["environment"]; // get the environment info passed in
2730  $logParms["token"] = ''; // the id used across all communications in session
2731  $logParms["txnId"] = time(); // the id for this transaction
2732  $logParms["logPoint"] = "GOTOMYCARD SSO"; // this action in a readable form
2733  $logParms["request"] = $soapString; // the request
2734  $logParms["reply"] = $response; // the response
2735  LogSSOActivity($logParms);
2736  }
2737 
2738 # check for soap fault & throw error
2739  if ($cerr) {
2740  throw new Exception("Connection Error $cerrno $cerr");
2741  }
2742  if ($response > '') {
2743  $response = html_entity_decode($response);
2744 
2745  $soapfault = strpos($response, "faultcode");
2746 
2747  if ($soapfault !== FALSE) {
2748  preg_match('/<faultcode>(.*)<\/faultcode>/i', $response, $stat);
2749  $gtmcfaultcode = $stat[1];
2750  preg_match('/<faultstring>(.*)<\/faultstring>/i', $response, $stat);
2751  $gtmcfaultstring = $stat[1];
2752  throw new Exception("GTMC Connection Fault $gtmcfaultstring");
2753  } else {
2754  preg_match('/<completion>(.*)<\/completion>/i', $response, $stat);
2755  $gtmcstat = $stat[1];
2756  }
2757  }
2758  if ($gtmcstat == '0') {
2759  preg_match('/<url>(.*)<\/url>/i', $response, $stat);
2760  $href = html_entity_decode($stat[1]);
2761 // $showurl = 1;
2762  } else {
2763  preg_match('/<completionscript>(.*)<\/completionscript>/i', $response, $stat);
2764  $gtmcstatstring = (empty($stat[1]) ? "GTMC Connection Failed" : $stat[1]);
2765  throw new Exception("GTMC Error $gtmcstatstring");
2766  }
2767  break;
2768 
2769  case "LASERTEC_ES":
2770  if (!hcu_checkService($dbh, "LASERTEC")) {
2771  $omsg = hcu_checkServiceMsg($dbh, "LASERTEC");
2772  throw new Exception("$omsg");
2773  }
2774  if (trim($Ml) == '') {
2775  throw new Exception("Not enough info for remote service (missing email)");
2776  }
2777 
2778  $UniqueKey = HCU_array_key_value('UniqueKey',$parms);
2779  $CustID = HCU_array_key_value('CustID',$parms);
2780  $currdate = gmdate('mdYHis'); # using GMT - OK?
2781  $currdate = date('mdYHis'); # using GMT - OK?
2782  // $Cn='545454'; # test value -- log in worked 10/3/13 MH
2783  $srcstring = "{$accountToUse}{$currdate}{$Ml}{$UniqueKey}";
2784 
2785  $hash = strtoupper(hash('SHA256', $srcstring, false));
2786 
2787  print <<<EOF
2788  <html>
2789  <body onload = "javascript:document.SSOform.submit();">
2790  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
2791  Loading Data..... Please Wait
2792  </div>
2793  <form name="SSOform" method="post" action="{$parms['ES_URL']}">
2794  <input type="hidden" name="CustID" value="$CustID">
2795  <input type="hidden" name="AccountNumber" value="$accountToUse">
2796  <input type="hidden" name="Date" value="$currdate">
2797  <input type="hidden" name="Email" value="$Ml">
2798  <input type="hidden" name="Hash" value="$hash">
2799  <input type="hidden" name="UniqueKey" value="$UniqueKey">
2800  </form>
2801  </body>
2802  </html>
2803 EOF;
2804 
2805  break;
2806 
2807  case "IDS_ES":
2808  if (!hcu_checkService($dbh, "IDS")) {
2809  $omsg = hcu_checkServiceMsg($dbh, "IDS");
2810  throw new Exception("$omsg");
2811  }
2812  $pilot = HCU_array_key_value('pilot', $parms);
2813  if ($pilot) {
2814  $UniqueKey = HCU_array_key_value('pilotKey', $parms);
2815  $InstID = HCU_array_key_value('pilotInstID', $parms);
2816  $ES_URL = HCU_array_key_value('pilotURL', $parms);
2817  } else {
2818  $UniqueKey = HCU_array_key_value('prodKey', $parms);
2819  $InstID = HCU_array_key_value('prodInstID', $parms);
2820  $ES_URL = HCU_array_key_value('prodURL', $parms);
2821  }
2822 
2823  if (empty($UniqueKey) || empty($InstID) || empty($ES_URL) ) {
2824  throw new Exception('Missing Settings');
2825  }
2826 
2827  $currdate = gmdate('mdYHis'); # using GMT - OK?
2828  $currdate = date('mdYHis'); # using local
2829  $srcstring = "{$accountToUse}{$currdate}{$Ml}";
2830 
2831  $hash = hash_hmac('sha256', $srcstring, $UniqueKey,false);
2832 
2833  print <<<EOF
2834  <html>
2835  <body onload = "javascript:document.SSOform.submit();">
2836  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
2837  Loading Data..... Please Wait
2838  </div>
2839  <form name="SSOform" method="post" action="{$ES_URL}" method="POST">
2840  <input type="hidden" name="institution" value="$InstID">
2841  <input type="hidden" name="account" value="$accountToUse">
2842  <input type="hidden" name="timestamp" value="$currdate">
2843  <input type="hidden" name="timezone" value="MST">
2844  <input type="hidden" name="hmac" value="$hash">
2845 EOF;
2846  if (!empty($Ml)) {
2847  print '<input type="hidden" name="email" value="' . $Ml . '">';
2848  }
2849  print <<<EOF
2850  </form>
2851  </body>
2852  </html>
2853 EOF;
2854 
2855  break;
2856  case "LASERPRINT_ES":
2857  if (!hcu_checkService($dbh, "LASERPRINTING")) {
2858  $omsg = hcu_checkServiceMsg($dbh, "LASERPRINTING");
2859  throw new Exception("$omsg");
2860  }
2861 
2862  /*
2863  * These are the entire specs .... but hey, they work!
2864  *
2865  * 1) Let's say for example, we want to access account number 12345.
2866  * 2) Convert the number to 10-digit string without spaces by prefixing it with zeroes. You should get "0000012345".
2867  * 3) Affix "test" at the beginning and "SALT123" at the end of the string. It should now give you "test0000012345SALT123".
2868  * 4) Convert the string to MD5 or SHA-256 hash. You should get "7248f8aad297d31a99b13ba8b48283f3" (lower case) if using MD5.
2869  * This is the value to assign to the "access" item.
2870  * 5) Submit the access value to our link using either POST or GET method (we recommend using the POST method because it's more secure)
2871  *
2872  * Following the above procedure, the complete URL to access account number 12345 will be
2873  * https://www.laserprinting.com/asp/mercer_test/test.asp?access=7248f8aad297d31a99b13ba8b48283f3 (using the GET method).
2874  * Following this link should get you to a page containing the credit union logo, plus a short message telling you which account record is accessed.
2875  *
2876  * We can setup dummy accounts for testing if you desire.
2877  * We then restrict access to your IP address or range.
2878  * The specification described here is for testing purposes only. We will be changing the main URL and the values described
2879  * in Step 3 when/if this goes live.
2880  *
2881  * Christopher P. Rachal
2882  * Operations Manager
2883  * Alpha Omega COM Inc.
2884  * crachal@laserprinting.com
2885  * Phone: 318-584-1673
2886  * Office: 318-227-8065
2887  * www.laserprinting.com
2888  */
2889 
2890 
2891  /*
2892  * ...and then they sent new specs:
2893  * Here's our basic single sign-on specs (converted from MD5 to SHA-256) :
2894 
2895  * The home banking site will be able to connect the users to our e-statements by passing
2896  * their account number in encrypted form.
2897 
2898  * Here's a sample procedure:
2899 
2900  * The home banking app will have to convert a member's account number to 10-digit string.
2901  * For example, an account number 1234 becomes 0000001234.
2902  * Affix "alpha" at the beginning and "OMEGA2000" at the end of the 10-digit string.
2903  * We should get "alpha0000001234OMEGA2000".
2904  * Encrypt the string using SHA-256 hash. We should get
2905  * "5e82568ed1df607623f739d82bef23d9ddf813fb3efdb0e96f1bb98cc28addbd".
2906  * Assign the SHA-256 hashed value to a form item named "access" and submit it to our
2907  * receiving URL using either POST or GET method (we recommend using the POST method).
2908 
2909  * The salt strings described in step #2 above are just for testing purposes and
2910  * will be changed accordingly for live implementation.
2911  * The link to our test app is https://www.laserprinting.com/asp/mcnjtfcu/e-stmt.asp.
2912  * Following the above procedure, a way to connect a user having account number
2913  * 1234 is by redirecting to this URL:
2914  * https://www.laserprinting.com/asp/mcnjtfcu/e-stmt.asp?access=5e82568ed1df607623f739d82bef23d9ddf813fb3efdb0e96f1bb98cc28addbd.
2915 
2916  * The link above should take them to a page showing the credit union logo and
2917  * information on which account number is accessed.
2918  * If you see a dash (-) under the Account Number column during testing,
2919  * it means the SHA-256 hash value submitted to our site does not exist or is invalid.
2920  * A plain message that says "Access Denied" is also an indication of an invalid SHA-256 value
2921  * submitted to the page.
2922 
2923  * The app is currently setup to accept the following test accounts as valid:
2924  * - 2267009
2925  * - 10207355
2926  * Let us know when you are ready to test live member statements and we will have it enabled.
2927  */
2928 
2929  $pilot = HCU_array_key_value('pilot', $parms);
2930  if ($pilot) {
2931  $ES_Pre = HCU_array_key_value('pilotPre', $parms);
2932  $ES_After = HCU_array_key_value('pilotAfter', $parms);
2933  $ES_PadLen = HCU_array_key_value('pilotPadLen', $parms);
2934  $ES_URL = HCU_array_key_value('pilotURL', $parms);
2935  } else {
2936  $ES_Pre = HCU_array_key_value('prodPre', $parms);
2937  $ES_After = HCU_array_key_value('prodAfter', $parms);
2938  $ES_PadLen = HCU_array_key_value('prodPadLen', $parms);
2939  $ES_URL = HCU_array_key_value('prodURL', $parms);
2940  }
2941 
2942  $srcstring = trim($ES_Pre) . str_pad($accountToUse,$ES_PadLen,"0",STR_PAD_LEFT) . trim($ES_After);
2943 // $access=md5($srcstring); # first specs used MD5
2944  $access=hash('sha256',$srcstring);
2945 
2946  if ($parms["logging"] == "enabled") {
2947  $logParms = $parms["environment"]; // get the environment info passed in
2948  $logParms["token"] = ''; // the id used across all communications in session
2949  $logParms["txnId"] = time(); // the id for this transaction
2950  $logParms["logPoint"] = "LASERPRINT_ES Redirect"; // this action in a readable form
2951  $logParms["request"] = "SSO $ES_URL w/ src $srcstring and access $access"; // the request
2952  $logParms["reply"] = ''; // the response
2953  LogSSOActivity($logParms);
2954  }
2955 
2956  print <<<EOF
2957  <html>
2958  <body onload = "javascript:document.SSOform.submit();">
2959  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
2960  Loading Data..... Please Wait
2961  </div>
2962  <form name="SSOform" method="post" action="{$ES_URL}" method="POST">
2963  <input type="hidden" name="access" value="$access">
2964  </form>
2965  </body>
2966  </html>
2967 EOF;
2968 
2969  break;
2970 
2971  case "MWI_LOANPAY":
2972  if (!hcu_checkService($dbh, "MWI")) {
2973  $omsg = hcu_checkServiceMsg($dbh, "MWI");
2974  throw new Exception("$omsg");
2975  }
2976 
2977  if ($HB_ENV["HCUPOST"]["option"] == 'SELECTACCT') {
2978  $dms_ok = Array("selacct" => "string");
2979 
2980  dms_import_v2($HB_ENV, "HCUPOST", $dms_ok);
2981 
2982  if (!sizeof($HB_ENV["HCUPOST"]["selacct"])) {
2983  # error if no selacct?
2984  }
2985  #
2986  list($loanACH, $paymentdue) = explode('|', $HB_ENV["HCUPOST"]["selacct"]);
2987  $Pilot = $parms['Pilot'];
2988  $URL = ($Pilot == 0 ? $parms['ProdUrl'] : $parms['PilotUrl']);
2989  $AccessNumber = $parms['AccessNumber'];
2990  $SecurityKey = $parms['SecurityKey'];
2991  $Password = $parms['Password'];
2992  $salt = $parms['salt'];
2993  $PaymentIndicator = $parms['PaymentIndicator'];
2994  $PaymentFunction = '1';
2995  $PaymentAmount = $paymentdue;
2996  $BillingID = "$Cn";
2997  $CreditAcctNumber = $loanACH;
2998  /*
2999  * Per Jeff Dean 2/14/14 ignore the specs and send
3000  * BillingID as the ACH value
3001  * InternalID as member number
3002  * CreditAcctNumber blank
3003  */
3004  $BillingID = "$loanACH";
3005  $CreditAcctNumber = '';
3006  $InternalID = "$Cn";
3007 
3008  $srcstring = "{$SecurityKey}|{$PaymentFunction}|{$PaymentAmount}|{$PaymentIndicator}|{$AccessNumber}|{$BillingID}|{$Password}";
3009 
3010 
3011  # set test values
3012  // $SecurityKey='jaywilson';
3013  // $PaymentFunction='1'; # payment function is always 6 according to specs, but sample uses 1
3014  // $PaymentAmount='1018.40';
3015  // $PaymentIndicator='3';
3016  // $AccessNumber='3001';
3017  // $BillingID='337764-000-2';
3018  // $CreditAcctNumber = '200337764';
3019  // $Password='jay1234';
3020  //
3021  // $srcstring = "jaywilson|1|1018.40|3|3001|337764-000-2|jay1234";
3022 
3023  $hash = hash_hmac('sha256', $srcstring, $salt, false);
3024  $request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
3025  $request .= "\n<PaymentRequest>
3026  <AuthInfo\n AccessNumber=\"$AccessNumber\"
3027  SecurityKey=\"$SecurityKey\"
3028  Password=\"$Password\"
3029  PaymentFunction=\"$PaymentFunction\"
3030  PaymentIndicator=\"$PaymentIndicator\"";
3031  /*
3032  * Magic Wrighter can't get the email to work
3033  * triggers 500 internal server error no matter how
3034  * I send it. Tried CustEMail, CustEmail,
3035  * single quotes, double quotes,
3036  * url-encoded, plain, with @ escaped as \@
3037  * can't find a combo that works
3038  * So per Jeff Dean 2/13/14
3039  * members will have to enter email on Magic Wrighter side
3040  */
3041 
3042  // if (!empty($Ml)) {
3043  //// $request .= "\nCustEmail=\"" . urlencode($Ml) . "\"\n";
3044  // $request .= "\nCustEmail=\"$Ml\"\n";
3045  // }
3046  $request .= "/>\n";
3047  $request .= "\n<PaymentInfo\n BillingID=\"$BillingID\"
3048  InternalID=\"$InternalID\"
3049  PaymentAmount=\"$PaymentAmount\"
3050  VerificationHash=\"$hash\"/>
3051  </PaymentRequest>";
3052  if ($parms["logging"] == "enabled") {
3053  $logParms = $parms["environment"]; // get the environment info passed in
3054  $logParms["token"] = ''; // the id used across all communications in session
3055  $logParms["txnId"] = time(); // the id for this transaction
3056  $logParms["logPoint"] = "MWI_LOANPAY SSO"; // this action in a readable form
3057  $logParms["request"] = "SRCSTRING $srcstring \nPOST $URL \nPaymentRequest = $request"; // the request
3058  $logParms["reply"] = ''; // no response - this is a redirect
3059  LogSSOActivity($logParms);
3060  }
3061 
3062  print <<<EOF
3063  <html>
3064  <body onload = "javascript:document.SSOform.submit();">
3065  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
3066  Loading Data..... Please Wait
3067  </div>
3068  <form name="SSOform" method="post" action="{$URL}">
3069  <input type="hidden" name="PaymentRequest" value='$request'>
3070  </form>
3071  </body>
3072  </html>
3073 EOF;
3074  } else {
3075 
3076  # get the list of valid transfer accounts
3077  $aryTxlist = TX_list($dbh, $HB_ENV);
3078  setFmsgTxCookie($HB_ENV, $aryTxlist);
3079 
3080  if ($aryTxlist['status']['code'] != '000') {
3081  throw new Exception("No eligible loans");
3082  }
3083  $arySelectList = array();
3084  foreach ($aryTxlist['acctlist'] as $acctkey => $details) {
3085  if ($details['acctclass'] == 'L' && $details['to'] == 'Y') {
3086  if ($parms['sendjoint'] || (!$parms['sendjoint'] && $details['trust'] == 'primary')) {
3087  $arySelectList[$acctkey]['display'] = $details['description'] . ' (' . $HB_ENV['MC']->msg('Payment') . ': ' . $details['paymentdue'] . ')';
3088 
3089  if (sizeof($parms['ACHfmt'])) {
3090  $loanACH = Set_ACH($parms['ACHfmt'], $details['suffix'], $details['member']);
3091  } else {
3092  # pretty stupid default, but probably need to set something...
3093  $loanACH = $details['member'] . $details['suffix'];
3094  }
3095  $arySelectList[$acctkey]['getvalue'] = trim($loanACH) . '|' . $details['paymentdue'];
3096  }
3097  }
3098  }
3099 
3100  if (!sizeof($arySelectList)) {
3101  throw new Exception("No eligible loans");
3102  }
3103 
3104  // set up the list of account choices
3105  $selectAccountString = "";
3106  $count = count($arySelectList);
3107  if ($count > 0) {
3108  $idx = 1;
3109  $checked = $count == 1 ? "checked" : "";
3110  foreach ($arySelectList as $acct_key => $acct_array) {
3111  $selectAccountString .="<input type='radio' name='selacct' id='response{$idx}' {$checked} value='{$acct_array['getvalue']}'/><label style='padding: 10px;' for='response{$idx}'>{$acct_array['display']}</label><br>";
3112  $idx++;
3113  }
3114  }
3115 
3116  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Cancel")}</button>";
3117  $continueButtonText = "Continue";
3118  // if the button needs to trigger a check of the radio buttons to make sure one selected, it must call CkRadio()
3119  $continueButton = "<button type='button' class='k-button' name='btnContinue' onClick='javascript:CkRadio();return false;'>$continueButtonText</button>";
3120  $buttons = "{$cancelButton} &nbsp; &nbsp; {$continueButton}";
3121 
3122  $descTtl = "";
3123  $pageTtl = '<p><span style="font-size: medium; font-family: arial,helvetica,sans-serif;"><strong>Please select the loan you wish to pay:</strong></span></p>';
3124  $acceptance = ""; // not needed for this form
3125 
3126  $noticeSubstitution = array(
3127  "#page_title#" => $pageTtl,
3128  "#description#" => $descTtl,
3129  "#content#" => $selectAccountString,
3130  "#acceptance#" => $acceptance,
3131  "#buttons#" => $buttons
3132  );
3133 
3134  /*
3135  * present a list of eligible loans, showing description & paymentdue
3136  * render as radio (select one only).
3137  */
3138  // get any notice text
3139  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
3140  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectSpeedbump');
3141 
3142  // make sure we got the notice
3143  if ($noticeInfo["status"]["code"] != "000" ||
3144  !count($noticeInfo["notice"]) ||
3145  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
3146  throw new Exception("Configuration Error: Custom Content (ConnectSpeedbump)");
3147  }
3148 
3149  $noticeText = $noticeInfo['notice'][0]['notice_text'];
3150 
3151  $inputList = array(array("name" => "mode", "value" => "$mode"),
3152  array("name" => "option", "value" => "SELECTACCT")
3153  );
3154  $checkMsg = "";
3155  $radioGroupName = "selacct";
3156  ShowUserNotice($noticeText, $inputList, $radioGroupName, $checkMsg);
3157  }
3158  break;
3159  case "Bit":
3160  if (!hcu_checkService($dbh, "Bit")) {
3161  $omsg = hcu_checkServiceMsg($dbh, "Bit");
3162  throw new Exception("$omsg");
3163  }
3164 
3165  $cuid = HCU_array_key_value("CustID", $parms);
3166  $bitkey = HCU_array_key_value("BitKey", $parms);
3167  $biturl = HCU_array_key_value("BitURL", $parms);
3168  if (empty($cuid) || empty($bitkey) || empty($biturl) ) {
3169  throw new Exception("Missing Bit Configuration Settings");
3170  }
3171  # if we want to charge for BIT access, check eStatement status here
3172  # throw error if eStatement is not set - or present terms of service
3173  # and require agreement
3174 
3175  $key = "";
3176  for ($i = 0; $i < strlen($bitkey); $i+=2) {
3177  $key .= chr(hexdec(substr($bitkey, $i, 2)));
3178  }
3179 
3180  $date = gmdate("Ymd");
3181  $ustr = $cuid . $accountToUse . $date;
3182  $mac = hash_hmac('MD5', $ustr, $key);
3183 
3184  $href = "$biturl?FI=$cuid&Account=$accountToUse&ProviderID=2&Email=$Ml&MAC=$mac";
3185 
3186  if ($parms["logging"] == "enabled") {
3187  $logParms = $parms["environment"]; // get the environment info passed in
3188  $logParms["token"] = ''; // the id used across all communications in session
3189  $logParms["txnId"] = time(); // the id for this transaction
3190  $logParms["logPoint"] = "Bit SSO"; // this action in a readable form
3191  $logParms["request"] = $href; // the request
3192  $logParms["reply"] = '';
3193  LogSSOActivity($logParms);
3194  }
3195 
3196  break;
3197 
3198  case "CERTEGY":
3199  if (!hcu_checkService($dbh, "CERTEGY")) {
3200  $omsg = hcu_checkServiceMsg($dbh, "CERTEGY");
3201  throw new Exception("$omsg");
3202  }
3203  // CERTEGY will post back to this address (the address we provide). Look for the parameters.
3204  $dms_ok = array('STATUS' => 'string', 'DISPLAYMESSAGE' => 'string');
3205  dms_import_v2($HB_ENV, "HCUPOST", $dms_ok);
3206  $DISPLAYMESSAGE = HCU_array_key_value("DISPLAYMESSAGE",$HB_ENV["HCUPOST"]);
3207  $STATUS = HCU_array_key_value("STATUS", $HB_ENV["HCUPOST"]);
3208  /*
3209  if ($pilot == 1) {
3210  $key = 'pO_cI0m&asoagia4lec#uHI8'; # NEW test key as of 10/25/2010
3211  $certegyURL = "https://bp01.premierbillpay.com/servlet/tpservlet";
3212  $ACCOUNT = "10006"; # enrolled";
3213  $ACCOUNT = "9874002"; # not enrolled
3214  $FIID = '0006'; #TEST
3215  } else {
3216  $key = '8Pqb@NZ&!JH%g89Fql0m12P$'; # one key for DMS
3217  # this is the new URL to be effective 3/2/11:
3218  # Effective for all 3 clients: CCCU, RIVER, SIACU
3219  #
3220  $certegyURL = "https://sso-redirector.ezbills.com/mvsso/servlet/tpservlet";
3221  #$certegyURL="https://bp04.internet-ebanking.com/servlet/tpservlet";
3222  $ACCOUNT = (trim($billpayid) == '' ? $Cn : $billpayid);
3223  $FIID = $bp_cuid; #CU Institution ID assigned per CU
3224  }
3225  */
3226  $pilot = HCU_array_key_value("pilot",$parms);
3227  if ($pilot == 1) {
3228  $key = HCU_array_key_value("pilotKey",$parms);
3229  $certegyURL = HCU_array_key_value("pilotURL", $parms);
3230  } else {
3231  $key = HCU_array_key_value("certegyKey", $parms);
3232  $certegyURL = HCU_array_key_value("certegyURL", $parms);
3233  }
3234  $FIID = HCU_array_key_value("FIID", $parms);
3235  $ACCOUNT = HCU_array_key_value("ACCOUNT", $parms);
3236 
3237  if (empty($ACCOUNT) ) {
3238  $ACCOUNT = (trim($billpayid) == '' ? $accountToUse : $billpayid);
3239  }
3240  if (empty($key) || empty($certegyURL) || empty($FIID) || empty($ACCOUNT) ) {
3241  throw new Exception("Missing Certegy Settings");
3242  }
3243 
3244  // ENCRYPTION
3245  if($use_openssl_encryption) {
3246  list($dm_token, $ACCOUNT) = encrypt_certegy_openssl($ACCOUNT, $key);
3247  } else {
3248  list($dm_token, $ACCOUNT) = encrypt_certegy_account_mcrypt($ACCOUNT, $key);
3249  }
3250 
3251  $DATA = strtoupper(bin2hex($dm_token));
3252  $authurl = urlencode("https://" . $_SERVER['SERVER_NAME']
3253  . $_SERVER['PHP_SELF'] . "?cu=$Cu&mode=CERTEGY");
3254  if (trim($STATUS) > "") {
3255  switch ($STATUS) {
3256 
3257  case 8:
3258  # member tried to log in but is not enrolled - send them to the enrollment
3259  # as of 3/22/11 just give member a 'you must enroll' message, no redirect
3260  #$href="{$certegyURL}?transactiontype=EnrollmentMaintActionBean&ACTIVITY_TYPE=GOTOEDIT&CHGMODE=A&USERID=$DATA&FIID=$FIID&AUTHENTICATIONURL=$authurl&LOGOFFURL=$authurl";
3261  #break;
3262  #
3263 // $fragfile = "/home/$chome/public_html/nobillpayfrag";
3264 // $fragext = (trim("$Flang") == "en_US" ? "" : "_" . substr($Flang, 0, strpos($Flang, "_")) );
3265 // $fragfile .= ($fragext > "" && is_readable("{$fragfile}{$fragext}.html") ? "$fragext.html" : ".html");
3266  #
3267  $DISPLAYMESSAGE = 'You must enroll before using this service. Please contact your credit union for assistance';
3268 
3269  case 0:
3270  if (strtoupper($DISPLAYMESSAGE) == 'USER_SIGNOFF') {
3271  $DISPLAYMESSAGE = 'Bill Pay Session Ended';
3272  } else if (strtoupper($DISPLAYMESSAGE) == 'INACTIVITY_TIMEOUT' ||
3273  strtoupper($DISPLAYMESSAGE) == 'SESSION_TIMEOUT') {
3274  $DISPLAYMESSAGE = 'Bill Pay Session Timed Out';
3275  }
3276  default:
3277  # CERTEGY returned a message other than 'not enrolled'.
3278  # show the message we got and bail out.
3279 // Need custom content file
3280  // show the "Not Available" notice
3281 
3282  $DISPLAYMESSAGE = (trim($DISPLAYMESSAGE) == '' ? 'Unable to contact Fidelity Bill Pay service' : $DISPLAYMESSAGE);
3283  $title = $HB_ENV['MC']->msg('Unable to Log In');
3284 
3285  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Close Window")}</button>";
3286 
3287  // set up the string substitution
3288  $noticeSubstitution = array(
3289  "#title#" => $title,
3290  "#service_name#" => "Fidelity Bill Pay",
3291  "#service_type#" => "BillPay",
3292  "#vendor_name#" => "",
3293  "#display_content#" => $DISPLAYMESSAGE,
3294  "#close_button#" => $cancelButton
3295  );
3296 
3297  // get any notice text
3298  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
3299  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectNoService');
3300 
3301  // make sure we got the notice
3302  if ($noticeInfo["status"]["code"] != "000" ||
3303  !count($noticeInfo["notice"]) ||
3304  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
3305  throw new Exception("Configuration Error: Custom Content (ConnectNoService)");
3306  }
3307 
3308  $noticeText = $noticeInfo['notice'][0]['notice_text'];
3309 
3310  ShowUserNotice($noticeText, array(), "", "");
3311  break;
3312  }
3313  } else {
3314 //$showurl = 1;
3315  # try to log in
3316  # $href="https://bp01.premierbillpay.com/servlet/tpservlet?transactiontype=UserInqAuthActionBean&USERID=$DATA&FIID=$FIID&AUTHENTICATIONURL=$authurl&LOGOFFURL=$authurl";
3317  // $href = "{$certegyURL}?transactiontype=UserInqAuthActionBean&USERID=$DATA&FIID=$FIID&AUTHENTICATIONURL=$authurl&LOGOFFURL=$authurl";
3318  $href = "{$certegyURL}?transactiontype=UserInqAuthActionBean&USERID=$DATA&FIID=$FIID&AUTHENTICATIONURL=$authurl";
3319  }
3320  break;
3321  case "LKCS":
3322  if (!hcu_checkService($dbh, "LKCS")) {
3323  $omsg = hcu_checkServiceMsg($dbh, "LKCS");
3324  throw new Exception("$omsg");
3325  }
3326  /*
3327  switch ($Cu) {
3328  case "CCU":
3329  # Century Credit Union
3330  #$showurl=1;
3331  $clid = "47"; // client ID
3332  $aduser = "ssoadmin"; // admin user
3333  $pwd = "H0n32sz862fn"; // admin password
3334  break;
3335  }
3336  */
3337  $clid = HCU_array_key_value("ClientID", $parms);
3338  $aduser = HCU_array_key_value("AdminUser", $parms);
3339  $pwd = HCU_array_key_value("AdminPwd", $parms);
3340  $url = HCU_array_key_value("Url", $parms);
3341 
3342  if (empty($clid) || empty($adusr) || empty($pwd) || empty($url) ) {
3343  throw new Exception("Missing Settings");
3344  }
3345 // $url = "https://secure.estatements.net/rpweb.dll/GetUserSession";
3346  $data = http_build_query(
3347  array('clid' => $clid, 'adminuser' => $aduser, 'password' => $pwd, 'account' => $Cn,), '', '&');
3348  $cURL_call = curl_init($url); // create a cURL object
3349  curl_setopt($cURL_call, CURLOPT_SSL_VERIFYPEER, false);
3350  curl_setopt($cURL_call, CURLOPT_POST, 1); // use cURL to send data as POST
3351  curl_setopt($cURL_call, CURLOPT_HEADER, false); // don't include header
3352  curl_setopt($cURL_call, CURLOPT_POSTFIELDS, $data); // the fields to POST
3353  curl_setopt($cURL_call, CURLOPT_RETURNTRANSFER, 1); // store return value
3354  $href = curl_exec($cURL_call); // make the request
3355  if (preg_match('/^URL=/', $href)) {
3356  $href = preg_replace('/^URL=/', '', $href);
3357  } else {
3358  $error["title"] = "Connection to eStatement service Failed";
3359  $error["content"] = "Please try again later or contact the credit union to report this error.<br>$href";
3360  # not sure this is a good way to handle the error, but as of 6/19/2018 no clients using this SSO
3361  # so probably good enough until we have a client
3362  throw new Exception(json_encode($error));
3363  }
3364  break;
3365  case "MVANTE":
3366  if (!hcu_checkService($dbh, "MVANTE")) {
3367  $omsg = hcu_checkServiceMsg($dbh, "MVANTE");
3368  throw new Exception("$omsg");
3369  }
3370 
3371  // get the trusted vendor configuration
3372 
3373  $brand_id = HCU_array_key_value("BrandID", $parms);
3374  $passwd = HCU_array_key_value("bp_secret", $parms);
3375  $pilot = HCU_array_key_value("pilot", $parms);
3376 
3377  // The appropriate billpayid for the user will be used if testing or production.
3378  if ($pilot) {
3379  $server = HCU_array_key_value("TestURL", $parms);
3380  } else {
3381  $server = HCU_array_key_value("ServerURL", $parms);
3382  }
3383  # this really should come from the trusted detail
3384  # but as of 6/19/2018 no clients, so
3385  # I'll leave it alone until we get a client
3386  $certfile = "/home/{$chome}/sslforms/mv_{$chome}.pem";
3387 
3388  if ($brand_id == "" || $passwd == "" || !(is_readable($certfile))) {
3389  $error["title"] = $HB_ENV['MC']->msg('Feature Unavailable');
3390  $error["content"] = $HB_ENV['MC']->msg('Feature Not Set');
3391  throw new Exception(json_encode($error));
3392  }
3393 
3394  /*
3395  switch ($Cu) {
3396  case "ESACU":
3397  $pilot = 0;
3398  # esacu switching to IPAY 12/3/13
3399  # set MVANTE variables here so IPAY variables
3400  # can be set in Monitor.
3401  $brand_id='l8t';
3402  $passwd='esa!cu!bp';
3403  break;
3404  case "TELCOPLUS":
3405  $pilot = 0;
3406  break;
3407  }
3408  */
3409  $billpayid = $mbrow['billpayid'];
3410 
3411  if (trim($billpayid) == '') {
3412  $billpayid = $accountToUse;
3413  }
3414 
3415  /*
3416  // The Trusted Vendor Detail will use the appropriate billpayid for the user and serverURL for the server
3417  // if testing or production.
3418  if ( $pilot ) {
3419  # testing
3420  # uses test server, uses $user instead of $Cn
3421  #$user='baduser11';
3422  $user = 'esacu01'; #ESACU
3423  $user = 'test12'; #TELCOPLUS
3424  # Metavante changes the test server periodically
3425  #$server="https://secuat1.readiness.metavante.com/csp/RemoteServlet";
3426  #$server="https://secuat2.readiness.metavante.com/csp/RemoteServlet";
3427  $server = "https://secbpmuat2.readiness.metavante.com/csp/RemoteServlet";
3428  # this was the original test certificate.
3429  #$certfile="/usr/miki/metavante.pem";
3430  $qstring = "?opcode=memberlogin&bid=$brand_id&slid=$billpayid";
3431  #$cmd="/usr/bin/curl --silent -H 'Content-Type: text/xml' '{$server}{$qstring}'";
3432  $cmd = "/usr/bin/curl --silent -k -H 'Content-Type: text/xml' -E $certfile:$passwd '{$server}{$qstring}'";
3433  } else {
3434  //$server = "https://secbpm3.metavante.com/csp/RemoteServlet";
3435  $server = $parms["ServerURL"];
3436  $qstring = "?opcode=memberlogin&bid=$brand_id&slid=$billpayid";
3437  $cmd = "/usr/bin/curl --silent -k -H 'Content-Type: text/xml' -E $certfile:$passwd '{$server}{$qstring}'";
3438  }
3439  *
3440  */
3441 
3442  $qstring = "?opcode=memberlogin&bid=$brand_id&slid=$billpayid";
3443  $cmd = "/usr/bin/curl --silent -k -H 'Content-Type: text/xml' -E $certfile:$passwd '{$server}{$qstring}'";
3444 
3445 #print "<pre>$cmd</pre>";
3446  # this should be embedded curl, but no clients as of 6/19/18 so moving on...
3447  $response = getcurl($cmd);
3448 
3449  if ("$response" > '') {
3450 #if ($pilot) { print htmlentities($response); exit; }
3451  if (!(is_numeric($response)) && !(preg_match("/Error/i", "$response"))) {
3452 # response isn't just an error code
3453 # and it doesn't contain an error message
3454  print "$response";
3455  exit;
3456  } elseif (!(preg_match("/-4/", "$response"))) {
3457 
3458 # response doesn't have a '-4 User not found' error embedded
3459 
3460  $title = $HB_ENV['MC']->msg('Unable to Log In');
3461  $message = $HB_ENV['MC']->msg('Unable to Log In') . "<br>" . $HB_ENV['MC']->msg('Please try again later');
3462 // $fragfile = '';
3463  } else {
3464  # Error -4 indicates not enrolled -- show the 'you need to sign up' page
3465  $title = 'Enrollment Required';
3466  $message = $HB_ENV['MC']->msg('Need Metavante');
3467 // $fragfile = "/home/$chome/public_html/nobillpayfrag";
3468 // $fragext = (trim("$Flang") == "en_US" ? "" : "_" . substr($Flang, 0, strpos($Flang, "_")) );
3469 // $fragfile .= ($fragext > "" && is_readable("{$fragfile}{$fragext}.html") ? "$fragext.html" : ".html");
3470  }
3471 
3472  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Close Window")}</button>";
3473 
3474  // set up the string substitution
3475  $noticeSubstitution = array(
3476  "#title#" => $title,
3477  "#service_name#" => "Metavante",
3478  "#service_type#" => "BillPay",
3479  "#vendor_name#" => "",
3480  "#display_content#" => $message,
3481  "#close_button#" => $cancelButton
3482  );
3483 
3484  // get any notice text
3485  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
3486  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectNoService');
3487 
3488  // make sure we got the notice
3489  if ($noticeInfo["status"]["code"] != "000" ||
3490  !count($noticeInfo["notice"]) ||
3491  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
3492  throw new Exception("Configuration Error: Custom Content (ConnectNoService)");
3493  }
3494 
3495  $noticeText = $noticeInfo['notice'][0]['notice_text'];
3496 
3497  ShowUserNotice($noticeText, array(), "", "");
3498  } else {
3499  # something went wrong -- couldn't open pipe
3500  $error["title"] = $HB_ENV['MC']->msg('Unable to Log In');
3501  $error["content"] = $HB_ENV['MC']->msg('Please try again later');
3502  throw new Exception(json_encode($error));
3503  }
3504  break;
3505  case "IPAY":
3506  if (!hcu_checkService($dbh, "IPAY")) {
3507  $omsg = hcu_checkServiceMsg($dbh, "IPAY");
3508  throw new Exception("$omsg");
3509  }
3510  #$bp_cuid = "34261";
3511  #$Cn = "1001641340";
3512  #$Cn = "550716762";
3513  #$bp_secret='test34261';
3514  #$key = substr(hash('SHA1','test34261',TRUE),0,16);
3515  // get the vendor settings
3516  $bp_cuid = HCU_array_key_value("bp_cuid", $parms);
3517  $bp_secret = HCU_array_key_value("bp_secret", $parms);
3518 
3519  if ($bp_secret == "" || $bp_cuid == "") {
3520  throw new Exception($HB_ENV['MC']->msg("Feature Not Set"));
3521  }
3522 
3523  $moc = HCU_array_key_value("moc", $parms);
3524  if ($moc == 0) {
3525  $serviceURL = HCU_array_key_value("serviceurl", $parms);
3526  $tokenURL = HCU_array_key_value("tokenurl", $parms);
3527  } else {
3528  $serviceURL = HCU_array_key_value("mocservice", $parms);
3529  $tokenURL = HCU_array_key_value("moctoken", $parms);
3530  }
3531  if (empty($serviceURL) || empty($tokenURL)) {
3532  throw new Exception($HB_ENV['MC']->msg("Feature Not Set"));
3533  }
3534 
3535  $billpayid = $mbrow["billpayid"];
3536 
3537  // use member id if no billpay-specific id
3538  if (trim($billpayid) == '') {
3539  $billpayid = $accountToUse;
3540  }
3541 
3542  $key = substr(hash('SHA1', $bp_secret, TRUE), 0, 16);
3543 
3544  // ENCRYPTION
3545  if($use_openssl_encryption) {
3546  list($ipay_token, $billpayid) = encrypt_billpay_openssl($billpayid, $key);
3547  } else {
3548  list($ipay_token, $billpayid) = encrypt_billpay_mcrypt($billpayid, $key);
3549  }
3550 
3551  #$ipay_session = @file_get_contents("https://www.billpaysite.com/request.asp?instid=$bp_cuid&p1=$ipay_token&op=Session&format=Text");
3552  // get the session token
3553  $ipay_url = "$tokenURL?instid=$bp_cuid&p1=$ipay_token&op=Session&format=Text";
3554 
3555  $cmd = "/usr/bin/curl --silent -H 'Content-Type: text/xml' '$ipay_url'";
3556 
3557  $ipay_session = getcurl($cmd);
3558 
3559  if ($parms["logging"] == "enabled") {
3560  $logParms = $parms["environment"]; // get the environment info passed in
3561  $logParms["token"] = $ipay_token; // the id used across all communications in session
3562  $logParms["txnId"] = time(); // the id for this transaction
3563  $logParms["logPoint"] = "IPAY get session"; // this action in a readable form
3564  $logParms["request"] = $cmd; // the request
3565  $logParms["reply"] = $ipay_session; // the response
3566  LogSSOActivity($logParms);
3567  }
3568 
3569  $ipay_session = trim(strip_tags($ipay_session));
3570 
3571  if ($ipay_session == '' || preg_match("/\D/", "$ipay_session")) {
3572  $error["title"] = "Connection to iPay Bill Pay service Failed";
3573  $error["content"] = "Please try again later or contact the credit union to report this error.<br>$ipay_session";
3574  throw new Exception(json_encode($error));
3575  } else {
3576  $stremail = ("{$HB_ENV["Ml"]}" == "" ? "" : "<input type='hidden' name='strEmail' value='{$HB_ENV["Ml"]}'>");
3577 
3578  if ($parms["logging"] == "enabled") {
3579  $logParms = $parms["environment"]; // get the environment info passed in
3580  $logParms["token"] = ''; // the id used across all communications in session
3581  $logParms["txnId"] = time(); // the id for this transaction
3582  $logParms["logPoint"] = "IPAY Redirect"; // this action in a readable form
3583  $logParms["request"] = "<form method=\"post\" name=\"SSOform\" action = \"$serviceURL?instid=$bp_cuid\">
3584  <input type=\"hidden\" name=\"p1\" value=\"$ipay_session\">
3585  <input type=\"hidden\" name=\"op\" value=\"Login\">
3586  <input type=\"hidden\" name=\"Method\" value=\"Session\">
3587  $stremail
3588  </form>"; // the request
3589  $logParms["reply"] = ''; // the response
3590  LogSSOActivity($logParms);
3591  }
3592 
3593  print <<<EOF
3594  <html>
3595  <body onload = "javascript:document.SSOform.submit();">
3596  <form method="post" name="SSOform" action = "$serviceURL?instid=$bp_cuid">
3597  <input type="hidden" name="p1" value="$ipay_session">
3598  <input type="hidden" name="op" value="Login">
3599  <input type="hidden" name="Method" value="Session">
3600  $stremail
3601  </form>
3602  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
3603  Loading Data..... Please Wait
3604  </div>
3605  </body>
3606  </html>
3607 EOF;
3608  }
3609 
3610  break;
3611  case "MDesk3":
3612  require_once('MDesk_API.i');
3613  require_once('hcuAuthShared.i');
3614 
3615  if (!hcu_checkService($dbh, "MDESK")) {
3616  $omsg = hcu_checkServiceMsg($dbh, "MDESK");
3617  throw new Exception("$omsg");
3618  }
3619  # previous check looks for all MDesk services down at server level
3620  # now look for MDesk service down for this particular client
3621  if (HCU_array_key_value('mxSvsDown',$parms)) {
3622  $omsg = (HCU_array_key_value('mxDownMsg',$parms) ? $parms['mxDownMsg'] : 'Service temporarily unavailable. Please try again later');
3623  throw new Exception("$omsg");
3624  }
3625  $dms_ok = array('mblsession' => 'digits');
3626  dms_import($dms_ok);
3627 
3628  # mdTokenKey used to hash Mx user key
3629  $mdtokenkey = HCU_array_key_value('mdTokenKey', $parms);
3630 
3631  if (empty($mdtokenkey)) {
3632  throw new Exception("Client misconfigured for remote Mx access", 912); # missing trusted detail parms (keys)
3633  }
3634 
3635  # default to production mode
3636  $testing = ( HCU_array_key_exists('testing', $parms) ? HCU_array_key_value('testing', $parms) : 0 );
3637 
3638  if ($testing) {
3639  # sharekey used by trusted vendor for hashing
3640  $mdkey = HCU_array_key_value('mdTestKey', $parms);
3641  $mdAPI_key = HCU_array_key_value('testAPIKey', $parms);
3642  $mdData_URL = HCU_array_key_value('testServerURL', $parms);
3643  $mdSso_URL = HCU_array_key_value('testSSOURL', $parms);
3644  $mdWidget_URL = HCU_array_key_value('testWidgetURL', $parms);
3645  $client_key_TTL = ( HCU_array_key_exists('mdTokenTTL', $parms) ? HCU_array_key_value('mdTokenTTL', $parms) : 86400 );
3646  } else {
3647  # sharekey used by trusted vendor for hashing
3648  $mdkey = HCU_array_key_value('mdShareKey', $parms);
3649  $mdAPI_key = HCU_array_key_value('APIKey', $parms);
3650  $mdData_URL = HCU_array_key_value('ServerURL', $parms);
3651  $mdSso_URL = HCU_array_key_value('SSOURL', $parms);
3652  $mdWidget_URL = HCU_array_key_value('WidgetURL', $parms);
3653  $client_key_TTL = ( HCU_array_key_exists('mdTokenTTL', $parms) ? HCU_array_key_value('mdTokenTTL', $parms) : 1800 );
3654  }
3655 
3656  if ( empty($mdkey) || empty($mdAPI_key) || empty($mdData_URL) || empty($mdSso_URL) || empty($mdWidget_URL) ) {
3657  throw new Exception("Client misconfigured for remote access", 903); # missing trusted detail parms (URL &/or API key)
3658  }
3659 
3660  $mdexpires = time() + $client_key_TTL;
3661 
3662  // build the timer token to be stored in Mx database
3663 # $Uid has the Odyssey Uid;
3664 # $Cn has the Odyssey user_name;
3665 # $accountToUse has the selected speedbump account
3666 
3667 // $HB_ENV["SYSENV"]["logger"]->info( "HB_ENV: " . print_r(array_diff_key($HB_ENV,array('MC' => 'drop', 'FeatureAccessList' => 'drop', 'SYSENV' => 'drop')),true) );
3668  # HB_ENV is built without the pwchange date - so go get our own copy of it
3669 // $pw_ary = GetPWChange($dbh, $Cu, $HB_ENV['Cn']);
3670 // if (!HCU_array_key_value('rowfound', $pw_ary)) {
3671 // throw new Exception("Invalid Member retrieving PWChange");
3672 // }
3673  $userrec = GetUserbyName($dbh, $Cu, $Cn);
3674  if (! HCU_array_key_value('rowfound', $userrec)) {
3675  throw new Exception("Invalid User");
3676  }
3677  $mxtoken = MakeV94Dkey($Cu, $Cn, $userrec, $client_key_TTL, $mdtokenkey, 'S');
3678  $mxUpdated = mdesk_sync($mdData_URL, $mdAPI_key, $Cu, $Uid, $Cn, $Ml, $mxtoken, $parms);
3679  if (HCU_array_key_value('code', $mxUpdated) > 0 ) {
3680  $status = HCU_array_key_value('status', $mxUpdated);
3681  $code = HCU_array_key_value('code', $mxUpdated);
3682  throw new Exception("Error ({$status} {$code}). Unable to connect to MoneyDesktop. Please contact the credit union");
3683  }
3684 
3685  # if mobile, get mobile_master_widget and set up w/ mobile-friendly
3686  # branding logo and div size
3687 
3688  # use 'platform' variable instead of mblsession as parameter, just for consistency
3689  $isapp = (integer) in_array(strtoupper(HCU_array_key_value('platform', $HB_ENV['HCUPOST'])), array('APP', 'ADA'));
3690  if ($isapp) {
3691  $widget = "mobile_master_widget";
3692  } else {
3693  $widget = "master_widget";
3694  $buttonText = $HB_ENV['MC']->msg("Return To Home Banking");
3695  $buttonClick = ($parms['hcuClose'] ? 'window.close();' : 'document.location="hcuAccounts.prg?cu=' . $Cu . '";');
3696 
3697  $mdbrand = "MDtoolbar_logo_md.png";
3698  if (is_readable("/home/$chome/public_html/$mdbrand")) {
3699  $mdsrc = "/fi/$chome/$mdbrand";
3700  } else {
3701  $mdsrc = "https://d1kryjpwpzirc7.cloudfront.net/homecu/images/MDtoolbar_logo_md.png";
3702  }
3703  }
3704 
3705  # get widget address from response
3706  $resparr = mdesk_getURL($mdSso_URL, $mdAPI_key, $Cu, $Uid, $widget, $parms);
3707  if (isset($resparr['error'])) {
3708  throw new Exception("Error ({$resparr['error']['message']}). Unable to retrieve URL for MoneyDesktop. Please contact the credit union");
3709  }
3710 
3711 # Configure menu so that mobile & app have $mblsession set, desktop does not
3712  if ($isapp) {
3713  $href = $resparr['url']['url'];
3714  } else {
3715  $login_url = $resparr['url']['url'];
3716 
3717  if (!$parms['hcuMenu']) {
3718 
3719  print <<<EOF
3720  <image src='$mdsrc' border=0>
3721  <button type='button' class='k-button' name='btnClose' onClick='$buttonClick'>{$buttonText}</button>
3722 EOF;
3723  }
3724 // <div class='md-widget' style='margin: 0' data-width="850" data-height="650" data-url="{$login_url}">
3725  print <<<EOF
3726  <script type="text/javascript" src="{$mdWidget_URL}"></script>
3727  <div class='md-widget' style='margin: 0' data-url="{$login_url}">
3728  </div>
3729 EOF;
3730 
3731  // so won't redirect
3732  $href = "";
3733  }
3734  break;
3735 
3736  case "VSOFT":
3737 
3738  # no clients on either VSOFT or VSHO as of June 2018
3739  # NOT UPGRADED FOR ODYSSEY YET
3740  #
3741  # If we get a client, this will take some work
3742  #
3743  # changes Sept '14 to re-activate VSOFT hybrid SSO
3744  //(calls 3rd party app, which must already be installed)
3745  // changes moved to new mobileConnect script instead
3746  // because hcuConnect calls upgrade code for speedbump, login timeout, etc
3747  // and that doesn't fit well in the mobile framework. Easier to
3748  // call mobile code than to tweak upgrade code for this one thing
3749  // left VSOFT mobile code here because it is intertwined with VSHO
3750  // MH 9/11/14
3751 
3752  // In the queries that follow for VSHO, $Cn is used to select the account number.
3753  // $Cn is the username which is not always an account number so the queries will
3754  // fail. The queries must be updated to use the user_id ($Uid) value instead of $Cn.
3755  // MGHandy: 9/5/18.
3756  case "VSHO":
3757  if (!hcu_checkService($dbh, 'VSOFT')) {
3758  $omsg = hcu_checkServiceMsg($dbh, "VSOFT");
3759  throw new Exception("$omsg");
3760  }
3761  # VSoft mobile -- activates App
3762  $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
3763  if (stripos($ua, 'android') === false && stripos($ua, 'iPhone') === false && stripos($ua, 'iPod') === false && stripos($ua, 'iPad') === false) {
3764  # not android and not iphone/ipod/ipad - no service
3765  throw new Exception("Feature Unavailable<BR>This feature is not supported on the device you are using");
3766  }
3767  # using cuusers.depositlimit to indicate Vsoft profile id
3768  $sql = "SELECT coalesce(depositlimit,0) FROM cuusers
3769  WHERE cu ='$Cu' and user_name='$Cn'";
3770  $img_rs = db_query($sql, $dbh);
3771 
3772  list($pro) = db_fetch_row($img_rs, 0);
3773  if ($pro == 0) {
3774  $message = "Account not permitted for Remote Deposit. Please contact the Credit Union for more information";
3775  throw new Exception($message);
3776  }
3777 
3778  $pro = sprintf("%d", intval($pro));
3779 
3780  # set defaults first, override by CU if needed
3781  $pilot = $parms["pilot"]; # pilot = 1 for test mode
3782 // $rtxn = $parms["rtxn"]; # deposit, loan pmt, credit card pmt
3783  $rtxn = ( sizeof($parms['rtxn']) == 0 ?
3784  array('AT' => 1, 'LP' => 1, 'CP' => 1) :
3785  json_decode($parms['rtxn'], TRUE) );
3786  $balwhere = $parms["balwhere"];
3787  $lnwhere = $parms["lnwhere"];
3788  $vs_id = $parms["vs_id"];
3789  $callbackurl = $parms["callbackurl"]; // for VSOFT
3790  $vsoftapp = $parms["vsoftapp"];
3791  $vsoftkey = $parms["vsoftkey"];
3792  /*
3793  switch ($Cu) {
3794  case "ACCLAIM":
3795  $rtxn=array("AT"=>1); # list of remote dep tran codes cu supports
3796  # use balwhere and lnwhere to adjust sql selection / limit chosen accts
3797  # ACCLAIM get open checking accounts only
3798  $balwhere=" and deposittype='Y' ";
3799  $lnwhere="";
3800  # institution ID provided by Vsoft
3801  $vs_id='142';
3802  $callbackurl='http://www.acclaimfcu.org/';
3803  #$tmode="test";
3804  break;
3805  }
3806  */
3807 # fetch transactions types
3808 
3809  $sql = "select ht.trancode, trim(t.trandesc),trim(ht.cudesc),t.specialproc
3810  from cutrans t, cuhavetrans ht where ht.cu='$Cu'
3811  and ht.trancode = t.trancode\n";
3812 
3813  $sth = db_query($sql, $dbh);
3814 
3815  $txncodes = array();
3816  for ($row = 0; list($code, $desc, $cudesc, $spec) = db_fetch_array($sth, $row); $row++) {
3817  $txncodes{$code} = array($desc, $spec, $cudesc);
3818  }
3819  db_free_result($sth);
3820 
3821  $sql = "";
3822  $verb = "";
3823 
3824  # find out how many valid accounts the member has:
3825 
3826  if ($txncodes{"AT"} && $rtxn{"AT"}) {
3827  # $txncodes is configured list @HomeCU - $rtxn is allowed list for remote vendor
3828  $sql = "SELECT description, trim(accounttype),
3829  case when upper(deposittype)='N' then '3'
3830  when upper(deposittype)='Y' then '1' end as rdctype,
3831  trim(micraccount) as micraccount
3832  FROM {$Cu}accountbalance
3833  WHERE accountnumber = '$Cn' $balwhere ";
3834 
3835  $verb = " UNION ";
3836  }
3837  # VSOFT only allows rdc to DDA, GL, SAVINGS, or MONEY MARKET - probably not loans
3838  # but left this older code in just in case service upgrades in the future MH 9/5/14
3839  if ($txncodes{"LP"} && $rtxn{"LP"}) {
3840 
3841  $sql .= "$verb
3842  SELECT description, trim(loannumber), '2', null
3843  FROM {$Cu}loanbalance
3844  WHERE accountnumber = '$Cn'
3845  AND currentbalance >0 $lnwhere ";
3846  if (($Fset2 & $CU2_SPEC18) == $CU2_SPEC18) {
3847  $sql .= " and (type <> '18' or type is null) ";
3848  if ($rtxn{"CP"}) {
3849  $sql .= "UNION
3850  SELECT description, trim(loannumber), '2', null
3851  FROM {$Cu}loanbalance
3852  WHERE accountnumber = '$Cn'
3853  AND type = '18' $lnwhere ";
3854  if (($Fset2 & $CU2_CC18SHOWZERO) != $CU2_CC18SHOWZERO) {
3855  $sql .= " and currentbalance > 0 ";
3856  }
3857  }
3858  }
3859  }
3860 
3861  $acct_rs = db_query($sql, $dbh);
3862 
3863  if (db_num_rows($acct_rs) == 0) {
3864  #print_r($rtxn);
3865  throw new Exception("No valid accounts found");
3866  }
3867 
3868  #
3869  # if more than one checking account found, let member select account
3870  # (even though VSHO would accept list, Joe says make 'em pick so it is
3871  # consistent w/ the VSOFT (mobile) SSO)
3872  # format $vsoft location string based on query results & fire off the vsoft app
3873  #
3874  # InstID will be assigned by vsoft
3875  # ProfileId is $pro (cuusers.depositlimit formatted integer)
3876  # AccountNumber is micraccount
3877  # UserId is $Cn
3878  # Email is $Ml
3879  # AccountType is 1 (DDA)
3880  # Description is accountbalance.description trimmed to 50 char & urlencoded
3881  # using rawurlencode instead of urlencode so that space becomes %20, not +
3882 
3883  $dms_ok = array('selacct' => 'string');
3884  dms_import_v2($HB_ENV, "HCUPOST", $dms_ok);
3885  $selacct = $HB_ENV["HCUPOST"]["selacct"];
3886 
3887  #
3888  $option = $HB_ENV["HCUPOST"]["option"];
3889 
3890  if ($option == "") {
3891  $err_msg = "";
3892 
3893  if (db_num_rows($acct_rs) > 1) {
3894  $descTtl = "Select an account for remote deposit";
3895  $pageTtl = "Online Remote Deposit";
3896 
3897  // set up the list of account choices
3898  $arySelectList = array();
3899  for ($row = 0; list($desc, $atype, $rdctype, $micr) = db_fetch_array($acct_rs, $row); $row++) {
3900  $displaydesc = rawurlencode(substr($desc, 0, 50) . " - $atype");
3901  $udesc = rawurlencode(substr($desc, 0, 50));
3902  $tokn = sha1("{$mode}{$Cn}{$atype}{$Cu}{$rdctype}{$micr}{$udesc}obl1vi0u5");
3903  $value = "$rdctype|$atype|$micr|$udesc|$tokn";
3904 
3905  $arySelectList[] = array("get_value" => $value,
3906  "display" => rawurldecode($displaydesc));
3907  }
3908 
3909  $selectAccountString = "";
3910  $count = count($arySelectList);
3911  if ($count > 0) {
3912  $idx = 1;
3913  $checked = $count == 1 ? "checked" : "";
3914  foreach ($arySelectList as $acct_key => $acct_array) {
3915  $selectAccountString .="<input type='radio' name='selacct' id='response{$idx}' {$checked} value='{$acct_array['get_value']}'/><label style='padding: 10px;' for='response{$idx}'>{$acct_array['display']}</label><br>";
3916  $idx++;
3917  }
3918  }
3919 
3920  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Cancel")}</button>";
3921  $continueButtonText = $HB_ENV['MC']->msg("Continue");
3922  // if the button needs to trigger a check of the radio buttons to make sure one selected, it must call CkRadio()
3923  $continueButton = "<button type='button' class='k-button' name='btnContinue' onClick='javascript:CkRadio();return false;'>$continueButtonText</button>";
3924  $buttons = "{$cancelButton} &nbsp; &nbsp; {$continueButton}";
3925 
3926  // set up the string substitution
3927  $acceptance = ""; // not needed for this form
3928 
3929  $noticeSubstitution = array(
3930  "#page_title#" => $pageTtl,
3931  "#description#" => $descTtl,
3932  "#content#" => $selectAccountString,
3933  "#acceptance#" => $acceptance,
3934  "#buttons#" => $buttons
3935  );
3936 
3937  // get any notice text
3938  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
3939  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectSpeedbump');
3940 
3941  // make sure we got the notice
3942  if ($noticeInfo["status"]["code"] != "000" ||
3943  !count($noticeInfo["notice"]) ||
3944  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
3945  throw new Exception("Configuration Error: Custom Content (ConnectSpeedbump)");
3946  }
3947 
3948  $noticeText = $noticeInfo['notice'][0]['notice_text'];
3949 
3950  $inputList = array(array("name" => "mode", "value" => "$mode"),
3951  array("name" => "option", "value" => "DEPOSIT")
3952  );
3953  $checkMsg = "Please choose an account before continuing.";
3954  $radioGroupName = "selacct";
3955  ShowUserNotice($noticeText, $inputList, $radioGroupName, $checkMsg);
3956 
3957  break; # if more than one account stop after printing screen.
3958  # if only one, allow to fall through for DEPOSIT option
3959  } else {
3960  list($desc, $atype, $rdctype, $micr) = db_fetch_row($acct_rs, 0);
3961  $udesc = rawurlencode(substr($desc, 0, 50));
3962  $tokn = sha1("{$mode}{$Cn}{$atype}{$Cu}{$rdctype}{$micr}{$udesc}obl1vi0u5");
3963  $selacct = "$rdctype|$atype|$micr|$udesc|$tokn";
3964  $option = "DEPOSIT";
3965  }
3966  }
3967 
3968  if ($option == "DEPOSIT") {
3969  list($rdctype, $atype, $micr, $udesc, $tokn) = explode("|", $selacct);
3970  if ($selacct == "" ||
3971  $tokn <> sha1("{$mode}{$Cn}{$atype}{$Cu}{$rdctype}{$micr}{$udesc}obl1vi0u5")) {
3972  throw new Exception("Invalid Account Selected");
3973  }
3974 
3975 
3976  if ($mode == 'VSOFT') {
3977  $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
3978  if (stripos($ua, 'iPhone') !== false || stripos($ua, 'iPod') !== false || stripos($ua, 'iPad') !== false || stripos($ua, 'android') !== false) {
3979 
3980  $vsoftqry = "userid=$Cn&instid=$vs_id&profileid=$pro&accountdesc=";
3981  $vsoftqry .= rawurldecode($udesc);
3982  $vsoftqry .= "&accounttype=$rdctype";
3983  $vsoftqry .= (trim($Ml) == '' ? "" : "&email=" . trim($Ml));
3984  $vsoftqry .= "&accountnumber=" . ("$micr" == "" ? $Cn : $micr);
3985  $vsoftqry .= ("$callbackurl" == "" ? "" : "&callbackurl=$callbackurl");
3986 
3987  $vsoftkey = $parms["vsoftkey"];
3988 
3989  // ENCRYPTION
3990  if($use_openssl_encryption) {
3991  list($vsoftenc, $vsoftqry) = encrypt_vsoftquery_openssl($vsoftqry, $vsoftkey);
3992  } else {
3993  list($vsoftenc, $vsoftqry) = encrypt_vsoftquery_mcrypt($vsoftqry, $vsoftkey);
3994  }
3995 
3996  } else {
3997  # not android and not iphone/ipod/ipad - no service
3998  # checked above so should never get here, but just in case....
3999  throw new Exception("This feature is not supported on the device you are using");
4000  }
4001 
4002  # print "header('Location: $vsoft');";
4003  print <<<EOF
4004  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
4005  Please wait - Calling App"
4006  </div>
4007  <script>
4008  {
4009  location.replace("{$vsoftapp}?$vsoftenc");
4010  }
4011  </script>
4012 EOF;
4013 
4014  exit;
4015  }
4016 
4017  if ($mode == 'VSHO') {
4018  /*
4019  * NOTE: VSHO has not been tested yet. This code was ported from RemoteDep where it wasn't tested there either.
4020  */
4021  # this option not tested yet 10/4/2012
4022  # figure out how to build hash
4023  # per Jim Bray 12/4/12 No Hash
4024  #$hash='';
4025  # build $parms array containing info for XML
4026  #$VSHOhost="demo1.vsoftcorp.com";
4027  $parms['InstId'] = $vs_id;
4028  $parms['UserId'] = $Cn;
4029  $parms['ProfileId'] = $pro;
4030  $parms['UserName'] = '';
4031  $parms['email'] = trim($Ml);
4032  $parms['AccountNumber'] = ("$micr" == "" ? $Cn : $micr);
4033  $parms['AccountType'] = $rdctype;
4034  $parms['AccountDesc'] = $udesc;
4035  $parms['AccountStatus'] = '';
4036  #$parms['Hash']=$hash;
4037  # format XML for Soap call, post SOAP and get response
4038  $vsho = VSHO_XML($parms, $VSHOhost);
4039  if (empty($vsho['sessionId'])) {
4040  $msg = "Could not open Remote Deposit Service ";
4041  if (!empty($vsho['errorMessage'])) {
4042  $msg .= "(error: {$vsho['errorMessage']})";
4043  }
4044  NoService($msg);
4045  } else {
4046  # redirect to VSHO URL
4047  # value from documentation
4048  #$vshourl="https://{$VSHOhost}/HomeOffice/HomeOffice.aspx?SessionId="
4049  # value from Jim Bray 12/4/12
4050  $vshourl = "https://scbctest.creditunionimages.com/homeoffice/HomeOfficeService.asmx?SessionId=";
4051  $vshourl .= urlencode($vsho['sessionId']);
4052  print <<<EOF
4053  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
4054  Please wait - contacting Remote Deposit Service
4055  </div>
4056  <script>
4057  {
4058  location.replace("$vshourl");
4059  }
4060  </script>
4061 EOF;
4062  exit;
4063  }
4064  }
4065  }
4066 
4067  // so won't redirect
4068  $href = "";
4069  break;
4070  case "Digital":
4071  /*
4072  * Updated specs 3/27/2014. Appears encryption/decryption works, no accounts to test
4073  * with until Electel gets up and running a little.
4074  * Code added 3/18/14 based on specs provided June 2013.
4075  * crypted value matches example exactly using test values, but remote side still
4076  * responds 'SSO: The parameter string is incorrect or could not be decrypted'. Might just be
4077  * that test value for date is very old, but even with current date gets error.
4078  * Not sure why, but waiting for new client to sign contract before contacting vendor to debug
4079  *
4080  * 3/18/14 MH
4081  *
4082  */
4083  if (!hcu_checkService($dbh, "Digital")) {
4084  $omsg = hcu_checkServiceMsg($dbh, "Digital");
4085  throw new Exception("$omsg");
4086  exit;
4087  }
4088  $pilot = HCU_array_key_value('pilot',$parms);
4089  if ($pilot == 1) {
4090  $serviceurl = HCU_array_key_value('piloturl',$parms);
4091  $servicepass = HCU_array_key_value('pilotpass',$parms);
4092  $servicekey = HCU_array_key_value('pilotkey',$parms);
4093  } else {
4094  $serviceurl = HCU_array_key_value('produrl',$parms);
4095  $servicepass = HCU_array_key_value('prodpass',$parms);
4096  $servicekey = HCU_array_key_value('prodkey',$parms);
4097  }
4098  $CustID = HCU_array_key_value('CustID',$parms);
4099  $ACCOUNT = $accountToUse;
4100  if (empty($serviceurl) || empty($servicepass) || empty($servicekey) ||
4101  empty($CustID) || empty($ACCOUNT)) {
4102  throw new Exception("Missing Parameters");
4103  }
4104  $currdate = gmdate('YmdHi'); # using GMT
4105  $GMT = 1; # notify digital that we are using GMT
4106 
4107 
4108  $srcstring = "ACCOUNT={$ACCOUNT}&TIMESTAMP={$currdate}&CID={$CustID}&PASS={$servicepass}&GMT={$GMT}";
4109 
4110  // ENCRYPTION
4111  if($use_openssl_encryption) {
4112  list($dm_token, $srcstring) = encrypt_digital_openssl($srcstring, $servicekey);
4113  } else {
4114  list($dm_token, $srcstring) = encrypt_digital_mcrypt($srcstring, $servicekey);
4115  }
4116 
4117  $DATA = "";
4118  for ($i = 0; $i < strlen($dm_token); $i++) {
4119  $DATA .= substr('00' . dechex(ord(substr($dm_token, $i, 1))), -2);
4120  }
4121  $DATA = strtoupper($DATA);
4122 
4123  $href = "{$serviceurl}?C=$CustID&DATA=$DATA";
4124 
4125  if ($parms["logging"] == "enabled") {
4126  $logParms = $parms["environment"]; // get the environment info passed in
4127  $logParms["token"] = ''; // the id used across all communications in session
4128  $logParms["txnId"] = time(); // the id for this transaction
4129  $logParms["logPoint"] = "Digital ES SSO"; // this action in a readable form
4130  $logParms["request"] = $href; // the request
4131  $logParms["reply"] = ''; // the response
4132  LogSSOActivity($logParms);
4133  }
4134 
4135  break;
4136  case "BDI":
4137  /*
4138  * E-Statement SSO for Prospectors FCU
4139  * 12/20/16 MH
4140  *
4141  */
4142  if (!hcu_checkService($dbh, "BDI")) {
4143  $omsg = hcu_checkServiceMsg($dbh, "BDI");
4144  throw new Exception("$omsg");
4145  exit;
4146  }
4147  $pilot = HCU_array_key_value('pilot',$parms);
4148  if ($pilot == 1) {
4149  $serviceurl = HCU_array_key_value('pilotURL',$parms);
4150  $servicekey = HCU_array_key_value('pilotKEY',$parms);
4151  } else {
4152  $serviceurl = HCU_array_key_value('prodURL',$parms);
4153  $servicekey = HCU_array_key_value('prodKEY',$parms);
4154  }
4155  $VendorID = HCU_array_key_value('VendorID', $parms);
4156  $serviceurl = str_replace("#FIID#",$parms['FIID'],$serviceurl);
4157  $servicekey = base64_decode($servicekey);
4158 
4159  # use a random IV instead?
4160  $method = 'AES-256-CBC';
4161  $ivlen = openssl_cipher_iv_length($method);
4162  $IV = openssl_random_pseudo_bytes ( $ivlen );
4163 // $IV = base64_decode($parms['IV']);
4164  $Member = $accountToUse;
4165  $tStamp = gmdate('U');
4166 
4167  # test values
4168 // $servicekey=base64_decode("hsZoZqQGt3wpdgqJKkRaluZ3FG+2IDZYTSx0eVctJ0c=");
4169 // $IV = base64_decode('3P2XNcPLMMw9l+KkbAKX3g==');
4170 // $Member="0000012345";
4171 // $tStamp = '1482201149';
4172 // $serviceurl = 'https://estmt.businessdatainc.com/ProspectorsFCU/SSOLogonRequest.do?VID=HomeCU&Number=0000012345&Name=&Emails=test+user@yahoo.com&T=1482201149&IV=3P2XNcPLMMw9l+KkbAKX3g==&SKEY=ppQCy5HCuBb77u//iw6B8AQTpmm7AGtMTZH9xz6qm0s='
4173 // $serviceurl = "https://estmt.businessdatainc.com/{$FIID}/SSOLogonRequest.do?VID=$VendorID";
4174 // $servicepass='R$ax&He0'; # didn't need this - only used to secure the zip file containing credentials
4175 // $servicekey="hsZoZqQGt3wpdgqJKkRaluZ3FG+2IDZYTSx0eVctJ0c=";
4176 
4177  $srcstring = "{$Member}{$tStamp}";
4178 // $srcstring = "00000123451482201149";
4179 
4180  $method = 'AES-256-CBC';
4181  # openssl appears to do it's own padding
4182 // $ivlen = openssl_cipher_iv_length($method);
4183 // $pad = $ivlen - (strlen($srcstring) % $ivlen);
4184 // $srcssl = ($srcstring . str_repeat(chr($pad),$pad));
4185 # if manually paddding, use OPENSSL_ZERO_PADDING flag on encrypt,
4186 # otherwise adds another full block of pad characters
4187 
4188  $SKEY = (openssl_encrypt($srcstring,$method,$servicekey,0,$IV));
4189 
4190 // $emsg='';
4191 // while ($msg = openssl_error_string())
4192 // $emsg .= $msg . "<br />\n";
4193 
4194  $href = "{$serviceurl}?VID={$VendorID}&Number={$Member}&Emails=";
4195  $href .= urlencode($Ml);
4196  $href .= "&T={$tStamp}&IV=";
4197  $href .= urlencode(base64_encode($IV));
4198  $href .= "&SKEY=";
4199  $href .= urlencode($SKEY);
4200 
4201 // if ($emsg != '') {
4202 // $showurl = 1;
4203 // $href .= "<br>$emsg";
4204 // }
4205 
4206  if ($parms["logging"] == "enabled") {
4207  $logParms = $parms["environment"]; // get the environment info passed in
4208  $logParms["token"] = ''; // the id used across all communications in session
4209  $logParms["txnId"] = time(); // the id for this transaction
4210  $logParms["logPoint"] = "BDI SSO"; // this action in a readable form
4211  $logParms["request"] = $href; // the request
4212  while ($msg = openssl_error_string())
4213  $logParms["request"] .= "<br />\n$msg";
4214  $logParms["reply"] = ''; // the response
4215  LogSSOActivity($logParms);
4216  }
4217 
4218  break;
4219 
4220 
4221  case "DELUXE_OP":
4222  if (!hcu_checkService($dbh, "Deluxe")) {
4223  $omsg = hcu_checkServiceMsg($dbh, "Deluxe");
4224  throw new Exception("$omsg");
4225  }
4226 
4227  if ($HB_ENV["HCUPOST"]["option"] == 'SELECTACCT') {
4228  $dms_ok = Array("sendmicr" => "string");
4229 
4230  dms_import_v2($HB_ENV, "HCUPOST", $dms_ok);
4231 
4232  if (!sizeof($HB_ENV["HCUPOST"]["sendmicr"])) {
4233  throw new Exception("No Account Selected");
4234  }
4235  #
4236  list($rt, $micr, $tokn, $rtype) = explode("|", $HB_ENV['HCUPOST']['sendmicr']);
4237  if ("{$HB_ENV['HCUPOST']['sendmicr']}" == "" ||
4238  $tokn <> sha1("${mode}${Cn}${rt}${micr}${Cu}obl1vi0u5")) {
4239  throw new Exception("Invalid Account Selected");
4240  }
4241 
4242  $pilot = $parms['pilot'];
4243  $HCUserv = urlencode($parms['HCUserv']);
4244  $HCUpass = urlencode($parms['HCUpass']);
4245  $certfile = $parms['certfile'];
4246  $passwd = $parms['passwd'];
4247  if ($pilot) {
4248  $server = $parms['pilotserver'];
4249  } else {
4250  $server = $parms['prodserver'];
4251  }
4252  if ("$passwd" == "") {
4253  throw new Exception($HB_ENV['MC']->msg('Feature Not Set'));
4254  exit;
4255  }
4256  if (empty($HCUserv) || empty($passwd) || empty($certfile) || !(is_readable($certfile)) || empty($server)) {
4257  throw new Exception("Missing Parameters");
4258  }
4259 
4260  list($gyr, $gmo, $gda, $ghr, $gmin) = explode(",", gmdate("Y,n,j,G,i"));
4261  $gyr = $gyr - 1900;
4262  $gmo = $gmo - 1;
4263  $gmin = intval($gmin);
4264 
4265  switch ($Cu) {
4266  case "TEST":
4267  $pgmname = "";
4268  break;
4269 
4270  case "TCCU":
4271  # TCCU passes BILLING_CODE 'U' and PROFILE_NUMBER '00002'for suffix 84
4272  # update to OrderPoint - send <ProgramName>UNLIMITED CHECKING</ProgramName> for suffix 84
4273  if ($rtype == '84') {
4274  $pgmname = "UNLIMITED CHECKING";
4275  } else {
4276  $pgmname = "";
4277  }
4278  break;
4279  default:
4280  $pgmname = "";
4281  break;
4282  }
4283  $xml = '<?xml version="1.0" encoding="UTF-8"?><Deluxe Version="7.0">';
4284  $xml .= "<DeluxePort><ChkOrdAddRq><RqUID>$HCUserv</RqUID><ChkOrdInfo><DepAcctId><AcctId>$micr</AcctId><AcctType>DDA</AcctType>";
4285  $xml .= "<BankInfo><BankIdType>ABA</BankIdType><BankId>$rt</BankId></BankInfo><Program><ProgramName>$pgmname</ProgramName></Program>";
4286  $xml .= "</DepAcctId></ChkOrdInfo></ChkOrdAddRq></DeluxePort></Deluxe>";
4287 
4288  /*
4289  * Deluxe Orderpoint is not really expecting xml data as xml, they are expecting
4290  * a form variable NAMED xml_data containing url-encoded xml string.
4291  * Deluxe returns a web page, we use curl to capture the headers, then strip out
4292  * a url and token from the location redirect, and also the LTPAToken from a set-cookie.
4293  */
4294  $cmd = "/usr/bin/curl -i --silent --data 'xml_data=$xml' --data 'app=orderpoint' -E $certfile:$passwd '$server'";
4295 
4296 #print "<pre>$cmd</pre>";exit;
4297  $fd = popen("$cmd", "r");
4298  if ($fd) {
4299  do {
4300  $data = @fread($fd, 8192);
4301  if (strlen($data) == 0) {
4302  break;
4303  }
4304  $response .= $data;
4305  } while (true);
4306 
4307  pclose($fd);
4308 
4309  if ($parms["logging"] == "enabled") {
4310  $logParms = $parms["environment"]; // get the environment info passed in
4311  $logParms["token"] = ''; // the id used across all communications in session
4312  $logParms["txnId"] = time(); // the id for this transaction
4313  $logParms["logPoint"] = "DELUXE_OP SSO"; // this action in a readable form
4314  $logParms["request"] = $cmd; // the request
4315  $logParms["reply"] = $response; // the response
4316  LogSSOActivity($logParms);
4317  }
4318 
4319  /*
4320  * Deluxe no longer returns an error. You just get a redirect page whether everything worked... or not.
4321  * left the code in just in case they fix that some day
4322  */
4323 
4324  if (!("$response" > '') || strtoupper(trim($response)) == "ERROR") {
4325  throw new Exception("Deluxe Connection Failed ($response)");
4326  } else {
4327  $dHEAD = preg_split('/\r\n|\n|\r/', $response, NULL, PREG_SPLIT_NO_EMPTY);
4328  foreach ($dHEAD as $fparm) {
4329  if (substr(strtoupper($fparm), 0, 9) == 'LOCATION:')
4330  $dLOC = substr($fparm, 10);
4331 
4332  if (substr(strtoupper($fparm), 0, 21) == 'SET-COOKIE: LTPATOKEN') {
4333  $dLtpa = substr($fparm, 22);
4334  $dLtpa = substr($dLtpa, 0, strpos($dLtpa, ';'));
4335  }
4336  }
4337  list($dURL, $dTOKEN) = explode("?", $dLOC, 2);
4338  $dPARMS = explode("&", rtrim($dTOKEN));
4339  $formopts = "";
4340  foreach ($dPARMS as $ptokn) {
4341  list($dNAME, $dVAL) = explode("=", $ptokn, 2);
4342  $formopts .= "<input type='hidden' name='$dNAME' value='$dVAL'>\n";
4343  }
4344  $formopts .= "<input type='hidden' name='LtpaToken' value='$dLtpa'>\n";
4345  $response = rtrim($response);
4346  print <<<EOF
4347 <html>
4348 <head>
4349 <title>
4350 Internet Check Ordering
4351 </title>
4352 <script language="JavaScript">
4353 function submitToDeluxe()
4354 {
4355 document.redirectionForm.action="$dURL";
4356 document.redirectionForm.submit();
4357 }
4358 </script>
4359 </head>
4360 <body onLoad="submitToDeluxe()">
4361 <form name="redirectionForm" method="POST">
4362 $formopts
4363 </form>
4364 </body>
4365 </html>
4366 EOF;
4367  }
4368  } else {
4369 # something went wrong -- couldn't open pipe to DELUXE
4370  throw new Exception("Deluxe Connection Failed");
4371  }
4372  } else {
4373 
4374  # get the list of valid checking accounts
4375 
4376  $acctlist = array();
4377 
4378  if (empty($mbrow['rt']) || preg_match("/\D/", $mbrow['rt'])) {
4379  throw new Exception('Missing parameters');
4380  }
4381 
4382 
4383 # find out how many valid primary checking accounts the member has:
4384  $sql = "
4385  SELECT
4386  ab.description,
4387  TRIM(ab.accountnumber),
4388  TRIM(ab.accounttype),
4389  TRIM(ab.micraccount),
4390  ab.certnumber,
4391  TRIM(ua.display_name)
4392  FROM ${Cu}accountbalance ab
4393  LEFT JOIN ${Cu}useraccounts ua
4394  ON ab.accountnumber = ua.accountnumber
4395  AND ab.accounttype = ua.accounttype
4396  AND ab.certnumber = ua.certnumber
4397  WHERE ua.user_id = $Uid
4398  AND UPPER(ab.deposittype) = 'Y'
4399  AND ab.accounttype not like '%@%' ";
4400  if (isset($parms['sqlwhere'])) {
4401  $sql .= " {$parms['sqlwhere']} ";
4402  }
4403 
4404  $acct_rs = db_query($sql, $dbh);
4405 
4406  if (db_num_rows($acct_rs) > 0) {
4407  $rt = $mbrow['rt'];
4408  # now see if there is an override micr for each account, but only if for the current $rt
4409  # (no check orders for outdated rt)
4410  # checked the table 9/24/15 no null or empty rt so this should work
4411  for ($row = 0; list($desc, $anumber, $atype, $ab_micr, $cert, $disp) = db_fetch_array($acct_rs, $row); $row++) {
4412  $om_sql = "
4413  SELECT TRIM(rt), TRIM(micraccount)
4414  FROM cuovermicr
4415  WHERE cu='$Cu'
4416  AND accountnumber='$anumber'
4417  AND accounttype='$atype'
4418  AND rt = '$rt'
4419  ORDER BY startcheck DESC LIMIT 1;";
4420 
4421  $om_rs = db_query($om_sql, $dbh);
4422  if (db_num_rows($om_rs) == 1) {
4423  list($om_rt, $om_micr) = db_fetch_array($om_rs, 0);
4424  if (isset($parms['micrsize']) && $parms['micrsize'] > 0) {
4425  $micr = substr(str_repeat('0', $parms['micrsize']) . $om_micr, (-1 * $parms['micrsize']), $parms['micrsize']);
4426  } else {
4427  $micr = $om_micr;
4428  }
4429  } else {
4430  if (trim($ab_micr) != '') {
4431  if (isset($parms['micrsize']) && $parms['micrsize'] > 0) {
4432  $micr = substr(str_repeat('0', $parms['micrsize']) . $ab_micr, (-1 * $parms['micrsize']), $parms['micrsize']);
4433  } else {
4434  $micr = $ab_micr;
4435  }
4436  }
4437  }
4438 
4439  if (trim($micr) != '') {
4440  $tokn = sha1("${mode}${Cn}${rt}${micr}${Cu}obl1vi0u5");
4441  $acctlistDesc = getAccountDescription($dbh, $HB_ENV['Cu'], $anumber, $desc, $atype, $disp, $HB_ENV['Fset3'], $cert);
4442 
4443  // On Mammoth, the users were not allowed to have multiple account access
4444  // preventing some accounts from being shown because the $acctlist key was
4445  // only the account type. When multiple sub-accounts had the same account type
4446  // the data from the previous account would be over written.
4447 
4448  // We use the account number and account type now to make the acctlist key more
4449  // unique to avoid overwritten data.
4450  $acctlistKey = "$anumber|$atype|$cert";
4451  $acctlist[$acctlistKey]['display'] = $acctlistDesc . ": {$rt} {$micr}";
4452  $acctlist[$acctlistKey]['getvalue'] = "$rt|$micr|$tokn|$atype";
4453  }
4454  }
4455  }
4456  if (!sizeof($acctlist)) {
4457  throw new Exception("No valid checking accounts found");
4458  }
4459  $descTtl = '<div style="text-align: center;" class="k-header">Verify the routing numbers on the bottom of your check match the information shown for your account.</div>
4460 <div style="text-align: center;"><span style="text-decoration: underline;">If the information does not match please contact the Credit Union to order checks.</span></div>';
4461  $pageTtl = "Please select an account to Order Checks";
4462 
4463  // set up the list of account choices
4464  $selectAccountString = "";
4465  $count = count($acctlist);
4466  if ($count > 0) {
4467  $idx = 1;
4468  $checked = $count == 1 ? "checked" : "";
4469  foreach ($acctlist as $acct_key => $acct_array) {
4470  $selectAccountString .="<input type='radio' name='sendmicr' id='response{$idx}' {$checked} value='{$acct_array['getvalue']}'/><label style='padding: 10px;' for='response{$idx}'>{$acct_array['display']}</label><br>";
4471  $idx++;
4472  }
4473  }
4474 
4475  $selectAccountString .= '
4476  <p style="margin: 10px 0px 10px 0px; text-align: left;"></p>
4477  <p style="margin: 10px 0px 10px 0px; text-align: left; display: inline-block;">See example below for help finding the routing information on your check.<br />
4478  <br /><img src="https://d1kryjpwpzirc7.cloudfront.net/homecu/images/odyssey/micr.gif" border="0" /></p>';
4479 
4480  $cancelButton = "<button type='button' class='k-button' name='btnCancel' onClick='window.close();'>{$HB_ENV['MC']->msg("Cancel")}</button>";
4481  $continueButtonText = "Continue";
4482  // if the button needs to trigger a check of the radio buttons to make sure one selected, it must call CkRadio()
4483  $continueButton = "<button type='button' class='k-button' name='btnContinue' onClick='javascript:CkRadio();return false;'>$continueButtonText</button>";
4484  $buttons = "{$cancelButton} &nbsp; &nbsp; {$continueButton}";
4485 
4486  // set up the string substitution
4487  $acceptance = ""; // not needed for this form
4488 
4489  $noticeSubstitution = array(
4490  "#page_title#" => $pageTtl,
4491  "#description#" => $descTtl,
4492  "#content#" => $selectAccountString,
4493  "#acceptance#" => $acceptance,
4494  "#buttons#" => $buttons
4495  );
4496 
4497  /*
4498  * present a list of eligible checking accounts and descriptions
4499  * render as radio (select one only).
4500  */
4501  // get any notice text
4502  $HB_ENV["noticeStrReplace"] = $noticeSubstitution;
4503  $noticeInfo = Get_NoticeInfo($dbh, $HB_ENV, $HB_ENV['MC'], 'D', 'ConnectSpeedbump');
4504 
4505  // make sure we got the notice
4506  if ($noticeInfo["status"]["code"] != "000" ||
4507  !count($noticeInfo["notice"]) ||
4508  strlen($noticeInfo["notice"][0]["notice_text"]) == 0) {
4509  throw new Exception("Configuration Error: Custom Content (ConnectSpeedbump)");
4510  }
4511 
4512  $noticeText = $noticeInfo['notice'][0]['notice_text'];
4513 
4514  $inputList = array(array("name" => "mode", "value" => "$mode"),
4515  array("name" => "option", "value" => "SELECTACCT")
4516  );
4517  $checkMsg = "Please choose the checking account to use.";
4518  $radioGroupName = "sendmicr";
4519  ShowUserNotice($noticeText, $inputList, $radioGroupName, $checkMsg);
4520  }
4521  break;
4522  case "ThinkDigital":
4523  if (!hcu_checkService($dbh, "ThinkDigital")) {
4524  $omsg = hcu_checkServiceMsg($dbh, "ThinkDigital");
4525  throw new Exception("$omsg");
4526  }
4527  $test = HCU_array_key_value('test', $parms);
4528  if ($test == 0) {
4529  $serviceInst = HCU_array_key_value("TestInstID", $parms);
4530  $serviceKey = HCU_array_key_value("TestKey", $parms);
4531  $serviceUrl = HCU_array_key_value("TestURL", $parms);
4532  } else {
4533  $serviceInst = HCU_array_key_value("ProdInstID", $parms);
4534  $serviceKey = HCU_array_key_value("ProdKey", $parms);
4535  $serviceUrl = HCU_array_key_value("ProdURL", $parms);
4536  }
4537  $serviceReqid = HCU_array_key_value("ReqID", $parms);
4538 
4539  if (empty($serviceInst) || empty($serviceKey) || empty($serviceUrl) ||
4540  empty($serviceReqid) ) {
4541  throw new Exception("Missing Settings");
4542  }
4543 // # for testing use 3376
4544 // $Cn = '3376';
4545 # key is plain string, not hex
4546 // $key = "";
4547 // for ($i = 0; $i < strlen($serviceKey); $i+=2) {
4548 // $key .= chr(hexdec(substr($serviceKey, $i, 2)));
4549 // }
4550 
4551  $date = gmdate("Ymd");
4552  $ustr = $serviceInst . $accountToUse . $serviceReqid . $date;
4553  $mac = hash_hmac('MD5', $ustr, $serviceKey);
4554 
4555  $href = "$serviceUrl?InstID=$serviceInst&ReqID=$serviceReqid&Account=$accountToUse&MAC=$mac";
4556 
4557  if ($parms["logging"] == "enabled") {
4558  $logParms = $parms["environment"]; // get the environment info passed in
4559  $logParms["token"] = ''; // the id used across all communications in session
4560  $logParms["txnId"] = time(); // the id for this transaction
4561  $logParms["logPoint"] = "ThinkDigital SSO"; // this action in a readable form
4562  $logParms["request"] = $href; // the request
4563  $logParms["reply"] = ''; // the response
4564  LogSSOActivity($logParms);
4565  }
4566 
4567  break;
4568 
4569  case "hcuLoanApp":
4570  /**
4571  * 9/6/2018
4572  * Expanding hcuLoanApp to work for both desktop and mobile apps
4573  * Desktop **
4574  * This will use the speed bump code to select an account prior to
4575  * redirecting to the eforms/AppMain.prg
4576  * The cookie is already created for this instance.
4577  *
4578  * Mobile App **
4579  * This method does not have a banking cookie in the local browser,
4580  * but it should already have the account selected. In order for the
4581  * SSO handshake with the loan system we will need to first create
4582  * a cookie to the browser then redirect to the URL
4583  */
4584  #
4585  # not updated yet
4586  # need Odyssey method for stale & expires
4587  # look for Odyssey method of building cookie
4588  #
4589  /*
4590  * NOTE at the top of Mammoth hcuConnect this block of code is used
4591  * to do a different type of credential check. This or something similar
4592  * will be needed on Odyssey as well. Be sure to address that, and
4593  * the Validate_Userkey function when updating the hcuLoanApp block
4594  *
4595  *
4596  } else if ($_REQUEST['mode'] == 'hcuLoanApp') {
4597  $serviceSkipCredentials = true;
4598  $serviceSkipSecurity = true;
4599  if (!empty($_REQUEST['USERKEY']) && !empty($_REQUEST['cu'])) {
4600  $tokenOK = Validate_Userkey($_REQUEST['cu'], $_REQUEST['USERKEY']);
4601  if (!$tokenOK['status']['response']) {
4602  throw new Exception('Unauthorized Access ' . $tokenOK['status']['message']);
4603  } else {
4604  $serviceSkipCredentials = true;
4605  $serviceSkipSecurity = true;
4606 
4607  $HB_ENV['cu'] = $_REQUEST['cu'];
4608  $MEMBER = $tokenOK['status']['member'];
4609  $CAUTH = $tokenOK['status']['cauth'];
4610  }
4611  }
4612 */
4613  if (!hcu_checkService($dbh, "hcuLoanApp")) {
4614  $omsg = hcu_checkServiceMsg($dbh, "hcuLoanApp");
4615  throw new Exception("$omsg");
4616  exit;
4617  }
4618 
4619  /**
4620  * ** CREATE BANKING COOKIE **
4621  * ** MOBILE APP ONLY
4622  */
4623  if (false && "MOBILE APP ONLY") {
4624  // we need to build a cookie for the loan app to authenticate with
4625  $now = time();
4626  $stale = $now + $GLOBALS['staleafter'];
4627  $expires = $now + $GLOBALS['TicketExpires'];
4628 
4629  $mycookie = "Ctime=$now&Cu=${HB_ENV['Cu']}&Cn=${HB_ENV['Cn']}&Ce=$expires&Cauth=${CAUTH}&Ffchg=${HB_ENV['Ffchg']}&Ffremain=${HB_ENV['Ffremain']}&Fset=${HB_ENV['Fset']}&Fset2=${HB_ENV['Fset2']}&Fset3=${HB_ENV['Fset3']}&Fhdays=${HB_ENV['Fhdays']}&Flite=0&Clw=${HB_ENV['Clw']}&Clu=${HB_ENV['Clu']}&Fplog=${HB_ENV['Fplog']}&Fflog=${HB_ENV['Fflog']}&Fmsg_tx=${HB_ENV['Fmsg_tx']}&Ml=${HB_ENV['Ml']}&Flang=$Flang&Ffreset=${HB_ENV['Ffreset']}";
4630 
4631  SetTicket("", $mycookie);
4632  }
4633  /**
4634  * ** REDIRECT TO LOAN SYSTEM **
4635  */
4636 
4637  /** * CREATE SELECTED ACCOUNT HASH * **/
4638  $encryptedAccount = hcu_encrypturl( $accountToUse, $HB_ENV['historyHash'] );
4639 
4640  /** * CREATE URL * **/
4641  // get the url
4642  $serviceurl = $parms['URL'];
4643 
4644  // get the app id
4645  $appID = urlencode($parms['lnAppId']);
4646 
4647  // put them together
4648  $href = "{$serviceurl}&id={$appID}&cu=$Cu&acct=$encryptedAccount";
4649 
4650  if ($parms["hcuLogging"] == "enabled") {
4651  $logParms = $parms["environment"]; // get the environment info passed in
4652  $logParms["token"] = ''; // the id used across all communications in session
4653  $logParms["txnId"] = time(); // the id for this transaction
4654  $logParms["logPoint"] = "HCU Loan App"; // this action in a readable form
4655  $logParms["request"] = $href; // the request
4656  $logParms["reply"] = '';
4657  LogSSOActivity($logParms);
4658  }
4659  // ** Clean output buffer
4660  ob_clean();
4661  header("Location: $href");
4662  exit;
4663  break;
4664 
4665  case "FISERV_CPS":
4666  if (!hcu_checkService($dbh, "FISERV")) {
4667  $omsg = hcu_checkServiceMsg($dbh, "FISERV");
4668  throw new Exception("$omsg");
4669  }
4670  $pilot = HCU_array_key_value('pilot', $parms);
4671  if ($pilot) {
4672  $fsOrg = HCU_array_key_value('pilotOrgid', $parms);
4673  $fsLogo = HCU_array_key_value('pilotCuLogo', $parms);
4674  $fsURL = HCU_array_key_value('piloturl', $parms);
4675  $fsCert = HCU_array_key_value('pilotcert', $parms);
4676  $fsPass = HCU_array_key_value('pilotpass', $parms);
4677  } else {
4678  $fsOrg = HCU_array_key_value('prodOrgid', $parms);
4679  $fsLogo = HCU_array_key_value('prodCuLogo', $parms);
4680  $fsURL = HCU_array_key_value('produrl', $parms);
4681  $fsCert = HCU_array_key_value('prodcert', $parms);
4682  $fsPass = HCU_array_key_value('prodpass', $parms);
4683  }
4684 
4685  $fsOrg = (empty($fsOrg) ? '000' : sprintf('%3d',intval($fsOrg)));
4686  $fsLogo = (empty($fsLogo) ? '000' : sprintf('%3d',intval($fsLogo)));
4687  $fsMember = $fsOrg . $fsLogo . substr("0000000000000$accountToUse",-13,13);
4688 
4689  if(empty($fsURL) || empty($fsCert) || empty($fsPass) ) {
4690  throw new Exception('Missing Settings');
4691  }
4692 
4693 // $fsAuth = "$fsURL?ReqType=ME&memberID=$fsMember&email=" . urlencode($Ml);
4694 // $fsAuth = "$fsURL?ReqType=ME&memberID=$fsMember&email=$Ml";
4695 
4696  $fsData = array('ReqType'=>'ME',
4697  'memberID'=>$fsMember,
4698  'email'=>$Ml);
4699 
4700  $response = "";
4701  $ch = curl_init();
4702 
4703  $curlopts = array(
4704  CURLOPT_RETURNTRANSFER => 1,
4705  CURLOPT_POST => 1,
4706  CURLOPT_URL => $fsURL,
4707  CURLOPT_SSLCERT => $fsCert);
4708  if ($ch) {
4709  curl_setopt_array($ch, $curlopts);
4710  if (!empty($fsPass) ) {
4711  curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $fsPass);
4712  }
4713  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fsData));
4714 
4715  $response = curl_exec($ch);
4716  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
4717  $respCURL = curl_errno($ch);
4718  curl_close($ch);
4719  }
4720  if ($parms["logging"] == "enabled") {
4721  $logParms = $parms["environment"]; // get the environment info passed in
4722  $logParms["token"] = ''; // the id used across all communications in session
4723  $logParms["txnId"] = time(); // the id for this transaction
4724  $logParms["logPoint"] = "FiservCPS Auth"; // this action in a readable form
4725  $logParms["request"] = "curl --request POST --data '" . http_build_query($fsData) . " -E '{$fsCert}" . (empty($fsPass) ? "'" : ":{$fsPass}'") . " '$fsURL'"; // the request
4726  $logParms["reply"] = $response; // the response
4727  LogSSOActivity($logParms);
4728  }
4729 
4730  if ($respCURL) {
4731  throw new Exception("HCUERROR: Connection Failed (cURL $respCURL)");
4732  } elseif ($respHTTP > 400) {
4733  throw new Exception("HCUERROR: (http $respHTTP)" . (empty($response) ? '' : " $response"));
4734  } elseif (!isset($response) || $response == '') {
4735  throw new Exception("HCUERROR: Empty Response (http $respHTTP)");
4736  } elseif (stripos($response,"ERROR_TEXT")) {
4737  # check return for error, show DE_ERROR_TEXT
4738  $respERR = stristr($response, "DE_ERROR_TEXT");
4739  throw new Exception("HCUERROR: (fiserv $respERR)");
4740  } else {
4741  # got a valid url -
4742  $href = $response;
4743  }
4744 
4745  break;
4746 
4747  case "MeridianLink":
4748 
4749  /*
4750  * API credentials as provided by Meridian Link
4751  * links go to a page that shows the apiUser and apiPassword
4752  * seem to be missing the SSO domain,
4753  * unless the domain showing is what to use?
4754  *
4755  * also, that lender code gets passed on the url.
4756  * not sure that will work out well.
4757 
4758 DEMO
4759 https://demo.loanspq.com/partners/SecureHtmlPageViewer.aspx?id=7190a699-6020-4c51-a277-8fa2412bdc11
4760 Link expires: 3/29/2017 8:06:57 AM
4761 
4762 LIVE
4763 https://cs.loanspq.com/partners/SecureHtmlPageViewer.aspx?id=e5cf9fdc-83c6-4957-879f-265d759ba2a9
4764 Link expires: 3/29/2017 8:06:57 AM
4765 
4766 Lender Code: LoneStarCU?N7q?º€m?ÂÓ8??=Á÷ù}?[?w?ÁÕ?¢w?µ???À?
4767  *
4768  */
4769 
4770  # this needs to have a function to run curl, catch errors
4771  # first call is to get consumer resource url
4772  # next need to get SSO Token
4773  # third, redirect with token.
4774  if (!hcu_checkService($dbh, "MeridianLink")) {
4775  $omsg = hcu_checkServiceMsg($dbh, "MeridianLink");
4776  throw new Exception("$omsg");
4777  }
4778  $pilot = HCU_array_key_value('pilot', $parms);
4779  if ($pilot) {
4780  $apiUser = HCU_array_key_value('pilotUser', $parms);
4781  $apiPass = HCU_array_key_value('pilotPass', $parms);
4782  $mlURL = HCU_array_key_value('piloturl', $parms);
4783  $mlLender = HCU_array_key_value('pilotlender', $parms);
4784  $ssoURL = HCU_array_key_value('pilotsso', $parms);
4785  } else {
4786  $apiUser = HCU_array_key_value('prodUser', $parms);
4787  $apiPass = HCU_array_key_value('prodPass', $parms);
4788  $mlURL = HCU_array_key_value('produrl', $parms);
4789  $mlLender = HCU_array_key_value('prodlender', $parms);
4790  $ssoURL = HCU_array_key_value('prodsso', $parms);
4791  }
4792 
4793  if (empty($apiUser) || empty($apiPass) || empty($mlURL) ||
4794  empty($mlLender) || empty($ssoURL) ) {
4795  throw new Exception('Missing Settings');
4796  }
4797 
4798 // $getConsumerResource = "https://$mlURL/services/resources.ashx/fis/$mlLender/consumers?MemberNumber=$Cn";
4799  $getConsumerResource = "$mlURL?MemberNumber=$accountToUse";
4800  $curlopts = array(
4801  CURLOPT_RETURNTRANSFER => 1,
4802  CURLOPT_URL => "$getConsumerResource",
4803  CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
4804  CURLOPT_USERPWD => "{$apiUser}:{$apiPass}");
4805  $parms['mlcall'] = 'GetConsumerResource';
4806 
4807  $response = merlink_embcurl($parms, $curlopts, '');
4808  if ($response['Status'] == 'Fail') {
4809  throw new Exception("{$response['Error']}");
4810  }
4811  # got a valid consumer resource url
4812  # next need to get SSO Token
4813  $curlopts[CURLOPT_URL] = ($response['MLinkDATA'] . '/ssotoken');
4814  $parms['mlcall'] = 'GetSSOToken';
4815  $response = merlink_embcurl($parms, $curlopts, '');
4816  if ($response['Status'] == 'Fail') {
4817  throw new Exception("{$response['Error']}");
4818  }
4819  # got a valid SSO Token
4820  # make sure the Token is not empty, and redirect
4821  $ssoToken = $response['MLinkDATA'];
4822  if (empty($ssoToken)) {
4823  throw new Exception("Meridian Link got Empty Token");
4824  }
4825 #
4826 # does $Ml need url_decoded? Submitting the form should encode it, will that be double?
4827 #
4828  print <<<EOF
4829  <html>
4830  <body onload = "javascript:document.SSOform.submit();">
4831  <form method="post" name="SSOform" action = "{$ssoURL}">
4832  <input type="hidden" name="SSOToken" value="{$ssoToken}">
4833  <input type="hidden" name="Email" value="$Ml">
4834  </form>
4835  </body>
4836  </html>
4837 EOF;
4838 
4839  break;
4840 
4841  case "WebShare":
4842 
4843 # generate a sha hash for member & timestamp using secret key
4844 # open iframe / div to load URL containing hash
4845 
4846  if (!hcu_checkService($dbh, "WebShare")) {
4847  $omsg = hcu_checkServiceMsg($dbh, "WebShare");
4848  throw new Exception("$omsg");
4849  }
4850  $pilot = HCU_array_key_value('pilot', $parms);
4851  if ($pilot) {
4852  $wsURL = HCU_array_key_value('piloturl', $parms);
4853  $wsKey = HCU_array_key_value('pilotkey', $parms);
4854  } else {
4855  $wsURL = HCU_array_key_value('produrl', $parms);
4856  $wsKey = HCU_array_key_value('prodkey', $parms);
4857  }
4858  if (empty($wsURL) || empty($wsKey) ) {
4859  throw new Exception("Missing Settings");
4860  }
4861  /*
4862  * date format is important! because it is used to hash
4863  * format used for hashing must be 'Y-m-d\TH:i:s\Z'
4864  * format passed on URL may vary, but represents same point in time
4865  *
4866  * example on page 4 uses
4867  * gmdate('n/j/Y h:i:s A'); * 3/7/2015 12:28:41 AM
4868  * but code examples on page 6 use
4869  * gmdate('Y-m-d H:i:s P'); * 2017-02-10 18:30:48 +00:00
4870  * and referenced RFC3339 would use
4871  * gmdate ('Y-m-d\TH:i:sP') * 2017-02-17T22:49:16+00:00
4872  * but Bluepoint uses a literal 'Z' instead of offset, so...
4873  * gmdate('Y-m-d\TH:i:s\Z') * 2017-02-17T22:49:16Z
4874  *
4875  */
4876 
4877 // for testing only
4878 // $Cn = '22797624';
4879 // $Cn = '999999';
4880 
4881  $rfcdate = gmdate('Y-m-d\TH:i:s\Z');
4882  $reqdate = rawurlencode($rfcdate);
4883  $rfc = $accountToUse . $rfcdate . $wsKey; #'L0n3$tarw3B';
4884  $hash = base64url_encode(openssl_digest($rfc,'sha512', true));
4885 
4886  $dataURL = "{$wsURL}/?m={$accountToUse}&t={$reqdate}&h=$hash";
4887 
4888  if ($parms["logging"] == "enabled") {
4889  $logParms = $parms["environment"]; // get the environment info passed in
4890  $logParms["token"] = ""; // the id used across all communications in session
4891  $logParms["txnId"] = time(); // the id for this transaction
4892  $logParms["logPoint"] = "WebShare"; // this action in a readable form
4893  $logParms["request"] = "{$accountToUse}{$reqdate}{$wsKey}\n$dataURL"; // the request
4894  $logParms["reply"] = ''; // the response
4895  LogSSOActivity($logParms);
4896  }
4897  // for testing only
4898 // $dataURL = 'https://webshare.lonestarcu.org/Bluepoint.ECM.WebShare/#/?m=32364061&t=12%2F30%2F2016%205:31:28%20PM&h=JZwywUBSU1NjpBtV1Hy6jaJ0dX-BdJcPudHGOs1vRhAeoVVnAAI1hmLQ-rLXJzjVKtOMofl4MQ9IoBURpGiXfw';
4899 // if we need to load a logo...
4900 // $mdbrand = "MDtoolbar_logo_md.png";
4901 // if (is_readable("/home/$chome/public_html/$mdbrand")) {
4902 // $mdsrc = "/fi/$chome/$mdbrand";
4903 // } else {
4904 // $mdsrc = "/IMAGES/$mdbrand";
4905 // }
4906 
4907 // if we need a button to close the window
4908 // $buttonText = $MC->msg("Return To Home Banking");
4909 
4910  print <<<EOF
4911  <div style="margin: 0;">
4912  <iframe src="$dataURL" width='100%' height='500'></iframe>
4913  </div>
4914 EOF;
4915 
4916  // so won't redirect
4917  $href = "";
4918  break;
4919  default:
4920  # none of the connection modes matched, throw an error
4921  throw new Exception("Invalid Connection Mode");
4922  break;
4923  }
4924 
4925  /**** I BELIEVE this is the end of the switch. ****/
4926 
4927  if ($href != '') {
4928  if ($showurl) {
4929  print "Location: $href <br>";
4930  } else {
4931  print <<<EOF
4932  <div style='font-size: 28px; text-align:center; padding-left: 40px; padding-right: 40px; padding-top: 40px;'>
4933  Loading Data..... Please Wait
4934  </div>
4935  <script>
4936  {
4937  location.replace("$href");
4938  }
4939  </script>
4940 EOF;
4941  }
4942  }
4943 
4944  } catch (Exception $ex) {
4945  //Return error message
4946  $thisPageErrors = $ex->getMessage();
4947 // $thisPageErrors = "(" . $ex->getline() . ") " . $ex->getMessage();
4948  $errorObject = json_decode($thisPageErrors);
4949 
4950  $serviceErrorTitle = "";
4951  if ( $errorObject ) {
4952  $serviceErrorMsg = strlen( $errorObject->content ) > 0 ? $errorObject->content : $thisPageErrors;
4953 
4954  if ( strlen( $errorObject->title ) ) {
4955  $serviceErrorTitle = $errorObject->title;
4956  }
4957  } else {
4958  $serviceErrorMsg = $thisPageErrors;
4959  }
4960 
4961 
4962  // * Include the Error page and finish
4963  // 916 includes 'close window' button
4964  // 915 does not
4965  if ($serviceShowMenu || $HB_ENV['HCUPOST']['vanilla']) {
4966  $serviceErrorCode = '915';
4967  } else {
4968  $serviceErrorCode = '916';
4969  }
4970 
4971 
4972  require_once('hcuErrorPage.i');
4973  }
4974 
4975  if ($usePrePostcontent) {
4976  require_once('hcuPostContent.i');
4977  }
4978 
4979 
4980 /**
4981  * Helper for switch ALLIED_SSO
4982  * @return array
4983  */
4984 function AlliedSsoServiceFlags() {
4985 
4986  $apVanilla = '';
4987  $apPlatform = '';
4988 
4989  if (isset($_REQUEST['vanilla']) && (trim($_REQUEST['vanilla']) == 1)) {
4990  $apVanilla = 1;
4991  }
4992 
4993  if (
4994  isset($_REQUEST['platform']) &&
4995  (
4996  (strtoupper(trim($_REQUEST['platform'])) == 'APP') ||
4997  (strtoupper(trim($_REQUEST['platform'])) == 'ADA')
4998  )
4999  ) {
5000  $apPlatform = 'APP';
5001  }
5002 
5003  if (($apVanilla == 1) || ($apPlatform == 'APP')) {
5004  // $service load menu, service show menu, service show info
5005  return [false, false, false];
5006  }
5007 
5008  // $service load menu, service show menu, service show info
5009  return [false, false, true];
5010 
5011 }
5012 
5013 function NoService($whynot) {
5014 /*
5015  global $HB_ENV;
5016  cu_header($HB_ENV['MC']->msg('Feature Unavailable'));
5017  print "<CENTER><BR><TABLE BORDER=0 CELLSPACING=0 WIDTH=90%>
5018  <tr><td CLASS=bar align=center>" . $HB_ENV['MC']->msg('Feature Unavailable') . "<br></td></tr>
5019  <tr><td CLASS='usu' align=center>$whynot<br></td></tr>
5020  <tr><td CLASS='usu' align='center'><br>&nbsp;<form>
5021 <script language=\"JavaScript\"><!--
5022 if (window.close)
5023  document.write('<input type=\"button\" value=\"" .
5024  $HB_ENV['MC']->js_msg('Close Window') .
5025  "\" onClick=\"window.close()\">');
5026 //--></script>
5027  </form>&nbsp;</td></tr></table>";
5028  *
5029  */
5030  throw new Exception( $whynot );
5031 }
5032 
5033 /**
5034  * expects $saywhat as array returned from Get_NoticeInfo
5035  * displays notice_text with notice_answers
5036  * posts back to self with option=SPEEDBUMP, which causes Update_NoticeInfo call
5037  **/
5038 function Speedbump($saywhat) {
5039  global $mode;
5040  global $Flang;
5041 
5042  foreach ($saywhat['notice'] as $noticekey => $noticearray) {
5043  // There should only be one
5044  if ($noticearray['notice_type'] == 'C') {
5045  $notice_answers = "";
5046  $notice_type = ($noticearray['notice_answertype'] == 'O' ? 'radio' : 'checkbox');
5047  if (count($noticearray['notice_answers']) > 0) {
5048  foreach ($noticearray['notice_answers'] as $notice_answer_key => $notice_answer_array) {
5049  $notice_answers .="<input type='{$notice_type}' name='notice_response[]' id='response{$notice_answer_array['answer_id']}' value='{$notice_answer_array['answer_id']}'/><label for='response{$notice_answer_array['answer_id']}'>{$notice_answer_array['answer_text']}</label>";
5050  }
5051  }
5052  $notice_answers = "<div style='text-align:center'>
5053  <fieldset>
5054  {$notice_answers}
5055  </fieldset>
5056  </div>";
5057  $notice_donotshow = '';
5058  $notice_votebutton = "<input type='button' name='btnCancel' value='Cancel' onClick='window.close();'>";
5059  $notice_votebutton .= "<input type='submit' name='btnContinue' value='Continue'>";
5060  print <<< CONTENTS
5061  <div class='hdrl' >
5062  <div style='padding:10px'>
5063  {$noticearray['notice_text']}
5064  </div>
5065 
5066  <form id='formTransferNotice{$noticekey}' action="{$_SERVER['PHP_SELF']}?{$_SERVER['QUERY_STRING']}" method="post">
5067  <input type='hidden' name='btnClose' value='1'>
5068  <input type='hidden' name='option' value='SPEEDBUMP'><BR>
5069  <input type='hidden' name='mode' value='$mode'><BR>
5070  <input type='hidden' name='notice_type' value='{$noticearray['notice_type']}'>
5071  <input type='hidden' name='notice_id' value='{$noticearray['notice_id']}'>
5072  <input type='hidden' name='notice_device' value='C'>
5073  {$notice_answers}
5074  {$notice_donotshow}
5075  <div align='center' class=''>
5076  <fieldset>
5077  {$notice_votebutton}
5078  </fieldset>
5079  </div>
5080  </form>
5081  </div>
5082 
5083 CONTENTS;
5084 
5085 // <form id='formTransferNotice{$noticekey}' method='post' action='{$_SERVER['PHP_SELF']}?cu=$Cu&mode=$mode&Flang=$Flang&option=SPEEDBUMP'>
5086  break;
5087  }
5088  }
5089 }
5090 /**
5091  * expect arySelectList array
5092  * ['acctlist'][$acctkey]['display'] = label to be displayed for each account in acctlist array
5093  * ['acctlist'][$acctkey]['getvalue'] = value to be returned when this account is selected
5094  * ['message_text'] = screen prompt to be displayed, also used as nag message if nothing is selected
5095  *
5096  * may need to adjust to allow for header_text, footer_text?
5097  *
5098  * screen includes heading using 'message_text'
5099  * screen includes radio group 'selacct' with radio button for each account in 'acctlist'
5100  * screen includes Cancel button to close window
5101  * screen includes Continue button to post back to self with selected radio item, option=SELACCT,
5102  * mode=[requesting mode], query string = requesting query string
5103 
5104 **/
5105 
5106 function SelectData($arySelectList) {
5107  global $mode;
5108  global $Flang;
5109  global $HB_ENV;
5110 
5111  $select_accounts = "";
5112  $continue_button = "<input type='button' name='btnCancel' value='" . $HB_ENV['MC']->msg('Cancel') . "' onClick='window.close();'>";
5113  $continue_button .= "&nbsp;&nbsp;&nbsp;&nbsp;";
5114  $continue_button .= "<input type='submit' id='btnContinue' name='btnContinue' value='" . $HB_ENV['MC']->msg('Continue') . "' onClick='javascript:CkRadio();return false;'>";
5115  if (count($arySelectList['acctlist']) > 0) {
5116  $idx = 1;
5117  foreach ($arySelectList['acctlist'] as $acct_key => $acct_array) {
5118  $select_accounts .="<input type='radio' name='selacct' id='response{$idx}' value='{$acct_array['getvalue']}'/><label for='response{$idx}'>{$acct_array['display']}</label><br>";
5119  $idx++;
5120  }
5121  }
5122  $select_accounts = "<div style='text-align:left; padding:15px'>
5123  {$select_accounts}
5124  </div>";
5125 // be aware that the mustmsg defined below may be overwritten in the MWI_Pagetop fragment
5126  print <<< CONTENTS
5127  <script>
5128  var mustmsg='Please choose the loan you wish to pay';
5129  </script>
5130  <div class='hdrl' >
5131  <div style='padding:3px'>
5132  {$arySelectList['notice'][0]['notice_text']}
5133  </div>
5134 
5135  <form name='formSelectAccount' id='formSelectAccount' action="{$_SERVER['PHP_SELF']}?{$_SERVER['QUERY_STRING']}" method="post">
5136  <input type='hidden' name='option' value='SELECTACCT'><BR>
5137  <input type='hidden' name='mode' value='$mode'>
5138  <fieldset>
5139  {$select_accounts}
5140  <div align='center' class=''>
5141  {$continue_button}
5142  </div>
5143  </fieldset>
5144  </form>
5145  <script>
5146 
5147  function CkRadio() {
5148  var somethingChecked = false;
5149  var radioGroup = document.formSelectAccount.selacct;
5150  if ( radioGroup.length ) {
5151  for (i = 0; i < radioGroup.length; i++) {
5152  if (radioGroup[i].checked) {
5153  somethingChecked = true;
5154  }
5155  }
5156  } else if ( radioGroup.checked ) {
5157  somethingChecked = true;
5158  }
5159  if (!somethingChecked) {
5160  window.alert(mustmsg);
5161  return false;
5162  } else {
5163  document.formSelectAccount.submit();
5164  }
5165  }
5166  </script>
5167 
5168  </div>
5169 
5170 CONTENTS;
5171 }
5172 
5173 /* This is a generic function that will show something to the user and ask for their input. The notice text is
5174  * already set up prior to calling. If there is an input list, that is the form variables to be passed on. The
5175  * radio button group is the name of the radio buttons for verifying one has been selected and if not the
5176  * checkMsg is shown. If no radio button group, then no check is done. Any buttons are passed in as part of the
5177  * notice text.
5178  * Generally this is used to select an account before continuing, or to show a failure with custom content.
5179  */
5180 function ShowUserNotice($noticeText, $inputList, $radioButtonGroup, $checkMsg) {
5181  // Change some styles in case user is viewing from a mobile device since some 3rd party solutions are
5182  // only available to mobile users and the Mobile Web doesn't have a native interface to them (e.g. VSOFT).
5183  if ( $GLOBALS['viewportAllowed'] ) {
5184  print '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />';
5185  }
5186 
5187  print <<< CONTENTS
5188  <style>
5189 @media only screen and (max-width: 767px) {
5190  body { min-width: 100px; }
5191  #main { min-width: 100px; }
5192  #submenu { display: none; }
5193  #content div { font-size: large; }
5194  #content button { display: block; width: 100%; }
5195  #topbar { margin-top:80px; }
5196 }
5197  </style>
5198  <script>
5199  var mustmsg='$checkMsg';
5200  </script>
5201  <form name='formSelectAccount' id='formSelectAccount' action="{$_SERVER['PHP_SELF']}?{$_SERVER['QUERY_STRING']}" method="post">
5202 CONTENTS;
5203 
5204  // add the input name/value pairs that get sent with the form POST
5205  for ( $i = 0; $i < count( $inputList ); $i++ ) {
5206  print "<input type='hidden' name='{$inputList[$i]["name"]}' value='{$inputList[$i]["value"]}'>\n";
5207  }
5208 
5209  // add the text, buttons, and check function
5210  print <<< CONTENTS
5211  {$noticeText}
5212  </form>
5213 CONTENTS;
5214 
5215  // only need this function if there is a radio button group
5216  if ( $radioButtonGroup ) {
5217  print <<< CONTENTS
5218  <script>
5219  function CkRadio() {
5220  var somethingChecked = false;
5221  var radioGroup = document.formSelectAccount.{$radioButtonGroup};
5222  if ( radioGroup.length ) {
5223  for (i = 0; i < radioGroup.length; i++) {
5224  if (radioGroup[i].checked) {
5225  somethingChecked = true;
5226  }
5227  }
5228  } else if ( radioGroup.checked ) {
5229  somethingChecked = true;
5230  }
5231  if (!somethingChecked) {
5232  window.alert(mustmsg);
5233  return false;
5234  } else {
5235  document.formSelectAccount.submit();
5236  }
5237  }
5238  </script>
5239 CONTENTS;
5240  }
5241 }
5242 
5243 
5244 /**
5245  * @param array $HB_ENV @todo this is an unused variable, already too many params
5246  * @param array $MIR
5247  * @param string $ipay_instid
5248  * @param string $ipay_iv
5249  * @param string $ipay_key
5250  * @param string $ipay_token
5251  * @param string $random
5252  * @param string $billpayid
5253  * @param string $ml
5254  * @param null|int $enrollmicr
5255  * @param int $micr
5256  * @return string
5257  * @throws Exception
5258  */
5259 function iPayEnrollXML($HB_ENV, $MIR, $ipay_instid, $ipay_iv, $ipay_key, $ipay_token, $random, $billpayid, $ml, $enrollmicr = null, $micr = 0) {
5260 
5261  $Email = (empty($MIR["data"]["email"]) ? $ml : $MIR["data"]["email"]);
5262 
5263  $msg = '';
5264  if (empty($MIR["data"]["accountnumber"])) {
5265  $msg .= 'AccountNumber ';
5266  }
5267  if (empty($MIR["data"]["firstname"])) {
5268  $msg .= 'FirstName ';
5269  }
5270  if (empty($MIR["data"]["lastname"])) {
5271  $msg .= 'LastName ';
5272  }
5273  if (empty($Email)) {
5274  $msg .= 'Email ';
5275  }
5276  if (empty($MIR["data"]["address1"])) {
5277  $msg .= 'Address1 ';
5278  }
5279  if (empty($MIR["data"]["city"])) {
5280  $msg .= 'City ';
5281  }
5282  if (empty($MIR["data"]["state"])) {
5283  $msg .= 'State ';
5284  }
5285  if (empty($MIR["data"]["zip"])) {
5286  $msg .= 'Zip ';
5287  }
5288 #
5289  if (empty($MIR["data"]["accountnumber"]) ||
5290  empty($MIR["data"]["firstname"]) ||
5291  empty($MIR["data"]["lastname"]) ||
5292  empty($Email) ||
5293  empty($MIR["data"]["address1"]) ||
5294  empty($MIR["data"]["city"]) ||
5295  empty($MIR["data"]["state"]) ||
5296  empty($MIR["data"]["zip"])) {
5297  throw new Exception("Not enough info to enroll ($msg)");
5298  }
5299  # try to enroll
5300  # generate a new authtoken and random, encrypt the ssn, try to enroll
5301 # $rdate=gmdate("Ymd H:i:s");
5302 # $random=gmdate("U");
5303 # list($ipay_token,$iv)=EncryptCredentials("{$ipay_instid};{$rdate}",$ipay_key,$ipay_iv);
5304  if (!empty($MIR["data"]["ssn"])) {
5305  list($EncryptedSSN, $iv) = EncryptCredentials("{$MIR["data"]["ssn"]}", $ipay_key, $ipay_iv);
5306  }
5307 
5308  if (strtotime($MIR["data"]["dob"])) {
5309  $DOB = date('Y-m-d', strtotime($MIR["data"]["dob"]));
5310  } else {
5311  $DOB = '';
5312  }
5313 
5314  $enroll = "<Message>\n";
5315  $enroll .= "<InstitutionID>$ipay_instid</InstitutionID>\n";
5316  $enroll .= "<Security>\n";
5317  $enroll .= "<IV>$ipay_iv</IV>\n";
5318  $enroll .= "<AuthToken>$ipay_token</AuthToken>\n";
5319  $enroll .= "</Security>\n";
5320  $enroll .= "<MessageRequest>\n";
5321  $enroll .= "<RequestID>$random</RequestID>\n";
5322  $enroll .= "<SubscriberCreate>\n";
5323  $enroll .= "<Info>\n";
5324  $enroll .= "<UserID>$billpayid</UserID>\n";
5325  $enroll .= "<UserType>2</UserType>\n";
5326  $enroll .= "</Info>\n";
5327  $enroll .= "<Data>\n";
5328  $enroll .= "<Subscriber>\n";
5329  $enroll .= "<FIAdminApproval>0</FIAdminApproval>\n";
5330  $enroll .= "<LoginID>$billpayid</LoginID>\n";
5331 # values from the MIR packet
5332  $enroll .= "<FirstName>{$MIR["data"]["firstname"]}</FirstName>\n";
5333  if (isset($MIR["data"]["middlename"])) {
5334  $enroll .= "<MiddleName>{$MIR["data"]["middlename"]}</MiddleName>\n";
5335  }
5336  $enroll .= "<LastName>{$MIR["data"]["lastname"]}</LastName>\n";
5337  $enroll .= "<Email>$Email</Email>\n";
5338  if (isset($MIR["data"]["homephone"])) {
5339  $enroll .= "<HomePhone>{$MIR["data"]["homephone"]}</HomePhone>\n";
5340  }
5341  if (isset($MIR["data"]["workphone"])) {
5342  $enroll .= "<WorkPhone>{$MIR["data"]["workphone"]}</WorkPhone>\n";
5343  }
5344  if (isset($MIR["data"]["fax"])) {
5345  $enroll .= "<Fax>{$MIR["data"]["fax"]}</Fax>\n";
5346  }
5347  $enroll .= "<SSN>$EncryptedSSN</SSN>\n";
5348 
5349  if ($enrollmicr) {
5350  $enroll .= "<AccountNumber>{$micr}</AccountNumber>\n";
5351  } else {
5352  $enroll .= "<AccountNumber>{$MIR['data']['accountnumber']}</AccountNumber>\n";
5353  }
5354 
5355 
5356  $enroll .= "<AccountType>1</AccountType>\n";
5357  $enroll .= "<Address1>{$MIR["data"]["address1"]}</Address1>\n";
5358  if (isset($MIR["data"]["address2"])) {
5359  $enroll .= "<Address2>{$MIR["data"]["address2"]}</Address2>\n";
5360  }
5361  $enroll .= "<City>{$MIR["data"]["city"]}</City>\n";
5362  $enroll .= "<State>{$MIR["data"]["state"]}</State>\n";
5363  $enroll .= "<Zip>{$MIR["data"]["zip"]}</Zip>\n";
5364  if ($DOB <> "") {
5365  $enroll .= "<DateOfBirth>$DOB</DateOfBirth>\n";
5366  }
5367 # end of MIR values
5368  $enroll .= "</Subscriber>\n";
5369  $enroll .= "</Data>\n";
5370  $enroll .= "</SubscriberCreate>\n";
5371  $enroll .= "</MessageRequest>\n";
5372  $enroll .= "</Message>\n";
5373 
5374  return $enroll;
5375 }
5376 
5377 function GetReqXML($ipay_instid, $ipay_iv, $ipay_token, $random, $Cu, $billpayid, $skip_company=0) {
5378  $request = "<Message>\n";
5379  $request .= "<InstitutionID>$ipay_instid</InstitutionID>\n";
5380  $request .= "<Security>\n";
5381  $request .= "<IV>$ipay_iv</IV>\n";
5382  $request .= "<AuthToken>$ipay_token</AuthToken>\n";
5383  $request .= "</Security>\n";
5384  $request .= "<MessageRequest>\n";
5385  $request .= "<RequestID>$random</RequestID>\n";
5386  $request .= "<Session>\n";
5387  $request .= "<Info />\n";
5388  $request .= "<Data>\n";
5389  $request .= "<Subscriber>\n";
5390  if (!$skip_company) {
5391  $request .= "<CompanyID>$Cu</CompanyID>\n";
5392  }
5393  $request .= "<LoginID>$billpayid</LoginID>\n";
5394  $request .= "</Subscriber>\n";
5395  $request .= "</Data>\n";
5396  $request .= "</Session>\n";
5397  $request .= "</MessageRequest>\n";
5398  $request .= "</Message>\n";
5399 
5400  return $request;
5401 }
5402 
5403 function GetReqResponse($ipayXML) {
5404  libxml_use_internal_errors(true);
5405  $ipayresp = simplexml_load_string($ipayXML);
5406  if ($ipayresp === false) {
5407  $ipaysuccess = NULL;
5408  $sessionID = NULL;
5409  $respcode = NULL;
5410  $respmsg = 'XML parse response failed ' . __LINE__;
5411 
5412  // $errors = libxml_get_errors();
5413  // foreach ($errors as $error) {
5414  // $respmsg .= " " . $error->message;
5415  // }
5416  // libxml_clear_errors();
5417 
5418  } else {
5419  $XMLsuccess = $ipayresp->xpath("MessageRequest/Session/Response/ProcessStatus/Successful");
5420  $ipaysuccess = (HCU_array_key_exists(0,$XMLsuccess) ? (string) $XMLsuccess[0] : NULL);
5421 
5422  $XMLsessionid = $ipayresp->xpath("MessageRequest/Session/Response/Data/SessionID");
5423  $sessionID = (HCU_array_key_exists(0,$XMLsessionid) ? (string) $XMLsessionid[0] : NULL);
5424 
5425  $XMLcode = $ipayresp->xpath("MessageRequest/Session/Response/ProcessStatus/Error/Code");
5426  $respcode = (HCU_array_key_exists(0,$XMLcode) ? (string) $XMLcode[0] : NULL);
5427 
5428  $XMLmsg = $ipayresp->xpath("MessageRequest/Session/Response/ProcessStatus/Error/Message");
5429  $respmsg = (HCU_array_key_exists(0,$XMLmsg) ? (string) $XMLmsg[0] : NULL);
5430  }
5431  return array($ipaysuccess, $sessionID, $respcode, $respmsg);
5432 }
5433 
5434 /**
5435  * @param type $ipayXML
5436  * @return type
5437  */
5438 function GetEnrollResponse($ipayXML) {
5439  libxml_use_internal_errors(true);
5440  $ipayresp = simplexml_load_string($ipayXML);
5441  if ($ipayresp === false) {
5442  $ipaysuccess = NULL;
5443  $respcode = NULL;
5444  $respmsg = 'XML parse response failed ' . __LINE__;
5445 
5446  // $errors = libxml_get_errors();
5447  // foreach ($errors as $error) {
5448  // $respmsg .= " " . $error->message;
5449  // }
5450  // libxml_clear_errors();
5451 
5452  } else {
5453 
5454  $XMLsuccess = $ipayresp->xpath("MessageRequest/SubscriberCreate/Response/ProcessStatus/Successful");
5455  $ipaysuccess = (HCU_array_key_exists(0,$XMLsuccess) ? (string) $XMLsuccess[0] : NULL);
5456 
5457  $XMLcode = $ipayresp->xpath("MessageRequest/SubscriberCreate/Response/ProcessStatus/Error/Code");
5458  $respcode = (HCU_array_key_exists(0,$XMLcode) ? (string) $XMLcode[0] : NULL);
5459 
5460  $XMLmsg = $ipayresp->xpath("MessageRequest/SubscriberCreate/Response/ProcessStatus/Error/Message");
5461  $respmsg = (HCU_array_key_exists(0,$XMLmsg) ? (string) $XMLmsg[0] : NULL);
5462  }
5463 
5464  return array($ipaysuccess, $respcode, $respmsg);
5465 }
5466 
5467 function Set_ACH($achfmt,$suffix,$member) {
5468  if (strpos($suffix, "@")) {
5469  list($jtype, $jacct) = explode("@", $suffix);
5470  } else {
5471  $jtype = $suffix;
5472  $jacct = $member;
5473  }
5474 
5475 // $loanACH = eval($achfmt);
5476  eval("\$loanACH=$achfmt;");
5477 
5478  return $loanACH;
5479 }
5480 
5481 function VSHO_XML ($parms, $VSHOhost) {
5482 #POST /HomeOfficeSvc/HomeOfficeService.asmx HTTP/1.1
5483 #Host: demo1.vsoftcorp.com
5484 #Content-Type: text/xml; charset=utf-8
5485 #Content-Length: length
5486 #SOAPAction: "http://homeoffice.vsoftcorp.com/VSHOSetCustomerInfo"
5487 
5488 $soapString = '<?xml version="1.0" encoding="utf-8"?>';
5489 $soapString .= "\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">";
5490 $soapString .= "<soap:Body>
5491 <VSHOSetCustomerInfo xmlns=\"http://homeoffice.vsoftcorp.com/\">
5492 <customerInfo>
5493 <InstId>{$parms['InstId']}</InstId>
5494 <UserId>{$parms['UserId']}</UserId>
5495 <ProfileId>{$parms['ProfileId']}</ProfileId>
5496 <UserName>{$parms['UserName']}</UserName>
5497 <Email>{$parms['email']}</Email>
5498 <Accounts>
5499 <VSHOAccountInfo>
5500 <AccountNumber>{$parms['AccountNumber']}</AccountNumber>
5501 <AccountType>{$parms['AccountType']}</AccountType>
5502 <AccountDesc>{$parms['AccountDesc']}</AccountDesc>
5503 <AccountStatus>{$parms['AccountStatus']}</AccountStatus>
5504 <AccountPin>{$parms['AccountPin']}</AccountPin>
5505 </VSHOAccountInfo>
5506 </Accounts>
5507 <Hash>{$parms['Hash']}</Hash>
5508 </customerInfo>
5509 </VSHOSetCustomerInfo>
5510 </soap:Body>
5511 </soap:Envelope>";
5512 
5513  $cmd="/usr/bin/curl --silent --data-binary '$soapString' -H 'Content-Type: text/xml; charset=utf-8' -H 'SOAPAction: \"http://homeoffice.vsoftcorp.com/VSHOSetCustomerInfo\"' $VSHOhost";
5514 print $cmd;
5515  $resparr=array();
5516  $vshoXML=getcurl($cmd);
5517 print "<br>After: $vshoXML";
5518  $VSHOresp = simplexml_load_string($vshoXML);
5519 
5520  $XMLresparr = $VSHOresp->xpath("VSHOSetCustomerInfoResponse");
5521 
5522  return $XMLresparr;
5523 
5524 }
5525 /**
5526  * strip slashes and dashes and non-digits from phone numbers
5527  * and zip code and tax id; rearrange DOB into mmddyyyy
5528  * then check to see if we have enough valid data to
5529  * satisfy the request
5530  *
5531  * 07-19 Add named back in for CUDIRECT_SSO.
5532  *
5533  * @param array $MIR mir packet info from core or local load
5534  * @param string $Ml homebanking email to use if mir.email is empty
5535  * @param array $reqMIR required items can't be empty in mir
5536  * @param string $datefmt format to use for DOB
5537  * @param string $phones 'flat' or 'split'
5538  * 'flat' = fill ['PHONE'] with first non-null of HomePhone, CellPhone, WorkPhone
5539  * 'split' = split each phone # into sub-array of optional [Area], required [Pre] & [Num]
5540  * 'named' = 07-19 re-added for CUDIRECT_SSO
5541  *
5542  * @param boolean $noEmpty unset empty mir values
5543  * @return array
5544  * @throws Exception
5545  */
5546 function populateMIR($MIR, $Ml, $reqMIR, $datefmt = 'Y-m-d', $phones = 'flat', $noEmpty = false) {
5547  try {
5548 /*
5549 //$mirFields = Array(
5550 // "accountnumber",
5551 // "firstname",
5552 // "middlename",
5553 // "lastname",
5554 // "email",
5555 // "homephone",
5556 // "workphone",
5557 // "cellphone",
5558 // "fax",
5559 // "ssn",
5560 // "address1",
5561 // "address2",
5562 // "city",
5563 // "state",
5564 // "zip",
5565 // "cc",
5566 // "dob",
5567 // "class"
5568 // );
5569  *
5570  */
5571  /* strip slashes and dashes and non-digits from phone numbers
5572  * and zip code and tax id; rearrange DOB into mmddyyyy
5573  * then check to see if we have enough valid data to
5574  * satisfy the request
5575  */
5576  if ($phones == 'flat') {
5577  $MIR['phone'] = preg_replace('/\D/', '', $MIR['homephone']);
5578  if (trim($MIR['phone']) == '') {
5579  $MIR['phone'] = preg_replace('/\D/', '', $MIR['cellphone']);
5580  }
5581  if (trim($MIR['phone']) == '') {
5582  $MIR['phone'] = preg_replace('/\D/', '', $MIR['workphone']);
5583  }
5584  } elseif ($phones == 'split') {
5585  $MIR['homephone'] = preg_replace('/\D/', '', $MIR['homephone']);
5586  switch (strlen($MIR['homephone'])) {
5587  case 10:
5588  $MIR['homephone'] = array('area' => substr($MIR['homephone'], 0, 3),
5589  'pre' => substr($MIR['homephone'], 3, 3),
5590  'num' => substr($MIR['homephone'], 6, 4));
5591  break;
5592  case 7:
5593  $MIR['homephone'] = array('pre' => substr($MIR['homephone'], 3, 3),
5594  'num' => substr($MIR['homephone'], 6, 4));
5595  break;
5596  default:
5597  unset($MIR['homephone']);
5598  break;
5599  }
5600  $MIR['cellphone'] = preg_replace('/\D/', '', $MIR['cellphone']);
5601  switch (strlen($MIR['cellphone'])) {
5602  case 10:
5603  $MIR['cellphone'] = array('area' => substr($MIR['cellphone'], 0, 3),
5604  'pre' => substr($MIR['cellphone'], 3, 3),
5605  'num' => substr($MIR['cellphone'], 6, 4));
5606  break;
5607  case 7:
5608  $MIR['cellphone'] = array('pre' => substr($MIR['cellphone'], 3, 3),
5609  'num' => substr($MIR['cellphone'], 6, 4));
5610  break;
5611  default:
5612  unset($MIR['cellphone']);
5613  break;
5614  }
5615  $MIR['workphone'] = preg_replace('/\D/', '', $MIR['workphone']);
5616  switch (strlen($MIR['workphone'])) {
5617  case 10:
5618  $MIR['workphone'] = array('area' => substr($MIR['workphone'], 0, 3),
5619  'pre' => substr($MIR['workphone'], 3, 3),
5620  'num' => substr($MIR['workphone'], 6, 4));
5621  break;
5622  case 7:
5623  $MIR['workphone'] = array('pre' => substr($MIR['workphone'], 3, 3),
5624  'num' => substr($MIR['workphone'], 6, 4));
5625  break;
5626  default:
5627  unset($MIR['workphone']);
5628  break;
5629  }
5630  } elseif ($phones == 'named') {
5631 
5632  $phone_formats = [
5633  'homephone' => 'Home',
5634  'cellphone' => 'Cell',
5635  'workphone' => 'Work'
5636  ];
5637 
5638  $MIR['phonenumbers'] = [];
5639 
5640  foreach ($phone_formats as $format => $name) {
5641 
5642  $MIR[$format] = preg_replace('/\D/', '', $MIR[$format]);
5643  switch (strlen($MIR[$format])) {
5644  case 10:
5645  case 7:
5646  $MIR['phonenumbers'][] = [
5647  'number' => format_phone($MIR[$format]),
5648  'name' => $name
5649  ];
5650  break;
5651 
5652  default:
5653  unset($MIR[$format]);
5654  break;
5655  }
5656  }
5657  }
5658 
5659  // 08-19, implemented from CUDIRECT_SSO in mammoth, see comments. All
5660  // calls to this function from other SSO's have been tested.
5661  $MIR['dob'] = format_date(HCU_array_key_value('dob', $MIR), $datefmt);
5662 
5663  $rmlist = array(' ', '-');
5664  $MIR['ssn'] = str_replace($rmlist, '', $MIR['ssn']);
5665 
5666  $MIR['zip'] = str_replace($rmlist, '', $MIR['zip']);
5667  if (strlen($MIR['zip']) < 5) {
5668  unset($MIR['zip']);
5669  }
5670 
5671  $rmlist = array("#", "&", "/", "%", ",", ":", "=", "?", "'");
5672 
5673  $EMAIL = (empty($MIR['email']) ? $Ml : $MIR['email']);
5674  $MIR['email'] = str_replace($rmlist, "", $EMAIL);
5675  $MIR['firstname'] = str_replace($rmlist, "", $MIR['firstname']);
5676  $MIR['middlename'] = str_replace($rmlist, "", $MIR['middlename']);
5677  $MIR['lastname'] = str_replace($rmlist, "", $MIR['lastname']);
5678  $MIR['address1'] = str_replace($rmlist, "", $MIR['address1']);
5679  $MIR['address2'] = str_replace($rmlist, "", $MIR['address2']);
5680  $MIR['city'] = str_replace($rmlist, "", $MIR['city']);
5681  $MIR['state'] = str_replace($rmlist, "", $MIR['state']);
5682  $MIR['accountnumber'] = str_replace($rmlist, "", $MIR['accountnumber']);
5683  # default country code to US. Assume CU will specify for other countries
5684  if (trim($MIR['cc']) == '') {
5685  $MIR['cc'] = 'US';
5686  }
5687 
5688  $MIR['class'] = str_replace($rmlist, "", $MIR['class']);
5689  if (trim($MIR['class']) == '') {
5690  $MIR['class'] = 'P'; # default to personal account
5691  }
5692 
5693  if ($noEmpty) {
5694  if (trim($MIR['email']) == false) {
5695  unset($MIR['email']);
5696  }
5697  if (trim($MIR['firstname']) == false) {
5698  unset($MIR['firstname']);
5699  }
5700  if (trim($MIR['middlename']) == false) {
5701  unset($MIR['middlename']);
5702  }
5703  if (trim($MIR['lastname']) == false) {
5704  unset($MIR['lastname']);
5705  }
5706  if (trim($MIR['address1']) == false) {
5707  unset($MIR['address1']);
5708  }
5709  if (trim($MIR['address2']) == false) {
5710  unset($MIR['address2']);
5711  }
5712  if (trim($MIR['city']) == false) {
5713  unset($MIR['city']);
5714  }
5715  if (trim($MIR['state']) == false) {
5716  unset($MIR['state']);
5717  }
5718  if (trim($MIR['accountnumber']) == false) {
5719  unset($MIR['accountnumber']);
5720  }
5721  if (trim($MIR['dob']) == false) {
5722  unset($MIR['dob']);
5723  }
5724  if (trim($MIR['zip']) == false) {
5725  unset($MIR['zip']);
5726  }
5727  }
5728 
5729  $missing = array_diff_key($reqMIR, $MIR);
5730  if (sizeof($missing)) {
5731 // throw new Exception("Incomplete Member Info (" . join(", ",array_keys($missing)) . ") mir gets " . print_r($MIR,true));
5732  throw new Exception("Incomplete Member Info (" . join(", ", array_keys($missing)) . ")");
5733  }
5734  $return['status']['response'] = true;
5735  $return['status']['message'] = 'Success';
5736  $return['data'] = $MIR;
5737  } catch (Exception $e) {
5738  $return['status']['response'] = false;
5739  $return['status']['message'] = $e->getMessage();
5740 // $return['status']['message'] = "(" . $e->getline() . ") " . $e->getMessage();
5741  $return['data'] = array();
5742  }
5743  return $return;
5744 }
5745 
5746 function Validate_Userkey($CU, $USERKEY) {
5747 
5748  try {
5749  $return = array();
5750  $apptokenkey = 'Chahriv8pahvahsa';
5751 
5752  if (empty($CU)) {
5753  throw new Exception('Userkey invalid - Missing Cu Parameter');
5754  }
5755  if (empty($USERKEY)) {
5756  throw new Exception('Userkey invalid - Missing Userkey Parameter');
5757  }
5758  # $mytoken="H=$hash&E=$expires&A=$member";
5759  # 11/6/14 to support switch accounts
5760  # $mytoken="H=$hash&E=$expires&A=$cauth_member&C=$current_member";
5761 
5762  $apptokarr = array();
5763  parse_str(urldecode($USERKEY), $apptokarr);
5764 
5765  if ($apptokarr['E'] < time()) {
5766  $resdesc = "Session Timed Out";
5767  throw new Exception($resdesc);
5768  }
5769 
5770  if (is_null($apptokarr['E']) || is_null($apptokarr['A']) || is_null($apptokarr['H'])) {
5771  $resdesc = "Partial Token";
5772  throw new Exception($resdesc);
5773  }
5774  # if no C= value, assume oldstyle userkey
5775  # and set member as A= value so hash works
5776  if (is_null($apptokarr['C'])) {
5777  $MEMBER = $apptokarr['A'];
5778  } else {
5779  $MEMBER = $apptokarr['C'];
5780  }
5781  $CAUTH = $apptokarr['A'];
5782  $EXPIRES = $apptokarr['E'];
5783  $hash = MD5($apptokenkey .
5784  MD5(join(':', array($apptokenkey, $EXPIRES, $CU, $MEMBER, $CAUTH))));
5785  if ($apptokarr['H'] != $hash) {
5786  $resdesc = "Corrupted Token" . print_r($apptokarr, true);
5787  throw new Exception($resdesc);
5788  }
5789 
5790  $return['status']['response'] = true;
5791  $return['status']['message'] = "Success";
5792  $return['status']['member'] = $MEMBER;
5793  $return['status']['cauth'] = $CAUTH;
5794  } catch (Exception $e) {
5795  $return[status][response] = false;
5796  $return[status][message] = $e->getMessage();
5797  }
5798  return $return;
5799 }
5800 
5801 
5802 function iPayEmbcurl($soapString, $soapHeaders, $soapServer, $soapCertfile='', $soapKeyfile='', $soapCACert='', $parms) {
5803 // CURLOPT_SSL_VERIFYHOST => 0,
5804 // CURLOPT_VERBOSE => 1,
5805 // CURLOPT_STDERR => '/tmp/chkfreetrace',
5806 // CURLINFO_HEADER_OUT => 1,
5807 
5808  $curlopts = array(
5809  CURLOPT_SSL_VERIFYPEER => 0,
5810  CURLOPT_RETURNTRANSFER => 1,
5811  CURLOPT_HEADER => 0,
5812  CURLOPT_POST => 1,
5813  CURLOPT_POSTFIELDS => "$soapString",
5814  CURLOPT_URL => "$soapServer");
5815  if (!empty($soapCertfile)) {
5816  $curlopts[CURLOPT_SSLCERT] = "$soapCertfile";
5817  }
5818  if (!empty($soapKeyfile)) {
5819  $curlopts[CURLOPT_SSLKEY] = "$soapKeyfile";
5820  }
5821  if (!empty($soapCACert)) {
5822  $curlopts[CURLOPT_CAINFO] = "$soapCACert";
5823  }
5824 
5825  $ch = @curl_init();
5826  @curl_setopt_array($ch, $curlopts);
5827  @curl_setopt($ch, CURLOPT_HTTPHEADER, $soapHeaders);
5828 
5829  $respERR = '';
5830  $return = '';
5831  $response = curl_exec($ch);
5832  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
5833  $respCURL = curl_errno($ch);
5834 
5835  if ($respCURL) {
5836  # Bad! Don't hide the error, return the curl error if it occurred.
5837  $respERR = "HCUERROR: Connection Failed cURL $respCURL";
5838  $return = array("status" => false, "code" => "hcuC{$respCURL}", "message" => "$respERR");
5839  } elseif ($respHTTP > 400 && $respHTTP < 600) {
5840  # HTTP Response 4xx client error or 5xx server error
5841  $respERR = "HCUERROR: Connection Failed HTTP $respHTTP ";
5842  $return = array("status" => false, "code" => $respHTTP, "message" => "$respERR");
5843  } elseif (!isset($response) || empty($response) ) {
5844  $return = array("status" => false, "code" => $respHTTP, "message" => "Empty Response");
5845  } else {
5846  $return = array("status" => true, "code" => 0, "message" => $response);
5847  }
5848 
5849  if ($parms["logging"] == "enabled") {
5850  $logParms = $parms["environment"]; // get the environment info passed in
5851  $logParms["token"] = ''; // the id used across all communications in session
5852  // logPoint is set before calling curl function.
5853  // Overriding it here hides needed detail, makes support difficult
5854  // $logParms['logPoint'] = 'Ipay Embed Curl';
5855  $logParms["txnId"] = time(); // the id for this transaction
5856  $logParms["reply"] = json_encode($return); // the response
5857  LogSSOActivity($logParms);
5858  }
5859 
5860  curl_close($ch);
5861  return $return;
5862 }
5863 
5864 /**
5865  * 08-19: Only require MICR account if EnrollMICR flag is set to 1
5866  * @param resource object $dbh
5867  * @param array $HB_ENV
5868  * @param string $accountToUse
5869  * @param int $enrollmicr from trusted detail property EnrollMICR 0|1
5870  * @return array
5871  */
5872 function iPay_getHCUAccounts($dbh, $HB_ENV, $accountToUse, $enrollmicr = 0) {
5873 
5874  try {
5875  $sql = "select trim(accountnumber) as accountnumber,
5876  trim(accounttype) as accounttype,
5877  certnumber as cert,
5878  trim(description) as description,
5879  trim(micraccount) as micr
5880  from {$HB_ENV['Cu']}accountbalance
5881  where accountnumber='$accountToUse' and deposittype='Y'
5882  and accounttype not like '%@%'";
5883 
5884  if ($enrollmicr > 0) {
5885  $sql .= " and trim(micraccount) > ''";
5886  }
5887 
5888  # Run the sql and see if we got anything
5889 
5890  $sthdp = db_query($sql, $dbh);
5891  $rows = db_num_rows($sthdp);
5892 
5893  if ($rows == 0) {
5894  throw new Exception("No Valid Accounts for bill pay service");
5895  }
5896  $reply['status']['response'] = true;
5897  $reply['status']['message'] = "{$rows} Payment Account(s) Found";
5898  $reply['data'] = db_fetch_all($sthdp);
5899  } catch (Exception $e) {
5900  $reply['status']['response'] = false;
5901  $reply['status']['message'] = $e->getMessage();
5902  $reply['data'] = array();
5903  }
5904 
5905  return $reply;
5906 }
5907 
5908 /**
5909  * @param string $ipay_instid
5910  * @param string $ipay_iv
5911  * @param string $ipay_session
5912  * @param string $ipay_token
5913  * @param string $Cu
5914  * @param string $billpayid
5915  * @param int $skip_company
5916  * @param array $parms
5917  * @param string $random
5918  * @return array|string
5919  */
5920 function iPay_getSession($ipay_instid, $ipay_iv, $ipay_session, $ipay_token, $Cu, $billpayid, $skip_company, $parms, $random) {
5921 
5922  # send login
5923  $request = GetReqXML($ipay_instid, $ipay_iv, $ipay_token, $random, $Cu, $billpayid, $skip_company);
5924 
5925  $cmd = "/usr/bin/curl --silent --request POST --data-binary '$request' -H 'Content-type: application/xml' '{$ipay_session}'";
5926 // $ipayXML = getcurl($cmd);
5927 
5928  $ipayHeaders = [];
5929  $ipayHeaders[] = "Content-type: application/xml";
5930 
5931  $parms["environment"]["logPoint"] = "V3_Login"; // this action in a readable form
5932  $parms["environment"]["request"] = "{$cmd}"; // the request
5933  $ipayXML = iPayEmbcurl($request, $ipayHeaders, $ipay_session, '', '', '', $parms);
5934 
5935  return $ipayXML;
5936 }
5937 
5938 function PSCU_getHCUAccounts($dbh, $HB_ENV, $accountToUse, $parms) {
5939  try {
5940  $acctsql = (HCU_array_key_value('acctsql', $parms) ? $parms['acctsql'] : "trim(micraccount)" );
5941  $sendjoint = (HCU_array_key_value('sendjoint', $parms) ? '' : "and accounttype not like '%@%' " );
5942 
5943  $sql = "select $acctsql as micr, trim(description) as description, available
5944  from {$HB_ENV['Cu']}accountbalance where accountnumber='$accountToUse'
5945  and deposittype='Y' $sendjoint order by accounttype;";
5946  $sthdp = db_query($sql, $dbh);
5947  $rows = db_num_rows($sthdp);
5948  if (!($sthdp) || $rows == 0) {
5949  throw new Exception($HB_ENV['MC']->msg('No Valid Accounts'));
5950  }
5951 
5952  $reply['status']['response'] = true;
5953  $reply['status']['message'] = "{$rows} Payment Account(s) Found";
5954  $reply['data'] = db_fetch_all($sthdp);
5955  } catch (Exception $e) {
5956  $reply['status']['response'] = false;
5957  $reply['status']['message'] = $e->getMessage();
5958  $reply['data'] = array();
5959  }
5960  return $reply;
5961 }
5962 function merlink_embcurl($parms, $reqOpts, $reqData='') {
5963 
5964  # parms is the array from trusted vendor, including logging status
5965  # reqOpts is the array of curl options to set
5966  # reqData is post data
5967 
5968  $ch = @curl_init();
5969  if ($ch) {
5970  curl_setopt_array($ch, $reqOpts);
5971  if (strlen($reqData) > 0) {
5972  curl_setopt($ch, CURLOPT_POSTFIELDS, $reqData);
5973  }
5974  $response = curl_exec($ch);
5975  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
5976  $respCURL = curl_errno($ch);
5977  curl_close($ch);
5978  }
5979 
5980  if ($parms["logging"] == "enabled") {
5981  $logParms = $parms["environment"]; // get the environment info passed in
5982  $logParms["token"] = ''; // the id used across all communications in session
5983  $logParms["txnId"] = time(); // the id for this transaction
5984  $logParms["logPoint"] = "MLink getConsumerResource"; // this action in a readable form
5985  $logParms["logPoint"] = $parms['mlcall'];
5986 
5987  $logParms["request"] = "curl "; // the request
5988 
5989 
5990  if (isset($reqOpts[CURLOPT_CUSTOMREQUEST]) && $reqOpts[CURLOPT_CUSTOMREQUEST] != 'GET') {
5991  $logParms["request"] .= "-X {$reqOpts[CURLOPT_CUSTOMREQUEST]} ";
5992  }
5993  if (isset($reqOpts[CURLOPT_USERPWD])) {
5994  $logParms["request"] .= "-u '{$reqOpts[CURLOPT_USERPWD]}' ";
5995  }
5996 
5997  $logParms["request"] .= "'{$reqOpts[CURLOPT_URL]}' "; // the request
5998 // $logParms["request"] .= print_r($reqOpts,true);
5999  if (strlen($reqData) > 0) {
6000  $logParms["request"] .= "-d '$reqData' "; // the request
6001  }
6002  $logParms["reply"] = $response; // the response
6003 // $logParms["reply"] .= "HTTP $respHTTP CURL $respCURL"; // the response
6004  LogSSOActivity($logParms);
6005  }
6006  $return = array();
6007  if ($respCURL) {
6008  $return['Status']='Fail';
6009  $return['Error']="ERROR: Connection Failed (cURL $respCURL)";
6010  # service responds with HTTP 200 when successful
6011  } elseif ($respHTTP != 200) {
6012  $return['Status']='Fail';
6013  $return['Error']="ERROR: (http $respHTTP)";
6014  if (!empty($response)) {
6015  $return['Error'] .= " $response";
6016  }
6017  } elseif (!isset($response) || $response == '') {
6018  $return['Status']='Fail';
6019  $return['Error']="ERROR: Empty Response (http $respHTTP)";
6020  } else {
6021  # got a valid url -
6022  $return['Status']='Success';
6023  $return['MLinkDATA']=$response;
6024  }
6025 
6026  return $return;
6027 
6028 }
6029 function base64url_encode($data) {
6030  #implements Base64 w/URL & Filename Safe Alphabet per RFC 4648
6031  # no padding
6032  return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
6033 }
6034 
6035 function base64url_decode($data) {
6036  # implements Base64 w/URL & Filename Safe Alphabet per RFC 4648
6037  # no padding
6038  return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
6039 }
6040 
6041 
6042 /**
6043  * sanitizing phone before calling this function, but just in case ...
6044  * @param $phone
6045  * @return string
6046  */
6047 function format_phone($phone) {
6048 
6049  $phone = preg_replace("/[^0-9]/", "", $phone);
6050  $length = strlen($phone);
6051 
6052  switch($length) {
6053  case 7:
6054  return preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2", $phone);
6055 
6056  case 10:
6057  return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $phone);
6058 
6059  default:
6060  return $phone;
6061  }
6062 }
6063 
6064 
6065 /**
6066  * A DOB value in the mir packet of all zeros passed the 'not empty' test and
6067  * then blew up at CuDirect. Using a very old minimum date, and current time
6068  * as max date. Kind of a wide filter, but at least make sure the value passed
6069  * to CuDirect will be a valid date string
6070  * Eliminated else and variable set, guard pattern.
6071  *
6072  * @param string $dob
6073  * @param string $datefmt
6074  * @return string formatted date
6075  */
6076 function format_date($dob, $datefmt = 'Y-m-d') {
6077 
6078  $mindate = strtotime('1901-12-31');
6079  $maxdate = time();
6080  $st = strtotime($dob);
6081 
6082  if (strtotime($dob) && $st > $mindate && $st < $maxdate) {
6083  return date($datefmt, $st);
6084  }
6085 
6086  return '';
6087 }
static GetInstance($dbh)