Advanced Authentication

This commit is contained in:
Mawoka
2022-12-18 18:31:06 +01:00
parent bb848adca8
commit 2e159af134
29 changed files with 3315 additions and 1620 deletions
@@ -0,0 +1,215 @@
<!--
- 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 https://mozilla.org/MPL/2.0/.
-->
<script lang="ts">
import Spinner from '$lib/Spinner.svelte';
import { browser } from '$app/environment';
import { startRegistration } from '@simplewebauthn/browser';
import TotpSetup from './totp_setup.svelte';
import BackupCodes from './backup_codes.svelte';
let user_data: object | undefined;
let security_keys: Array<{ id: number }> | undefined;
let totp_activated: boolean | undefined;
let totp_data;
let backup_code;
const get_data = async () => {
const res1 = await fetch('/api/v1/users/me');
user_data = await res1.json();
const res2 = await fetch('/api/v1/users/webauthn/list');
security_keys = await res2.json();
const res3 = await fetch('/api/v1/users/2fa/totp');
totp_activated = (await res3.json()).activated;
};
let data = get_data();
const save_password_required = async () => {
console.log(user_data?.require_password, 'here');
if (!browser || user_data?.require_password === undefined) {
return;
}
const res = await fetch('/api/v1/users/2fa/require_password', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ require_password: user_data?.require_password })
});
user_data.require_password = (await res.json()).require_password;
};
const add_security_key = async () => {
const res1 = await fetch('/api/v1/users/webauthn/add_key');
if (!res1.ok) {
throw Error('Response not ok');
}
let attResp;
const resp_data = await res1.json();
try {
resp_data.authenticatorSelection.authenticatorAttachment = 'cross-platform';
for (let i = 0; i++; i < resp_data.excludeCredentials.length) {
resp_data.excludeCredentials[i].transports = undefined;
}
attResp = await startRegistration(resp_data);
} catch (e) {
throw e;
}
await fetch('/api/v1/users/webauthn/add_key', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(attResp)
});
data = get_data();
};
const remove_security_key = async (key_id: number) => {
await fetch(`/api/v1/users/webauthn/key/${key_id}`, { method: 'DELETE' });
data = get_data();
};
const disable_totp = async () => {
await fetch(`/api/v1/users/2fa/totp`, { method: 'DELETE' });
data = get_data();
};
const enable_totp = async () => {
const res = await fetch('/api/v1/users/2fa/totp', { method: 'POST' });
data = get_data();
totp_data = await res.json();
};
const get_backup_code = async () => {
const res = await fetch('/api/v1/users/2fa/backup_code');
backup_code = (await res.json()).code;
};
$: console.log(user_data?.require_password, 'hello');
</script>
{#await data}
<Spinner my_20={false} />
{:then _}
<div class="grid grid-rows-2 h-screen">
<div class="grid grid-cols-2 h-full border-b-2 border-black">
<div class="h-full w-full border-r-2 border-black">
<h2 class="text-center text-2xl">Backup-Code</h2>
<div class="flex h-full w-full justify-center">
<button
class="m-auto text-lg rounded-lg bg-[#B07156] p-4 hover:bg-opacity-80 transition"
on:click={get_backup_code}
>Get Backup-Codes
</button>
</div>
</div>
<div class="h-full w-full">
<h2 class="text-center text-2xl">Activate 2 Factor</h2>
<div class="flex h-full w-full justify-center flex-col">
<div class="m-auto">
{#if user_data.require_password}
<div class="flex items-center space-x-2">
<button
on:click={() => {
user_data.require_password = !user_data.require_password;
save_password_required();
}}
type="button"
role="switch"
aria-checked="true"
class="relative inline-flex h-5 w-8 shrink-0 cursor-pointer appearance-none rounded-full border-2 border-transparent bg-blue-700 transition focus:outline-none focus:ring focus:ring-blue-200"
>
<span
aria-hidden="true"
class="pointer-events-none inline-block h-4 w-4 translate-x-3 rounded-full bg-white transition will-change-transform"
/>
</button>
<span class="text-sm font-medium text-gray-700"
>Two Factor authentication is activated</span
>
</div>
{:else}
<div class="flex items-center space-x-2">
<button
type="button"
on:click={() => {
user_data.require_password = !user_data.require_password;
save_password_required();
}}
role="switch"
aria-checked="false"
class="relative inline-flex h-5 w-8 shrink-0 cursor-pointer appearance-none rounded-full border-2 border-transparent bg-gray-200 transition focus:outline-none focus:ring focus:ring-blue-200"
>
<span
aria-hidden="true"
class="pointer-events-none inline-block h-4 w-4 translate-x-0 rounded-full bg-white transition will-change-transform"
/>
</button>
<span class="text-sm font-medium text-gray-700"
>Two Factor authentication is deactivated</span
>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="grid grid-cols-2 h-full">
<div class="h-full w-full flex flex-col border-r-2 border-black">
<h2 class="text-center text-2xl">Webauthn</h2>
<div class="flex justify-center">
{#if security_keys.length > 0}
<p>Webauthn is available</p>
{:else}
<p>Webauthn is not available</p>
{/if}
</div>
<div class="flex justify-center">
<button on:click={add_security_key}>Add Security-Key</button>
</div>
<div class="flex justify-center">
<ul class="list-disc block">
{#each security_keys as key, i}
<li>
<button
on:click={() => {
remove_security_key(key.id);
}}
class="hover:line-through transition">{i + 1}</button
>
</li>
{/each}
</ul>
</div>
</div>
<div class="h-full w-full flex flex-col">
<h2 class="text-center text-2xl">Totp</h2>
<div class="flex justify-center">
{#if totp_activated}
<p>Totp is available</p>
{:else}
<p>Totp is not available</p>
{/if}
</div>
<div class="flex justify-center">
{#if totp_activated}
<button on:click={disable_totp}>Disable Totp</button>
{:else}
<button on:click={enable_totp}>Enable Totp</button>
{/if}
</div>
</div>
</div>
</div>
{/await}
{#if totp_data}
<TotpSetup bind:totp_data />
{/if}
{#if backup_code}
<BackupCodes bind:backup_code />
{/if}