import { Component, createSignal, Show } from 'solid-js'; import { showError, showSuccess } from '@/utils/toast'; import { setApiToken as setApiClientToken } from '@/utils/apiClient'; import type { WizardState } from '../SetupWizard'; interface SecurityStepProps { state: WizardState; updateState: (updates: Partial) => void; bootstrapToken: string; onNext: () => void; onBack: () => void; } export const SecurityStep: Component = (props) => { const [username, setUsername] = createSignal(props.state.username || 'admin'); const [useCustomPassword, setUseCustomPassword] = createSignal(false); const [password, setPassword] = createSignal(''); const [confirmPassword, setConfirmPassword] = createSignal(''); const [isSettingUp, setIsSettingUp] = createSignal(false); const generatePassword = () => { const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789!@#$%'; let pass = ''; for (let i = 0; i < 16; i++) { pass += chars.charAt(Math.floor(Math.random() * chars.length)); } return pass; }; const generateToken = (): string => { const array = new Uint8Array(24); crypto.getRandomValues(array); return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join(''); }; const handleSetup = async () => { if (useCustomPassword()) { if (!password() || password().length < 12) { showError('Password must be at least 12 characters'); return; } if (password() !== confirmPassword()) { showError('Passwords do not match'); return; } } setIsSettingUp(true); const finalPassword = useCustomPassword() ? password() : generatePassword(); const token = generateToken(); try { setApiClientToken(token); const response = await fetch('/api/security/quick-setup', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Setup-Token': props.bootstrapToken, }, credentials: 'include', body: JSON.stringify({ username: username(), password: finalPassword, apiToken: token, force: false, setupToken: props.bootstrapToken, }), }); if (!response.ok) { throw new Error(await response.text()); } props.updateState({ username: username(), password: finalPassword, apiToken: token, }); showSuccess('Security configured!'); props.onNext(); } catch (error) { showError(`Setup failed: ${error}`); } finally { setIsSettingUp(false); } }; return (

Secure Your Dashboard

Create your admin account

{/* Username */}
setUsername(e.currentTarget.value)} class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-xl text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="admin" />
{/* Password choice */}
setPassword(e.currentTarget.value)} class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-xl text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Password (min 12 characters)" /> setConfirmPassword(e.currentTarget.value)} class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-xl text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Confirm password" />

A secure 16-character password will be generated and shown after setup.

{/* Info */}

This creates your admin account and an API token for automation. Credentials will be displayed once - save them securely!

{/* Actions */}
); };