package jnpf.bizcommon.onlyoffice.service.impl; import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeProperties; import jnpf.exception.DataException; import jnpf.file.FileApi; import jnpf.file.FileUploadApi; import jnpf.util.UploaderUtil; import org.mockito.MockedStatic; import org.dromara.x.file.storage.core.FileInfo; import org.junit.Test; import java.util.Map; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; public class UploadEditStorageTest { private final String lease = "0123456789abcdef0123456789abcdef"; @Test public void rejectsTraversalAndMissingScope() { for (String directory : new String[]{"../annex", "a/b", "a,b", "/tmp", ""}) { try { UploadEditStorage.relativeDirectory(directory, "tenant", lease); fail("accepted unsafe directory"); } catch (DataException expected) { } } assertNotEquals(UploadEditStorage.relativeDirectory("onlyoffice-edit-temp", "a", lease), UploadEditStorage.relativeDirectory("onlyoffice-edit-temp", "b", lease)); } @Test public void reviewDirectoryRemainsScopedAndRejectsMalformedLeaseIds() { String review = UploadEditStorage.relativeDirectory("onlyoffice-edit-temp", "tenant", "review_" + lease); assertTrue(review.endsWith("/review_" + lease + "/")); assertNotEquals(review, UploadEditStorage.relativeDirectory("onlyoffice-edit-temp", "tenant", lease)); for (String invalid : new String[]{"review_", "review_../" + lease, "review_" + lease + "/x", "review_" + lease + ",x", "review_review_" + lease}) { try { UploadEditStorage.relativeDirectory("onlyoffice-edit-temp", "tenant", invalid); fail("unsafe lease accepted"); } catch (DataException expected) { } } } @Test public void savesReviewResultUnderDedicatedDirectory() { assertSaved("review_" + lease); } @Test public void savesUnderDedicatedDirectoryAndNeverReplacesSource() { assertSaved(lease); assertSaved(lease, "doc"); } private void assertSaved(String lease) { assertSaved(lease, "docx"); } private void assertSaved(String lease, String extension) { FileApi fileApi = mock(FileApi.class); FileUploadApi upload = mock(FileUploadApi.class); when(fileApi.getPath("annex")).thenReturn("annex/"); FileInfo stored = new FileInfo(); stored.setFilename("generated." + extension); stored.setSize(3L); when(upload.uploadFile(any(), anyString(), eq("source." + extension))).thenReturn(stored); UploadEditStorage storage = new UploadEditStorage(new OnlyOfficeProperties(), fileApi, upload); try (MockedStatic urls = mockStatic(UploaderUtil.class)) { urls.when(() -> UploaderUtil.uploaderFile(anyString())).thenReturn("/file?token=test"); Map saved = storage.save("tenant", lease, "source." + extension, new byte[]{1, 2, 3}); String prefix = UploadEditStorage.relativeDirectory("onlyoffice-edit-temp", "tenant", lease); assertEquals(prefix.replace('/', ',') + "generated." + extension, saved.get("fileId")); assertEquals("source." + extension, saved.get("name")); assertEquals(extension, saved.get("fileExtension")); verify(upload).uploadFile(argThat(part -> ("doc".equals(extension) ? "application/msword" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document").equals(part.getContentType())), eq("annex/" + prefix), eq("source." + extension)); verifyNoMoreInteractions(upload); } } @Test(expected = DataException.class) public void missingFileServiceResultIsNotReportedAsSaved() { FileApi fileApi = mock(FileApi.class); when(fileApi.getPath("annex")).thenReturn("annex/"); new UploadEditStorage(new OnlyOfficeProperties(), fileApi, mock(FileUploadApi.class)) .save("tenant", lease, "source.docx", new byte[]{1}); } }