刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package jnpf.dmsService;
 
import jnpf.dmsEntity.storage.*;
import jnpf.dmsMapper.DmsRevisionEditMapper;
import jnpf.exception.DataException;
import jnpf.util.JsonUtil;
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
 
public class DmsRevisionEditServiceTest {
    @Test public void nonEditableSourcesReceiveFreshVerifiableReceiptsWithoutOldUploadTokens() {
        for (String extension : List.of("txt", "pdf", "doc", "docx")) {
            DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class);
            DmsRevisionEditSource source = source();
            source.setFiles(JsonUtil.getObjectToString(List.of(Map.of("fileId", "original", "name", "source." + extension,
                    "uploadReceipt", "expired-upload", "laiyuan_muban_id", "template"))));
            when(mapper.sources("tenant", "owner", "source", "model")).thenReturn(List.of(source));
            Map<String, String> tickets = new HashMap<>();
            DmsRevisionEditService service = new DmsRevisionEditService(mapper, tickets::get,
                    (json, ttl) -> { tickets.put("receipt", json); return "receipt"; });
            Map<?, ?> file = (Map<?, ?>)((List<?>)service.prepare(request(), "tenant", "owner").get(0).get("files")).get(0);
            assertEquals("receipt", file.get("revisionEditReceipt"));
            assertFalse(file.containsKey("uploadReceipt"));
            Map<?, ?> verified = (Map<?, ?>) service.verify(request()).get("file");
            assertEquals("source." + extension, verified.get("name"));
            assertEquals("template", verified.get("laiyuan_muban_id"));
            source.setFiles(JsonUtil.getObjectToString(List.of(Map.of("fileId", "original", "name", "source." + extension,
                    "uploadReceipt", "expired-upload"))));
            Map<?, ?> ordinary = (Map<?, ?>)((List<?>)service.prepare(request(), "tenant", "owner").get(0).get("files")).get(0);
            assertFalse(ordinary.containsKey("laiyuan_muban_id"));
            assertFalse(((Map<?, ?>)service.verify(request()).get("file")).containsKey("laiyuan_muban_id"));
            when(mapper.sources("tenant", "owner", "source", "model")).thenReturn(List.of());
            assertThrows(DataException.class, () -> service.verify(request()));
        }
    }
    @Test public void unchangedSourceReturnsCompleteTrustedJsonButEditedCopyDoesNot() throws Exception {
        DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class);
        DmsRevisionEditSource source = source();
        String original = "{\"fileId\":\"original\",\"name\":\"source.txt\",\"uploadReceipt\":\"historical-owner-token\",\"fileVersionId\":null}";
        source.setFiles("[" + original + "]");
        when(mapper.sources("tenant", "owner", "source", "model")).thenReturn(List.of(source));
        Map<String,Object> grant = proof();
        grant.put("file", Map.of("fileId", "original", "name", "source.txt"));
        grant.put("sourceFileJson", "forged");
        DmsRevisionEditService service = new DmsRevisionEditService(mapper,
                token -> JsonUtil.getObjectToString(grant), (json, ttl) -> "issued");
        Map<String,Object> verified = service.verify(request());
        com.fasterxml.jackson.databind.ObjectMapper json = new com.fasterxml.jackson.databind.ObjectMapper();
        assertEquals(json.readTree(original), json.readTree((String)verified.get("sourceFileJson")));
        assertFalse(((Map<?,?>)verified.get("file")).containsKey("laiyuan_muban_id"));
        grant.put("file", Map.of("fileId", "copy", "name", "source.docx"));
        assertFalse(service.verify(request()).containsKey("sourceFileJson"));
    }
 
    private static void assertThrows(Class<? extends Throwable> type, Runnable action) {
        try { action.run(); } catch (Throwable error) { if (type.isInstance(error)) return; throw error; }
        fail("Expected " + type.getSimpleName());
    }
 
    private DmsRevisionEditRequest request() {
        DmsRevisionEditRequest r = new DmsRevisionEditRequest();
        r.setTenantId("tenant"); r.setOwnerId("owner"); r.setModelId("model");
        r.setSourceItemId("source"); r.setField("wenjian"); r.setParentField(""); r.setReceipt("receipt"); return r;
    }
    private DmsRevisionEditSource source() {
        DmsRevisionEditSource s = new DmsRevisionEditSource();
        s.setVersionId("version"); s.setField("wenjian"); s.setParentField("");
        s.setFiles("[{\"fileId\":\"original\",\"name\":\"source.docx\"}]"); return s;
    }
    private Map<String,Object> proof() {
        Map<String,Object> p = new HashMap<>();
        p.put("purpose", "dms-revision-edit"); p.put("tenantId", "tenant"); p.put("ownerId", "owner");
        p.put("modelId", "model"); p.put("sourceItemId", "source"); p.put("field", "wenjian"); p.put("parentField", "");
        p.put("versionId", "version"); p.put("originFileId", "original"); p.put("expiresAt", System.currentTimeMillis()+60000);
        p.put("file", Map.of("fileId", "copy", "name", "source.docx")); return p;
    }
    @Test public void receiptRevalidatesCanonicalSourceAndRejectsTampering() {
        DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class);
        when(mapper.sources("tenant","owner","source","model")).thenReturn(List.of(source()));
        Map<String,Object> current = proof();
        DmsRevisionEditService service = new DmsRevisionEditService(mapper,
                token -> JsonUtil.getObjectToString(current), (json, ttl) -> "issued");
        assertEquals("copy", ((Map<?,?>)service.verify(request()).get("file")).get("fileId"));
        for (String field : List.of("purpose", "tenantId", "ownerId", "modelId", "field", "parentField", "versionId", "originFileId")) {
            Object original = current.put(field, "foreign");
            assertThrows(DataException.class, () -> service.verify(request())); current.put(field, original);
        }
        current.put("expiresAt", 1); assertThrows(DataException.class, () -> service.verify(request()));
    }
    @Test public void sourceRemovedAfterIssuanceIsRejected() {
        DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class);
        DmsRevisionEditService service = new DmsRevisionEditService(mapper,
                token -> JsonUtil.getObjectToString(proof()), (json, ttl) -> "issued");
        assertThrows(DataException.class, () -> service.verify(request()));
    }
    @Test public void prepareUsesOnlyServerFilesAndBindsChildVersion() {
        DmsRevisionEditMapper mapper = mock(DmsRevisionEditMapper.class);
        DmsRevisionEditSource child = source(); child.setParentField("jilu_mingxi"); child.setField("jilu_wenjian");
        when(mapper.sources("tenant","owner","source","model")).thenReturn(List.of(child));
        DmsRevisionEditService service = new DmsRevisionEditService(mapper, token -> null, (json, ttl) -> {
            Map<?,?> proof = JsonUtil.getJsonToBean(json, Map.class);
            assertEquals("jilu_mingxi", proof.get("parentField")); assertEquals("version", proof.get("versionId"));
            assertEquals("original", proof.get("originFileId")); assertEquals(14400L, ttl.longValue()); return "issued";
        });
        List<Map<String,Object>> rows = service.prepare(request(), "tenant", "owner");
        assertEquals("issued", ((Map<?,?>)((List<?>)rows.get(0).get("files")).get(0)).get("revisionEditReceipt"));
    }
}