Odyssey
GenMDX.prg
1 <?php
2 /* GenMDX.prg
3  *
4  * History:
5  * 06/28/18 Cloned from GenAPP for new script to test MDX restful API
6  */
7 try {
8  $serviceMinimal = true;
9  $serviceShowInfo = false;
10  $serviceLoadMenu = false;
11  $serviceShowMenu = false;
12 
13  // ** INCLUDE MAIN GLOBAL SCRIPT -- Handles security / global variable values
14  // hcuService will be returning a status object: e.g. ["homecuErrors":{[{"message":"message1"}...{"message":"messageN"}}]
15  require_once(dirname(__FILE__) . '/../library/hcuService.i');
16  require_once(dirname(__FILE__) . '/../library/hcuDispFunctions.i');
17  require_once(dirname(__FILE__) . '/../library/hcuAuthShared.i');
18  require_once('cutrusted.i');
19  setIncludeFiles(false,true,'bootstrap',true);
20 
21  // no dictionary
22  unset( $HB_ENV["MC"] );
23 
24  $inPost = array();
25  $varOk = array(
26  "APPID" => array('filter' => FILTER_SANITIZE_STRING),
27  "CRED2" => array('filter' => FILTER_SANITIZE_STRING),
28  "CRED3" => array('filter' => FILTER_SANITIZE_STRING),
29  "USERID" => array('filter' => FILTER_SANITIZE_STRING),
30  "USERPASS" => array('filter' => FILTER_SANITIZE_STRING),
31  "USERKEY" => array('filter' => FILTER_SANITIZE_STRING),
32  "cu" => array('filter' => FILTER_SANITIZE_STRING),
33  "URLQstr" => array('filter' => FILTER_SANITIZE_STRING),
34  "sessionKey" => array('filter' => FILTER_SANITIZE_STRING),
35  "URLPassWith" => array('filter' => FILTER_SANITIZE_STRING),
36  "generate" => array('filter' => FILTER_SANITIZE_STRING),
37  "msg" => array('filter' => FILTER_SANITIZE_STRING),
38  "WWWSvr" => array('filter' => FILTER_SANITIZE_STRING),
39  "AMOUNT" => array('filter' => FILTER_SANITIZE_NUMBER_INT),
40  "PASSTO" => array('filter' => FILTER_SANITIZE_STRING),
41  "PASSWITH" => array('filter' => FILTER_SANITIZE_STRING),
42  'MFA_' => 'prefix_s'
43  );
44 
45 HCU_ImportVars( $inPost, "", $varOk );
46 
47  $cu = HCU_array_key_value('cu',$inPost);
48  # look a little closer at that cu value --
49  # ctype_alnum ensures not empty / null, and contains only letters / digits
50  if (!ctype_alnum($cu)) {
51  throw new Exception("Invalid Request", 901); # empty ORG
52  }
53 
54 $msg=HCU_array_key_value('msg',$inPost);
55 $USERID=HCU_array_key_value('USERID',$inPost);
56 $USERPASS=HCU_array_key_value('USERPASS',$inPost);
57 $USERKEY=urldecode(HCU_array_key_value('USERKEY',$inPost));
58 $APPID=HCU_array_key_value('APPID',$inPost);
59 $URLQstr=HCU_array_key_value('URLQstr',$inPost);
60 $sessionKey=HCU_array_key_value('sessionKey',$inPost);
61 $URLPassWith=HCU_array_key_value('URLPassWith',$inPost);
62 $generate=HCU_array_key_value('generate',$inPost);
63 $WWWSvr=HCU_array_key_value('WWWSvr',$inPost);
64 
65 $CU = $cu;
66 $cmd = '';
67 $response = '';
68 if (!empty($generate)) {
69  $msg = "";
70  if (empty($USERID) && empty($USERKEY)) {
71  $msg .= "Please enter User ID or User Key<br>\n";
72  }
73  switch ($APPID) {
74  case "MDESK":
75  # consider trusted detail settings for these ?
76  $client_source_override = 'OMX'; # unique for Mx
77 
78  require_once(dirname(__FILE__) . '/../library/MDesk_API.i');
79 
80  if (!hcu_checkService($dbh, "MDESK")) {
81  $omsg = hcu_checkServiceMsg($dbh, "MDESK");
82  throw new Exception("$omsg");
83  }
84 
85  # cutrusted_read will fall back to master if detail not found
86  $Mxtrusted = cutrusted_read($dbh, array('Cu' => $CU, 'trustedid' => 'MDesk3'));
87 
88  if ($Mxtrusted['status']['Response'] == 'false') {
89  throw new Exception("Client not configured for remote Mx access", 913); # missing trusted detail
90  }
91  if (HCU_array_key_exists('data', $Mxtrusted)) {
92  $mxParms = $Mxtrusted['data'];
93  } else {
94  throw new Exception("Client not configured for remote Mx access", 914); # missing trusted detail parms
95  }
96 
97  # default to production mode
98  $testing = ( HCU_array_key_exists('testing', $mxParms) ? HCU_array_key_value('testing', $mxParms) : 0 );
99 
100  if ($testing) {
101  # HCU-issued sharekey used by trusted vendor for hashing CRED2/CRED3
102  # maybe not needed for MDX5?
103  $mdkey = HCU_array_key_value('mdTestKey', $mxParms);
104  $mdAPI_key = HCU_array_key_value('testAPIKey', $mxParms);
105  $mdData_URL = HCU_array_key_value('testServerURL', $mxParms);
106  $mxHMACKey = HCU_array_key_value('testHMACKey', $mxParms);
107  } else {
108  # HCU-issued sharekey used by trusted vendor for hashing CRED2/CRED3
109  # maybe not needed for MDX5?
110  $mdkey = HCU_array_key_value('mdShareKey', $mxParms);
111  $mdAPI_key = HCU_array_key_value('APIKey', $mxParms);
112  $mdData_URL = HCU_array_key_value('ServerURL', $mxParms);
113  $mxHMACKey = HCU_array_key_value('HMACKey', $mxParms);
114  }
115 
116  if (empty($mdkey)) {
117  throw new Exception("Client misconfigured for remote authentication", 902); # missing trusted detail parms (keys)
118  }
119 
120  if (empty($mxHMACKey)) {
121  throw new Exception("Client misconfigured for remote Mx access", 912); # missing trusted detail parms (keys)
122  }
123 
124  $mdtokenkey = HCU_array_key_value('mdTokenKey', $mxParms);
125 
126  if (empty($mdtokenkey)) {
127  throw new Exception("Client misconfigured for remote authentication", 902); # missing trusted detail parms (keys)
128  }
129 
130  $client_key_TTL = ( HCU_array_key_exists('mdTokenTTL', $mxParms) ? HCU_array_key_value('mdTokenTTL', $mxParms) : 900 );
131  $SENDAS = ( HCU_array_key_exists('resultsAs', $mxParms) ? HCU_array_key_value('resultsAs', $mxParms) : 'XML' );
132 
133 
134  break;
135 
136  default:
137  $msg .= "Invalid App ID<br>\n";
138  }
139  if ($msg == '') {
140 if ($APPID == 'MDESK') {
141 
142  $mxSessionData = array('userkey' => $USERKEY, 'userid' => $USERID, 'userpass' => $USERPASS, 'formpost' => $URLPassWith
143  # accountid = selected account identifier
144  # start_date = start date for transaction list
145  );
146  $mxRequestArr = mxMakeRequest($WWWSvr, $CU, $mxHMACKey, $URLQstr, $mxSessionData, $sessionKey);
147  # mxSessionData is array of required content varies based on mxRestOpt
148  $mxStatus = HCU_array_key_value('status', $mxRequestArr);
149  $mxVerb = HCU_array_key_value('mxVerb', $mxRequestArr);
150  $mxURL = HCU_array_key_value('mxURL', $mxRequestArr);
151  $mxContent = HCU_array_key_value('mxContent', $mxRequestArr);
152  $mxHeaders = HCU_array_key_value('headers', $mxRequestArr);
153 
154  $reason = '';
155  if (!($mxStatus)) $reason .= 'Status ';
156  if (empty($mxVerb)) $reason .= 'mxVerb ';
157  if (empty($mxURL)) $reason .= 'mxURL ';
158  if (empty($mxHeaders)) $reason .= 'mxHeaders ';
159 
160  if (!($mxStatus) || empty($mxVerb) || empty($mxURL) || empty($mxHeaders)) {
161  $cmd = "Error: missing {$reason}" . HCU_array_key_value('because', $mxRequestArr);
162  } else {
163  $cmd = 'curl';
164  if (strtoupper($mxVerb) != 'GET') {
165  $cmd .= ' -X ' . strtoupper($mxVerb);
166  }
167  foreach ($mxHeaders as $hdr => $hdrContent) {
168  $cmd .= " -H '{$hdr}: {$hdrContent}'";
169  }
170  if (!empty($mxContent)) {
171  $cmd .= " --data '$mxContent'";
172  }
173  $cmd .= " '{$mxURL}'";
174 
175  $embedResponse = mxGetData($mxVerb, $mxHeaders, $mxContent, $mxURL);
176  # format this to show request, headers, etc.?
177 // $response = print_r($embedResponse, true);
178  $response = '';
179 // $response .= "Request: \n " . HCU_array_key_value('request',$embedResponse) . " \n";
180 
181  $response .= "HTTP " . (integer) HCU_array_key_value('respHTTP',$embedResponse) . " \n";
182  $response .= "CURL " . (integer) HCU_array_key_value('respCURL',$embedResponse) . " \n";
183  if (HCU_array_key_value('respERR', $embedResponse) ) {
184  $response .= "ERR {$embedResponse['respCURL']} \n";
185  }
186  $response .= "\n" . htmlentities(HCU_array_key_value('responseHeaders', $embedResponse));
187  $response .= "\n" . htmlentities(HCU_array_key_value('responseBody', $embedResponse));
188 
189  }
190 
191 // print "<pre>" . htmlentities($response) . "</pre>"; exit;
192 
193  if (!empty($USERKEY)) {
194  # get member out of userkey hash
195  # H=$apphash&E=$appexpires&A=$MEMBER&P=DeviceToken
196  #
197  $apptokarr = array();
198  parse_str(urldecode($USERKEY), $apptokarr);
199  $MEMBER = HCU_array_key_value('A', $apptokarr);
200 
201  } else {
202  $USERID = trim($USERID);
203  $MEMBER = $USERID;
204  }
205 
206  # new sha384 key - load pchange date from member last pw change
207  # legacy md5 key, PCHANGE = 0 but not used to build token
208  $userrec = GetUserbyName($dbh, $CU, $MEMBER);
209  if (! HCU_array_key_value('rowfound', $userrec)) {
210  throw new Exception("Invalid User");
211  }
212  $apptoken = MakeV94Dkey($CU, $MEMBER, $userrec, $client_key_TTL, $mdtokenkey, 'S');
213 
214  if (empty($USERPASS)) {
215  $USERKEY = (empty($USERKEY) ? $apptoken : urlencode($USERKEY));
216  }
217 
218  }
219  }
220 
221 }
222 //cu_header("Generate HomeCU APP Key");
223 //========================================
224 $WWWSvr = (empty($WWWSvr) ? "http://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/MoneyDesk3.prg" : $WWWSvr);
225 $error = '';
226  } catch (Exception $ex) {
227  $error = $ex-> getMessage();
228  }
229 
230 ?>
231 <!DOCTYPE html>
232 <html>
233  <head>
234  <title><?php echo hcu_displayHtml("App Simulator"); ?></title>
235  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
236  <meta name="robots" content="noindex,nofollow" />
237  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
238 
239  <meta name="viewport" content="width=device-width, initial-scale=1" />
240  </head>
241  <body>
242  <div class='container-fluid'>
243 <?php
244  if ( strlen( $msg ) > 0 ) {
245  print <<<EOP
246  <div class="well" style="color:darkred;">
247  $msg
248  </div>
249 EOP;
250  }
251 ?>
252  <div class='well well-sm col-xs-6' style="max-width:48%;">
253 
254  <h3>HomeCU Mx/MDX Test Generator</h3>
255 
256  <form id='formAppKey' name='formAppKey' method="post" action="GenMDX.prg">
257  <fieldset>
258 
259  <div class="col-xs-12 hcu-container-margin">
260  <label for="APPID" class="col-xs-3">
261  APP ID:
262  </label>
263  <input id='APPID' name='APPID' class='col-xs-8' placeholder="Choose: MDESK"
264  required data-required-msg="Choose: MDESK" value="<?php echo "$APPID"; ?>" size="50"/>
265  </div>
266 
267  <div class="col-xs-12 hcu-container-margin">
268  <label for="cu" class="col-xs-3" >
269  ORG ID:
270  </label>
271  <input id='cu' name='cu' class='col-xs-8' placeholder="Upper Case CU Code"
272  required data-required-msg="The CU code" value="<?php echo "$cu"; ?>" size="50"/>
273  </div>
274 
275  <div class="col-xs-12 hcu-container-margin">
276  <label for="USERID" class="col-xs-3">
277  UserID:
278  </label>
279  <input id='USERID' name='USERID' class='col-xs-8' value="<?php echo "$USERID"; ?>" size="50"/>
280  </div>
281 
282  <div class="col-xs-12 hcu-container-margin">
283  <div class="col-xs-12" style='font-size:smaller; opacity=0.38; padding-bottom: 10px;'>
284  User Key is added to computed link; copy in latest
285  </div>
286  <label for="USERKEY" class="col-xs-3">
287  User Key:
288  </label>
289  <textarea id='USERKEY' name='USERKEY' class='col-xs-8' style="height: 5em;"><?php echo "$USERKEY"; ?></textarea>
290  </div>
291 
292  <div class="well col-xs-12 hcu-container-margin">
293  <div class="row">
294  <div class="col-xs-12" style='font-size:smaller; opacity=0.38; padding-bottom: 10px;'>Use if testing authentication process (supply Password, blank User Key, click Generate Link first)</div>
295  </div>
296  <div class="row">
297  <label for="USERPASS" class="col-xs-3">
298  Password:
299  </label>
300  <input id='USERPASS' name='USERPASS' type="password" class='col-xs-8' placeholder="Leave blank to populate User Key" value="<?php echo "$USERPASS"; ?>" size="50"/>
301  </div>
302  <div class="row">
303  <div class="col-xs-12">&nbsp;</div>
304  </div>
305  </div>
306 
307  <div class="well col-xs-12 hcu-container-margin">
308  <div class="row">
309  <label for="URLQstr" class="col-xs-3">
310  Rest Option:
311  </label>
312  <input id='URLQstr' name='URLQstr' class='col-xs-8' placeholder="sessions or accounts or transactions" value="<?php echo "$URLQstr"; ?>" size="50"/>
313  </div>
314  <div class="row">
315  <label for="sessionKey" class="col-xs-3">
316  Session Key:
317  </label>
318  <input id='sessionKey' name='sessionKey' class='col-xs-8' placeholder="session key as returned from server" value="<?php echo "$sessionKey"; ?>" size="50"/>
319  </div>
320  <div class="row">
321  <div class="col-xs-12">&nbsp;</div>
322  </div>
323  <div class="row">
324  <label for="URLPassWith" class="col-xs-3">
325  Pass With:
326  </label>
327  <input id='URLPassWith' name='URLPassWith' class='col-xs-8' placeholder='start_date=Y-m-d or accountid=accounthash, etc.' value="<?php echo "$URLPassWith"; ?>" size="50"/>
328  </div>
329  </div>
330 
331  <div class="col-xs-12 hcu-container-margin">
332  <label for="WWWSvr" class="col-xs-3">
333  Mx Rest Endpoint:
334  </label>
335  <input id='WWWSvr' name='WWWSvr' class='col-xs-8' value="<?php echo "$WWWSvr"; ?>" size="50"/>
336  </div>
337 
338 
339  <div class="col-xs-12 hcu-container-margin">
340  <div class="col-xs-6">
341  <button id="btnGenerate" name='btnGenerate' type="submit" class="k-button k-primary hcu-all-100 hcu-xs-btn-margin-top hcu-xs-btn-pad">
342  <span class="fa fa-arrow-right local-pad-icon"></span>
343  Format and Fetch
344  </button>
345  </div>
346  <input type="hidden" name="generate" value="go">
347  </div>
348  </fieldset>
349  </form>
350  </div>
351  <div class='well well-sm col-xs-6' style="max-width:48%; margin-left:10px;">
352  <div class="col-xs-12 hcu-container-margin">
353  Computed Request
354  <textarea id='targetLink' name='targetLink' class='col-xs-12' style="height: 10em;">
355 <?php echo "$error"; ?>
356 <?php echo htmlentities($cmd); ?>
357  </textarea>
358  </div>
359  <div class="col-xs-12 hcu-container-margin">
360  Result
361  <textarea id="getDataResult" name="getDataResult" class="col-xs-12" style="height: 27em;">
362 <?php echo $response; ?>
363  </textarea>
364  </div>
365  </div>
366  <div class='col-xs-12'>
367  <div class="well">
368  How to use:<br>
369  <ol>
370  <li>Enter App ID, Org ID, User ID. Leave User Key blank to get generated key.</li>
371  <li>Set Rest Option [sessions | accounts | transactions] and Pass With (as needed). </li>
372  <li>Click 'Format and Fetch' Key. This generates a User Key to start communications.</li>
373  <ul>
374  <li>Note that first click will show Error in response - because there wasn't a key yet on post. 'Fetch' again and the userkey will work.</li>
375  <li>Could also copy/paste key from vendor log to test key planted at Mx</li>
376  </ul>
377  <li>If testing authentication process, enter password matching the User ID; Copy &lt;key&gt; from previous reply as session key.</li>
378  <li>Sending password generates a challenge reply. To respond, set passwith to send corresponding MFA_E and MFA_## answers; Copy &lt;key&gt; from previous reply as session key.</li>
379  </ol>
380  </div>
381  <div class="well">
382  Possible Rest Options are:<br>
383  <ul>
384  <li>sessions</li>
385  <li>accounts</li>
386  <li>transactions</li>
387  </ul>
388  Possible Passwith Options:
389  <ul>
390  <li>sessions request MFA challenge response
391  <ul>
392  <li>send MFA_E=email@host.com&MFA_55=answer55&MFA_64=answer64 where MFA_## matches challenge received</li>
393  </ul>
394  </li>
395  <li>accounts request
396  <ul>
397  <li>accounts request has no passwith</li>
398  </ul>
399  </li>
400  <li>transactions request
401  <ul>
402  <li>send start_date=YYYY-MM-DD&accountid=&lt;id&gt; of selected account from previous accounts request</li>
403  </ul>
404  </li>
405  </ul>
406  </div>
407 </div>
408 </body>
409 </html>
410 
411 <!--============================================-->
412 <?php
413 /**
414  *
415  * @param string $baseURL base HomeCU URL to hit for data
416  * @param string $mxClient HomeCU client code
417  * @param string $mxHMACKey trusted-detail configured HMAC key
418  * @param string $mxRestOpt [sessions | accounts | transactions]
419  * @param array $mxSessionData array of query values
420  * @param string $mxSessionKey valid key returned from prior call
421  * empty on initial sessions call
422  * @return boolean
423  * @throws Exception
424  */
425 function mxMakeRequest($baseURL, $mxClient, $mxHMACKey, $mxRestOpt, $mxSessionData, $mxSessionKey) {
426  # baseURL=wwwServer mxClient=cu mxRestOpt=URLQstr
427  # mxSessionData is array of
428  # userkey = $USERKEY
429  # userid = $USERID # used as member identifier for 'accounts' request
430  # userpass = $USERPASS
431  # accountid = selected account identifier
432  # start_date = start date for transaction list
433  # formpost = form variables to be posted. Send as name=value string, format here
434  # required content varies based on mxRestOpt
435  #
436  # mxSessionKey is valid key returned on previous session call,
437  # or empty for initial session create
438  try {
439 
440  # when testing from docker the baseURL is localhost:8000
441  # but popen to port 8000 fails.
442  # so... remove the :8000 and php is happy
443  # but note! put the :8000 back to paste in terminal session
444  $baseURL = str_replace(":8000","", $baseURL);
445  $userkey = HCU_array_key_value('userkey', $mxSessionData);
446  $userid = HCU_array_key_value('userid', $mxSessionData);
447  $userpass = HCU_array_key_value('userpass', $mxSessionData);
448 
449  $formpost = HCU_array_key_value('formpost', $mxSessionData);
450  # turn the name=value pairs into an array, and count how many are MFA_*
451  $mfa = 0;
452  $formfields = array();
453  parse_str($formpost, $formfields);
454  foreach (array_keys($formfields) as $rkey) {
455  $m = strpos($rkey, 'MFA_');
456  if ($m !== FALSE && $m == 0) {
457  $mfa++;
458  }
459  }
460  $account = HCU_array_key_value('accountid', $formfields);
461  $start_date = HCU_array_key_value('start_date', $formfields);
462 
463  $boolresult = true;
464  if (empty($mxHMACKey)) {
465  throw new Exception("Missing key");
466  }
467 
468  $result['headers']['Accept'] = 'application/vnd.moneydesktop.mdx.v5+xml';
469  $result['headers']['Content-Type'] = 'application/vnd.moneydesktop.mdx.v5+xml';
470  $result['headers']['MDX-Job-Type'] = 'foreground';
471 # $result['headers']['MDX-Job-Type'] = 'background';
472 
473  # $mxSessionKey s/b empty for initial session create, otherwise return what the server sent
474  if (!empty($mxSessionKey)) {
475  $result['headers']['MDX-Session-Key'] = $mxSessionKey;
476  }
477 
478  switch ($mxRestOpt) {
479  case 'sessions':
480  $mxURL = "$baseURL/$mxClient/sessions";
481  if (empty($mxSessionKey) ) {
482  if (empty($userkey) ) {
483  # no session key - create session
484  $mxVerb = 'POST';
485  /*
486  * <mdx version='5.0'>
487  * <session>
488  * <login><![CDATA[janedoe]]></login>
489  * <password><![CDATA[topsecret]]></password>
490  * </session>
491  * </mdx>
492  */
493  $mxContent = "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n<session>\n<login><![CDATA[$userid]]></login>\n<password><![CDATA[$userpass]]></password>\n</session>\n</mdx>\n";
494  } else {
495  # no session key - create session
496  $mxVerb = 'POST';
497  /*
498  * <mdx version='5.0'>
499  * <session>
500  * <userkey><![CDATA[UNIQUE_KEY_FOR_THIS_USER]]><</userkey>
501  * </session>
502  * </mdx>
503  */
504  $mxContent = "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n<session>\n<userkey><![CDATA[$userkey]]></userkey>\n</session>\n</mdx>\n";
505  print $mxContent;
506  }
507  } else {
508  if (!$mfa) {
509  throw new Exception('SessionKey but no MFA_*');
510  }
511  # must be mfa challenge response
512  $mxVerb = 'PUT';
513  /*
514  * <mdx version='5.0'>
515  * <session>
516  * <key>UNIQUE_KEY_FOR_THIS_SESSION</key>
517  * <challenges>
518  * <challenge>
519  * <id>UNIQUE_IDENTIFIER_FOR_THIS_CHALLENGE</id>
520  * <answer><![CDATA[answer]]></answer>
521  * </challenge>
522  * <challenge>
523  * <id>UNIQUE_IDENTIFIER_FOR_THIS_CHALLENGE</id>
524  * <answer><![CDATA[answer]]></question>
525  * </challenge>
526  * <!-- additional challenge questions -->
527  * </challenges>
528  * </session>
529  * </mdx>
530  */
531  $mxContent = "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n<session>\n<key>$mxSessionKey</key>\n";
532  if (is_array($formfields) ) {
533  $ffcount = 0;
534  $mxMFA = '';
535  foreach ($formfields as $key => $value) {
536  if (substr($key,0,4) == 'MFA_') {
537  $mxMFA .= "<challenge>\n<id>$key</id>\n<answer><![CDATA[$value]]></answer></challenge>\n";
538  $ffcount++;
539  }
540  }
541  if ($ffcount) {
542  $mxContent .= "<challenges>\n$mxMFA\n</challenges>\n";
543  } else {
544  throw new Exception('Invalid session content requested');
545  }
546  }
547  $mxContent .= "</session>\n</mdx>\n";
548  }
549 // # POST and PUT requests include a Content-Type header
550 // $result['headers']['Content-Type'] = 'application/vnd.moneydesktop.mdx.v5+xml';
551  break;
552  case 'accounts':
553  # GET /accounts
554  # need to send a SessionKey header w/enough info to get the right member
555  if (empty($userid)) {
556  throw new Exception("Missing accounts parameters");
557  }
558  $mxURL = "$baseURL/$mxClient/accounts";
559  $mxVerb = 'GET';
560  $mxContent = '';
561 
562  break;
563  case 'transactions':
564  #GET /accounts/:account_id/transactions?start_date=YYYY-MM-DD&page=n
565  # need to send a SessionKey header w/enough info to get the right member
566  if (empty($account) || empty($start_date)) {
567  throw new Exception("Missing transactions parameters " . json_encode($formfields));
568  }
569  if (!strtotime($start_date)) {
570  throw new Exception("Invalid transactions parameter start_date");
571  }
572  $start_date = date('Y-m-d', strtotime($start_date));
573  $mxURL = "$baseURL/$mxClient/accounts/$account/transactions?start_date=$start_date&page=1";
574  $mxVerb = 'GET';
575  $mxContent = '';
576  break;
577  default:
578  throw new Exception("Unknown rest endpoint");
579  break;
580  }
581  $mxRestOpt = (substr($mxRestOpt,0,1) == '/' ? $mxRestOpt : "/$mxRestOpt");
582  $result['mxRestOpt'] = $mxRestOpt;
583  $result['mxVerb'] = $mxVerb;
584  $result['mxURL'] = $mxURL;
585  $result['mxContent'] = $mxContent;
586  $mxContentType = HCU_array_key_value('Content-Type', $result['headers']);
587  $mxEpoch = time();
588  $result['headers']['Date'] = $mxEpoch;
589  $result['headers']['Content-MD5'] =md5($mxContent);
590  $mxAccept = HCU_array_key_value('Accept', $result['headers']);
591  if (empty($mxSessionKey)) {
592  $mxSessionKey = ''; # in case it is null, force empty string
593  }
594  $mxContentMD5 = HCU_array_key_value('Content-MD5', $result['headers']);
595 //POST /sessions "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n <session>\n <userkey><![CDATA[the-userkey]]></userkey>\n </session>\n</mdx>\n"
596 //Content-Type: application/vnd.moneydesktop.mdx.v5+xml
597 //Date: 1382975431
598 //Accept: application/vnd.moneydesktop.mdx.v5+xml
599 //MDX-Session-Key:
600  #HTTP VERB + "\n" + # $mxVerb
601  #Content-MD5 Header + "\n" + # $mxContentMD5
602  #Content-Type Header + "\n" + # $mxContentType
603  #UNIX Epoch Date Time + "\n" + # $mxEpoch
604  #Accept Header + "\n" + # $mxAccept
605  #MDX-Session-Key + "\n" + # $mxSessionKey
606  #REST Resource of Request # $mxRestOpt
607 
608 // $sigStr = "POST\ne9a179f879165fd64bdeaa57032d342f\napplication/vnd.moneydesktop.mdx.v5+xml\n1382975431\napplication/vnd.moneydesktop.mdx.v5+xml\n\n/sessions";
609 // Dom't be mislead by the \n\n/sessions at the end. That is \n{empty session key}\n/sessions
610  $sigStr = "{$mxVerb}\n{$mxContentMD5}\n{$mxContentType}\n{$mxEpoch}\n{$mxAccept}\n{$mxSessionKey}\n{$mxRestOpt}";
611  # calculate SHA1 using key mxHMACKey above as test
612  $sigHash = hash_hmac("SHA1", $sigStr, base64_decode($mxHMACKey));
613  $result['headers']['MDX-HMAC'] = $sigHash;
614 
615  } catch (Exception $e) {
616  $boolresult = false;
617  $result['because'] = $e->getMessage();
618  }
619  $result['status'] = $boolresult;
620  $result['showme']= json_encode(array(
621  'mxHMACKey' => $mxHMACKey,
622  'sigStr' => $sigStr,
623  'sigHash' => $sigHash));
624  return $result;
625 }
626 function mxGetData($mxVerb, $mxHeaders, $mxContent, $mxURL) {
627 
628  # when testing from docker the baseURL is localhost:8000
629  # but popen to port 8000 fails.
630  # so... remove the :8000 and php is happy
631  # but note! put the :8000 back to paste in terminal session
632  $mxURL = str_replace(":8000","", $mxURL);
633 
634 
635  $curlopts = array(
636  CURLOPT_RETURNTRANSFER => 1,
637  CURLOPT_SSL_VERIFYPEER => 0,
638  CURLOPT_SSL_VERIFYHOST => 0,
639  CURLOPT_HEADER => TRUE,
640  CURLOPT_USERAGENT => 'HCU_GenMDX',
641  CURLOPT_URL => "$mxURL");
642 
643  $ch = curl_init();
644 
645 // to capture verbose log.....
646 //curl_setopt($ch, CURLOPT_VERBOSE, true);
647 //$verbose = fopen('/tmp/ectrace', 'a+');
648 //fwrite($verbose,"\n{$mxContent}\n");
649 //curl_setopt($ch, CURLOPT_STDERR, $verbose);
650 
651  curl_setopt_array($ch, $curlopts);
652  if ($mxVerb != 'GET') {
653  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mxVerb);
654  }
655  if (strlen($mxContent) > 0) {
656  curl_setopt($ch, CURLOPT_POSTFIELDS, $mxContent);
657  }
658  $headers = array();
659  if (count($mxHeaders) ) {
660  foreach ($mxHeaders as $hdr => $hdrContent) {
661  $headers[] = "{$hdr}: {$hdrContent}";
662  }
663  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
664  }
665 
666  $respERR = '';
667  $return = array();
668  $return['request'] = "$mxVerb to $mxURL with headers " . print_r($headers, true) . " and content $mxContent";
669  $response = curl_exec($ch);
670 
671  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
672  $return['respHTTP'] = (integer) $respHTTP;
673 
674  $respCURL = curl_errno($ch);
675  $return['respCURL'] = (integer) $respCURL;
676 
677  // Split response headers from the Response Body
678  $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
679  $return['responseHeaders'] = substr($response, 0, $header_size);
680  $return['responseBody'] = substr($response, $header_size);
681 
682 
683  if ($respCURL) {
684  # Bad! Don't hide the error, return the curl error if it occurred.
685  $return['respERR'] = "Connection Failed cURL $respCURL";
686  } elseif ($respHTTP > 400 && $respHTTP < 600) {
687  # HTTP Response 4xx client error or 5xx server error
688  $return['respERR'] = "Connection Failed HTTP $respHTTP ";
689  } elseif (!isset($response) || trim($response) == '') {
690  if ($respHTTP != 204 && $respHTTP != 200) {
691  # HTTP 204 No Content w/o response = 'Everything OK but no data'
692  # HTTP 200 OK w/o response = 'Everything OK but no data'
693  $return['respERR'] = "Empty Response with HTTP $respHTTP ";
694  }
695  }
696  return $return;
697 
698 }
699 
700 function formatData($data) {
701 
702 
703 
704  $dom = new DOMDocument();
705 
706  $dom->preserveWhiteSpace = false;
707  $dom->formatOutput = true;
708 
709  $dom->loadXML($data);
710  $out = $dom->saveXML();
711  return ($out);
712 }
713 
714 ?>
715 <script>
716  $("#btnGenerate").click( function() {
717  var org = $("#cu").val();
718  var action = $("#formAppKey").attr( "action" );
719 
720 
721  });
722 
723 </script>
724 <style>
725 
726 html {
727  overflow: auto;
728 }
729 ol, ul {
730  padding-left: 20px;
731 }
732 .local-transfer-msg {
733  padding: 1em;
734 }
735 
736 .local-transfer-button {
737  padding-top: 20px;
738 }
739 
740 
741 .k-dropdown .k-input,.k-selectbox .k-input {
742  white-space: normal;
743 }
744 
745  .container-fluid-margin {
746  margin: 15px;
747  }
748 
749  .k-block > .k-header {
750  white-space: normal;
751  height: 100%;
752  }
753 
754  .hcu-info-margin, .hcu-error-margin {
755  margin: 15px 0;
756  }
757 
758  .hcu-info-padding, .hcu-error-padding {
759  padding: 15px;
760  }
761 
762  .hcu-all-100 {
763  width: 100%;
764  }
765  /* top-bottom margin */
766  .hcu-container-margin {
767  margin: 15px 0;
768  }
769  .local-pad-icon {
770  padding-right: 5px;
771  }
772 
773 </style>
774 
Definition: User.php:7