diff --git a/assets/less/classes/auth.less b/assets/less/classes/auth.less index b2b16a2a..0c7e5b55 100644 --- a/assets/less/classes/auth.less +++ b/assets/less/classes/auth.less @@ -33,4 +33,17 @@ display: flex; flex-direction: column; } + + &__buttons { + display: flex; + justify-content: space-evenly; + } + + &__button { + flex: 1 1 auto; + + &:not(:first-child) { + margin-left: 2px; + } + } } diff --git a/assets/typescript/misuzu.ts b/assets/typescript/misuzu.ts index a3d36d17..0e041e2f 100644 --- a/assets/typescript/misuzu.ts +++ b/assets/typescript/misuzu.ts @@ -28,6 +28,15 @@ window.addEventListener('load', () => { changelogChangeAction.title = "This is supposed to be sideways, but your browser doesn't support that."; } + const loginButtons: HTMLCollectionOf = document.getElementsByClassName('js-login-button') as HTMLCollectionOf; + + if (loginButtons.length > 0) { + for (let i = 0; i < loginButtons.length; i++) { + loginButtons[i].href = 'javascript:void(0);'; + loginButtons[i].addEventListener('click', () => loginModal()); + } + } + const loginForms: HTMLCollectionOf = document.getElementsByClassName('js-login-form') as HTMLCollectionOf; if (loginForms.length > 0) { @@ -76,8 +85,7 @@ interface MessageBoxButton { callback: Function; } -function messageBox(text: string, title: string = null, buttons: MessageBoxButton[] = []): boolean -{ +function messageBox(text: string, title: string = null, buttons: MessageBoxButton[] = []): boolean { if (document.querySelector('.messagebox')) { return false; } @@ -104,11 +112,13 @@ function messageBox(text: string, title: string = null, buttons: MessageBoxButto const buttonsContainer = container.appendChild(document.createElement('div')); buttonsContainer.className = 'messagebox__buttons'; + let firstButton = null; + if (buttons.length < 1) { - const okButton = buttonsContainer.appendChild(document.createElement('button')); - okButton.className = 'input__button'; - okButton.textContent = 'OK'; - okButton.addEventListener('click', () => element.remove()); + firstButton = buttonsContainer.appendChild(document.createElement('button')); + firstButton.className = 'input__button'; + firstButton.textContent = 'OK'; + firstButton.addEventListener('click', () => element.remove()); } else { for (let i = 0; i < buttons.length; i++) { let button = buttonsContainer.appendChild(document.createElement('button')); @@ -118,9 +128,87 @@ function messageBox(text: string, title: string = null, buttons: MessageBoxButto element.remove(); buttons[i].callback(); }); + + if (firstButton === null) + firstButton = button; } } document.body.appendChild(element); + firstButton.focus(); + return true; +} + +function loginModal(): boolean { + if (document.querySelector('.messagebox') || getCurrentUser('user_id') > 0) { + return false; + } + + const element: HTMLDivElement = document.createElement('div'); + element.className = 'messagebox'; + + const container: HTMLFormElement = element.appendChild(document.createElement('form')); + container.className = 'container messagebox__container auth js-login-form'; + container.method = 'post'; + container.action = '/auth.php'; + + const titleElement = container.appendChild(document.createElement('div')), + titleBackground = titleElement.appendChild(document.createElement('div')), + titleHeader = titleElement.appendChild(document.createElement('div')); + + titleElement.className = 'container__title'; + titleBackground.className = 'container__title__background'; + titleHeader.className = 'auth__header'; + + const authAvatar: HTMLDivElement = titleHeader.appendChild(document.createElement('div')); + authAvatar.className = 'avatar auth__avatar'; + authAvatar.style.backgroundImage = "url('/profile.php?u=0&m=avatar')"; + + const hiddenMode: HTMLInputElement = container.appendChild(document.createElement('input')); + hiddenMode.type = 'hidden'; + hiddenMode.name = 'auth[mode]'; + hiddenMode.value = 'login'; + + const hiddenCsrf: HTMLInputElement = container.appendChild(document.createElement('input')); + hiddenCsrf.type = 'hidden'; + hiddenCsrf.name = 'csrf[login]'; + hiddenCsrf.value = getCSRFToken('login'); + + const hiddenRedirect: HTMLInputElement = container.appendChild(document.createElement('input')); + hiddenRedirect.type = 'hidden'; + hiddenRedirect.name = 'auth[redirect]'; + hiddenRedirect.value = location.toString(); + + const authForm: HTMLDivElement = container.appendChild(document.createElement('div')); + authForm.className = 'auth__form'; + + const inputUsername: HTMLInputElement = authForm.appendChild(document.createElement('input')); + inputUsername.className = 'input__text auth__input'; + inputUsername.placeholder = 'Username'; + inputUsername.type = 'text'; + inputUsername.name = 'auth[username]'; + inputUsername.addEventListener('keyup', () => loginFormUpdateAvatar(authAvatar, inputUsername)); + + const inputPassword: HTMLInputElement = authForm.appendChild(document.createElement('input')); + inputPassword.className = 'input__text auth__input'; + inputPassword.placeholder = 'Password'; + inputPassword.type = 'password'; + inputPassword.name = 'auth[password]'; + + const formButtons: HTMLDivElement = authForm.appendChild(document.createElement('div')); + formButtons.className = 'auth__buttons'; + + const inputLogin: HTMLButtonElement = formButtons.appendChild(document.createElement('button')); + inputLogin.className = 'input__button auth__button'; + inputLogin.textContent = 'Log in'; + + const inputClose: HTMLButtonElement = formButtons.appendChild(document.createElement('button')); + inputClose.className = 'input__button auth__button'; + inputClose.textContent = 'Close'; + inputClose.type = 'button'; + inputClose.addEventListener('click', () => element.remove()); + + document.body.appendChild(element); + inputUsername.focus(); return true; } diff --git a/misuzu.php b/misuzu.php index 48e3fb70..44be858d 100644 --- a/misuzu.php +++ b/misuzu.php @@ -390,6 +390,9 @@ MIG; if (!empty($userDisplayInfo)) { tpl_var('current_user', $userDisplayInfo); + } else { + // make sure the login csrf token is available + csrf_token('login'); } $inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage'); diff --git a/public/auth.php b/public/auth.php index 0558e17f..a784d514 100644 --- a/public/auth.php +++ b/public/auth.php @@ -227,7 +227,7 @@ MSG; $remainingAttempts === 2 ? '' : 's' ); - if ($userData['user_id'] < 1) { + if (empty($userData) || $userData['user_id'] < 1) { user_login_attempt_record(false, null, $ipAddress, $userAgent); $authLoginError = $loginFailedError; break; diff --git a/templates/_layout/header.twig b/templates/_layout/header.twig index 8cf71d5e..f542ecbf 100644 --- a/templates/_layout/header.twig +++ b/templates/_layout/header.twig @@ -82,6 +82,7 @@ 'title': 'Log in', 'url': '/auth.php?m=login', 'icon': 'fas fa-sign-in-alt fa-fw', + 'class': 'js-login-button', }, ] %} @@ -116,7 +117,7 @@
{% for item in user_menu %} {% if item.display is not defined or item.display %} - + {% endif %} @@ -126,7 +127,7 @@ {% else %} - {% endif %}
@@ -154,7 +155,7 @@
{% for item in user_menu %} {% if item.display is not defined or item.display %} - + {{ item.title }} {% endif %} diff --git a/templates/auth/macros.twig b/templates/auth/macros.twig index 81819d2e..618b9434 100644 --- a/templates/auth/macros.twig +++ b/templates/auth/macros.twig @@ -31,7 +31,9 @@ {{ input_text('auth[username]', 'auth__input js-login-username', username|default(''), 'text', 'Username', true, null, 0, autofocus) }} {{ input_text('auth[password]', 'auth__input', '', 'password', 'Password', true, null) }} - +
+ +
{% endmacro %}