obf_runs: how obfuscated articles come in runs (strict, and per poster and tool with a time gap). obf_kinds: what they are (unquoted subjects with a counter, random tokens equal to the message-id, other random tokens, ...), with examples. LOG.md 2026-10-11 (5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
2.1 KiB
TypeScript
44 lines
2.1 KiB
TypeScript
/**
|
|
* What the obfuscated lines of a capture are (LOG.md 2026-10-11 (5)):
|
|
* unquoted subjects with a counter ("Name.exe (1/2)", parseable without
|
|
* quotes), random tokens equal to the message-id's local part (ngPost-style
|
|
* private uploads), other random tokens, and the rest; with examples.
|
|
*
|
|
* node --import=@poppinss/ts-exec tools/obf_kinds.ts <capture dir>...
|
|
*/
|
|
import { readFile, readdir } from 'node:fs/promises'
|
|
import { join } from 'node:path'
|
|
import { unzipSync } from 'node:zlib'
|
|
import { SegmentScanner, scanOverviewText } from '#lib/edge/scan'
|
|
|
|
for (const dir of process.argv.slice(2)) {
|
|
const { group } = JSON.parse(await readFile(join(dir, 'range.json'), 'utf8'))
|
|
const scanner = new SegmentScanner()
|
|
const kinds = new Map<string, { n: number; examples: string[] }>()
|
|
let obfuscated = 0
|
|
const add = (kind: string, subject: string) => {
|
|
const k = kinds.get(kind) ?? { n: 0, examples: [] }
|
|
k.n++
|
|
if (k.examples.length < 3) k.examples.push(subject.slice(0, 90))
|
|
kinds.set(kind, k)
|
|
}
|
|
for (const file of (await readdir(dir)).filter((f) => f.endsWith('.gz')).sort()) {
|
|
scanOverviewText(unzipSync(await readFile(join(dir, file))).toString('utf8'), (n, subject, from, date, messageId, bytes, xref) => {
|
|
if (xref && scanner.owner(xref, group, { [group]: 1 }) !== group) return
|
|
if (scanner.segment(n, subject, from, date, messageId, bytes, xref, group)) return
|
|
obfuscated++
|
|
const local = messageId.replace(/^</, '').split('@')[0]
|
|
const s = subject.trim()
|
|
if (/\(\d+\/\d+\)\s*$/.test(s) || /\[\d+\/\d+\]\s*$/.test(s)) add(/"/.test(s) ? 'counter, quoted name not parsed' : 'counter, unquoted name', s)
|
|
else if (s === local) add('random = message-id', s)
|
|
else if (/^[A-Za-z0-9]{16,}$/.test(s)) add('random token', s)
|
|
else if (/yEnc/i.test(s)) add('yEnc, no counter', s)
|
|
else add('other', s)
|
|
})
|
|
}
|
|
console.log(`== ${dir}: ${obfuscated} obfuscated`)
|
|
for (const [kind, k] of [...kinds].sort((a, b) => b[1].n - a[1].n)) {
|
|
console.log(` ${kind}: ${k.n} (${((100 * k.n) / obfuscated).toFixed(1)}%) e.g. ${k.examples.map((e) => JSON.stringify(e)).join(' | ')}`)
|
|
}
|
|
}
|