1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-03 01:39:37 +02:00

Check max ZIP uncompressed size

This commit is contained in:
Chocobozzz 2025-04-07 08:27:38 +02:00
parent 69c851c8e6
commit 473cd4f7ef
No known key found for this signature in database
GPG key ID: 583A612D890159BE
4 changed files with 36 additions and 4 deletions

BIN
packages/tests/fixtures/zip-bomb.zip vendored Normal file

Binary file not shown.

View file

@ -122,7 +122,8 @@ describe('Test user import API validators', function () {
'export-without-videos.zip',
'export-bad-structure.zip',
'export-bad-structure.zip',
'export-crash.zip'
'export-crash.zip',
'zip-bomb.zip'
]
const tokens: string[] = []

View file

@ -7,7 +7,14 @@ import { logger, loggerTagsFactory } from './logger.js'
const lTags = loggerTagsFactory('unzip')
export async function unzip (source: string, destination: string) {
export async function unzip (options: {
source: string
destination: string
maxSize: number // in bytes
maxFiles: number
}) {
const { source, destination } = options
await ensureDir(destination)
logger.info(`Unzip ${source} to ${destination}`, lTags())
@ -18,9 +25,25 @@ export async function unzip (source: string, destination: string) {
zipFile.on('error', err => rej(err))
let decompressedSize = 0
let entries = 0
zipFile.readEntry()
zipFile.on('entry', async entry => {
decompressedSize += entry.uncompressedSize
entries++
if (decompressedSize > options.maxSize) {
zipFile.close()
return rej(new Error(`Unzipped size exceeds ${options.maxSize} bytes`))
}
if (entries > options.maxFiles) {
zipFile.close()
return rej(new Error(`Unzipped files count exceeds ${options.maxFiles}`))
}
const entryPath = join(destination, entry.fileName)
try {

View file

@ -1,5 +1,5 @@
import { UserImportResultSummary, UserImportState } from '@peertube/peertube-models'
import { getFilenameWithoutExt } from '@peertube/peertube-node-utils'
import { getFilenameWithoutExt, getFileSize } from '@peertube/peertube-node-utils'
import { saveInTransactionWithRetries } from '@server/helpers/database-utils.js'
import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
import { unzip } from '@server/helpers/unzip.js'
@ -20,6 +20,7 @@ import { UserVideoHistoryImporter } from './importers/user-video-history-importe
import { VideoPlaylistsImporter } from './importers/video-playlists-importer.js'
import { VideosImporter } from './importers/videos-importer.js'
import { WatchedWordsListsImporter } from './importers/watched-words-lists-importer.js'
import { parseBytes } from '@server/helpers/core-utils.js'
const lTags = loggerTagsFactory('user-import')
@ -51,7 +52,14 @@ export class UserImporter {
const inputZip = getFSUserImportFilePath(importModel)
this.extractedDirectory = join(dirname(inputZip), getFilenameWithoutExt(inputZip))
await unzip(inputZip, this.extractedDirectory)
await unzip({
source: inputZip,
destination: this.extractedDirectory,
// Videos that take a lot of space don't have a good compression ratio
// Keep a minimum of 1GB if the archive doesn't contain video files
maxSize: Math.max(await getFileSize(inputZip) * 2, parseBytes('1GB')),
maxFiles: 10000
})
const user = await UserModel.loadByIdFull(importModel.userId)