From c21d1b65acc112a6d61b41592b1c0a8fe59c6ebc Mon Sep 17 00:00:00 2001 From: flashwave Date: Tue, 2 Oct 2018 21:16:42 +0200 Subject: [PATCH] cool new CSRF protection system --- assets/less/main.less | 20 ++++ misuzu.php | 6 +- public/auth.php | 17 ++- public/comments.php | 2 +- public/forum/posting.php | 2 +- public/manage/changelog.php | 6 +- public/manage/users.php | 4 +- public/settings.php | 83 ++++++++------ src/csrf.php | 114 ++++++++++++++++++++ templates/_layout/comments.twig | 10 +- templates/_layout/header.twig | 2 +- templates/auth/auth.twig | 4 + templates/auth/logout.twig | 2 +- templates/auth/macros.twig | 1 + templates/forum/macros.twig | 3 +- templates/manage/changelog/action_edit.twig | 4 +- templates/manage/changelog/change_edit.twig | 8 +- templates/manage/changelog/tag_edit.twig | 52 +-------- templates/manage/users/roles_create.twig | 4 +- templates/manage/users/view.twig | 8 +- templates/master.twig | 2 +- templates/settings/account.twig | 26 ++++- templates/settings/sessions.twig | 6 +- templates/user/profile.twig | 2 +- utility.php | 12 --- 25 files changed, 276 insertions(+), 124 deletions(-) create mode 100644 src/csrf.php diff --git a/assets/less/main.less b/assets/less/main.less index 80d5fde8..ffa80280 100644 --- a/assets/less/main.less +++ b/assets/less/main.less @@ -67,6 +67,26 @@ body { &--legacy { --background-color: #fbeeff; } + + &--bg-blend { + background-blend-mode: multiply; + } + + /*&--bg-slide { + }*/ + + &--bg-cover { + background-repeat: no-repeat; + } + + &--bg-stretch { + background-size: 100% 100%; + background-repeat: no-repeat; + } + + &--bg-tile { + background-repeat: repeat; + } } // Input elements diff --git a/misuzu.php b/misuzu.php index 2199780d..08ab438c 100644 --- a/misuzu.php +++ b/misuzu.php @@ -30,6 +30,7 @@ require_once 'src/audit_log.php'; require_once 'src/changelog.php'; require_once 'src/colour.php'; require_once 'src/comments.php'; +require_once 'src/csrf.php'; require_once 'src/general.php'; require_once 'src/git.php'; require_once 'src/manage.php'; @@ -261,10 +262,11 @@ MIG; tpl_add_function('vsprintf', true); tpl_add_function('perms_check', true); tpl_add_function('bg_settings', true, 'user_background_settings_strings'); + tpl_add_function('csrf', true, 'csrf_html'); tpl_add_function('git_commit_hash'); tpl_add_function('git_branch'); - tpl_add_function('csrf_token', false, 'tmp_csrf_token'); + tpl_add_function('csrf_token'); tpl_add_function('startup_time', false, function (float $time = MSZ_STARTUP) { return microtime(true) - $time; }); @@ -301,6 +303,8 @@ MIG; } } + csrf_init('soapsoapsoap', empty($userDisplayInfo) ? ip_remote_address() : $_COOKIE['msz_sid']); + $privateInfo = $app->getPrivateInfo(); if (!$misuzuBypassLockdown && $privateInfo['enabled'] && !$app->hasActiveSession()) { diff --git a/public/auth.php b/public/auth.php index 3e9a4ce5..214d7036 100644 --- a/public/auth.php +++ b/public/auth.php @@ -44,7 +44,7 @@ switch ($authMode) { return; } - if (isset($_GET['s']) && tmp_csrf_verify($_GET['s'])) { + if (csrf_verify('logout', $_GET['s'] ?? '')) { set_cookie_m('uid', '', -3600); set_cookie_m('sid', '', -3600); user_session_delete($app->getSessionId()); @@ -159,6 +159,11 @@ switch ($authMode) { } while ($isSubmission) { + if (!csrf_verify('passforgot', $_POST['csrf'] ?? '')) { + tpl_var('auth_forgot_error', 'Possible request forgery detected, refresh and try again.'); + break; + } + if (empty($authEmail)) { tpl_var('auth_forgot_error', 'Please enter an e-mail address.'); break; @@ -257,6 +262,11 @@ MSG; break; } + if (!csrf_verify('login', $_POST['csrf'] ?? '')) { + $authLoginError = 'Possible request forgery detected, refresh and try again.'; + break; + } + $getUser = Database::prepare(' SELECT `user_id`, `password` FROM `msz_users` @@ -340,6 +350,11 @@ MSG; break; } + if (!csrf_verify('register', $_POST['csrf'] ?? '')) { + $authRegistrationError = 'Possible request forgery detected, refresh and try again.'; + break; + } + $checkSpamBot = mb_strtolower($_POST['auth']['meow'] ?? ''); $spamBotValid = [ '19', '21', 'nineteen', 'nine-teen', 'nine teen', 'twentyone', 'twenty-one', 'twenty one', diff --git a/public/comments.php b/public/comments.php index 97b346bd..ee032998 100644 --- a/public/comments.php +++ b/public/comments.php @@ -15,7 +15,7 @@ if ($isXHR) { return; } -if (!tmp_csrf_verify($_REQUEST['csrf'] ?? '')) { +if (!csrf_verify('comments', $_REQUEST['csrf'] ?? '')) { echo render_info_or_json($isXHR, "Couldn't verify this request, please refresh the page and try again.", 403); return; } diff --git a/public/forum/posting.php b/public/forum/posting.php index 65979117..f8328483 100644 --- a/public/forum/posting.php +++ b/public/forum/posting.php @@ -83,7 +83,7 @@ if (!forum_may_have_topics($forum['forum_type'])) { } if ($postRequest) { - if (!tmp_csrf_verify($_POST['csrf'] ?? '')) { + if (!csrf_verify('settings', $_POST['csrf'] ?? '')) { echo 'Could not verify request.'; return; } diff --git a/public/manage/changelog.php b/public/manage/changelog.php index 18bbba57..cfebc0c9 100644 --- a/public/manage/changelog.php +++ b/public/manage/changelog.php @@ -73,7 +73,7 @@ switch ($_GET['v'] ?? null) { $changeId = (int)($_GET['c'] ?? 0); - if ($_SERVER['REQUEST_METHOD'] === 'POST' && tmp_csrf_verify($_POST['csrf'] ?? '')) { + if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_verify('changelog_add', $_POST['csrf'] ?? '')) { if (!empty($_POST['change']) && is_array($_POST['change'])) { if ($changeId > 0) { $postChange = Database::prepare(' @@ -260,7 +260,7 @@ switch ($_GET['v'] ?? null) { $tagId = (int)($_GET['t'] ?? 0); - if ($_SERVER['REQUEST_METHOD'] === 'POST' && tmp_csrf_verify($_POST['csrf'] ?? '')) { + if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_verify('changelog_tag', $_POST['csrf'] ?? '')) { if (!empty($_POST['tag']) && is_array($_POST['tag'])) { if ($tagId > 0) { $updateTag = Database::prepare(' @@ -325,7 +325,7 @@ switch ($_GET['v'] ?? null) { $actionId = (int)($_GET['a'] ?? 0); - if ($_SERVER['REQUEST_METHOD'] === 'POST' && tmp_csrf_verify($_POST['csrf'] ?? '')) { + if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_verify('changelog_action', $_POST['csrf'] ?? '')) { if (!empty($_POST['action']) && is_array($_POST['action'])) { if ($actionId > 0) { $updateAction = Database::prepare(' diff --git a/public/manage/users.php b/public/manage/users.php index 37025db9..629e1e2e 100644 --- a/public/manage/users.php +++ b/public/manage/users.php @@ -113,7 +113,7 @@ switch ($_GET['v'] ?? null) { } if ($isPostRequest) { - if (!tmp_csrf_verify($_POST['csrf'] ?? '')) { + if (!csrf_verify('users_edit', $_POST['csrf'] ?? '')) { echo 'csrf err'; break; } @@ -303,7 +303,7 @@ switch ($_GET['v'] ?? null) { } if ($isPostRequest) { - if (!tmp_csrf_verify($_POST['csrf'] ?? '')) { + if (!csrf_verify('users_role', $_POST['csrf'] ?? '')) { echo 'csrf err'; break; } diff --git a/public/settings.php b/public/settings.php index 1128a16d..982520e8 100644 --- a/public/settings.php +++ b/public/settings.php @@ -57,7 +57,7 @@ $avatarProps = $app->getAvatarProps(); $backgroundProps = $app->getBackgroundProps(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (!tmp_csrf_verify($_POST['csrf'] ?? '')) { + if (!csrf_verify('settings', $_POST['csrf'] ?? '')) { $settingsErrors[] = MSZ_TMP_USER_ERROR_STRINGS['csrf']; } else { if (!empty($_POST['profile']) && is_array($_POST['profile'])) { @@ -156,6 +156,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { switch ($_POST['background']['mode'] ?? '') { case 'delete': user_background_delete($settingsUserId); + user_background_set_settings($settingsUserId, MSZ_USER_BACKGROUND_ATTACHMENT_NONE); break; case 'upload': @@ -164,40 +165,55 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { break; } - if (empty($_FILES['background']) - || !is_array($_FILES['background']) - || empty($_FILES['background']['name']['file'])) { + if (empty($_POST['background']) + || !is_array($_POST['background'])) { break; } - if ($_FILES['background']['error']['file'] !== UPLOAD_ERR_OK) { - $settingsErrors[] = sprintf( - MSZ_TMP_USER_ERROR_STRINGS['avatar']['upload'][$_FILES['background']['error']['file']] - ?? MSZ_TMP_USER_ERROR_STRINGS['avatar']['upload']['_'], - $_FILES['background']['error']['file'], - byte_symbol($backgroundProps['max_size'], true), - $backgroundProps['max_width'], - $backgroundProps['max_height'] + if (!empty($_FILES['background']['name']['file'])) { + if ($_FILES['background']['error']['file'] !== UPLOAD_ERR_OK) { + $settingsErrors[] = sprintf( + MSZ_TMP_USER_ERROR_STRINGS['avatar']['upload'][$_FILES['background']['error']['file']] + ?? MSZ_TMP_USER_ERROR_STRINGS['avatar']['upload']['_'], + $_FILES['background']['error']['file'], + byte_symbol($backgroundProps['max_size'], true), + $backgroundProps['max_width'], + $backgroundProps['max_height'] + ); + break; + } + + $setBackground = user_background_set_from_path( + $settingsUserId, + $_FILES['background']['tmp_name']['file'], + $backgroundProps ); - break; + + if ($setBackground !== MSZ_USER_BACKGROUND_NO_ERRORS) { + $settingsErrors[] = sprintf( + MSZ_TMP_USER_ERROR_STRINGS['avatar']['set'][$setBackground] + ?? MSZ_TMP_USER_ERROR_STRINGS['avatar']['set']['_'], + $setBackground, + byte_symbol($backgroundProps['max_size'], true), + $backgroundProps['max_width'], + $backgroundProps['max_height'] + ); + } } - $setBackground = user_background_set_from_path( - $settingsUserId, - $_FILES['background']['tmp_name']['file'], - $backgroundProps - ); + $backgroundSettings = in_array($_POST['background']['attach'] ?? '', MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES) + ? array_flip(MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES)[$_POST['background']['attach']] + : MSZ_USER_BACKGROUND_ATTACHMENTS[0]; - if ($setBackground !== MSZ_USER_BACKGROUND_NO_ERRORS) { - $settingsErrors[] = sprintf( - MSZ_TMP_USER_ERROR_STRINGS['avatar']['set'][$setBackground] - ?? MSZ_TMP_USER_ERROR_STRINGS['avatar']['set']['_'], - $setBackground, - byte_symbol($backgroundProps['max_size'], true), - $backgroundProps['max_width'], - $backgroundProps['max_height'] - ); + if (!empty($_POST['background']['attr']['blend'])) { + $backgroundSettings |= MSZ_USER_BACKGROUND_ATTRIBUTE_BLEND; } + + if (!empty($_POST['background']['attr']['slide'])) { + $backgroundSettings |= MSZ_USER_BACKGROUND_ATTRIBUTE_SLIDE; + } + + user_background_set_settings($settingsUserId, $backgroundSettings); break; } } @@ -220,7 +236,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } elseif ((int)$session['user_id'] !== $settingsUserId) { $settingsErrors[] = 'You may only end your own sessions.'; } elseif ((int)$session['session_id'] === $app->getSessionId()) { - header('Location: /auth.php?m=logout&s=' . tmp_csrf_token()); + header('Location: /auth.php?m=logout&s=' . csrf_token('logout')); return; } else { user_session_delete($session['session_id']); @@ -334,11 +350,17 @@ switch ($settingsMode) { $getAccountInfo = Database::prepare(sprintf( ' - SELECT %s, `email`, `user_about_content`, `user_about_parser` + SELECT + %1$s, `email`, `user_about_content`, `user_about_parser`, + `user_background_settings` & 0x0F as `user_background_attachment`, + (`user_background_settings` & %2$d) > 0 as `user_background_attr_blend`, + (`user_background_settings` & %3$d) > 0 as `user_background_attr_slide` FROM `msz_users` WHERE `user_id` = :user_id ', - pdo_prepare_array($profileFields, true, '`user_%s`') + pdo_prepare_array($profileFields, true, '`user_%s`'), + MSZ_USER_BACKGROUND_ATTRIBUTE_BLEND, + MSZ_USER_BACKGROUND_ATTRIBUTE_SLIDE )); $getAccountInfo->bindValue('user_id', $settingsUserId); $accountInfo = $getAccountInfo->execute() ? $getAccountInfo->fetch(PDO::FETCH_ASSOC) : []; @@ -354,6 +376,7 @@ switch ($settingsMode) { 'settings_profile_fields' => $profileFields, 'settings_disable_account_options' => $disableAccountOptions, 'account_info' => $accountInfo, + 'background_attachments' => MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES, ]); break; diff --git a/src/csrf.php b/src/csrf.php new file mode 100644 index 00000000..8d488225 --- /dev/null +++ b/src/csrf.php @@ -0,0 +1,114 @@ +'); +define('MSZ_CSRF_SECRET_STORE', '_msz_csrf_secret'); +define('MSZ_CSRF_IDENTITY_STORE', '_msz_csrf_identity'); +define('MSZ_CSRF_TOKEN_STORE', '_msz_csrf_tokens'); +define('MSZ_CSRF_HASH_ALGO', 'sha256'); +define('MSZ_CSRF_TOKEN_LENGTH', 76); // 8 + 4 + 64 + +// the following two functions DO NOT depend on csrf_init(). +// $realm = Some kinda identifier for whatever's trying to do a validation. +// $identity = When the user is logged in I recommend just using their ID, otherwise IP will be fine. +function csrf_token_create( + string $realm, + string $identity, + string $secretKey, + ?int $timestamp = null, + int $tolerance = MSZ_CSRF_TOLERANCE +): string { + $timestamp = $timestamp ?? time(); + $token = bin2hex(pack('Vv', $timestamp, $tolerance)); + + return $token . csrf_token_hash( + MSZ_CSRF_HASH_ALGO, + $realm, + $identity, + $secretKey, + $timestamp, + $tolerance + ); +} + +function csrf_token_hash( + string $algo, + string $realm, + string $identity, + string $secretKey, + int $timestamp, + int $tolerance +): string { + return hash_hmac( + $algo, + implode(',', [$realm, $identity, $timestamp, $tolerance]), + $secretKey + ); +} + +function csrf_token_verify( + string $realm, + string $token, + string $identity, + string $secretKey +): bool { + if (empty($token) || strlen($token) !== MSZ_CSRF_TOKEN_LENGTH) { + return false; + } + + [$timestamp, $tolerance] = [0, 0]; + extract(unpack('Vtimestamp/vtolerance', hex2bin(substr($token, 0, 12)))); + + if (time() > $timestamp + $tolerance) { + return false; + } + + // remove timestamp + tolerance from token + $token = substr($token, 12); + + $compare = csrf_token_hash( + MSZ_CSRF_HASH_ALGO, + $realm, + $identity, + $secretKey, + $timestamp, + $tolerance + ); + + return hash_equals($compare, $token); +} + +// Sets some defaults +function csrf_init(string $secretKey, string $identity): void +{ + $GLOBALS[MSZ_CSRF_SECRET_STORE] = $secretKey; + $GLOBALS[MSZ_CSRF_IDENTITY_STORE] = $identity; + $GLOBALS[MSZ_CSRF_TOKEN_STORE] = []; +} + +function csrf_token(string $realm): string +{ + if (array_key_exists($realm, $GLOBALS[MSZ_CSRF_TOKEN_STORE])) { + return $GLOBALS[MSZ_CSRF_TOKEN_STORE][$realm]; + } + + return $GLOBALS[MSZ_CSRF_TOKEN_STORE][$realm] = csrf_token_create( + $realm, + $GLOBALS[MSZ_CSRF_IDENTITY_STORE], + $GLOBALS[MSZ_CSRF_SECRET_STORE] + ); +} + +function csrf_verify(string $realm, string $token): bool +{ + return csrf_token_verify( + $realm, + $token, + $GLOBALS[MSZ_CSRF_IDENTITY_STORE], + $GLOBALS[MSZ_CSRF_SECRET_STORE] + ); +} + +function csrf_html(string $realm, string $name = 'csrf'): string +{ + return sprintf(MSZ_CSRF_HTML, $name, csrf_token($realm)); +} diff --git a/templates/_layout/comments.twig b/templates/_layout/comments.twig index 12f7e563..fc8978e0 100644 --- a/templates/_layout/comments.twig +++ b/templates/_layout/comments.twig @@ -5,7 +5,7 @@ method="post" action="/comments.php?m=create" id="comment-{{ reply_mode ? 'reply-' ~ reply_to.comment_id : 'create-' ~ category.category_id }}"> - + {{ 'comments'|csrf|raw }} {% if reply_mode %} @@ -86,14 +86,14 @@
{% if perms.can_vote %} + href="/comments.php?m=vote&c={{ comment.comment_id }}&v={{ comment.comment_user_vote == 'Like' ? '0' : '1' }}&csrf={{ csrf_token('comments') }}"> Like {% if comment.comment_likes > 0 %} ({{ comment.comment_likes|number_format }}) {% endif %} + href="/comments.php?m=vote&c={{ comment.comment_id }}&v={{ comment.comment_user_vote == 'Dislike' ? '0' : '-1' }}&csrf={{ csrf_token('comments') }}"> Dislike {% if comment.comment_dislikes > 0 %} ({{ comment.comment_dislikes|number_format }}) @@ -431,7 +431,7 @@ var replyCsrf = document.createElement('input'); replyCsrf.name = 'csrf'; - replyCsrf.value = '{{ csrf_token() }}'; + replyCsrf.value = '{{ csrf_token("comments") }}'; replyCsrf.type = 'hidden'; commentReplyInput.appendChild(replyCsrf); @@ -571,7 +571,7 @@ commentVoteLock = false; }; - xhr.open('GET', '/comments.php?m=vote&c={0}&v={1}&csrf={{ csrf_token() }}'.replace('{0}', id).replace('{1}', vote)); + xhr.open('GET', '/comments.php?m=vote&c={0}&v={1}&csrf={{ csrf_token("comments") }}'.replace('{0}', id).replace('{1}', vote)); xhr.setRequestHeader('X-Misuzu-XHR', 'comments'); xhr.send(); } diff --git a/templates/_layout/header.twig b/templates/_layout/header.twig index e874342c..9e123dac 100644 --- a/templates/_layout/header.twig +++ b/templates/_layout/header.twig @@ -82,7 +82,7 @@ {% endif %}
  • - Log out + Log out
  • {% else %}
  • diff --git a/templates/auth/auth.twig b/templates/auth/auth.twig index f72185e5..749d2988 100644 --- a/templates/auth/auth.twig +++ b/templates/auth/auth.twig @@ -11,6 +11,8 @@ {% if not prevent_registration %}
    + {{ 'register'|csrf|raw }} +
    Register
    {% if auth_register_error is defined %} @@ -44,6 +46,8 @@ {% if not prevent_password_reset %} + {{ 'passforgot'|csrf|raw }} +
    Forgot password
    {% if auth_forgot_error is defined %} diff --git a/templates/auth/logout.twig b/templates/auth/logout.twig index da37a8b0..c8b177bb 100644 --- a/templates/auth/logout.twig +++ b/templates/auth/logout.twig @@ -7,7 +7,7 @@

    We couldn't verify that you were actually the person attempting to log out.

    Press the button below to verify the logout request, otherwise click back in your browser or close this tab.

    - Logout + Logout
  • {% endblock %} diff --git a/templates/auth/macros.twig b/templates/auth/macros.twig index ac4dfc24..7a8b3ba4 100644 --- a/templates/auth/macros.twig +++ b/templates/auth/macros.twig @@ -3,6 +3,7 @@ + {{ 'login'|csrf|raw }}
    + {{ 'forum_post'|csrf|raw }} {#

    Error: Your post contained too much text, shorten it a bit or split it out in two posts.

    @@ -331,7 +332,7 @@
    - +
    diff --git a/templates/manage/changelog/action_edit.twig b/templates/manage/changelog/action_edit.twig index 5c9b9b96..065a42c9 100644 --- a/templates/manage/changelog/action_edit.twig +++ b/templates/manage/changelog/action_edit.twig @@ -3,6 +3,8 @@ {% block manage_content %}
    + {{ 'changelog_action'|csrf|raw }} +

    {% if edit_action is defined %} Editing {{ edit_action.action_name }} ({{ edit_action.action_id }}) @@ -56,7 +58,7 @@
    - +

    diff --git a/templates/manage/changelog/change_edit.twig b/templates/manage/changelog/change_edit.twig index ec438f76..38856261 100644 --- a/templates/manage/changelog/change_edit.twig +++ b/templates/manage/changelog/change_edit.twig @@ -7,6 +7,8 @@ {% block manage_content %}
    + {{ 'changelog_add'|csrf|raw }} +

    {% if edit_change is defined %} Editing #{{ edit_change.change_id }} @@ -57,7 +59,7 @@
    - +
    @@ -82,7 +84,7 @@
    - +
    {% endif %} @@ -103,7 +105,7 @@
    - +
    {% endif %} diff --git a/templates/manage/changelog/tag_edit.twig b/templates/manage/changelog/tag_edit.twig index b62d29e3..1702aae3 100644 --- a/templates/manage/changelog/tag_edit.twig +++ b/templates/manage/changelog/tag_edit.twig @@ -3,6 +3,8 @@ {% block manage_content %}
    + {{ 'changelog_tag'|csrf|raw }} +

    {% if edit_tag is defined %} Editing {{ edit_tag.tag_name }} ({{ edit_tag.tag_id }}) @@ -42,56 +44,8 @@ {% endif %}
    - +
    - - {% if edit_change is defined %} -

    - Tags -

    - - {% if edit_change_assigned_tags|length > 0 %} -
    - - -
    - -
    -
    - {% endif %} - - {% if edit_change_available_tags|length > 0 %} -
    - - -
    - -
    -
    - {% endif %} - {% endif %}
    {% endblock %} diff --git a/templates/manage/users/roles_create.twig b/templates/manage/users/roles_create.twig index 4a20860a..e1d695c5 100644 --- a/templates/manage/users/roles_create.twig +++ b/templates/manage/users/roles_create.twig @@ -3,6 +3,8 @@ {% block manage_content %}
    + {{ 'users_role'|csrf|raw }} +

    {% if edit_role is defined %} @@ -93,6 +95,6 @@

    {% endif %} - +
    {% endblock %} diff --git a/templates/manage/users/view.twig b/templates/manage/users/view.twig index bad16b3a..bb7f0386 100644 --- a/templates/manage/users/view.twig +++ b/templates/manage/users/view.twig @@ -6,6 +6,8 @@ {% block manage_content %} {% if can_manage_users %}
    + {{ 'users_edit'|csrf|raw }} +
    Viewing {{ view_user.username }} ({{ view_user.user_id }}) @@ -145,7 +147,7 @@
    {% endif %} - + {% endif %} @@ -154,7 +156,7 @@
    Manage Roles
    - + {{ 'users_edit'|csrf|raw }}
    - +
    {% endif %} diff --git a/templates/master.twig b/templates/master.twig index 0cac8f91..8644a238 100644 --- a/templates/master.twig +++ b/templates/master.twig @@ -14,7 +14,7 @@ {% endif %} - + {% include '_layout/header.twig' %}
    diff --git a/templates/settings/account.twig b/templates/settings/account.twig index 0d16d368..5cc27dc4 100644 --- a/templates/settings/account.twig +++ b/templates/settings/account.twig @@ -14,7 +14,7 @@
    Account