import type { LoginState } from "@hibas123/openauth-internalapi"; import { derived, get, writable } from "svelte/store"; import InternalAPI from "../../helper/api"; import sha from "../../helper/sha512"; interface LocalLoginState extends LoginState { loading: boolean; error?: string; username?: string; } class LoginStore { state = writable({ username: undefined, password: false, passwordSalt: undefined, requireTwoFactor: [], success: false, loading: true, error: undefined }) isFinished = derived(this.state, $state => $state.success); constructor() { this.state.subscribe((state) => { if (state.success) { setTimeout(() => { this.finish(); }, 2000); } }) this.getState(); } setLoading(loading: boolean) { this.state.update(current => ({ ...current, loading, error: loading ? undefined : current.error, })); } setError(error: string) { this.state.update(current => ({ ...current, error, })); } async getState() { try { this.setLoading(true); let state = await InternalAPI.Login.GetState(); this.state.update(current => ({ ...current, ...state, })); } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async setUsername(username: string) { try { this.setLoading(true); let state = await InternalAPI.Login.Start(username); this.state.update(current => ({ ...current, ...state, username })); } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async setPassword(password: string) { try { this.setLoading(true); const date = new Date().valueOf(); let salt = get(this.state).passwordSalt let pw = sha(sha(salt + password) + date.toString()); let state = await InternalAPI.Login.UsePassword(pw, date); this.state.update(current => ({ ...current, ...state, })); } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async useTOTP(id: string, code: string) { try { this.setLoading(true); let state = await InternalAPI.Login.UseTOTP(id, code); this.state.update(current => ({ ...current, ...state, })); } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async useBackupCode(id: string, code: string) { try { this.setLoading(true); let state = await InternalAPI.Login.UseBackupCode(id, code); this.state.update(current => ({ ...current, ...state, })); } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async getWebAuthnChallenge(id: string) { try { this.setLoading(true); let challenge = await InternalAPI.Login.GetWebAuthnChallenge(id); return challenge; } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async useWebAuthn(id: string, response: any) { try { this.setLoading(true); let state = await InternalAPI.Login.UseWebAuthn(id, JSON.stringify(response)); this.state.update(current => ({ ...current, ...state, })); } catch (err) { this.setError(err.message); } finally { this.setLoading(false); } } async finish() { let url = new URL(window.location.href); let state = url.searchParams.get("state"); let red = "/"; if (state) { let base64 = url.searchParams.get("base64"); if (base64) red = atob(state); else red = state; } setTimeout(() => (window.location.href = red), 200); } } const loginState = new LoginStore(); export default loginState;