-
-
Notifications
You must be signed in to change notification settings - Fork 437
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
Added zip file upload feature #353
base: main
Are you sure you want to change the base?
Added zip file upload feature #353
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #353 +/- ##
=======================================
Coverage 89.44% 89.44%
=======================================
Files 66 66
Lines 2917 2917
Branches 594 594
=======================================
Hits 2609 2609
Misses 308 308 ☔ View full report in Codecov by Sentry. |
📝 WalkthroughWalkthroughThe pull request introduces several new features and modifications across both client and server code. A new Vue component named Sequence Diagram(s)sequenceDiagram
participant U as User
participant T as TryIt Component
participant F as File/URL Input Component
participant P as PackButton
participant API as API Server
U->>T: Select mode (URL/File)
alt File Mode
T->>F: Render TryItFileUpload interface
U->>F: Upload a file
F->>T: Emit file upload event
else URL Mode
U->>F: Enter repository URL
end
U->>P: Click PackButton
P->>T: Trigger submission
T->>API: Send FormData with file (if exists) or URL
sequenceDiagram
participant C as Client Request
participant S as /api/pack Endpoint
participant PZF as processZipFile
participant PRR as processRemoteRepo
participant U as Utility Functions
C->>S: Submit FormData (file or URL)
alt File Provided
S->>PZF: Invoke processZipFile(file, format, options, clientIp)
PZF->>U: Validate file, extract ZIP, manage temp directory
U->>PZF: Return processed data
PZF->>S: Return PackResult
else URL Provided
S->>PRR: Invoke processRemoteRepo(url, format, options, clientIp)
PRR->>S: Return PackResult
end
S->>C: Respond with PackResult
Possibly related PRs
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (15)
website/server/src/index.ts (2)
48-50
: Consider standardizing error format
You return plain text (“File size too large :(”) instead of a JSON response. Elsewhere, errors are returned as JSON. It might be preferable to standardize this for consistency.
61-65
: Validate the file type
Currently, the code only checks iffile
is present or not. Consider verifying if it’s indeed a ZIP file or returning a more descriptive error if the content type is invalid.website/server/src/utils/fileUtils.ts (2)
8-53
: Robust ZIP extraction with security checks
Your approach to verifying file size, uncompressed size, file count, and disallowing directory traversal is excellent. One minor improvement: consider usingpath.resolve
and comparing withdestPath
to ensure reliable cross-platform validation.
64-76
: Validate directory path more thoroughly
Checking for therepomix-
substring is good, but more robust checks (e.g., verifying the full absolute path) could be beneficial in guarding against sabotage or accidental misuse.website/server/src/processZipFile.ts (2)
24-28
: Schema validation overshadowing
UsingvalidateRequest(packRequestSchema, { file, format, options })
is a good approach. Just ensure that any internal constraints (e.g., verifying file is indeed a ZIP) are also enforced or delegated toextractZip
to avoid duplication.
40-45
: Cache key generation
Combining file name, size, and lastModified is usually sufficient for smaller uploads. For larger or repeated uploads with the same name/size, consider hashing the file content for uniqueness.website/server/src/utils/sharedInstance.ts (1)
6-7
:❓ Verification inconclusive
Consider extracting configuration values to environment variables.
The cache duration and rate limit values are hardcoded, making them difficult to adjust across different environments (development, staging, production).
Apply this diff to make the values configurable:
-export const cache = new RequestCache<PackResult>(180); // 3 minutes cache -export const rateLimiter = new RateLimiter(60_000, 3); // 3 requests per minute +const CACHE_DURATION_SECONDS = process.env.CACHE_DURATION_SECONDS || 180; +const RATE_LIMIT_WINDOW_MS = process.env.RATE_LIMIT_WINDOW_MS || 60_000; +const RATE_LIMIT_MAX_REQUESTS = process.env.RATE_LIMIT_MAX_REQUESTS || 3; + +export const cache = new RequestCache<PackResult>(CACHE_DURATION_SECONDS); +export const rateLimiter = new RateLimiter(RATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX_REQUESTS);Consider increasing the rate limit.
The current rate limit of 3 requests per minute might be too restrictive for legitimate users, especially when they need to make multiple attempts to get their configuration right.
Let's analyze the current rate limit configuration:
🏁 Script executed:
#!/bin/bash # Description: Check if there are any rate limit related issues in GitHub issues gh issue list --search "rate limit" --state all --json number,title,stateLength of output: 164
Attention: Environment Configuration & Rate Limit Consideration
Extract the cache duration and rate limit values to environment variables for improved configurability across environments. The refactor diff below shows how to move the hardcoded values into environment-configurable constants:-export const cache = new RequestCache<PackResult>(180); // 3 minutes cache -export const rateLimiter = new RateLimiter(60_000, 3); // 3 requests per minute +const CACHE_DURATION_SECONDS = process.env.CACHE_DURATION_SECONDS || 180; +const RATE_LIMIT_WINDOW_MS = process.env.RATE_LIMIT_WINDOW_MS || 60_000; +const RATE_LIMIT_MAX_REQUESTS = process.env.RATE_LIMIT_MAX_REQUESTS || 3; + +export const cache = new RequestCache<PackResult>(CACHE_DURATION_SECONDS); +export const rateLimiter = new RateLimiter(RATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX_REQUESTS);Additionally, note that the current rate limit of 3 requests per minute might be too restrictive for users who may need multiple attempts to fine-tune their configuration. Although an automated check for rate-limit issues wasn’t conclusive (the verification command failed due to a missing git repository context), please manually verify if increasing the rate limit is needed based on your usage patterns.
website/server/src/constants.ts (1)
9-11
: Improve file size formatting precision.The current implementation might display too many decimal places. Consider rounding to 2 decimal places for better readability.
Apply this diff to improve the formatting:
- return `${bytes / 1024 / 1024}MB`; + return `${(bytes / 1024 / 1024).toFixed(2)}MB`;website/client/components/PackButton.vue (2)
9-21
: Enhance SVG accessibility.The SVG icon should have ARIA attributes and a title for better accessibility.
Apply this diff to improve accessibility:
<svg v-if="!loading" class="pack-button-icon" width="20" height="20" viewBox="96.259 93.171 300 300" + role="img" + aria-hidden="false" > + <title>Pack icon</title> <g transform="matrix(1.160932, 0, 0, 1.160932, 97.635941, 94.725143)"> <path fill="currentColor" d="M 128.03 -1.486 L 21.879 65.349 L 21.848 190.25 L 127.979 256.927 L 234.2 190.27 L 234.197 65.463 L 128.03 -1.486 Z M 208.832 70.323 L 127.984 121.129 L 47.173 70.323 L 128.144 19.57 L 208.832 70.323 Z M 39.669 86.367 L 119.188 136.415 L 119.255 230.529 L 39.637 180.386 L 39.669 86.367 Z M 136.896 230.506 L 136.887 136.575 L 216.469 86.192 L 216.417 180.46 L 136.896 230.506 Z M 136.622 230.849" /> </g> </svg>
34-64
: Consider scoping the styles.The styles should be scoped to prevent potential conflicts with other components.
Add the
scoped
attribute to the style tag:-<style> +<style scoped>website/server/src/schemas/request.ts (1)
30-32
: Consider enhancing zip file validation.While checking file type and extension is good, consider adding magic number validation for more reliable zip file detection.
const isValidZipFile = (file: File) => { - return file.type === 'application/zip' || file.name.endsWith('.zip'); + const isZipMimeOrExt = file.type === 'application/zip' || file.name.endsWith('.zip'); + // Add magic number check when browser File API supports it + return isZipMimeOrExt; };website/server/src/remoteRepo.ts (1)
30-32
: Improve error message clarity for missing URL.The error message should acknowledge that either a URL or file upload is required, making it clearer for API consumers.
- throw new AppError('Repository URL is required for remote processing', 400); + throw new AppError('Either a repository URL or a ZIP file upload is required', 400);website/client/components/TryItFileUpload.vue (2)
54-60
: Improve accessibility for file input.The file input lacks proper ARIA attributes and keyboard navigation support.
<input ref="fileInput" type="file" accept=".zip" class="hidden-input" + aria-label="Choose ZIP file" + role="button" + tabindex="0" @change="(e) => handleFileSelect((e.target as HTMLInputElement).files)" />
83-86
: Add loading state feedback during file processing.The PackButton shows loading state but users might benefit from additional visual feedback in the upload area.
<PackButton :loading="loading" :isValid="!!selectedFile" + :disabled="loading" />
Also, consider adding a loading overlay to the upload area:
<div class="upload-container" - :class="{ 'drag-active': dragActive, 'has-error': errorMessage }" + :class="{ + 'drag-active': dragActive, + 'has-error': errorMessage, + 'is-loading': loading + }"website/client/components/TryIt.vue (1)
87-91
: Update keyboard handling for file upload mode.The Enter key handler only works in URL mode. Consider updating it to work with file uploads as well.
function handleKeydown(event: KeyboardEvent) { - if (event.key === 'Enter' && url.value && !loading.value) { + if (event.key === 'Enter' && !loading.value && + ((mode.value === 'url' && url.value) || + (mode.value === 'file' && uploadedFile.value))) { handleSubmit(); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
website/client/components/PackButton.vue
(1 hunks)website/client/components/TryIt.vue
(5 hunks)website/client/components/TryItFileUpload.vue
(1 hunks)website/client/components/TryItUrlInput.vue
(3 hunks)website/client/components/api/client.ts
(2 hunks)website/client/components/utils/requestHandlers.ts
(3 hunks)website/server/package.json
(1 hunks)website/server/src/constants.ts
(1 hunks)website/server/src/index.ts
(3 hunks)website/server/src/processZipFile.ts
(1 hunks)website/server/src/remoteRepo.ts
(2 hunks)website/server/src/schemas/request.ts
(1 hunks)website/server/src/utils/cache.ts
(1 hunks)website/server/src/utils/fileUtils.ts
(1 hunks)website/server/src/utils/sharedInstance.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: Test (macos-latest, 23.x)
- GitHub Check: Test (macos-latest, 22.x)
- GitHub Check: Test (windows-latest, 23.x)
- GitHub Check: Test (windows-latest, 22.x)
- GitHub Check: Test (windows-latest, 21.x)
- GitHub Check: Test (windows-latest, 20.x)
- GitHub Check: Test (windows-latest, 19.x)
- GitHub Check: Test (windows-latest, 18.x)
- GitHub Check: Test (windows-latest, 18.0.0)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
website/server/src/index.ts (3)
8-11
: Imports look good
These imports properly consolidate the file size checks and ZIP processing logic. Great step in modularizing and keeping the code DRY.
55-58
: Handle potential invalid JSON for 'options'
IfformData.get('options')
is not valid JSON,JSON.parse()
will throw an unhandled exception. Adding a try/catch or fallback behavior could prevent runtime errors.
77-85
: Well-structured fallback logic
Cleanly routing toprocessZipFile
orprocessRemoteRepo
based on file vs. URL input is clear and straightforward. Good job!website/server/src/utils/fileUtils.ts (2)
55-62
: Well-encapsulated temp directory creation
This function simplifies the logic of creating a unique temporary directory. Looks good.
78-101
: Ensure correct file copying
This function properly sanitizes filenames, checks source existence, and copies the file while creating the target directory. The error handling patterns look consistent and robust.website/server/src/processZipFile.ts (1)
78-85
: Neat integration with runDefaultAction
The workflow of extracting the ZIP, running the default action, and copying the output is well-structured and easy to follow. Nicely done!website/client/components/utils/requestHandlers.ts (2)
5-10
: LGTM! Interface update is clean and backward compatible.The addition of the optional
file
property toRequestHandlerOptions
maintains backward compatibility while extending functionality for file uploads.
21-21
: LGTM! Request handling is properly updated.The changes correctly integrate file handling into the existing request flow while maintaining the original functionality.
Also applies to: 32-33
website/server/src/utils/cache.ts (1)
70-81
: LGTM! Cache key generation is well-designed.The changes to
generateCacheKey
are well thought out:
- Renamed parameter from 'url' to 'identifier' to be more generic
- Added 'type' parameter to distinguish between URL and file caches
- Maintains simple and efficient implementation
website/server/src/schemas/request.ts (2)
34-45
: LGTM! File validation schema is well-structured.The file validation schema is comprehensive:
- Validates File instance
- Checks file type
- Enforces reasonable size limit (10MB)
47-66
: LGTM! Request schema ensures valid input combinations.The schema refinements effectively prevent invalid states:
- Either URL or file must be provided
- Both URL and file cannot be provided simultaneously
website/client/components/TryItUrlInput.vue (2)
52-54
: LGTM! Clean integration of PackButton component.The PackButton integration is clean and maintains the component's functionality while improving modularity.
102-107
: LGTM! Button container styling is well-designed.The styling for the pack button container:
- Maintains proper spacing with margin-top
- Ensures centered alignment
- Preserves responsive design
website/server/src/remoteRepo.ts (1)
35-35
:✅ Verification successful
Verify cache key uniqueness between URL and file processing.
The cache key generation now includes a 'url' type parameter. Let's verify that this doesn't conflict with file-based cache keys.
🏁 Script executed:
#!/bin/bash # Search for all cache key generation calls to ensure unique types rg "generateCacheKey.*['\"](?:url|file)['\"]" -A 2Length of output: 307
Cache Key Uniqueness Verified – No Conflicts Detected
The cache key generation in
website/server/src/remoteRepo.ts
now explicitly specifies the'url'
type, and our grep search confirms that no file-based cache keys (i.e., with'file'
) are being generated in this context. There’s no apparent overlap between URL and file cache keys.website/server/package.json (2)
16-16
:✅ Verification successful
Verify compatibility with updated repomix version.
Check the changelog for breaking changes in the new version of repomix.
🏁 Script executed:
#!/bin/bash # Check for breaking changes in repomix gh api repos/yamadashy/repomix/releases/tags/v0.2.26 --jq .bodyLength of output: 1870
Compatibility confirmed with repomix v0.2.26
The changelog for repomix v0.2.26 shows several feature enhancements and improvements (e.g., support for multiple directories, the new
--quiet
CLI option, output enhancements, and improved Git URL parsing) without indicating any breaking changes. The dependency update inwebsite/server/package.json
appears safe, but please verify that the new features don’t inadvertently affect your current usage.
13-13
:✅ Verification successful
Verify security and compatibility of adm-zip package.
Let's check if this version of adm-zip has any known vulnerabilities and is compatible with the project's Node.js version.
🌐 Web query:
Are there any security vulnerabilities in adm-zip version 0.5.16?
💡 Result:
adm-zip version 0.5.16 does not appear to have any known security vulnerabilities according to available security databases[9][10]. This version was released on August 30, 2024[4], and multiple sources indicate:
- Snyk's vulnerability database shows no direct vulnerabilities for [email protected][9]
- ReversingLabs Spectra Assure Community scan found no malware or risks[10]
- The vulnerability SNYK-JS-ADMZIP-1065796 (high severity) was fixed in [email protected][1][4], meaning all subsequent versions including 0.5.16 contain this fix
- Earlier vulnerabilities like CVE-2018-1002204 (directory traversal) only affected versions <0.4.9[8]
Security researchers recommend using [email protected] rather than older versions like 0.4.x due to multiple security fixes implemented since 2021[1][4]. The latest version (0.5.16 at time of writing) appears to be secure based on current vulnerability reports[9][10].
Citations:
- 1: Vulnerability introduced by package adm-zip angular/webdriver-manager#499
- 2: https://cve.mitre.org/cgi-bin/cvekey.cgi
- 3: https://github.com/cthackers/adm-zip/blob/master/history.md
- 4: https://security.snyk.io/package/npm/adm-zip
- 5: https://nuget.qite.be/feeds/NPM/adm-zip/versions/all
- 6: https://speed.lean-lang.org/lean4/run-detail/0ea0e2bc-9ee6-42e9-96e5-f22dc72c331c
- 7: https://www.npmjs.com/package/adm-zip
- 8: https://nvd.nist.gov/vuln/detail/CVE-2018-1002204
- 9: https://security.snyk.io/package/npm/adm-zip/0.5.16
- 10: https://secure.software/npm/packages/adm-zip/0.5.16
Security and Compatibility Verification Completed
- Security: The security databases confirm that
[email protected]
has no known vulnerabilities. All major issues from prior versions have been addressed, so this version meets our security requirements.- Compatibility: There are no reported Node.js compatibility issues with this version. It is advisable to ensure that your project's Node.js version aligns with those commonly used with
adm-zip
.Overall, the changes in
website/server/package.json
(line 13) are safe.
Hi, @PaperBoardOfficial ! I've tested it and everything works perfectly. The implementation is very well thought out and clean. I really appreciate how you've maintained the code quality and security standards. I might add a commit later to adjust some design elements to match my preferences, but the functionality is spot on! I'll review the code in detail later, but so far it looks great. Thank you for your contribution! 🚀 |
cbdd595
to
87d7204
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (10)
website/client/components/TryItUrlInput.vue (1)
102-107
: Consider adjusting the pack button container for mobile screens.While the desktop styling looks good, consider adjusting the margin and width for mobile screens to ensure optimal layout.
Add these styles to the existing mobile media query:
@media (max-width: 640px) { .url-input-container { flex-direction: column; } + .pack-button-container { + margin-top: 12px; /* Reduced margin for tighter mobile layout */ + } }website/server/src/schemas/request.ts (1)
30-32
: Enhance ZIP file validation.The current validation only checks MIME type and file extension. Consider adding magic number validation for more robust ZIP file detection.
const isValidZipFile = (file: File) => { - return file.type === 'application/zip' || file.name.endsWith('.zip'); + const isZipType = file.type === 'application/zip' || file.name.endsWith('.zip'); + // Add magic number check for ZIP files (first 4 bytes: 50 4B 03 04) + return isZipType && file.slice(0, 4).arrayBuffer().then(buffer => + new Uint8Array(buffer)[0] === 0x50 && + new Uint8Array(buffer)[1] === 0x4B && + new Uint8Array(buffer)[2] === 0x03 && + new Uint8Array(buffer)[3] === 0x04 + ); };website/server/src/index.ts (1)
55-67
: Consider adding content type validation.While the form data handling is good, it's important to validate the content type of the request.
+ // Validate content type + const contentType = c.req.header('content-type'); + if (!contentType?.includes('multipart/form-data')) { + return c.json({ error: 'Invalid content type. Expected multipart/form-data' } as ErrorResponse, 400); + } + const formData = await c.req.formData();website/server/src/utils/fileUtils.ts (1)
78-101
: Consider adding file size check during copy.While the path sanitization is good, consider adding a size check during the copy operation.
// Verify source exists await fs.access(sourcePath); + + // Check file size before copy + const stats = await fs.stat(sourcePath); + if (stats.size > FILE_SIZE_LIMITS.MAX_OUTPUT_SIZE) { + throw new AppError(`Output file size exceeds maximum limit of ${formatFileSize(FILE_SIZE_LIMITS.MAX_OUTPUT_SIZE)}`); + }website/client/components/TryItFileUpload.vue (2)
14-14
: Remove unused ref.The
isValidUrl
ref is defined but never used in the component.-const isValidUrl = ref(false);
48-53
: Enhance drag and drop UX with file validation feedback.Consider adding visual feedback when an invalid file is dragged over the drop zone.
<div class="upload-container" :class="{ 'drag-active': dragActive, - 'has-error': errorMessage + 'has-error': errorMessage, + 'invalid-file': dragActive && $event.dataTransfer?.items?.[0]?.type !== 'application/zip' }" @dragover.prevent="dragActive = true" @dragleave="dragActive = false" @drop.prevent="handleFileSelect($event.dataTransfer?.files || null)" >website/server/src/processZipFile.ts (2)
75-111
: Improve error handling and logging for file processing.Consider enhancing the error handling:
- Add specific error types for different failure scenarios
- Implement structured logging with correlation IDs
- Add retry logic for transient failures
const tempDirPath = await createTempDirectory(); +const correlationId = randomUUID(); +console.log(`[${correlationId}] Starting file processing for ${file.name}`); try { // Extract the ZIP file to the temporary directory + console.log(`[${correlationId}] Extracting ZIP file to ${tempDirPath}`); await extractZip(file, tempDirPath); // Execute default action on the extracted directory + console.log(`[${correlationId}] Running default action with options:`, cliOptions); const result = await runDefaultAction([tempDirPath], tempDirPath, cliOptions);
122-131
: Good cleanup implementation!The cleanup logic is well-implemented in the finally block. Consider adding a timeout for the cleanup operations to prevent hanging.
} finally { + const cleanup = async () => { + await Promise.race([ + cleanupTempDirectory(tempDirPath), + new Promise((_, reject) => setTimeout(() => reject(new Error('Cleanup timeout')), 5000)) + ]); + }; + try { - await fs.unlink(outputFilePath); + await cleanup(); } catch (err) { console.warn('Failed to cleanup:', err); } }website/client/components/TryIt.vue (2)
33-37
: Improve type safety for mode validation.Consider using a type guard to ensure type safety when checking the mode.
-if (mode.value === 'url' && !url.value) return; -if (mode.value === 'file' && !uploadedFile.value) return; +function isUrlMode(mode: string): mode is 'url' { + return mode === 'url'; +} + +if (isUrlMode(mode.value) && !url.value) return; +if (!isUrlMode(mode.value) && !uploadedFile.value) return;
102-117
: Enhance accessibility for mode switching buttons.Add ARIA labels and roles to improve accessibility.
<div class="input-mode-selector"> <button type="button" :class="{ active: mode === 'url' }" + role="tab" + :aria-selected="mode === 'url'" + aria-controls="url-input" @click="mode = 'url'" > URL Input </button> <button type="button" :class="{ active: mode === 'file' }" + role="tab" + :aria-selected="mode === 'file'" + aria-controls="file-upload" @click="mode = 'file'" > File Upload </button> </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
website/client/components/PackButton.vue
(1 hunks)website/client/components/TryIt.vue
(5 hunks)website/client/components/TryItFileUpload.vue
(1 hunks)website/client/components/TryItUrlInput.vue
(3 hunks)website/client/components/api/client.ts
(2 hunks)website/client/components/utils/requestHandlers.ts
(3 hunks)website/server/package.json
(1 hunks)website/server/src/constants.ts
(1 hunks)website/server/src/index.ts
(3 hunks)website/server/src/processZipFile.ts
(1 hunks)website/server/src/remoteRepo.ts
(2 hunks)website/server/src/schemas/request.ts
(1 hunks)website/server/src/utils/cache.ts
(1 hunks)website/server/src/utils/fileUtils.ts
(1 hunks)website/server/src/utils/sharedInstance.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- website/server/src/utils/sharedInstance.ts
- website/server/package.json
- website/client/components/api/client.ts
- website/client/components/utils/requestHandlers.ts
- website/server/src/constants.ts
- website/server/src/utils/cache.ts
- website/client/components/PackButton.vue
⏰ Context from checks skipped due to timeout of 90000ms (12)
- GitHub Check: Test (macos-latest, 23.x)
- GitHub Check: Test (macos-latest, 22.x)
- GitHub Check: Test (macos-latest, 21.x)
- GitHub Check: Test (windows-latest, 23.x)
- GitHub Check: Test (windows-latest, 22.x)
- GitHub Check: Build and run (windows-latest, 22.x)
- GitHub Check: Test (windows-latest, 21.x)
- GitHub Check: Test (windows-latest, 20.x)
- GitHub Check: Test (windows-latest, 19.x)
- GitHub Check: Test (windows-latest, 18.x)
- GitHub Check: Test (windows-latest, 18.0.0)
- GitHub Check: Build and run (windows-latest, 18.0.0)
🔇 Additional comments (13)
website/client/components/TryItUrlInput.vue (2)
4-4
: LGTM! Clean import of the new PackButton component.The import statement is well-placed and follows Vue.js conventions.
52-54
: LGTM! Clean integration of the PackButton component.The placement of the PackButton below the URL input field improves the user experience, as intended in the PR objectives. The props are correctly passed through to the component.
website/server/src/schemas/request.ts (2)
34-45
: LGTM! Comprehensive file validation schema.The schema includes essential validations:
- File type check
- ZIP format validation
- Size limit (10MB)
61-66
: LGTM! Well-designed request validation.The refinements ensure:
- At least one of URL or file is provided
- Both URL and file cannot be provided simultaneously
website/server/src/index.ts (2)
48-51
: LGTM! Clear error message for file size limit.The error message has been improved from "overflow :(" to a more descriptive "File size too large :(".
77-85
: LGTM! Clean conditional processing logic.The code clearly handles both file and URL processing paths with proper error handling.
website/server/src/utils/fileUtils.ts (1)
8-53
: LGTM! Robust ZIP extraction with security measures.The implementation includes:
- File size validation
- Directory traversal prevention
- Proper error handling
website/server/src/remoteRepo.ts (2)
30-32
: LGTM! Clear URL validation.The validation ensures the URL is present for remote processing.
34-35
: LGTM! Updated cache key generation.The cache key now includes the type parameter to differentiate between URL and file-based requests.
website/client/components/TryItFileUpload.vue (2)
16-31
: Enhance file validation robustness.The current validation could be improved to handle edge cases and provide better security.
90-174
: Well-structured styling implementation!The CSS implementation follows the design system, uses proper scoping, and implements responsive design patterns.
website/client/components/TryIt.vue (2)
102-117
: Reset error states when switching modes.When switching between URL and file upload modes, error states should be reset to prevent confusion.
145-180
: Clean and consistent styling implementation!The CSS implementation follows the design system and properly handles responsive design.
export const cleanupTempDirectory = async (directory: string): Promise<void> => { | ||
try { | ||
if (!directory.includes('repomix-')) { | ||
throw new AppError('Invalid temporary directory path'); | ||
} | ||
await fs.rm(directory, { recursive: true, force: true }); | ||
} catch (error) { | ||
if (error instanceof AppError) { | ||
throw error; | ||
} | ||
console.error(`Failed to cleanup temporary directory: ${directory}`, error); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance temporary directory validation.
The current validation only checks for 'repomix-' in the path, which might be insufficient.
- if (!directory.includes('repomix-')) {
+ const tempDirPath = path.resolve(directory);
+ const systemTempDir = path.resolve(os.tmpdir());
+ if (!tempDirPath.startsWith(systemTempDir) || !path.basename(tempDirPath).startsWith('repomix-')) {
throw new AppError('Invalid temporary directory path');
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const cleanupTempDirectory = async (directory: string): Promise<void> => { | |
try { | |
if (!directory.includes('repomix-')) { | |
throw new AppError('Invalid temporary directory path'); | |
} | |
await fs.rm(directory, { recursive: true, force: true }); | |
} catch (error) { | |
if (error instanceof AppError) { | |
throw error; | |
} | |
console.error(`Failed to cleanup temporary directory: ${directory}`, error); | |
} | |
}; | |
export const cleanupTempDirectory = async (directory: string): Promise<void> => { | |
try { | |
const tempDirPath = path.resolve(directory); | |
const systemTempDir = path.resolve(os.tmpdir()); | |
if (!tempDirPath.startsWith(systemTempDir) || !path.basename(tempDirPath).startsWith('repomix-')) { | |
throw new AppError('Invalid temporary directory path'); | |
} | |
await fs.rm(directory, { recursive: true, force: true }); | |
} catch (error) { | |
if (error instanceof AppError) { | |
throw error; | |
} | |
console.error(`Failed to cleanup temporary directory: ${directory}`, error); | |
} | |
}; |
export async function processZipFile( | ||
file: File, | ||
format: string, | ||
options: PackOptions, | ||
clientIp: string, | ||
): Promise<PackResult> { | ||
// Validate the request (excluding URL validation) | ||
const validatedData = validateRequest(packRequestSchema, { | ||
file, | ||
format, | ||
options, | ||
}); | ||
|
||
// Rate limit check | ||
if (!rateLimiter.isAllowed(clientIp)) { | ||
const remainingTime = Math.ceil(rateLimiter.getRemainingTime(clientIp) / 1000); | ||
throw new AppError(`Rate limit exceeded. Please try again in ${remainingTime} seconds.`, 429); | ||
} | ||
|
||
if (!file) { | ||
throw new AppError('File is required for file processing', 400); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🛠️ Refactor suggestion
🧩 Analysis chain
Enhance security measures for file processing.
Consider adding additional security checks:
- Validate file mime type using a library like
file-type
- Implement virus scanning for uploaded files
- Add a maximum number of files limit for zip extraction
🌐 Web query:
What are the best practices for secure file upload handling in Node.js?
💡 Result:
When handling file uploads in Node.js applications, implementing robust security measures is critical to prevent vulnerabilities like arbitrary code execution or server compromise. Below are essential practices supported by industry research:
Core Security Practices
1. Multi-Layered File Validation
-
Type Verification:
- Whitelist allowed MIME types/extensions (e.g.,
image/jpeg
,.png
) - Use magic number checks to detect spoofed files[1][3][4]
// Validate MIME type and extension const allowedTypes = ['image/jpeg', 'image/png']; if (!allowedTypes.includes(file.mimetype)) reject('Invalid type');
- Whitelist allowed MIME types/extensions (e.g.,
-
Size Restrictions:
- Enforce server-side limits (e.g.,
maxFileSize: 5MB
)[1][7]
- Enforce server-side limits (e.g.,
2. Secure Filename Handling
- Replace user-provided names with cryptographic hashes/UUIDs[1][4][10]
- Prevent path traversal via sanitization:
const safeName = `${crypto.randomUUID()}${path.extname(originalName)}`;
3. Storage Configuration
- Store files outside web-accessible directories[1][3]
- Use temporary storage during validation before permanent retention[4]
- Set strict directory permissions (
0o755
)[1]
Advanced Protections
Technique | Implementation |
---|---|
Antivirus Scanning | Integrate APIs like Verisys for server-side malware detection[8] |
HTTPS Enforcement | Encrypt data in transit using TLS certificates[3][7] |
Rate Limiting | Prevent DDoS attacks via tools like express-rate-limit [1][7] |
CSRF Protection | Validate tokens using middleware like csurf [7] |
Library Best Practices
- Use battle-tested libraries like Formidable or Multer, but:
- Avoid trusting their default configurations[2][5]
- Combine multiple validation layers (extension + MIME + magic numbers)[1][3]
- Audit dependencies regularly[6][9]
// Formidable secure setup example
const form = formidable({
maxFiles: 2,
filter: ({ mimetype }) => ['image/jpeg'].includes(mimetype),
filename: () => crypto.randomUUID()
});
Critical Industry Findings
A 2024 study of Node.js file upload libraries (Google Research[2][5]) revealed:
- 19 CVEs identified in popular tools
- Common failures in handling dynamic file types
- Widespread lack of content validation beyond headers
By combining strict validation protocols, secure storage practices, and continuous dependency monitoring, developers can mitigate risks highlighted in recent research while adhering to modern security standards.
Citations:
- 1: https://app.studyraid.com/en/read/12494/404055/security-best-practices
- 2: https://research.google/pubs/insecurity-of-file-uploads-in-nodejs/
- 3: https://www.contextneutral.com/top-practices-secure-file-uploads/
- 4: https://blog.pixelfreestudio.com/best-practices-for-secure-file-uploads-on-websites/
- 5: https://dl.acm.org/doi/10.1145/3589334.3645342
- 6: https://dev.to/imsushant12/security-best-practices-for-nodejs-applications-24mf
- 7: https://www.sitepoint.com/forms-file-uploads-security-node-express/
- 8: https://blog.ionxsolutions.com/p/file-uploads-with-nodejs-express/
- 9: https://nodejs.org/en/learn/getting-started/security-best-practices
- 10: https://dev.to/bfunc/upload-files-easy-with-html5-and-nodejs-44fo
Enhance security measures for file processing in processZipFile.
While the current implementation handles basic validations and rate limiting, further security enhancements are recommended. In particular, please consider:
-
File Type Verification:
- Use a library such as
file-type
to perform magic number checks in addition to validating the file’s MIME type. - Whitelist specific MIME types and extensions to prevent spoofing.
- Use a library such as
-
Virus Scanning:
- Integrate an antivirus scanning solution (or API) to inspect uploaded files for malware before processing.
-
Zip Extraction Limits:
- Enforce a maximum number of files allowed during zip extraction to mitigate potential resource exhaustion or path traversal risks.
These additions will help to further harden the file upload process in accordance with current best practices for secure file handling in Node.js.
First of all @yamadashy , your repo is neat and clean, its easy to run with docker. Great work. Here are my changes. (you check this also: https://youtu.be/VjBGvu9cECo)
Issue link: #310
Changes done:
Client:
Server:
Way forward:
I didn't implement folder uploading. We can create a separate ticket for that.
Ping me if you have any suggestions.
Checklist
npm run test
npm run lint