Spec 016 — Backlog: Exportar códigos backup 2FA
Criado: 2026-06-19
Solicitado por: Roger
Status: 📋 BACKLOG — aguardando implementação
Prioridade: P2 (UX + retenção; não bloqueia onboarding)
Sistema: Portal VM112 (ibytera-mail-portal) — modal PortalTotpSetup.jsx
Agregado a: spec.md (Spec 016)
Relacionado: Spec 004 (Desk — backup codes equivalentes), Spec 021 (segurança wizard)
Contexto
Após activar o TOTP no portal (ligbox.com.br), o utilizador vê o ecrã «Salve estes códigos» com 10 códigos de recuperação de uso único. Hoje só pode ler na tela e clicar «Continuar para o onboarding →».
Problema: utilizadores perdem os códigos por não os guardarem; recuperação posterior é mais difícil.
Pedido Roger: oferecer opções explícitas para guardar os códigos em locais seguros de escolha do utilizador.
Ecrã actual (referência)
┌─────────────────────────────────────────┐
│ 🛡️ Autenticação em duas etapas │
│ Mais segurança para proteger sua conta│
├─────────────────────────────────────────┤
│ Salve estes códigos │
│ Use um código se perder o celular... │
│ │
│ 3A8A8D08 598AF02F │
│ 328CE565 9E6D208A │
│ ... (10 códigos) │
│ │
│ [ NOVO — barra de acções de export ] │
│ │
│ [ Continuar para o onboarding → ] │
└─────────────────────────────────────────┘
Ficheiro: frontend/src/PortalTotpSetup.jsx (estado recoveryCodes)
Requisitos funcionais (backlog)
FR-B01 — Descarregar ficheiro local
| Item |
Detalhe |
| Acção |
Botão «Guardar no computador» / «Descarregar .txt» |
| Formato |
.txt UTF-8 com cabeçalho Ligbox + data + login + 10 códigos |
| Nome ficheiro |
ligbox-codigos-recuperacao-{login}-{YYYYMMDD}.txt |
| API browser |
Blob + <a download> — sem servidor |
| Confirmação |
Checkbox «Guardei os códigos» ou contador mínimo 5s antes de «Continuar» (opcional P2) |
FR-B02 — Google Drive
| Item |
Detalhe |
| Acção |
Botão «Guardar no Google Drive» |
| Método |
Google Picker API ou OAuth scope drive.file — upload de ficheiro .txt |
| Conta |
Conta Google do utilizador (consentimento explícito) |
| Fallback |
Se OAuth falhar → sugerir descarregar local |
FR-B03 — Telegram
| Item |
Detalhe |
| Acção |
Botão «Enviar para Telegram» |
| Método A (MVP) |
Deep link https://t.me/share/url?text= com texto codificado (utilizador escolhe chat) |
| Método B (futuro) |
Bot Ligbox + sendMessage após /start com token one-time |
| Aviso UI |
«Não envie para grupos públicos» |
FR-B04 — WhatsApp
| Item |
Detalhe |
| Acção |
Botão «Enviar para WhatsApp» |
| Método |
Deep link https://wa.me/?text= (Web Share API em mobile quando disponível) |
| Limitação |
Sem API Business no MVP — partilha manual para contacto escolhido |
FR-B05 — Cofre de senhas (password vault)
| Item |
Detalhe |
| Acção |
Botão «Abrir no cofre de senhas» |
| Suporte MVP |
Copiar tudo + instruções para 1Password / Bitwarden / Apple Passwords |
| Suporte fase 2 |
Web Share API → apps instaladas que aceitem text/plain |
| Suporte fase 3 |
Integração 1Password (onepassword:// ou Connect) / Bitwarden (CLI web vault export) — avaliar viabilidade |
| Formato cópia |
Bloco estruturado para colar como Secure Note |
Modelo texto cofre:
Ligbox — Códigos de recuperação 2FA
Conta: {login}
Gerado: {ISO date}
---
{código1}
{código2}
...
Cada código funciona apenas uma vez.
FR-B06 — Copiar todos (complementar)
| Item |
Detalhe |
| Acção |
Botão «Copiar códigos» (já parcialmente previsto noutros fluxos) |
| Feedback |
Toast «Copiado» 2s |
Requisitos não-funcionais
| ID |
Regra |
| NFR-01 |
Códigos nunca enviados para servidor Ligbox excepto armazenamento já existente (recovery_codes hash server-side) |
| NFR-02 |
Exportações cliente-side preferidas (download, clipboard, deep links) |
| NFR-03 |
Google Drive / Telegram bot exigem consentimento explícito antes de upload |
| NFR-04 |
Não logar códigos em plaintext em analytics / webhooks / Desk |
| NFR-05 |
UI pt-BR; ícones reconhecíveis (Drive, Telegram, WhatsApp, cofre) |
| NFR-06 |
Funcionar em desktop e mobile (layout responsivo) |
UX proposta — barra de acções
┌──────────────────────────────────────────────────┐
│ 💾 Computador ☁️ Google Drive 📋 Copiar │
│ ✈️ Telegram 💬 WhatsApp 🔐 Cofre │
└──────────────────────────────────────────────────┘
- Botões secundários (outline), não competir com CTA principal «Continuar».
- Tooltip em cada botão com explicação curta.
- Após qualquer export bem-sucedido: badge «✓ Guardado» no botão correspondente (sessão).
Fases de implementação (backlog)
| Fase |
Entrega |
Esforço |
Prioridade |
| B1 |
Descarregar .txt + Copiar todos |
S |
P2 — quick win |
| B2 |
Deep links Telegram + WhatsApp |
S |
P2 |
| B3 |
Bloco «Cofre» + instruções 1Password/Bitwarden |
S |
P2 |
| B4 |
Google Drive OAuth upload |
M |
P3 |
| B5 |
Telegram Bot Ligbox (opcional) |
L |
P4 |
| B6 |
Web Share API nativo (mobile) |
S |
P3 |
| B7 |
Paridade Spec 004 Desk (activate.html backup export) |
M |
P3 |
Tarefas backlog
Ver tasks.md secção Backlog 2FA export.
Critérios de aceitação (quando implementar)
- Given utilizador concluiu TOTP, When vê ecrã códigos, Then tem ≥3 opções de guardar (local, copiar, +1 canal).
- Given clica «Guardar no computador», When download completa, Then ficheiro
.txt contém 10 códigos + metadados.
- Given clica Telegram/WhatsApp, When app abre, Then texto pré-preenchido com códigos (utilizador confirma envio).
- Given export concluído, When clica «Continuar para onboarding», Then fluxo Spec 016 mantém-se (pré-preenchimento wizard).
- Given auditoria segurança, When revista logs VM112, Then zero códigos em plaintext em logs.
Fora de escopo (esta fase)
- Re-envio de códigos por e-mail (já pode existir noutro fluxo — não duplicar sem revisão)
- Armazenamento Ligbox cloud dos códigos do utilizador
- Integração LastPass / Dashlane proprietária (só via cofre genérico / Web Share)
Referências código
| Ficheiro |
Notas |
frontend/src/PortalTotpSetup.jsx |
Ecrã códigos — ponto de inserção UI |
frontend/src/portalAuth.js |
confirmPortalTotp() → recovery_codes |
frontend/src/ligbox/components/TwoFactorCardHeader.jsx |
Cabeçalho modal |
Spec 004 backup_codes.py |
Padrão Desk (paridade futura) |
Histórico
| Data |
Evento |
| 2026-06-19 |
Roger solicita opções export — registado como backlog agregado Spec 016 |