From 3f32258ba0d77fa20073a1499f14dee357a09c09 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Thu, 20 Dec 2018 23:58:35 -0700 Subject: [PATCH 1/9] Fix bug --- api/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/index.php b/api/index.php index a930798..59d0c2a 100644 --- a/api/index.php +++ b/api/index.php @@ -18,7 +18,7 @@ if ($_SERVER['REQUEST_METHOD'] != "GET") { $requestbody = file_get_contents('php://input'); $requestjson = json_decode($requestbody, TRUE); if (json_last_error() == JSON_ERROR_NONE) { - $requestdata = array_merge($requestdata, $requestjson); + $VARS = array_merge($VARS, $requestjson); } // If we're not using the old api.php file, allow more flexible requests From a559901ac04f320d0e75370638692de466175228 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Sat, 22 Dec 2018 16:57:45 -0700 Subject: [PATCH 2/9] Redirect to AccountHub for user login --- action.php | 2 +- index.php | 223 +++++++++++++++------------------------------ langs/en/core.json | 14 +-- 3 files changed, 75 insertions(+), 164 deletions(-) diff --git a/action.php b/action.php index d1ea966..67b230b 100644 --- a/action.php +++ b/action.php @@ -33,6 +33,6 @@ function returnToSender($msg, $arg = "") { switch ($VARS['action']) { case "signout": session_destroy(); - header('Location: index.php'); + header('Location: index.php?logout=1'); die("Logged out."); } \ No newline at end of file diff --git a/index.php b/index.php index f3a816c..9e9468e 100644 --- a/index.php +++ b/index.php @@ -1,7 +1,9 @@ get("no access permission", false); -} +if (!empty($_GET['logout'])) { + // Show a logout message instead of immediately redirecting to login flow + ?> + + + + -/* Authenticate user */ -$userpass_ok = false; -$multiauth = false; -if (Login::checkLoginServer()) { - if (empty($VARS['progress'])) { - // Easy way to remove "undefined" warnings. - } else if ($VARS['progress'] == "1") { - if (!$SETTINGS['captcha']['enabled'] || ($SETTINGS['captcha']['enabled'] && Login::verifyCaptcha($VARS['captcheck_session_code'], $VARS['captcheck_selected_answer'], $SETTINGS['captcha']['server'] . "/api.php"))) { - $autherror = ""; - $user = User::byUsername($VARS['username']); - if ($user->exists()) { - $status = $user->getStatus()->getString(); - switch ($status) { - case "LOCKED_OR_DISABLED": - $alert = $Strings->get("account locked", false); - break; - case "TERMINATED": - $alert = $Strings->get("account terminated", false); - break; - case "CHANGE_PASSWORD": - $alert = $Strings->get("password expired", false); - break; - case "NORMAL": - $username_ok = true; - break; - case "ALERT_ON_ACCESS": - $mail_resp = $user->sendAlertEmail(); - if ($SETTINGS['debug']) { - var_dump($mail_resp); - } - $username_ok = true; - break; - default: - if (!empty($error)) { - $alert = $error; - } else { - $alert = $Strings->get("login error", false); - } - break; - } - if ($username_ok) { - if ($user->checkPassword($VARS['password'])) { - $_SESSION['passok'] = true; // stop logins using only username and authcode - if ($user->has2fa()) { - $multiauth = true; - } else { - Session::start($user); - header('Location: app.php'); - die("Logged in, go to app.php"); - } - } else { - $alert = $Strings->get("login incorrect", false); - } - } - } else { // User does not exist anywhere - $alert = $Strings->get("login incorrect", false); - } - } else { - $alert = $Strings->get("captcha error", false); + <?php echo $SETTINGS['site_title']; ?> + + + + + + + +
+
+
+

get("You have been logged out.") ?>

+
+ + +
+
+ + + $_SESSION["login_code"]]); + if ($uidinfo["status"] == "ERROR") { + throw new Exception(); } - if ($user->check2fa($VARS['authcode'])) { + if (is_numeric($uidinfo['uid'])) { + $user = new User($uidinfo['uid'] * 1); Session::start($user); + $_SESSION["login_code"] = null; header('Location: app.php'); die("Logged in, go to app.php"); } else { - $alert = $Strings->get("2fa incorrect", false); + throw new Exception(); } + } catch (Exception $ex) { + $redirecttologin = true; } -} else { - $alert = $Strings->get("login server unavailable", false); } -header("Link: ; rel=preload; as=style", false); -header("Link: ; rel=preload; as=style", false); -header("Link: ; rel=preload; as=style", false); -header("Link: ; rel=preload; as=style", false); -header("Link: ; rel=preload; as=script", false); -header("Link: ; rel=preload; as=script", false); -?> - - - - - - - <?php echo $SETTINGS['site_title']; ?> +if ($redirecttologin) { + try { + $codedata = AccountHubApi::get("getloginkey", ["appname" => $SETTINGS["site_title"]]); - + if ($codedata['status'] != "OK") { + throw new Exception($Strings->get("login server unavailable", false)); + } - - - - - - - - -
-
- -
-
-
-
-
-
get("sign in"); ?>
-
- -
- -
- - " required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus />
- " required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
- -
-
- - - -
- get("2fa prompt"); ?> -
- " required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus />
- - - - -
-
-
-
- - - - - - \ No newline at end of file + $_SESSION["login_code"] = $codedata["code"]; + + header("Location: " . $codedata["loginurl"] . "?code=" . htmlentities($codedata["code"]) . "&redirect=" . htmlentities($redirecturl)); + } catch (Exception $ex) { + sendError($ex->getMessage()); + } +} \ No newline at end of file diff --git a/langs/en/core.json b/langs/en/core.json index 5e55996..20eac0a 100644 --- a/langs/en/core.json +++ b/langs/en/core.json @@ -1,17 +1,7 @@ { - "sign in": "Sign In", - "username": "Username", - "password": "Password", - "continue": "Continue", - "authcode": "Authentication code", - "2fa prompt": "Enter the six-digit code from your mobile authenticator app.", - "2fa incorrect": "Authentication code incorrect.", - "login incorrect": "Login incorrect.", + "You have been logged out.": "You have been logged out.", + "Log in again": "Log in again", "login server unavailable": "Login server unavailable. Try again later or contact technical support.", - "account locked": "This account has been disabled. Contact technical support.", - "password expired": "You must change your password before continuing.", - "account terminated": "Account terminated. Access denied.", - "account state error": "Your account state is not stable. Log out, restart your browser, and try again.", "welcome user": "Welcome, {user}!", "sign out": "Sign out", "settings": "Settings", From ba1369d842bbc4d2fe00bce552ba9da2cb37aabe Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Sat, 22 Dec 2018 21:26:57 -0700 Subject: [PATCH 3/9] Add app icon to login flow --- index.php | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/index.php b/index.php index 9e9468e..8f3b4b9 100644 --- a/index.php +++ b/index.php @@ -28,14 +28,30 @@ if (!empty($_GET['logout'])) {
+
+ +
+

get("You have been logged out.") ?>

@@ -79,13 +95,15 @@ if (empty($_SESSION["login_code"])) { if ($redirecttologin) { try { - $codedata = AccountHubApi::get("getloginkey", ["appname" => $SETTINGS["site_title"]]); + $urlbase = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . (($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) ? ":" . $_SERVER['SERVER_PORT'] : ""); + $iconurl = $urlbase . str_replace("index.php", "", $_SERVER["REQUEST_URI"]) . "static/img/logo.svg"; + $codedata = AccountHubApi::get("getloginkey", ["appname" => $SETTINGS["site_title"], "appicon" => $iconurl]); if ($codedata['status'] != "OK") { throw new Exception($Strings->get("login server unavailable", false)); } - $redirecturl = $url = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . (($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) ? ":" . $_SERVER['SERVER_PORT'] : "") . $_SERVER['REQUEST_URI']; + $redirecturl = $urlbase . $_SERVER['REQUEST_URI']; $_SESSION["login_code"] = $codedata["code"]; From 016c71d30de7a246874e3483320e411ab1c7b244 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Sat, 22 Dec 2018 22:38:50 -0700 Subject: [PATCH 4/9] Fix index.php not redirecting to app.php when already logged in --- index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/index.php b/index.php index 8f3b4b9..e4cafd8 100644 --- a/index.php +++ b/index.php @@ -10,6 +10,7 @@ require_once __DIR__ . "/required.php"; // if we're logged in, we don't need to be here. if (!empty($_SESSION['loggedin']) && $_SESSION['loggedin'] === true && !isset($_GET['permissionerror'])) { header('Location: app.php'); + die(); } if (!empty($_GET['logout'])) { From e0802f582b4ecf124cf006c35cf03a8433220d1d Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Wed, 26 Dec 2018 16:22:09 -0700 Subject: [PATCH 5/9] Remove unneeded index.css --- static/css/index.css | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 static/css/index.css diff --git a/static/css/index.css b/static/css/index.css deleted file mode 100644 index 81e0ba0..0000000 --- a/static/css/index.css +++ /dev/null @@ -1,15 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -.banner-image { - max-height: 100px; - margin: 2em auto; - border: 1px solid grey; - border-radius: 15%; -} - -.footer { - margin-top: 10em; - text-align: center; -} \ No newline at end of file From 106e697fc38dcbc0f347598cb4e99ccde8719c81 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Wed, 26 Dec 2018 16:25:48 -0700 Subject: [PATCH 6/9] Remove captcha-related code, since login is done by AccountHub now --- langs/en/core.json | 1 - lib/Login.lib.php | 23 ----------------------- required.php | 9 ++++----- settings.template.php | 15 --------------- 4 files changed, 4 insertions(+), 44 deletions(-) diff --git a/langs/en/core.json b/langs/en/core.json index 20eac0a..c9a9d0b 100644 --- a/langs/en/core.json +++ b/langs/en/core.json @@ -11,6 +11,5 @@ "invalid parameters": "Invalid request parameters.", "login server error": "The login server returned an error: {arg}", "login server user data error": "The login server refused to provide account information. Try again or contact technical support.", - "captcha error": "There was a problem with the CAPTCHA (robot test). Try again.", "no access permission": "You do not have permission to access this system." } diff --git a/lib/Login.lib.php b/lib/Login.lib.php index b136c6c..219cfea 100644 --- a/lib/Login.lib.php +++ b/lib/Login.lib.php @@ -45,29 +45,6 @@ class Login { return Login::LOGIN_OK; } - public static function verifyCaptcha(string $session, string $answer, string $url): bool { - $data = [ - 'session_id' => $session, - 'answer_id' => $answer, - 'action' => "verify" - ]; - $options = [ - 'http' => [ - 'header' => "Content-type: application/x-www-form-urlencoded\r\n", - 'method' => 'POST', - 'content' => http_build_query($data) - ] - ]; - $context = stream_context_create($options); - $result = file_get_contents($url, false, $context); - $resp = json_decode($result, TRUE); - if (!$resp['result']) { - return false; - } else { - return true; - } - } - /** * Check the login server API for sanity * @return boolean true if OK, else false diff --git a/required.php b/required.php index 3fe1060..3cfa346 100644 --- a/required.php +++ b/required.php @@ -32,7 +32,6 @@ session_start(); // stick some cookies in it // renew session cookie setcookie(session_name(), session_id(), time() + $session_length, "/", false, false); -$captcha_server = ($SETTINGS['captcha']['enabled'] === true ? preg_replace("/http(s)?:\/\//", "", $SETTINGS['captcha']['server']) : ""); if ($_SESSION['mobile'] === TRUE) { header("Content-Security-Policy: " . "default-src 'self';" @@ -42,8 +41,8 @@ if ($_SESSION['mobile'] === TRUE) { . "frame-src 'none'; " . "font-src 'self'; " . "connect-src *; " - . "style-src 'self' 'unsafe-inline' $captcha_server; " - . "script-src 'self' 'unsafe-inline' $captcha_server"); + . "style-src 'self' 'unsafe-inline'; " + . "script-src 'self' 'unsafe-inline'"); } else { header("Content-Security-Policy: " . "default-src 'self';" @@ -53,8 +52,8 @@ if ($_SESSION['mobile'] === TRUE) { . "frame-src 'none'; " . "font-src 'self'; " . "connect-src *; " - . "style-src 'self' 'nonce-$SECURE_NONCE' $captcha_server; " - . "script-src 'self' 'nonce-$SECURE_NONCE' $captcha_server"); + . "style-src 'self' 'nonce-$SECURE_NONCE'; " + . "script-src 'self' 'nonce-$SECURE_NONCE'"); } // diff --git a/settings.template.php b/settings.template.php index 75a1896..22c1b16 100644 --- a/settings.template.php +++ b/settings.template.php @@ -15,7 +15,6 @@ $SETTINGS = [ // Turning this on in production is a security risk and can sometimes break // things, such as JSON output where extra content is not expected. "debug" => false, - // Database connection settings // See http://medoo.in/api/new for info "database" => [ @@ -26,10 +25,8 @@ $SETTINGS = [ "password" => "", "charset" => "utf8" ], - // Name of the app. "site_title" => "Web App Template", - // Settings for connecting to the AccountHub server. "accounthub" => [ // URL for the API endpoint @@ -39,26 +36,14 @@ $SETTINGS = [ // API key "key" => "123" ], - // For supported values, see http://php.net/manual/en/timezones.php "timezone" => "America/Denver", - - // Use Captcheck on login screen to slow down bots - // https://captcheck.netsyms.com - "captcha" => [ - "enabled" => false, - "server" => "https://captcheck.netsyms.com" - ], - // Language to use for localization. See langs folder to add a language. "language" => "en", - // Shown in the footer of all the pages. "footer_text" => "", - // Also shown in the footer, but with "Copyright " in front. "copyright" => "Netsyms Technologies", - // Base URL for building links relative to the location of the app. // Only used when there's no good context for the path. // The default is almost definitely fine. From 4d2b78bdba36427dfdfdee86b824d82e7cb69704 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Wed, 26 Dec 2018 16:28:32 -0700 Subject: [PATCH 7/9] Remove unused strings --- langs/en/core.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/langs/en/core.json b/langs/en/core.json index c9a9d0b..6121060 100644 --- a/langs/en/core.json +++ b/langs/en/core.json @@ -2,14 +2,10 @@ "You have been logged out.": "You have been logged out.", "Log in again": "Log in again", "login server unavailable": "Login server unavailable. Try again later or contact technical support.", - "welcome user": "Welcome, {user}!", "sign out": "Sign out", - "settings": "Settings", - "options": "Options", "404 error": "404 Error", "page not found": "Page not found.", "invalid parameters": "Invalid request parameters.", "login server error": "The login server returned an error: {arg}", - "login server user data error": "The login server refused to provide account information. Try again or contact technical support.", "no access permission": "You do not have permission to access this system." } From 1729b842ba410a84058dcc8f755d7943b0666cd4 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Wed, 26 Dec 2018 16:32:43 -0700 Subject: [PATCH 8/9] Add permission check during login --- index.php | 5 +++++ settings.template.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/index.php b/index.php index e4cafd8..5cac7ba 100644 --- a/index.php +++ b/index.php @@ -82,6 +82,11 @@ if (empty($_SESSION["login_code"])) { } if (is_numeric($uidinfo['uid'])) { $user = new User($uidinfo['uid'] * 1); + foreach ($SETTINGS['permissions'] as $perm) { + if (!$user->hasPermission($perm)) { + die($Strings->get("no access permission", false)); + } + } Session::start($user); $_SESSION["login_code"] = null; header('Location: app.php'); diff --git a/settings.template.php b/settings.template.php index 22c1b16..94686c0 100644 --- a/settings.template.php +++ b/settings.template.php @@ -36,6 +36,9 @@ $SETTINGS = [ // API key "key" => "123" ], + // List of required user permissions to access this app. + "permissions" => [ + ], // For supported values, see http://php.net/manual/en/timezones.php "timezone" => "America/Denver", // Language to use for localization. See langs folder to add a language. From d7ca7125ce500d220f20b30d8317c54f73dc9c99 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Thu, 27 Dec 2018 00:15:27 -0700 Subject: [PATCH 9/9] Nicer access denied message --- index.php | 43 +++++++++++++++++++++++++++---------------- langs/en/core.json | 6 +----- langs/en/index.json | 8 ++++++++ 3 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 langs/en/index.json diff --git a/index.php b/index.php index 5cac7ba..1bdd70d 100644 --- a/index.php +++ b/index.php @@ -13,8 +13,19 @@ if (!empty($_SESSION['loggedin']) && $_SESSION['loggedin'] === true && !isset($_ die(); } -if (!empty($_GET['logout'])) { - // Show a logout message instead of immediately redirecting to login flow +/** + * Show a simple HTML page with a line of text and a button. Matches the UI of + * the AccountHub login flow. + * + * @global type $SETTINGS + * @global type $SECURE_NONCE + * @global type $Strings + * @param string $title Text to show, passed through i18n + * @param string $button Button text, passed through i18n + * @param string $url URL for the button + */ +function showHTML(string $title, string $button, string $url) { + global $SETTINGS, $SECURE_NONCE, $Strings; ?> @@ -26,7 +37,6 @@ if (!empty($_GET['logout'])) { -
@@ -54,24 +59,25 @@ if (!empty($_GET['logout'])) {
-

get("You have been logged out.") ?>

+

get($title); ?>

- - hasPermission($perm)) { - die($Strings->get("no access permission", false)); + showHTML("no access permission", "sign out", "./action.php?action=signout"); + die(); } } Session::start($user); $_SESSION["login_code"] = null; header('Location: app.php'); - die("Logged in, go to app.php"); + showHTML("Logged in", "Continue", "./app.php"); + die(); } else { throw new Exception(); } @@ -113,7 +121,10 @@ if ($redirecttologin) { $_SESSION["login_code"] = $codedata["code"]; - header("Location: " . $codedata["loginurl"] . "?code=" . htmlentities($codedata["code"]) . "&redirect=" . htmlentities($redirecturl)); + $locationurl = $codedata["loginurl"] . "?code=" . htmlentities($codedata["code"]) . "&redirect=" . htmlentities($redirecturl); + header("Location: $locationurl"); + showHTML("Continue", "Continue", $locationurl); + die(); } catch (Exception $ex) { sendError($ex->getMessage()); } diff --git a/langs/en/core.json b/langs/en/core.json index 6121060..f2d85fb 100644 --- a/langs/en/core.json +++ b/langs/en/core.json @@ -1,11 +1,7 @@ { - "You have been logged out.": "You have been logged out.", - "Log in again": "Log in again", - "login server unavailable": "Login server unavailable. Try again later or contact technical support.", "sign out": "Sign out", "404 error": "404 Error", "page not found": "Page not found.", "invalid parameters": "Invalid request parameters.", - "login server error": "The login server returned an error: {arg}", - "no access permission": "You do not have permission to access this system." + "login server error": "The login server returned an error: {arg}" } diff --git a/langs/en/index.json b/langs/en/index.json new file mode 100644 index 0000000..c516bbb --- /dev/null +++ b/langs/en/index.json @@ -0,0 +1,8 @@ +{ + "You have been logged out.": "You have been logged out.", + "Log in again": "Log in again", + "login server unavailable": "Login server unavailable. Try again later or contact technical support.", + "no access permission": "You do not have permission to access this system.", + "Logged in": "Logged in", + "Continue": "Continue" +}