OpenAuth_server/Frontend/src/pages/user/pages/Security.svelte

218 lines
5.4 KiB
Svelte

<script lang="ts">
import { Session, TFAOption, TFAType } from "@hibas123/openauth-internalapi";
import InternalAPI from "../../../helper/api";
import Loading from "../Loading.svelte";
import { onMount } from "svelte";
import {
Button,
Card,
Input,
Label,
Select,
Heading,
Spinner,
Helper,
Table,
TableHead,
TableHeadCell,
TableBody,
TableBodyRow,
TableBodyCell,
Accordion,
AccordionItem,
Alert,
} from "flowbite-svelte";
import AddTwoFactor from "./AddTwoFactor.svelte";
let tokens: Session[];
let twofactors: TFAOption[];
let error: string | undefined;
let loading = true;
async function load() {
loading = true;
try {
tokens = await InternalAPI.Security.GetSessions();
twofactors = await InternalAPI.TwoFactor.GetOptions();
} catch (e) {
error = e.message;
} finally {
loading = false;
}
}
async function reload() {
try {
tokens = await InternalAPI.Security.GetSessions();
twofactors = await InternalAPI.TwoFactor.GetOptions();
} catch (e) {
error = e.message;
}
}
onMount(() => {
load();
});
async function revokeToken(id: string) {
try {
await InternalAPI.Security.RevokeSession(id);
await load();
} catch (e) {
error = e.message;
}
}
const typeToName = {
[TFAType.TOTP]: "TOTP",
[TFAType.WEBAUTHN]: "Security Key (WebAuthn)",
[TFAType.BACKUP_CODE]: "Backup-Code",
[TFAType.APP_ALLOW]: "App-Auth",
};
let addTwoFactorOpen = false;
function openAddTwoFactor() {
addTwoFactorOpen = true;
}
async function deleteTwoFactor(id: string) {
try {
await InternalAPI.TwoFactor.Delete(id);
await reload();
} catch (e) {
error = e.message;
}
}
let old_pw = "";
let new_pw = "";
let new_pw_repeat = "";
let change_password_success = false;
let change_password_error: string | undefined;
function changePassword() {
change_password_success = false;
change_password_error = undefined;
if (new_pw !== new_pw_repeat) {
change_password_error = "Passwords do not match";
return;
}
InternalAPI.Security.ChangePassword(old_pw, new_pw)
.then(() => {
change_password_error = undefined;
old_pw = "";
new_pw = "";
new_pw_repeat = "";
change_password_success = true;
})
.catch((e) => {
change_password_error = e.message;
});
}
</script>
<Loading {loading} {error}>
<Card size="xl">
<Heading tag="h5">Active Sessions</Heading>
<hr class="mb-6" />
<Table>
<TableHead>
<TableHeadCell>Browser</TableHeadCell>
<TableHeadCell class="w-full">IP</TableHeadCell>
<TableHeadCell class="material-icons-outlined w-20"
>delete</TableHeadCell
>
</TableHead>
<TableBody>
{#each tokens as token}
<TableBodyRow
class="bg-yellow-50"
color={token.isthis ? "custom" : "default"}
>
<TableBodyCell>{token.browser}</TableBodyCell>
<TableBodyCell>{token.ip}</TableBodyCell>
<TableBodyCell>
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<a
class="font-medium text-red-600 hover:underline dark:text-blue-500"
on:click={() => revokeToken(token.id)}
>
Revoke
</a>
</TableBodyCell>
</TableBodyRow>
{/each}
</TableBody>
</Table>
</Card>
<Card size="xl" class="mt-4">
<Heading tag="h5">Change Password</Heading>
<hr class="mb-6" />
{#if change_password_success}
<Alert color="green">Password changed successfully.</Alert>
{/if}
{#if change_password_error}
<Alert color="red">{change_password_error}</Alert>
{/if}
<div class="mb-6">
<Label for="oldPassword">Old Password</Label>
<Input type="password" id="oldPassword" bind:value={old_pw} />
</div>
<div class="mb-6">
<Label for="newPassword">New Password</Label>
<Input type="password" id="newPassword" bind:value={new_pw} />
</div>
<div class="mb-6">
<Label for="newPasswordRepeat">Repeat New Password</Label>
<Input
type="password"
id="newPasswordRepeat"
bind:value={new_pw_repeat}
/>
</div>
<Button class="mt-4" on:click={changePassword}>Change Password</Button>
</Card>
<Card size="xl" class="mt-4">
<Heading tag="h5">Two Factor Auth</Heading>
<hr class="mb-6" />
<Accordion>
{#each twofactors as tfa}
<AccordionItem>
<span slot="header">{tfa.name ?? typeToName[tfa.tfatype]}</span>
<div>
<Button
color="red"
class="mt-4"
on:click={() => deleteTwoFactor(tfa.id)}>Delete</Button
>
</div>
</AccordionItem>
{/each}
</Accordion>
<Button class="mt-4" on:click={openAddTwoFactor}>Add Option</Button>
</Card>
<AddTwoFactor on:reload={reload} bind:open={addTwoFactorOpen} />
<!-- <Card size="xl" class="mt-4">
<Heading tag="h5">Delete Account</Heading>
<hr class="mb-6" />
<div class="mb-6">
<Label for="password">Password</Label>
<Input type="password" id="password" />
</div>
<Button class="mt-4">Delete Account</Button>
</Card> -->
</Loading>