Secure, self-hosted TOTP authenticator with advanced encryption and multi-format backup support
🚀 TRY THE APP DIRECTLY HERE! 🚀
Personal 2FA is a secure, offline-first TOTP authenticator that gives you complete control over your two-factor authentication codes. Import from Google Authenticator, create encrypted backups, and never worry about losing access to your accounts again.
- ✅ 100% Offline - Sin conexiones a internet
- ✅ Cifrado AES-256-GCM con Web Crypto API
- ✅ Almacenamiento local cifrado con IndexedDB
- ✅ Contraseña maestra con PBKDF2 (100,000 iteraciones)
- ✅ Código fuente legible e inspecciónable
- 📥 Importar códigos QR de exportación de Google Auth
- 📤 Exportar para backup (QR individuales o formato migración)
- 🔄 Uso directo como aplicación 2FA independiente
- 📹 Escáner QR via cámara web
- ⏰ Códigos TOTP con temporizadores visuales
- ➕ Añadir manualmente códigos TOTP
- 💾 Backup JSON cifrado
- 🔒 Auto-bloqueo configurable
- Navegador moderno con Web Crypto API (Chrome 37+, Firefox 34+, Safari 11+)
- HTTPS o localhost (requerido para Web Crypto y cámara)
- Cámara web (opcional, para escanear QR codes)
# Clonar o descargar el proyecto
cd personal-2fa
# Instalar dependencias
npm install
# Ejecutar en modo desarrollo
npm run dev
# Abrir http://localhost:3000# Generar archivos finales legibles (sin minificar)
npm run build
# Los archivos estaran en dist/
# - index.html (archivo principal)
# - personal-2fa.js (JavaScript legible)
# - personal-2fa-standalone.html (archivo único)
# - *.css (estilos)# Generar build y copiar a /docs para GitHub Pages
npm run build:docs
# Crea /docs/ con mismos archivos que /dist/
# Listo para configurar GitHub Pages con carpeta /docs- Crear contraseña maestra (mínimo 8 caracteres)
- Verificación de seguridad automática
- Inicialización del almacén cifrado
- Desbloquear con contraseña maestra
- Importar desde Google Authenticator (QR)
- Ver códigos TOTP con temporizadores
- Exportar para backup (sin almacenar en app)
- En Google Authenticator: Menú → Exportar cuentas
- En Personal 2FA: Importar → Activar Cámara
- Escanear el QR de Google Auth
- Códigos importados automáticamente
- Genera un QR por cada código
- Compatible con cualquier app 2FA
- Escanea cada QR en la app destino
- Formato nativo de Google Authenticator
- Múltiples códigos en un QR
- Importa directo en Google Auth
- Archivo cifrado con todos los códigos
- Para restaurar en Personal 2FA
- Incluye metadatos completos
- Añadir Manual → Completar formulario
- Servicio: Nombre del servicio (ej: Google, GitHub)
- Cuenta: Tu usuario/email
- Secreto: Código Base32 del servicio
- Opciones avanzadas: Algoritmo, dígitos, período
La app incluye indicadores de seguridad en tiempo real:
- 🔐 Cifrado: Estado del Web Crypto API
- 🏠 Almacenamiento: Confirmación local
- 📡 Red: Estado de conexión (offline = ✅)
// En consola del navegador
Personal2FA.performSecurityChecks()La aplicación utiliza almacenamiento local del navegador con cifrado:
- Ubicación: Base de datos
Personal2FAen IndexedDB del navegador - Datos: Secretos TOTP cifrados con AES-256-GCM
- Persistencia: Permanente hasta factory reset manual
- Ubicación: localStorage del navegador con prefijo
personal-2fa- - Uso: Solo si IndexedDB falla o no está disponible
- Datos: Misma estructura cifrada que IndexedDB
1. Abrir DevTools (F12)
2. Ir a pestaña "Application"
3. Sección "Storage":
- IndexedDB → Personal2FA → secrets (datos principales)
- Local Storage → buscar claves "personal-2fa-*" (fallback)
// Ver estado de IndexedDB
console.log('IndexedDB disponible:', !!window.indexedDB);
// Ver datos en localStorage (si existe)
Object.keys(localStorage).filter(key => key.startsWith('personal-2fa')).forEach(key => {
console.log(key + ':', localStorage.getItem(key));
});
// Verificar base de datos Personal2FA
const request = indexedDB.open('Personal2FA');
request.onsuccess = (event) => {
console.log('Base de datos Personal2FA existe:', !!event.target.result);
};- IndexedDB: No debe existir base de datos
Personal2FA - localStorage: No deben existir claves con prefijo
personal-2fa- - sessionStorage: Debe estar limpio de datos de la app
// Ejecutar en consola del navegador DESPUÉS del factory reset
console.log('=== VERIFICACIÓN POST FACTORY RESET ===');
// Verificar localStorage
const localKeys = Object.keys(localStorage).filter(k => k.includes('personal') || k.includes('2fa'));
console.log('localStorage keys restantes:', localKeys.length === 0 ? '✅ LIMPIO' : '❌ ' + localKeys);
// Verificar sessionStorage
const sessionKeys = Object.keys(sessionStorage).filter(k => k.includes('personal') || k.includes('2fa'));
console.log('sessionStorage keys restantes:', sessionKeys.length === 0 ? '✅ LIMPIO' : '❌ ' + sessionKeys);
// Verificar IndexedDB
indexedDB.databases().then(dbs => {
const personal2faDB = dbs.find(db => db.name === 'Personal2FA');
console.log('IndexedDB Personal2FA:', !personal2faDB ? '✅ ELIMINADA' : '❌ AÚN EXISTE');
});
console.log('=== Si todo muestra ✅, el borrado fue exitoso ===');- Chrome/Edge:
%LOCALAPPDATA%\Google\Chrome\User Data\Default\IndexedDB\ - Firefox:
%APPDATA%\Mozilla\Firefox\Profiles\[profile]\storage\default\ - Safari:
~/Library/Safari/Databases/
- Web Crypto API: Cifrado hardware-acelerado
- AES-256-GCM: Cifrado autenticado
- PBKDF2: Derivación segura de claves
- IndexedDB: Base de datos local persistente
src/js/
├── crypto.js # Criptografía (AES-256-GCM)
├── storage.js # Almacenamiento seguro (IndexedDB)
├── totp.js # Generación TOTP (RFC 6238)
├── qr.js # Escáner y generador QR
├── googleAuth.js # Import/Export Google Auth
└── main.js # Controlador principal
- Vite: Bundler moderno
- ES Modules: Módulos nativos
- Sin minificación: Código legible
- Desarrollo rápido: Hot reload
El archivo vite.config.js está configurado para generar código legible:
export default defineConfig({
build: {
minify: false, // ❌ Sin minificar
rollupOptions: {
output: {
compact: false, // Mantener espaciado
indent: ' ' // Indentación legible
}
}
}
})- Usa contraseñas maestras fuertes
- Mantén backups cifrados seguros
- Verifica el código fuente antes de usar
- Solo usa en HTTPS o localhost
- Requiere navegador moderno
- Cámara web para importar QR
- Sin sincronización entre dispositivos
- Backups manuales únicamente
- No uses en HTTP público
- No compartas la contraseña maestra
- No confíes en código modificado
- No uses con navegadores obsoletos
| Aplicación | Import | Export | Notas |
|---|---|---|---|
| Google Authenticator | ✅ | ✅ | Soporte completo |
| Microsoft Authenticator | ❌ | ✅ | Solo export |
| Authy | ❌ | ❌ | Sin soporte estándar |
| Aegis Authenticator | ✅ | ✅ | Soporte completo |
| andOTP | ✅ | ✅ | Via QR individual |
| Bitwarden | ❌ | ✅ | Via QR individual |
| LastPass | ❌ | Solo SHA1, 6 dígitos |
npm run dev # Servidor desarrollo (localhost:3000)
npm run build # Build producción (dist/)
npm run build:docs # Build + copiar a /docs para GitHub Pages
npm run preview # Vista previa del build
npm run serve # Servir build en local
npm run serve-docs # Servir /docs en local- Fork el repositorio
- Crear rama para tu feature
- Mantener código legible (sin minificar)
- Documentar cambios de seguridad
- Pull request con descripción detallada
- 🚀 Aplicación Completa (Standalone) - Archivo único con todo incluido
- 📱 Aplicación Modular - Versión con archivos separados
- 📂 Repositorio - Código fuente completo
GitHub Pages sirve automáticamente los archivos estáticos desde:
- URL base:
https://lfern.github.io/personal-2fa/ - Archivos servidos: Todo lo que esté en la rama
main - Carpeta dist/: Los builds de producción están disponibles directamente
✅ Sin instalación: Funciona inmediatamente desde el navegador
✅ Siempre actualizado: Refleja la última versión del repositorio
✅ HTTPS garantizado: GitHub Pages siempre usa HTTPS
✅ Código verificable: Puedes inspeccionar el código fuente en el repositorio
✅ Completamente funcional: Incluye todas las características
- Verifica el código: Revisa el repositorio antes de usar
- Descarga local: Para uso sensible, descarga y ejecuta localmente
- Inspecciona la red: Confirma que no hay requests externos (F12 → Network)
- Hash del archivo: Compara checksums si quieres estar 100% seguro
MIT License - Usa bajo tu responsabilidad
Sí, si verificas el código fuente y usas HTTPS/localhost. Todo funciona offline y se cifra localmente.
El código está diseñado para ser 100% legible e inspecciónable. Revisa especialmente los módulos crypto.js y storage.js.
Los datos se pierden permanentemente. Mantén backups seguros.
Sí, en navegadores móviles modernos. Para mejor experiencia, considera una PWA.
NO. Todo funciona offline. Los exports son solo para que tú los uses en otras apps.
Si eres fork/colaborador y quieres habilitar GitHub Pages en tu repositorio:
- Ve a tu repositorio en GitHub
- Settings → Pages (en el menú lateral)
- Source: Deploy from a branch
- Branch:
main - Folder:
/docs - Save → Esperar 1-2 minutos
https://[tu-usuario].github.io/personal-2fa/personal-2fa-standalone.html
# Verificar que el enlace responde
curl -I https://[tu-usuario].github.io/personal-2fa/dist/personal-2fa-standalone.html
# Debe retornar HTTP 200 OK🔒 Personal 2FA - Tu seguridad, tu control, tu dispositivo.