diff --git a/frontend/src/components/dashboard/SecurityContent.svelte b/frontend/src/components/dashboard/SecurityContent.svelte index 8c95447..7d64527 100644 --- a/frontend/src/components/dashboard/SecurityContent.svelte +++ b/frontend/src/components/dashboard/SecurityContent.svelte @@ -1,6 +1,5 @@
- {#if loading} -
{$_('common.loading')}
- {:else} + passkeyCount = count} + /> + + totpEnabled = enabled} + /> + + hasPassword = has} + onReauthRequired={handleReauthRequired} + /> + + {#if ssoProviders.length > 0}
-

{$_('security.passkeys')}

+

{$_('oauth.sso.linkedAccounts')}

- {#if !passkeysLoading} - {#if passkeys.length > 0} -
    - {#each passkeys as passkey} -
  • - {#if editingPasskeyId === passkey.id} -
    - - - -
    - {:else} -
    - {passkey.friendlyName || $_('security.unnamedPasskey')} - - {$_('security.added')} {formatDate(passkey.createdAt)} - {#if passkey.lastUsed} - - {$_('security.lastUsed')} {formatDate(passkey.lastUsed)} - {/if} - -
    -
    - - {#if hasPassword || passkeys.length > 1} - - {/if} -
    - {/if} + {#if linkedAccountsLoading} +
    {$_('common.loading')}
    + {:else} + {#if linkedAccounts.length > 0} +
      + {#each linkedAccounts as account} +
    • +
      + {account.provider_name} + {account.provider_username} + {$_('oauth.sso.linkedAt')} {formatDate(account.created_at)} +
      +
    • {/each}
    {:else} -
    {$_('security.noPasskeys')}
    +

    {$_('oauth.sso.noLinkedAccounts')}

    {/if} -
    - - +
    +

    {$_('oauth.sso.linkNewAccount')}

    +
    + {#each ssoProviders as provider} + {@const isLinked = linkedAccounts.some(a => a.provider === provider.provider)} + + {/each} +
    - {/if}
+ {/if} + {#if hasMfa}
-

{$_('security.totp')}

- - {#if totpSetup.step === 'idle'} - {#if totpEnabled} -
{$_('security.totpEnabled')}
- - {#if !showDisableForm && !showRegenForm} -
- - -
- {/if} - - {#if showRegenForm} -
-

{$_('security.regenerateBackupCodes')}

-

{$_('security.regenerateConfirm')}

-
- - -
-
- - -
-
- - -
-
- {/if} - - {#if showDisableForm} -
-

{$_('security.disableTotp')}

-

{$_('security.disableTotpWarning')}

-
- - -
-
- - -
-
- - -
-
- {/if} - {:else} -
{$_('security.totpDisabled')}
- - {/if} - {:else if totpSetup.step === 'qr'} - {@const qrData = totpSetup as TotpQr} -
-

{$_('security.totpSetupInstructions')}

-
- TOTP QR Code +

{$_('security.appCompatibility')}

+

{$_('security.legacyLoginDescription')}

+ + {#if !legacyLoginLoading} +
+
+ {$_('security.legacyLogin')} + + {#if allowLegacyLogin} + {$_('security.legacyLoginOn')} + {:else} + {$_('security.legacyLoginOff')} + {/if} +
-
- {$_('security.cantScan')} - {qrData.totpUri.split('secret=')[1]?.split('&')[0] || ''} -
- -
- {:else if totpSetup.step === 'verify'} - {@const verifyData = totpSetup} -
-

{$_('security.totpCodePlaceholder')}

-
- -
- - -
-
+
- {:else if totpSetup.step === 'backup'} -
-

{$_('security.backupCodes')}

-

{$_('security.backupCodesDescription')}

-
- {#each totpSetup.backupCodes as code} - {code} - {/each} -
-
- - + + {#if totpEnabled && allowLegacyLogin} +
+ {$_('security.legacyLoginWarning')}
+ {/if} + +
+ {$_('security.legacyAppsTitle')} +

{$_('security.legacyAppsDescription')}

{/if}
+ {/if} -
-

{$_('security.password')}

- {#if !passwordLoading} - {#if hasPassword} -
{$_('security.passwordStatus')}
- - {#if !showChangePasswordForm && !showRemovePasswordForm} -
- - {#if passkeys.length > 0} - - {/if} -
- {/if} - - {#if showChangePasswordForm} -
-

{$_('security.changePassword')}

-
- +
+

{$_('security.trustedDevices')}

+

{$_('security.trustedDevicesDescription')}

+ + {#if trustedDevicesLoading} +
{$_('common.loading')}
+ {:else if trustedDevices.length === 0} +

{$_('trustedDevices.noDevices')}

+

{$_('trustedDevices.noDevicesHint')}

+ {:else} +
+ {#each trustedDevices as device} +
+
+ {#if editingDeviceId === device.id} -
-
- - -
-
- - -
-
- - -
- - {/if} - - {#if showRemovePasswordForm} -
-

{$_('security.removePasswordWarning')}

-
- + +
+ {:else} + {device.friendlyName || parseUserAgent(device.userAgent)} + - -
+ {/if}
- {/if} - {:else} -
{$_('security.noPassword')}
- - {#if !showSetPasswordForm} - - {:else} -
-

{$_('security.setPassword')}

-
- - -
-
- - -
-
- - -
-
- {/if} - {/if} - {/if} -
- - {#if ssoProviders.length > 0} -
-

{$_('oauth.sso.linkedAccounts')}

- {#if linkedAccountsLoading} -
{$_('common.loading')}
- {:else} - {#if linkedAccounts.length > 0} -
    - {#each linkedAccounts as account} -
  • -
    - {account.provider_name} - {account.provider_username} - {$_('oauth.sso.linkedAt')} {formatDate(account.created_at)} -
    - -
  • - {/each} -
- {:else} -

{$_('oauth.sso.noLinkedAccounts')}

- {/if} - -
-

{$_('oauth.sso.linkNewAccount')}

-
- {#each ssoProviders as provider} - {@const isLinked = linkedAccounts.some(a => a.provider === provider.provider)} - - {/each} + + {/if}
-
- {/if} -
- {/if} - - {#if hasMfa} -
-

{$_('security.appCompatibility')}

-

{$_('security.legacyLoginDescription')}

- {#if !legacyLoginLoading} -
-
- {$_('security.legacyLogin')} - - {#if allowLegacyLogin} - {$_('security.legacyLoginOn')} - {:else} - {$_('security.legacyLoginOff')} - {/if} - -
-
- - {#if totpEnabled && allowLegacyLogin} -
- {$_('security.legacyLoginWarning')} -
- {/if} - -
- {$_('security.legacyAppsTitle')} -

{$_('security.legacyAppsDescription')}

-
- {/if} -
+ {/each} +
{/if} - -
-

{$_('security.trustedDevices')}

-

{$_('security.trustedDevicesDescription')}

- - {#if trustedDevicesLoading} -
{$_('common.loading')}
- {:else if trustedDevices.length === 0} -

{$_('trustedDevices.noDevices')}

-

{$_('trustedDevices.noDevicesHint')}

- {:else} -
- {#each trustedDevices as device} -
-
- {#if editingDeviceId === device.id} - -
- - -
- {:else} - {device.friendlyName || parseUserAgent(device.userAgent)} - - {/if} -
- -
- {#if device.userAgent} - {parseUserAgent(device.userAgent)} - {/if} - {#if device.trustedAt} - {$_('trustedDevices.trustedSince')} {formatDate(device.trustedAt)} - {/if} - {$_('trustedDevices.lastSeen')} {formatDate(device.lastSeenAt)} - {#if device.trustedUntil} - {@const daysRemaining = getDaysRemaining(device.trustedUntil)} - - {#if daysRemaining <= 0} - {$_('trustedDevices.expired')} - {:else if daysRemaining === 1} - {$_('trustedDevices.tomorrow')} - {:else} - {$_('trustedDevices.inDays', { values: { days: daysRemaining } })} - {/if} - - {/if} -
- - -
- {/each} -
- {/if} -
- {/if} +