fix(aihr): sanitize mobile review responses

This commit is contained in:
2026-07-15 01:45:57 +08:00
parent 78600ff509
commit 03a691c770
5 changed files with 13 additions and 10 deletions
@@ -26,6 +26,7 @@ import org.dromara.aihr.domain.vo.AihrMobileDto.HomeResponse;
import org.dromara.aihr.domain.vo.AihrMobileDto.IdentityResponse;
import org.dromara.aihr.service.AihrOrgSyncService;
import org.dromara.aihr.service.AihrMobileSeedService;
import org.dromara.aihr.service.AihrSensitiveText;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.UserType;
@@ -300,10 +301,10 @@ public class AihrMobileController {
data.put("scene", detail.scene());
data.put("score", detail.score());
data.put("status", detail.status());
data.put("summary", detail.summary());
data.put("mentorRewrite", detail.mentorRewrite());
data.put("aiComment", detail.aiComment());
data.put("reviewAdvice", detail.reviewAdvice());
data.put("summary", maskSensitiveText(detail.summary()));
data.put("mentorRewrite", maskSensitiveText(detail.mentorRewrite()));
data.put("aiComment", maskSensitiveText(detail.aiComment()));
data.put("reviewAdvice", maskSensitiveText(detail.reviewAdvice()));
data.put("incentivePoint", detail.incentivePoint());
data.put("scoreItems", detail.scoreItems().stream().map(item -> Map.of(
"label", item.label(),
@@ -334,9 +335,6 @@ public class AihrMobileController {
}
private static String maskSensitiveText(String value) {
if (value == null || value.isBlank()) {
return value;
}
return value.replaceAll("(1\\d{2})\\d{4}(\\d{4})", "$1****$2");
return AihrSensitiveText.forModel(value);
}
}
@@ -8,7 +8,7 @@ import java.util.regex.Pattern;
* <p>这不是正式的数据分类引擎;它只负责拦截当前一期已知的手机号、邮箱、房号和带称谓姓名,
* 避免“入库已脱敏、出境仍是原文”的边界漏洞。正式试点仍需配套供应商留存、审计和删除合同。</p>
*/
final class AihrSensitiveText {
public final class AihrSensitiveText {
// 保持案例服务既有展示口径:手机号保留前 4 位和后 4 位,中间统一遮蔽。
private static final Pattern PHONE = Pattern.compile("(?<!\\d)(1[3-9]\\d{2})\\d{3}(\\d{4})(?!\\d)");
@@ -20,7 +20,7 @@ final class AihrSensitiveText {
private AihrSensitiveText() {
}
static String forModel(String text) {
public static String forModel(String text) {
if (text == null || text.isBlank()) {
return text;
}
@@ -46,6 +46,7 @@ class AihrSensitiveTextTest {
String caseSource = Files.readString(source("AihrCaseService.java"));
String practiceLlmSource = Files.readString(source("AihrPracticeLlmService.java"));
String speechControllerSource = Files.readString(controllerSource("AihrSpeechController.java"));
String mobileControllerSource = Files.readString(controllerSource("AihrMobileController.java"));
assertTrue(modelSource.contains("AihrSensitiveText.forModel(prompt)"));
assertTrue(modelSource.contains("prompt_tokens"));
@@ -69,6 +70,7 @@ class AihrSensitiveTextTest {
assertTrue(videoSource.contains("处理输出已隐藏"));
assertTrue(caseSource.contains("case audio upload failed(处理错误已隐藏)"));
assertTrue(practiceLlmSource.contains("practice score parse failed, falls back to seed(处理错误已隐藏)"));
assertTrue(mobileControllerSource.contains("return AihrSensitiveText.forModel(value)"));
}
@Test
+2
View File
@@ -1,5 +1,7 @@
# BRD 功能审查与未完成项记录
- 2026-07-15 BRD G3 移动端复盘响应脱敏补强:复盘详情响应此前只在控制器内遮蔽手机号,历史或外部写入的邮箱、房号和带称谓姓名可能继续出现在对话、标注、摘要、导师改写、AI 点评和主管建议中;现统一复用 `AihrSensitiveText.forModel` 覆盖这些响应文本,并补 AIHR 回归与 `demo-check` marker。该修复只收紧响应边界,不改变训练评分、组织范围或姓名展示配置;生产发布仍需按版本化迁移与静态资源发布流程验证。
- 2026-07-15 当前提交线上漂移复核:生产根站、`/h5/`、`/prod-api/auth/tenant/list` 和 `/prod-api/api/aihr/mobile/home/user` 均返回 HTTP `200`,`wygj-aihr.service` 为 `active`,但线上管理端仍加载 `assets/index-B9T505HT.js`(SHA-256 `66a827a7b3e5d794ae9da54c6e2276080995614fa52f54d49f746087663f8c94`),H5 仍加载 `assets/index-CDn6TrX8.js`(SHA-256 `eecb4820f3887aceb952efe3e6f2210bab325be8b03f2813e6ec304c68b26f08`);当前 `HEAD=2f44e6b7` 本地产物分别为 `assets/index-nV05JukM.js`(SHA-256 `b25d4945c5e41a93a3b6a288d6acc1be689431e363426626753e2227f8a290dc`)和 `assets/index-9sen8HYN.js`(SHA-256 `66900a9aa00c17e04d73a2d3509c16784b1ddcfc109098751b95b4138ebe26de`)。远端 `ruoyi-aihr-5.6.2.jar` 归一化内容 SHA-256 为 `b57c06ec6da4dd0e5eef16fb96c23881b2f1f253f461eb58ec3158122f76b543`,当前本地构建为 `02ca2d913f43e7cab3d9fe253d849611bf957481f69fcb6ae509d7814f11256b`。本轮仅做公开 GET、SSH 服务状态和远端包哈希只读检查,未同步静态资源、迁移数据库、重启后端或写入生产数据;当前结论是代码可继续发布准备,线上尚未追平。
- 2026-07-15 BRD G3/4.6 案例音频地址暴露收紧:案例详情和上传响应此前直接返回 `sys_oss.url`,客户端可绕过案例接口的登录与项目范围校验访问原始音频;现新增 `GET /api/knowledge/case/records/{caseId}/media`,复用案例查看权限和项目范围后由服务端流式下载 OSS,管理端与 `mobile-uni` 改用鉴权 blob/temp 文件播放;详情/上传响应不再返回原始 OSS URL。已通过 AIHR 全量测试、管理端构建和 `mobile-uni` H5 构建;未修改生产资源或生产数据,生产发布仍需窗口、备份/回滚责任和回归验证。
+1
View File
@@ -395,6 +395,7 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/control
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "mobileSeedService.home(role, identity)"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "!UserType.APP_USER.getUserType().equals(loginUser.getUserType())"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "无权访问该录音"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "return AihrSensitiveText.forModel(value)"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "supervisorRoleRequested"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "public MobileTeamMetrics mobileTeamMetrics(String supervisorExtPartyId)"
contains mobile-uni/src/services/practice.ts "/api/train/practice/start"