Skip to content

Commit c9adee8

Browse files
AyuAyu
Ayu
authored and
Ayu
committed
[feature] Desensitize sensitive information(new)
1 parent f31909a commit c9adee8

File tree

8 files changed

+389
-2
lines changed

8 files changed

+389
-2
lines changed

hertzbeat-common/pom.xml

+8
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,20 @@
135135
<version>${poi.version}</version>
136136
<scope>compile</scope>
137137
</dependency>
138+
138139
<dependency>
139140
<groupId>org.apache.poi</groupId>
140141
<artifactId>poi-ooxml</artifactId>
141142
<version>${poi.version}</version>
142143
<scope>compile</scope>
143144
</dependency>
145+
146+
<!-- hutool -->
147+
<dependency>
148+
<groupId>cn.hutool</groupId>
149+
<artifactId>hutool-all</artifactId>
150+
<version>${hutool-all.version}</version>
151+
</dependency>
144152
</dependencies>
145153

146154
</project>

hertzbeat-common/src/main/java/org/apache/hertzbeat/common/cache/CacheFactory.java

+9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ private CacheFactory() {}
3333

3434
private static final CommonCacheService<String, Object> ALERT_CONVERGE_CACHE =
3535
new CaffeineCacheServiceImpl<>(10, 1000, Duration.ofDays(1), false);
36+
37+
private static final CommonCacheService<String, Object> DESENSITIZATION_MAP_CACHE =
38+
new CaffeineCacheServiceImpl<>(10, 1000, Duration.ofDays(1), false);
3639

3740
/**
3841
* get notice cache
@@ -57,4 +60,10 @@ public static CommonCacheService<String, Object> getAlertSilenceCache() {
5760
public static CommonCacheService<String, Object> getAlertConvergeCache() {
5861
return ALERT_CONVERGE_CACHE;
5962
}
63+
64+
/**
65+
* get desensitizationMap cache
66+
* @return desensitizationMap cache
67+
*/
68+
public static CommonCacheService<String, Object> getDesensitizationMapCache(){return DESENSITIZATION_MAP_CACHE;};
6069
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hertzbeat.common.entity.dto.vo;
19+
20+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
21+
import io.swagger.v3.oas.annotations.media.Schema;
22+
import jakarta.persistence.Column;
23+
import jakarta.persistence.GeneratedValue;
24+
import jakarta.persistence.GenerationType;
25+
import jakarta.persistence.Id;
26+
import jakarta.validation.constraints.Min;
27+
import jakarta.validation.constraints.NotBlank;
28+
import jakarta.validation.constraints.NotNull;
29+
import jakarta.validation.constraints.Size;
30+
import lombok.AllArgsConstructor;
31+
import lombok.Builder;
32+
import lombok.Data;
33+
import lombok.NoArgsConstructor;
34+
import org.apache.hertzbeat.common.serialize.EmailDesensitizationSerializer;
35+
import org.apache.hertzbeat.common.serialize.PhoneDesensitizationSerializer;
36+
import org.springframework.data.annotation.CreatedBy;
37+
import org.springframework.data.annotation.CreatedDate;
38+
import org.springframework.data.annotation.LastModifiedBy;
39+
import org.springframework.data.annotation.LastModifiedDate;
40+
41+
import java.time.LocalDateTime;
42+
43+
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
44+
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE;
45+
46+
/**
47+
* 2024-12-06
48+
*/
49+
@Data
50+
@AllArgsConstructor
51+
@NoArgsConstructor
52+
@Builder
53+
public class NoticeReceiverVO {
54+
55+
@Id
56+
@GeneratedValue(strategy = GenerationType.IDENTITY)
57+
@Schema(title = "Recipient entity primary key index ID", description = "Recipient entity primary key index ID",
58+
example = "87584674384", accessMode = READ_ONLY)
59+
private Long id;
60+
61+
@Schema(title = "Recipient name", description = "Recipient name",
62+
example = "tom", accessMode = READ_WRITE)
63+
@Size(max = 100)
64+
@NotBlank(message = "name can not null")
65+
private String name;
66+
67+
@Schema(title = "Notification information method: 0-SMS 1-Email 2-webhook 3-WeChat Official Account 4-Enterprise WeChat Robot "
68+
+ "5-DingTalk Robot 6-FeiShu Robot 7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise WeChat app message",
69+
description = "Notification information method: "
70+
+ "0-SMS 1-Email 2-webhook 3-WeChat Official Account "
71+
+ "4-Enterprise WeChat Robot 5-DingTalk Robot 6-FeiShu Robot "
72+
+ "7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise "
73+
+ "WeChat app message",
74+
accessMode = READ_WRITE)
75+
@Min(0)
76+
@NotNull(message = "type can not null")
77+
private Byte type;
78+
79+
@Schema(title = "Mobile number: Valid when the notification method is SMS",
80+
description = "Mobile number: Valid when the notification method is SMS",
81+
example = "18923435643", accessMode = READ_WRITE)
82+
@Size(max = 100)
83+
@JsonSerialize(using = PhoneDesensitizationSerializer.class)
84+
private String phone;
85+
86+
@Schema(title = "Email account: Valid when the notification method is email",
87+
description = "Email account: Valid when the notification method is email",
88+
example = "[email protected]", accessMode = READ_WRITE)
89+
@Size(max = 100)
90+
@JsonSerialize(using = EmailDesensitizationSerializer.class)
91+
private String email;
92+
93+
@Schema(title = "URL address: The notification method is valid for webhook",
94+
description = "URL address: The notification method is valid for webhook",
95+
example = "https://www.tancloud.cn", accessMode = READ_WRITE)
96+
@Size(max = 300)
97+
@Column(length = 300)
98+
private String hookUrl;
99+
100+
@Schema(title = "openId : The notification method is valid for WeChat official account, enterprise WeChat robot or FlyBook robot",
101+
description = "openId : The notification method is valid for WeChat official account, enterprise WeChat robot or FlyBook robot",
102+
example = "343432", accessMode = READ_WRITE)
103+
@Size(max = 300)
104+
@Column(length = 300)
105+
private String wechatId;
106+
107+
@Schema(title = "Access token : The notification method is valid for DingTalk robot",
108+
description = "Access token : The notification method is valid for DingTalk robot",
109+
example = "34823984635647", accessMode = READ_WRITE)
110+
@Size(max = 300)
111+
@Column(length = 300)
112+
private String accessToken;
113+
114+
@Schema(title = "Telegram bot token : The notification method is valid for Telegram Bot",
115+
description = "Telegram bot token : The notification method is valid for Telegram Bot",
116+
example = "1499012345:AAEOB_wEYS-DZyPM3h5NzI8voJMXXXXXX", accessMode = READ_WRITE)
117+
private String tgBotToken;
118+
119+
@Schema(title = "Telegram user id: The notification method is valid for Telegram Bot",
120+
description = "Telegram user id: The notification method is valid for Telegram Bot",
121+
example = "779294123", accessMode = READ_WRITE)
122+
private String tgUserId;
123+
124+
@Schema(title = "DingTalk,FeiShu,WeWork user id: The notification method is valid for DingTalk,FeiShu,WeWork Bot",
125+
description = "DingTalk,FeiShu,WeWork user id: The notification method is valid for DingTalk,FeiShu,WeWork Bot",
126+
example = "779294123", accessMode = READ_WRITE)
127+
private String userId;
128+
129+
@Schema(title = "URL address: The notification method is valid for Slack",
130+
description = "URL address: The notification method is valid for Slack",
131+
example = "https://hooks.slack.com/services/XXXX/XXXX/XXXX", accessMode = READ_WRITE)
132+
@Size(max = 300)
133+
@Column(length = 300)
134+
private String slackWebHookUrl;
135+
136+
@Schema(title = "Enterprise weChat message: The notification method is valid for Enterprise WeChat app message",
137+
description = "Enterprise weChat message: The notification method is valid for Enterprise WeChat app message",
138+
example = "ww1a603432123d0dc1", accessMode = READ_WRITE)
139+
private String corpId;
140+
141+
@Schema(title = "Enterprise weChat appId: The notification method is valid for Enterprise WeChat app message",
142+
description = "Enterprise weChat appId: The notification method is valid for Enterprise WeChat app message",
143+
example = "1000001", accessMode = READ_WRITE)
144+
private Integer agentId;
145+
146+
@Schema(title = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message",
147+
description = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message",
148+
example = "oUydwn92ey0lnuY02MixNa57eNK-20dJn5NEOG-u2uE", accessMode = READ_WRITE)
149+
private String appSecret;
150+
151+
@Schema(title = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message",
152+
description = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message",
153+
example = "779294123", accessMode = READ_WRITE)
154+
private String partyId;
155+
156+
@Schema(title = "Enterprise weChat tag id: The notification method is valid for Enterprise WeChat app message",
157+
description = "Enterprise weChat tag id: The notification method is valid for Enterprise WeChat app message",
158+
example = "779294123", accessMode = READ_WRITE)
159+
private String tagId;
160+
161+
@Schema(title = "Discord channel id: The notification method is valid for Discord",
162+
description = "Discord channel id: The notification method is valid for Discord",
163+
example = "1065303416030642266", accessMode = READ_WRITE)
164+
@Size(max = 300)
165+
@Column(length = 300)
166+
private String discordChannelId;
167+
168+
@Schema(title = "Discord bot token: The notification method is valid for Discord",
169+
description = "Discord bot token: The notification method is valid for Discord",
170+
example = "MTA2NTMwMzU0ODY4Mzg4MjUzNw.xxxxx.xxxxxxx", accessMode = READ_WRITE)
171+
@Size(max = 300)
172+
@Column(length = 300)
173+
private String discordBotToken;
174+
175+
@Schema(title = "huawei cloud SMN ak: If the notification method is valid for huawei cloud SMN",
176+
description = "huawei cloud SMN ak: If the notification method is valid for huawei cloud SMN",
177+
example = "NCVBODJOEYHSW3VNXXXX", accessMode = READ_WRITE)
178+
@Size(max = 22)
179+
@Column(length = 22)
180+
private String smnAk;
181+
182+
@Schema(title = "huawei cloud SMN sk: If the notification method is valid for huawei cloud SMN",
183+
description = "huawei cloud SMN sk: If the notification method is valid for huawei cloud SMN",
184+
example = "nmSNhUJN9MlpPl8lfCsgdA0KvHCL9JXXXX", accessMode = READ_WRITE)
185+
@Size(max = 42)
186+
@Column(length = 42)
187+
private String smnSk;
188+
189+
@Schema(title = "huawei cloud SMN projectId: If the notification method is valid for huawei cloud SMN",
190+
description = "huawei cloud SMN projectId: If the notification method is valid for huawei cloud SMN",
191+
example = "320c2fb11edb47a481c299c1XXXXXX", accessMode = READ_WRITE)
192+
@Size(max = 32)
193+
@Column(length = 32)
194+
private String smnProjectId;
195+
196+
@Schema(title = "huawei cloud SMN region: If the notification method is valid for huawei cloud SMN",
197+
description = "huawei cloud SMN region: If the notification method is valid for huawei cloud SMN",
198+
example = "cn-east-3", accessMode = READ_WRITE)
199+
@Size(max = 32)
200+
@Column(length = 32)
201+
private String smnRegion;
202+
203+
@Schema(title = "huawei cloud SMN TopicUrn: If the notification method is valid for huawei cloud SMN",
204+
description = "huawei cloud SMN TopicUrn: If the notification method is valid for huawei cloud SMN",
205+
example = "urn:smn:cn-east-3:xxx:hertzbeat_test", accessMode = READ_WRITE)
206+
@Size(max = 300)
207+
@Column(length = 300)
208+
private String smnTopicUrn;
209+
210+
@Schema(title = "serverChanToken : The notification method is valid for ServerChan",
211+
description = "serverChanToken : The notification method is valid for ServerChan",
212+
example = "SCT193569TSNm6xIabdjqeZPtOGOWcvU1e", accessMode = READ_WRITE)
213+
@Size(max = 300)
214+
@Column(length = 300)
215+
private String serverChanToken;
216+
217+
@Schema(title = "Gotify token : The notification method is valid for Gotify",
218+
description = "Gotify token : The notification method is valid for Gotify",
219+
example = "A845h__ZMqDxZlO", accessMode = READ_WRITE)
220+
@Size(max = 300)
221+
@Column(length = 300)
222+
private String gotifyToken;
223+
224+
@Schema(title = "The creator of this record", example = "tom",
225+
accessMode = READ_ONLY)
226+
@CreatedBy
227+
private String creator;
228+
229+
@Schema(title = "This record was last modified by", example = "tom", accessMode = READ_ONLY)
230+
@LastModifiedBy
231+
private String modifier;
232+
233+
@Schema(title = "Record creation time (millisecond timestamp)",
234+
example = "1612198922000", accessMode = READ_ONLY)
235+
@CreatedDate
236+
private LocalDateTime gmtCreate;
237+
238+
@Schema(title = "Record the latest modification time (timestamp in milliseconds)",
239+
example = "1612198444000", accessMode = READ_ONLY)
240+
@LastModifiedDate
241+
private LocalDateTime gmtUpdate;
242+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hertzbeat.common.serialize;
19+
20+
import cn.hutool.core.util.StrUtil;
21+
import com.fasterxml.jackson.core.JsonGenerator;
22+
import com.fasterxml.jackson.databind.JsonSerializer;
23+
import com.fasterxml.jackson.databind.SerializerProvider;
24+
import org.apache.hertzbeat.common.cache.CacheFactory;
25+
import org.apache.hertzbeat.common.cache.CommonCacheService;
26+
import org.apache.hertzbeat.common.entity.dto.vo.NoticeReceiverVO;
27+
28+
import java.io.IOException;
29+
30+
/**
31+
* 2024-12-06
32+
* Email Desensitizing serializer
33+
*/
34+
public class EmailDesensitizationSerializer extends JsonSerializer<String> {
35+
36+
@Override
37+
public void serialize(String email, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
38+
String emailDesensitization = "";
39+
CommonCacheService<String, Object> desensitizationMapCache = CacheFactory.getDesensitizationMapCache();
40+
if (StrUtil.isNotBlank(email)) {
41+
int index = StrUtil.indexOf(email, '@');
42+
emailDesensitization = index <= 1 ? email :
43+
StrUtil.replace(email, 1, index, '*');
44+
NoticeReceiverVO currentValue = (NoticeReceiverVO) jsonGenerator.getOutputContext().getCurrentValue();
45+
desensitizationMapCache.put(currentValue.getId() + "_" + emailDesensitization, email);
46+
}
47+
jsonGenerator.writeString(emailDesensitization);
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hertzbeat.common.serialize;
19+
20+
import cn.hutool.core.util.DesensitizedUtil;
21+
import cn.hutool.core.util.StrUtil;
22+
import com.fasterxml.jackson.core.JsonGenerator;
23+
import com.fasterxml.jackson.databind.JsonSerializer;
24+
import com.fasterxml.jackson.databind.SerializerProvider;
25+
import org.apache.hertzbeat.common.cache.CacheFactory;
26+
import org.apache.hertzbeat.common.cache.CommonCacheService;
27+
import org.apache.hertzbeat.common.entity.dto.vo.NoticeReceiverVO;
28+
29+
import java.io.IOException;
30+
31+
/**
32+
* 2024-12-06
33+
* Phone Desensitizing serializer
34+
*/
35+
public class PhoneDesensitizationSerializer extends JsonSerializer<String> {
36+
37+
@Override
38+
public void serialize(String phone, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
39+
String phoneDesensitization = "";
40+
CommonCacheService<String, Object> desensitizationMapCache = CacheFactory.getDesensitizationMapCache();
41+
if (StrUtil.isNotBlank(phone)){
42+
phoneDesensitization = DesensitizedUtil.mobilePhone(phone);
43+
NoticeReceiverVO currentValue = (NoticeReceiverVO)jsonGenerator.getOutputContext().getCurrentValue();
44+
desensitizationMapCache.put(currentValue.getId()+"_"+phoneDesensitization, phone);
45+
}
46+
47+
jsonGenerator.writeString(phoneDesensitization);
48+
}
49+
}

0 commit comments

Comments
 (0)