diff --git a/app/src/lib/auth/api.ts b/app/src/lib/auth/api.ts index 6554eb23..ccfaebd5 100644 --- a/app/src/lib/auth/api.ts +++ b/app/src/lib/auth/api.ts @@ -151,6 +151,56 @@ export async function validateSession(token: string): Promise { return res.json(); } +export async function changeEmail(token: string, newEmail: string): Promise { + const res = await fetch(`${API_BASE}/change-email`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ new_email: newEmail }), + }); + if (!res.ok) throw new Error(`change-email failed: ${res.status}`); +} + +export interface Setup2FAResponse { + secret: string; + qr_code: string; +} + +export async function setup2FA(token: string): Promise { + const res = await fetch(`${API_BASE}/2fa/setup`, { + method: 'POST', + headers: { Authorization: `Bearer ${token}` }, + }); + if (!res.ok) throw new Error(`2fa setup failed: ${res.status}`); + return res.json(); +} + +export async function enable2FA(token: string, code: string): Promise { + const res = await fetch(`${API_BASE}/2fa/enable`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ code }), + }); + if (!res.ok) throw new Error(`2fa enable failed: ${res.status}`); +} + +export async function disable2FA(token: string, code: string): Promise { + const res = await fetch(`${API_BASE}/2fa/disable`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ code }), + }); + if (!res.ok) throw new Error(`2fa disable failed: ${res.status}`); +} + export class TwoFactorRequiredError extends Error { constructor( public readonly username: string, diff --git a/app/src/lib/components/settings/account-settings.svelte b/app/src/lib/components/settings/account-settings.svelte new file mode 100644 index 00000000..affb2e4d --- /dev/null +++ b/app/src/lib/components/settings/account-settings.svelte @@ -0,0 +1,227 @@ + + +
+
+

Profile

+
+ + +
+
+ +
+ + +
+
+
+ +
+

Password

+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Two-factor authentication

+

Require an authenticator code at login

+
+ +
+ + {#if twoFactorStep === "enrolling"} +
+

Scan with your authenticator app, then enter the code

+ {#if qrCode} + 2FA QR code + {/if} + + {#snippet children({ cells })} + + {#each cells.slice(0, 3) as cell (cell)} + + {/each} + + + + {#each cells.slice(3, 6) as cell (cell)} + + {/each} + + {/snippet} + +
+ + +
+
+ {:else if twoFactorStep === "disabling"} +
+

Enter your current code to disable 2FA

+ + {#snippet children({ cells })} + + {#each cells.slice(0, 3) as cell (cell)} + + {/each} + + + + {#each cells.slice(3, 6) as cell (cell)} + + {/each} + + {/snippet} + +
+ + +
+
+ {/if} +
+
diff --git a/app/src/lib/components/settings/general-settings.svelte b/app/src/lib/components/settings/general-settings.svelte new file mode 100644 index 00000000..bbe69da5 --- /dev/null +++ b/app/src/lib/components/settings/general-settings.svelte @@ -0,0 +1 @@ +

No general settings configured.

diff --git a/app/src/lib/components/settings/settings-dialog.svelte b/app/src/lib/components/settings/settings-dialog.svelte new file mode 100644 index 00000000..a39c9f9b --- /dev/null +++ b/app/src/lib/components/settings/settings-dialog.svelte @@ -0,0 +1,55 @@ + + + settingsDialog.set(value)}> + +
+ +
+ {#if activeSection === "account"} + + {:else if activeSection === "general"} + + {:else if activeSection === "update"} + + {:else if activeSection === "logs"} + + {/if} +
+
+
+
diff --git a/app/src/lib/components/settings/settings-store.svelte.ts b/app/src/lib/components/settings/settings-store.svelte.ts new file mode 100644 index 00000000..807f8169 --- /dev/null +++ b/app/src/lib/components/settings/settings-store.svelte.ts @@ -0,0 +1,16 @@ +let open = $state(false); + +export const settingsDialog = { + get open() { + return open; + }, + show() { + open = true; + }, + hide() { + open = false; + }, + set(value: boolean) { + open = value; + }, +}; diff --git a/app/src/lib/components/settings/update-settings.svelte b/app/src/lib/components/settings/update-settings.svelte index c4df2faf..2301a0e5 100644 --- a/app/src/lib/components/settings/update-settings.svelte +++ b/app/src/lib/components/settings/update-settings.svelte @@ -2,6 +2,7 @@ import { onMount, onDestroy } from "svelte"; import * as Card from "$lib/components/ui/card/index.js"; import { Button } from "$lib/components/ui/button/index.js"; + import { Switch } from "$lib/components/ui/switch/index.js"; import { auth } from "$lib/auth/store.svelte"; import { getUpdateStatus, @@ -216,18 +217,15 @@ Available releases Select a version to update or downgrade -