diff --git a/apps/calendar/apps/web/src/lib/stores/auth.svelte.ts b/apps/calendar/apps/web/src/lib/stores/auth.svelte.ts index 8310c2494..5e9b97ec8 100644 --- a/apps/calendar/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/calendar/apps/web/src/lib/stores/auth.svelte.ts @@ -122,6 +122,29 @@ export const authStore = { /** * Check if passkeys are available in this browser */ + + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + isPasskeyAvailable(): boolean { const authService = getAuthService(); if (!authService) return false; diff --git a/apps/calendar/apps/web/src/routes/(auth)/login/+page.svelte b/apps/calendar/apps/web/src/routes/(auth)/login/+page.svelte index e55516535..3036c6425 100644 --- a/apps/calendar/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/calendar/apps/web/src/routes/(auth)/login/+page.svelte @@ -58,6 +58,8 @@ onResendVerification={handleResendVerification} passkeyAvailable={authStore.isPasskeyAvailable()} onSignInWithPasskey={() => authStore.signInWithPasskey()} + onVerifyTwoFactor={(code, trust) => authStore.verifyTwoFactor(code, trust)} + onVerifyBackupCode={(code) => authStore.verifyBackupCode(code)} {goto} successRedirect={redirectTo} registerPath="/register" diff --git a/apps/chat/apps/web/src/lib/stores/auth.svelte.ts b/apps/chat/apps/web/src/lib/stores/auth.svelte.ts index 27186ff81..6c9df46ea 100644 --- a/apps/chat/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/chat/apps/web/src/lib/stores/auth.svelte.ts @@ -122,6 +122,29 @@ export const authStore = { /** * Check if passkeys are available in this browser */ + + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + isPasskeyAvailable(): boolean { const authService = getAuthService(); if (!authService) return false; diff --git a/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte b/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte index 64aa778de..4b062c72c 100644 --- a/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte @@ -65,6 +65,8 @@ onResendVerification={handleResendVerification} passkeyAvailable={authStore.isPasskeyAvailable()} onSignInWithPasskey={() => authStore.signInWithPasskey()} + onVerifyTwoFactor={(code, trust) => authStore.verifyTwoFactor(code, trust)} + onVerifyBackupCode={(code) => authStore.verifyBackupCode(code)} {goto} successRedirect={redirectTo} registerPath="/register" diff --git a/apps/citycorners/apps/web/src/lib/stores/auth.svelte.ts b/apps/citycorners/apps/web/src/lib/stores/auth.svelte.ts index f0330d61e..c9af89ab0 100644 --- a/apps/citycorners/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/citycorners/apps/web/src/lib/stores/auth.svelte.ts @@ -105,6 +105,28 @@ export const authStore = { } }, + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + isPasskeyAvailable(): boolean { const authService = getAuthService(); if (!authService) return false; diff --git a/apps/citycorners/apps/web/src/routes/(auth)/login/+page.svelte b/apps/citycorners/apps/web/src/routes/(auth)/login/+page.svelte index 13427ff98..0fc36c24f 100644 --- a/apps/citycorners/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/citycorners/apps/web/src/routes/(auth)/login/+page.svelte @@ -49,6 +49,8 @@ onResendVerification={handleResendVerification} passkeyAvailable={authStore.isPasskeyAvailable()} onSignInWithPasskey={() => authStore.signInWithPasskey()} + onVerifyTwoFactor={(code, trust) => authStore.verifyTwoFactor(code, trust)} + onVerifyBackupCode={(code) => authStore.verifyBackupCode(code)} {goto} successRedirect={redirectTo} registerPath="/register" diff --git a/apps/clock/apps/web/src/lib/stores/auth.svelte.ts b/apps/clock/apps/web/src/lib/stores/auth.svelte.ts index 738cdbc29..7b426d977 100644 --- a/apps/clock/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/clock/apps/web/src/lib/stores/auth.svelte.ts @@ -122,6 +122,29 @@ export const authStore = { /** * Check if passkeys are available in this browser */ + + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + isPasskeyAvailable(): boolean { const authService = getAuthService(); if (!authService) return false; diff --git a/apps/clock/apps/web/src/routes/(auth)/login/+page.svelte b/apps/clock/apps/web/src/routes/(auth)/login/+page.svelte index d097d9ed5..6cab19920 100644 --- a/apps/clock/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/clock/apps/web/src/routes/(auth)/login/+page.svelte @@ -56,6 +56,8 @@ onResendVerification={handleResendVerification} passkeyAvailable={authStore.isPasskeyAvailable()} onSignInWithPasskey={() => authStore.signInWithPasskey()} + onVerifyTwoFactor={(code, trust) => authStore.verifyTwoFactor(code, trust)} + onVerifyBackupCode={(code) => authStore.verifyBackupCode(code)} {goto} successRedirect={redirectTo} registerPath="/register" diff --git a/apps/contacts/apps/web/src/lib/stores/auth.svelte.ts b/apps/contacts/apps/web/src/lib/stores/auth.svelte.ts index 8f7b80639..7a501c33a 100644 --- a/apps/contacts/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/contacts/apps/web/src/lib/stores/auth.svelte.ts @@ -122,6 +122,29 @@ export const authStore = { /** * Check if passkeys are available in this browser */ + + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + isPasskeyAvailable(): boolean { const authService = getAuthService(); if (!authService) return false; diff --git a/apps/contacts/apps/web/src/routes/(auth)/login/+page.svelte b/apps/contacts/apps/web/src/routes/(auth)/login/+page.svelte index 07ce2f8a6..6ad155be5 100644 --- a/apps/contacts/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/contacts/apps/web/src/routes/(auth)/login/+page.svelte @@ -55,6 +55,8 @@ onResendVerification={handleResendVerification} passkeyAvailable={authStore.isPasskeyAvailable()} onSignInWithPasskey={() => authStore.signInWithPasskey()} + onVerifyTwoFactor={(code, trust) => authStore.verifyTwoFactor(code, trust)} + onVerifyBackupCode={(code) => authStore.verifyBackupCode(code)} {goto} successRedirect={redirectTo} registerPath="/register" diff --git a/apps/context/apps/web/src/lib/stores/auth.svelte.ts b/apps/context/apps/web/src/lib/stores/auth.svelte.ts index 7478d546f..1e649a7ee 100644 --- a/apps/context/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/context/apps/web/src/lib/stores/auth.svelte.ts @@ -106,6 +106,28 @@ export const authStore = { } }, + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available on server' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + isPasskeyAvailable(): boolean { const authService = getAuthService(); if (!authService) return false; diff --git a/apps/context/apps/web/src/routes/(auth)/login/+page.svelte b/apps/context/apps/web/src/routes/(auth)/login/+page.svelte index 99897720d..2512d8b7e 100644 --- a/apps/context/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/context/apps/web/src/routes/(auth)/login/+page.svelte @@ -50,6 +50,8 @@ onResendVerification={handleResendVerification} passkeyAvailable={authStore.isPasskeyAvailable()} onSignInWithPasskey={() => authStore.signInWithPasskey()} + onVerifyTwoFactor={(code, trust) => authStore.verifyTwoFactor(code, trust)} + onVerifyBackupCode={(code) => authStore.verifyBackupCode(code)} {goto} successRedirect={redirectTo} registerPath="/register" diff --git a/apps/manacore/apps/web/src/lib/stores/auth.svelte.ts b/apps/manacore/apps/web/src/lib/stores/auth.svelte.ts index 5f159f77f..f0c50b504 100644 --- a/apps/manacore/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/manacore/apps/web/src/lib/stores/auth.svelte.ts @@ -138,6 +138,46 @@ export const authStore = { } }, + async enableTwoFactor(password: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available' }; + return authService.enableTwoFactor(password); + }, + + async disableTwoFactor(password: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available' }; + return authService.disableTwoFactor(password); + }, + + async verifyTwoFactor(code: string, trustDevice?: boolean) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available' }; + const result = await authService.verifyTwoFactor(code, trustDevice); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async verifyBackupCode(code: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available' }; + const result = await authService.verifyBackupCode(code); + if (result.success) { + const userData = await authService.getUserFromToken(); + user = userData; + } + return result; + }, + + async generateBackupCodes(password: string) { + const authService = getAuthService(); + if (!authService) return { success: false, error: 'Auth not available' }; + return authService.generateBackupCodes(password); + }, + async registerPasskey(friendlyName?: string) { const authService = getAuthService(); if (!authService) return { success: false, error: 'Auth not available' }; diff --git a/apps/manacore/apps/web/src/routes/(app)/settings/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/settings/+page.svelte index 99d87441c..d351fe3df 100644 --- a/apps/manacore/apps/web/src/routes/(app)/settings/+page.svelte +++ b/apps/manacore/apps/web/src/routes/(app)/settings/+page.svelte @@ -1,7 +1,7 @@ + +
{t.disableConfirmText}
+ {/if} + + {#if error} + + {/if} + + + {:else if view === 'setup'} +{t.setupStep1}
+ + {#if totpURI} +{t.manualEntryLabel}
+{extractSecret(totpURI)}
+
+ {t.setupStep2}
+{t.backupCodesWarning}
+ +{code}
+ {/each}
+ {t.backupCodesWarning}
+ +{code}
+ {/each}
+