[feat] Auto-generate AES key if not configured (#3604)

Co-authored-by: shown <yuluo08290126@gmail.com>
This commit is contained in:
Yang Chen
2025-07-24 21:06:45 +08:00
committed by GitHub
co-authored by shown
parent 2f5cfa9d5d
commit a13dd89fd2
5 changed files with 54 additions and 20 deletions
@@ -19,7 +19,6 @@ package org.apache.hertzbeat.common.config;
import org.apache.hertzbeat.common.constants.ConfigConstants;
import org.apache.hertzbeat.common.constants.SignConstants;
import org.apache.hertzbeat.common.util.AesUtil;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
@@ -34,10 +33,4 @@ import org.springframework.context.annotation.ComponentScan;
+ ConfigConstants.FunctionModuleConstants.COMMON)
@EnableConfigurationProperties(CommonProperties.class)
public class CommonConfig {
public CommonConfig(CommonProperties commonProperties) {
if (commonProperties != null && commonProperties.getSecret() != null) {
AesUtil.setDefaultSecretKey(commonProperties.getSecret());
}
}
}
@@ -37,7 +37,7 @@ public final class AesUtil {
* Default encryption key The AES encryption key is 16 bits by default.
* If the AES encryption key is larger than or smaller than 16 bits, an error message is displayed
*/
private static final String ENCODE_RULES = "tomSun28HaHaHaHa";
public static final String ENCODE_RULES = "tomSun28HaHaHaHa";
/**
* Default algorithm
@@ -90,4 +90,15 @@ class AesUtilTest {
assertFalse(isCiphertext(encryptedText, invalidKey));
}
@Test
void testDefaultKeyCompatibility() {
// Test with default key
String originalText = "This is a secret message";
// encode use default secret key
String encryptedText = aesEncode(originalText, AesUtil.ENCODE_RULES);
// decode use new secret key
String decryptedText = aesDecode(encryptedText, "newkey1234567890");
// old data can decode with default secret key
assertEquals(originalText, decryptedText);
}
}
@@ -28,6 +28,7 @@ import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.util.AesUtil;
import org.apache.hertzbeat.common.util.TimeZoneUtil;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.apache.hertzbeat.manager.pojo.dto.MuteConfig;
@@ -62,6 +63,9 @@ public class ConfigInitializer implements SmartLifecycle {
@Value("${sureness.jwt.secret:" + DEFAULT_JWT_SECRET + "}")
private String currentJwtSecret;
@Value("${common.secret:" + AesUtil.ENCODE_RULES + "}")
private String currentAesSecret;
@Resource
private SystemGeneralConfigServiceImpl systemGeneralConfigService;
@@ -111,21 +115,15 @@ public class ConfigInitializer implements SmartLifecycle {
TemplateConfig templateConfig = templateConfigService.getConfig();
appService.updateCustomTemplateConfig(templateConfig);
// for system secrets
boolean needUpdate = false;
SystemSecret.SystemSecretBuilder builder = SystemSecret.builder();
if (DEFAULT_JWT_SECRET.equals(currentJwtSecret)) {
// use the random jwt secret
SystemSecret systemSecret = systemSecretService.getConfig();
if (systemSecret == null || StringUtils.isBlank(systemSecret.getJwtSecret())) {
char[] chars = DEFAULT_JWT_SECRET.toCharArray();
Random rand = new Random();
for (int i = 0; i < chars.length; i++) {
int index = rand.nextInt(chars.length);
char temp = chars[i];
chars[i] = chars[index];
chars[index] = temp;
}
currentJwtSecret = new String(chars);
systemSecret = SystemSecret.builder().jwtSecret(currentJwtSecret).build();
systemSecretService.saveConfig(systemSecret);
currentJwtSecret = randomizeSecret(DEFAULT_JWT_SECRET);
builder.jwtSecret(currentJwtSecret);
needUpdate = true;
} else {
currentJwtSecret = systemSecret.getJwtSecret();
}
@@ -133,7 +131,22 @@ public class ConfigInitializer implements SmartLifecycle {
// else use the user custom jwt secret
// set the jwt secret token in util
JsonWebTokenUtil.setDefaultSecretKey(currentJwtSecret);
// Aes secret config
if (AesUtil.ENCODE_RULES.equals(currentAesSecret)) {
// use the random aes secret
SystemSecret systemSecret = systemSecretService.getConfig();
if (systemSecret == null || StringUtils.isBlank(systemSecret.getAesSecret())) {
currentAesSecret = randomizeSecret(AesUtil.ENCODE_RULES);
builder.aesSecret(currentAesSecret);
} else {
currentAesSecret = systemSecret.getAesSecret();
}
}
AesUtil.setDefaultSecretKey(currentAesSecret);
if (needUpdate) {
SystemSecret systemSecret = builder.build();
systemSecretService.saveConfig(systemSecret);
}
// init web-app mute config
MuteConfig muteConfig = muteGeneralConfigService.getConfig();
if (muteConfig == null) {
@@ -162,4 +175,16 @@ public class ConfigInitializer implements SmartLifecycle {
public int getPhase() {
return Ordered.HIGHEST_PRECEDENCE;
}
private String randomizeSecret(String secret) {
char[] chars = secret.toCharArray();
Random rand = new Random();
for (int i = 0; i < chars.length; i++) {
int index = rand.nextInt(chars.length);
char temp = chars[i];
chars[i] = chars[index];
chars[index] = temp;
}
return new String(chars);
}
}
@@ -35,4 +35,9 @@ public class SystemSecret {
* secret key for jwt
*/
private String jwtSecret;
/**
* secret key for aes
*/
private String aesSecret;
}