|
30 | 30 | import java.io.File;
|
31 | 31 | import java.io.IOException;
|
32 | 32 | import java.nio.charset.StandardCharsets;
|
| 33 | +import java.nio.file.Files; |
| 34 | +import java.nio.file.Path; |
| 35 | +import java.nio.file.Paths; |
33 | 36 | import java.util.ArrayList;
|
34 | 37 | import java.util.List;
|
35 | 38 | import java.util.Map;
|
@@ -586,6 +589,160 @@ public void multipleFileUploadWithMixedContent() throws IOException {
|
586 | 589 | }
|
587 | 590 | }
|
588 | 591 |
|
| 592 | + @Test |
| 593 | + public void createTemporaryFileGeneratesSecureNames() { |
| 594 | + // Create a test instance to access the protected method |
| 595 | + AbstractMultiPartRequest testRequest = createMultipartRequest(); |
| 596 | + Path testLocation = Paths.get(tempDir); |
| 597 | + |
| 598 | + // when - create multiple temporary files |
| 599 | + File tempFile1 = testRequest.createTemporaryFile("test1.csv", testLocation); |
| 600 | + File tempFile2 = testRequest.createTemporaryFile("test2.csv", testLocation); |
| 601 | + File tempFile3 = testRequest.createTemporaryFile("../../../malicious.csv", testLocation); |
| 602 | + |
| 603 | + // then - verify secure naming |
| 604 | + assertThat(tempFile1.getName()).startsWith("upload_"); |
| 605 | + assertThat(tempFile1.getName()).endsWith(".tmp"); |
| 606 | + assertThat(tempFile2.getName()).startsWith("upload_"); |
| 607 | + assertThat(tempFile2.getName()).endsWith(".tmp"); |
| 608 | + assertThat(tempFile3.getName()).startsWith("upload_"); |
| 609 | + assertThat(tempFile3.getName()).endsWith(".tmp"); |
| 610 | + |
| 611 | + // Verify each file has a unique name |
| 612 | + assertThat(tempFile1.getName()).isNotEqualTo(tempFile2.getName()); |
| 613 | + assertThat(tempFile2.getName()).isNotEqualTo(tempFile3.getName()); |
| 614 | + assertThat(tempFile1.getName()).isNotEqualTo(tempFile3.getName()); |
| 615 | + |
| 616 | + // Verify all files are in the correct location |
| 617 | + assertThat(tempFile1.getParent()).isEqualTo(tempDir); |
| 618 | + assertThat(tempFile2.getParent()).isEqualTo(tempDir); |
| 619 | + assertThat(tempFile3.getParent()).isEqualTo(tempDir); |
| 620 | + |
| 621 | + // Verify malicious filename doesn't affect the location |
| 622 | + assertThat(tempFile3.getName()).doesNotContain(".."); |
| 623 | + assertThat(tempFile3.getName()).doesNotContain("/"); |
| 624 | + assertThat(tempFile3.getName()).doesNotContain("\\"); |
| 625 | + |
| 626 | + // Clean up test files |
| 627 | + tempFile1.delete(); |
| 628 | + tempFile2.delete(); |
| 629 | + tempFile3.delete(); |
| 630 | + } |
| 631 | + |
| 632 | + @Test |
| 633 | + public void createTemporaryFileInSpecificDirectory() throws IOException { |
| 634 | + // Create a subdirectory for testing |
| 635 | + Path subDir = Paths.get(tempDir, "subdir"); |
| 636 | + Files.createDirectories(subDir); |
| 637 | + |
| 638 | + AbstractMultiPartRequest testRequest = createMultipartRequest(); |
| 639 | + |
| 640 | + // when |
| 641 | + File tempFile = testRequest.createTemporaryFile("test.csv", subDir); |
| 642 | + |
| 643 | + // then - verify file is created in the specified subdirectory |
| 644 | + assertThat(tempFile.getParent()).isEqualTo(subDir.toString()); |
| 645 | + assertThat(tempFile.getName()).startsWith("upload_"); |
| 646 | + assertThat(tempFile.getName()).endsWith(".tmp"); |
| 647 | + |
| 648 | + // Clean up |
| 649 | + tempFile.delete(); |
| 650 | + Files.delete(subDir); |
| 651 | + } |
| 652 | + |
| 653 | + @Test |
| 654 | + public void createTemporaryFileWithNullFileName() throws IOException { |
| 655 | + AbstractMultiPartRequest testRequest = createMultipartRequest(); |
| 656 | + Path testLocation = Paths.get(tempDir); |
| 657 | + |
| 658 | + // when - create temp file with null filename |
| 659 | + File tempFile = testRequest.createTemporaryFile(null, testLocation); |
| 660 | + |
| 661 | + // then - should still create a valid temporary file |
| 662 | + assertThat(tempFile.getName()).startsWith("upload_"); |
| 663 | + assertThat(tempFile.getName()).endsWith(".tmp"); |
| 664 | + assertThat(tempFile.getParent()).isEqualTo(tempDir); |
| 665 | + |
| 666 | + // Clean up |
| 667 | + tempFile.delete(); |
| 668 | + } |
| 669 | + |
| 670 | + @Test |
| 671 | + public void createTemporaryFileWithEmptyFileName() throws IOException { |
| 672 | + AbstractMultiPartRequest testRequest = createMultipartRequest(); |
| 673 | + Path testLocation = Paths.get(tempDir); |
| 674 | + |
| 675 | + // when - create temp file with empty filename |
| 676 | + File tempFile = testRequest.createTemporaryFile("", testLocation); |
| 677 | + |
| 678 | + // then - should still create a valid temporary file |
| 679 | + assertThat(tempFile.getName()).startsWith("upload_"); |
| 680 | + assertThat(tempFile.getName()).endsWith(".tmp"); |
| 681 | + assertThat(tempFile.getParent()).isEqualTo(tempDir); |
| 682 | + |
| 683 | + // Clean up |
| 684 | + tempFile.delete(); |
| 685 | + } |
| 686 | + |
| 687 | + @Test |
| 688 | + public void createTemporaryFileWithSpecialCharacters() { |
| 689 | + AbstractMultiPartRequest testRequest = createMultipartRequest(); |
| 690 | + Path testLocation = Paths.get(tempDir); |
| 691 | + |
| 692 | + // when - create temp files with various special characters |
| 693 | + File tempFile1 = testRequest.createTemporaryFile("file with spaces.csv", testLocation); |
| 694 | + File tempFile2 = testRequest.createTemporaryFile("file@#$%^&*().csv", testLocation); |
| 695 | + File tempFile3 = testRequest.createTemporaryFile("файл.csv", testLocation); // Cyrillic |
| 696 | + |
| 697 | + // then - all should create valid secure temporary files |
| 698 | + File[] tempFiles = {tempFile1, tempFile2, tempFile3}; |
| 699 | + for (File tempFile : tempFiles) { |
| 700 | + assertThat(tempFile.getName()).startsWith("upload_"); |
| 701 | + assertThat(tempFile.getName()).endsWith(".tmp"); |
| 702 | + assertThat(tempFile.getParent()).isEqualTo(tempDir); |
| 703 | + // Verify no special characters leak into the actual filename |
| 704 | + assertThat(tempFile.getName()).matches("upload_[a-zA-Z0-9_]+\\.tmp"); |
| 705 | + } |
| 706 | + |
| 707 | + // All should have unique names |
| 708 | + assertThat(tempFile1.getName()).isNotEqualTo(tempFile2.getName()); |
| 709 | + assertThat(tempFile2.getName()).isNotEqualTo(tempFile3.getName()); |
| 710 | + assertThat(tempFile1.getName()).isNotEqualTo(tempFile3.getName()); |
| 711 | + |
| 712 | + // Clean up |
| 713 | + tempFile1.delete(); |
| 714 | + tempFile2.delete(); |
| 715 | + tempFile3.delete(); |
| 716 | + } |
| 717 | + |
| 718 | + @Test |
| 719 | + public void createTemporaryFileConsistentNaming() { |
| 720 | + AbstractMultiPartRequest testRequest = createMultipartRequest(); |
| 721 | + Path testLocation = Paths.get(tempDir); |
| 722 | + |
| 723 | + // when - create many temporary files to verify naming consistency |
| 724 | + List<File> tempFiles = new ArrayList<>(); |
| 725 | + for (int i = 0; i < 100; i++) { |
| 726 | + tempFiles.add(testRequest.createTemporaryFile("test" + i + ".csv", testLocation)); |
| 727 | + } |
| 728 | + |
| 729 | + // then - all should follow the same naming pattern |
| 730 | + for (File tempFile : tempFiles) { |
| 731 | + assertThat(tempFile.getName()).startsWith("upload_"); |
| 732 | + assertThat(tempFile.getName()).endsWith(".tmp"); |
| 733 | + assertThat(tempFile.getParent()).isEqualTo(tempDir); |
| 734 | + // Verify UUID pattern (without hyphens, replaced with underscores) |
| 735 | + assertThat(tempFile.getName()).matches("upload_[a-zA-Z0-9_]+\\.tmp"); |
| 736 | + } |
| 737 | + |
| 738 | + // Verify all names are unique |
| 739 | + List<String> fileNames = tempFiles.stream().map(File::getName).toList(); |
| 740 | + assertThat(fileNames).doesNotHaveDuplicates(); |
| 741 | + |
| 742 | + // Clean up |
| 743 | + tempFiles.forEach(File::delete); |
| 744 | + } |
| 745 | + |
589 | 746 | protected String formFile(String fieldName, String filename, String content) {
|
590 | 747 | return endline +
|
591 | 748 | "--" + boundary + endline +
|
|
0 commit comments