-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
api server: deploy endpoint: validate uploaded tarball #28
Labels
enhancement
New feature or request
Comments
|
example code starting point: const tar = require('tar');
const zlib = require('zlib');
const stream = require('stream');
async function copyTarGzInMemory(sourceStream, destinationStream, maxFileSize = 4 * 1024 * 1024, maxFiles = 1024) {
const files = [];
let fileCount = 0; // Counter for the number of files
// Step 1: Extract files in memory
const extract = new tar.Parse({
onentry: (entry) => {
// Increment file count and enforce file limit
fileCount++;
if (fileCount > maxFiles) {
throw new Error(`Tarball contains more than the allowed number of files (${maxFiles}).`);
}
// Reject symbolic links
if (entry.type === 'SymbolicLink') {
throw new Error(`Symbolic links are not allowed: ${entry.path}`);
}
// Reject files with invalid paths
if (entry.path.includes('..') || entry.path.startsWith('/')) {
throw new Error(`Invalid file path detected: ${entry.path}`);
}
// Accumulate files for later repacking
let fileSize = 0;
const chunks = [];
entry.on('data', (chunk) => {
fileSize += chunk.length;
if (fileSize > maxFileSize) {
throw new Error(`File ${entry.path} exceeds maximum allowed size (${maxFileSize} bytes).`);
}
chunks.push(chunk);
});
entry.on('end', () => {
files.push({ path: entry.path, content: Buffer.concat(chunks) });
});
},
});
await new Promise((resolve, reject) => {
sourceStream
.pipe(zlib.createGunzip()) // Decompress the tar.gz
.pipe(extract) // Parse and extract files
.on('error', reject)
.on('finish', resolve);
});
// Step 2: Repack files into a new tar.gz
const pack = new tar.Pack({ gzip: true, portable: true });
const repackStream = stream.Readable.from(
files.map((file) => ({
path: file.path,
content: file.content,
}))
).pipe(pack);
await new Promise((resolve, reject) => {
repackStream.pipe(destinationStream).on('error', reject).on('finish', resolve);
});
}
module.exports = copyTarGzInMemory; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
No description provided.
The text was updated successfully, but these errors were encountered: