diff --git a/apps/web/src/lib/stores/auth.svelte.ts b/apps/web/src/lib/stores/auth.svelte.ts index 57255de..5171ae1 100644 --- a/apps/web/src/lib/stores/auth.svelte.ts +++ b/apps/web/src/lib/stores/auth.svelte.ts @@ -55,6 +55,39 @@ function getUser(username: string): StoredUser | undefined { return getStoredUsers()[username.toLowerCase()]; } +// ============================================================================ +// MIGRATION: Check if user needs to set password (existing user from old version) +// ============================================================================ + +export interface MigrationStatus { + needsMigration: boolean; + username: string | null; +} + +function checkMigrationStatus(): MigrationStatus { + if (typeof window === "undefined") + return { needsMigration: false, username: null }; + + // Check if there's an existing session from old version (without password system) + const stored = localStorage.getItem("locanote_session"); + if (!stored) return { needsMigration: false, username: null }; + + try { + const session = JSON.parse(stored); + // Check if this user has a password set + const users = getStoredUsers(); + const hasPassword = users[session.username?.toLowerCase()] !== undefined; + + if (!hasPassword && session.username) { + return { needsMigration: true, username: session.username }; + } + } catch { + // Invalid session + } + + return { needsMigration: false, username: null }; +} + // ============================================================================ // METHODS // ============================================================================ @@ -82,6 +115,38 @@ export const auth = { return authState; }, + // Check if user needs to migrate (set password for existing account) + checkMigration(): MigrationStatus { + return checkMigrationStatus(); + }, + + // Migrate existing user to password system + async migrateUser( + username: string, + password: string, + confirmPassword: string, + ): Promise<{ success: boolean; error?: string }> { + if (!password || password.length < 6) { + return { + success: false, + error: "Password must be at least 6 characters", + }; + } + + if (password !== confirmPassword) { + return { + success: false, + error: "Passwords do not match", + }; + } + + // Hash and store password + const passwordHash = await hashPassword(password); + saveUser(username, passwordHash); + + return { success: true }; + }, + // Login with password async login( username: string, diff --git a/apps/web/src/routes/+page.svelte b/apps/web/src/routes/+page.svelte index 81d2966..87b3d64 100644 --- a/apps/web/src/routes/+page.svelte +++ b/apps/web/src/routes/+page.svelte @@ -15,6 +15,13 @@ LANDING PAGE - Beautiful Glass Design let isRegister = $state(false); let mounted = $state(false); + // Migration state for existing users + let showMigrationModal = $state(false); + let migrationUsername = $state(""); + let migrationPassword = $state(""); + let migrationConfirmPassword = $state(""); + let migrationError = $state(""); + // Check session BEFORE mount to prevent flash function checkSession() { if (typeof window === "undefined") return false; @@ -40,12 +47,56 @@ LANDING PAGE - Beautiful Glass Design onMount(() => { mounted = true; + // Check if user needs to migrate from old version + const migration = auth.checkMigration(); + if (migration.needsMigration && migration.username) { + showMigrationModal = true; + migrationUsername = migration.username; + return; // Don't redirect, show migration modal instead + } // Double-check session after mount (handles edge cases) if (checkSession()) { goto("/app", { replaceState: true }); } }); + // Handle migration submission + async function handleMigration() { + if (!migrationPassword || migrationPassword.length < 6) { + migrationError = "Password must be at least 6 characters"; + return; + } + if (migrationPassword !== migrationConfirmPassword) { + migrationError = "Passwords do not match"; + return; + } + + isLoading = true; + migrationError = ""; + + const result = await auth.migrateUser( + migrationUsername, + migrationPassword, + migrationConfirmPassword, + ); + + isLoading = false; + + if (result.success) { + showMigrationModal = false; + // After migration, try to auto-login + const loginResult = await auth.login( + migrationUsername, + migrationPassword, + ); + if (loginResult.success) { + goto("/app", { replaceState: true }); + } + } else { + migrationError = result.error || "Migration failed"; + } + } + async function handleSubmit() { if (!username.trim()) { error = "Please enter a username"; @@ -223,6 +274,54 @@ LANDING PAGE - Beautiful Glass Design + +{#if showMigrationModal} +
+{/if} + diff --git a/apps/web/src/routes/app/note/[id]/+page.svelte b/apps/web/src/routes/app/note/[id]/+page.svelte index 7c51bef..1073d68 100644 --- a/apps/web/src/routes/app/note/[id]/+page.svelte +++ b/apps/web/src/routes/app/note/[id]/+page.svelte @@ -252,8 +252,8 @@ NOTEPAD EDITOR PAGE - Notepad++ Style Layout - -