fix:异常信息返回中文化
This commit is contained in:
parent
e9240a38d6
commit
3040ed443b
@ -62,7 +62,7 @@ public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(MultipartException.class)
|
||||
public ResponseEntity<ApiResponse<Void>> handleMultipartException(MultipartException ex, HttpServletRequest request) {
|
||||
return response(HttpStatus.BAD_REQUEST, ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "failed to parse multipart request")
|
||||
return response(HttpStatus.BAD_REQUEST, ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "解析 multipart 上传请求失败")
|
||||
.withPath(request.getRequestURI()));
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ public class GlobalExceptionHandler {
|
||||
}
|
||||
log.warn("Replay protection 执行失败", ex);
|
||||
return response(HttpStatus.SERVICE_UNAVAILABLE,
|
||||
ApiResponse.fail(ErrorCode.SERVICE_UNAVAILABLE.getCode(), "replay protection unavailable")
|
||||
ApiResponse.fail(ErrorCode.SERVICE_UNAVAILABLE.getCode(), "防重放校验服务不可用")
|
||||
.withPath(request.getRequestURI()));
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ public class GlobalExceptionHandler {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
return response(HttpStatus.NOT_FOUND,
|
||||
ApiResponse.fail(ErrorCode.NOT_FOUND.getCode(), "resource not found")
|
||||
ApiResponse.fail(ErrorCode.NOT_FOUND.getCode(), "资源不存在")
|
||||
.withPath(request.getRequestURI()));
|
||||
}
|
||||
|
||||
|
||||
@ -14,13 +14,13 @@ public class PcieErrorMapper {
|
||||
lowByteErrorMap.put(0x1F, "UKey错误");
|
||||
lowByteErrorMap.put(0x20, "生成密钥错误");
|
||||
lowByteErrorMap.put(0x21, "状态错误");
|
||||
lowByteErrorMap.put(0x22, "retry exceeded");
|
||||
lowByteErrorMap.put(0x23, "device busy");
|
||||
lowByteErrorMap.put(0x24, "error status");
|
||||
lowByteErrorMap.put(0x25, "init status");
|
||||
lowByteErrorMap.put(0x26, "already logined");
|
||||
lowByteErrorMap.put(0x27, "timeout");
|
||||
lowByteErrorMap.put(0x1D, "invalid argument");
|
||||
lowByteErrorMap.put(0x22, "重试次数超限");
|
||||
lowByteErrorMap.put(0x23, "设备忙");
|
||||
lowByteErrorMap.put(0x24, "状态错误");
|
||||
lowByteErrorMap.put(0x25, "初始化状态错误");
|
||||
lowByteErrorMap.put(0x26, "已登录");
|
||||
lowByteErrorMap.put(0x27, "操作超时");
|
||||
lowByteErrorMap.put(0x1D, "参数无效");
|
||||
}
|
||||
|
||||
public String toMessage(int retCode) {
|
||||
|
||||
@ -2115,7 +2115,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
|
||||
private static List<RecoverUserKeyRequest> requireUserKeyRequests(List<RecoverUserKeyRequest> requests) {
|
||||
if (requests == null || requests.isEmpty()) {
|
||||
throw new IllegalArgumentException("userKeyRequests must not be empty");
|
||||
throw new IllegalArgumentException("userKeyRequests不能为空");
|
||||
}
|
||||
for (RecoverUserKeyRequest request : requests) {
|
||||
RecoverUserKeyRequest req = requireRequest("userKeyRequest", request);
|
||||
@ -2447,21 +2447,21 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
|
||||
private static int requirePositive(String name, int value) {
|
||||
if (value <= 0) {
|
||||
throw new IllegalArgumentException(name + " must be > 0");
|
||||
throw new IllegalArgumentException(name + "必须大于0");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int requireNonNegative(String name, int value) {
|
||||
if (value < 0) {
|
||||
throw new IllegalArgumentException(name + " must be >= 0");
|
||||
throw new IllegalArgumentException(name + "必须大于等于0");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int requireByteRange(String name, int value) {
|
||||
if (value < 0 || value > 255) {
|
||||
throw new IllegalArgumentException(name + " must be in [0,255]");
|
||||
throw new IllegalArgumentException(name + "必须在[0,255]范围内");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -2469,7 +2469,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
private int requireValidAlgId(String name, int algId) {
|
||||
int value = requirePositive(name, algId);
|
||||
if (strictAlgIdValidation && !Gm0018AlgorithmIds.isSupported(value)) {
|
||||
throw new IllegalArgumentException(name + " is not a supported GM/T 0018 algorithm id: 0x" + Integer.toHexString(value));
|
||||
throw new IllegalArgumentException(name + "不是支持的GM/T 0018算法标识:0x" + Integer.toHexString(value));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -2482,14 +2482,14 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
|
||||
private static byte[] requireNonEmptyBytes(String name, byte[] value) {
|
||||
if (value == null || value.length == 0) {
|
||||
throw new IllegalArgumentException(name + " must not be empty");
|
||||
throw new IllegalArgumentException(name + "不能为空");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static byte[] requireBytes(String name, byte[] value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException(name + " must not be null");
|
||||
throw new IllegalArgumentException(name + "不能为null");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -2557,10 +2557,10 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
int size = structure.size();
|
||||
if (allowPartial) {
|
||||
if (source.length > size) {
|
||||
throw new IllegalArgumentException(name + " length must be <= " + size + ", actual: " + source.length);
|
||||
throw new IllegalArgumentException(name + "长度必须小于等于" + size + ",实际为:" + source.length);
|
||||
}
|
||||
} else if (source.length != size) {
|
||||
throw new IllegalArgumentException(name + " length must be exactly " + size + ", actual: " + source.length);
|
||||
throw new IllegalArgumentException(name + "长度必须等于" + size + ",实际为:" + source.length);
|
||||
}
|
||||
Pointer pointer = structure.getPointer();
|
||||
pointer.clear(size);
|
||||
@ -2571,7 +2571,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
|
||||
private static <T> T requireRequest(String name, T request) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException(name + " must not be null");
|
||||
throw new IllegalArgumentException(name + "不能为null");
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -915,7 +915,7 @@ public class MockPcieCryptoService implements PcieCryptoService {
|
||||
recoverIkComponent(2, req.getAuthIkComponent());
|
||||
recoverIkComponent(1, req.getDeviceIkComponent());
|
||||
if (req.getUserKeyRequests() == null || req.getUserKeyRequests().isEmpty()) {
|
||||
throw new IllegalArgumentException("userKeyRequests must not be empty");
|
||||
throw new IllegalArgumentException("userKeyRequests不能为空");
|
||||
}
|
||||
req.getUserKeyRequests().forEach(this::recoverUserKey);
|
||||
if (!checkLmk()) {
|
||||
@ -1099,49 +1099,49 @@ public class MockPcieCryptoService implements PcieCryptoService {
|
||||
|
||||
private static int requirePositive(String name, int value) {
|
||||
if (value <= 0) {
|
||||
throw new IllegalArgumentException(name + " must be > 0");
|
||||
throw new IllegalArgumentException(name + "必须大于0");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int requireNonNegative(String name, int value) {
|
||||
if (value < 0) {
|
||||
throw new IllegalArgumentException(name + " must be >= 0");
|
||||
throw new IllegalArgumentException(name + "必须大于等于0");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int requireByteRange(String name, int value) {
|
||||
if (value < 0 || value > 255) {
|
||||
throw new IllegalArgumentException(name + " must be in [0,255]");
|
||||
throw new IllegalArgumentException(name + "必须在[0,255]范围内");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static byte[] requireNonEmptyBytes(String name, byte[] value) {
|
||||
if (value == null || value.length == 0) {
|
||||
throw new IllegalArgumentException(name + " must not be empty");
|
||||
throw new IllegalArgumentException(name + "不能为空");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static byte[] requireBytes(String name, byte[] value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException(name + " must not be null");
|
||||
throw new IllegalArgumentException(name + "不能为null");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String requireNonBlank(String name, String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
throw new IllegalArgumentException(name + " must not be blank");
|
||||
throw new IllegalArgumentException(name + "不能为空");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static <T> T requireRequest(String name, T request) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException(name + " must not be null");
|
||||
throw new IllegalArgumentException(name + "不能为null");
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -164,12 +164,12 @@ public class AuthAdminServiceImpl implements AuthAdminService {
|
||||
loadRole(targetRoleCode);
|
||||
RoleCode targetRole = resolveRoleCode(targetRoleCode);
|
||||
if (uid == null || uid < 1 || uid > targetRole.getRequiredUkeyCount()) {
|
||||
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "uid exceeds role ukey requirement");
|
||||
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "uid超出角色UKey席位要求");
|
||||
}
|
||||
AuthFullAccountEntity account = authFullAccountRepository.findByRoleCodeAndUid(targetRoleCode, uid)
|
||||
.orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "目标角色完整账号不存在"));
|
||||
if (!passwordHasher.matches(oldPassword, account.getPasswordSalt(), account.getPasswordHash())) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "old password is incorrect");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "旧密码错误");
|
||||
}
|
||||
applyAdminPasswordChange(account, newPassword);
|
||||
authFullAccountRepository.update(account);
|
||||
@ -476,7 +476,7 @@ public class AuthAdminServiceImpl implements AuthAdminService {
|
||||
|
||||
private void validateRoleUid(RoleCode targetRole, Integer uid) {
|
||||
if (uid == null || uid < 1 || uid > targetRole.getRequiredUkeyCount()) {
|
||||
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "uid exceeds role ukey requirement");
|
||||
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "uid超出角色UKey席位要求");
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,7 +484,7 @@ public class AuthAdminServiceImpl implements AuthAdminService {
|
||||
return List.of(RoleCode.values()).stream()
|
||||
.filter(item -> item.getCode().equals(roleCode))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "invalid roleCode"));
|
||||
.orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "roleCode无效"));
|
||||
}
|
||||
|
||||
private LocalDateTime now() {
|
||||
|
||||
@ -154,7 +154,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
RoleUkeyBindingEntity binding = bindingsByUid.getOrDefault(proof.getUid(), List.of()).stream()
|
||||
.filter(item -> item.getUkeyPubkey().equals(proof.getPubKey()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey auth info does not match bound role"));
|
||||
.orElseThrow(() -> new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey认证信息与绑定角色不匹配"));
|
||||
compatUkeyVerifier.verifyIssuedBinding(buildIssuePayload(request.getRoleCode(), proof, authKeyPair), proof.getIssueSignature());
|
||||
compatUkeyVerifier.verifyLoginSignature(proof.getPubKey(), proof.getLoginPayload(), proof.getLoginSignature());
|
||||
matchedSerials.add(binding.getUkeySerial());
|
||||
@ -208,7 +208,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
PasswordComplexityValidator.validate(newPassword);
|
||||
AuthSessionEntity session = requireActiveSession(sessionToken);
|
||||
if (uid == null || !containsAuthenticatedUid(session, uid)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "account is not authenticated in current session");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "当前会话未完成账号认证");
|
||||
}
|
||||
AuthFullAccountEntity fullAccount = authFullAccountRepository.findByRoleCodeAndUid(session.getRoleCode(), uid)
|
||||
.orElseThrow(() -> new BizException(ErrorCode.UNAUTHORIZED.getCode(), "账号不存在"));
|
||||
@ -237,7 +237,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
|
||||
private void validateRoleStatus(RoleAccountEntity roleAccount) {
|
||||
if (!RoleAccountStatus.ACTIVE.name().equals(roleAccount.getStatus())) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "role is not enabled");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "角色未启用");
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,7 +249,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
if (accounts == null || accounts.size() != expectedCount) {
|
||||
throw new BizException(
|
||||
ErrorCode.UNAUTHORIZED.getCode(),
|
||||
roleAccount.getRoleCode() + " requires exactly " + expectedCount + " account passwords"
|
||||
roleAccount.getRoleCode() + "必须提交" + expectedCount + "个账号密码"
|
||||
);
|
||||
}
|
||||
|
||||
@ -258,7 +258,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
for (PasswordLoginAccountRequest account : accounts) {
|
||||
Integer uid = account.getUid();
|
||||
if (uid == null || !uniqueUids.add(uid)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "duplicate account uid submitted");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "提交了重复的账号uid");
|
||||
}
|
||||
AuthFullAccountEntity roleAccountSeat = authFullAccountRepository
|
||||
.findByRoleCodeAndUid(roleAccount.getRoleCode(), uid)
|
||||
@ -274,11 +274,11 @@ public class AuthServiceImpl implements AuthService {
|
||||
|
||||
private void validateFullAccountStatus(AuthFullAccountEntity fullAccount) {
|
||||
if (RoleAccountStatus.UNENABLED.name().equals(fullAccount.getStatus())) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "full account is not enabled");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "完整账号未启用");
|
||||
}
|
||||
if (RoleAccountStatus.LOCKED.name().equals(fullAccount.getStatus())
|
||||
&& (fullAccount.getLockedUntil() == null || fullAccount.getLockedUntil().isAfter(now()))) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "full account is locked");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "完整账号已锁定");
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,10 +290,10 @@ public class AuthServiceImpl implements AuthService {
|
||||
fullAccount.setStatus(RoleAccountStatus.LOCKED.name());
|
||||
fullAccount.setLockedUntil(now().plusMinutes(IDLE_TIMEOUT_MINUTES));
|
||||
authFullAccountRepository.update(fullAccount);
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "full account is locked");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "完整账号已锁定");
|
||||
}
|
||||
authFullAccountRepository.update(fullAccount);
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "password is incorrect");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "密码错误");
|
||||
}
|
||||
|
||||
private void resetValidatedAccounts(List<AuthFullAccountEntity> validatedAccounts) {
|
||||
@ -320,7 +320,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
if (fullAccounts == null || fullAccounts.size() != expectedCount) {
|
||||
throw new BizException(
|
||||
ErrorCode.UNAUTHORIZED.getCode(),
|
||||
roleAccount.getRoleCode() + " requires exactly " + expectedCount + " full-account passwords"
|
||||
roleAccount.getRoleCode() + "必须提交" + expectedCount + "个完整账号密码"
|
||||
);
|
||||
}
|
||||
|
||||
@ -329,7 +329,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
for (FullLoginAccountRequest account : fullAccounts) {
|
||||
Integer uid = account.getUid();
|
||||
if (uid == null || !uniqueUids.add(uid)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "duplicate full-account uid submitted");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "提交了重复的完整账号uid");
|
||||
}
|
||||
AuthFullAccountEntity fullAccount = authFullAccountRepository
|
||||
.findByRoleCodeAndUid(roleAccount.getRoleCode(), uid)
|
||||
@ -347,17 +347,17 @@ public class AuthServiceImpl implements AuthService {
|
||||
List<AuthFullAccountEntity> fixedAccounts = authFullAccountRepository.findByRoleCode(roleCode);
|
||||
int requiredCount = authPolicyService.requiredUkeyCount(RoleCode.valueOf(roleCode));
|
||||
if (fixedAccounts.size() < requiredCount) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "role fixed account mapping is incomplete");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "角色固定账号映射不完整");
|
||||
}
|
||||
|
||||
List<FullLoginAccountRequest> requests = new ArrayList<>();
|
||||
for (UkeyLoginProof proof : proofs.stream().sorted(java.util.Comparator.comparing(UkeyLoginProof::getUid)).toList()) {
|
||||
Integer uid = proof.getUid();
|
||||
if (uid == null || uid < 1 || uid > fixedAccounts.size()) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "uid does not match fixed role account");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "uid与固定角色账号不匹配");
|
||||
}
|
||||
if (proof.getPassword() == null || proof.getPassword().isBlank()) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "account password不能为空");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "账号密码不能为空");
|
||||
}
|
||||
FullLoginAccountRequest accountRequest = new FullLoginAccountRequest();
|
||||
accountRequest.setUid(uid);
|
||||
@ -370,7 +370,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
private void ensureMasterKeyReady() {
|
||||
MasterKeyStatus.StatusDetail status = lmkService.getMasterKeyStatus();
|
||||
if (status == null || status.getCode() == MasterKeyStatus.ABNORMAL.getCode()) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "master key is not ready");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "主密钥未就绪");
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,7 +386,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
Set<String> uniqueSerials = new LinkedHashSet<>(ukeySerials);
|
||||
int requiredUkeyCount = authPolicyService.requiredUkeyCount(RoleCode.valueOf(roleAccount.getRoleCode()));
|
||||
if (uniqueSerials.size() != requiredUkeyCount) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey count does not satisfy role requirement");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey数量不满足角色要求");
|
||||
}
|
||||
|
||||
List<RoleUkeyBindingEntity> bindings = roleUkeyBindingRepository.findActiveByRoleCode(roleAccount.getRoleCode());
|
||||
@ -394,7 +394,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
.map(RoleUkeyBindingEntity::getUkeySerial)
|
||||
.collect(Collectors.toSet());
|
||||
if (!boundSerials.containsAll(uniqueSerials)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey verification 执行失败");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey校验执行失败");
|
||||
}
|
||||
long matchedUidCount = bindings.stream()
|
||||
.filter(binding -> uniqueSerials.contains(binding.getUkeySerial()))
|
||||
@ -402,7 +402,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
.distinct()
|
||||
.count();
|
||||
if (matchedUidCount != requiredUkeyCount) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey count does not satisfy role requirement");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey数量不满足角色要求");
|
||||
}
|
||||
return authPolicyService.resolveAuthLevel(AuthMethod.UKEY);
|
||||
}
|
||||
@ -413,20 +413,20 @@ public class AuthServiceImpl implements AuthService {
|
||||
List<UkeyLoginProof> proofs
|
||||
) {
|
||||
if (proofs == null || proofs.size() != authPolicyService.requiredUkeyCount(roleCode)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey count does not satisfy role requirement");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey数量不满足角色要求");
|
||||
}
|
||||
Set<Integer> requestUids = proofs.stream()
|
||||
.map(UkeyLoginProof::getUid)
|
||||
.collect(Collectors.toSet());
|
||||
int requiredCount = authPolicyService.requiredUkeyCount(roleCode);
|
||||
if (requestUids.size() != requiredCount) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey count does not satisfy role requirement");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey数量不满足角色要求");
|
||||
}
|
||||
Set<Integer> activeUids = activeBindings.stream()
|
||||
.map(RoleUkeyBindingEntity::getUid)
|
||||
.collect(Collectors.toSet());
|
||||
if (!activeUids.containsAll(requestUids)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "ukey count does not satisfy role requirement");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "UKey数量不满足角色要求");
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,7 +437,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(UKeySignEntity.getInstance(dto, authKeyPair, RoleCode.valueOf(roleCode).getCode()));
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new IllegalStateException("serialize ukey issue payload 执行失败", ex);
|
||||
throw new IllegalStateException("序列化UKey签发载荷失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,7 +502,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(authenticatedPrincipals);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new IllegalStateException("serialize authenticated principals 执行失败", ex);
|
||||
throw new IllegalStateException("序列化已认证主体失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -536,7 +536,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
new TypeReference<List<AuthSessionPrincipal>>() { }
|
||||
);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new IllegalStateException("deserialize authenticated principals 执行失败", ex);
|
||||
throw new IllegalStateException("反序列化已认证主体失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ public class InMemoryUkeyLoginRandomService implements UkeyLoginRandomService {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "登录随机数不存在或已过期");
|
||||
}
|
||||
if (randoms == null || randoms.size() != issuedRandoms.randoms().size() || !issuedRandoms.randoms().containsAll(randoms)) {
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "login random verification 执行失败");
|
||||
throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "登录随机数校验失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -533,7 +533,7 @@ public class ResourcePackageServiceImpl implements ResourcePackageService {
|
||||
}
|
||||
String resourceCode = trim(item.getResourceCode()).isEmpty() ? "UNKNOWN" : trim(item.getResourceCode());
|
||||
String resolvedPath = trim(item.getResolvedPath());
|
||||
String message = "required backup resource is unavailable: code=" + resourceCode + ", reason=" + reason;
|
||||
String message = "必需备份资源不可用:code=" + resourceCode + ", reason=" + reason;
|
||||
if (!resolvedPath.isEmpty()) {
|
||||
message += ", path=" + resolvedPath;
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ public class ResourceBackupServiceImpl implements ResourceBackupService {
|
||||
resourceTaskAdmissionGuard.assertCanStartBackup();
|
||||
// 资源备份必须基于“最近一次成功初始化”快照收集上下文,避免前端重新传一套可能失真的参数。
|
||||
InitTaskEntity initTask = initTaskRepository.findLatestByTaskTypeAndStatus("INIT", "SUCCESS")
|
||||
.orElseThrow(() -> new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功ful init task is missing"));
|
||||
.orElseThrow(() -> new BizException(ErrorCode.BIZ_ERROR.getCode(), "缺少成功的初始化任务"));
|
||||
|
||||
// taskId 用于后台任务表和工作目录;backupId 写入备份包 manifest,
|
||||
// 恢复创建时用户需要确认同一个 backupId,避免把预检包和恢复包搞混。
|
||||
@ -184,7 +184,7 @@ public class ResourceBackupServiceImpl implements ResourceBackupService {
|
||||
result.setContentLength(Files.size(packagePath));
|
||||
return result;
|
||||
} catch (Exception ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to read resource backup package");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "读取资源备份包失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ public class ResourceRestoreServiceImpl implements ResourceRestoreService {
|
||||
ResourceRestorePrecheckResponse precheck = context.getResponse();
|
||||
validatePrecheck(precheck);
|
||||
if (!trim(request.getConfirmBackupId()).equals(trim(precheck.getBackupId()))) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "confirmed backup id does not match precheck result");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "确认的备份ID与预检结果不匹配");
|
||||
}
|
||||
FileRecordEntity packageFile = fileRecordRepository.findByFileId(context.getFileId())
|
||||
.orElseThrow(() -> new BizException(ErrorCode.BIZ_ERROR.getCode(), "资源备份包文件不存在:" + trim(context.getFileId())));
|
||||
@ -223,7 +223,7 @@ public class ResourceRestoreServiceImpl implements ResourceRestoreService {
|
||||
}
|
||||
// 兼容性和过期时间在创建恢复时再次校验,防止用户拿旧的或不匹配的预检结果继续恢复。
|
||||
if (!Boolean.TRUE.equals(precheck.getCompatible())) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "resource restore precheck is not compatible");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "资源恢复预检结果不兼容");
|
||||
}
|
||||
String expiresAt = trim(precheck.getExpiresAt());
|
||||
if (!expiresAt.isEmpty()) {
|
||||
|
||||
@ -42,7 +42,7 @@ public class TimeConfigServiceImpl implements TimeConfigService {
|
||||
}
|
||||
|
||||
if (!ZoneId.getAvailableZoneIds().contains(timezone)) {
|
||||
throw new IllegalArgumentException( "Invalid timezone");
|
||||
throw new IllegalArgumentException("时区不存在");
|
||||
}
|
||||
|
||||
String datetime = request.getDatetime();
|
||||
@ -131,7 +131,7 @@ public class TimeConfigServiceImpl implements TimeConfigService {
|
||||
|
||||
String status = executeCommand("chronyc", "tracking");
|
||||
if (!status.contains("Reference ID")) {
|
||||
throw new RuntimeException("NTP sync status check 执行失败");
|
||||
throw new RuntimeException("NTP同步状态检查失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@ -141,10 +141,10 @@ public class TimeConfigServiceImpl implements TimeConfigService {
|
||||
executeCommand("systemctl", "restart", "chronyd");
|
||||
}
|
||||
} catch (Exception rollbackEx) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "Failed to apply new Chrony configuration. CRITICAL: Rollback also 执行失败!");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "应用新的Chrony配置失败,且回滚也失败");
|
||||
}
|
||||
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "Failed to apply new Chrony configuration. Rolled back to original state.");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "应用新的Chrony配置失败,已回滚到原始状态");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("未知模式:" + mode);
|
||||
|
||||
@ -78,7 +78,7 @@ public final class CryptoPayloadCodec {
|
||||
|
||||
private static String requireText(String fieldName, String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
throw new IllegalArgumentException(fieldName + " must not be blank");
|
||||
throw new IllegalArgumentException(fieldName + "不能为空");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -88,10 +88,10 @@ public final class CryptoPayloadCodec {
|
||||
try {
|
||||
decoded = HexFormat.of().parseHex(hex);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException(fieldName + " must be valid HEX", e);
|
||||
throw new IllegalArgumentException(fieldName + "必须是有效HEX", e);
|
||||
}
|
||||
if (decoded.length != expectedBytes) {
|
||||
throw new IllegalArgumentException(fieldName + " length must be " + expectedBytes + " bytes");
|
||||
throw new IllegalArgumentException(fieldName + "长度必须为" + expectedBytes + "字节");
|
||||
}
|
||||
System.arraycopy(decoded, 0, target, offset, decoded.length);
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ public class FileServiceImpl implements FileService {
|
||||
Files.createDirectories(target.getParent());
|
||||
file.transferTo(target);
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to save upload file");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "保存上传文件失败");
|
||||
}
|
||||
|
||||
// 直接落库存储绝对路径,避免后续再依赖可能变化的配置重新推导文件位置。
|
||||
@ -84,7 +84,7 @@ public class FileServiceImpl implements FileService {
|
||||
// 文件大小以磁盘上的真实文件为准,保证查询结果反映当前实际落盘状态。
|
||||
response.setSize(Files.exists(path) ? Files.size(path) : 0L);
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to read file detail");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "读取文件详情失败");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -387,7 +387,7 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
||||
String raw = firstNonBlank(configuredPath, defaultPath);
|
||||
Path path = Paths.get(raw).normalize().toAbsolutePath();
|
||||
if (!Files.exists(path) || !Files.isRegularFile(path)) {
|
||||
throw new IllegalArgumentException(fieldName + " not found: " + path);
|
||||
throw new IllegalArgumentException(fieldName + "不存在:" + path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
@ -1427,7 +1427,7 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
||||
private void verifyCommon(Map<String, String> configMap, PlanContext context, List<String> failures) {
|
||||
requireNotBlank(configMap, "MY_CIPSID_OR_BIC", failures);
|
||||
if (!normalize(unquote(configMap.get("MY_CIPSID_OR_BIC"))).equals(normalize(context.orgCode()))) {
|
||||
failures.add("MY_CIPSID_OR_BIC mismatch");
|
||||
failures.add("MY_CIPSID_OR_BIC不匹配");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -258,7 +258,7 @@ public class InitServiceImpl implements InitService {
|
||||
public CurrentInitConfigResponse loadCurrentInitConfig() {
|
||||
Optional<InitTaskEntity> latestInit = initTaskRepository.findLatestByTaskTypeAndStatus(TASK_TYPE_INIT, "SUCCESS");
|
||||
if (latestInit.isEmpty()) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "device is not initialized");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "设备未初始化");
|
||||
}
|
||||
return resolveCurrentInitConfigFromTask(latestInit.get());
|
||||
}
|
||||
@ -306,17 +306,17 @@ public class InitServiceImpl implements InitService {
|
||||
InitTaskStepEntity step = requireStep(taskId, stepNo);
|
||||
|
||||
if (isBlank(step.getLogPath())) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "log file not generated for task step");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "任务步骤日志文件尚未生成");
|
||||
}
|
||||
|
||||
Path logPath = Paths.get(step.getLogPath()).normalize().toAbsolutePath();
|
||||
Path logDir = Paths.get(initExecutorProperties.getLogDir()).normalize().toAbsolutePath();
|
||||
// 只允许读取配置日志目录下的文件,防止路径穿越读取任意系统文件
|
||||
if (!logPath.startsWith(logDir)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "log path is out of allowed directory");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "日志路径超出允许目录");
|
||||
}
|
||||
if (!Files.exists(logPath) || !Files.isRegularFile(logPath)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "log file does not exist");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "日志文件不存在");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -329,7 +329,7 @@ public class InitServiceImpl implements InitService {
|
||||
response.setContent(content);
|
||||
return response;
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to read log file");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "读取日志文件失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@ public class InitServiceImpl implements InitService {
|
||||
InitTaskEntity task = requireTask(taskId);
|
||||
List<InitTaskStepEntity> steps = initTaskStepRepository.findByTaskIdOrderByStepNo(taskId);
|
||||
if (steps.isEmpty()) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "init task has no steps: " + taskId);
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "初始化任务没有步骤:" + taskId);
|
||||
}
|
||||
if (steps.stream().allMatch(step -> "SUCCESS".equals(step.getStatus()))) {
|
||||
task.setStatus("SUCCESS");
|
||||
@ -478,7 +478,7 @@ public class InitServiceImpl implements InitService {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(root);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to serialize init plan");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "序列化初始化计划失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,7 +501,7 @@ public class InitServiceImpl implements InitService {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(root);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to serialize reset plan");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "序列化重置计划失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,7 +587,7 @@ public class InitServiceImpl implements InitService {
|
||||
|
||||
private List<String> resetSteps(String productType, String mqType) {
|
||||
if ("DIRECT".equals(productType)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "reset is not supported for current product type: " + productType);
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "当前产品类型不支持重置:" + productType);
|
||||
}
|
||||
return List.of(
|
||||
"STOP_APPS",
|
||||
@ -627,7 +627,7 @@ public class InitServiceImpl implements InitService {
|
||||
private String resolveSupportedResetProductType() {
|
||||
String productType = resolvePresetProductType();
|
||||
if ("DIRECT".equals(productType)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "reset is not supported for current product type: " + productType);
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "当前产品类型不支持重置:" + productType);
|
||||
}
|
||||
return productType;
|
||||
}
|
||||
@ -672,11 +672,11 @@ public class InitServiceImpl implements InitService {
|
||||
String productType = resolveSupportedResetProductType();
|
||||
Optional<InitTaskEntity> latestInit = initTaskRepository.findLatestByTaskTypeAndStatus(TASK_TYPE_INIT, "SUCCESS");
|
||||
if (latestInit.isEmpty()) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "device is not initialized, reset is forbidden");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "设备未初始化,禁止重置");
|
||||
}
|
||||
Optional<InitTaskEntity> latestReset = initTaskRepository.findLatestByTaskTypeAndStatus(TASK_TYPE_RESET, "SUCCESS");
|
||||
if (latestReset.isPresent() && compareTaskRecency(latestReset.get(), latestInit.get()) >= 0) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "device is not initialized, reset is forbidden");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "设备未初始化,禁止重置");
|
||||
}
|
||||
|
||||
ResolvedResetContext context = resolveResetContextFromInitTask(latestInit.get());
|
||||
@ -692,10 +692,10 @@ public class InitServiceImpl implements InitService {
|
||||
|
||||
private ResolvedResetContext resolveResetContextFromInitTask(InitTaskEntity task) {
|
||||
if (task == null) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功ful init task is missing");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "缺少成功的初始化任务");
|
||||
}
|
||||
if (isBlank(task.getInitPlanJson())) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功ful init task snapshot is missing");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功初始化任务快照缺失");
|
||||
}
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(task.getInitPlanJson());
|
||||
@ -707,20 +707,20 @@ public class InitServiceImpl implements InitService {
|
||||
String channelUsername = firstNonBlank(text(mq, "channelUsername"), text(request, "channelUsername"));
|
||||
|
||||
if (isBlank(productType) || isBlank(orgCode) || isBlank(mqType)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功ful init task snapshot is incomplete");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功初始化任务快照不完整");
|
||||
}
|
||||
return new ResolvedResetContext(productType, normalize(orgCode), normalizeUpper(mqType), normalize(channelUsername), task.getTaskId());
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to parse 成功ful init task snapshot");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "解析成功初始化任务快照失败");
|
||||
}
|
||||
}
|
||||
|
||||
private CurrentInitConfigResponse resolveCurrentInitConfigFromTask(InitTaskEntity task) {
|
||||
if (task == null) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功ful init task is missing");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "缺少成功的初始化任务");
|
||||
}
|
||||
if (isBlank(task.getInitPlanJson())) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功ful init task snapshot is missing");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "成功初始化任务快照缺失");
|
||||
}
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(task.getInitPlanJson());
|
||||
@ -747,7 +747,7 @@ public class InitServiceImpl implements InitService {
|
||||
response.setCfmqFileNames(buildCfmqFileNames(mq, mqType));
|
||||
return response;
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to parse 成功ful init task snapshot");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "解析成功初始化任务快照失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,13 +869,13 @@ public class InitServiceImpl implements InitService {
|
||||
|
||||
private static void requireAllowed(String field, String value, Set<String> allowed) {
|
||||
if (!allowed.contains(value)) {
|
||||
throw new IllegalArgumentException(field + " must be one of " + allowed);
|
||||
throw new IllegalArgumentException(field + "必须是以下值之一:" + allowed);
|
||||
}
|
||||
}
|
||||
|
||||
private static void requireNotBlank(String field, String value) {
|
||||
if (isBlank(value)) {
|
||||
throw new IllegalArgumentException(field + " is required");
|
||||
throw new IllegalArgumentException(field + "不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,7 +887,7 @@ public class InitServiceImpl implements InitService {
|
||||
|
||||
private static void requireFileId(String field, String value) {
|
||||
if (isBlank(value) || !FILE_ID_PATTERN.matcher(normalize(value)).matches()) {
|
||||
throw new IllegalArgumentException(field + " must be a fileId");
|
||||
throw new IllegalArgumentException(field + "必须是fileId");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -398,12 +398,12 @@ public class LmkServiceImpl implements LmkService {
|
||||
|
||||
private byte[] decodeConfiguredPin(String fieldName, String base64Value) {
|
||||
if (base64Value == null || base64Value.isBlank()) {
|
||||
throw new IllegalStateException(fieldName + " is not configured");
|
||||
throw new IllegalStateException(fieldName + "未配置");
|
||||
}
|
||||
try {
|
||||
return Base64.getDecoder().decode(base64Value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalStateException(fieldName + " is not valid Base64", e);
|
||||
throw new IllegalStateException(fieldName + "不是有效Base64");
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,7 +417,7 @@ public class LmkServiceImpl implements LmkService {
|
||||
|
||||
private Map<Integer, String> parseNativeComponentMap(byte[] componentBytes, String name) {
|
||||
if (componentBytes.length % NATIVE_COMPONENT_COUNT != 0) {
|
||||
throw new IllegalStateException(name + " native component bytes length is invalid: " + componentBytes.length);
|
||||
throw new IllegalStateException(name + "原生分量字节长度无效:" + componentBytes.length);
|
||||
}
|
||||
// 原生分量总长度必须能被 3 整除;每一段等长,依次映射为 1/2/3 号分量。
|
||||
int componentLength = componentBytes.length / NATIVE_COMPONENT_COUNT;
|
||||
@ -440,18 +440,18 @@ public class LmkServiceImpl implements LmkService {
|
||||
private String requiredComponent(Map<Integer, String> componentMap, int componentIndex, String name) {
|
||||
String component = componentMap.get(componentIndex);
|
||||
if (component == null || component.isBlank()) {
|
||||
throw new IllegalArgumentException(name + " component missing: " + componentIndex);
|
||||
throw new IllegalArgumentException(name + "分量缺失:" + componentIndex);
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
private String requiredPacketComponent(Map<Integer, String> componentMap, int componentIndex, String name, int packetIndex) {
|
||||
if (componentMap == null) {
|
||||
throw new IllegalArgumentException(name + " component missing in packet " + packetIndex);
|
||||
throw new IllegalArgumentException(name + "在分包" + packetIndex + "中缺少分量");
|
||||
}
|
||||
String component = componentMap.get(componentIndex);
|
||||
if (component == null || component.isBlank()) {
|
||||
throw new IllegalArgumentException(name + " component " + componentIndex + " missing in packet " + packetIndex);
|
||||
throw new IllegalArgumentException(name + "分量" + componentIndex + "在分包" + packetIndex + "中缺失");
|
||||
}
|
||||
return component;
|
||||
}
|
||||
@ -462,7 +462,7 @@ public class LmkServiceImpl implements LmkService {
|
||||
String packet1Overlap = requiredPacketComponent(packet1Components, NATIVE_COMPONENT_TWO, name, PACKET_INDEX_ONE);
|
||||
String packet2Overlap = requiredPacketComponent(packet2Components, NATIVE_COMPONENT_TWO, name, PACKET_INDEX_TWO);
|
||||
if (!packet1Overlap.equals(packet2Overlap)) {
|
||||
throw new IllegalArgumentException(name + " component 2 is inconsistent");
|
||||
throw new IllegalArgumentException(name + "分量2不一致");
|
||||
}
|
||||
return packet1Overlap;
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ public class ReplayProtectionServiceImpl implements ReplayProtectionService {
|
||||
|
||||
var reloaded = replayNonceRepository.findByScopeAndPrincipalIdAndNonce(scope, principalId, nonce);
|
||||
if (reloaded.isEmpty()) {
|
||||
throw new ReplayProtectionException("replay nonce claim 执行失败 without existing record");
|
||||
throw new ReplayProtectionException("防重放nonce占用失败,且未找到已存在记录");
|
||||
}
|
||||
return buildReplayResult(request, reloaded.get());
|
||||
}
|
||||
@ -170,7 +170,7 @@ public class ReplayProtectionServiceImpl implements ReplayProtectionService {
|
||||
}
|
||||
|
||||
private String buildMismatchDetail(ReplayCheckRequest request) {
|
||||
return "request fingerprint mismatch: scope=" + request.getScope().name()
|
||||
return "请求指纹不匹配:scope=" + request.getScope().name()
|
||||
+ ", method=" + normalize(request.getRequestMethod())
|
||||
+ ", path=" + normalize(request.getRequestPath())
|
||||
+ ", bodyHash=" + normalize(request.getBodyHash());
|
||||
|
||||
@ -199,7 +199,7 @@ public class UpgradeTaskRunner {
|
||||
Path resolved = stagedDir.resolve(trim(scriptPath)).normalize().toAbsolutePath();
|
||||
// 防止脚本路径通过 ../ 跳出升级包解压目录。
|
||||
if (!resolved.startsWith(stagedDir) || !Files.exists(resolved)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade " + phase + " script not found");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级" + phase + "脚本不存在");
|
||||
}
|
||||
Process process = new ProcessBuilder("bash", resolved.toString(), task.getTaskId())
|
||||
.directory(stagedDir.toFile())
|
||||
@ -218,7 +218,7 @@ public class UpgradeTaskRunner {
|
||||
: "upgrade 成功, scheduling detached TMS restart");
|
||||
triggerDetachedTmsRestart(logPath, rollback);
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to schedule detached tms restart");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "调度TMS后台重启失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,11 +68,11 @@ public class UpgradePackageService {
|
||||
String targetVersion = normalize(manifest.getVersion());
|
||||
|
||||
if (!currentVersion.isEmpty() && versionComparator.compare(targetVersion, currentVersion) < 0) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "target version is lower than current version");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "目标版本低于当前版本");
|
||||
}
|
||||
String minCompatibleVersion = normalize(manifest.getMinCompatibleVersion());
|
||||
if (!currentVersion.isEmpty() && !minCompatibleVersion.isEmpty() && versionComparator.compare(currentVersion, minCompatibleVersion) < 0) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "current version does not satisfy minimum compatible version");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "当前版本不满足最低兼容版本要求");
|
||||
}
|
||||
|
||||
UpgradePreviewResponse response = new UpgradePreviewResponse();
|
||||
@ -145,7 +145,7 @@ public class UpgradePackageService {
|
||||
String currentProductType = normalizeUpper(cisdPresetProperties.getProductType());
|
||||
String packageType = normalizeUpper(packageProductType);
|
||||
if (!currentProductType.isEmpty() && !packageType.equals(currentProductType)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade package product type does not match current device");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级包产品类型与当前设备不匹配");
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ public class UpgradePackageService {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级payload.zip不存在");
|
||||
}
|
||||
if (!expected.equals(sm3Hex(payloadZip))) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade package payload sm3 mismatch");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级包payload SM3摘要不匹配");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ public class UpgradeService {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), blankAs(preview.getBlockReason(), "升级预检不允许继续"));
|
||||
}
|
||||
if (!trim(request.getTaskType()).equals(trim(preview.getTaskType()))) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "selected taskType does not match package taskType");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "选择的taskType与升级包taskType不匹配");
|
||||
}
|
||||
FileRecordEntity fileRecord = fileRecordRepository.findByFileId(request.getFileId().trim())
|
||||
.orElseThrow(() -> new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级包文件不存在:" + request.getFileId().trim()));
|
||||
@ -148,7 +148,7 @@ public class UpgradeService {
|
||||
// 第一版按一体机单机串行升级处理,避免同时升级 TMS、收发器或固件造成状态不可控。
|
||||
UpgradeTaskEntity runningTask = upgradeTaskRepository.findRunningTask().orElse(null);
|
||||
if (runningTask != null && !runningTask.getTaskId().equals(taskId)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "another upgrade task is running");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "已有升级任务正在执行");
|
||||
}
|
||||
if (activeExecutions.containsKey(taskId)) {
|
||||
return toResponse(loadTask(taskId));
|
||||
@ -179,7 +179,7 @@ public class UpgradeService {
|
||||
}
|
||||
UpgradeTaskEntity runningTask = upgradeTaskRepository.findRunningTask().orElse(null);
|
||||
if (runningTask != null && !runningTask.getTaskId().equals(taskId)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "another upgrade task is running");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "已有升级任务正在执行");
|
||||
}
|
||||
if (activeExecutions.containsKey(taskId)) {
|
||||
return toResponse(loadTask(taskId));
|
||||
@ -235,16 +235,16 @@ public class UpgradeService {
|
||||
UpgradeTaskEntity task = loadTask(taskId);
|
||||
String logPath = trim(task.getDetailLogPath());
|
||||
if (logPath.isEmpty()) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade log not generated");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级日志尚未生成");
|
||||
}
|
||||
Path path = Path.of(logPath).normalize().toAbsolutePath();
|
||||
Path allowedRoot = Path.of(trim(upgradeProperties.getLogDir())).normalize().toAbsolutePath();
|
||||
// 日志路径必须落在升级日志根目录下,防止通过篡改任务记录读取任意文件。
|
||||
if (!path.startsWith(allowedRoot)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade log path is out of allowed directory");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级日志路径超出允许目录");
|
||||
}
|
||||
if (!Files.exists(path)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade log file does not exist");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级日志文件不存在");
|
||||
}
|
||||
try {
|
||||
UpgradeLogResponse response = new UpgradeLogResponse();
|
||||
@ -253,7 +253,7 @@ public class UpgradeService {
|
||||
response.setContent(Files.readString(path));
|
||||
return response;
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to read upgrade log");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "读取升级日志失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,7 +304,7 @@ public class UpgradeService {
|
||||
}
|
||||
return path;
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to prepare upgrade log file");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "准备升级日志文件失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public class SoftUpgradePackageSignatureVerifier implements UpgradePackageSignat
|
||||
|
||||
// 第一版升级包仅对 manifest.json 做离线软验签,避免在包内脚本执行前信任未授权包。
|
||||
PublicKey publicKey = loadPublicKey();
|
||||
byte[] manifestBytes = readBytes(manifestPath, "failed to read manifest for signature verification");
|
||||
byte[] manifestBytes = readBytes(manifestPath, "读取验签manifest失败");
|
||||
byte[] signatureBytes = loadSignature(signaturePath);
|
||||
|
||||
try {
|
||||
@ -59,14 +59,14 @@ public class SoftUpgradePackageSignatureVerifier implements UpgradePackageSignat
|
||||
} catch (BizException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade package signature verification 执行失败");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级包签名验签失败");
|
||||
}
|
||||
}
|
||||
|
||||
private PublicKey loadPublicKey() {
|
||||
Path pemPath = Path.of(normalize(upgradeProperties.getSignaturePublicKeyPemPath())).normalize().toAbsolutePath();
|
||||
if (normalize(upgradeProperties.getSignaturePublicKeyPemPath()).isEmpty()) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade signature public key pem path not configured");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级签名公钥PEM路径未配置");
|
||||
}
|
||||
if (!Files.exists(pemPath)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级签名公钥PEM文件不存在");
|
||||
@ -84,14 +84,14 @@ public class SoftUpgradePackageSignatureVerifier implements UpgradePackageSignat
|
||||
} catch (BizException ex) {
|
||||
throw ex;
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to read upgrade signature public key pem");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "读取升级签名公钥PEM失败");
|
||||
} catch (Exception ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级签名公钥PEM无效");
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] loadSignature(Path signaturePath) {
|
||||
byte[] raw = readBytes(signaturePath, "failed to read upgrade signature file");
|
||||
byte[] raw = readBytes(signaturePath, "读取升级签名文件失败");
|
||||
if (raw.length == 0) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级包签名文件为空");
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public class UpgradePackageStagingService {
|
||||
unzip(packagePath, taskDir, "");
|
||||
return taskDir;
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "failed to stage upgrade package");
|
||||
throw new BizException(ErrorCode.INTERNAL_ERROR.getCode(), "暂存升级包失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ public class UpgradePackageStagingService {
|
||||
deleteDirectoryIfExists(root.resolve("payload"));
|
||||
unzip(payloadZip, root, "payload/");
|
||||
} catch (IOException ex) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to extract upgrade payload.zip");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "解压升级payload.zip失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,12 +56,12 @@ public class UpgradePackageStagingService {
|
||||
while ((entry = zipInputStream.getNextEntry()) != null) {
|
||||
String entryName = entry.getName();
|
||||
if (!requiredEntryPrefix.isEmpty() && !entryName.startsWith(requiredEntryPrefix)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "invalid upgrade payload entry");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级payload条目无效");
|
||||
}
|
||||
Path target = targetDir.resolve(entry.getName()).normalize().toAbsolutePath();
|
||||
// 防止恶意 zip 条目通过 ../ 写出 staging 目录。
|
||||
if (!target.startsWith(targetDir)) {
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "invalid upgrade package entry");
|
||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "升级包条目无效");
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
Files.createDirectories(target);
|
||||
|
||||
@ -58,7 +58,7 @@ public class InternalApiReplayInterceptor implements HandlerInterceptor {
|
||||
String timestamp = trimHeader(request, TIMESTAMP_HEADER);
|
||||
String nonce = trimHeader(request, NONCE_HEADER);
|
||||
if (isBlank(timestamp) || isBlank(nonce)) {
|
||||
writeJson(response, HttpServletResponse.SC_BAD_REQUEST, ErrorCode.BAD_REQUEST.getCode(), "missing replay protection headers");
|
||||
writeJson(response, HttpServletResponse.SC_BAD_REQUEST, ErrorCode.BAD_REQUEST.getCode(), "防重放请求头缺失");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public class InternalApiReplayInterceptor implements HandlerInterceptor {
|
||||
try {
|
||||
requestTimestamp = Long.parseLong(timestamp);
|
||||
} catch (NumberFormatException ex) {
|
||||
writeJson(response, HttpServletResponse.SC_BAD_REQUEST, ErrorCode.BAD_REQUEST.getCode(), "invalid replay timestamp");
|
||||
writeJson(response, HttpServletResponse.SC_BAD_REQUEST, ErrorCode.BAD_REQUEST.getCode(), "防重放时间戳格式无效");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ public class InternalApiReplayInterceptor implements HandlerInterceptor {
|
||||
try {
|
||||
ReplayCheckResult result = replayProtectionService.check(replayRequest);
|
||||
if (result.isReplayed()) {
|
||||
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.CONFLICT.getCode(), "replayed nonce");
|
||||
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.CONFLICT.getCode(), "nonce已被重放");
|
||||
return false;
|
||||
}
|
||||
} catch (ReplayProtectionException ex) {
|
||||
@ -153,6 +153,6 @@ public class InternalApiReplayInterceptor implements HandlerInterceptor {
|
||||
return;
|
||||
}
|
||||
writeJson(response, HttpServletResponse.SC_SERVICE_UNAVAILABLE, ErrorCode.SERVICE_UNAVAILABLE.getCode(),
|
||||
"replay protection unavailable");
|
||||
"防重放校验服务不可用");
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,14 +51,14 @@ public class OpenApiSignAuthInterceptor implements HandlerInterceptor {
|
||||
String signature = trimHeader(request, SIGNATURE_HEADER);
|
||||
|
||||
if (isBlank(appId) || isBlank(timestamp) || isBlank(nonce) || isBlank(signature)) {
|
||||
writeUnauthorized(response, "missing openapi auth headers");
|
||||
writeUnauthorized(response, "OpenAPI认证请求头缺失");
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, String> clients = securityProperties.getOpenapi().getClients();
|
||||
String appSecret = clients.get(appId);
|
||||
if (isBlank(appSecret)) {
|
||||
writeUnauthorized(response, "unknown app id");
|
||||
writeUnauthorized(response, "未知的appId");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public class OpenApiSignAuthInterceptor implements HandlerInterceptor {
|
||||
try {
|
||||
requestEpoch = Long.parseLong(timestamp);
|
||||
} catch (NumberFormatException ex) {
|
||||
writeUnauthorized(response, "invalid timestamp");
|
||||
writeUnauthorized(response, "时间戳格式无效");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ public class OpenApiSignAuthInterceptor implements HandlerInterceptor {
|
||||
// 先完成签名校验,再占用 nonce,避免伪造请求提前消耗合法 nonce。
|
||||
ReplayCheckResult result = replayProtectionService.check(buildReplayRequest(request, appId, nonce, requestEpoch));
|
||||
if (result.isReplayed()) {
|
||||
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.CONFLICT.getCode(), "replayed nonce");
|
||||
writeJson(response, HttpServletResponse.SC_CONFLICT, ErrorCode.CONFLICT.getCode(), "nonce已被重放");
|
||||
return false;
|
||||
}
|
||||
} catch (ReplayProtectionException ex) {
|
||||
@ -159,6 +159,6 @@ public class OpenApiSignAuthInterceptor implements HandlerInterceptor {
|
||||
return;
|
||||
}
|
||||
writeJson(response, HttpServletResponse.SC_SERVICE_UNAVAILABLE,
|
||||
ErrorCode.SERVICE_UNAVAILABLE.getCode(), "replay protection unavailable");
|
||||
ErrorCode.SERVICE_UNAVAILABLE.getCode(), "防重放校验服务不可用");
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,15 @@ class ChineseErrorMessageContractTest {
|
||||
private static final Pattern VALIDATION_MESSAGE = Pattern.compile(
|
||||
"@(?:NotNull|NotBlank|NotEmpty|Size|Pattern|Min|Max|Positive|AssertTrue)\\([^\\n]*message\\s*=\\s*\"([^\"]+)\""
|
||||
);
|
||||
private static final Pattern USER_FACING_STATEMENT = Pattern.compile(
|
||||
"(?s)(?:new\\s+(?:BizException|IllegalArgumentException|IllegalStateException|RuntimeException|ReplayProtectionException)\\([^;]*;"
|
||||
+ "|ApiResponse\\.fail\\([^;]*;"
|
||||
+ "|write(?:Unauthorized|Forbidden|SessionInvalid|Json)\\([^;]*;"
|
||||
+ "|InitStepExecutionResult\\.failure\\([^;]*;"
|
||||
+ "|new\\s+PcieCryptoException\\([^;]*;"
|
||||
+ "|new\\s+RequiredBackupResourceMissingException\\([^;]*;)"
|
||||
);
|
||||
private static final Pattern STRING_LITERAL_WITH_ENGLISH = Pattern.compile("\"([^\"]*[A-Za-z][^\"]*)\"");
|
||||
|
||||
@Test
|
||||
void productionErrorMessagesShouldBeChinese() throws IOException {
|
||||
@ -41,7 +50,9 @@ class ChineseErrorMessageContractTest {
|
||||
|
||||
private static void collectViolations(Path path, List<String> violations) {
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(path);
|
||||
String content = Files.readString(path);
|
||||
collectStatements(content, path, violations);
|
||||
List<String> lines = content.lines().toList();
|
||||
for (int index = 0; index < lines.size(); index++) {
|
||||
String line = lines.get(index);
|
||||
if (line.trim().startsWith("//") || line.contains("log.")) {
|
||||
@ -55,6 +66,48 @@ class ChineseErrorMessageContractTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectStatements(String content, Path path, List<String> violations) {
|
||||
Matcher statementMatcher = USER_FACING_STATEMENT.matcher(content);
|
||||
while (statementMatcher.find()) {
|
||||
String statement = statementMatcher.group();
|
||||
if (statement.trim().startsWith("//") || statement.contains("log.")) {
|
||||
continue;
|
||||
}
|
||||
if (CHINESE.matcher(statement).find()) {
|
||||
continue;
|
||||
}
|
||||
Matcher literalMatcher = STRING_LITERAL_WITH_ENGLISH.matcher(statement);
|
||||
int literalIndex = 0;
|
||||
while (literalMatcher.find()) {
|
||||
String message = literalMatcher.group(1);
|
||||
if (isNonMessagePcieApiName(statement, message, literalIndex)) {
|
||||
literalIndex++;
|
||||
continue;
|
||||
}
|
||||
if (!CHINESE.matcher(message).find()) {
|
||||
violations.add(path + ":" + lineNumber(content, statementMatcher.start() + literalMatcher.start()) + " -> " + message);
|
||||
}
|
||||
literalIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNonMessagePcieApiName(String statement, String message, int literalIndex) {
|
||||
return statement.contains("PcieCryptoException(")
|
||||
&& literalIndex == 0
|
||||
&& message.matches("[A-Za-z0-9_./-]+");
|
||||
}
|
||||
|
||||
private static int lineNumber(String content, int offset) {
|
||||
int line = 1;
|
||||
for (int i = 0; i < offset; i++) {
|
||||
if (content.charAt(i) == '\n') {
|
||||
line++;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private static void collect(String line, Pattern pattern, Path path, int index, List<String> violations) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
while (matcher.find()) {
|
||||
|
||||
@ -46,7 +46,7 @@ class GlobalExceptionHandlerTest {
|
||||
Assertions.assertNotNull(response.getBody());
|
||||
Assertions.assertFalse(response.getBody().isSuccess());
|
||||
Assertions.assertEquals(ErrorCode.VALIDATE_FAILED.getCode(), response.getBody().getCode());
|
||||
Assertions.assertEquals("failed to parse multipart request", response.getBody().getMsg());
|
||||
Assertions.assertEquals("解析 multipart 上传请求失败", response.getBody().getMsg());
|
||||
Assertions.assertEquals("/api/v1/files/upload", response.getBody().getPath());
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ class GlobalExceptionHandlerTest {
|
||||
Assertions.assertNotNull(response.getBody());
|
||||
Assertions.assertFalse(response.getBody().isSuccess());
|
||||
Assertions.assertEquals(ErrorCode.NOT_FOUND.getCode(), response.getBody().getCode());
|
||||
Assertions.assertEquals("resource not found", response.getBody().getMsg());
|
||||
Assertions.assertEquals("资源不存在", response.getBody().getMsg());
|
||||
Assertions.assertEquals("/missing.js", response.getBody().getPath());
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ class AuthAdminServiceTest {
|
||||
));
|
||||
|
||||
Assertions.assertEquals(ErrorCode.UNAUTHORIZED.getCode(), exception.getCode());
|
||||
Assertions.assertEquals("old password is incorrect", exception.getMessage());
|
||||
Assertions.assertEquals("旧密码错误", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -140,7 +140,7 @@ class AuthServiceTest {
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.login(request));
|
||||
|
||||
Assertions.assertEquals("full account is locked", exception.getMessage());
|
||||
Assertions.assertEquals("完整账号已锁定", exception.getMessage());
|
||||
AuthFullAccountEntity locked = accounts.findByRoleCodeAndUid(RoleCode.SUPER_ADMIN.getCode(), 1).orElseThrow();
|
||||
AuthFullAccountEntity untouched = accounts.findByRoleCodeAndUid(RoleCode.SUPER_ADMIN.getCode(), 2).orElseThrow();
|
||||
Assertions.assertEquals(RoleAccountStatus.LOCKED.name(), locked.getStatus());
|
||||
|
||||
@ -8,8 +8,8 @@ class RequiredBackupResourceMissingExceptionTest {
|
||||
@Test
|
||||
void shouldExposeMessage() {
|
||||
RequiredBackupResourceMissingException exception =
|
||||
new RequiredBackupResourceMissingException("required backup resource is unavailable");
|
||||
new RequiredBackupResourceMissingException("必需备份资源不可用");
|
||||
|
||||
Assertions.assertEquals("required backup resource is unavailable", exception.getMessage());
|
||||
Assertions.assertEquals("必需备份资源不可用", exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ class ResourceBackupServiceTest {
|
||||
Mockito.same(initTask),
|
||||
Mockito.eq(discoveredItems),
|
||||
Mockito.any(CreateResourceBackupRequest.class)
|
||||
)).thenThrow(new RequiredBackupResourceMissingException("required backup resource is unavailable: code=TMS_CONFIG"));
|
||||
)).thenThrow(new RequiredBackupResourceMissingException("必需备份资源不可用:code=TMS_CONFIG"));
|
||||
|
||||
ResourceBackupService service = new ResourceBackupServiceImpl(
|
||||
initTaskRepository,
|
||||
|
||||
@ -101,7 +101,7 @@ class UpgradePackageServiceTest {
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.preview(fileRecord.getFileId()));
|
||||
Assertions.assertEquals(ErrorCode.BIZ_ERROR.getCode(), exception.getCode());
|
||||
Assertions.assertEquals("upgrade package product type does not match current device", exception.getMessage());
|
||||
Assertions.assertEquals("升级包产品类型与当前设备不匹配", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -124,7 +124,7 @@ class UpgradePackageServiceTest {
|
||||
);
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.preview(fileRecord.getFileId()));
|
||||
Assertions.assertEquals("target version is lower than current version", exception.getMessage());
|
||||
Assertions.assertEquals("目标版本低于当前版本", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -147,7 +147,7 @@ class UpgradePackageServiceTest {
|
||||
);
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.preview(fileRecord.getFileId()));
|
||||
Assertions.assertEquals("current version does not satisfy minimum compatible version", exception.getMessage());
|
||||
Assertions.assertEquals("当前版本不满足最低兼容版本要求", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -210,7 +210,7 @@ class UpgradePackageServiceTest {
|
||||
);
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.preview(fileRecord.getFileId()));
|
||||
Assertions.assertEquals("upgrade package payload sm3 mismatch", exception.getMessage());
|
||||
Assertions.assertEquals("升级包payload SM3摘要不匹配", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -108,7 +108,7 @@ class UpgradeServiceTest {
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.createTask(request));
|
||||
|
||||
Assertions.assertEquals("selected taskType does not match package taskType", exception.getMessage());
|
||||
Assertions.assertEquals("选择的taskType与升级包taskType不匹配", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -129,7 +129,7 @@ class UpgradeServiceTest {
|
||||
|
||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.executeTask("UPG-001"));
|
||||
|
||||
Assertions.assertEquals("another upgrade task is running", exception.getMessage());
|
||||
Assertions.assertEquals("已有升级任务正在执行", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -99,7 +99,7 @@ class InternalApiReplayInterceptorTest {
|
||||
|
||||
Assertions.assertFalse(allowed);
|
||||
Assertions.assertEquals(400, response.getStatus());
|
||||
Assertions.assertTrue(response.getContentAsString().contains("missing replay protection headers"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("防重放请求头缺失"));
|
||||
Mockito.verifyNoInteractions(replayProtectionService);
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ class InternalApiReplayInterceptorTest {
|
||||
|
||||
Assertions.assertFalse(allowed);
|
||||
Assertions.assertEquals(409, response.getStatus());
|
||||
Assertions.assertTrue(response.getContentAsString().contains("replayed nonce"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("nonce已被重放"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.CONFLICT.getCode()));
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ class InternalApiReplayInterceptorTest {
|
||||
|
||||
Assertions.assertFalse(allowed);
|
||||
Assertions.assertEquals(503, response.getStatus());
|
||||
Assertions.assertTrue(response.getContentAsString().contains("replay protection unavailable"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("防重放校验服务不可用"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.SERVICE_UNAVAILABLE.getCode()));
|
||||
}
|
||||
|
||||
|
||||
@ -117,7 +117,7 @@ class OpenApiSignAuthInterceptorTest {
|
||||
|
||||
Assertions.assertFalse(allowed);
|
||||
Assertions.assertEquals(409, response.getStatus());
|
||||
Assertions.assertTrue(response.getContentAsString().contains("replayed nonce"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("nonce已被重放"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.CONFLICT.getCode()));
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ class OpenApiSignAuthInterceptorTest {
|
||||
|
||||
Assertions.assertFalse(allowed);
|
||||
Assertions.assertEquals(503, response.getStatus());
|
||||
Assertions.assertTrue(response.getContentAsString().contains("replay protection unavailable"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("防重放校验服务不可用"));
|
||||
Assertions.assertTrue(response.getContentAsString().contains("\"code\":" + ErrorCode.SERVICE_UNAVAILABLE.getCode()));
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user