lib/nntp (XOVER client, Xref, GROUP), lib/headers (subjects, file keys, segments from overview lines; the yEnc path stays behind for phase 2), lib/release (identity, random names, now in lib), lib/files (aggregator, volume names), lib/rules (posting tools, owner by priority, release verdicts), lib/chunks (release chunk codec). Their unit tests came along; new ones for codec, rules and volumes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
28 lines
1.5 KiB
TypeScript
28 lines
1.5 KiB
TypeScript
import { isGenericName } from './identity.js'
|
|
|
|
/**
|
|
* Obfuscated names: one long token of mixed letters and digits, no
|
|
* separators, and the other generated shapes seen on Usenet (LOG.md
|
|
* 2026-10-01 (3)). Kept in step with SQL's is_readable_name().
|
|
*/
|
|
export function looksRandom(name: string): boolean {
|
|
// An unknown short extension (e.g. ".bin") says nothing about the name.
|
|
name = name.replace(/\.[A-Za-z0-9]{1,4}$/, '')
|
|
// VIDEO_TS, Sample, CD1: real words, but no name.
|
|
if (isGenericName(name)) return true
|
|
if (/^[0-9a-f]{16,}$/i.test(name)) return true
|
|
// 6327d9fa2d6acf3e9a61fb053359d5e7.1790574045 (hex and a Unix time)
|
|
if (/^[0-9a-f]{16,}\.\d{9,}$/i.test(name)) return true
|
|
// UUIDs
|
|
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(name)) return true
|
|
// 1650777167 (yEncBin), "83111763 n" (rclone uploads)
|
|
if (/^\d{6,}( n)?$/.test(name)) return true
|
|
// prvjr7hapd0i1ny14pz4, and rclone's long base32 names
|
|
if (/^[a-z0-9]{12,}$/.test(name) && (name.match(/\d/g)?.length ?? 0) >= 2 && (name.match(/[a-z]/g)?.length ?? 0) >= 4) return true
|
|
// wHJ7s71sAGE: short, but capitals all over the token, not only at word starts
|
|
if (/^[A-Za-z0-9]{8,15}$/.test(name) && /\d/.test(name) && /[a-z]/.test(name) && (name.slice(1).match(/[A-Z]/g)?.length ?? 0) >= 3) return true
|
|
if (!/^[A-Za-z0-9]{16,}$/.test(name) || !/[a-z]/.test(name) || !/[A-Z]/.test(name)) return false
|
|
// Digits, or many capitals without separators (e.g. RmISakytFwXSCEzjVEpaKk).
|
|
return /\d/.test(name) || (name.match(/[A-Z]/g) ?? []).length >= 6
|
|
}
|