mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 23:23:55 +08:00
秘钥加密
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package xiaozhi.common.utils;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 敏感数据处理工具类
|
||||
*/
|
||||
public class SensitiveDataUtils {
|
||||
|
||||
// 敏感字段列表
|
||||
private static final Set<String> SENSITIVE_FIELDS = new HashSet<>(Arrays.asList(
|
||||
"api_key", "personal_access_token", "access_token", "token",
|
||||
"secret", "access_key_secret", "secret_key"
|
||||
));
|
||||
|
||||
/**
|
||||
* 隐藏字符串中间部分
|
||||
* @param value 原始字符串
|
||||
* @return 隐藏后的字符串
|
||||
*/
|
||||
public static String maskMiddle(String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
int length = value.length();
|
||||
if (length <= 8) {
|
||||
// 字符串太短,返回前2后2,中间用*代替
|
||||
return value.substring(0, 2) + "****" + value.substring(length - 2);
|
||||
} else {
|
||||
// 返回前4后4,中间用*代替
|
||||
int maskLength = length - 8;
|
||||
StringBuilder maskBuilder = new StringBuilder();
|
||||
for (int i = 0; i < maskLength; i++) {
|
||||
maskBuilder.append('*');
|
||||
}
|
||||
return value.substring(0, 4) + maskBuilder.toString() + value.substring(length - 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理JSONObject中的敏感字段
|
||||
* @param jsonObject 原始JSONObject
|
||||
* @return 处理后的JSONObject副本
|
||||
*/
|
||||
public static JSONObject maskSensitiveFields(JSONObject jsonObject) {
|
||||
if (jsonObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 创建副本避免修改原始数据
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
for (String key : jsonObject.keySet()) {
|
||||
Object value = jsonObject.get(key);
|
||||
|
||||
if (SENSITIVE_FIELDS.contains(key.toLowerCase()) && value instanceof String) {
|
||||
// 处理敏感字段
|
||||
result.put(key, maskMiddle((String) value));
|
||||
} else if (value instanceof JSONObject) {
|
||||
// 递归处理嵌套的JSONObject
|
||||
result.put(key, maskSensitiveFields((JSONObject) value));
|
||||
} else {
|
||||
// 非敏感字段保持不变
|
||||
result.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个JSONObject的敏感字段处理后是否相同
|
||||
* @param original 原始JSONObject
|
||||
* @param updated 更新后的JSONObject
|
||||
* @return 是否相同
|
||||
*/
|
||||
public static boolean isSensitiveDataEqual(JSONObject original, JSONObject updated) {
|
||||
if (original == null && updated == null) {
|
||||
return true;
|
||||
}
|
||||
if (original == null || updated == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSONObject maskedOriginal = maskSensitiveFields(original);
|
||||
JSONObject maskedUpdated = maskSensitiveFields(updated);
|
||||
|
||||
return maskedOriginal.toString().equals(maskedUpdated.toString());
|
||||
}
|
||||
}
|
||||
+17
-58
@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
@@ -19,6 +20,7 @@ import xiaozhi.common.redis.RedisKeys;
|
||||
import xiaozhi.common.redis.RedisUtils;
|
||||
import xiaozhi.common.utils.ConvertUtils;
|
||||
import xiaozhi.common.utils.JsonUtils;
|
||||
import xiaozhi.common.utils.SensitiveDataUtils;
|
||||
import xiaozhi.modules.agent.dao.AgentVoicePrintDao;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentPluginMapping;
|
||||
@@ -349,6 +351,9 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
* @param intentModelId 意图模型ID
|
||||
* @param result 结果Map
|
||||
*/
|
||||
/**
|
||||
* 构建模块配置
|
||||
*/
|
||||
private void buildModuleConfig(
|
||||
String assistantName,
|
||||
String prompt,
|
||||
@@ -366,12 +371,12 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
Map<String, Object> result,
|
||||
boolean isCache) {
|
||||
Map<String, String> selectedModule = new HashMap<>();
|
||||
|
||||
|
||||
String[] modelTypes = { "VAD", "ASR", "TTS", "Memory", "Intent", "LLM", "VLLM" };
|
||||
String[] modelIds = { vadModelId, asrModelId, ttsModelId, memModelId, intentModelId, llmModelId, vllmModelId };
|
||||
String intentLLMModelId = null;
|
||||
String memLocalShortLLMModelId = null;
|
||||
|
||||
|
||||
for (int i = 0; i < modelIds.length; i++) {
|
||||
if (modelIds[i] == null) {
|
||||
continue;
|
||||
@@ -382,66 +387,20 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
}
|
||||
Map<String, Object> typeConfig = new HashMap<>();
|
||||
if (model.getConfigJson() != null) {
|
||||
typeConfig.put(model.getId(), model.getConfigJson());
|
||||
// 如果是TTS类型,添加private_voice属性
|
||||
if ("TTS".equals(modelTypes[i])) {
|
||||
if (voice != null)
|
||||
((Map<String, Object>) model.getConfigJson()).put("private_voice", voice);
|
||||
if (referenceAudio != null)
|
||||
((Map<String, Object>) model.getConfigJson()).put("ref_audio", referenceAudio);
|
||||
if (referenceText != null)
|
||||
((Map<String, Object>) model.getConfigJson()).put("ref_text", referenceText);
|
||||
}
|
||||
// 如果是Intent类型,且type=intent_llm,则给他添加附加模型
|
||||
if ("Intent".equals(modelTypes[i])) {
|
||||
Map<String, Object> map = (Map<String, Object>) model.getConfigJson();
|
||||
if ("intent_llm".equals(map.get("type"))) {
|
||||
intentLLMModelId = (String) map.get("llm");
|
||||
if (StringUtils.isNotBlank(intentLLMModelId) && intentLLMModelId.equals(llmModelId)) {
|
||||
intentLLMModelId = null;
|
||||
}
|
||||
}
|
||||
if (map.get("functions") != null) {
|
||||
String functionStr = (String) map.get("functions");
|
||||
if (StringUtils.isNotBlank(functionStr)) {
|
||||
String[] functions = functionStr.split("\\;");
|
||||
map.put("functions", functions);
|
||||
}
|
||||
}
|
||||
System.out.println("map: " + map);
|
||||
}
|
||||
if ("Memory".equals(modelTypes[i])) {
|
||||
Map<String, Object> map = (Map<String, Object>) model.getConfigJson();
|
||||
if ("mem_local_short".equals(map.get("type"))) {
|
||||
memLocalShortLLMModelId = (String) map.get("llm");
|
||||
if (StringUtils.isNotBlank(memLocalShortLLMModelId)
|
||||
&& memLocalShortLLMModelId.equals(llmModelId)) {
|
||||
memLocalShortLLMModelId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果是LLM类型,且intentLLMModelId不为空,则添加附加模型
|
||||
if ("LLM".equals(modelTypes[i])) {
|
||||
if (StringUtils.isNotBlank(intentLLMModelId)) {
|
||||
if (!typeConfig.containsKey(intentLLMModelId)) {
|
||||
ModelConfigEntity intentLLM = modelConfigService.getModelById(intentLLMModelId, isCache);
|
||||
typeConfig.put(intentLLM.getId(), intentLLM.getConfigJson());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(memLocalShortLLMModelId)) {
|
||||
if (!typeConfig.containsKey(memLocalShortLLMModelId)) {
|
||||
ModelConfigEntity memLocalShortLLM = modelConfigService
|
||||
.getModelById(memLocalShortLLMModelId, isCache);
|
||||
typeConfig.put(memLocalShortLLM.getId(), memLocalShortLLM.getConfigJson());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 复制一份配置,避免修改原始数据
|
||||
JSONObject configJsonCopy = new JSONObject(model.getConfigJson());
|
||||
|
||||
// 对敏感数据进行隐藏处理
|
||||
JSONObject maskedConfigJson = SensitiveDataUtils.maskSensitiveFields(configJsonCopy);
|
||||
|
||||
typeConfig.put(model.getId(), maskedConfigJson);
|
||||
|
||||
}
|
||||
result.put(modelTypes[i], typeConfig);
|
||||
|
||||
|
||||
selectedModule.put(modelTypes[i], model.getId());
|
||||
}
|
||||
|
||||
|
||||
result.put("selected_module", selectedModule);
|
||||
if (StringUtils.isNotBlank(prompt)) {
|
||||
prompt = prompt.replace("{{assistant_name}}", StringUtils.isBlank(assistantName) ? "小智" : assistantName);
|
||||
|
||||
+127
-40
@@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
@@ -24,6 +25,7 @@ import xiaozhi.common.redis.RedisKeys;
|
||||
import xiaozhi.common.redis.RedisUtils;
|
||||
import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||
import xiaozhi.common.utils.ConvertUtils;
|
||||
import xiaozhi.common.utils.SensitiveDataUtils;
|
||||
import xiaozhi.modules.agent.dao.AgentDao;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
import xiaozhi.modules.model.dao.ModelConfigDao;
|
||||
@@ -36,6 +38,8 @@ import xiaozhi.modules.model.entity.ModelConfigEntity;
|
||||
import xiaozhi.modules.model.service.ModelConfigService;
|
||||
import xiaozhi.modules.model.service.ModelProviderService;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, ModelConfigEntity>
|
||||
@@ -101,35 +105,24 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
return getPageData(modelConfigEntityIPage, ModelConfigDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||
// 先验证有没有供应器
|
||||
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
|
||||
throw new RenException(ErrorCode.MODEL_TYPE_PROVIDE_CODE_NOT_NULL);
|
||||
}
|
||||
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
|
||||
if (CollectionUtil.isEmpty(providerList)) {
|
||||
throw new RenException(ErrorCode.MODEL_PROVIDER_NOT_EXIST);
|
||||
}
|
||||
|
||||
// 再保存供应器提供的模型
|
||||
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
|
||||
modelConfigEntity.setModelType(modelType);
|
||||
modelConfigEntity.setIsDefault(0);
|
||||
modelConfigDao.insert(modelConfigEntity);
|
||||
return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||
// 先验证有没有供应器
|
||||
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
|
||||
throw new RenException(ErrorCode.MODEL_TYPE_PROVIDE_CODE_NOT_NULL);
|
||||
throw new RenException("modelType和provideCode不能为空");
|
||||
}
|
||||
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
|
||||
if (CollectionUtil.isEmpty(providerList)) {
|
||||
throw new RenException(ErrorCode.MODEL_PROVIDER_NOT_EXIST);
|
||||
}
|
||||
|
||||
// 获取原始配置
|
||||
ModelConfigEntity originalEntity = modelConfigDao.selectById(id);
|
||||
if (originalEntity == null) {
|
||||
throw new RenException(ErrorCode.RESOURCE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 验证LLM配置
|
||||
if (modelConfigBodyDTO.getConfigJson().containsKey("llm")) {
|
||||
String llm = modelConfigBodyDTO.getConfigJson().get("llm").toString();
|
||||
ModelConfigEntity modelConfigEntity = modelConfigDao.selectOne(new LambdaQueryWrapper<ModelConfigEntity>()
|
||||
@@ -145,15 +138,63 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
throw new RenException(ErrorCode.INVALID_LLM_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 再更新供应器提供的模型
|
||||
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
|
||||
modelConfigEntity.setId(id);
|
||||
modelConfigEntity.setModelType(modelType);
|
||||
|
||||
// 检查敏感字段是否有变化
|
||||
if (originalEntity.getConfigJson() != null && modelConfigBodyDTO.getConfigJson() != null) {
|
||||
boolean sensitiveEqual = SensitiveDataUtils.isSensitiveDataEqual(
|
||||
originalEntity.getConfigJson(),
|
||||
modelConfigBodyDTO.getConfigJson()
|
||||
);
|
||||
|
||||
if (sensitiveEqual) {
|
||||
// 敏感数据没有变化,使用原始的configJson值
|
||||
modelConfigEntity.setConfigJson(originalEntity.getConfigJson());
|
||||
}
|
||||
}
|
||||
|
||||
modelConfigDao.updateById(modelConfigEntity);
|
||||
|
||||
// 清除缓存
|
||||
redisUtils.delete(RedisKeys.getModelConfigById(modelConfigEntity.getId()));
|
||||
return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
|
||||
|
||||
// 返回数据前处理敏感字段
|
||||
ModelConfigDTO dto = ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
|
||||
if (dto.getConfigJson() != null) {
|
||||
dto.setConfigJson(SensitiveDataUtils.maskSensitiveFields(dto.getConfigJson()));
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||
// 先验证有没有供应器
|
||||
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
|
||||
throw new RenException("modelType和provideCode不能为空");
|
||||
}
|
||||
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
|
||||
if (CollectionUtil.isEmpty(providerList)) {
|
||||
throw new RenException(ErrorCode.MODEL_PROVIDER_NOT_EXIST);
|
||||
}
|
||||
|
||||
// 保存供应器提供的模型
|
||||
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
|
||||
modelConfigEntity.setModelType(modelType);
|
||||
modelConfigEntity.setIsDefault(0);
|
||||
modelConfigDao.insert(modelConfigEntity);
|
||||
|
||||
// 返回数据前处理敏感字段
|
||||
ModelConfigDTO dto = ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
|
||||
if (dto.getConfigJson() != null) {
|
||||
dto.setConfigJson(SensitiveDataUtils.maskSensitiveFields(dto.getConfigJson()));
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -242,24 +283,6 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelConfigEntity getModelById(String id, boolean isCache) {
|
||||
if (StringUtils.isBlank(id)) {
|
||||
return null;
|
||||
}
|
||||
if (isCache) {
|
||||
ModelConfigEntity cachedConfig = (ModelConfigEntity) redisUtils.get(RedisKeys.getModelConfigById(id));
|
||||
if (cachedConfig != null) {
|
||||
return ConvertUtils.sourceToTarget(cachedConfig, ModelConfigEntity.class);
|
||||
}
|
||||
}
|
||||
ModelConfigEntity entity = modelConfigDao.selectById(id);
|
||||
if (entity != null) {
|
||||
redisUtils.set(RedisKeys.getModelConfigById(id), entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultModel(String modelType, int isDefault) {
|
||||
ModelConfigEntity entity = new ModelConfigEntity();
|
||||
@@ -267,4 +290,68 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
modelConfigDao.update(entity, new QueryWrapper<ModelConfigEntity>()
|
||||
.eq("model_type", modelType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelConfigEntity selectById(Serializable id) {
|
||||
ModelConfigEntity entity = super.selectById(id);
|
||||
if (entity != null && entity.getConfigJson() != null) {
|
||||
// 对配置中的敏感数据进行隐藏处理
|
||||
JSONObject maskedConfigJson = SensitiveDataUtils.maskSensitiveFields(entity.getConfigJson());
|
||||
entity.setConfigJson(maskedConfigJson);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
// 重写getPageData方法,添加敏感数据处理
|
||||
@Override
|
||||
protected <D> PageData<D> getPageData(IPage<?> page, Class<D> target) {
|
||||
List<?> records = page.getRecords();
|
||||
if (records != null && !records.isEmpty()) {
|
||||
for (Object record : records) {
|
||||
if (record instanceof ModelConfigEntity) {
|
||||
ModelConfigEntity entity = (ModelConfigEntity) record;
|
||||
if (entity.getConfigJson() != null) {
|
||||
// 对配置中的敏感数据进行隐藏处理
|
||||
JSONObject maskedConfigJson = SensitiveDataUtils.maskSensitiveFields(entity.getConfigJson());
|
||||
entity.setConfigJson(maskedConfigJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.getPageData(page, target);
|
||||
}
|
||||
|
||||
// 确保只有一个getModelById方法实现
|
||||
@Override
|
||||
public ModelConfigEntity getModelById(String id, boolean isCache) {
|
||||
ModelConfigEntity entity = null;
|
||||
if (isCache) {
|
||||
String cacheKey = RedisKeys.getModelConfigById(id);
|
||||
entity = (ModelConfigEntity) redisUtils.get(cacheKey);
|
||||
if (entity != null) {
|
||||
// 从缓存获取的数据也需要处理敏感信息
|
||||
if (entity.getConfigJson() != null) {
|
||||
JSONObject maskedConfigJson = SensitiveDataUtils.maskSensitiveFields(entity.getConfigJson());
|
||||
entity.setConfigJson(maskedConfigJson);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
// 从数据库获取数据
|
||||
entity = modelConfigDao.selectById(id);
|
||||
if (entity != null) {
|
||||
// 处理敏感信息
|
||||
if (entity.getConfigJson() != null) {
|
||||
JSONObject maskedConfigJson = SensitiveDataUtils.maskSensitiveFields(entity.getConfigJson());
|
||||
entity.setConfigJson(maskedConfigJson);
|
||||
}
|
||||
|
||||
if (isCache) {
|
||||
// 缓存处理后的对象
|
||||
redisUtils.set(RedisKeys.getModelConfigById(id), entity);
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user