package jnpf.file; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jnpf.base.ActionResultCode; import jnpf.exception.DataException; import jnpf.model.filecontent.FileContentComparisonForm; import java.util.HashSet; import java.util.Set; /** Compare canonical, authorized attachments. Never treats a client-supplied checksum as evidence. */ public final class FileContentEquality { private static final ObjectMapper JSON = new ObjectMapper(); private FileContentEquality() {} public static boolean same(String original, Object candidate, FileContentApi api) { JsonNode before = files(original), after = files(candidate); if (before == null || after == null || before.size() != after.size()) return false; boolean identical = true; for (int i = 0; i < before.size(); i++) { if (!before.get(i).path("fileId").equals(after.get(i).path("fileId")) || !before.get(i).path("url").equals(after.get(i).path("url"))) identical = false; } if (identical) return true; // Same immutable server object; display metadata is not content. if (api == null) throw new DataException("文件内容校验服务不可用,请稍后重试"); FileContentComparisonForm form = new FileContentComparisonForm(); form.setOriginal(before.toString()); form.setCandidate(after.toString()); var result = api.sameContent("jnpf-dms", form); if (result == null || !ActionResultCode.SUCCESS.getCode().equals(result.getCode()) || result.getData() == null) throw new DataException("文件内容校验失败,请稍后重试"); return result.getData(); } private static JsonNode files(Object value) { try { JsonNode files = value instanceof String text ? JSON.readTree(text) : JSON.valueToTree(value); if (files == null || !files.isArray() || files.isEmpty() || files.size() > 100) return null; Set ids = new HashSet<>(); for (JsonNode file : files) { String id = file.path("fileId").asText(""); if (id.isBlank() || file.path("url").asText("").isBlank() || !ids.add(id)) return null; } return files; } catch (Exception invalid) { return null; } } }