Spots: more password phrasings; read listed spots' articles and NZBs
passwordFromSpot finds 30 more passwords in the stored descriptions (480 → 510): words between keyword and separator, trailing "!!", the value on the next line, "wachtwoord is x", "… wachtwoord. Deze is: x", "WW x" as a whole line. Listed spots were read from their overview only, so the NZB's own password and the description were unknown for 2.27M of them. SpotService.readListing reads the spot's article and NZB without importing files: details, the NZB password (over a spot-text one), the spot-text password, placeholder NZBs. worker:spots does a batch when idle; spot:postprocess works through the history (nzb_read_at). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
36f84ae3e6
commit
ee898be8c8
8 files changed
+322
-17
No files matched your search
@@ -107,3 +107,77 @@ test.group('SpotService passwords', (group) => {
|
||||
assert.equal(passwordState(null, false), 'none')
|
||||
})
|
||||
})
|
||||
|
||||
test.group('SpotService reading listings', (group) => {
|
||||
group.each.setup(() => testUtils.db().withGlobalTransaction())
|
||||
|
||||
const nzb = (password: string | null, bytes = 700_000_000) => `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<nzb xmlns="http://www.newzbin.com/DTD/2003/nzb"><head>${password ? `<meta type="password">${password}</meta>` : ''}</head>
|
||||
<file poster="p" date="1700000000" subject=""a.part1.rar" yEnc (1/1)"><groups><group>alt.binaries.test</group></groups>
|
||||
<segments><segment bytes="${bytes}" number="1">a1@x</segment></segments></file></nzb>`
|
||||
|
||||
/** A listed spot, as worker:spots leaves an old one, with its article and NZB as given. */
|
||||
async function listedSpot(id: string, read: { description?: string; nzb?: string | null; error?: string }) {
|
||||
await db.table('spots').insert({
|
||||
message_id: id, group_name: 'free.pt', article_number: 1, title: `Listed ${id}`, poster: 'Bart', key_id: 7, size: 700_000_000,
|
||||
posted_at: new Date('2019-05-01T12:00:00Z'), verified: true, created_at: new Date(), status: 'pending',
|
||||
})
|
||||
const [claimed] = await SpotService.claim(10)
|
||||
await SpotService.list([claimed])
|
||||
const service = SpotService as any
|
||||
service.readHead = async () => {
|
||||
if (read.error) throw new Error(read.error)
|
||||
return { header: { size: 700_000_000 }, xml: { description: read.description ?? '', nzbSegments: ['n@x'] } }
|
||||
}
|
||||
service.readNzb = async () => read.nzb ?? null
|
||||
}
|
||||
|
||||
const restore = () => {
|
||||
delete (SpotService as any).readHead
|
||||
delete (SpotService as any).readNzb
|
||||
}
|
||||
group.each.teardown(restore)
|
||||
|
||||
const passwordOf = async (id: string) => {
|
||||
const spot = await db.from('spots').where('message_id', id).first()
|
||||
const release = await db.from('releases').where('id', spot.release_id).first()
|
||||
return { spot, password: release.password, source: release.password_source }
|
||||
}
|
||||
|
||||
test("reads the NZB's password and the details, without importing files", async ({ assert }) => {
|
||||
await listedSpot('l1@spot.net', { description: 'Plot', nzb: nzb('fromnzb1') })
|
||||
assert.deepEqual(await SpotService.readListings(10, 2), { 'nzb-password': 1 })
|
||||
const { spot, password, source } = await passwordOf('l1@spot.net')
|
||||
assert.deepEqual([password, source, spot.status, spot.description], ['fromnzb1', 'nzb', 'listed', 'Plot'])
|
||||
assert.isNotNull(spot.nzb_read_at)
|
||||
assert.equal((await db.from('releases').where('id', spot.release_id).first()).file_count, 0)
|
||||
// Read once: nothing left.
|
||||
assert.deepEqual(await SpotService.readListings(10, 2), {})
|
||||
})
|
||||
|
||||
test("the spot's text when the NZB has none; the NZB's own password wins over it", async ({ assert }) => {
|
||||
await listedSpot('l2@spot.net', { description: 'Wachtwoord: fromtext2', nzb: nzb(null) })
|
||||
assert.deepEqual(await SpotService.readListings(10, 1), { 'spot-password': 1 })
|
||||
assert.include(await passwordOf('l2@spot.net'), { password: 'fromtext2', source: 'spot' })
|
||||
|
||||
await listedSpot('l3@spot.net', { description: 'Wachtwoord: fromtext3', nzb: nzb('fromnzb3') })
|
||||
await db.from('releases').where('id', (await db.from('spots').where('message_id', 'l3@spot.net').first()).release_id).update({ password: 'fromtext3', password_source: 'spot' })
|
||||
assert.deepEqual(await SpotService.readListings(10, 1), { 'nzb-password': 1 })
|
||||
assert.include(await passwordOf('l3@spot.net'), { password: 'fromnzb3', source: 'nzb' })
|
||||
})
|
||||
|
||||
test('a placeholder NZB hides the listing; a lost connection gives the spot back, a gone article does not', async ({ assert }) => {
|
||||
await listedSpot('l4@spot.net', { nzb: nzb(null, 1500) })
|
||||
assert.deepEqual(await SpotService.readListings(10, 1), { dummy: 1 })
|
||||
assert.equal((await db.from('spots').where('message_id', 'l4@spot.net').first()).status, 'dummy')
|
||||
|
||||
await listedSpot('l5@spot.net', { error: 'Connection reset' })
|
||||
assert.deepEqual(await SpotService.readListings(10, 1), { retry: 1 })
|
||||
assert.isNull((await db.from('spots').where('message_id', 'l5@spot.net').first()).nzb_read_at)
|
||||
|
||||
await db.from('spots').where('message_id', 'l5@spot.net').delete()
|
||||
await listedSpot('l6@spot.net', { error: '430 No Such Article' })
|
||||
assert.deepEqual(await SpotService.readListings(10, 1), { gone: 1 })
|
||||
assert.isNotNull((await db.from('spots').where('message_id', 'l6@spot.net').first()).nzb_read_at)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user