2026-01-24 22:59:20 +00:00
|
|
|
<template>
|
2026-02-17 19:42:59 +00:00
|
|
|
<div class="min-h-screen flex items-center justify-center p-4 relative z-10 login-fly-perspective">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="w-full max-w-md relative z-20">
|
2026-02-17 19:42:59 +00:00
|
|
|
<!-- Login Card - flies towards user on success -->
|
2026-02-17 19:19:54 +00:00
|
|
|
<div
|
2026-02-17 19:42:59 +00:00
|
|
|
class="glass-card p-8 pt-20 relative login-card overflow-visible"
|
|
|
|
|
:class="{ 'login-fly-towards': whooshAway }"
|
2026-02-17 19:19:54 +00:00
|
|
|
>
|
2026-01-24 22:59:20 +00:00
|
|
|
<!-- Logo - half in, half out of container -->
|
|
|
|
|
<div class="absolute -top-10 left-1/2 -translate-x-1/2 z-10">
|
2026-02-18 08:18:14 +00:00
|
|
|
<div class="logo-gradient-border w-20 h-20">
|
|
|
|
|
<AnimatedLogo no-border fit />
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Title -->
|
|
|
|
|
<h1 class="text-2xl font-semibold text-white/96 text-center mb-8 drop-shadow-[0_2px_6px_rgba(0,0,0,0.4)]">
|
2026-03-29 17:15:56 +01:00
|
|
|
<span v-if="isCheckingSetup"> </span>
|
|
|
|
|
<span v-else-if="isSetupMode && !isSetup">{{ t('login.setupTitle') }}</span>
|
2026-03-11 13:45:59 +00:00
|
|
|
<span v-else>{{ t('login.title') }}</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</h1>
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
<!-- Server Startup Progress -->
|
2026-03-11 13:04:31 +00:00
|
|
|
<div v-if="!serverReady" class="mb-6" role="status" aria-live="polite">
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
<div class="flex items-center justify-center gap-2 mb-3">
|
2026-03-11 13:04:31 +00:00
|
|
|
<svg class="animate-spin h-4 w-4 text-orange-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
|
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
|
|
|
</svg>
|
2026-03-11 13:45:59 +00:00
|
|
|
<span class="text-sm text-white/60">{{ t('login.serverStarting') }}</span>
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
</div>
|
|
|
|
|
<div class="startup-progress-track">
|
|
|
|
|
<div class="startup-progress-bar" :style="{ width: startupProgress + '%' }"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
<!-- Error Message -->
|
2026-03-11 13:04:31 +00:00
|
|
|
<div v-if="error" role="alert" class="mb-4 p-3 bg-red-500/20 border border-red-500/40 rounded-lg text-red-200 text-sm">
|
2026-01-24 22:59:20 +00:00
|
|
|
{{ error }}
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-29 17:15:56 +01:00
|
|
|
<!-- Checking setup state -->
|
|
|
|
|
<div v-if="isCheckingSetup" class="flex items-center justify-center py-8">
|
|
|
|
|
<svg class="animate-spin h-6 w-6 text-white/40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
|
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
|
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
<!-- Setup Mode: Password Setup -->
|
2026-03-29 17:15:56 +01:00
|
|
|
<template v-else-if="isSetupMode && !isSetup">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="mb-4 p-4 bg-white/5 border border-white/10 rounded-lg text-white/80 text-sm">
|
|
|
|
|
<p class="mb-2">Create a password to secure your Archipelago node.</p>
|
|
|
|
|
<p class="text-white/60 text-xs">This password will be required to access your node.</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="mb-4">
|
2026-03-11 13:04:31 +00:00
|
|
|
<label for="setup-password" class="block text-sm font-medium text-white/80 mb-2">
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.password') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</label>
|
|
|
|
|
<input
|
2026-03-11 13:04:31 +00:00
|
|
|
id="setup-password"
|
2026-01-24 22:59:20 +00:00
|
|
|
v-model="password"
|
|
|
|
|
type="password"
|
2026-03-29 17:15:56 +01:00
|
|
|
autocomplete="new-password"
|
|
|
|
|
data-form-type="other"
|
2026-01-24 22:59:20 +00:00
|
|
|
class="w-full px-4 py-3 bg-transparent border border-white/20 rounded-lg text-white placeholder-white/40 focus:outline-none focus:border-white/40 focus:ring-1 focus:ring-white/20 transition-colors"
|
2026-03-11 13:45:59 +00:00
|
|
|
:placeholder="t('login.enterPasswordSetup')"
|
2026-03-28 23:41:40 +00:00
|
|
|
@keydown.enter="handleSetupWithSound"
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
:disabled="loading || formDisabled"
|
2026-01-24 22:59:20 +00:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="mb-6">
|
2026-03-11 13:04:31 +00:00
|
|
|
<label for="setup-confirm-password" class="block text-sm font-medium text-white/80 mb-2">
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.confirmPassword') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</label>
|
|
|
|
|
<input
|
2026-03-11 13:04:31 +00:00
|
|
|
id="setup-confirm-password"
|
2026-01-24 22:59:20 +00:00
|
|
|
v-model="confirmPassword"
|
|
|
|
|
type="password"
|
2026-03-29 17:15:56 +01:00
|
|
|
autocomplete="new-password"
|
|
|
|
|
data-form-type="other"
|
2026-01-24 22:59:20 +00:00
|
|
|
class="w-full px-4 py-3 bg-transparent border border-white/20 rounded-lg text-white placeholder-white/40 focus:outline-none focus:border-white/40 focus:ring-1 focus:ring-white/20 transition-colors"
|
2026-03-11 13:45:59 +00:00
|
|
|
:placeholder="t('login.confirmPasswordPlaceholder')"
|
2026-03-28 23:41:40 +00:00
|
|
|
@keydown.enter="handleSetupWithSound"
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
:disabled="loading || formDisabled"
|
2026-01-24 22:59:20 +00:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button
|
2026-02-18 10:35:04 +00:00
|
|
|
@click="handleSetupWithSound"
|
2026-03-11 13:04:31 +00:00
|
|
|
:disabled="loading || formDisabled || !password || password.length < 8 || password !== confirmPassword"
|
2026-01-24 22:59:20 +00:00
|
|
|
class="w-full glass-button px-6 py-3 rounded-lg font-medium transition-all hover:bg-black/70 hover:border-white/30 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
<span v-if="!loading">{{ t('login.setupButton') }}</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
<span v-else class="flex items-center justify-center">
|
|
|
|
|
<svg class="animate-spin h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
|
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
|
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
|
|
|
</svg>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.settingUp') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
</template>
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
<!-- TOTP Verification Step -->
|
|
|
|
|
<template v-else-if="requiresTotp">
|
|
|
|
|
<div class="mb-6 text-center">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-12 h-12 mx-auto mb-3 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z" />
|
|
|
|
|
</svg>
|
2026-03-11 13:45:59 +00:00
|
|
|
<p class="text-white/80 text-sm mb-1">{{ t('login.twoFactorTitle') }}</p>
|
|
|
|
|
<p class="text-white/50 text-xs">{{ t('login.totpInstruction') }}</p>
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="mb-4">
|
|
|
|
|
<input
|
|
|
|
|
ref="totpInputRef"
|
|
|
|
|
v-model="totpCode"
|
|
|
|
|
type="text"
|
|
|
|
|
inputmode="numeric"
|
|
|
|
|
pattern="[0-9]*"
|
|
|
|
|
maxlength="8"
|
|
|
|
|
autocomplete="one-time-code"
|
2026-03-11 13:45:59 +00:00
|
|
|
:aria-label="t('login.totpLabel')"
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
class="w-full px-4 py-3 bg-transparent border border-white/20 rounded-lg text-white text-center text-2xl tracking-[0.5em] placeholder-white/40 focus:outline-none focus:border-orange-400/60 focus:ring-1 focus:ring-orange-400/30 transition-colors"
|
|
|
|
|
:placeholder="useBackupCode ? 'XXXX-XXXX' : '000000'"
|
|
|
|
|
@keyup.enter="handleTotpVerify"
|
|
|
|
|
:disabled="loading"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
@click="handleTotpVerify"
|
|
|
|
|
:disabled="loading || !totpCode"
|
|
|
|
|
class="w-full glass-button px-6 py-3 rounded-lg font-medium transition-all hover:bg-black/70 hover:border-white/30 disabled:opacity-50 disabled:cursor-not-allowed mb-3"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
<span v-if="!loading">{{ t('login.verifyButton') }}</span>
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
<span v-else class="flex items-center justify-center">
|
|
|
|
|
<svg class="animate-spin h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
|
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
|
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
|
|
|
</svg>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.verifying') }}
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
@click="useBackupCode = !useBackupCode; totpCode = ''"
|
|
|
|
|
class="w-full text-white/50 text-sm hover:text-white/70 transition-colors py-2"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ useBackupCode ? t('login.useAuthCode') : t('login.useBackupCode') }}
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
</button>
|
|
|
|
|
</template>
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
<!-- Normal Login Mode -->
|
|
|
|
|
<template v-else>
|
|
|
|
|
<div class="mb-6">
|
2026-03-11 13:04:31 +00:00
|
|
|
<label for="login-password" class="block text-sm font-medium text-white/80 mb-2">
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.password') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</label>
|
|
|
|
|
<input
|
2026-03-11 13:04:31 +00:00
|
|
|
id="login-password"
|
2026-01-24 22:59:20 +00:00
|
|
|
v-model="password"
|
|
|
|
|
type="password"
|
2026-03-29 17:15:56 +01:00
|
|
|
autocomplete="current-password"
|
|
|
|
|
data-form-type="other"
|
2026-01-24 22:59:20 +00:00
|
|
|
class="w-full px-4 py-3 bg-transparent border border-white/20 rounded-lg text-white placeholder-white/40 focus:outline-none focus:border-white/40 focus:ring-1 focus:ring-white/20 transition-colors"
|
2026-03-11 13:45:59 +00:00
|
|
|
:placeholder="t('login.enterPasswordPlaceholder')"
|
2026-03-28 23:41:40 +00:00
|
|
|
@keydown.enter="handleLoginWithSound"
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
:disabled="loading || formDisabled"
|
2026-01-24 22:59:20 +00:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button
|
2026-02-18 10:35:04 +00:00
|
|
|
@click="handleLoginWithSound"
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
:disabled="loading || formDisabled || !password"
|
2026-01-24 22:59:20 +00:00
|
|
|
class="w-full glass-button px-6 py-3 rounded-lg font-medium transition-all hover:bg-black/70 hover:border-white/30 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
<span v-if="!loading">{{ t('login.loginButton') }}</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
<span v-else class="flex items-center justify-center">
|
|
|
|
|
<svg class="animate-spin h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
|
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
|
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
|
|
|
</svg>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.loggingIn') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Footer Links -->
|
2026-03-11 13:04:31 +00:00
|
|
|
<div class="mt-6 text-center text-sm text-white/40">
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.recoveryNote') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-02 08:34:13 +00:00
|
|
|
<!-- Replay Intro / Restart Onboarding - Bottom of Page -->
|
|
|
|
|
<div class="mt-8 text-center flex items-center justify-center gap-4">
|
2026-01-24 22:59:20 +00:00
|
|
|
<button
|
|
|
|
|
@click="replayIntro"
|
|
|
|
|
class="text-xs text-white/50 hover:text-white/70 transition-colors underline-offset-2 hover:underline"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('login.replayIntro') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</button>
|
2026-03-02 08:34:13 +00:00
|
|
|
<span class="text-white/30">|</span>
|
|
|
|
|
<button
|
|
|
|
|
@click="restartOnboarding"
|
|
|
|
|
:disabled="isResettingOnboarding"
|
|
|
|
|
class="text-xs text-white/50 hover:text-white/70 transition-colors underline-offset-2 hover:underline disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ isResettingOnboarding ? t('login.resetting') : t('login.onboarding') }}
|
2026-03-02 08:34:13 +00:00
|
|
|
</button>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-03-01 18:07:35 +00:00
|
|
|
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
2026-03-16 12:58:35 +00:00
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
import { isLocalRedirect } from '../router'
|
2026-03-11 13:45:59 +00:00
|
|
|
import { useI18n } from 'vue-i18n'
|
2026-02-18 08:18:14 +00:00
|
|
|
import AnimatedLogo from '@/components/AnimatedLogo.vue'
|
2026-01-24 22:59:20 +00:00
|
|
|
import { useAppStore } from '../stores/app'
|
2026-03-11 13:45:59 +00:00
|
|
|
|
|
|
|
|
const { t } = useI18n()
|
2026-02-17 19:19:54 +00:00
|
|
|
import { useLoginTransitionStore } from '../stores/loginTransition'
|
2026-01-24 22:59:20 +00:00
|
|
|
import { rpcClient } from '../api/rpc-client'
|
2026-03-01 17:53:18 +00:00
|
|
|
import { resumeAudioContext, startSynthwave, stopSynthwave, playLoginSuccessWhoosh, playPop } from '@/composables/useLoginSounds'
|
2026-01-24 22:59:20 +00:00
|
|
|
|
|
|
|
|
const router = useRouter()
|
2026-03-16 12:58:35 +00:00
|
|
|
const currentRoute = useRoute()
|
|
|
|
|
|
|
|
|
|
/** After login, redirect to the intended page or default to home */
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
const loginRedirectTo = computed(() => {
|
|
|
|
|
const redirect = currentRoute.query.redirect as string
|
|
|
|
|
if (redirect && isLocalRedirect(redirect)) return redirect
|
|
|
|
|
return '/dashboard'
|
|
|
|
|
})
|
2026-01-24 22:59:20 +00:00
|
|
|
const store = useAppStore()
|
2026-02-17 19:19:54 +00:00
|
|
|
const loginTransition = useLoginTransitionStore()
|
2026-01-24 22:59:20 +00:00
|
|
|
|
|
|
|
|
const password = ref('')
|
|
|
|
|
const confirmPassword = ref('')
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
const error = ref<string | null>(null)
|
|
|
|
|
const isSetup = ref(false)
|
2026-02-17 19:19:54 +00:00
|
|
|
const whooshAway = ref(false)
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
const requiresTotp = ref(false)
|
|
|
|
|
const totpCode = ref('')
|
|
|
|
|
const useBackupCode = ref(false)
|
|
|
|
|
const totpInputRef = ref<HTMLInputElement | null>(null)
|
|
|
|
|
|
|
|
|
|
// Server startup state
|
|
|
|
|
const serverReady = ref(false)
|
|
|
|
|
const serverChecking = ref(true)
|
|
|
|
|
const startupProgress = ref(0)
|
|
|
|
|
let startupPollTimer: ReturnType<typeof setTimeout> | null = null
|
|
|
|
|
let startupProgressInterval: ReturnType<typeof setInterval> | null = null
|
2026-01-24 22:59:20 +00:00
|
|
|
|
fix: production onboarding, CI tests, container security, keyboard nav
Install & Onboarding:
- Remove DEV_MODE=true from production ISO service file (auto-created
users, skipped password setup)
- Auto-install no longer overwrites rootfs service file with bad template
- Login.vue always checks auth.isSetup — shows password creation form
on fresh install without requiring dev build flag
- Deploy image-versions.sh to /opt/archipelago/scripts/ on installed nodes
- First-boot-containers sources image-versions.sh, runs podman as
archipelago user (rootless), enables linger + podman.socket
- Correct volume ownership (100000:100000 for rootless UID mapping)
Container Security:
- FileBrowser: add --cap-add=DAC_OVERRIDE for rootless podman volume access
- FileBrowser: add --read-only, /data volume for database, proper cmd args
- First-boot script matches backend config (security hardening + health check)
CI Pipeline:
- Add vue-tsc type check + vitest run to build-iso.yml (runs every push)
- Add post-install-tests.yml workflow (workflow_dispatch, SSH to target)
- Build report: set +eo pipefail, fix rootfs path, add || true guards
- Bundle run-post-install-tests.sh into ISO
E2E Test Suite (scripts/run-post-install-tests.sh):
- Phase 1: Install verification (files, services, podman, linger, DEV_MODE check)
- Phase 2: Onboarding flow (auth.isSetup, auth.setup, login, DID, complete)
- Phase 3: Container lifecycle (install 3 apps via package.install RPC,
verify running, stop, verify stopped, restart, verify running, health)
- Phase 4: Log verification (first-boot log, diagnostics, journal errors)
- Correct package.install params: {"id", "dockerImage"}
Frontend:
- Fix backdrop-filter tab-switch bug (keep animations paused during rebuild)
- Dashboard glitch animations paused during tab-hidden
- Gamepad nav: auto-focus first container on route change
- Tab roving: Left/Right on role="tab" cycles and activates sibling tabs
- ContainerApps: data-controller-launch on running app cards
- 515 tests passing (fixed 30 broken, added 19 new keyboard nav tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:16:57 +00:00
|
|
|
// Whether we're in setup mode (no password created yet)
|
|
|
|
|
const isSetupMode = ref(false)
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-03-29 17:15:56 +01:00
|
|
|
// Whether we're still checking the setup state (prevents flash of wrong form)
|
|
|
|
|
const isCheckingSetup = ref(true)
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
// Whether the login form should be disabled (server not ready)
|
|
|
|
|
const formDisabled = computed(() => !serverReady.value)
|
|
|
|
|
|
|
|
|
|
async function checkServerHealth(): Promise<boolean> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch('/rpc/v1', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({ method: 'server.echo', params: { message: 'ping' } }),
|
|
|
|
|
signal: AbortSignal.timeout(5000),
|
|
|
|
|
})
|
|
|
|
|
// Any HTTP response from backend (200, 401, 403, etc.) means it's up
|
|
|
|
|
// Only 502/503 from nginx means backend isn't running yet
|
|
|
|
|
return response.status !== 502 && response.status !== 503
|
|
|
|
|
} catch {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pollServerStartup(): Promise<void> {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
// Animate progress slowly while waiting
|
|
|
|
|
startupProgressInterval = setInterval(() => {
|
|
|
|
|
if (startupProgress.value < 90) {
|
|
|
|
|
startupProgress.value += Math.random() * 8 + 2
|
|
|
|
|
if (startupProgress.value > 90) startupProgress.value = 90
|
|
|
|
|
}
|
|
|
|
|
}, 600)
|
|
|
|
|
|
|
|
|
|
const poll = async () => {
|
|
|
|
|
const healthy = await checkServerHealth()
|
|
|
|
|
if (healthy) {
|
|
|
|
|
if (startupProgressInterval) clearInterval(startupProgressInterval)
|
|
|
|
|
startupProgress.value = 100
|
|
|
|
|
// Brief pause to show 100% before revealing form
|
|
|
|
|
await new Promise(r => setTimeout(r, 400))
|
|
|
|
|
serverReady.value = true
|
|
|
|
|
serverChecking.value = false
|
|
|
|
|
resolve()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// Retry in 2s
|
|
|
|
|
startupPollTimer = setTimeout(poll, 2000)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
poll()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-01 18:07:35 +00:00
|
|
|
let unlockHandler: (() => void) | null = null
|
|
|
|
|
|
|
|
|
|
function removeUnlockListeners() {
|
|
|
|
|
if (unlockHandler) {
|
|
|
|
|
document.removeEventListener('click', unlockHandler)
|
|
|
|
|
document.removeEventListener('touchstart', unlockHandler)
|
|
|
|
|
document.removeEventListener('keydown', unlockHandler)
|
|
|
|
|
unlockHandler = null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
removeUnlockListeners()
|
|
|
|
|
if (startupPollTimer) clearTimeout(startupPollTimer)
|
|
|
|
|
if (startupProgressInterval) clearInterval(startupProgressInterval)
|
|
|
|
|
})
|
2026-03-01 18:07:35 +00:00
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
onMounted(async () => {
|
2026-03-01 17:53:18 +00:00
|
|
|
const fromSplash = sessionStorage.getItem('archipelago_from_splash') === '1'
|
|
|
|
|
if (fromSplash) sessionStorage.removeItem('archipelago_from_splash')
|
2026-03-01 18:07:35 +00:00
|
|
|
unlockHandler = () => {
|
2026-03-01 17:53:18 +00:00
|
|
|
if (!fromSplash) {
|
|
|
|
|
resumeAudioContext()
|
|
|
|
|
startSynthwave()
|
|
|
|
|
}
|
2026-03-01 18:07:35 +00:00
|
|
|
removeUnlockListeners()
|
2026-02-17 19:19:54 +00:00
|
|
|
}
|
2026-03-01 18:07:35 +00:00
|
|
|
document.addEventListener('click', unlockHandler, { once: true })
|
|
|
|
|
document.addEventListener('touchstart', unlockHandler, { once: true })
|
|
|
|
|
document.addEventListener('keydown', unlockHandler, { once: true })
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
|
|
|
|
|
// Check server health first
|
|
|
|
|
const healthy = await checkServerHealth()
|
|
|
|
|
if (healthy) {
|
|
|
|
|
serverReady.value = true
|
|
|
|
|
serverChecking.value = false
|
|
|
|
|
} else {
|
|
|
|
|
// Server not ready — start polling with progress bar
|
|
|
|
|
await pollServerStartup()
|
|
|
|
|
}
|
|
|
|
|
|
fix: production onboarding, CI tests, container security, keyboard nav
Install & Onboarding:
- Remove DEV_MODE=true from production ISO service file (auto-created
users, skipped password setup)
- Auto-install no longer overwrites rootfs service file with bad template
- Login.vue always checks auth.isSetup — shows password creation form
on fresh install without requiring dev build flag
- Deploy image-versions.sh to /opt/archipelago/scripts/ on installed nodes
- First-boot-containers sources image-versions.sh, runs podman as
archipelago user (rootless), enables linger + podman.socket
- Correct volume ownership (100000:100000 for rootless UID mapping)
Container Security:
- FileBrowser: add --cap-add=DAC_OVERRIDE for rootless podman volume access
- FileBrowser: add --read-only, /data volume for database, proper cmd args
- First-boot script matches backend config (security hardening + health check)
CI Pipeline:
- Add vue-tsc type check + vitest run to build-iso.yml (runs every push)
- Add post-install-tests.yml workflow (workflow_dispatch, SSH to target)
- Build report: set +eo pipefail, fix rootfs path, add || true guards
- Bundle run-post-install-tests.sh into ISO
E2E Test Suite (scripts/run-post-install-tests.sh):
- Phase 1: Install verification (files, services, podman, linger, DEV_MODE check)
- Phase 2: Onboarding flow (auth.isSetup, auth.setup, login, DID, complete)
- Phase 3: Container lifecycle (install 3 apps via package.install RPC,
verify running, stop, verify stopped, restart, verify running, health)
- Phase 4: Log verification (first-boot log, diagnostics, journal errors)
- Correct package.install params: {"id", "dockerImage"}
Frontend:
- Fix backdrop-filter tab-switch bug (keep animations paused during rebuild)
- Dashboard glitch animations paused during tab-hidden
- Gamepad nav: auto-focus first container on route change
- Tab roving: Left/Right on role="tab" cycles and activates sibling tabs
- ContainerApps: data-controller-launch on running app cards
- 515 tests passing (fixed 30 broken, added 19 new keyboard nav tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:16:57 +00:00
|
|
|
// Check if password has been set up — show setup form if not
|
|
|
|
|
try {
|
|
|
|
|
const result = await rpcClient.call<boolean>({ method: 'auth.isSetup', params: {}, timeout: 8000 })
|
|
|
|
|
isSetup.value = Boolean(result)
|
|
|
|
|
isSetupMode.value = !isSetup.value
|
|
|
|
|
} catch {
|
|
|
|
|
isSetup.value = false
|
|
|
|
|
isSetupMode.value = true
|
2026-03-29 17:15:56 +01:00
|
|
|
} finally {
|
|
|
|
|
isCheckingSetup.value = false
|
2026-01-24 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2026-02-17 19:19:54 +00:00
|
|
|
|
2026-02-18 10:35:04 +00:00
|
|
|
function handleSetupWithSound() {
|
|
|
|
|
if (!loading.value && password.value && password.value === confirmPassword.value) {
|
|
|
|
|
playPop()
|
|
|
|
|
}
|
|
|
|
|
handleSetup()
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
async function handleSetup() {
|
|
|
|
|
if (!password.value || password.value.length < 8) {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = t('login.errorMinLength')
|
2026-01-24 22:59:20 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (password.value !== confirmPassword.value) {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = t('login.errorMismatch')
|
2026-01-24 22:59:20 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
error.value = null
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await rpcClient.call({
|
|
|
|
|
method: 'auth.setup',
|
2026-03-18 00:55:00 +00:00
|
|
|
params: { password: password.value.trim() }
|
2026-01-24 22:59:20 +00:00
|
|
|
})
|
2026-03-18 00:55:00 +00:00
|
|
|
|
2026-03-29 17:15:56 +01:00
|
|
|
await store.login(password.value.trim())
|
|
|
|
|
// Verify session cookie works before navigating (prevents connection lost on first login)
|
|
|
|
|
try {
|
|
|
|
|
await rpcClient.call({ method: 'server.echo', params: { message: 'session-check' } })
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'Setup succeeded but session could not be established. Try refreshing.'
|
|
|
|
|
store.logout()
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-02-17 19:19:54 +00:00
|
|
|
stopSynthwave()
|
|
|
|
|
whooshAway.value = true
|
|
|
|
|
playLoginSuccessWhoosh()
|
|
|
|
|
loginTransition.setJustLoggedIn(true)
|
2026-02-17 19:42:59 +00:00
|
|
|
await new Promise(r => setTimeout(r, 520))
|
2026-03-16 12:58:35 +00:00
|
|
|
await router.replace(loginRedirectTo.value).catch(() => {
|
|
|
|
|
window.location.href = loginRedirectTo.value
|
2026-03-01 17:53:18 +00:00
|
|
|
})
|
2026-01-24 22:59:20 +00:00
|
|
|
} catch (err) {
|
2026-02-17 19:19:54 +00:00
|
|
|
whooshAway.value = false
|
2026-03-01 17:53:18 +00:00
|
|
|
const msg = err instanceof Error ? err.message : ''
|
|
|
|
|
if (/502|503|Bad Gateway|timeout|fetch|network/i.test(msg)) {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = t('login.errorServerStarting')
|
2026-03-01 17:53:18 +00:00
|
|
|
} else {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = msg || t('login.errorSetupFailed')
|
2026-03-01 17:53:18 +00:00
|
|
|
}
|
2026-02-17 19:19:54 +00:00
|
|
|
startSynthwave()
|
2026-01-24 22:59:20 +00:00
|
|
|
} finally {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-18 10:35:04 +00:00
|
|
|
function handleLoginWithSound() {
|
|
|
|
|
if (!loading.value && password.value) {
|
|
|
|
|
playPop()
|
|
|
|
|
}
|
|
|
|
|
handleLogin()
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
async function handleLogin() {
|
|
|
|
|
if (!password.value) return
|
|
|
|
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
error.value = null
|
|
|
|
|
|
|
|
|
|
try {
|
2026-03-18 00:55:00 +00:00
|
|
|
const result = await store.login(password.value.trim())
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
if (result?.requires_totp) {
|
|
|
|
|
requiresTotp.value = true
|
|
|
|
|
loading.value = false
|
|
|
|
|
// Focus the TOTP input after DOM update
|
|
|
|
|
setTimeout(() => totpInputRef.value?.focus(), 100)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-28 23:41:40 +00:00
|
|
|
// Verify session cookie works before navigating (prevents login loop on LAN)
|
|
|
|
|
try {
|
|
|
|
|
await rpcClient.call({ method: 'server.echo', params: { message: 'session-check' } })
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'Login succeeded but session could not be established. Try clearing cookies and refreshing.'
|
|
|
|
|
store.logout()
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-02-17 19:19:54 +00:00
|
|
|
stopSynthwave()
|
|
|
|
|
whooshAway.value = true
|
|
|
|
|
playLoginSuccessWhoosh()
|
|
|
|
|
loginTransition.setJustLoggedIn(true)
|
2026-02-17 19:42:59 +00:00
|
|
|
await new Promise(r => setTimeout(r, 520))
|
2026-03-16 12:58:35 +00:00
|
|
|
await router.replace(loginRedirectTo.value).catch(() => {
|
|
|
|
|
window.location.href = loginRedirectTo.value
|
2026-03-01 17:53:18 +00:00
|
|
|
})
|
2026-01-24 22:59:20 +00:00
|
|
|
} catch (err) {
|
2026-02-17 19:19:54 +00:00
|
|
|
whooshAway.value = false
|
2026-03-01 17:53:18 +00:00
|
|
|
const msg = err instanceof Error ? err.message : ''
|
|
|
|
|
if (/502|503|Bad Gateway|timeout|fetch|network/i.test(msg)) {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = t('login.errorServerStarting')
|
2026-03-01 17:53:18 +00:00
|
|
|
} else {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = msg || t('login.errorLoginFailed')
|
2026-03-01 17:53:18 +00:00
|
|
|
}
|
2026-02-17 19:19:54 +00:00
|
|
|
startSynthwave()
|
2026-01-24 22:59:20 +00:00
|
|
|
} finally {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
async function handleTotpVerify() {
|
|
|
|
|
if (!totpCode.value) return
|
|
|
|
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
error.value = null
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (useBackupCode.value) {
|
|
|
|
|
await rpcClient.loginBackup(totpCode.value)
|
|
|
|
|
} else {
|
|
|
|
|
await rpcClient.loginTotp(totpCode.value)
|
|
|
|
|
}
|
|
|
|
|
await store.completeLoginAfterTotp()
|
|
|
|
|
stopSynthwave()
|
|
|
|
|
whooshAway.value = true
|
|
|
|
|
playLoginSuccessWhoosh()
|
|
|
|
|
loginTransition.setJustLoggedIn(true)
|
|
|
|
|
await new Promise(r => setTimeout(r, 520))
|
2026-03-16 12:58:35 +00:00
|
|
|
await router.replace(loginRedirectTo.value).catch(() => {
|
|
|
|
|
window.location.href = loginRedirectTo.value
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
})
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const msg = err instanceof Error ? err.message : ''
|
|
|
|
|
if (/expired|too many/i.test(msg)) {
|
|
|
|
|
// Session expired, go back to password step
|
|
|
|
|
requiresTotp.value = false
|
|
|
|
|
totpCode.value = ''
|
|
|
|
|
error.value = msg
|
|
|
|
|
} else {
|
2026-03-11 13:45:59 +00:00
|
|
|
error.value = msg || t('login.errorInvalidCode')
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
}
|
|
|
|
|
totpCode.value = ''
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
function replayIntro() {
|
|
|
|
|
// Clear the intro seen flag
|
|
|
|
|
localStorage.removeItem('neode_intro_seen')
|
|
|
|
|
// Navigate to root to trigger splash screen
|
|
|
|
|
window.location.href = '/'
|
|
|
|
|
}
|
2026-03-02 08:34:13 +00:00
|
|
|
|
|
|
|
|
const isResettingOnboarding = ref(false)
|
|
|
|
|
|
|
|
|
|
async function restartOnboarding() {
|
|
|
|
|
if (isResettingOnboarding.value) return
|
|
|
|
|
isResettingOnboarding.value = true
|
2026-03-09 17:09:59 +00:00
|
|
|
// Local-only reset — no RPC needed since user isn't logged in.
|
|
|
|
|
// Onboarding pages are all public, so clearing localStorage is enough.
|
|
|
|
|
localStorage.removeItem('neode_onboarding_complete')
|
|
|
|
|
localStorage.removeItem('neode_did')
|
|
|
|
|
localStorage.removeItem('neode_did_state')
|
|
|
|
|
localStorage.removeItem('neode_backup_created')
|
|
|
|
|
router.push('/onboarding/intro').then(() => {
|
2026-03-02 08:34:13 +00:00
|
|
|
window.location.reload()
|
2026-03-09 17:09:59 +00:00
|
|
|
}).catch(() => {
|
|
|
|
|
window.location.href = '/onboarding/intro'
|
|
|
|
|
})
|
2026-03-02 08:34:13 +00:00
|
|
|
}
|
2026-01-24 22:59:20 +00:00
|
|
|
</script>
|
|
|
|
|
|
2026-02-17 19:19:54 +00:00
|
|
|
<style scoped>
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
/* Server startup progress bar */
|
|
|
|
|
.startup-progress-track {
|
|
|
|
|
height: 4px;
|
|
|
|
|
background: rgba(255, 255, 255, 0.08);
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.startup-progress-bar {
|
|
|
|
|
height: 100%;
|
|
|
|
|
background: linear-gradient(90deg, #fb923c, #f59e0b);
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
transition: width 0.5s ease-out;
|
|
|
|
|
box-shadow: 0 0 8px rgba(251, 146, 60, 0.4);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-17 19:42:59 +00:00
|
|
|
/* Perspective for 3D fly effect */
|
|
|
|
|
.login-fly-perspective {
|
|
|
|
|
perspective: 1200px;
|
|
|
|
|
perspective-origin: center center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-card {
|
|
|
|
|
transform-style: preserve-3d;
|
|
|
|
|
transition: transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
|
|
|
|
opacity 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
|
|
|
|
filter 0.5s ease-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fly towards user - card zooms forward as it transitions out */
|
|
|
|
|
.login-fly-towards {
|
|
|
|
|
animation: login-fly-towards 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes login-fly-towards {
|
|
|
|
|
0% {
|
|
|
|
|
transform: translateZ(0) scale(1);
|
|
|
|
|
opacity: 1;
|
|
|
|
|
filter: blur(0);
|
|
|
|
|
}
|
|
|
|
|
60% {
|
|
|
|
|
transform: translateZ(180px) scale(1.4);
|
|
|
|
|
opacity: 0.95;
|
|
|
|
|
filter: blur(2px);
|
|
|
|
|
}
|
|
|
|
|
100% {
|
|
|
|
|
transform: translateZ(400px) scale(2);
|
|
|
|
|
opacity: 0;
|
|
|
|
|
filter: blur(8px);
|
|
|
|
|
}
|
2026-02-17 19:19:54 +00:00
|
|
|
}
|
|
|
|
|
</style>
|