Skip to content

Commit 76e651f

Browse files
committed
feat: add bilingual support
1 parent b108717 commit 76e651f

135 files changed

Lines changed: 9241 additions & 3453 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/java/top/whgojp/common/config/WebConfig.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@
33
import lombok.SneakyThrows;
44
import lombok.extern.slf4j.Slf4j;
55
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.context.annotation.Bean;
67
import org.springframework.context.annotation.Configuration;
8+
import org.springframework.context.MessageSource;
9+
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
10+
import org.springframework.web.servlet.LocaleResolver;
11+
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
12+
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
713
import org.springframework.web.servlet.config.annotation.*;
814
import top.whgojp.common.constant.SysConstant;
915

16+
import java.util.Locale;
17+
1018
/**
1119
* @description 自定义静态资源的访问路径、文件映射
1220
* @author: whgojp
@@ -30,4 +38,34 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
3038
.addResourceLocations("classpath:/static/");
3139
}
3240

41+
@Bean
42+
public MessageSource messageSource() {
43+
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
44+
messageSource.setBasename("classpath:i18n/messages");
45+
messageSource.setDefaultEncoding("UTF-8");
46+
messageSource.setFallbackToSystemLocale(false);
47+
return messageSource;
48+
}
49+
50+
@Bean
51+
public LocaleResolver localeResolver() {
52+
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
53+
localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
54+
localeResolver.setCookieName("JavaSecLab-Language");
55+
localeResolver.setCookieMaxAge(30 * 24 * 60 * 60);
56+
return localeResolver;
57+
}
58+
59+
@Bean
60+
public LocaleChangeInterceptor localeChangeInterceptor() {
61+
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
62+
interceptor.setParamName("lang");
63+
return interceptor;
64+
}
65+
66+
@Override
67+
public void addInterceptors(InterceptorRegistry registry) {
68+
registry.addInterceptor(localeChangeInterceptor());
69+
}
70+
3371
}

src/main/java/top/whgojp/common/enums/LoginError.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,24 @@
1313
public enum LoginError {
1414

1515

16-
FAILURE(0, "登录失败!"),
16+
FAILURE(0, "login.error.failure"),
1717

18-
BADCREDENTIALS(1, "用户名或密码错误!"),
18+
BADCREDENTIALS(1, "login.error.badCredentials"),
1919

20-
LOCKED(2, "用户已被锁定,无法登录!"),
20+
LOCKED(2, "login.error.locked"),
2121

22-
ACCOUNTEXPIRED(3, "用户已过时,无法登录!"),
22+
ACCOUNTEXPIRED(3, "login.error.accountExpired"),
2323

24-
USERNAMENOTFOUND(4, "用户不存在!"),
24+
USERNAMENOTFOUND(4, "login.error.usernameNotFound"),
2525

26-
CAPTCHANOTFOUND(5,"验证码不能为空!"),
27-
CAPTCHAEXPIRED(6,"验证码已过期!"),
28-
CAPTCHAERROR(7,"验证码错误!");
26+
CAPTCHANOTFOUND(5,"login.error.captchaNotFound"),
27+
CAPTCHAEXPIRED(6,"login.error.captchaExpired"),
28+
CAPTCHAERROR(7,"login.error.captchaError");
2929

3030

3131
private Integer type;
3232

33-
private String message;
33+
private String messageCode;
3434

3535
private final static Map<Integer, LoginError> mappings = new HashMap<>();
3636

@@ -50,15 +50,15 @@ public static LoginError resolve(Integer type) {
5050
return type != null ? mappings.get(type) : null;
5151
}
5252

53-
public static String getMessage(Integer type) {
53+
public static String getMessageCode(Integer type) {
5454
LoginError loginError = resolve(type);
5555

56-
return loginError != null ? loginError.message : null;
56+
return loginError != null ? loginError.messageCode : null;
5757
}
5858

59-
LoginError(Integer type, String message) {
59+
LoginError(Integer type, String messageCode) {
6060
this.type = type;
61-
this.message = message;
61+
this.messageCode = messageCode;
6262
}
6363

6464
public Integer getType() {
@@ -69,11 +69,11 @@ public void setType(Integer type) {
6969
this.type = type;
7070
}
7171

72-
public String getMessage() {
73-
return message;
72+
public String getMessageCode() {
73+
return messageCode;
7474
}
7575

76-
public void setMessage(String message) {
77-
this.message = message;
76+
public void setMessageCode(String messageCode) {
77+
this.messageCode = messageCode;
7878
}
79-
}
79+
}

src/main/java/top/whgojp/common/utils/UploadUtil.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public class UploadUtil {
1717
private SysConstant sysConstant;
1818

1919
public String uploadFile(MultipartFile file, String suffix, String path) throws IOException {
20+
String fileUrl = uploadFileAndReturnUrl(file, suffix, path);
21+
return "上传文件成功,文件路径:" + fileUrl;
22+
}
23+
24+
public String uploadFileAndReturnUrl(MultipartFile file, String suffix, String path) throws IOException {
2025
// 从配置中获取上传目录
2126
String uploadFolderPath = sysConstant.getUploadFolder();
2227
try {
@@ -31,11 +36,11 @@ public String uploadFile(MultipartFile file, String suffix, String path) throws
3136
// 保存文件
3237
file.transferTo(new File(newFilePath));
3338
log.info("上传文件成功,文件路径:" + newFilePath);
34-
return "上传文件成功,文件路径:" + path + fileName;
39+
return path + fileName;
3540
} catch (IOException e) {
3641
log.error("文件上传失败:{}", e.getMessage(), e);
3742
throw e; // 重新抛出异常供上层处理
3843
}
3944
}
4045

41-
}
46+
}

src/main/java/top/whgojp/modules/components/jackson/controller/JacksonController.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import io.swagger.annotations.Api;
77
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.context.MessageSource;
9+
import org.springframework.context.i18n.LocaleContextHolder;
810
import org.springframework.stereotype.Controller;
911
import org.springframework.web.bind.annotation.*;
1012

@@ -23,6 +25,12 @@
2325
@CrossOrigin(origins = "*")
2426
@RequestMapping("/jackson")
2527
public class JacksonController {
28+
private final MessageSource messageSource;
29+
30+
public JacksonController(MessageSource messageSource) {
31+
this.messageSource = messageSource;
32+
}
33+
2634
@RequestMapping("")
2735
public String jackson() {
2836
return "vul/components/jackson";
@@ -40,10 +48,10 @@ public String vul(@RequestBody(required = false) String content) {
4048

4149
// 反序列化接收的JSON数据,触发漏洞
4250
Object obj = mapper.readValue(content, Object.class);
43-
return "[+]Jackson 反序列化: " + obj.toString();
51+
return msg("component.jackson.result.vul", obj);
4452
} catch (Exception e) {
4553
e.printStackTrace();
46-
return "[-]Jackson反序列化失败";
54+
return msg("component.jackson.result.failed");
4755
}
4856
}
4957

@@ -63,10 +71,14 @@ public String safeJackson(@RequestBody(required = false) String payload) {
6371
return mapper.writeValueAsString(safePayload);
6472
} catch (Exception e) {
6573
e.printStackTrace();
66-
return "Jackson Safe Deserialization Error";
74+
return msg("component.jackson.result.safeFailed");
6775
}
6876
}
6977

78+
private String msg(String key, Object... args) {
79+
return messageSource.getMessage(key, args, LocaleContextHolder.getLocale());
80+
}
81+
7082

7183
/**
7284
* CVE-2020-35728

src/main/java/top/whgojp/modules/components/log4j2/controller/Log4j2Controller.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import io.swagger.annotations.Api;
44
import org.apache.logging.log4j.LogManager;
55
import org.apache.logging.log4j.Logger;
6+
import org.springframework.context.MessageSource;
7+
import org.springframework.context.i18n.LocaleContextHolder;
68
import org.springframework.stereotype.Controller;
79
import org.springframework.web.bind.annotation.*;
810
import org.apache.commons.text.StringEscapeUtils;
@@ -19,6 +21,12 @@
1921
@CrossOrigin(origins = "*")
2022
@RequestMapping("/log4j2")
2123
public class Log4j2Controller {
24+
private final MessageSource messageSource;
25+
26+
public Log4j2Controller(MessageSource messageSource) {
27+
this.messageSource = messageSource;
28+
}
29+
2230
@RequestMapping("")
2331
public String log4j2() {
2432
return "vul/components/log4j2";
@@ -31,7 +39,7 @@ public String log4j2() {
3139
public String vul(@RequestParam("payload") String payload) {
3240
System.out.println("[+]Log4j2反序列化:"+payload);
3341
logger.error(payload);
34-
return "[+]Log4j2反序列化:"+payload;
42+
return msg("component.log4j2.result.vul", payload);
3543
}
3644

3745
@PostMapping("/safe")
@@ -41,9 +49,11 @@ public String safe(@RequestParam("payload") String payload) {
4149

4250
System.out.println("[+]Log4j2反序列化:"+payload);
4351
logger.error(payload);
44-
return "[+]Log4j2反序列化:"+payload;
52+
return msg("component.log4j2.result.safe", payload);
4553
}
4654

47-
55+
private String msg(String key, Object... args) {
56+
return messageSource.getMessage(key, args, LocaleContextHolder.getLocale());
57+
}
4858

4959
}

src/main/java/top/whgojp/modules/components/shiro/controller/ShiroController.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import io.swagger.annotations.Api;
44
import lombok.extern.slf4j.Slf4j;
55
import org.apache.shiro.web.mgt.CookieRememberMeManager;
6+
import org.springframework.context.MessageSource;
7+
import org.springframework.context.i18n.LocaleContextHolder;
68
import org.springframework.stereotype.Controller;
79
import org.springframework.web.bind.annotation.CrossOrigin;
810
import org.springframework.web.bind.annotation.GetMapping;
@@ -25,6 +27,12 @@
2527
@CrossOrigin(origins = "*")
2628
@RequestMapping("/shiro")
2729
public class ShiroController {
30+
private final MessageSource messageSource;
31+
32+
public ShiroController(MessageSource messageSource) {
33+
this.messageSource = messageSource;
34+
}
35+
2836
@RequestMapping("")
2937
public String shiro() {
3038
return "vul/components/shiro";
@@ -35,10 +43,14 @@ public String shiro() {
3543
public R getShiroKey(){
3644
try{
3745
byte[] key = new CookieRememberMeManager().getCipherKey();
38-
return R.ok("Shiro AES密钥硬编码为:"+new String(Base64.getEncoder().encode(key)));
46+
return R.ok(msg("component.shiro.result.key", new String(Base64.getEncoder().encode(key))));
3947
}catch (Exception ignored){
40-
return R.error("获取AES密钥失败!");
48+
return R.error(msg("component.shiro.result.keyFailed"));
4149
}
4250
}
4351

52+
private String msg(String key, Object... args) {
53+
return messageSource.getMessage(key, args, LocaleContextHolder.getLocale());
54+
}
55+
4456
}

src/main/java/top/whgojp/modules/components/xstream/controller/XstreamController.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import com.thoughtworks.xstream.security.*;
55
import io.swagger.annotations.Api;
66
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.context.MessageSource;
8+
import org.springframework.context.i18n.LocaleContextHolder;
79
import org.springframework.stereotype.Controller;
810
import org.springframework.web.bind.annotation.CrossOrigin;
911
import org.springframework.web.bind.annotation.RequestBody;
@@ -25,6 +27,12 @@
2527
@CrossOrigin(origins = "*")
2628
@RequestMapping("/xstream")
2729
public class XstreamController {
30+
private final MessageSource messageSource;
31+
32+
public XstreamController(MessageSource messageSource) {
33+
this.messageSource = messageSource;
34+
}
35+
2836
@RequestMapping("")
2937
public String xstream() {
3038
return "vul/components/xstream";
@@ -51,10 +59,10 @@ public String vul(@RequestBody(required = false) String content) {
5159
Object result = xs.fromXML(content); // 反序列化得到的对象
5260

5361
// 检查反序列化后的结果并返回相关信息
54-
return "组件漏洞-Xstream Vul, 反序列化结果: \n" + result;
62+
return msg("component.xstream.result.vul", result);
5563
} catch (Exception e) {
5664
log.error("XStream反序列化失败", e);
57-
return "组件漏洞-Xstream Vul 执行失败:" + e.getMessage();
65+
return msg("component.xstream.result.vulFailed", e.getMessage());
5866
}
5967
}
6068

@@ -69,10 +77,10 @@ public String safe1(@RequestBody(required = false) String content) {
6977
// 黑名单示例:拒绝已知危险类型。
7078
xstream.denyPermission(new ExplicitTypePermission(new Class[]{ImageIO.class}));
7179
Object result = xstream.fromXML(content);
72-
return "组件漏洞-Xstream Safe-BlackList, 解析结果:" + result;
80+
return msg("component.xstream.result.blacklist", result);
7381
} catch (Exception e) {
7482
log.error("XStream黑名单场景解析失败", e);
75-
return "组件漏洞-Xstream Safe-BlackList 执行失败:" + e.getMessage();
83+
return msg("component.xstream.result.blacklistFailed", e.getMessage());
7684
}
7785
}
7886
@RequestMapping("/safe2")
@@ -92,13 +100,17 @@ public String safe2(@RequestBody(required = false) String content) {
92100
// 添加自定义的类列表
93101
xstream.addPermission(new ExplicitTypePermission(new Class[]{Date.class}));
94102
Object result = xstream.fromXML(content);
95-
return "组件漏洞-Xstream Safe-WhiteList, 解析结果:" + result;
103+
return msg("component.xstream.result.allowlist", result);
96104
} catch (Exception e) {
97105
log.error("XStream白名单场景解析失败", e);
98-
return "组件漏洞-Xstream Safe-WhiteList 执行失败:" + e.getMessage();
106+
return msg("component.xstream.result.allowlistFailed", e.getMessage());
99107
}
100108
}
101109

110+
private String msg(String key, Object... args) {
111+
return messageSource.getMessage(key, args, LocaleContextHolder.getLocale());
112+
}
113+
102114
// CVE-2020-26259 任意文件删除示例
103115
public static void main(String[] args) {
104116
String xml_poc = "<map>\n" +

0 commit comments

Comments
 (0)