package com.sinata.appointment.service; import static org.assertj.core.api.Assertions.assertThat; import com.fasterxml.jackson.databind.ObjectMapper; import com.sinata.appointment.config.HikvisionQrcodeProperties; import com.sinata.appointment.entity.AppointmentOrder; import com.sinata.appointment.entity.AppointmentVisitor; import com.sinata.appointment.entity.MpUser; import java.time.LocalDate; import java.time.LocalDateTime; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.junit.jupiter.api.Test; class IntegrationHikvisionServiceTest { private static final String AES_KEY = "WwXxYyZz1234!@#$"; private static final String AES_IV = "AaBbCcDd1234!@#$"; private final ObjectMapper objectMapper = new ObjectMapper(); @Test void encryptedQrcodePayloadCanBeDecrypted() throws Exception { IntegrationHikvisionService service = newService(true); String plainJson = "{\"visitorName\":\"张燕\",\"visitorIdCard\":\"51090219960705552X\",\"visitorIdCardType\":\"111\",\"visitorPhone\":\"19382531220\",\"workUnit\":\"喜望\",\"beVisitorPhone\":\"14725836905\",\"startTime\":\"20260727000000\",\"endTime\":\"20260728235959\",\"areas\":\"A区域\",\"beVisitorName\":\"张强\",\"date\":\"260727000000.000\",\"validTime\":\"m4320\",\"codeId\":\"177\"}"; String encrypted = service.encryptQrcodePayload(plainJson); // String encrypted = "nVMz8HLX4TKP8NSYbHAmhXUurZyGWAte2fsf5W/mqu63c1cAhDOg/VhbdtZx0ceMtkOo1qdL5JBdIEJ6J0LPcg6K9vJwcKPVtsDwllxAsnNyKK+JYBry7WOhGYSqys07OsPpXKOEFcS3WfUdq0JZATHr/A5f6Bev1GM6Ge4a3CRXszqaptZavZI7zAxEFnPMnpkuU6JozYmYZh4i7tKuJ43Y7WC6SHLBK//yFo1nQzym+FMHXyIAJCril1S2MhnWz7CdcSjd+I85NVW+5jKU88oFQ4OtxncG4bnjzfJAroDRaqGfLL1vhYOvnSa0ijwYNhuRloJN5P6pM5ZDJ1SBymF012tljU0jMkWu5kM28sqChQrERXq9A2xyZ7DZ5gaTDVZvFvztnZO/QdGMDqcj15427236BTES2Oti+2moZ2smZsbQTbOjJ1AwvXIsyQjUu13wxS8q2WMo9KCO+1aXxw=="; System.out.println(encrypted); System.out.println(decrypt(encrypted)); // // assertThat(encrypted).isNotEqualTo(plainJson); // assertThat(decrypt(encrypted)).isEqualTo(plainJson); } @Test void encryptQrcodePayloadKeepsPlainJsonWhenEncryptionDisabled() { IntegrationHikvisionService service = newService(false); String plainJson = "{\"codeId\":\"TICKET-002\"}"; String result = service.encryptQrcodePayload(plainJson); assertThat(result).isEqualTo(plainJson); } @Test void buildPlainQrcodePayloadOmitsEmptyCustomFieldsAndUsesGivenCodeId() throws Exception { IntegrationHikvisionService service = newService(false); AppointmentOrder order = new AppointmentOrder(); order.setId(1L); order.setVisitedUserName("李医生"); order.setVisitorOrg("测试单位"); order.setVisitStartDate(LocalDate.of(2026, 7, 9)); order.setVisitEndDate(LocalDate.of(2026, 7, 9)); AppointmentVisitor visitor = new AppointmentVisitor(); visitor.setName("张三"); visitor.setMobile("13800000000"); MpUser visitedUser = new MpUser(); visitedUser.setStaffNo("STAFF-001"); visitedUser.setMobile("13900000000"); visitedUser.setNickName("李医生"); String plain = service.buildPlainQrcodePayload( order, visitor, null, visitedUser, "来访", "行政楼", LocalDateTime.of(2026, 7, 9, 10, 0), LocalDateTime.of(2026, 7, 9, 23, 59), 60, "CODE-001", "500101199001011234"); Map payload = objectMapper.readValue(plain, Map.class); assertThat(payload.get("codeId")).isEqualTo("CODE-001"); assertThat(payload.containsKey("jobNo")).isFalse(); assertThat(payload.containsKey("customa")).isFalse(); assertThat(payload.containsKey("customb")).isFalse(); assertThat(payload.containsKey("customc")).isFalse(); assertThat(payload.get("visitorPhone")).isEqualTo("13800000000"); assertThat(payload.containsKey("workUnit")).isFalse(); assertThat(payload.containsKey("visitPurpose")).isFalse(); } private IntegrationHikvisionService newService(boolean encryptEnabled) { HikvisionQrcodeProperties properties = new HikvisionQrcodeProperties(); properties.setEncryptEnabled(encryptEnabled); properties.setAesKey(AES_KEY); properties.setAesIv(AES_IV); return new IntegrationHikvisionService(new ObjectMapper(), properties); } private String decrypt(String encrypted) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(StandardCharsets.UTF_8), "AES"); IvParameterSpec ivSpec = new IvParameterSpec(AES_IV.getBytes(StandardCharsets.UTF_8)); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encrypted)); return new String(decrypted, StandardCharsets.UTF_8); } }