consolidate attr_url function (#2143)
[openemr.git] / interface / main / main_screen.php
blob8f3542a0a777daf850ec2e799f1c0a1fdfc1283d
1 <?php
2 /**
3 * The outside frame that holds all of the OpenEMR User Interface.
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Rod Roark <rod@sunsetsystems.com>
8 * @author Brady Miller <brady.g.miller@gmail.com>
9 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 /* Include our required headers */
14 require_once('../globals.php');
16 use OpenEMR\Core\Header;
17 use u2flib_server\U2F;
18 use OpenEMR\Services\FacilityService;
20 ///////////////////////////////////////////////////////////////////////
21 // Functions to support MFA.
22 ///////////////////////////////////////////////////////////////////////
24 function posted_to_hidden($name)
26 if (isset($_POST[$name])) {
27 echo "<input type='hidden' name='" . attr($name) . "' value='" . attr($_POST[$name]) . "' />\n";
31 function generate_html_start($title)
33 global $appId;
35 <html>
36 <head>
37 <?php Header::setupHeader(); ?>
38 <title><?php echo text($title); ?></title>
39 <script src="<?php echo $GLOBALS['webroot'] ?>/library/js/u2f-api.js"></script>
40 <script>
41 function doAuth() {
42 var f = document.forms[0];
43 var requests = JSON.parse(f.form_requests.value);
44 // The server's getAuthenticateData() repeats the same challenge in all requests.
45 var challenge = requests[0].challenge;
46 var registeredKeys = new Array();
47 for (var i = 0; i < requests.length; ++i) {
48 registeredKeys[i] = {"version": requests[i].version, "keyHandle": requests[i].keyHandle};
50 u2f.sign(
51 '<?php echo addslashes($appId); ?>',
52 challenge,
53 registeredKeys,
54 function(data) {
55 if(data.errorCode && data.errorCode != 0) {
56 alert('<?php echo xls("Key access failed with error"); ?> ' + data.errorCode);
57 return;
59 f.form_response.value = JSON.stringify(data);
60 f.submit();
65 </script>
66 </head>
67 <body class='body_top'>
68 <center>
69 <h2><?php echo text($title); ?></h2>
70 <form method="post"
71 action="main_screen.php?auth=login&site=<?php echo attr_url($_GET['site']); ?>"
72 target="_top" name="challenge_form">
73 <?php
74 posted_to_hidden('new_login_session_management');
75 posted_to_hidden('authProvider');
76 posted_to_hidden('languageChoice');
77 posted_to_hidden('authUser');
78 posted_to_hidden('clearPass');
81 function generate_html_end()
83 echo "</form></center></body></html>\n";
84 session_unset();
85 session_destroy();
86 unset($_COOKIE[session_name()]);
87 return 0;
90 $errormsg = '';
92 ///////////////////////////////////////////////////////////////////////
93 // Begin code to support U2F.
94 ///////////////////////////////////////////////////////////////////////
96 $regs = array(); // for mapping device handles to their names
97 $registrations = array(); // the array of stored registration objects
98 $res1 = sqlStatement(
99 "SELECT a.name, a.var1 FROM login_mfa_registrations AS a " .
100 "WHERE a.user_id = ? AND a.method = 'U2F' ORDER BY a.name",
101 array($_SESSION['authId'])
103 while ($row1 = sqlFetchArray($res1)) {
104 $regobj = json_decode($row1['var1']);
105 $regs[json_encode($regobj->keyHandle)] = $row1['name'];
106 $registrations[] = $regobj;
108 if (!empty($registrations)) {
109 // There is at least one U2F key registered so we have to request or verify key data.
110 // https is required, and with a proxy the server might not see it.
111 $scheme = "https://"; // isset($_SERVER['HTTPS']) ? "https://" : "http://";
112 $appId = $scheme . $_SERVER['HTTP_HOST'];
113 $u2f = new u2flib_server\U2F($appId);
114 $userid = $_SESSION['authId'];
115 $form_response = empty($_POST['form_response']) ? '' : $_POST['form_response'];
116 if ($form_response) {
117 // We have key data, check if it matches what was registered.
118 $tmprow = sqlQuery("SELECT login_work_area FROM users_secure WHERE id = ?", array($userid));
119 try {
120 $registration = $u2f->doAuthenticate(
121 json_decode($tmprow['login_work_area']), // these are the original challenge requests
122 $registrations,
123 json_decode($_POST['form_response'])
125 // Stored registration data needs to be updated because the usage count has changed.
126 // We have to use the matching registered key.
127 $strhandle = json_encode($registration->keyHandle);
128 if (isset($regs[$strhandle])) {
129 sqlStatement(
130 "UPDATE login_mfa_registrations SET `var1` = ? WHERE " .
131 "`user_id` = ? AND `method` = 'U2F' AND `name` = ?",
132 array(json_encode($registration), $userid, $regs[$strhandle])
134 } else {
135 error_log("Unexpected keyHandle returned from doAuthenticate(): '$strhandle'");
137 // Keep track of when challenges were last answered correctly.
138 sqlStatement(
139 "UPDATE users_secure SET last_challenge_response = NOW() WHERE id = ?",
140 array($_SESSION['authId'])
142 } catch (u2flib_server\Error $e) {
143 // Authentication failed so we will build the U2F form again.
144 $form_response = '';
145 $errormsg = xl('Authentication error') . ": " . $e->getMessage();
148 if (!$form_response) {
149 // There is no key data yet or authentication failed, so we need to solicit it.
150 $requests = json_encode($u2f->getAuthenticateData($registrations));
151 // Persist the challenge also in the database because the browser is untrusted.
152 sqlStatement(
153 "UPDATE users_secure SET login_work_area = ? WHERE id = ?",
154 array($requests, $userid)
156 generate_html_start(xl('U2F Key Verification'));
157 echo "<p>\n";
158 echo xlt('Insert your key into a USB port and click the Authenticate button below.');
159 echo " " . xlt('Then press the flashing button on your key within 1 minute.') . "</p>\n";
160 echo "<table><tr><td>\n";
161 echo "<input type='button' value='" . xla('Authenticate') . "' onclick='doAuth()' />\n";
162 echo "<input type='hidden' name='form_requests' value='" . attr($requests) . "' />\n";
163 echo "<input type='hidden' name='form_response' value='' />\n";
164 echo "</td></tr></table>\n";
165 if ($errormsg) {
166 echo "<p style='color:red;font-weight:bold'>" . text($errormsg) . "</p>\n";
168 exit(generate_html_end());
172 ///////////////////////////////////////////////////////////////////////
173 // End of U2F logic.
174 ///////////////////////////////////////////////////////////////////////
176 // Creates a new session id when load this outer frame
177 // (allows creations of separate OpenEMR frames to view patients concurrently
178 // on different browser frame/windows)
179 // This session id is used below in the restoreSession.php include to create a
180 // session cookie for this specific OpenEMR instance that is then maintained
181 // within the OpenEMR instance by calling top.restoreSession() whenever
182 // refreshing or starting a new script.
183 if (isset($_POST['new_login_session_management'])) {
184 // This is a new login, so create a new session id and remove the old session
185 session_regenerate_id(true);
186 } else {
187 // This is not a new login, so check csrf and then create a new session id and do NOT remove the old session
188 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
189 csrfNotVerified();
191 session_regenerate_id(false);
193 // Create the csrf_token
194 $_SESSION['csrf_token'] = createCsrfToken();
196 $_SESSION["encounter"] = '';
198 if ($GLOBALS['login_into_facility']) {
199 $facility_id = $_POST['facility'];
200 if ($facility_id === 'user_default') {
201 //get the default facility of login user from users table
202 $facilityService = new FacilityService();
203 $facility = $facilityService->getFacilityForUser($_SESSION['authUserID']);
204 $facility_id = $facility['id'];
206 $_SESSION['facilityId'] = $facility_id;
207 if ($GLOBALS['set_facility_cookie']) {
208 // set cookie with facility for the calender screens
209 setcookie("pc_facility", $_SESSION['facilityId'], time() + (3600 * 365), $GLOBALS['webroot']);
213 // Fetch the password expiration date
214 $is_expired=false;
215 if ($GLOBALS['password_expiration_days'] != 0) {
216 $is_expired=false;
217 $q= (isset($_POST['authUser'])) ? $_POST['authUser'] : '';
218 $result = sqlStatement("select pwd_expiration_date from users where username = ?", array($q));
219 $current_date = date('Y-m-d');
220 $pwd_expires_date = $current_date;
221 if ($row = sqlFetchArray($result)) {
222 $pwd_expires_date = $row['pwd_expiration_date'];
225 // Display the password expiration message (starting from 7 days before the password gets expired)
226 $pwd_alert_date = date('Y-m-d', strtotime($pwd_expires_date . '-7 days'));
228 if (strtotime($pwd_alert_date) != '' &&
229 strtotime($current_date) >= strtotime($pwd_alert_date) &&
230 (!isset($_SESSION['expiration_msg'])
231 or $_SESSION['expiration_msg'] == 0)) {
232 $is_expired = true;
233 $_SESSION['expiration_msg'] = 1; // only show the expired message once
237 if ($is_expired) {
238 //display the php file containing the password expiration message.
239 $frame1url = "pwd_expires_alert.php?csrf_token_form=" . attr_url(collectCsrfToken());
240 $frame1target = "adm";
241 } else if (!empty($_POST['patientID'])) {
242 $patientID = 0 + $_POST['patientID'];
243 if (empty($_POST['encounterID'])) {
244 // Open patient summary screen (without a specific encounter)
245 $frame1url = "../patient_file/summary/demographics.php?set_pid=" . attr_url($patientID);
246 $frame1target = "pat";
247 } else {
248 // Open patient summary screen with a specific encounter
249 $encounterID = 0 + $_POST['encounterID'];
250 $frame1url = "../patient_file/summary/demographics.php?set_pid=" . attr_url($patientID) . "&set_encounterid=" . attr_url($encounterID);
251 $frame1target = "pat";
253 } else if (isset($_GET['mode']) && $_GET['mode'] == "loadcalendar") {
254 $frame1url = "calendar/index.php?pid=" . attr_url($_GET['pid']);
255 if (isset($_GET['date'])) {
256 $frame1url .= "&date=" . attr_url($_GET['date']);
259 $frame1target = "cal";
260 } else {
261 // standard layout
262 $map_paths_to_targets = array(
263 'main_info.php' => ('cal'),
264 '../new/new.php' => ('pat'),
265 '../../interface/main/finder/dynamic_finder.php' => ('fin'),
266 '../../interface/patient_tracker/patient_tracker.php?skip_timeout_reset=1' => ('flb'),
267 '../../interface/main/messages/messages.php?form_active=1' => ('msg')
269 if ($GLOBALS['default_top_pane']) {
270 $frame1url=attr($GLOBALS['default_top_pane']);
271 $frame1target = $map_paths_to_targets[$GLOBALS['default_top_pane']];
272 if (empty($frame1target)) {
273 $frame1target = "msc";
275 } else {
276 $frame1url = "main_info.php";
277 $frame1target = "cal";
279 if ($GLOBALS['default_second_tab']) {
280 $frame2url=attr($GLOBALS['default_second_tab']);
281 $frame2target = $map_paths_to_targets[$GLOBALS['default_second_tab']];
282 if (empty($frame2target)) {
283 $frame2target = "msc";
285 } else {
286 $frame2url = "../../interface/main/messages/messages.php?form_active=1";
287 $frame2target = "msg";
291 $nav_area_width = '130';
292 if (!empty($GLOBALS['gbl_nav_area_width'])) {
293 $nav_area_width = $GLOBALS['gbl_nav_area_width'];
296 // This is where will decide whether to use tabs layout or non-tabs layout
297 // Will also set Session variables to communicate settings to tab layout
298 if ($GLOBALS['new_tabs_layout']) {
299 $_SESSION['frame1url'] = $frame1url;
300 $_SESSION['frame1target'] = $frame1target;
301 $_SESSION['frame2url'] = $frame2url;
302 $_SESSION['frame2target'] = $frame2target;
303 // mdsupport - Apps processing invoked for valid app selections from list
304 if ((isset($_POST['appChoice'])) && ($_POST['appChoice'] !== '*OpenEMR')) {
305 $_SESSION['app1'] = $_POST['appChoice'];
308 // Pass a unique token, so main.php script can not be run on its own
309 $_SESSION['token_main_php'] = createUniqueToken();
310 header('Location: ' . $web_root . "/interface/main/tabs/main.php?token_main=" . urlencode($_SESSION['token_main_php']));
311 exit();
315 <html>
316 <head>
317 <title>
318 <?php echo text($openemr_name) ?>
319 </title>
320 <script type="text/javascript" src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-1-9-1/jquery.min.js"></script>
321 <script type="text/javascript" src="../../library/topdialog.js"></script>
322 <script type="text/javascript" src="tabs/js/dialog_utils.js?v=<?php echo $v_js_includes; ?>"></script>
324 <link rel="shortcut icon" href="<?php echo $GLOBALS['images_static_relative']; ?>/favicon.ico" />
326 <script language='JavaScript'>
328 // Flag that tab mode is off
329 var tab_mode=false;
331 var webroot_url = '<?php echo $GLOBALS['web_root']; ?>';
332 var jsLanguageDirection = "<?php echo $_SESSION["language_direction"]; ?>";
334 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
336 // Since this should be the parent window, this is to prevent calls to the
337 // window that opened this window. For example when a new window is opened
338 // from the Patient Flow Board or the Patient Finder.
339 window.opener = null;
341 // This flag indicates if another window or frame is trying to reload the login
342 // page to this top-level window. It is set by javascript returned by auth.inc
343 // and is checked by handlers of beforeunload events.
344 var timed_out = false;
346 // This counts the number of frames that have reported themselves as loaded.
347 // Currently only left_nav and Title do this, so the maximum will be 2.
348 // This is used to determine when those frames are all loaded.
349 var loadedFrameCount = 0;
351 function allFramesLoaded() {
352 // Change this number if more frames participate in reporting.
353 return loadedFrameCount >= 2;
355 </script>
357 </head>
359 <?php
361 * for RTL layout we need to change order of frames in framesets
363 $lang_dir = $_SESSION['language_direction'];
365 $sidebar_tpl = "<frameset rows='*,0' frameborder='0' border='0' framespacing='0'>
366 <frame src='left_nav.php' name='left_nav' />
367 <frame src='daemon_frame.php' name='Daemon' scrolling='no' frameborder='0'
368 border='0' framespacing='0' />
369 </frameset>";
371 $main_tpl = "<frameset rows='60%,*' id='fsright' bordercolor='#999999' frameborder='1'>" ;
372 $main_tpl .= "<frame src='". $frame1url ."' name='RTop' scrolling='auto' />
373 <frame src='messages/messages.php?form_active=1' name='RBot' scrolling='auto' /></frameset>";
375 // Please keep in mind that border (mozilla) and framespacing (ie) are the
376 // same thing. use both.
377 // frameborder specifies a 3d look, not whether there are borders.
379 if (empty($GLOBALS['gbl_tall_nav_area'])) {
380 // not tall nav area ?>
381 <frameset rows='<?php echo attr($GLOBALS['titleBarHeight']) + 5 ?>,*' frameborder='1' border='1' framespacing='1' onunload='imclosing()'>
382 <frame src='main_title.php' name='Title' scrolling='no' frameborder='1' noresize />
383 <?php if ($lang_dir != 'rtl') { ?>
384 <frameset cols='<?php echo attr($nav_area_width) . ',*'; ?>' id='fsbody' frameborder='1' border='4' framespacing='4'>
385 <?php echo $sidebar_tpl ?>
386 <?php echo $main_tpl ?>
387 </frameset>
389 <?php } else { ?>
390 <frameset cols='<?php echo '*,' . attr($nav_area_width); ?>' id='fsbody' frameborder='1' border='4' framespacing='4'>
391 <?php echo $main_tpl ?>
392 <?php echo $sidebar_tpl ?>
393 </frameset>
395 <?php } ?>
397 </frameset>
398 </frameset>
400 <?php } else { // use tall nav area ?>
401 <frameset cols='<?php echo attr($nav_area_width); ?>,*' id='fsbody' frameborder='1' border='4' framespacing='4' onunload='imclosing()'>
402 <frameset rows='*,0' frameborder='0' border='0' framespacing='0'>
403 <frame src='left_nav.php' name='left_nav' />
404 <frame src='daemon_frame.php' name='Daemon' scrolling='no' frameborder='0'
405 border='0' framespacing='0' />
406 </frameset>
407 <frameset rows='<?php echo attr($GLOBALS['titleBarHeight']) + 5 ?>,*' frameborder='1' border='1' framespacing='1'>
408 <frame src='main_title.php' name='Title' scrolling='no' frameborder='1' />
409 <frameset rows='60%,*' id='fsright' bordercolor='#999999' frameborder='1' border='4' framespacing='4'>
410 <frame src='<?php echo $frame1url ?>' name='RTop' scrolling='auto' />
411 <frame src='messages/messages.php?form_active=1' name='RBot' scrolling='auto' />
412 </frameset>
413 </frameset>
414 </frameset>
416 <?php } // end tall nav area ?>
418 </html>