diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2e1f2..e278ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - project.linkedcorp.net +## [2.7.1] - 2026-10-01 +### Changed +- "Contraseñas" vuelve a pedir el PIN cada vez que se sale del menú (a otro, o cerrando la + pestaña) y se vuelve a entrar — antes quedaba desbloqueado el resto de la sesión del sistema. +- Si el menú queda abierto sin atención, sale solo al Panel a los 3 minutos de haberse + desbloqueado. + ## [2.7.0] - 2026-10-01 ### Added - Nuevo menú "Contraseñas": repositorio personal de credenciales (nombre, enlace, usuario, diff --git a/VERSION b/VERSION index 24ba9a3..860487c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.0 +2.7.1 diff --git a/backend/package.json b/backend/package.json index cbed952..ad12616 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "project-linkedcorp-backend", - "version": "2.7.0", + "version": "2.7.1", "private": true, "type": "module", "main": "src/server.js", diff --git a/frontend/package.json b/frontend/package.json index a589798..dfc952f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "project-linkedcorp-frontend", "private": true, - "version": "2.7.0", + "version": "2.7.1", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/i18n/messages.js b/frontend/src/i18n/messages.js index c5bf5ad..21d789f 100644 --- a/frontend/src/i18n/messages.js +++ b/frontend/src/i18n/messages.js @@ -212,6 +212,7 @@ export const messages = { vault_copy: 'Copiar', vault_copied: 'Copiado al portapapeles', vault_generate: 'Generar', + vault_auto_lock_notice: 'Saliste de Contraseñas por seguridad — ingresa tu PIN de nuevo para volver a entrar.', notes_title: 'Notas', notes_placeholder: 'Escribe un apunte rápido...', notes_add: 'Agregar', @@ -538,6 +539,7 @@ export const messages = { vault_copy: 'Copy', vault_copied: 'Copied to clipboard', vault_generate: 'Generate', + vault_auto_lock_notice: 'You left Passwords for security — enter your PIN again to come back in.', notes_title: 'Notes', notes_placeholder: 'Write a quick note...', notes_add: 'Add', diff --git a/frontend/src/pages/Contrasenas/ContrasenasPage.jsx b/frontend/src/pages/Contrasenas/ContrasenasPage.jsx index f34df4d..6266803 100644 --- a/frontend/src/pages/Contrasenas/ContrasenasPage.jsx +++ b/frontend/src/pages/Contrasenas/ContrasenasPage.jsx @@ -1,9 +1,10 @@ import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import { Plus, Trash2, Eye, EyeOff, Copy, Pencil, Save, X, RefreshCw, ShieldAlert } from 'lucide-react'; import { useUi } from '../../context/ui-context.jsx'; import { useAction } from '../../hooks/useAsync.js'; import { - getVaultStatus, createVaultPin, unlockVault, changeVaultPin, forgotVaultPin, + getVaultStatus, createVaultPin, unlockVault, changeVaultPin, forgotVaultPin, setVaultToken, listVaultEntries, getVaultEntry, createVaultEntry, updateVaultEntry, deleteVaultEntry, } from '../../services/vault.js'; import { ListView } from '../../components/ListView.jsx'; @@ -13,6 +14,7 @@ import { PasswordInput } from '../../components/PasswordInput.jsx'; import { DetailPopup } from '../../components/DetailPopup.jsx'; const EMPTY_FORM = { title: '', url: '', username: '', password: '', notes: '' }; +const AUTO_LOCK_MS = 3 * 60 * 1000; // 3 minutos: salir solo del menu si queda abierto sin atencion function randomPassword(length = 20) { const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789!@#$%^&*'; @@ -23,6 +25,7 @@ function randomPassword(length = 20) { export default function ContrasenasPage() { const { t, pushToast, openDialog } = useUi(); const runAction = useAction(); + const navigate = useNavigate(); const [locked, setLocked] = useState(true); const [checking, setChecking] = useState(true); @@ -68,6 +71,21 @@ export default function ContrasenasPage() { useEffect(() => { checkAccess(); }, []); + // Por seguridad: salir de este menu (a otro, o cerrando la pestaña) siempre bloquea de nuevo -- + // el token de desbloqueo se borra al desmontar, asi que la proxima vez que se entra aca pide el + // PIN de nuevo, sin importar cuanto haya durado la sesion del sistema. + useEffect(() => () => setVaultToken(null), []); + + // Si queda abierto sin atencion, sale solo al Panel a los 3 minutos de haberse desbloqueado. + useEffect(() => { + if (locked) return; + const timer = setTimeout(() => { + pushToast({ tone: 'warning', message: t('vault_auto_lock_notice') }); + navigate('/'); + }, AUTO_LOCK_MS); + return () => clearTimeout(timer); + }, [locked]); + async function submitPin() { setPinError(''); if (!/^\d{4}$/.test(pin)) { setPinError(t('vault_pin_invalid')); return; }