Fixes #6190 Portal Login Redirect (#6191)
[openemr.git] / portal / index.php
blobf5e697d153bb26cd43b305e88a79ece8f869df4e
1 <?php
3 /**
4 * import_template.php
6 * @package OpenEMR
7 * @link https://www.open-emr.org
8 * @author Cassian LUP <cassi.lup@gmail.com>
9 * @author Jerry Padgett <sjpadgett@gmail.com>
10 * @author Brady Miller <brady.g.miller@gmail.com>
11 * @author Tyler Wrenn <tyler@tylerwrenn.com>
12 * @copyright Copyright (c) 2011 Cassian LUP <cassi.lup@gmail.com>
13 * @copyright Copyright (c) 2016-2022 Jerry Padgett <sjpadgett@gmail.com>
14 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
15 * @copyright Copyright (c) 2020 Tyler Wrenn <tyler@tylerwrenn.com>
16 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
19 // prevent UI redressing
20 Header("X-Frame-Options: DENY");
21 Header("Content-Security-Policy: frame-ancestors 'none'");
23 //setting the session & other config options
25 // Will start the (patient) portal OpenEMR session/cookie.
26 require_once __DIR__ . "/../src/Common/Session/SessionUtil.php";
27 OpenEMR\Common\Session\SessionUtil::portalSessionStart();
29 //don't require standard openemr authorization in globals.php
30 $ignoreAuth_onsite_portal = true;
32 //includes
33 require_once '../interface/globals.php';
34 require_once __DIR__ . "/lib/appsql.class.php";
35 $logit = new ApplicationTable();
37 use OpenEMR\Common\Crypto\CryptoGen;
38 use OpenEMR\Common\Csrf\CsrfUtils;
39 use OpenEMR\Common\Logging\EventAuditLogger;
40 use OpenEMR\Common\Logging\SystemLogger;
41 use OpenEMR\Core\Header;
42 use OpenEMR\Services\LogoService;
44 //For redirect if the site on session does not match
45 $landingpage = "index.php?site=" . urlencode($_SESSION['site_id']);
46 $logoService = new LogoService();
47 $logoSrc = $logoService->getLogo("portal/login/primary");
49 // allow both get and post redirect params here... everything will be sanitized in get_patient_info.php before we
50 // actually do anything with the redirect
51 // this value should already be url encoded.
52 $redirectUrl = $_REQUEST['redirect'] ?? '';
54 //exit if portal is turned off
55 if (!(isset($GLOBALS['portal_onsite_two_enable'])) || !($GLOBALS['portal_onsite_two_enable'])) {
56 echo xlt('Patient Portal is turned off');
57 exit;
59 $auth['portal_pwd'] = '';
60 if (isset($_GET['woops'])) {
61 unset($_GET['woops']);
62 unset($_SESSION['password_update']);
65 if (!empty($_GET['forward_email_verify'])) {
66 if (empty($GLOBALS['portal_onsite_two_register']) || empty($GLOBALS['google_recaptcha_site_key']) || empty($GLOBALS['google_recaptcha_secret_key'])) {
67 (new SystemLogger())->debug("registration not supported, so stopped attempt to use forward_email_verify token");
68 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
69 header('Location: ' . $landingpage . '&w&u');
70 exit();
73 $crypto = new CryptoGen();
74 if (!$crypto->cryptCheckStandard($_GET['forward_email_verify'])) {
75 (new SystemLogger())->debug("illegal token, so stopped attempt to use forward_email_verify token");
76 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
77 header('Location: ' . $landingpage . '&w&u');
78 exit();
81 $token_one_time = $crypto->decryptStandard($_GET['forward_email_verify'], null, 'drive', 6);
82 if (empty($token_one_time)) {
83 (new SystemLogger())->debug("unable to decrypt token, so stopped attempt to use forward_email_verify token");
84 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
85 header('Location: ' . $landingpage . '&w&u');
86 exit();
89 $sqlResource = sqlStatementNoLog("SELECT `id`, `token_onetime`, `fname`, `mname`, `lname`, `dob`, `email`, `language` FROM `verify_email` WHERE `active` = 1 AND `token_onetime` LIKE BINARY ?", [$token_one_time . '%']);
90 if (sqlNumRows($sqlResource) > 1) {
91 (new SystemLogger())->debug("active token (" . $token_one_time . ") found more than once, so stopped attempt to use forward_email_verify token");
92 EventAuditLogger::instance()->newEvent('patient-reg-email-verify', '', '', 0, "active token (" . $token_one_time . ") found more than once, so stopped attempt to use forward_email_verify token");
93 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
94 header('Location: ' . $landingpage . '&w&u');
95 exit();
97 if (!sqlNumRows($sqlResource)) {
98 (new SystemLogger())->debug("active token (" . $token_one_time . ") not found, so stopped attempt to use forward_email_verify token");
99 EventAuditLogger::instance()->newEvent('patient-reg-email-verify', '', '', 0, "active token (" . $token_one_time . ") not found, so stopped attempt to use forward_email_verify token");
100 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
101 header('Location: ' . $landingpage . '&w&u');
102 exit();
104 $sqlVerify = sqlFetchArray($sqlResource);
105 if (empty($sqlVerify['id']) || empty($sqlVerify['token_onetime'])) {
106 (new SystemLogger())->debug("active token (" . $token_one_time . ") not properly set up, so stopped attempt to use forward_email_verify token");
107 EventAuditLogger::instance()->newEvent('patient-reg-email-verify', '', '', 0, "active token (" . $token_one_time . ") not properly set up, so stopped attempt to use forward_email_verify token");
108 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
109 header('Location: ' . $landingpage . '&w&u');
110 exit();
112 // have "used" token, so now make it inactive
113 sqlStatementNoLog("UPDATE `verify_email` SET `active` = 0 WHERE `id` = ?", [$sqlVerify['id']]);
115 $validateTime = hex2bin(str_replace($token_one_time, '', $sqlVerify['token_onetime']));
116 if ($validateTime <= time()) {
117 (new SystemLogger())->debug("active token (" . $token_one_time . ") has expired, so stopped attempt to use forward_email_verify token");
118 EventAuditLogger::instance()->newEvent('patient-reg-email-verify', '', '', 0, "active token (" . $token_one_time . ") has expired, so stopped attempt to use forward_email_verify token");
119 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
120 die(xlt("Your email verification link has expired. Reset and try again."));
123 if (!empty($sqlVerify['fname']) && !empty($sqlVerify['lname']) && !empty($sqlVerify['dob']) && !empty($sqlVerify['email']) && !empty($sqlVerify['language'])) {
124 // token has passed and have all needed data
125 $fnameRegistration = $sqlVerify['fname'];
126 $_SESSION['fnameRegistration'] = $fnameRegistration;
127 $mnameRegistration = $sqlVerify['mname'] ?? '';
128 $_SESSION['mnameRegistration'] = $mnameRegistration;
129 $lnameRegistration = $sqlVerify['lname'];
130 $_SESSION['lnameRegistration'] = $lnameRegistration;
131 $dobRegistration = $sqlVerify['dob'];
132 $_SESSION['dobRegistration'] = $dobRegistration;
133 $emailRegistration = $sqlVerify['email'];
134 $_SESSION['emailRegistration'] = $emailRegistration;
135 $languageRegistration = $sqlVerify['language'];
136 $_SESSION['language_choice'] = (int)($languageRegistration ?? 1);
137 $portalRegistrationAuthorization = true;
138 $_SESSION['token_id_holder'] = $sqlVerify['id'];
139 (new SystemLogger())->debug("token worked for forward_email_verify token, now on to registration");
140 EventAuditLogger::instance()->newEvent('patient-reg-email-verify', '', '', 1, "token (" . $token_one_time . ") was successful for forward_email_verify token");
141 require_once(__DIR__ . "/account/register.php");
142 exit();
143 } else {
144 (new SystemLogger())->debug("active token (" . $token_one_time . ") did not have all required data, so stopped attempt to use forward_email_verify token");
145 EventAuditLogger::instance()->newEvent('patient-reg-email-verify', '', '', 0, "active token (" . $token_one_time . ") did not have all required data, so stopped attempt to use forward_email_verify token");
146 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
147 header('Location: ' . $landingpage . '&w&u');
148 exit();
150 } elseif (isset($_GET['forward'])) {
151 if ((empty($GLOBALS['portal_two_pass_reset']) && empty($GLOBALS['portal_onsite_two_register'])) || empty($GLOBALS['google_recaptcha_site_key']) || empty($GLOBALS['google_recaptcha_secret_key'])) {
152 (new SystemLogger())->debug("reset password and registration not supported, so stopped attempt to use forward token");
153 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
154 header('Location: ' . $landingpage . '&w&u');
155 exit();
157 $auth = false;
158 if (strlen($_GET['forward']) >= 64) {
159 $crypto = new CryptoGen();
160 if ($crypto->cryptCheckStandard($_GET['forward'])) {
161 $one_time = $crypto->decryptStandard($_GET['forward'], null, 'drive', 6);
162 if (!empty($one_time)) {
163 $auth = sqlQueryNoLog("Select * From patient_access_onsite Where portal_onetime Like BINARY ?", array($one_time . '%'));
167 if ($auth === false) {
168 error_log("PORTAL ERROR: " . errorLogEscape('One time reset:' . $_GET['forward']), 0);
169 $logit->portalLog('login attempt', '', ($_GET['forward'] . ':invalid one time'), '', '0');
170 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
171 header('Location: ' . $landingpage . '&w&u');
172 exit();
174 $parse = str_replace($one_time, '', $auth['portal_onetime']);
175 $validate = hex2bin(substr($parse, 6));
176 if ($validate <= time()) {
177 error_log("PORTAL ERROR: " . errorLogEscape('One time reset link expired. Dying.'), 0);
178 $logit->portalLog('password reset attempt', '', ($_POST['uname'] . ':link expired'), '', '0');
179 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
180 die(xlt("Your one time credential reset link has expired. Reset and try again.") . "time:$validate time:" . time());
182 $_SESSION['pin'] = substr($parse, 0, 6);
183 $_SESSION['forward'] = $auth['portal_onetime'];
184 $_SESSION['portal_username'] = $auth['portal_username'];
185 $_SESSION['portal_login_username'] = $auth['portal_login_username'];
186 $_SESSION['password_update'] = 2;
187 $_SESSION['onetime'] = $auth['portal_pwd'];
188 unset($auth);
190 // security measure -- will check on next page.
191 $_SESSION['itsme'] = 1;
195 // Deal with language selection
197 // collect default language id (skip this if this is a password update or reset)
198 if (!(isset($_SESSION['password_update']) || (!empty($GLOBALS['portal_two_pass_reset']) && !empty($GLOBALS['google_recaptcha_site_key']) && !empty($GLOBALS['google_recaptcha_secret_key']) && isset($_GET['requestNew'])))) {
199 $res2 = sqlStatement("select * from lang_languages where lang_description = ?", array($GLOBALS['language_default']));
200 for ($iter = 0; $row = sqlFetchArray($res2); $iter++) {
201 $result2[$iter] = $row;
204 if (count($result2) == 1) {
205 $defaultLangID = $result2[0]["lang_id"];
206 $defaultLangName = $result2[0]["lang_description"];
207 } else {
208 //default to english if any problems
209 $defaultLangID = 1;
210 $defaultLangName = "English";
213 // set session variable to default so login information appears in default language
214 $_SESSION['language_choice'] = $defaultLangID;
215 // collect languages if showing language menu
216 if ($GLOBALS['language_menu_login']) {
217 // sorting order of language titles depends on language translation options.
218 $mainLangID = empty($_SESSION['language_choice']) ? '1' : $_SESSION['language_choice'];
219 // Use and sort by the translated language name.
220 $sql = "SELECT ll.lang_id, " .
221 "IF(LENGTH(ld.definition),ld.definition,ll.lang_description) AS trans_lang_description, " .
222 "ll.lang_description " .
223 "FROM lang_languages AS ll " .
224 "LEFT JOIN lang_constants AS lc ON lc.constant_name = ll.lang_description " .
225 "LEFT JOIN lang_definitions AS ld ON ld.cons_id = lc.cons_id AND " .
226 "ld.lang_id = ? " .
227 "ORDER BY IF(LENGTH(ld.definition),ld.definition,ll.lang_description), ll.lang_id";
228 $res3 = SqlStatement($sql, array($mainLangID));
229 for ($iter = 0; $row = sqlFetchArray($res3); $iter++) {
230 $result3[$iter] = $row;
232 if (count($result3) == 1) {
233 //default to english if only return one language
234 $hiddenLanguageField = "<input type='hidden' name='languageChoice' value='1' />\n";
236 } else {
237 $hiddenLanguageField = "<input type='hidden' name='languageChoice' value='" . attr($defaultLangID) . "' />\n";
241 <!DOCTYPE html>
242 <html>
243 <head>
244 <title><?php echo xlt('Patient Portal Login'); ?></title>
245 <?php
246 Header::setupHeader(['no_main-theme', 'datetime-picker', 'patientportal-style', 'patientportal-base', 'patientportal-register']);
248 <script>
249 function checkUserName() {
250 let vacct = document.getElementById('uname').value;
251 let vsuname = document.getElementById('login_uname').value;
252 if (vsuname.length < 12) {
253 alert(<?php echo xlj('User Name must be at least 12 characters!'); ?>);
254 return false;
256 let data = {
257 'action': 'userIsUnique',
258 'account': vacct,
259 'loginUname': vsuname
261 $.ajax({
262 type: 'GET',
263 url: './account/account.php',
264 data: data
265 }).done(function (rtn) {
266 if (rtn === '1') {
267 return true;
269 alert(<?php echo xlj('Log In Name is unavailable. Try again!'); ?>);
270 return false;
274 function process() {
275 if (!(validate())) {
276 alert(<?php echo xlj('Field(s) are missing!'); ?>);
277 return false;
279 return true;
282 function validate() {
283 let pass = true;
285 if (document.getElementById('uname').value == "") {
286 $('#uname').addClass('is-invalid');
287 pass = false;
289 if (document.getElementById('pass').value == "") {
290 $('#pass').addClass('is-invalid');
291 pass = false;
293 return pass;
296 function process_new_pass() {
297 if (!(validate_new_pass())) {
298 alert(<?php echo xlj('Field(s) are missing!'); ?>);
299 return false;
301 if (document.getElementById('pass_new').value != document.getElementById('pass_new_confirm').value) {
302 alert(<?php echo xlj('The new password fields are not the same.'); ?>);
303 return false;
305 if (document.getElementById('pass').value == document.getElementById('pass_new').value) {
306 alert(<?php echo xlj('The new password can not be the same as the current password.'); ?>);
307 return false;
311 function validate_new_pass() {
312 var pass = true;
313 if (document.getElementById('uname').value == "") {
314 $('#uname').addClass('is-invalid');
315 pass = false;
317 if (document.getElementById('pass').value == "") {
318 $('#pass').addClass('is-invalid');
319 pass = false;
321 if (document.getElementById('pass_new').value == "") {
322 $('#pass_new').addClass('is-invalid');
323 pass = false;
325 if (document.getElementById('pass_new_confirm').value == "") {
326 $('#pass_new_confirm').addClass('is-invalid');
327 pass = false;
329 return pass;
331 </script>
333 <?php if (!empty($GLOBALS['portal_two_pass_reset']) && !empty($GLOBALS['google_recaptcha_site_key']) && !empty($GLOBALS['google_recaptcha_secret_key']) && isset($_GET['requestNew'])) { ?>
334 <script src="https://www.google.com/recaptcha/api.js" async defer></script>
335 <script>
336 function enableVerifyBtn(){
337 document.getElementById("submitRequest").disabled = false;
339 </script>
340 <?php // add csrf mechanism for the password reset ui
341 CsrfUtils::setupCsrfKey();
343 <?php } ?>
345 </head>
346 <body class="login">
347 <div id="wrapper" class="container text-center mx-auto">
348 <?php if (isset($_SESSION['password_update']) || isset($_GET['password_update'])) {
349 $_SESSION['password_update'] = 1;
351 <h2 class="title"><?php echo xlt('Please Enter New Credentials'); ?></h2>
352 <form class="form pb-5" action="get_patient_info.php" method="POST" onsubmit="return process_new_pass()">
353 <input style="display: none" type="text" name="dummyuname" />
354 <input style="display: none" type="password" name="dummypass" />
355 <?php if (isset($redirectUrl)) { ?>
356 <input id="redirect" type="hidden" name="redirect" value="<?php echo attr($redirectUrl); ?>" />
357 <?php } ?>
358 <div class="form-row my-3">
359 <label class="col-md-2 col-form-label" for="uname"><?php echo xlt('Account Name'); ?></label>
360 <div class="col-md">
361 <input class="form-control" name="uname" id="uname" type="text" readonly autocomplete="none" value="<?php echo attr($_SESSION['portal_username']); ?>" />
362 </div>
363 </div>
364 <div class="form-row my-3">
365 <label class="col-md-2 col-form-label" for="login_uname"><?php echo xlt('Use Username'); ?></label>
366 <div class="col-md">
367 <input class="form-control" name="login_uname" id="login_uname" type="text" autofocus autocomplete="none" title="<?php echo xla('Please enter a username of 12 to 80 characters. Recommended to include symbols and numbers but not required.'); ?>" placeholder="<?php echo xla('Must be 12 to 80 characters'); ?>" pattern=".{12,80}" value="<?php echo attr($_SESSION['portal_login_username']); ?>" onblur="checkUserName()" />
368 </div>
369 </div>
370 <div class="form-row my-3">
371 <label class="col-md-2 col-form-label" for="pass"><?php echo empty($_SESSION['onetime'] ?? null) ? xlt('Current Password') : ''; ?></label>
372 <div class="col-md">
373 <input class="form-control" name="pass" id="pass" <?php echo ($_SESSION['onetime'] ?? null) ? 'type="hidden" ' : 'type="password" '; ?> autocomplete="none" value="<?php echo attr($_SESSION['onetime'] ?? '');
374 $_SESSION['password_update'] = ($_SESSION['onetime'] ?? null) ? 2 : 1;
375 unset($_SESSION['onetime']); ?>" required />
376 </div>
377 </div>
378 <?php if ($_SESSION['pin'] ?? null) { ?>
379 <div class="form-row my-3">
380 <label class="col-md-2 col-form-label" for="token_pin"><?php echo xlt('One Time PIN'); ?></label>
381 <div class="col-md">
382 <input class="form-control" name="token_pin" id="token_pin" type="password" autocomplete="none" value="" required pattern=".{6,20}" />
383 </div>
384 </div>
385 <?php } ?>
386 <div class="form-row my-3">
387 <label class="col-md-2 col-form-label" for="pass_new"><?php echo xlt('New Password'); ?></label>
388 <div class="col-md">
389 <input class="form-control" name="pass_new" id="pass_new" type="password" required placeholder="<?php echo xla('Min length is 8 with upper,lowercase,numbers mix'); ?>" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" />
390 </div>
391 </div>
392 <div class="form-row my-3">
393 <label class="col-md-2 col-form-label" for="pass_new_confirm"><?php echo xlt('Confirm New Password'); ?></label>
394 <div class="col-md">
395 <input class="form-control" name="pass_new_confirm" id="pass_new_confirm" type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" />
396 </div>
397 </div>
398 <?php if ($GLOBALS['enforce_signin_email']) { ?>
399 <div class="form-row my-3">
400 <label class="col-md-2 col-form-label" for="passaddon"><?php echo xlt('Confirm Email Address'); ?></label>
401 <div class="col-md">
402 <input class="form-control" name="passaddon" id="passaddon" required placeholder="<?php echo xla('Current on record trusted email'); ?>" type="email" autocomplete="none" value="" />
403 </div>
404 </div>
405 <?php } ?>
406 <input class="btn btn-secondary float-left" type="button" onclick="document.location.replace('./index.php?woops=1&site=<?php echo attr_url($_SESSION['site_id']); ?><?php if (!empty($redirectUrl)) {
407 echo "&redirect=" . attr_url($redirectUrl); } ?>');" value="<?php echo xla('Cancel'); ?>" />
408 <input class="btn btn-primary float-right" type="submit" value="<?php echo xla('Log In'); ?>" />
409 </form>
410 <?php } elseif (!empty($GLOBALS['portal_two_pass_reset']) && !empty($GLOBALS['google_recaptcha_site_key']) && !empty($GLOBALS['google_recaptcha_secret_key']) && isset($_GET['requestNew'])) { ?>
411 <form id="resetPass" action="#" method="post">
412 <input type='hidden' id='csrf_token_form' name='csrf_token_form' value='<?php echo attr(CsrfUtils::collectCsrfToken('passwordResetCsrf')); ?>' />
413 <?php if (isset($redirectUrl)) { ?>
414 <input id="redirect" type="hidden" name="redirect" value="<?php echo attr($redirectUrl); ?>" />
415 <?php } ?>
416 <div class="text-center">
417 <fieldset>
418 <legend class='bg-primary text-white pt-2 py-1'><h3><?php echo xlt('Patient Credentials Reset') ?></h3></legend>
419 <div class="jumbotron jumbotron-fluid px-5 py-3">
420 <div class="form-row my-3">
421 <label class="col-md-2 col-form-label" for="fname"><?php echo xlt('First Name') ?></label>
422 <div class="col-md">
423 <input type="text" class="form-control" id="fname" required placeholder="<?php echo xla('First Name'); ?>" />
424 </div>
425 </div>
426 <div class="form-row my-3">
427 <label class="col-md-2 col-form-label" for="lname"><?php echo xlt('Last Name') ?></label>
428 <div class="col-md">
429 <input type="text" class="form-control" id="lname" required placeholder="<?php echo xla('Last Name'); ?>" />
430 </div>
431 </div>
432 <div class="form-row my-3">
433 <label class="col-md-2 col-form-label" for="dob"><?php echo xlt('Birth Date') ?></label>
434 <div class="col-md">
435 <input id="dob" type="text" required class="form-control datepicker" placeholder="<?php echo xla('YYYY-MM-DD'); ?>" />
436 </div>
437 </div>
438 <div class="form-row my-3">
439 <label class="col-md-2 col-form-label" for="emailInput"><?php echo xlt('Enter E-Mail Address') ?></label>
440 <div class="col-md">
441 <input id="emailInput" type="email" class="form-control" required placeholder="<?php echo xla('Current trusted email address on record.'); ?>" maxlength="100" />
442 </div>
443 </div>
444 </div>
445 <div class="form-group">
446 <div class="d-flex justify-content-center">
447 <div class="g-recaptcha" data-sitekey="<?php echo attr($GLOBALS['google_recaptcha_site_key']); ?>" data-callback="enableVerifyBtn"></div>
448 </div>
449 </div>
450 <input class="btn btn-secondary float-left" type="button" onclick="document.location.replace('./index.php?woops=1&site=<?php echo attr_url($_SESSION['site_id']); ?><?php if (!empty($redirectUrl)) {
451 echo "&redirect=" . attr_url($redirectUrl); } ?>');" value="<?php echo xla('Cancel'); ?>" />
452 <button id="submitRequest" class="btn btn-primary nextBtn float-right" type="submit" disabled="disabled"><?php echo xlt('Verify') ?></button>
453 </fieldset>
454 </div>
455 </form>
456 <?php } else {
457 ?> <!-- Main logon -->
458 <img class="img-fluid login-logo" src='<?php echo $logoSrc; ?>'>
459 <form class="text-center" action="get_patient_info.php" method="POST" onsubmit="return process()">
460 <?php if (isset($redirectUrl)) { ?>
461 <input id="redirect" type="hidden" name="redirect" value="<?php echo attr($redirectUrl); ?>" />
462 <?php } ?>
463 <fieldset>
464 <legend class="bg-primary text-white pt-2 py-1"><h3><?php echo xlt('Patient Portal Login'); ?></h3></legend>
465 <div class="jumbotron jumbotron-fluid px-5 py-3">
466 <div class="form-row my-3">
467 <label class="col-md-2 col-form-label" for="uname"><?php echo xlt('Username') ?></label>
468 <div class="col-md">
469 <input type="text" class="form-control" name="uname" id="uname" autocomplete="none" required />
470 </div>
471 </div>
472 <div class="form-row mt-3">
473 <label class="col-md-2 col-form-label" for="pass"><?php echo xlt('Password') ?></label>
474 <div class="col-md">
475 <input class="form-control" name="pass" id="pass" type="password" required autocomplete="none" />
476 </div>
477 </div>
478 <?php if ($GLOBALS['enforce_signin_email']) { ?>
479 <div class="form-row mt-3">
480 <label class="col-md-2 col-form-label" for="passaddon"><?php echo xlt('E-Mail Address') ?></label>
481 <div class="col-md">
482 <input class="form-control" name="passaddon" id="passaddon" type="email" autocomplete="none" />
483 </div>
484 </div>
485 <?php } ?>
486 <?php if ($GLOBALS['language_menu_login']) { ?>
487 <?php if (count($result3) != 1) { ?>
488 <div class="form-group mt-1">
489 <label class="col-form-label-sm" for="selLanguage"><?php echo xlt('Language'); ?></label>
490 <select class="form-control form-control-sm" id="selLanguage" name="languageChoice">
491 <?php
492 echo "<option selected='selected' value='" . attr($defaultLangID) . "'>" .
493 text(xl('Default') . " - " . xl($defaultLangName)) . "</option>\n";
494 foreach ($result3 as $iter) {
495 if ($GLOBALS['language_menu_showall']) {
496 if (!$GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
497 continue; // skip the dummy language
499 echo "<option value='" . attr($iter['lang_id']) . "'>" .
500 text($iter['trans_lang_description']) . "</option>\n";
501 } else {
502 if (in_array($iter['lang_description'], $GLOBALS['language_menu_show'])) {
503 if (!$GLOBALS['allow_debug_language'] && $iter['lang_description'] == 'dummy') {
504 continue; // skip the dummy language
506 echo "<option value='" . attr($iter['lang_id']) . "'>" .
507 text($iter['trans_lang_description']) . "</option>\n";
512 </select>
513 </div>
514 <?php }
515 } ?>
516 </div>
517 <div class="row">
518 <div class="col-12">
519 <?php if (!empty($GLOBALS['portal_onsite_two_register']) && !empty($GLOBALS['google_recaptcha_site_key']) && !empty($GLOBALS['google_recaptcha_secret_key'])) { ?>
520 <button class="btn btn-secondary float-left" onclick="location.replace('./account/verify.php?site=<?php echo attr_url($_SESSION['site_id']); ?>')"><?php echo xlt('Register'); ?></button>
521 <?php } ?>
522 <?php if (!empty($GLOBALS['portal_two_pass_reset']) && !empty($GLOBALS['google_recaptcha_site_key']) && !empty($GLOBALS['google_recaptcha_secret_key']) && isset($_GET['w']) && (isset($_GET['u']) || isset($_GET['p']))) { ?>
523 <button class="btn btn-danger ml-2" onclick="location.replace('./index.php?requestNew=1&site=<?php echo attr_url($_SESSION['site_id']); ?><?php if (!empty($redirectUrl)) {
524 echo "&redirect=" . attr_url($redirectUrl); } ?>')"><?php echo xlt('Reset Credentials'); ?></button>
525 <?php } ?>
526 <button class="btn btn-success float-right" type="submit"><?php echo xlt('Log In'); ?></button>
527 </div>
528 </div>
529 </fieldset>
530 <?php if (!(empty($hiddenLanguageField))) {
531 echo $hiddenLanguageField;
532 } ?>
533 </form>
534 </div><!-- div wrapper -->
535 <?php } ?> <!-- logon wrapper -->
537 <div id="alertStore" class="d-none">
538 <div class="h6 alert alert-warning alert-dismissible fade show my-1 py-1" role="alert">
539 <button type="button" class="close my-1 py-0" data-dismiss="alert" aria-label="Close">
540 <span aria-hidden="true">&times;</span>
541 </button>
542 </div>
543 </div>
545 <script>
546 var tab_mode = true;
547 var webroot_url = <?php echo js_escape($GLOBALS['web_root']) ?>;
549 function restoreSession() {
550 //dummy functions so the dlgopen function will work in the patient portal
551 return true;
554 var isPortal = 1;
556 $(function () {
557 <?php // if something went wrong
558 if (!empty($GLOBALS['portal_two_pass_reset']) && !empty($GLOBALS['google_recaptcha_site_key']) && !empty($GLOBALS['google_recaptcha_secret_key']) && isset($_GET['requestNew'])) {
559 $_SESSION['register'] = true;
560 $_SESSION['authUser'] = 'portal-user';
561 $_SESSION['pid'] = true;
563 $('.datepicker').datetimepicker({
564 <?php $datetimepicker_timepicker = false; ?>
565 <?php $datetimepicker_showseconds = false; ?>
566 <?php $datetimepicker_formatInput = false; ?>
567 <?php require $GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'; ?>
569 $(document.body).on('hidden.bs.modal', function () {
570 callServer('cleanup');
572 $("#resetPass").on('submit', function (e) {
573 e.preventDefault();
574 callServer('reset_password');
575 return false;
577 <?php } ?>
578 <?php if (isset($_GET['w'])) { ?>
579 // mdsupport - Would be good to include some clue about what went wrong!
580 bsAlert(<?php echo xlj('Something went wrong. Please try again.'); ?>);
581 <?php } ?>
582 <?php // if successfully logged out
583 if (isset($_GET['logout'])) { ?>
584 bsAlert(<?php echo xlj('You have been successfully logged out.'); ?>);
585 <?php } ?>
587 return false;
590 function callServer(action) {
591 var data = {};
592 if (action === 'reset_password') {
593 data = {
594 'action': action,
595 'dob': $("#dob").val(),
596 'last': $("#lname").val(),
597 'first': $("#fname").val(),
598 'email': $("#emailInput").val(),
599 'g-recaptcha-response': grecaptcha.getResponse(),
600 'csrf_token_form': $("#csrf_token_form").val()
603 if (action === 'cleanup') {
604 data = {
605 'action': action
608 $.ajax({
609 type: 'GET',
610 url: './account/account.php',
611 data: data
612 }).done(function (rtn) {
613 if (action === "cleanup") {
614 let url = "./index.php?site=" + <?php echo js_url($_SESSION['site_id']); ?>; // Goto landing page.
615 let redirectUrl = $("#redirect").val();
616 if (redirectUrl) {
617 url += "&redirect=" + encodeURIComponent(redirectUrl);
619 window.location.href = url;
620 } else if (action === "reset_password") {
621 if (JSON.parse(rtn) === 1) {
622 dialog.alert(<?php echo xlj("Check your email inbox (and possibly your spam folder) for further instructions to reset your password. If you have not received an email, then recommend contacting the clinic.") ?>);
623 return false;
624 } else {
625 dialog.alert(<?php echo xlj("Something went wrong. Recommend contacting the clinic.") ?>);
626 return false;
629 }).fail(function (err) {
630 var message = <?php echo xlj('Something went wrong.') ?>;
631 alert(message);
635 function bsAlert(msg) {
636 let divAlert = document.getElementById("alertStore").querySelector("div.alert").cloneNode(true);
637 document.querySelector("form").prepend(divAlert);
638 let strongMsg = document.createElement("strong");
639 strongMsg.innerHTML = msg;
640 divAlert.prepend(strongMsg);
641 setTimeout(() => {
642 document.querySelector("div.alert").remove();
643 }, 3000);
645 </script>
646 </body>
647 </html>