# 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.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` + `` — 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](tasks.md) secção **Backlog 2FA export**. --- ## Critérios de aceitação (quando implementar) 1. **Given** utilizador concluiu TOTP, **When** vê ecrã códigos, **Then** tem ≥3 opções de guardar (local, copiar, +1 canal). 2. **Given** clica «Guardar no computador», **When** download completa, **Then** ficheiro `.txt` contém 10 códigos + metadados. 3. **Given** clica Telegram/WhatsApp, **When** app abre, **Then** texto pré-preenchido com códigos (utilizador confirma envio). 4. **Given** export concluído, **When** clica «Continuar para onboarding», **Then** fluxo Spec 016 mantém-se (pré-preenchimento wizard). 5. **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 |