feat: version 2.7.0 -- menu Contraseñas (repositorio de credenciales privado)

Nuevo modulo backend/src/modules/vault/: contraseña y notas cifradas
en el servidor (AES-256-GCM, mismo mecanismo ya usado para la clave
SMTP). Acceso al menu protegido con un PIN de 4 digitos independiente
del login (token corto propio, header X-Vault-Token, nunca el JWT de
sesion). El PIN no participa del cifrado -- cambiarlo o restablecerlo
por correo nunca afecta las contraseñas ya guardadas. Privado por
usuario, sin excepcion. Cada accion sensible (crear/editar/eliminar/
revelar/desbloquear) queda en audit_log. Compartir con otro usuario
queda para una proxima version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-01 12:12:54 -05:00
parent f607455668
commit 0be0712ff0
20 changed files with 879 additions and 10 deletions
+24
View File
@@ -0,0 +1,24 @@
-- Repositorio de credenciales privado por usuario ("Contraseñas"). Idempotente.
-- password_enc/notes_enc guardan el resultado de encrypt() (AES-256-GCM, backend/src/utils/crypto.js),
-- nunca texto plano. Privado por usuario -- nadie mas lo ve, ni siquiera un superadmin.
CREATE TABLE IF NOT EXISTS vault_entries (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(160) NOT NULL,
url VARCHAR(500) NULL,
username VARCHAR(160) NULL,
password_enc TEXT NULL,
notes_enc TEXT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_vault_entries_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE INDEX IF NOT EXISTS idx_vault_entries_user ON vault_entries(user_id);
-- PIN de acceso al modulo (candado, NO participa del cifrado -- 4 digitos seria debil para eso).
-- Independiente del password_hash de login: cambiarlo/resetearlo nunca toca vault_entries.
ALTER TABLE users
ADD COLUMN IF NOT EXISTS vault_pin_hash VARCHAR(255) NULL,
ADD COLUMN IF NOT EXISTS vault_pin_reset_token VARCHAR(128) NULL,
ADD COLUMN IF NOT EXISTS vault_pin_reset_token_expires DATETIME NULL;
CREATE INDEX IF NOT EXISTS idx_users_vault_pin_reset_token ON users(vault_pin_reset_token);