update totp and profile style

This commit is contained in:
Jordan Blasenhauer 2023-12-27 19:04:32 +01:00
parent 1920d89b49
commit 556fc69365
6 changed files with 184 additions and 43 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,5 @@
import { Tabs, Popover } from "./utils/settings.js";
class SubmitProfile {
constructor() {
this.pwEl = document.querySelector("#admin_password");
@ -41,7 +43,7 @@ class SubmitProfile {
"focus:valid:!border-red-500",
"active:!border-red-500",
"active:valid:!border-red-500",
"valid:!border-red-500",
"valid:!border-red-500"
);
this.pwAlertEl.classList.add("opacity-0");
this.pwAlertEl.setAttribute("aria-hidden", "true");
@ -53,7 +55,7 @@ class SubmitProfile {
"focus:valid:!border-red-500",
"active:!border-red-500",
"active:valid:!border-red-500",
"valid:!border-red-500",
"valid:!border-red-500"
);
this.pwAlertEl.classList.remove("opacity-0");
this.pwAlertEl.setAttribute("aria-hidden", "false");
@ -71,14 +73,14 @@ class PwBtn {
const passwordContainer = e.target.closest("[data-input-group]");
const inpEl = passwordContainer.querySelector("input");
const invBtn = passwordContainer.querySelector(
'[data-setting-password="invisible"]',
'[data-setting-password="invisible"]'
);
const visBtn = passwordContainer.querySelector(
'[data-setting-password="visible"]',
'[data-setting-password="visible"]'
);
inpEl.setAttribute(
"type",
inpEl.getAttribute("type") === "password" ? "text" : "password",
inpEl.getAttribute("type") === "password" ? "text" : "password"
);
if (inpEl.getAttribute("type") === "password") {
@ -96,3 +98,5 @@ class PwBtn {
const setPWBtn = new PwBtn();
const setSubmit = new SubmitProfile();
const setTabs = new Tabs();
const setPopover = new Popover();

View file

@ -31,7 +31,7 @@
<!-- info -->
<main
class="xl:pl-75 w-full px-2 sm:px-6 pb-0 pt-20 sm:pt-6 min-h-[80vh] h-full flex flex-col justify-between"
class="xl:pl-75 w-full px-2 sm:px-6 pb-0 pt-20 sm:pt-6 min-h-[85vh] h-full flex flex-col justify-between"
>
<div
class="max-w-[1920px] grid gap-y-4 gap-3 sm:gap-4 lg:gap-6 grid-cols-12 w-full"

View file

@ -44,6 +44,6 @@
{% elif current_endpoint == "jobs" %}
<script type="module" src="./js/jobs.js"></script>
{% elif current_endpoint == "profile" %}
<script defer src="./js/profile.js"></script>
<script type="module" src="./js/profile.js"></script>
{% endif %}
</head>

View file

@ -2,12 +2,12 @@
url_for(request.endpoint)[1:].split("/")[-1].strip() %}
<div
class="w-full overflow-hidden overflow-y-auto overflow-x-auto max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
class="h-fit w-full overflow-hidden overflow-y-auto overflow-x-auto col-span-12 md:col-span-6 2xl:col-span-4 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="my-2 font-bold dark:text-white/90 mx-2">PROFILE</h5>
<div class="grid grid-cols-12 justify-items-center w-full">
<div
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 md:px-6 mb-4 md:mb-3 lg:px-6 lg:mb-1 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -31,10 +31,131 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
</div>
<div
class="w-full overflow-hidden overflow-y-auto overflow-x-auto max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
data-service-content
class="w-full overflow-hidden overflow-y-auto overflow-x-auto col-span-12 lg:col-span-6 2xl:col-span-8 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="my-2 font-bold dark:text-white/90 mx-2">EDIT PROFILE</h5>
<!-- desktop tabs -->
<div
role="tablist"
data-{{current_endpoint}}-tabs-desktop
class="hidden md:block col-span-12 mb-4"
>
<!-- tabs -->
<button
role="tab"
data-tab-handler="profile"
class="active settings-tabs-tab-btn"
>
<span class="w-full flex justify-between items-center">
<!-- text and icon -->
<span class="settings-tabs-name"> User </span>
<svg
data-popover-btn="profile"
class="fill-blue-500 h-5 w-5 mr-2 hover:brightness-95"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32z"
/>
</svg>
<!-- end text and icon -->
<!-- popover -->
<span
data-popover-content="profile"
class="settings-tabs-popover-container hidden"
>
<span class="settings-tabs-popover-text"
>Update profile data (username, password...)</span
>
</span>
<!-- end popover -->
</span>
</button>
<button role="tab" data-tab-handler="totp" class="settings-tabs-tab-btn">
<span class="w-full flex justify-between items-center">
<!-- text and icon -->
<span class="settings-tabs-name"> TOTP </span>
<svg
data-popover-btn="totp"
class="fill-blue-500 h-5 w-5 mr-2 hover:brightness-95"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32z"
/>
</svg>
<!-- end text and icon -->
<!-- popover -->
<span
data-popover-content="totp"
class="settings-tabs-popover-container hidden"
>
<span class="settings-tabs-popover-text"
>Enabled / Disabled TOTP
</span>
</span>
<!-- end popover -->
</span>
</button>
<!--end tabs-->
</div>
<!-- end desktop tabs -->
<!-- mobile tabs -->
<div class="md:hidden relative col-span-12 mb-4 mt-2 mx-2">
<button
data-tab-dropdown-btn
aria-controls="tab-dropdown-mobile"
class="settings-tabs-mobile-btn"
>
<span aria-description="current tab" class="settings-tabs-mobile-btn-text"
>Profile
</span>
<!-- chevron -->
<svg
class="transition-transform h-4 w-4 fill-primary dark:fill-gray-300"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"
/>
</svg>
<!-- end chevron -->
</button>
<!-- dropdown-->
<div
id="tab-dropdown-mobile"
role="listbox"
data-tab-dropdown
class="hidden z-100 absolute flex-col w-full overflow-hidden overflow-y-auto max-h-90"
>
<button
role="option"
data-tab-handler-mobile="profile"
data-select="false"
id="edit-{{current_endpoint}}-profile-tab"
class="active first settings-tabs-mobile-dropdown-btn"
>
Profile
</button>
<button
role="option"
data-tab-handler-mobile="totp"
data-select="false"
id="edit-{{current_endpoint}}-totp-tab"
class="settings-tabs-mobile-dropdown-btn rounded-b"
>
TOTP
</button>
</div>
<!-- end dropdown-->
</div>
<!-- end mobile tabs -->
<form
data-plugin-item="profile"
class="grid grid-cols-12 w-full justify-items-center"
id="profile-form"
action="profile"
@ -49,12 +170,12 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
/>
<!-- username inpt-->
<div
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
>
username
Username
</h5>
<label class="sr-only" for="admin_username">New username</label>
<input
@ -72,7 +193,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
<!-- password inpt-->
<div
data-input-group
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -85,7 +206,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
id="curr_password"
name="curr_password"
class="col-span-12 regular-input"
placeholder="enter password"
placeholder="enter current password"
value=""
pattern="^(?=.*?\d)(?=.*?[ !\u0022#$%&'\(\)*+,.\/:;<=>?@\[\\\]^_`\u007B\u007C\u007D\u007E\u002D]).{8,}$"
minlength="8"
@ -131,7 +252,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
<!-- password inpt-->
<div
data-input-group
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -144,14 +265,14 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
id="admin_password"
name="admin_password"
class="col-span-12 regular-input"
placeholder="enter password"
placeholder="enter new password"
value=""
pattern="^(?=.*?\d)(?=.*?[ !\u0022#$%&'\(\)*+,.\/:;<=>?@\[\\\]^_`\u007B\u007C\u007D\u007E\u002D]).{8,}$"
minlength="8"
/>
<div
data-setting-password-container
class="absolute flex right-8 h-5 w-5 top-[60%] md:top-[45%] lg:top-11"
class="absolute flex right-8 h-5 w-5 top-[60%] lg:top-11"
>
<button
data-setting-password="visible"
@ -189,7 +310,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
<!-- password inpt-->
<div
data-input-group
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -204,7 +325,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
id="admin_password_check"
name="admin_password_check"
class="col-span-12 regular-input"
placeholder="confirm password"
placeholder="confirm new password"
value=""
pattern="^(?=.*?\d)(?=.*?[ !\u0022#$%&'\(\)*+,.\/:;<=>?@\[\\\]^_`\u007B\u007C\u007D\u007E\u002D]).{8,}$"
minlength="8"
@ -255,27 +376,26 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
id="profile-button"
name="profile-button"
value="profile"
class="valid-btn"
class="edit-btn"
>
Save
Edit
</button>
</div>
</form>
</div>
<div
class="w-full overflow-hidden overflow-y-auto overflow-x-auto max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="my-2 font-bold dark:text-white/90 mx-2">
2FA SETTINGS {% if not is_totp %} (NOT SETUP) {% else %} (SETUP) {% endif %}
</h5>
<form
class="grid grid-cols-12 w-full justify-items-center"
data-plugin-item="totp"
class="hidden grid grid-cols-12 w-full justify-items-center"
id="profile-form"
action="profile"
method="POST"
autocomplete="off"
>
<h5
class="{% if not is_totp %} text-red-500 {% else %} text-green-500 {% endif %} uppercase col-span-12 text-sm my-2 font-bold dark:text-white/90 mx-2"
>
{% if not is_totp %} TOTP is currently off {% else %} TOTP is currently on
{% endif %}
</h5>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input
type="hidden"
@ -286,24 +406,26 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
<!-- qr secret -->
<div
data-input-group
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
>
2FA QR CODE
</h5>
<img
src="data:image/png;base64, {{ totp_qr_image }}"
alt="Secret Token"
style="width: 200px; height: 200px"
/>
<div class="flex justify-center">
<img
src="data:image/png;base64, {{ totp_qr_image }}"
alt="Secret Token"
style="width: 200px; height: 200px"
/>
</div>
</div>
<!-- end qr secret -->
<!-- secret -->
<div
data-input-group
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -322,7 +444,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
/>
<div
data-setting-password-container
class="absolute flex right-8 h-5 w-5 top-[60%] md:top-[45%] lg:top-11"
class="absolute flex right-8 h-5 w-5 top-[60%] lg:top-11"
>
<button
data-setting-password="visible"
@ -360,7 +482,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
{% endif %} {% if is_totp or not is_totp %}
<!-- username inpt-->
<div
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -383,7 +505,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
{% endif %}
<div
data-input-group
class="flex flex-col relative col-span-12 md:col-span-6 lg:col-span-4 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full"
>
<h5
class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"
@ -440,17 +562,18 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
</div>
<!-- end password inpt-->
<div class="col-span-12 flex justify-center">
<div class="col-span-12 flex justify-center mt-6">
<button
type="submit"
id="profile-button"
name="profile-button"
value="profile"
class="valid-btn"
class="{% if not is_totp %}valid-btn{% else %}delete-btn{% endif %}"
>
{% if not is_totp %} enable totp {% else %} disable totp {% endif %}
</button>
</div>
</form>
</div>
{% endblock %}

View file

@ -125,7 +125,20 @@
</div>
</div>
<!-- end form -->
<!-- particles -->
<div class="-z-10 fixed bg-primary">
<div id="particles-js" class="login-img [&>*]:bg-primary"></div>
<div class="hidden lg:flex justify-center">
<img
class="max-w-60 max-h-30"
src="images/BUNKERWEB-print-hd-blanc.png"
alt="logo"
class="images login-logo"
/>
</div>
</div>
</main>
<script src="js/tsparticles.bundle.min.js"></script>
<script>
class Loader {
constructor() {
@ -201,6 +214,7 @@
const setLoader = new Loader();
const setFlash = new FlashMsg();
tsParticles.loadJSON("particles-js", "json/particles.json");
</script>
</body>
</html>