Repository navigation
Codex/meta coexistence upstream - #2750
Open
christianini-debug wants to merge 145 commits into
Open
christianini-debug wants to merge 145 commits into
christianini-debug wants to merge 145 commits into
Conversation
Introduces a new API endpoint and supporting logic to decrypt WhatsApp poll votes. Adds DecryptPollVoteDto, validation schema, controller method, and service logic to process and aggregate poll vote results based on poll creation message key.
Updated DecryptPollVoteDto to use a nested message.key structure and moved remoteJid to the top level. Adjusted the controller and validation schema to match the new structure for consistency and clarity.
feat(channel): add support for @newsletter in sendMessage and findChannels
…elop Feature: Endpoint para Descriptografar e Visualizar Votos de Enquetes
…es in chat controller
…tejid-wrong-format fix(baileys): normalize remote JIDs for consistent database lookups
… in contact cache
…tejid-normalization-and-cache-race fix: normalize remoteJid in message updates and handle race condition in contact cache
- Introduced a flag to prevent reconnection during instance deletion. - Improved logging for connection updates and errors during logout. - Added a delay before reconnection attempts to avoid rapid loops. - Enhanced webhook headers for better tracking and debugging. - Updated configuration to support manual Baileys version setting.
…QL, and PSQL Bouncer schemas
Creates new migration to ensure lid column exists even in databases where it was previously dropped by the Kafka integration migration. Uses prepared statement to check column existence before adding, ensuring compatibility with both fresh and existing installations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add audio-decode library for audio buffer analysis - Implement getAudioDuration() to extract duration from audio - Implement getAudioWaveform() to generate 64-value waveform array - Normalize waveform values to 0-100 range for WhatsApp compatibility - Change audio bitrate from 128k to 48k per WhatsApp PTT requirements - Add Baileys patch to prevent waveform overwrite - Increase Node.js heap size for build to prevent OOM Fixes evolution-foundation#1086
…preview - Fix linkPreview logic in Baileys to default to true - Add support for 'file' and 'embed' types in Typebot integration - Ensure correct media type detection for PDFs and docs
…ng, Typebot integration, and comprehensive API functionalities for chat, group, and business profiles.
…tions, messages, groups, profiles, and integrating with Chatwoot, OpenAI, and S3.
…ryption, and channel fetching
…n/fix/logout-baileys fix: logout instance
AxiosHeaderValue widened to include number; explicit String() cast keeps runtime behavior and unblocks tsc --noEmit.
When EVOLUTION_OPERATOR_EMAIL is set in .env, initializeRuntime silently calls the licensing server's /v1/register/auto endpoint on startup, persists the returned api_key and activates the instance — skipping the browser registration flow entirely. Falls back to the manual registration flow on any failure (email not yet registered, server unreachable, key suspended, etc.). Non-fatal. Requires one prior manual registration so the email is known server-side.
…volution-foundation#2544) After WhatsApp's LID (Linked Identity) migration, DMs to contacts that resolve to @lid JIDs fail with a BadRequestException because onWhatsApp returns exists:false for LID-based identifiers. Add @lid to the whitelist alongside @broadcast in both sendMessageWithTyping and sendPresence so these contacts are not rejected by the existence check. Co-authored-by: CORREIA Eduardo <eduardo.correia@hexagon.com>
…olution-foundation#2485) (evolution-foundation#2516) The `audioWhatsapp` method was not forwarding `data.quoted` to `sendMessageWithTyping`, so audio messages sent with a `quoted` key were delivered as standalone messages instead of replies. Added `quoted: data?.quoted` to the options object in both `sendMessageWithTyping` call sites inside `audioWhatsapp` (the encoding path and the direct path), matching the pattern used by all other message-sending methods (textMessage, pollMessage, etc.). Co-authored-by: octo-patch <octo-patch@github.com>
…ose' state (evolution-foundation#2420) Evolution is a webhook-based integration that should always be considered 'open' since it passively receives events. Three changes fix the issue: 1. monitor.service.ts: Always call connectToWhatsapp() for Evolution instances on server restart, regardless of stored connection status. 2. instance.controller.ts: Call connectToWhatsapp() for Evolution instances during creation to initialize Chatwoot settings. 3. evolution.channel.service.ts: Restore stateConnection to 'open' and persist it to DB when connectToWhatsapp() is called in init mode. Closes evolution-foundation#2419 https://claude.ai/code/session_013wxk4cj5U2H5fr2cxCgWdH Co-authored-by: Claude <noreply@anthropic.com>
…ion#2546) Prevents instances with trailing/leading whitespace in their names from becoming undeletable via the API or UI. Fixes evolution-foundation#2543.
…foundation#2540) * feat: add gifPlayback support for video messages Allow gifPlayback and gifAttribution options to be passed to Baileys video messages. * feat: add gif options to media DTOs Add gifPlayback and gifAttribution properties to media DTO definitions. * feat: add gif fields to media message schema Add gifPlayback and gifAttribution validation support to media message schema. * fix: validate gifAttribution values before assignment Prevent invalid gifAttribution values from reaching Baileys media payload.
Stabilization release on top of 2.4.0-rc1. No DB or HTTP contract changes — fixes in WhatsApp/Baileys (@lid bypass, audio quoted, instanceName trim) and Evolution Channel (instances stuck in close), native GIF send support, and optional headless licensing auto-activation via EVOLUTION_OPERATOR_EMAIL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…m:error 515 (evolution-foundation#2509) * fix(baileys): prevent healthy instances from being killed after stream:error 515 When WhatsApp sends stream:error code=515 (Connection Replaced), Baileys handles the reconnect correctly and fires connection.update with state='open'. However, WhatsApp then sends a 401 (loggedOut) to clean up the old session slot, which Evolution API incorrectly treated as a real logout, killing the newly-connected healthy instance. The fix tracks when a stream:error 515 node arrives via the CB:stream:error WebSocket event. If a loggedOut (401) close event fires within 30 seconds of a 515, it is treated as a transient reconnect rather than a real logout. Fixes evolution-foundation#2498 * fix(baileys): name the 515 reconnect grace + tighten stream-error types Addresses sourcery-ai review feedback on the previous commit: - Extract the 30 000ms reconnect grace window into a named class constant STREAM_515_RECONNECT_GRACE_MS so future tuning is self-documenting rather than a literal scattered through the close handler. - Extract the magic '515' string into STREAM_ERROR_CODE_RECONNECT. - Replace the loose 'node: any' on the 'CB:stream:error' handler with a minimal structural type ({ attrs?: { code?: string | number } }) so the payload shape is documented and type-checked. - Compare the code via String(...) so a numeric 515 from the underlying socket library still triggers the grace window — the original literal '515' check would have silently broken on a type change. * fix(baileys): satisfy prettier — collapse 515 reconnect guard onto one line Check Code Quality lint failed on prettier/prettier (the recentStream515 expression fits within the project's 120-col printWidth on a single line, while shouldReconnect still needs to break across two). Co-authored-by: Octopus <liyuan851277048@icloud.com> --------- Co-authored-by: octo-patch <octo-patch@github.com> Co-authored-by: octo-patch <octo-patch@users.noreply.github.com>
…hName in fetchChats (evolution-foundation#2460) * refactor(channel): remove unused pushName field * refactor(channel): simplify pushName assignment logic * fix(channel): remove Message.pushName fallback from MySQL CASE query * fix(channel): remove duplicated pushName alias and prefer Contact.pushName in fetchChats
…olution-foundation#2514) * fix(meta): handle message_echoes and guard missing contact fields * feat(meta): fallback pushName from persisted contact on cloud api * fix(meta): address review feedback on remoteId and status fromMe
…-foundation#2483) * feat(chat): add fetchLid endpoint for PN to LID resolution * fix(pr-feedback): log error when failing to fetch LID for WUID * chore: trigger CI --------- Co-authored-by: shennawy <m.alshenaawy@mu.edu.sa>
…(CVE pending, evolution-foundation#2435) (evolution-foundation#2549) * security: prevent cross-instance auth bypass via query/body override (evolution-foundation#2435) The auth guard in src/api/guards/auth.guard.ts validates instance ownership using req.params.instanceName. The abstract router then merged req.query (and, on /instance/create, req.body) into the instance object via Object.assign — which silently overwrote the already-authenticated instanceName. An attacker with one valid token could send: GET /chat/findMessages/MY_INSTANCE?instanceName=VICTIM_INSTANCE Auth passed for MY_INSTANCE, but dataValidate() then replaced the instance with VICTIM_INSTANCE before execute() ran — giving the caller full access to read/send messages, modify settings, and delete other tenants' instances. CWE-639: Authorization Bypass Through User-Controlled Key Fix: introduce sanitizeUntrustedInput() that strips PROTECTED_INSTANCE_FIELDS (instanceName, instanceId) from any untrusted source before merging into the instance object. Logs a warning on attempts so abuse is auditable. Closes evolution-foundation#2435 Reported by @lighthousekeeper1212 via static analysis. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(lint): remove extra blank line introduced by recent merge Pre-push lint flagged whatsapp.baileys.service.ts:531 (double blank line after the stream:error 515 fix merged via evolution-foundation#2509). Trivial prettier fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-foundation#2577) * fix(gitignore): exclude _evo* files from version control * feat(channel): add EvoHub channel (Phase 1 — link-existing) EvoHub é um canal adicional, espelho transparente do canal Meta (Cloud API) roteado pelo proxy do EvoHub. Não altera o comportamento do canal Meta existente. Data-plane: EvoHubStartupService extends BusinessStartupService, sobrescreve só o transporte (URL {HUB}/meta sem versão + Bearer channel_token). Control-plane: EvoHubClient + rotas /evohub/* (apikey global). Fase 1 entrega o fluxo link-existing (resolve token + phone_number_id server-side via GET /api/v1/channels/:id; o front nunca vê o token). Webhook: EvoHubController reusa o parser Meta + valida HMAC X-Hub-Signature-256 sobre raw body (soft-mode na Fase 1). Edição mínima na base Meta (autorizada): 3 private→protected + helper fetchMediaFromGraph (JS emitido idêntico; bloco S3 inline roteado pelo helper p/ evitar vazamento de mídia inbound EvoHub para a Meta com S3 ligado). tsc --noEmit verde, eslint limpo, tsup build success. * fix(evohub): normalize hub channel list response + correct self endpoints - listChannels: o hub retorna { channels: [...], count } (channel_handler.go GetChannels), não um array nu — causava 'channels.filter is not a function' na rota /evohub/available-channels. Adiciona normalizeChannelList (tolera channels|data|array nu). - getPlan/getMetaAppOptions: corrige paths para /me/plan e /me/meta-app-options (endpoints self-service do hub; /plan é admin-por-id e exige UUID). Fase 2. * fix(evohub): provision request mapping + channel list normalization + filtros whatsapp - evohub.client: listChannels normaliza a resposta do hub { channels: [] } (não array nu) — corrige 'channels.filter is not a function'. - evohub.client.provisionChannel: monta o request correto do hub { name, type, channel_credentials_id?, webhook_url } (antes passava o body cru → 400) e registra o webhook do evolution-api (single-shot, register-with-own-secret). Normaliza a resposta { channel } | plano. - getPlan/getMetaAppOptions: paths corretos /me/plan e /me/meta-app-options. - controlplane.router: /provision mapeia instanceName→name, fixa type=whatsapp, monta webhook_url do SERVER.URL; /available-channels filtra só type=whatsapp (evolution-api é API de WhatsApp; o hub devolve fb/ig também). - env: EVOLUTION_HUB_FRONTEND_URL default corrigido p/ o domínio do hub. * build(manager): rebuild manager-v2 com o canal EvoHub (Fase 1) Atualiza manager/dist com o build do evolution-manager-v2 incluindo a opção de canal EvoHub na criação de instância (vincular-existente + criar-novo).
…5, ESLint 10, Redis 6, TS 6 (evolution-foundation#2575) * chore(deps): bump baileys 7.0.0-rc.9 -> rc13 and drop obsolete waveform patch - baileys atualizado para a ultima versao publicada (rc13) - remove patches/baileys+7.0.0-rc.6.patch: a correcao de waveform PTT (requiresWaveformProcessing) ja foi incorporada upstream no rc13 - API additionalNodes do relayMessage confirmada identica: botoes/lista/carrossel preservados - adiciona ATUALIZACAO-DEPENDENCIAS.md (plano de atualizacao em tiers) tsc --noEmit e build (tsup) passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(deps): tier 1 - safe minor/patch bumps within same major - runtime: axios 1.17, @sentry/node 10.56, pg 8.21, dayjs, jimp, socket.io(+client) 4.8.3, minio, mediainfo.js, libphonenumber-js, jsonwebtoken, cors, fetch-socks, multer 2.1, @aws-sdk/client-sqs, prisma+@prisma/client 6.19.3, undici 7.27 - dev: prettier 3.8, tsx 4.22, @typescript-eslint/* 8.60, eslint-plugin-prettier, @types/node 24, lint-staged 16 - fix(types): cast response.headers['content-type'] as string (axios 1.17 endureceu AxiosHeaderValue) em whatsapp.baileys.service.ts e chatwoot.service.ts tsc --noEmit e build passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(deps): tier 2 - low/medium-risk majors - uuid 14, dotenv 17, node-cron 4, i18next 26, @paralleldrive/cuid2 3, class-validator 0.15, pusher 5.3, mime-types 3 (+@types/mime-types 3), amqplib 2 - fix(rabbitmq): coerce url.port para Number (amqplib 2 exige port:number) - mantidos na faixa de peer do baileys rc13 (evita ERESOLVE/quebra interna): audio-decode 2, link-preview-js 3, pino 9, jimp 1.6 - adiados (majors ESM-only que exigiriam mudar moduleResolution): https-proxy-agent 9, socks-proxy-agent 10, undici 8 -> mantidos em 7/8/7 tsc --noEmit e build passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(deps): tier 3a - migrate to eslint 10 flat config - eslint 8 -> 10 com eslint.config.mjs (flat config), removendo .eslintrc.js e .eslintignore - substitui @typescript-eslint/eslint-plugin+parser pelo meta-pacote typescript-eslint 8 - troca eslint-plugin-import (sem suporte a eslint 10) por eslint-plugin-import-x 4 (regras import-x/first e import-x/no-duplicates) - simple-import-sort 13, @commitlint/* 21, lint-staged 17, globals - desativa regras novas do recommended do eslint 10 (preserve-caught-error, no-useless-assignment) para preservar baseline - scripts lint/lint:check sem --ext (flat config) - reinstalacao limpa da arvore (lock regenerado, peers do baileys respeitados) lint:check, tsc --noEmit e build passam limpos (apos prisma generate). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(deps): tier 3b - migrate to express 5 - express 4 -> 5 (+@types/express 5), movido de volta para dependencies - rotas wildcard adaptadas ao path-to-regexp v8: - index.router.ts: /assets/* -> /assets/*splat (req.params.splat agora e array, juntado com '/') - view.router.ts: '*' -> /{*splat} - cast 'as string' em req.params.<id> nos 7 routers de chatbot (req.params agora e string|string[] no @types/express 5; rotas :param sempre retornam string) tsc --noEmit, lint e build passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(deps): tier 3c - openai 6 + remove express-async-errors (incompativel com express 5) - openai 4 -> 6: beta.threads.runs.retrieve/submitToolOutputs agora recebem runId e thread_id no objeto de params - remove express-async-errors (peer so suporta express 4; express 5 ja trata erros async de handlers nativamente) e seu import em abstract.router.ts tsc --noEmit, lint e build passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(deps): tier 3d - redis (node-redis) 4 -> 6 - redis 4 -> 6: cast 'as string' no retorno de get()/hGet() em rediscache.ts (redis 6/RESP3 tipa retorno como string|{}; JSON.parse exige string) - has() ja tratava exists() > 0 (exists retorna numero) tsc --noEmit, lint e build passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(deps): tier 3e - typescript 5 -> 6 - typescript 5.7 -> 6.0.3 (compativel com typescript-eslint <6.1.0) - adiciona 'ignoreDeprecations: 6.0' no tsconfig: baseUrl e moduleResolution=node10 viraram deprecation-error no TS 6; migracao real (node16/bundler) exigiria extensoes .js em todos os imports — adiado para o TS 7 tsc --noEmit, lint e build passam limpos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: atualiza plano de dependencias com progresso dos tiers 0-3 e notas finais Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(deps): override whatsapp-rust-bridge to 0.5.5 (fix CJS runtime resolution) - baileys rc13 depende de whatsapp-rust-bridge@0.5.4 (ESM-only, exports so com 'import'): app nao sobe via tsx/require (ERR_PACKAGE_PATH_NOT_EXPORTED) - 0.5.5 adiciona condicao 'require' nos exports -> resolve em contexto CommonJS (Node 24 suporta require de ESM) - aplicado via overrides no package.json Validado: require do modulo funciona e dev:server inicializa toda a stack ate a conexao de infra (DB/Redis). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(deps): tier 3f - moduleResolution bundler + proxy agents 9/10 - tsconfig: module CommonJS->preserve, moduleResolution node10->bundler - remove baseUrl e ignoreDeprecations: elimina por completo a divida de deprecacao do TS 6/7 (node10 e baseUrl); paths resolvem relativo ao tsconfig (validado em tsc, tsup e tsx) - https-proxy-agent 7->9 e socks-proxy-agent 8->10 (majors ESM-only, agora resolviveis com bundler) - src nao usa require()/export = (compativel com module preserve) Validado: tsc, lint, build limpos; dev:server carrega TODOS os modulos (aliases + proxy agents ESM-only) ate a fronteira de infra (auth do Postgres). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(deps)!: tier 4 - migrate to Prisma 7 (driver adapters + prisma-client generator) BREAKING: Prisma 6 -> 7 (ESM-only, driver adapters obrigatorios) - @prisma/client+prisma 7.8.0; adiciona @prisma/adapter-pg e @prisma/adapter-mariadb - generator 'prisma-client-js' -> 'prisma-client' com output ./generated/client (TS gerado) nos 3 schemas (postgresql, mysql, psql_bouncer); url removida do datasource (proibida no v7) - prisma.config.ts: connection string (datasource.url via DATABASE_CONNECTION_URI) + selecao dinamica de schema/migrations por DATABASE_PROVIDER (multi-provider) - repository.service.ts: instancia PrismaClient com driver adapter conforme provider (PrismaPg | PrismaMariaDb) - alias @prisma/client -> client gerado: no tsconfig (tsx/tsc) e reforcado no tsup (noExternal + esbuild alias), pois esbuild nao honra paths do tsconfig - tsup: shims:true (shim de import.meta.url p/ client v7 no bundle CJS) e platform:node - start:prod usa dist/main.js (CJS) - ESM puro quebra por imports sem extensao do @figuro/chatwoot-sdk - 3 imports de JsonValue: @prisma/client/runtime/library -> /runtime/client (caminho mudou no v7) - prisma/generated/ no .gitignore (gerado por provider via db:generate) Validado: db:generate (postgres+mysql), tsc, lint, build; boot dev (tsx) e prod (node dist/main.js) inicializam ate a query real (DriverAdapterError: AuthenticationFailed = credenciais/infra, nao codigo). HTTP server sobe na porta 3210. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: registra Tier 3f (moduleResolution+proxies) e Tier 4 (Prisma 7) concluidos Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(audio): delega waveform/duracao ao Baileys rc13 nativo (EVO-1670) Remove o getAudioMetadata() redundante: o Baileys rc13 ja calcula seconds/waveform nativamente (getAudioDuration/getAudioWaveform via audio-decode) quando ausentes no envio de PTT. - removido getAudioMetadata() (~50 linhas) e o import orfao de audio-decode - audioWhatsapp() para de passar seconds/waveform nos 2 caminhos; agora URL tambem ganha waveform - audio-decode mantido no package.json (peerOptional usado internamente pelo Baileys) Validado: tsc/lint/build limpos; PTT real -> resposta com seconds:9 + waveform (Uint8Array) gerados pelo Baileys; confirmado visualmente pelo usuario. Ref: EVO-1670 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matheus Pastorini <matheus.pastorini@etus.com.br> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Davidson Gomes <davidsongviolao@gmail.com>
…pendências - tsup.config.ts: fecha esbuildOptions antes do bloco define (erro de sintaxe derrubava o parse do config e abortava o tsup) - evohub.controlplane.router.ts: normaliza req.params.id com String() — no Express 5 req.params é tipado string | string[] e o tsc falhava (TS2345) - package-lock.json: sincroniza version com o package.json (2.4.0) Refs EVO-2097
O fluxo link-existing criava a Instance mas não registrava webhook no hub (só o provision registrava, via single-shot do POST /channels). Resultado: canal vinculado enviava mensagens mas nunca recebia — nenhum evento inbound chegava em /webhook/evohub e não havia erro em lugar algum. - evohub.client.ts: novo ensureChannelWebhook(channelId, url) idempotente — (1) webhook já associado ao canal com a mesma URL: no-op; (2) webhook do usuário com a mesma URL: associa via POST /webhooks/:id/associate (se all_channels, nem associa); (3) cria via POST /webhooks single-shot com channels [channelId] e events [] (vazio = todos). Secret enviado quando EVOLUTION_HUB_WEBHOOK_SECRET setado (register-with-own-secret). Inclui HubWebhookInfo, listChannelWebhooks, listWebhooks e associateWebhook. - evohub.controlplane.router.ts: link-existing garante o webhook ANTES de criar a Instance — falha do hub responde 502 sem efeito colateral (retry seguro); SERVER_URL vazio mantém paridade com o provision (segue sem webhook). - .env.example: documenta o preenchimento das variáveis EvoHub (formato evh_pk_ da API key, SERVER_URL alcançável pelo hub, host local 8086, soft mode do webhook secret). Refs EVO-2098
The Check Code Quality job has been red since dd552c7 and never reached its "Check build" step: Prisma 7's prisma.config.ts resolves datasource.url via env("DATABASE_CONNECTION_URI"), which throws PrismaConfigEnvError when the variable is absent, and the runner has no .env (the Dockerfile copies .env.example, which is why image builds got past this point). prisma generate never opens a connection, so a syntactically valid URI is enough. Without this the build gate stays dead and the next dependency bump breaks develop unnoticed, exactly as this one did. Also aligns the EvoHub req.params.id cast with the convention used by the other 30 call sites in src (as string), instead of String().
ensureChannelWebhook treated any webhook whose status was not exactly 'inactive' as good enough and no-oped. But the hub also auto-moves a webhook to status 'disabled' after repeated delivery failures, and its dispatcher delivers ONLY when status == 'active' (webhook_dispatcher.go:294). So a disabled webhook matched the URL, was accepted, and the channel stayed deaf — the exact "silently not receiving" symptom this feature exists to fix, in a common scenario (evolution-api was down long enough for the hub to disable the webhook; the operator re-links and gets 201 but still receives nothing). Now the guard keys on status === 'active' and reactivates a matching but non-active webhook via PUT /webhooks/:id/status (the hub's official path out of 'disabled'), for both the channel-associated and the user-level webhook. Also validates channel/webhook ids as UUID before interpolating them into the hub request path (assertHubId), closing the CodeQL js/request-forgery paths the new listChannelWebhooks method added and hardening getChannel/connectToMeta. Hub ids are UUIDs (uuid.Parse server-side), so this rejects nothing legitimate. Verified: tsc/eslint/build green, plus a stubbed-http harness driving ensureChannelWebhook through the disabled/active/missing/user-inactive/ all_channels branches and the id guard (10/10 assertions).
…n/fix/EVO-2097-build-develop fix(build): develop não compila — Express 5 quebra rotas EvoHub e tsup.config.ts com erro de sintaxe
… webhook ensureChannelWebhook matched an existing hub webhook by URL alone and reused it as-is. The hub only signs the inbound delivery when the webhook has a secret stored (webhook_dispatcher.go:983) and its WebhookResponse exposes neither the secret nor a has_secret flag (webhook.go:116), so drift is undetectable from the client side. A deployment that ran EvoHub phase 1 in soft mode (empty secret — the documented default) has a hub webhook with NO secret. The moment the operator follows the guidance this branch adds to .env.example and sets EVOLUTION_HUB_WEBHOOK_SECRET, the next link-existing reuses that secret-less webhook, the hub delivers unsigned, verifyHmac answers 401 and the channel is deaf — the very symptom this feature exists to kill. Rotating the secret does the same. Worse: the webhook is shared across channels, so the repeated 401 makes the hub auto-disable it and every EvoHub channel stops receiving. Now every reuse path rewrites the configured secret (PUT /webhooks/:id/secret) BEFORE reactivating the webhook — reactivating first would just take another 401 and get auto-disabled again. Empty secret stays a no-op: the inbound accepts unsigned payloads in soft mode. Verified: tsc/eslint/build green, plus a stubbed-http harness driving the real client through reuse-with-secret, disabled-webhook ordering, soft mode, user-level webhook and the id guard (12/12 assertions). Refs EVO-2098
The UUID guard lived in assertHubId(), a separate method. It blocks path/URL injection at runtime just fine, but CodeQL's taint analysis does not carry a throwing guard across a function boundary, so js/request-forgery kept flagging every method that interpolates a hub id into the request path — the alerts the guard was added to close stayed open. Same check, now inline at each sink (HUB_ID.test), which is what both the scanner and the runtime accept. Behaviour is unchanged: hub ids are UUIDs (uuid.Parse server-side), so nothing legitimate is rejected. Refs EVO-2098
Repo convention is English code comments; the EvoHub comments introduced by this branch were in Portuguese. No behaviour change. Refs EVO-2098
…n/feat/EVO-2098-evohub-link-existing-webhook feat(evohub): registra webhook inbound no hub durante o link-existing
The only patch file (patches/baileys+7.0.0-rc.6.patch) was dropped in dd552c7 when Baileys moved to rc13, which left the directory untracked. The builder still runs COPY ./patches ./patches before npm ci, so every image build since has failed with: failed to compute cache key: "/patches": not found. Keep the directory tracked (patch-package is still wired into postinstall) so the COPY resolves and a future patch works by just dropping in a .patch file.
…n/fix/docker-build-missing-patches-dir fix(docker): restore the patches/ directory the builder copies
Validate Meta POST signatures before dispatch, preserve business ID senders and contact names, and await status delivery. BREAKING CHANGE: Meta POST webhooks require WA_BUSINESS_APP_SECRET. Missing configuration returns 503; invalid signatures return 401.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📋 Description
🔗 Related Issue
Closes #(issue_number)
🧪 Type of Change
🧪 Testing
📸 Screenshots (if applicable)
✅ Checklist
📝 Additional Notes