7z: encrypted headers are known from the encoded header, without bsdtar
Test and deploy / test (push) Successful in 2m6s
Test and deploy / deploy (push) Successful in 2m25s

85% of the 7z archives inspected have encrypted headers (-mhe). Their
encoded header lists the 7zAES coder, so the packed header stream is no
longer downloaded and bsdtar no longer runs for them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-06 10:23:32 +02:00
1 parent 9ae15ed26f
commit 4d3cb6474c
3 files changed
+97 -2

No files matched your search

+5 -1
View File
@@ -11,6 +11,7 @@ import { decodeSegment, type DecodedSegment } from '#lib/yenc/index'
import type { RarInfo } from '#lib/rar/index'
import {
checkHeader,
encodedHeaderEncrypted,
listingStart,
parseBsdtarListing,
parseSevenZipStart,
@@ -70,6 +71,8 @@ class SevenZipService {
const tail = await this.readTail(volumes[volumes.length - 1], start)
if (!tail) return null
// Encrypted headers (-mhe): known from the header alone, no listing possible (most 7z uploads).
if ('headersEncrypted' in tail) return this.info([], true, true, volumes.length > 1)
const dir = await mkdtemp(path.join(tmpdir(), '7z-'))
try {
@@ -140,7 +143,7 @@ class SevenZipService {
* CRC) and, for an encoded header, the packed stream before it. `from` is
* its position in the whole archive.
*/
private async readTail(last: any, start: SevenZipStart): Promise<{ from: number; data: Buffer } | null> {
private async readTail(last: any, start: SevenZipStart): Promise<{ from: number; data: Buffer } | { headersEncrypted: true } | null> {
const ids = new Map(segmentsOf(last).map((s) => [s.number, s]))
const numbers = [...ids.keys()]
if (numbers.length === 0) return null
@@ -180,6 +183,7 @@ class SevenZipService {
const header = await read(start.headerStart, start.archiveSize)
if (!header || !checkHeader(start, header)) return null
if (encodedHeaderEncrypted(header)) return { headersEncrypted: true }
const from = Math.min(listingStart(start, header), start.headerStart)
if (start.archiveSize - from > MAX_TAIL_BYTES) return null
const data = await read(from, start.archiveSize)