diff --git a/KNOWN-BUGS.md b/KNOWN-BUGS.md index fdeba111..434dd473 100644 --- a/KNOWN-BUGS.md +++ b/KNOWN-BUGS.md @@ -39,6 +39,84 @@ lista de "balão" do CHR1 tem os mesmos 13 antes e depois). ## P0 — quebram o jogo ou mentem para quem mede +### ~~BUG-75 · carteira cripto injetada no documento abria issue de crash como se fosse bug do jogo~~ · RESOLVIDO 21/08 (issues #403 e #404) + +**Sintoma (literal, issues #403 e #404, abertas pelo `crash-fix.yml` em alpha.172):** + +``` +TypeError: undefined is not an object (evaluating 'window.ethereum.selectedAddress = undefined') #403, fingerprint ab1ad30e +TypeError: undefined is not an object (evaluating 'window.ethereum.emit') #404, fingerprint e32cd1e4 +Origem: https://www.csbrasil.online/:1:16 +Stack: global code@https://www.csbrasil.online/:1:16 +``` + +**Não é defeito do jogo, e a prova é tripla.** (1) `window.ethereum`, `selectedAddress` e +qualquer identificador web3 **não existem em nenhum arquivo do repositório**, e +`git log --all -S "window.ethereum"` / `-S "selectedAddress"` não devolvem um único commit — +o `mint-assets.json` é o registro do gerador de modelos 3D (mint.gg), não tem web3. (2) O +fingerprint publicado reproduz EXATAMENTE +`crashFingerprint('error', , 'https://www.csbrasil.online/:1:16')`, ou seja o +`e.filename` é a **própria página**, `lineno=1`, `colno=16`. (3) O único frame é +`global code@` — nenhum arquivo do jogo aparece na pilha. + +É extensão de carteira cripto injetando script **inline no documento**. O próprio +`index.astro` já dizia isso em comentário desde antes: *"extensões de carteira injetam +vários"*. + +**Causa raiz — confirmada.** O `isExternalCrash` (`src/lib/error-provenance.mjs`) inocenta +por **origem**. O Safari reporta script de extensão injetado no mundo da página com o +filename **da página**, então o atalho + +```js +if (sourceOrigin === ownOrigin) return false; +``` + +decidia "é nosso" antes de qualquer outra prova. Daí nenhuma das regex seguintes +(`OPAQUE_RE`, `AMBIENTE_RE`, `CACHE_SPLIT_RE`, `RECOVERABLE_RE`, `MEDIA_ABORT_RE`) mordia e +o `classifyCrash` caía no `return 'codigo'` final — que escala e abre issue. + +As irmãs **#138** (`Cannot redefine property: ethereum`) e **#166** +(`Failed to connect to MetaMask`) são a mesma família, mas traziam `chrome-extension://` no +source/stack e já caíam na `EXTENSION_RE`. O que era novo em #403/#404 é a forma **sem +esquema de extensão em campo nenhum**. + +**Correção, em duas camadas espelhadas** — o mesmo remédio das BUG-51/72/73: + +- `src/lib/error-provenance.mjs` — `CARTEIRA_RE` e o ramo em `isExternalCrash`, na **mesma + posição e pelo mesmo motivo da `VENDOR_RE`**: antes do atalho same-origin, porque a + carteira roda no próprio domínio mas o código é de terceiro. Classe `externo`. A linha + continua gravada no `js_error`; some o disparo automático, não o dado. +- `src/pages/index.astro` — a MESMA redação em `origemDoJogo`. Sem cota nova: carteira cai + no balde do `TETO_EXTERNO` que a BUG-51 já abriu (ao contrário do `TETO_MIDIA`, que a + BUG-73 precisou criar). Com `interna === false` o erro também deixa de virar `erroDoBoot` + e `lancamento.fail` — hoje uma carteira que estoura durante o boot podia ser acusada de + ter derrubado o carregamento do jogo. + +O corte é **estreito de propósito**: exige o NOME do global injetado +(`window.`/`globalThis.`/`self.` + `ethereum|solana|tronWeb|…`), nunca a forma da mensagem. +`ethereum` como palavra solta num texto nosso continua `codigo`, e é isso que o mutante +`carteira-ampla` prova. Cobre a **família** de carteiras e não uma regex por incidente, que +é a crítica que a BUG-72 fez ao padrão antigo. + +**Custo declarado, medido na população real e não estimado.** Reclassificando as **90** +issues `crash-auto` do repositório com o helper de antes e o de depois, exatamente **2** +mudam de classe — a #403 e a #404, `codigo -> externo`. As outras 88 ficam idênticas +(51 `codigo`, 25 `externo`, 12 `recuperavel`). **Nenhuma outra issue deixa de abrir.** + +**Régua:** `EP16` em `tools/eval/error-provenance-check.mjs` (`npm run eval:error-origin`, +já no `check:fast` e no `check:deploy` — nenhum passo novo no portão). Classifica os +payloads REAIS das duas issues (com os fingerprints publicados conferidos contra a receita), +exige que 5 mensagens vizinhas continuem `codigo`, e **executa o `origemDoJogo` recortado do +fonte** — regex de fiação sozinha aprovaria `function origemDoJogo(){ return true; }`. +Carrega ainda uma **invariante de honestidade**: varre `src/` e `public/js/` e fica VERMELHA +no dia em que o jogo passar a ter um `window.ethereum` de verdade, para o corte não virar +mordaça silenciosa sobre código nosso. Mutantes novos: `sem-carteira`, `carteira-ampla` e +`sem-carteira-cliente`, todos acendendo EP16. Cláusulas 15 -> 16, matriz de mutação 42/42. + +**NÃO VERIFICADO:** não há browser nesta máquina, então a reprodução com uma extensão de +carteira de verdade não foi feita — a régua mede a **classificação**, não a injeção. A +tabela `js_error` do Supabase também não foi consultada. + ### ~~BUG-74 · o watchdog de boot relatava uma paráfrase nossa e jogava fora o erro do navegador~~ · RESOLVIDO 19/08 (issue #386) **Sintoma (literal, issue #386, aberta pelo `crash-fix.yml` em 19/08 20:51:29Z):** diff --git a/docs/docs/colaborar.md b/docs/docs/colaborar.md index 2d5b3e07..e8008507 100644 --- a/docs/docs/colaborar.md +++ b/docs/docs/colaborar.md @@ -14,7 +14,7 @@ O número abaixo não é retórica, e não é escrito à mão: sai de `git short {/* BEGIN:GERADO:pessoas — não edite à mão, rode `npm run docs` */} -**11 identidades de autoria humana** assinam commit no histórico **desta branch**: `ruben-cytonic`, `Ruben`, `Emerson Garrido`, `rubenmarcus`, `Ruben Marcus`, `William Oliveira`, `Juan Versolato Lopes`, `daeeseD`, `matheusgb`, `Maná Soares`, `daltonfontes`. O resto dos commits é assinado por agentes de IA. Branch não é repositório: quem contribuiu num ramo que esta branch não contém **não aparece aqui**. +**12 identidades de autoria humana** assinam commit no histórico **desta branch**: `ruben-cytonic`, `Ruben`, `Emerson Garrido`, `rubenmarcus`, `Ruben Marcus`, `William Oliveira`, `Juan Versolato Lopes`, `daeeseD`, `matheusgb`, `Maná Soares`, `daltonfontes`, `nunreasonable`. O resto dos commits é assinado por agentes de IA. Branch não é repositório: quem contribuiu num ramo que esta branch não contém **não aparece aqui**. > Bloco gerado por `node tools/gen-docs.mjs`. Fonte: `git shortlog -sn --no-merges (descontando autores que são agentes)` diff --git a/docs/i18n/en/docusaurus-plugin-content-docs/current/colaborar.md b/docs/i18n/en/docusaurus-plugin-content-docs/current/colaborar.md index ad72a3a1..e6f135e3 100644 --- a/docs/i18n/en/docusaurus-plugin-content-docs/current/colaborar.md +++ b/docs/i18n/en/docusaurus-plugin-content-docs/current/colaborar.md @@ -17,7 +17,7 @@ The number below is not rhetoric, and it is not hand-written: it comes from `git {/* BEGIN:GERADO:pessoas — não edite à mão, rode `npm run docs` */} -**11 human author identities** sign commits in this branch: `ruben-cytonic`, `Ruben`, `Emerson Garrido`, `rubenmarcus`, `Ruben Marcus`, `William Oliveira`, `Juan Versolato Lopes`, `daeeseD`, `matheusgb`, `Maná Soares`, `daltonfontes`. Automated identities are excluded. A Git author name is not necessarily one unique person. +**12 human author identities** sign commits in this branch: `ruben-cytonic`, `Ruben`, `Emerson Garrido`, `rubenmarcus`, `Ruben Marcus`, `William Oliveira`, `Juan Versolato Lopes`, `daeeseD`, `matheusgb`, `Maná Soares`, `daltonfontes`, `nunreasonable`. Automated identities are excluded. A Git author name is not necessarily one unique person. > Block generated by `node tools/gen-docs.mjs`. Source: `git shortlog -sn --no-merges (descontando autores que são agentes)` diff --git a/src/lib/error-provenance.mjs b/src/lib/error-provenance.mjs index f2eb5f27..62d27e3e 100644 --- a/src/lib/error-provenance.mjs +++ b/src/lib/error-provenance.mjs @@ -25,6 +25,9 @@ const OPAQUE_RE = /uncaught exception: undefined|illegal character\s+U\+[0-9a-f] e já exibiu o painel amigável (BUG-44). É ambiente do jogador, não defeito de código — não abre issue (#277/#276/#274: 3 issues automáticas pela mesma causa num dia). */ const AMBIENTE_RE = /^sem_webgl:/i; +// Carteira cripto injeta script inline no documento e o filename vira a própria página: +// same-origin não inocenta. Estreito, exige o nome do global (KNOWN-BUGS.md, BUG-75). +const CARTEIRA_RE = /\b(?:window|globalThis|self)\.(?:ethereum|solana|tronWeb|tronLink|phantom|keplr|BinanceChain|coinbaseWalletExtension|web3)\b|\bCannot redefine property:\s*(?:ethereum|solana|web3)\b|\bFailed to connect to MetaMask\b/i; const normalizedOrigin = (value, base) => { if (!value) return null; @@ -38,6 +41,9 @@ export function isExternalCrash({ message = '', source = '', stack = '' } = {}, if (EXTENSION_RE.test(sourceText)) return true; // Vale antes do atalho same-origin: /_vercel/ é próprio domínio, mas terceiro. if (VENDOR_RE.test(sourceText) || VENDOR_RE.test(String(stack || ''))) return true; + // Mesmo motivo e mesmo lugar da VENDOR_RE: próprio domínio, código de terceiro. + // Vale em qualquer campo — o nome do global É a proveniência (BUG-75). + if (CARTEIRA_RE.test(evidence)) return true; const sourceOrigin = /^https?:\/\//i.test(sourceText) ? normalizedOrigin(sourceText, ownOrigin) diff --git a/src/pages/index.astro b/src/pages/index.astro index 0ee01ece..8e756459 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -185,6 +185,10 @@ window.__GEO_LANG__ = (function () { var vendor = /\/_vercel\//i; if (extensao.test(sourceText)) return false; if (vendor.test(sourceText) || vendor.test(String(stack || ''))) return false; + // MESMA redação da `CARTEIRA_RE` de `src/lib/error-provenance.mjs` - se os dois lados + // discordarem, a carteira volta a comer cota aqui ou a abrir issue lá (BUG-75). + var carteira = /\b(?:window|globalThis|self)\.(?:ethereum|solana|tronWeb|tronLink|phantom|keplr|BinanceChain|coinbaseWalletExtension|web3)\b|\bCannot redefine property:\s*(?:ethereum|solana|web3)\b|\bFailed to connect to MetaMask\b/i; + if (carteira.test(sourceText + '\n' + String(stack || '') + '\n' + String(mensagem || ''))) return false; var propria = location.origin; if (sourceText && /^https?:\/\//i.test(sourceText)) { try {