mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-03 09:49:20 +02:00
Check max ZIP uncompressed size
This commit is contained in:
parent
69c851c8e6
commit
473cd4f7ef
4 changed files with 36 additions and 4 deletions
BIN
packages/tests/fixtures/zip-bomb.zip
vendored
Normal file
BIN
packages/tests/fixtures/zip-bomb.zip
vendored
Normal file
Binary file not shown.
|
@ -122,7 +122,8 @@ describe('Test user import API validators', function () {
|
||||||
'export-without-videos.zip',
|
'export-without-videos.zip',
|
||||||
'export-bad-structure.zip',
|
'export-bad-structure.zip',
|
||||||
'export-bad-structure.zip',
|
'export-bad-structure.zip',
|
||||||
'export-crash.zip'
|
'export-crash.zip',
|
||||||
|
'zip-bomb.zip'
|
||||||
]
|
]
|
||||||
|
|
||||||
const tokens: string[] = []
|
const tokens: string[] = []
|
||||||
|
|
|
@ -7,7 +7,14 @@ import { logger, loggerTagsFactory } from './logger.js'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('unzip')
|
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)
|
await ensureDir(destination)
|
||||||
|
|
||||||
logger.info(`Unzip ${source} to ${destination}`, lTags())
|
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))
|
zipFile.on('error', err => rej(err))
|
||||||
|
|
||||||
|
let decompressedSize = 0
|
||||||
|
let entries = 0
|
||||||
|
|
||||||
zipFile.readEntry()
|
zipFile.readEntry()
|
||||||
|
|
||||||
zipFile.on('entry', async entry => {
|
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)
|
const entryPath = join(destination, entry.fileName)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { UserImportResultSummary, UserImportState } from '@peertube/peertube-models'
|
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 { saveInTransactionWithRetries } from '@server/helpers/database-utils.js'
|
||||||
import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
|
import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
|
||||||
import { unzip } from '@server/helpers/unzip.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 { VideoPlaylistsImporter } from './importers/video-playlists-importer.js'
|
||||||
import { VideosImporter } from './importers/videos-importer.js'
|
import { VideosImporter } from './importers/videos-importer.js'
|
||||||
import { WatchedWordsListsImporter } from './importers/watched-words-lists-importer.js'
|
import { WatchedWordsListsImporter } from './importers/watched-words-lists-importer.js'
|
||||||
|
import { parseBytes } from '@server/helpers/core-utils.js'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
|
@ -51,7 +52,14 @@ export class UserImporter {
|
||||||
const inputZip = getFSUserImportFilePath(importModel)
|
const inputZip = getFSUserImportFilePath(importModel)
|
||||||
this.extractedDirectory = join(dirname(inputZip), getFilenameWithoutExt(inputZip))
|
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)
|
const user = await UserModel.loadByIdFull(importModel.userId)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue