218 lines
5.4 KiB
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>
|