Skip to main content

pin-auth-nodejs-sqlite

Patrón completo de autenticación con PIN para apps Node.js + SQLite (sql.js). Migración de BD existente, login con creación de usuario, PIN siempre visible, endpoint de set/change PIN, frontend con modal de setup.

Zur Installation springen

Quellinformationen

Repository
Ntizar/NtizarBrainMasterMind
Letzte Quellaktivität
26. Juni 2026 um 12:05
Erkannte Sprache von SKILL.md
Spanisch
Sterne
2
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
pin-auth-nodejs-sqlite
description
Patrón completo de autenticación con PIN para apps Node.js + SQLite (sql.js). Migración de BD existente, login con creación de usuario, PIN siempre visible, endpoint de set/change PIN, frontend con modal de setup.
version
2.0.0
tags
["auth","security","nodejs","sqlite","pin"]
# PIN Auth — Node.js + SQLite Patrón de autenticación con PIN de 4-6 dígitos para apps multi-usuario. ## Backend (server.js) ### 1. Schema + Migración (CRÍTICO) ```sql CREATE TABLE IF NOT EXISTS usuarios ( id INTEGER PRIMARY KEY AUTOINCREMENT, nombre TEXT UNIQUE NOT NULL, pin TEXT, -- nullable: usuarios existentes sin PIN activo INTEGER DEFAULT 1, created_at TEXT DEFAULT (datetime('now')) ) ``` **⚠️ PITFALL: `CREATE TABLE IF NOT EXISTS` NO añade columnas nuevas a tablas existentes.** Si la tabla ya existe sin `pin`, el `CREATE TABLE` no hace nada y el `SELECT pin` falla con `no such column`. **Solución: ALTER TABLE con try-catch después del CREATE TABLE:** ```javascript db.run(`CREATE TABLE IF NOT EXISTS usuarios (...)`); // Migración: añadir columna pin si no existe (BDs viejas) try { db.run("ALTER TABLE usuarios ADD COLUMN pin TEXT"); } catch(e) { /* ya existe */ } ``` El `ALTER TABLE` lanza excepción si la columna ya existe — por eso el try-catch silencioso. ### 2. Login: crear usuario con PIN en primer acceso ```javascript app.post('/api/auth/login', (req, res) => { const { nombre, pin } = req.body; let user = sql_get('SELECT id, nombre, pin FROM usuarios WHERE nombre = ?', [cleanName]); if (user) { // Usuario existente — PIN requerido si está configurado if (user.pin) { if (!pin) return res.status(400).json({ error: 'PIN requerido', pin_required: true }); if (String(pin).trim() !== user.pin) return res.status(400).json({ error: 'PIN incorrecto' }); } } else { // Usuario nuevo — crear CON el PIN que introduce const pinValue = (pin && /^\d{4,6}$/.test(String(pin).trim())) ? String(pin).trim() : null; sql_run('INSERT INTO usuarios (nombre, pin) VALUES (?, ?)', [cleanName, pinValue]); user = { id: lastId(), nombre: cleanName, pin: pinValue }; sql_run("INSERT INTO perfil (usuario_id, genero, notas) VALUES (?, 'no definido', '')", [user.id]); } const token = crypto.randomBytes(32).toString('hex'); res.json({ ok: true, sessionId: token, user: { id, nombre }, needs_pin: !user.pin }); }); ``` **Flujo:** - Nuevo + PIN → crea usuario CON PIN → entra - Nuevo sin PIN → crea usuario SIN PIN → `needs_pin: true` → modal setup - Existente + tiene PIN + PIN correcto → entra - Existente + tiene PIN + sin PIN/error → `pin_required: true` - Existente + sin PIN → entra directo (backward compat) ### 3. Endpoint set/change PIN ```javascript app.post('/api/auth/set-pin', requireAuth, (req, res) => { const { pin } = req.body; if (!pin || !/^\d{4,6}$/.test(String(pin).trim())) { return res.status(400).json({ error: 'PIN debe ser de 4 a 6 dígitos' }); } sql_run('UPDATE usuarios SET pin = ? WHERE id = ?', [String(pin).trim(), req.userId]); saveDB(); res.json({ ok: true }); }); ``` ### 4. Usuarios con has_pin ```javascript app.get('/api/auth/usuarios', (req, res) => { const users = sql_all("SELECT id, nombre, pin IS NOT NULL as has_pin FROM usuarios WHERE activo = 1"); res.json({ ok: true, usuarios: users }); }); ``` ## Frontend (dashboard.html) ### 5. PIN siempre visible El input de PIN **NUNCA** se oculta. Siempre está visible debajo del nombre. ```html <input type="text" id="auth-name" placeholder="Tu nombre" autocomplete="name" autofocus> <input type="password" id="auth-pin" placeholder="PIN (4-6 dígitos)" pattern="[0-9]*" maxlength="6" inputmode="numeric" style="margin-top:12px"> <button class="btn-primary" onclick="doLogin()">Entrar</button> ``` **No usar `display:none` en el PIN.** El usuario debe ver que hay un campo PIN siempre. ### 6. Selector de usuario → foco en PIN ```javascript data.usuarios.forEach(function(u) { var btn = document.createElement('button'); btn.className = 'user-btn'; btn.textContent = (u.has_pin ? '🔒 ' : '👤 ') + u.nombre; btn.onclick = function() { document.getElementById('auth-name').value = u.nombre; document.getElementById('auth-pin').value = ''; document.getElementById('auth-pin').focus(); }; }); ``` Al clicar un perfil: rellena nombre, limpia PIN, foco en PIN. Simple. ### 7. doLogin envía PIN siempre ```javascript var pin = document.getElementById('auth-pin').value.trim(); var body = { nombre: name }; if (pin) body.pin = pin; var data = await api('/api/auth/login', { method: 'POST', body }); if (data.ok) { document.getElementById('auth-pin').value = ''; enterApp(); if (data.needs_pin) setTimeout(showPinSetup, 800); } else { document.getElementById('auth-pin').value = ''; document.getElementById('auth-pin').focus(); } ``` ### 8. Modal setup de PIN (para usuarios sin PIN) ```javascript function showPinSetup() { // Overlay con input password + botones "Configurar" y "Ahora no" // POST /api/auth/set-pin con el PIN } ``` ## Pitfalls 1. **`CREATE TABLE IF NOT EXISTS` no migra columnas.** Si la tabla existe sin `pin`, el SELECT falla. Siempre hacer `ALTER TABLE ... ADD COLUMN` con try-catch después del CREATE. 2. **PIN en texto plano** es suficiente para apps de fitness. No usar bcrypt para 4-6 dígitos (overkill + sql.js no soporta native). 3. **Usuarios existentes** quedan sin PIN (nullable). Son compatibles con el sistema nuevo. 4. **`needs_pin: true`** se envía si el usuario NO tiene PIN configurado. 5. **`pin_required: true`** en error response indica que el usuario tiene PIN pero no se proporcionó. 6. **PIN input SIEMPRE visible.** No ocultarlo con display:none. El usuario debe ver que hay seguridad. 7. **No guardar PIN** en localStorage. Solo el sessionId. 8. **sql.js** `pin IS NOT NULL as has_pin` funciona como SQL estándar. Verificar con `node -c`.
Auf GitHub ansehen