From b7c2f0144f95f7fda4a5f5d6b4b62612a1f2c49b Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Sat, 23 May 2026 00:28:51 +0800 Subject: [PATCH] refactor(license): remove server-side package name validation Package name matching is now entirely the SDK's responsibility. - DeviceService: drop packageName param from register/verify, delete validatePackageName() - LicensePublicController: remove matchesPackageName check in resolveAppKey(), remove packageName from service calls, add GET /api/license/app-info for SDK appKey-only flow to fetch configured package names for local comparison Co-Authored-By: Claude Sonnet 4.6 --- .../controller/LicensePublicController.java | 51 ++++++++++++------- .../xuqm/license/service/DeviceService.java | 33 +----------- 2 files changed, 36 insertions(+), 48 deletions(-) diff --git a/license-service/src/main/java/com/xuqm/license/controller/LicensePublicController.java b/license-service/src/main/java/com/xuqm/license/controller/LicensePublicController.java index d2c832f..543d110 100644 --- a/license-service/src/main/java/com/xuqm/license/controller/LicensePublicController.java +++ b/license-service/src/main/java/com/xuqm/license/controller/LicensePublicController.java @@ -6,15 +6,15 @@ import com.fasterxml.jackson.databind.JsonNode; import com.xuqm.common.exception.BusinessException; import com.xuqm.common.model.ApiResponse; import com.xuqm.common.security.LicenseFileCrypto; +import com.xuqm.license.entity.AppLicenseEntity; +import com.xuqm.license.service.AppLicenseService; import com.xuqm.license.service.DeviceService; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import java.util.LinkedHashMap; import java.util.Map; @RestController @@ -22,24 +22,25 @@ import java.util.Map; public class LicensePublicController { private final DeviceService deviceService; + private final AppLicenseService appLicenseService; - public LicensePublicController(DeviceService deviceService) { + public LicensePublicController(DeviceService deviceService, AppLicenseService appLicenseService) { this.deviceService = deviceService; + this.appLicenseService = appLicenseService; } @PostMapping("/register") public ResponseEntity>> register(@Valid @RequestBody RegisterRequest req) { - String resolvedAppKey = resolveAppKey(req.appKey(), req.packageName(), req.licenseFile()); + String resolvedAppKey = resolveAppKey(req.appKey(), req.licenseFile()); DeviceService.RegisterResult result = deviceService.register( resolvedAppKey, - req.packageName(), req.deviceId(), req.deviceName(), req.deviceModel(), req.deviceVendor(), req.osVersion(), req.userInfo()); - Map data = new java.util.LinkedHashMap<>(); + Map data = new LinkedHashMap<>(); data.put("success", result.success()); data.put("token", result.token()); if (result.message() != null) { @@ -50,9 +51,9 @@ public class LicensePublicController { @PostMapping("/verify") public ResponseEntity>> verify(@Valid @RequestBody VerifyRequest req) { - String resolvedAppKey = resolveAppKey(req.appKey(), req.packageName(), req.licenseFile()); - DeviceService.VerifyResult result = deviceService.verify(resolvedAppKey, req.packageName(), req.deviceId(), req.token(), req.userInfo()); - Map data = new java.util.LinkedHashMap<>(); + String resolvedAppKey = resolveAppKey(req.appKey(), req.licenseFile()); + DeviceService.VerifyResult result = deviceService.verify(resolvedAppKey, req.deviceId(), req.token(), req.userInfo()); + Map data = new LinkedHashMap<>(); data.put("valid", result.valid()); if (result.error() != null) { data.put("error", result.error()); @@ -60,12 +61,28 @@ public class LicensePublicController { return ResponseEntity.ok(ApiResponse.success(data)); } - private static String resolveAppKey(String appKey, String packageName, String licenseFile) { + /** + * Returns configured package names for the given appKey. + * Used by the SDK (appKey-only flow) to validate the caller's package name client-side. + */ + @GetMapping("/app-info") + public ResponseEntity>> appInfo(@RequestParam String appKey) { + AppLicenseEntity license; + try { + license = appLicenseService.getByAppKey(appKey); + } catch (BusinessException e) { + throw new BusinessException(404, "App not found"); + } + Map data = new LinkedHashMap<>(); + data.put("androidPackageName", license.getAndroidPackageName()); + data.put("iosBundleId", license.getIosBundleId()); + data.put("harmonyBundleName", license.getHarmonyBundleName()); + return ResponseEntity.ok(ApiResponse.success(data)); + } + + private static String resolveAppKey(String appKey, String licenseFile) { if (licenseFile != null && !licenseFile.isBlank()) { LicenseFileCrypto.LicensePayload payload = LicenseFileCrypto.decrypt(licenseFile); - if (!payload.matchesPackageName(packageName)) { - throw new BusinessException(403, "包名与应用配置不匹配"); - } return payload.appKey(); } if (appKey == null || appKey.isBlank()) { @@ -76,7 +93,7 @@ public class LicensePublicController { public record RegisterRequest( String appKey, - @NotBlank @JsonProperty("packageName") @JsonAlias("package_name") String packageName, + @JsonProperty("packageName") @JsonAlias("package_name") String packageName, @JsonProperty("licenseFile") @JsonAlias("license_file") String licenseFile, @NotBlank @JsonProperty("deviceId") @JsonAlias("device_id") String deviceId, @JsonProperty("deviceName") @JsonAlias("device_name") String deviceName, @@ -88,7 +105,7 @@ public class LicensePublicController { public record VerifyRequest( String appKey, - @NotBlank @JsonProperty("packageName") @JsonAlias("package_name") String packageName, + @JsonProperty("packageName") @JsonAlias("package_name") String packageName, @JsonProperty("licenseFile") @JsonAlias("license_file") String licenseFile, @NotBlank @JsonProperty("deviceId") @JsonAlias("device_id") String deviceId, @NotBlank String token, diff --git a/license-service/src/main/java/com/xuqm/license/service/DeviceService.java b/license-service/src/main/java/com/xuqm/license/service/DeviceService.java index 4454474..c99f426 100644 --- a/license-service/src/main/java/com/xuqm/license/service/DeviceService.java +++ b/license-service/src/main/java/com/xuqm/license/service/DeviceService.java @@ -43,11 +43,9 @@ public class DeviceService { } @Transactional - public RegisterResult register(String appKey, String packageName, String deviceId, String deviceName, + public RegisterResult register(String appKey, String deviceId, String deviceName, String deviceModel, String deviceVendor, String osVersion, JsonNode userInfo) { - validatePackageName(appKey, packageName); - // Check if device already registered for this app Optional existingOpt = deviceRepository.findByAppKeyAndDeviceId(appKey, deviceId); if (existingOpt.isPresent()) { @@ -116,12 +114,7 @@ public class DeviceService { } @Transactional - public VerifyResult verify(String appKey, String packageName, String deviceId, String token, JsonNode userInfo) { - try { - validatePackageName(appKey, packageName); - } catch (BusinessException e) { - return new VerifyResult(false, e.getMessage()); - } + public VerifyResult verify(String appKey, String deviceId, String token, JsonNode userInfo) { if (!licenseAuthService.verifyTokenPayload(token, appKey, deviceId)) { return new VerifyResult(false, "Token mismatch"); } @@ -168,28 +161,6 @@ public class DeviceService { appLicenseService.incrementRegisteredDevices(device.getAppKey()); } - private void validatePackageName(String appKey, String packageName) { - if (packageName == null || packageName.isBlank()) { - throw new BusinessException(403, "packageName is required"); - } - AppLicenseEntity license; - try { - license = appLicenseService.getByAppKey(appKey); - } catch (BusinessException e) { - throw new BusinessException(403, "App license not found"); - } - String android = license.getAndroidPackageName(); - String ios = license.getIosBundleId(); - String harmony = license.getHarmonyBundleName(); - boolean anyConfigured = hasText(android) || hasText(ios) || hasText(harmony); - if (anyConfigured) { - boolean matches = packageName.equals(android) || packageName.equals(ios) || packageName.equals(harmony); - if (!matches) { - throw new BusinessException(403, "包名与应用配置不匹配"); - } - } - } - private static boolean hasText(String s) { return s != null && !s.isBlank(); }