Add MIME-type validation to document uploads#77
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 21 minutes and 30 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
📝 WalkthroughWalkthroughDocumentService.uploadDocument(...) gained strict upload validation: max size enforcement (10 MB), extension allowlist mapped to expected MIME types, multipart content-type verification, and server-side MIME detection via Apache Tika before uploading bytes (now uploaded from an in-memory ByteArrayInputStream). Tests updated to use PDF fixtures and pom.xml adds tika-core. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client
participant Service as DocumentService
participant Tika as Apache Tika
participant S3 as S3
Client->>Service: POST multipart file (filename, contentType, bytes)
Service->>Service: check file size <= 10MB
Service->>Service: derive extension from filename
Service->>Service: lookup expected MIME for extension
Service->>Service: compare multipart contentType with expected MIME
Service->>Tika: TIKA.detect(fileBytes)
Tika-->>Service: detected MIME
Service->>Service: compare detected MIME with expected MIME
Service->>S3: upload ByteArrayInputStream(fileBytes)
S3-->>Service: upload result
Service-->>Client: response (created / error)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/test/java/org/example/projektarendehantering/DocumentIntegrationTest.java (1)
94-109:⚠️ Potential issue | 🟡 MinorUse a PDF-like fixture instead of labeling
"hello"as a PDF.These integration fixtures now satisfy the new checks only because content type and extension are client-provided. Use a minimal PDF payload or fixture file so the test remains valid if MIME detection starts inspecting bytes.
🧪 Example fixture adjustment
+ byte[] pdfBytes = "%PDF-1.4\n%%EOF\n".getBytes(java.nio.charset.StandardCharsets.US_ASCII); - MockMultipartFile file = new MockMultipartFile("file", "test.pdf", "application/pdf", "hello".getBytes()); + MockMultipartFile file = new MockMultipartFile("file", "test.pdf", "application/pdf", pdfBytes);Apply the same fixture pattern to the unauthorized upload test.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/projektarendehantering/DocumentIntegrationTest.java` around lines 94 - 109, The test uses MockMultipartFile with plain "hello" bytes but labels it as a PDF, so change the fixture to a minimal valid PDF payload or load a small PDF test resource instead of the "hello" string; update the MockMultipartFile instantiation(s) in the test method(s) (e.g., the first upload test and uploadDocument_shouldDenyUnauthorized) to pass a byte[] or InputStream containing a minimal PDF header/content (or read from src/test/resources fixture) while keeping the same filename "test.pdf" and contentType "application/pdf" so the MIME/extension checks will still pass and the rest of the assertions (documentRepository checks and verify(s3Template).upload(...)) remain unchanged.
🧹 Nitpick comments (1)
src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java (1)
72-116: Add negative tests for the new validation rules.This PR adds rejection paths, but the unit tests only update existing valid fixtures. Please cover at least oversized files, disallowed extensions, disallowed content types, and extension/content-type mismatches.
🧪 Suggested test cases
`@Test` void uploadDocument_shouldRejectDisallowedExtension() { MockMultipartFile file = new MockMultipartFile("file", "test.exe", "application/pdf", "hello".getBytes()); assertThatThrownBy(() -> documentService.uploadDocument(doctorActor, caseId, file)) .isInstanceOf(BadRequestException.class); } `@Test` void uploadDocument_shouldRejectDisallowedContentType() { MockMultipartFile file = new MockMultipartFile("file", "test.pdf", "text/plain", "hello".getBytes()); assertThatThrownBy(() -> documentService.uploadDocument(doctorActor, caseId, file)) .isInstanceOf(BadRequestException.class); } `@Test` void uploadDocument_shouldRejectMismatchedExtensionAndContentType() { MockMultipartFile file = new MockMultipartFile("file", "test.pdf", "image/png", "hello".getBytes()); assertThatThrownBy(() -> documentService.uploadDocument(doctorActor, caseId, file)) .isInstanceOf(BadRequestException.class); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java` around lines 72 - 116, The tests lack negative coverage for the new upload validation in DocumentService.uploadDocument; add unit tests in DocumentServiceTest that create MockMultipartFile inputs to assert BadRequestException is thrown for (1) oversized file (create a byte[] larger than the allowed max), (2) disallowed extension (e.g., "test.exe" with a PDF content type), (3) disallowed content type (e.g., "test.pdf" with "text/plain"), and (4) mismatched extension/content-type (e.g., "test.pdf" with "image/png"); use doctorActor and caseId fixtures, stub caseRepository.findById(caseId) to return Optional.of(caseEntity) as in other tests, and assertThatThrownBy(() -> documentService.uploadDocument(...)).isInstanceOf(BadRequestException.class) for each case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/org/example/projektarendehantering/application/service/DocumentService.java`:
- Around line 66-74: The extension and MIME checks in DocumentService are
independent, allowing spoofed uploads; replace them with a correlated mapping
(e.g., Map<String, Set<String>> extensionToMime) and validate that the uploaded
file's extension (derived from originalFilename) maps to the provided
contentType before accepting the file (use the same symbols
ALLOWED_EXTENSIONS/ALLOWED_CONTENT_TYPES to migrate into extensionToMime and
validate in the method that handles file upload). Additionally, for stronger
server-side validation, detect the actual MIME from file.getInputStream() (e.g.,
via Apache Tika or similar) and compare that detected type against the
extensionToMime entry to reject mismatches.
---
Outside diff comments:
In
`@src/test/java/org/example/projektarendehantering/DocumentIntegrationTest.java`:
- Around line 94-109: The test uses MockMultipartFile with plain "hello" bytes
but labels it as a PDF, so change the fixture to a minimal valid PDF payload or
load a small PDF test resource instead of the "hello" string; update the
MockMultipartFile instantiation(s) in the test method(s) (e.g., the first upload
test and uploadDocument_shouldDenyUnauthorized) to pass a byte[] or InputStream
containing a minimal PDF header/content (or read from src/test/resources
fixture) while keeping the same filename "test.pdf" and contentType
"application/pdf" so the MIME/extension checks will still pass and the rest of
the assertions (documentRepository checks and verify(s3Template).upload(...))
remain unchanged.
---
Nitpick comments:
In
`@src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java`:
- Around line 72-116: The tests lack negative coverage for the new upload
validation in DocumentService.uploadDocument; add unit tests in
DocumentServiceTest that create MockMultipartFile inputs to assert
BadRequestException is thrown for (1) oversized file (create a byte[] larger
than the allowed max), (2) disallowed extension (e.g., "test.exe" with a PDF
content type), (3) disallowed content type (e.g., "test.pdf" with "text/plain"),
and (4) mismatched extension/content-type (e.g., "test.pdf" with "image/png");
use doctorActor and caseId fixtures, stub caseRepository.findById(caseId) to
return Optional.of(caseEntity) as in other tests, and assertThatThrownBy(() ->
documentService.uploadDocument(...)).isInstanceOf(BadRequestException.class) for
each case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 92021ae0-996a-4736-8697-433634cdebb7
📒 Files selected for processing (3)
src/main/java/org/example/projektarendehantering/application/service/DocumentService.javasrc/test/java/org/example/projektarendehantering/DocumentIntegrationTest.javasrc/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/org/example/projektarendehantering/application/service/DocumentService.java (1)
70-79: UseLocale.ROOTand collapse the two identical-message branches.
toLowerCase()without a Locale is locale-sensitive (TurkishI/ıis the classic trap) — not currently exploitable since the map keys are ASCII, but the prior review already suggestedLocale.ROOT; worth applying here for consistency. The twothrowbranches at lines 74-76 and 77-79 produce the exact same error message and can be merged.♻️ Optional refactor
String extension = originalFilename.contains(".") - ? originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase() + ? originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase(java.util.Locale.ROOT) : ""; String expectedMime = EXTENSION_TO_MIME.get(extension); - if (expectedMime == null) { - throw new BadRequestException("File type not allowed. Allowed types: pdf, png, jpg, jpeg, docx"); - } - if (!expectedMime.equalsIgnoreCase(contentType)) { + if (expectedMime == null || !expectedMime.equalsIgnoreCase(contentType)) { throw new BadRequestException("File type not allowed. Allowed types: pdf, png, jpg, jpeg, docx"); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/projektarendehantering/application/service/DocumentService.java` around lines 70 - 79, In DocumentService.java, make the filename-to-extension normalization use Locale.ROOT (e.g., call toLowerCase(Locale.ROOT) on the substring derived from originalFilename) and collapse the two identical BadRequestException branches into one check: look up expectedMime from EXTENSION_TO_MIME by the normalized extension and if expectedMime is null or not equalIgnoreCase to contentType, throw the single BadRequestException with the existing message; update references to originalFilename, EXTENSION_TO_MIME, and contentType accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/org/example/projektarendehantering/application/service/DocumentService.java`:
- Around line 81-85: The current byte-array-only check using TIKA.detect(byte[])
in DocumentService.java rejects real .docx files because Tika without parsers
returns application/zip; change the detection to use the filename hint by
calling TIKA.detect(fileBytes, file.getOriginalFilename() or filename) instead
of TIKA.detect(fileBytes) (i.e., replace the TIKA.detect(byte[]) call), and add
a unit test that uploads a real .docx fixture to exercise the docx path;
alternatively, if you prefer stronger detection, include
org.apache.tika:tika-parsers-standard-package and switch to a
DefaultDetector/TikaInputStream-based detection flow, but for a minimal fix use
TIKA.detect(byte[], String) and update the BadRequestException check
accordingly.
---
Nitpick comments:
In
`@src/main/java/org/example/projektarendehantering/application/service/DocumentService.java`:
- Around line 70-79: In DocumentService.java, make the filename-to-extension
normalization use Locale.ROOT (e.g., call toLowerCase(Locale.ROOT) on the
substring derived from originalFilename) and collapse the two identical
BadRequestException branches into one check: look up expectedMime from
EXTENSION_TO_MIME by the normalized extension and if expectedMime is null or not
equalIgnoreCase to contentType, throw the single BadRequestException with the
existing message; update references to originalFilename, EXTENSION_TO_MIME, and
contentType accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 82871ae0-e6b9-4410-aa9b-3869e37fdb7a
📒 Files selected for processing (4)
pom.xmlsrc/main/java/org/example/projektarendehantering/application/service/DocumentService.javasrc/test/java/org/example/projektarendehantering/DocumentIntegrationTest.javasrc/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java
✅ Files skipped from review due to trivial changes (1)
- pom.xml
🚧 Files skipped from review as they are similar to previous changes (2)
- src/test/java/org/example/projektarendehantering/DocumentIntegrationTest.java
- src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java
…rehensive `uploadDocument` test
…instead of text files
Closes #78
Summary by CodeRabbit
New Features
Tests
Chores