mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-09 03:18:18 +00:00
refac
This commit is contained in:
parent
4b9d31b390
commit
5b0f53e827
3 changed files with 107 additions and 29 deletions
78
src/lib/components/auth/MfaManagement.svelte
Normal file
78
src/lib/components/auth/MfaManagement.svelte
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<script context="module" lang="ts">
|
||||
import type { MfaChallenge } from '$lib/apis/auths/mfa';
|
||||
export type MfaManagementFlow =
|
||||
| { challenge: MfaChallenge }
|
||||
| { code: string; recovery: boolean; token: string };
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { mfaRequest } from '$lib/apis/auths/mfa';
|
||||
import { user } from '$lib/stores';
|
||||
import MfaChallengeForm from './MfaChallenge.svelte';
|
||||
import MfaRecoveryCodes from './MfaRecoveryCodes.svelte';
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
|
||||
const i18n: any = getContext('i18n');
|
||||
export let flow: MfaManagementFlow;
|
||||
export let onClose: () => void;
|
||||
let codes: string[] = [];
|
||||
let error = '';
|
||||
let reauthenticate = false;
|
||||
|
||||
const signIn = async () => {
|
||||
localStorage.removeItem('token');
|
||||
user.set(undefined);
|
||||
await goto('/auth?state=logout&form=signin', { replaceState: true });
|
||||
onClose();
|
||||
};
|
||||
|
||||
const cancel = async () => {
|
||||
if (!$user) await signIn();
|
||||
else onClose();
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
if ('challenge' in flow) return;
|
||||
try {
|
||||
const response = await mfaRequest(
|
||||
'recovery/codes',
|
||||
{ code: flow.code, recovery: flow.recovery },
|
||||
flow.token
|
||||
);
|
||||
codes = response.recovery_codes;
|
||||
} catch (e) {
|
||||
reauthenticate = e instanceof Error && e.message === 'reauthentication_required';
|
||||
error = reauthenticate
|
||||
? $i18n.t('Sign in again before changing your authenticator settings.')
|
||||
: e instanceof Error
|
||||
? e.message
|
||||
: String(e);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<main id="main-content" class="flex min-h-screen items-center justify-center px-5 py-10">
|
||||
<div class="w-full max-w-sm">
|
||||
{#if 'challenge' in flow}
|
||||
<MfaChallengeForm challenge={flow.challenge} onComplete={signIn} onCancel={cancel} />
|
||||
{:else if codes.length}
|
||||
<MfaRecoveryCodes {codes} onContinue={signIn} />
|
||||
{:else if error}
|
||||
<p role="alert" class="text-xs text-red-500">{error}</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-3 text-xs text-gray-500 hover:text-gray-700 dark:hover:text-gray-200"
|
||||
on:click={reauthenticate ? signIn : cancel}
|
||||
>
|
||||
{reauthenticate || !$user ? $i18n.t('Sign in again') : $i18n.t('Back')}
|
||||
</button>
|
||||
{:else}
|
||||
<div role="status" class="flex items-center justify-center gap-2 text-xs text-gray-500">
|
||||
<Spinner />
|
||||
{$i18n.t('Loading...')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
|
|
@ -1,13 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { onMount, getContext } from 'svelte';
|
||||
import { mfaRequest, type MfaChallenge } from '$lib/apis/auths/mfa';
|
||||
import MfaChallengeForm from '$lib/components/auth/MfaChallenge.svelte';
|
||||
import MfaRecoveryCodes from '$lib/components/auth/MfaRecoveryCodes.svelte';
|
||||
import { mfaRequest } from '$lib/apis/auths/mfa';
|
||||
import type { MfaManagementFlow } from '$lib/components/auth/MfaManagement.svelte';
|
||||
const i18n: any = getContext('i18n');
|
||||
const showMfaManagement = getContext<(flow: MfaManagementFlow) => void>('showMfaManagement');
|
||||
let status: { enabled: boolean; required: boolean; recovery_codes_remaining: number } | null =
|
||||
null;
|
||||
let challenge: MfaChallenge | null = null;
|
||||
let codes: string[] = [];
|
||||
let code = '';
|
||||
let recovery = false;
|
||||
let busy = false;
|
||||
|
|
@ -28,17 +26,18 @@
|
|||
window.location.href = '/auth?state=logout&form=signin';
|
||||
};
|
||||
const manage = async (replace: boolean) => {
|
||||
if (busy) return;
|
||||
if (!replace) {
|
||||
showMfaManagement({ code, recovery, token: localStorage.token });
|
||||
code = '';
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
error = '';
|
||||
try {
|
||||
const response = await mfaRequest(
|
||||
replace ? 'replace' : 'recovery/codes',
|
||||
{ code, recovery },
|
||||
localStorage.token
|
||||
);
|
||||
const response = await mfaRequest('replace', { code, recovery }, localStorage.token);
|
||||
code = '';
|
||||
if (replace) challenge = response;
|
||||
else codes = response.recovery_codes;
|
||||
showMfaManagement({ challenge: response });
|
||||
} catch (e) {
|
||||
reauthenticate = e instanceof Error && e.message === 'reauthentication_required';
|
||||
error = reauthenticate
|
||||
|
|
@ -53,19 +52,7 @@
|
|||
</script>
|
||||
|
||||
<div class="space-y-2.5 text-xs">
|
||||
{#if codes.length}
|
||||
<div class="w-full sm:max-w-md"><MfaRecoveryCodes {codes} onContinue={signIn} /></div>
|
||||
{:else if challenge}
|
||||
<div class="w-full sm:max-w-md">
|
||||
<MfaChallengeForm
|
||||
{challenge}
|
||||
onComplete={signIn}
|
||||
onCancel={() => {
|
||||
challenge = null;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else if status}
|
||||
{#if status}
|
||||
<div class="flex items-center justify-between gap-2.5">
|
||||
<span class="text-gray-600 dark:text-gray-400"
|
||||
>{status.enabled
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@
|
|||
import AppSidebar from '$lib/components/app/AppSidebar.svelte';
|
||||
import SyncStatsModal from '$lib/components/chat/Settings/SyncStatsModal.svelte';
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
import MfaManagement from '$lib/components/auth/MfaManagement.svelte';
|
||||
import { getOutputText } from '$lib/components/chat/Messages/structuredOutput';
|
||||
import { getUserSettings } from '$lib/apis/users';
|
||||
import dayjs from 'dayjs';
|
||||
|
|
@ -101,13 +102,22 @@
|
|||
|
||||
// handle frontend updates (https://svelte.dev/docs/kit/configuration#version)
|
||||
beforeNavigate(async ({ willUnload, to }) => {
|
||||
if (updated.current && !willUnload && to?.url) {
|
||||
if (updated.current && !mfaManagement && !willUnload && to?.url) {
|
||||
await unregisterServiceWorkers();
|
||||
location.href = to.url.href;
|
||||
}
|
||||
});
|
||||
|
||||
setContext('i18n', i18n);
|
||||
/** @type {import('$lib/components/auth/MfaManagement.svelte').MfaManagementFlow | null} */
|
||||
let mfaManagement = null;
|
||||
setContext(
|
||||
'showMfaManagement',
|
||||
/** @param {import('$lib/components/auth/MfaManagement.svelte').MfaManagementFlow} flow */
|
||||
(flow) => {
|
||||
mfaManagement = flow;
|
||||
}
|
||||
);
|
||||
|
||||
const bc = new BroadcastChannel('active-tab-channel');
|
||||
|
||||
|
|
@ -208,8 +218,9 @@
|
|||
|
||||
if (version !== null || deploymentId !== null) {
|
||||
if (
|
||||
($WEBUI_VERSION !== null && version !== $WEBUI_VERSION) ||
|
||||
($WEBUI_DEPLOYMENT_ID !== null && deploymentId !== $WEBUI_DEPLOYMENT_ID)
|
||||
!mfaManagement &&
|
||||
(($WEBUI_VERSION !== null && version !== $WEBUI_VERSION) ||
|
||||
($WEBUI_DEPLOYMENT_ID !== null && deploymentId !== $WEBUI_DEPLOYMENT_ID))
|
||||
) {
|
||||
await unregisterServiceWorkers();
|
||||
location.href = location.href;
|
||||
|
|
@ -1465,7 +1476,9 @@
|
|||
{/if}
|
||||
|
||||
{#if loaded}
|
||||
{#if $isApp}
|
||||
{#if mfaManagement}
|
||||
<MfaManagement flow={mfaManagement} onClose={() => (mfaManagement = null)} />
|
||||
{:else if $isApp}
|
||||
<div class="flex flex-row h-screen">
|
||||
<AppSidebar />
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue