diff --git a/src/detect.js b/src/detect.js index 99e3572..46ba1cd 100644 --- a/src/detect.js +++ b/src/detect.js @@ -13,7 +13,7 @@ const { rules } = require('./rules'); const { entropy } = require('./entropy'); -const { isCamelIdentifier } = require('./forms'); +const { isCamelIdentifier, commonForm } = require('./forms'); // Labels in English, Portuguese and Spanish. The value is the first run of // non-space, non-quote characters after the separator. @@ -495,6 +495,8 @@ function scanContextual(text, taken) { if ((opens || closes) && opens !== next[0]) continue; const p = profileOf(text, value, start, end); if (!p || !contextToken(value, p.cued)) continue; + // `ref: -<64 hex>` ends every monitor event: it names an event, so only a credential word right before it makes it a candidate. + if (!p.cued && commonForm(value) === 'eventref') continue; out.push({ rule: 'contextual', name: `Credential by context (${p.profile})`, value, start, end, confidence: 'medium', profile: p.profile }); } return out; diff --git a/src/forms.js b/src/forms.js index 9e7f6ff..0a27641 100644 --- a/src/forms.js +++ b/src/forms.js @@ -79,10 +79,10 @@ const isMessageId = (w) => /^3EB0[0-9A-F]{16,28}$/.test(w); // prefix that sessions quote to name a value without showing it. Too short to be a key. const isShortHash = (w) => /^(?=[a-f]*\d)(?=\d*[a-f])[0-9a-f]{7,12}$/.test(w); -// The reference a monitor event carries after `ref:`: an id of 6 to 12 lowercase letters and +// The reference a monitor event carries after `ref:`: an id of 6 to 16 lowercase letters and // digits, a hyphen and the 64-hex hash of the event contract (`hn9abcdefg-<64 hex>`). It names // an event; it opens nothing. A provider prefix (`sk-`, `ghp_`...) is judged before this form. -const isEventRef = (w) => /^[a-z0-9]{6,12}-[0-9a-f]{64}$/.test(w) && /[a-z]/.test(w.split('-')[0]); +const isEventRef = (w) => /^[a-z0-9]{6,16}-[0-9a-f]{64}$/.test(w) && /[a-z]/.test(w.split('-')[0]); // A reference to a variable, not its value: `$NOME`, `${NOME}`, a grep anchor `^NOME=`, // an assignment with nothing after the sign `NOME=`. Only when the name is made of words diff --git a/test/travas.test.js b/test/travas.test.js index 566baa3..f29a1ee 100644 --- a/test/travas.test.js +++ b/test/travas.test.js @@ -70,6 +70,14 @@ const cfgWrite = (jev) => fs.writeFileSync(cfgFile, JSON.stringify({ promptMode: check(`id de evento com hash do contrato não é forma forte (${ref.slice(0, 12)}...)`, strongShape(ref), false); check(`id de evento não vai ao classificador (${ref.slice(0, 12)}...)`, candidatesOf(`resumo do monitor ref: ${ref} fim`).length, 0); } + // o ref no fim do evento do monitor não é capturado pelo contexto, em qualquer prefixo + for (const pre of ['hn9u08zc1k', 'hn9abcdefghijkl', 'evt12345ab']) { + const ref = `${pre}-${H64}`; + for (const txt of [`ref: ${ref}`, `[monitor] [resumo]: eventos 101 102\nref: ${ref}`, `resumo de 30 min\nref: ${ref}`]) { + check(`ref do monitor não é achado por contexto (${pre})`, scan(txt, { ambiguous: true, message: true }).findings.length, 0); + } + } + check('ref do monitor com palavra de credencial antes continua achado', scan(`token: hn9u08zc1k-${H64}`, { ambiguous: true, message: true }).findings.length > 0, true); check('prefixo de provedor com 64 hex continua forte', strongShape(`sk-${H64}`), true); check('64 hex puro continua forte', strongShape(H64), true); check('prefixo curto demais com 64 hex continua forte', strongShape(`ab-${H64}`), true);