|
@@ -0,0 +1,255 @@
|
|
|
+package com.malk.aipocloud.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.malk.aipocloud.repository.dao.ABEventDao;
|
|
|
+import com.malk.aipocloud.repository.dao.ABUserDao;
|
|
|
+import com.malk.aipocloud.repository.entity.AbEventPo;
|
|
|
+import com.malk.aipocloud.repository.entity.AbUserPo;
|
|
|
+import com.malk.aipocloud.service.ABClient;
|
|
|
+import com.malk.server.dingtalk.DDConf;
|
|
|
+import com.malk.server.dingtalk.DDFormComponentDto;
|
|
|
+import com.malk.service.dingtalk.DDClient;
|
|
|
+import com.malk.service.dingtalk.DDClient_Contacts;
|
|
|
+import com.malk.service.dingtalk.DDClient_Notice;
|
|
|
+import com.malk.service.dingtalk.DDClient_Workflow;
|
|
|
+import com.malk.utils.*;
|
|
|
+import lombok.SneakyThrows;
|
|
|
+import lombok.Synchronized;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class ABImplClient implements ABClient {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DDClient ddClient;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DDClient_Contacts ddClient_contacts;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ABUserDao abUserDao;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通讯录同步
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Synchronized
|
|
|
+ public void syncContact() {
|
|
|
+
|
|
|
+ List<Long> deptList = ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true, DDConf.TOP_DEPARTMENT);
|
|
|
+ for (long deptId : deptList) {
|
|
|
+ List<String> userIds = ddClient_contacts.listDepartmentUserId(ddClient.getAccessToken(), deptId);
|
|
|
+ if (userIds.size() == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String deptName = String.valueOf(ddClient_contacts.getDepartmentInfo(ddClient.getAccessToken(), deptId).get("name"));
|
|
|
+ for (String userId : userIds) {
|
|
|
+ Map userInfo = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), userId);
|
|
|
+ log.info("同步人员, {}", userInfo);
|
|
|
+ if (StringUtils.isBlank(UtilMap.getString(userInfo, "email"))) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ AbUserPo userPo = AbUserPo.builder()
|
|
|
+ .userId(userId)
|
|
|
+ .name(String.valueOf(userInfo.get("name")))
|
|
|
+ .dept(deptName)
|
|
|
+ .email(String.valueOf(userInfo.get("email")))
|
|
|
+ .build();
|
|
|
+ userPo.upsert(abUserDao.findByUserId(userId)); // 匹配更新
|
|
|
+ abUserDao.save(userPo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DDClient_Workflow ddClient_workflow;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ABEventDao abEventDao;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DDConf ddConf;
|
|
|
+
|
|
|
+ // DLP
|
|
|
+ private static final String CODE = "PROC-FA464E73-56A4-43DF-A9DD-CCE11114C129";
|
|
|
+ //private static final String CODE = "PROC-B501FF97-E6FC-41D5-8704-D988D4878F45"; // poc
|
|
|
+ private static final String USER = "dingTalk";
|
|
|
+ private static final int DLP_DAYS = 1;
|
|
|
+ private static final int DLP_NUM = 10;
|
|
|
+
|
|
|
+ private String _getUrl(String path) {
|
|
|
+ return "https://10.14.2.5:8443" + path; // 内网
|
|
|
+// return "https://ucss.aipocloud.com:8443" + path; // 公网
|
|
|
+ }
|
|
|
+
|
|
|
+ // 认证逻辑: token作为后续接口密码
|
|
|
+ private String _getToken() {
|
|
|
+
|
|
|
+ Map header = UtilMap.map("content-type, user-agent", "application/json, QKAct-External-Client");
|
|
|
+ Map body = UtilMap.map("client-id", USER);
|
|
|
+ String rsp = UtilHttp.doRequest(UtilHttp.METHOD.POST, _getUrl("/qkact/v0/checkin"),
|
|
|
+ header, null, body, null, "dingtalk_dlp", "SkyP@ssw0rd1!");
|
|
|
+ Map data = (Map) JSON.parse(rsp);
|
|
|
+ return UtilMap.getString(data, "access-token");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同步审批单 [prd 审批去重逻辑:用户 + 通道 + md5 + 有效期(审批通过且在生效时间内)] - 查询5min, 避免拒绝\撤销重复推送问题
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Synchronized
|
|
|
+ public void syncProcess(LocalDateTime sTime, LocalDateTime eTime) {
|
|
|
+
|
|
|
+ String parttern = "yyyy-MM-dd'T'HH:mm:ss";
|
|
|
+ String pwd = _getToken();
|
|
|
+ Map query = (Map) UtilFile.readJsonObjectFromResource("static/json/query.json"); // 事件查询条件: 查询5min, 避免拒绝\撤销重复推送问题
|
|
|
+ query = (Map) JSON.parse(JSON.toJSONString(query).replace("xxxx-xx-xxSxx:xx:xx", UtilDateTime.formatLocal(sTime, parttern)).replace("xxxx-xx-xxExx:xx:xx", UtilDateTime.formatLocal(eTime, parttern)));
|
|
|
+
|
|
|
+ Map header = UtilMap.map("content-type, user-agent", "application/json, QKAct-External-Client");
|
|
|
+ String rsp = UtilHttp.doRequest(UtilHttp.METHOD.POST, _getUrl("/sps/v1/proxy/dlp-endpoint/_search"), header, null, query, null, USER, pwd);
|
|
|
+ Map data = (Map) JSON.parse(rsp);
|
|
|
+ List<Map> list = (List<Map>) UtilMap.getList(UtilMap.getMap(data, "hits"), "hits");
|
|
|
+ for (Map record : list) {
|
|
|
+
|
|
|
+ record = UtilMap.getMap(record, "_source");
|
|
|
+ List<Map> attachments = (List<Map>) record.get("attachments");
|
|
|
+ if (UtilList.isEmpty(attachments)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // prd 审批去重逻辑:用户 + 通道 + md5 + 有效期(审批通过且在生效时间内)
|
|
|
+ Map<String, String> source = UtilMap.getMap(record, "source");
|
|
|
+ int channel = UtilMap.getInt(record, "channelType");
|
|
|
+ Date detect = UtilDateTime.parse(String.valueOf(record.get("detectDateTime")), "yyyy-MM-dd'T'HH:mm:ss.SSS");
|
|
|
+ Date expire = new Date(detect.getTime() + DLP_DAYS * 24 * 60 * 60 * 1000L);
|
|
|
+ List<AbEventPo> eventPoList = abEventDao.queryList(UtilDateTime.convertToDateFromLocalDateTime(sTime), UtilDateTime.convertToDateFromLocalDateTime(eTime), channel, source.get("logonName"), expire);
|
|
|
+ if (eventPoList.stream().filter(item -> attachments.get(0).get("fileMd5").equals(item.getAttachmentsDisplay().get(0).get("fileMd5"))).findAny().isPresent()) {
|
|
|
+ log.info("记录已存在, {}", record);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 邮箱错误通知管理员
|
|
|
+ String userId = "";
|
|
|
+ AbUserPo userPo = abUserDao.findByEmail(source.get("mail"));
|
|
|
+ if (ObjectUtil.isNull(userPo)) {
|
|
|
+ Map message = UtilMap.map("msgtype", "text");
|
|
|
+ message.put("text", UtilMap.map("content", "「" + source.get("mail") + "」: 未匹配到客户,需要维护花名册邮箱信息。"));
|
|
|
+ ddClient_notice.sendNotification(ddClient.getAccessToken(), Arrays.asList(ddConf.getOperator()), null, false, message);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ userId = userPo.getUserId();
|
|
|
+ //userId = ddConf.getOperator(); // test
|
|
|
+ List<Map<String, String>> policies = UtilMap.getList(record, "matchedPolicies");
|
|
|
+ List<String> tPolicies = policies.stream().map(item -> item.get("name")).collect(Collectors.toList());
|
|
|
+ List<Map<String, String>> rules = UtilMap.getList(record, "extendIncidentRules");
|
|
|
+ List<String> tRules = rules.stream().map(item -> item.get("name")).collect(Collectors.toList());
|
|
|
+ List<Map<String, String>> destinations = UtilMap.getList(record, "destinations");
|
|
|
+ List<String> tDestinations = destinations.stream().map(item -> item.get("displayName")).collect(Collectors.toList());
|
|
|
+
|
|
|
+ AbEventPo eventPo = AbEventPo.builder()
|
|
|
+ .serialId(UtilMap.getInt(record, "serialId"))
|
|
|
+ .userId(userId)
|
|
|
+ .userName(userPo.getName())
|
|
|
+ .logonName(source.get("logonName"))
|
|
|
+ .department(source.get("department"))
|
|
|
+ .fqdn(source.get("fqdn"))
|
|
|
+ .ipAddress(source.get("ipAddress"))
|
|
|
+ .email(source.get("mail"))
|
|
|
+ .detectDateTime(detect)
|
|
|
+ .expire(expire)
|
|
|
+ .channelType(channel)
|
|
|
+ .channelTypeDisplay(AbEventPo.convertChannelTypeDisplay(channel))
|
|
|
+ .policiesName(String.join(", ", tPolicies))
|
|
|
+ .classificationLevelNames(String.join(", ", UtilMap.getList(record, "classificationLevelNames")))
|
|
|
+ .rulesName(String.join(", ", tRules))
|
|
|
+ .tagNames(String.join(", ", UtilMap.getList(record, "tagNames")))
|
|
|
+ .displayName(String.join(", ", tDestinations))
|
|
|
+ .attachments(JSON.toJSONString(attachments))
|
|
|
+ .attachmentsDisplay(attachments)
|
|
|
+ .build();
|
|
|
+ // 组件数据格式化: prd 发送通道钉钉取值发送的目标名称
|
|
|
+ Map ruleForm = UtilMap.map("logonName, department, fqdn, detectDateTime, displayName, tagNames",
|
|
|
+ "用户姓名, 用户所在部门, 计算机名称, DLP事件产生时间, 发送通道, 文件标签名称");
|
|
|
+ Map ruleDetail = UtilMap.map("attachmentsDisplay", UtilMap.map("filename, fileSize, fileMd5", "附件名称, 附件大小, 附件MD5"));
|
|
|
+ ruleForm.put("attachmentsDisplay", "附件信息");
|
|
|
+
|
|
|
+ // 推送钉钉审批
|
|
|
+ Map formData = (Map<String, ?>) JSON.parse(JSON.toJSONString(eventPo));
|
|
|
+ detect = new Date(detect.getTime() + 8 * 60 * 60 * 1000L); // prd utc转gmt显示
|
|
|
+ formData.putAll(UtilMap.map("detectDateTime, logonName", UtilDateTime.formatDateTime(detect), JSON.toJSONString(Arrays.asList(userId)))); // 默认值
|
|
|
+ List<Map> formValues = DDFormComponentDto.formatComponentValues(formData, ruleForm, ruleDetail);
|
|
|
+ Map extInfo = UtilMap.map("dept_id", DDConf.TOP_DEPARTMENT);
|
|
|
+ String processInstanceId = ddClient_workflow.doProcessInstances(ddClient.getAccessToken(), userId, CODE, formValues, extInfo);
|
|
|
+ eventPo.setInstanceId(processInstanceId);
|
|
|
+ eventPo.setState("process");
|
|
|
+ abEventDao.save(eventPo);
|
|
|
+ log.info("推送钉钉审批, {}", eventPo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DDClient_Notice ddClient_notice;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 审批回调
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ @Override
|
|
|
+ public void callbackApprove(String processCode, String processInstanceId, String state, String staffId) {
|
|
|
+ // 回调结果
|
|
|
+ if (CODE.equals(processCode)) {
|
|
|
+
|
|
|
+ if (!"agree".equals(state)) {
|
|
|
+ abEventDao.updateState(processInstanceId, state, null);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // prd: 审批去重逻辑:用户 + 通道 + md5 +有效期(审批通过且在生效时间内)
|
|
|
+ AbEventPo abEventPo = abEventDao.findByInstanceId(processInstanceId);
|
|
|
+ List<Map> attachments = abEventPo.getAttachmentsDisplay();
|
|
|
+ if (attachments.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 匹配审批人信息
|
|
|
+ Map userInfo = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), staffId);
|
|
|
+ Map data = UtilMap.map("approver, submitter_fqdn, approved_time, forensic", userInfo.get("name"), abEventPo.getFqdn(), new Date().getTime() / 1000L, 1);
|
|
|
+ data.putAll(UtilMap.map("submitter_name, submitter_ip, submitter_email", abEventPo.getLogonName(), abEventPo.getIpAddress().split(",")[0], abEventPo.getEmail()));
|
|
|
+ Map attachment = attachments.get(0);
|
|
|
+ data.putAll(UtilMap.map("file_size, file_md5, file_name", attachment.get("fileSize"), attachment.get("fileMd5"), attachment.get("filename")));
|
|
|
+ // prd channel 号 是100-106 的对应成22 通道进行回传
|
|
|
+ int channel = abEventPo.getChannelType();
|
|
|
+ if (channel >= 100 && channel <= 106) {
|
|
|
+ channel = 22;
|
|
|
+ }
|
|
|
+ data.put("channel", Arrays.asList(channel));
|
|
|
+ // 匹配单据必填项
|
|
|
+ //List<Map<String, String>> formComponentValues = UtilMap.getList(instance, "formComponentValues");
|
|
|
+ //String expired = formComponentValues.stream().filter(item -> "过期时间".equals(item.get("name"))).findAny().get().get("value");
|
|
|
+ //data.put("expired_time", UtilDateTime.parse(expired, "yyyy-MM-dd HH:mm").getTime());
|
|
|
+ //data.put("max_num", formComponentValues.stream().filter(item -> "可发送次数".equals(item.get("name"))).findAny().get().get("value"));
|
|
|
+ data.put("expired_time", abEventPo.getExpire().getTime() / 1000L);
|
|
|
+ data.put("max_num", DLP_NUM);
|
|
|
+
|
|
|
+ Map body = UtilMap.map("data", Arrays.asList(data));
|
|
|
+ Map header = UtilMap.map("content-type, user-agent", "application/json, QKAct-External-Client");
|
|
|
+ String rsp = UtilHttp.doRequest(UtilHttp.METHOD.POST, _getUrl("/qkact/v0/dlp/incident/approval"),
|
|
|
+ header, null, body, null, USER, _getToken());
|
|
|
+ abEventDao.updateState(processInstanceId, state, rsp);
|
|
|
+ // 延迟5分钟通知
|
|
|
+ Thread.sleep(5 * 60 * 1000);
|
|
|
+ Map message = UtilMap.map("msgtype", "text");
|
|
|
+ String tips = "「" + abEventPo.getUserName() + "」,您的文件:「" + attachment.get("filename") + "」通过「" + abEventPo.getDisplayName() + "」外发的审批已通过,截止「" + UtilDateTime.formatDateTime(abEventPo.getExpire()) + "」前有效,请重新发起文件外发。";
|
|
|
+ message.put("text", UtilMap.map("content", tips));
|
|
|
+ ddClient_notice.sendNotification(ddClient.getAccessToken(), Arrays.asList(abEventPo.getUserId()), null, false, message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|