Skip to content

fix(security): Move integração do Notion para Cloud Function e remove segredos do bundle do app - #262

Open
jpmcarrilho wants to merge 4 commits into
devfrom
security/remove-client-secrets
Open

jpmcarrilho wants to merge 4 commits into
devfrom
security/remove-client-secrets

Conversation

@jpmcarrilho

Copy link
Copy Markdown
Member

Descrição

Continuação do #257: remove do bundle JS do app os últimos segredos importados de @env e move a integração com o Notion para uma Cloud Function, no mesmo padrão de discordIntegration/stripeApi.

Servidor (server-functions/notionIntegration)

  • Nova função callable notionIntegration (southamerica-east1, runtime nodejs22) que cria a página no banco do Fale Conosco do Notion.
  • Exige autenticação, exceto para type: 'erro' (relatórios anônimos do ErrorBoundary, igual ao discordIntegration).
  • senderId vem de request.auth.uid, não do corpo da requisição (antes qualquer usuário podia informar outro userId).
  • Valida type/message, normaliza reportedTarget desconhecido para none e trunca textos no limite de 2000 caracteres do Notion.
  • reportId (protocolo) passa a ser gerado no servidor; o app recebe apenas { id, object, reportId }.
  • config_all.sh ganha o caso *notion*. Sem ele, a função receberia todas as variáveis do .env (incluindo STRIPE_SECRET_KEY).
  • Variáveis documentadas em .env.sample, server-functions/README.md e notionIntegration/README.md.

App

  • sendMessageToNotionContactUs chama firebaseFunctions.httpsCallable('notionIntegration'); userId sai de NotionContactUsOptions e dos dois chamadores (ContactUsInsertMessage e errorBoundaryHandler).
  • Removidos de environment/index.ts e env.d.ts: SENTRY_AUTH_TOKEN, NOTION_FALECONOSCO_KEY/ID, NOTION_APPICONS_KEY/ID (NOTION_APPICONS_* não era usado em nenhum lugar).
  • SENTRY_AUTH_TOKEN fica apenas como variável do EAS com visibilidade secret (build time).
  • app/README.md documenta quais variáveis podem ficar no .env do app.

Demais variáveis de @env revisadas. Todas são públicas por natureza (config do Firebase client, IDs OAuth, STRIPE_PUBLISHABLE_KEY, DSN_SENTRY), com duas verificações pendentes:

  • ALGOLIA_KEY do app precisa ser uma chave Search-Only (o app só faz search).
  • Chaves do Google Maps precisam estar restritas por app/API no GCP.

Coordenação com feat/upgrade-expo-sdk-57. Aquela branch ainda não foi integrada e não altera nenhum arquivo deste PR. Usei firebaseFunctions.httpsCallable como as demais chamadas em dev; a migração para a API modular (httpsCallable(getFunctions(getApp(), 'southamerica-east1'), 'notionIntegration')) entra junto com as outras na branch do Firebase.

⚠️ Ações necessárias (ordem)

  1. NOTION_FALECONOSCO_KEY e NOTION_FALECONOSCO_ID no .env de server-functions, depois bash config_all.sh e cd notionIntegration && npm run deploy, antes de publicar este código no app.
  2. eas env:set --name SENTRY_AUTH_TOKEN --value <token> --environment production --visibility secret (e development, se necessário).
  3. Rotacionar credenciais. Estes valores foram embutidos nos binários e nas atualizações OTA já publicados, então devem ser considerados comprometidos:
    • Token do Sentry: revogar e gerar um novo Org Auth Token. Não afeta o app em produção; pode ser feito imediatamente.
    • Integração do Notion do Fale Conosco: gerar novo token e atualizar só no servidor. Versões antigas do app, que chamam o Notion direto, deixam de gravar no Notion ao rotacionar; o Discord continua recebendo. Por isso, rotacionar logo após o deploy da função e a publicação do OTA.
    • Integração do Notion de App Icons: não é usada pelo app, então pode ser revogada.
  4. Remover NOTION_* e SENTRY_AUTH_TOKEN do .env local de cada dev e da página de variáveis no Notion.

Teste

  • server-functions/notionIntegration: npm run build sem erros. Teste local do handler compilado (notionIntegration.run(...)), com a API do Notion mockada:
    • chamada anônima com tipo ≠ erro → unauthenticated
    • chamada anônima com erro → grava senderId: anonymous
    • autenticada → senderId = uid do token, ignorando userId enviado pelo cliente
    • tipo inválido ou mensagem vazia → invalid-argument
    • erro do Notion ou variáveis ausentes → internal
    • truncamento em 2000 caracteres, título pelas 15 primeiras palavras e resposta sem o objeto bruto do Notion
  • config_all.sh com .env fictício: notionIntegration recebe somente as 2 variáveis do Notion; discord e stripe inalterados.
  • App: transform do Babel/react-native-dotenv sobre environment/index.ts com o .env real. Em dev, os 5 valores aparecem no JS gerado; nesta branch, nenhum.
  • App: tsc e ESLint sem erros novos nos arquivos alterados. O conjunto de erros do tsc é idêntico ao de dev.
  • Não testado: deploy real da função e envio de Fale Conosco, denúncia e erro no app. Após o deploy em dev, conferir se a página é criada no banco do Notion e se a mensagem chega ao Discord com o mesmo protocolo.

Referências

🤖 Generated with Claude Code

jpmcarrilho and others added 4 commits September 25, 2026 16:46
…rar Fale Conosco no Notion

Move a criação de páginas no banco do Fale Conosco do Notion para uma
Cloud Function callable, seguindo o padrão de discordIntegration, para que
o token da integração deixe de ser embutido no app.

- Exige autenticação, exceto para relatórios do tipo 'erro'
- Usa request.auth.uid como senderId em vez de confiar no corpo da requisição
- Valida tipo, mensagem e alvo da denúncia e trunca textos no limite do Notion
- Gera o protocolo (reportId) no servidor e retorna apenas id/object/reportId
- Runtime nodejs22 (nodejs20 é descomissionado em 2026-10-30)
- config_all.sh passa somente NOTION_FALECONOSCO_KEY/ID para a função
- Documenta as variáveis no .env.sample e no README

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ation

O app deixa de chamar a API do Notion diretamente com NOTION_FALECONOSCO_KEY
e passa a usar firebaseFunctions.httpsCallable('notionIntegration').
O remetente passa a ser identificado no servidor pelo token de autenticação,
então userId sai de NotionContactUsOptions e dos dois chamadores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… do app

SENTRY_AUTH_TOKEN, NOTION_FALECONOSCO_KEY/ID e NOTION_APPICONS_KEY/ID eram
importados de @env e, por isso, embutidos pelo react-native-dotenv no bundle
JS distribuído nas lojas e nas atualizações OTA.

- SENTRY_AUTH_TOKEN só é necessário em tempo de build (upload de source maps)
- NOTION_FALECONOSCO_* agora vivem apenas na função notionIntegration
- NOTION_APPICONS_* não eram usados em nenhum lugar do app

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…RY_AUTH_TOKEN no EAS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant