From 4cfe2e432b1c95f0bfd7b188d9b5f74549066715 Mon Sep 17 00:00:00 2001 From: Jeffrey Lembeck Date: Tue, 22 Feb 2022 08:55:33 -0800 Subject: [PATCH] feat(login): styles This styles the login page and adds a layer of error notifications. The error notifications need to be fleshed out more, but this is fine for now. As for the login, it has some more touches that can be applied, but this is so other people can also touch it up --- www/common.inc | 14 ++ www/cpauth/login.php | 20 ++- www/nginx.conf | 2 + www/pagestyle2.css | 179 ++++++++++++++++++++++++++ www/src/Exception/ClientException.php | 10 +- www/templates/account/login.php | 66 ++++++---- www/templates/layouts/headless.php | 19 +++ 7 files changed, 274 insertions(+), 36 deletions(-) create mode 100644 www/templates/layouts/headless.php diff --git a/www/common.inc b/www/common.inc index 0a654339c5..8337424def 100644 --- a/www/common.inc +++ b/www/common.inc @@ -14,6 +14,7 @@ require_once(__DIR__ . '/util.inc'); use WebPageTest\Util; use WebPageTest\User; use WebPageTest\RequestContext; +use WebPageTest\Exception\ClientException; if (Util::getSetting('cp_auth')) { @@ -21,6 +22,19 @@ if (Util::getSetting('cp_auth')) { session_start(); } +if (Util::getSetting('cp_auth')) { + set_exception_handler(function($e) { + if(is_a($e, ClientException::class)) { + $route = $e->getRoute(); + $message = $e->getMessage(); + $_SESSION['error_message'] = $message; + header('HTTP/1.1 302 Found'); + header('Location: ' . $route); + exit(0); + } + }); +} + // Disable caching by default header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0", true); diff --git a/www/cpauth/login.php b/www/cpauth/login.php index 02b379ab72..10ba8e73ec 100644 --- a/www/cpauth/login.php +++ b/www/cpauth/login.php @@ -14,7 +14,8 @@ if ($request_method === 'POST') { $csrf_token = filter_input(INPUT_POST, 'csrf_token'); if ($csrf_token !== $_SESSION['csrf_token']) { - throw new ClientException("You submitted an incorrect CSRF token", 403); + error_log("Incorrect CSRF token"); + throw new ClientException("There was an error logging you in. Please try again.", "/login", 403); exit(); } @@ -22,14 +23,15 @@ $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); $password = filter_input(INPUT_POST, 'password'); } catch (Exception $e) { - throw new ClientException($e->getMessage(), 400); + error_log("Incorrect CSRF token"); + throw new ClientException($e->getMessage(), "/login", 400); } try { $auth_token = $request_context->getClient()->login($email, $password); $request_context->getClient()->authenticate($auth_token->access_token); } catch (Exception $e) { - throw new ClientException($e->getMessage(), 403); + throw new ClientException($e->getMessage(), "/login", 403); } $protocol = getUrlProtocol(); @@ -43,14 +45,18 @@ exit(); } elseif ($request_method === 'GET') { $_SESSION['csrf_token'] = bin2hex(random_bytes(35)); - + $error = $_SESSION['error_message'] ?? ""; + unset($_SESSION['error_message']); $tpl = new Template('account'); + $tpl->setLayout('headless'); + $args = array( + 'csrf_token' => $_SESSION['csrf_token'], + 'has_error' => !empty($error) + ); echo $tpl->render( 'login', - array( - 'csrf_token' => $_SESSION['csrf_token'] - ) + $args ); exit(); } diff --git a/www/nginx.conf b/www/nginx.conf index f5a14ef9ed..ead5497bc3 100644 --- a/www/nginx.conf +++ b/www/nginx.conf @@ -75,6 +75,8 @@ rewrite ^/tv$ /tv.php permanent; rewrite ^/login /cpauth/login.php last; rewrite ^/logout /cpauth/logout.php last; +rewrite ^/forgot-password /cpauth/forgot_password.php last; +rewrite ^/signup /cpauth/signup.php last; #result paths rewrite ^/result/([a-zA-Z0-9_]+)$ /result/$1/ permanent; diff --git a/www/pagestyle2.css b/www/pagestyle2.css index b3e24e0b32..971f7c4b5e 100644 --- a/www/pagestyle2.css +++ b/www/pagestyle2.css @@ -6509,3 +6509,182 @@ div.bar { padding-left: 1em; margin-bottom: 1.5em; } + +.headless { + height: 100%; +} + +.headless body, .headless body:not(.home) { + background: initial; + height: 100%; + display: block; +} + +.headless * { + box-sizing: border-box; +} + +.page.theme-c { + height: 100%; + display: grid; + background-color: #6b25cf; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 800 400'%3E%3Cdefs%3E%3CradialGradient id='a' cx='396' cy='281' r='514' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%237D0688'/%3E%3Cstop offset='1' stop-color='%23150033'/%3E%3C/radialGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='400' y1='148' x2='400' y2='333'%3E%3Cstop offset='0' stop-color='%23D617C5' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='%23D617C5' stop-opacity='0.5'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect fill='url(%23a)' width='800' height='400'/%3E%3Cg fill-opacity='0.49'%3E%3Ccircle fill='url(%23b)' cx='267.5' cy='61' r='300'/%3E%3Ccircle fill='url(%23b)' cx='532.5' cy='61' r='300'/%3E%3Ccircle fill='url(%23b)' cx='400' cy='30' r='300'/%3E%3C/g%3E%3C/svg%3E"); + background-position: bottom 0 left 50%; + background-repeat: no-repeat; + background-size: cover; + color: white; +} + +.page.theme-c .container { + margin: auto; + min-width: 320px; + width: 100%; + background: #24334F; + padding: 30px 40px 80px; + font-size: 20px; + font-weight: 300; + border-radius: 10px; + box-shadow: 5px 5px 10px 1px rgb(43 38 51 / 50%); +} + +.page.theme-c .container a, +.page.theme-c .container a:hover, +.page.theme-c .container a:visited { + text-decoration: none; + color: #A9C8F1; +} + +@media (min-width: 480px) { + .page.theme-c .container { + width: 480px; + } +} + +.page.theme-c .subhed { +} + +.page.theme-c .subhed h1 { + font-weight: 300; + text-align: center; + font-size: 38px; + margin-top: 0.5em; + margin-bottom: 0.8em; +} + +.page.theme-c .subhed .error-text { + text-align: center; + color: #FF8A88; + padding-bottom: 0.5em; + margin-bottom: 1.1em; +} + +.page.theme-c .subhed .error-text span { + display: block; +} + +.page.theme-c .container .container-signup-link { + text-align: center; + margin-top: 20px; +} + + +.form-login { +} + +.form-login fieldset { + border: 0; + margin: 0; + padding: 0; + margin-inline-start: 0; + margin-inline-end: 0; + padding-block-start: 0; + padding-inline-start: 0; + padding-inline-end: 0; + padding-block-end: 0; + min-inline-size: initial; +} + +.form-login .inputs { + margin-bottom: 30px; +} + +.form-login .inputs > div:first-child { + margin-bottom: 16px; +} + +.form-login .inputs label { + display: block; +} + +.form-login .inputs input { + display: block; + width: 100%; + font-size: 20px; + line-height: 1.15em; + padding: 0.7em 8px; + border: 1px #24334F; + border-radius: 2px; +} + +.form-login .inputs input:focus { + outline: 1px solid #2F80ED; +} + +.form-login .container-password { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: .5fr 1fr; + gap: 0px 0px; + grid-template-areas: + "label link" + "input input"; +} + +.form-login .container-password-label { + grid-area: label; +} +.form-login .container-password input[type=password] { + grid-area: input; +} +.form-login .container-password .link-forgot-password { + text-align: right; + grid-area: link; +} + +.form-login .container-submit { +} + +.form-login .container-submit button { + width: 100%; + appearance: none; + border: 0; + background: #F9D856; + padding: 16px 0; + font-weight: 300; + font-size: 20px; + display: block; + border-radius: 4px; +} + +.form-login .container-submit button:hover { + background: #F2CC35; +} + +.form-login .container-submit button:focus { + outline: 1px solid #333; +} + +.form-login .container-submit button:active { + background: #EABC08; +} + +.a11y-hidden { + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(50%); + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; +} diff --git a/www/src/Exception/ClientException.php b/www/src/Exception/ClientException.php index bb8360f093..b1304c4883 100644 --- a/www/src/Exception/ClientException.php +++ b/www/src/Exception/ClientException.php @@ -6,8 +6,16 @@ class ClientException extends \Exception { - public function __construct($message, $code = 400, \Throwable $previous = null) + private string $route; + + public function __construct(string $message, string $route = '/', int $code = 400, \Throwable $previous = null) { parent::__construct($message, $code, $previous); + $this->route = $route; + } + + public function getRoute(): string + { + return $this->route; } } diff --git a/www/templates/account/login.php b/www/templates/account/login.php index d360ee3699..e7d7e30d09 100644 --- a/www/templates/account/login.php +++ b/www/templates/account/login.php @@ -1,31 +1,41 @@ -
-
- LOGO -
-
-
-
-
- - WPT Credentials - -
-
- - -
-
- - -
- -
-
- +
+
+
+
WebPageTest, by Catchpoint
+

Log in

+ +
+ Incorrect email address or password. + Please try again.
-
-
-
- + +
+ +
diff --git a/www/templates/layouts/headless.php b/www/templates/layouts/headless.php new file mode 100644 index 0000000000..2ecabeea9b --- /dev/null +++ b/www/templates/layouts/headless.php @@ -0,0 +1,19 @@ + + + + + <?php echo $page_title; ?> + + + + + +