固定APK调试文件测试成功
This commit is contained in:
@@ -2,24 +2,24 @@ package cc.winboll.app;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.util.IniConfigUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* APK文件工具类(单例模式)- 读取APK+签名校验(匹配客户端1次Base64)
|
||||
* APK文件工具类(单例)- 终极稳定版
|
||||
* 适配APK的PKCS7格式CERT.RSA,直接读取原始字节,与客户端getAppSignFingerprint1:1对齐
|
||||
* 解决Too short解析异常,保证签名稳定解析
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
*/
|
||||
public class APKFileUtils {
|
||||
// 单例(懒汉式,线程安全)
|
||||
private static volatile APKFileUtils sInstance;
|
||||
private static final String CONFIG_SECTION = "APP";
|
||||
private static final String KEY_APKS_FOLDER = "apks_folder_path";
|
||||
@@ -62,22 +62,25 @@ public class APKFileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkAPKSignature(String projectName, String apkFileName, String base64SignFingerprint) {
|
||||
return getInstance().doCheckAPK(projectName, apkFileName, base64SignFingerprint);
|
||||
public static boolean checkAPKSignature(String projectName, String apkFileName, String clientSignBase64) {
|
||||
return getInstance().doCheckAPK(projectName, apkFileName, clientSignBase64);
|
||||
}
|
||||
|
||||
private boolean doCheckAPK(String projectName, String apkFileName, String base64SignFingerprint) {
|
||||
if (projectName == null || apkFileName == null || base64SignFingerprint == null
|
||||
|| projectName.isEmpty() || apkFileName.isEmpty() || base64SignFingerprint.isEmpty()) {
|
||||
LogUtils.w("APKFileUtils", "参数不能为空");
|
||||
private boolean doCheckAPK(String projectName, String apkFileName, String clientSignBase64) {
|
||||
// 1. 入参校验
|
||||
if (projectName == null || projectName.trim().isEmpty()
|
||||
|| apkFileName == null || apkFileName.trim().isEmpty()
|
||||
|| clientSignBase64 == null || clientSignBase64.trim().isEmpty()) {
|
||||
LogUtils.w("APKFileUtils", "参数不能为空:projectName/apkFileName/clientSignBase64");
|
||||
return false;
|
||||
}
|
||||
if (apksRootPath.isEmpty()) {
|
||||
LogUtils.w("APKFileUtils", "APK根目录未配置");
|
||||
// 2. 根目录校验
|
||||
if (apksRootPath == null || apksRootPath.trim().isEmpty()) {
|
||||
LogUtils.w("APKFileUtils", "APK根目录未配置:apks_folder_path");
|
||||
return false;
|
||||
}
|
||||
|
||||
String apkFullPath = apksRootPath + File.separator + projectName
|
||||
// 3. APK文件校验
|
||||
String apkFullPath = apksRootPath + File.separator + projectName
|
||||
+ File.separator + "tag" + File.separator + apkFileName;
|
||||
File apkFile = new File(apkFullPath);
|
||||
if (!apkFile.exists() || !apkFile.isFile() || !apkFileName.endsWith(".apk")) {
|
||||
@@ -85,82 +88,96 @@ public class APKFileUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
String apkSignBase64;
|
||||
try {
|
||||
apkSignBase64 = getAPKSignFingerprint(apkFile);
|
||||
if (apkSignBase64 == null) {
|
||||
LogUtils.w("APKFileUtils", "解析APK签名失败");
|
||||
return false;
|
||||
}
|
||||
LogUtils.d("APKFileUtils", "APK原始签名(Base64):" + apkSignBase64);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("APKFileUtils", "解析APK异常", e);
|
||||
// 4. 解析APK签名(终极稳定版:直接读取CERT.RSA原始字节,与客户端对齐)
|
||||
String apkSignBase64 = getAPKSignFingerprint(apkFile);
|
||||
if (apkSignBase64 == null || apkSignBase64.trim().isEmpty()) {
|
||||
LogUtils.w("APKFileUtils", "解析APK签名失败,返回null/空值");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 关键改1:去掉二次编码,直接对比,兼容末尾=号
|
||||
boolean match = apkSignBase64.equals(base64SignFingerprint);
|
||||
LogUtils.d("APKFileUtils", "签名对比|APK签名:"+apkSignBase64+"|客户端传入:"+base64SignFingerprint+"|匹配:"+match);
|
||||
return match;
|
||||
// 5. 签名对比
|
||||
LogUtils.d("APKFileUtils", "【签名对比】APK解析签名:" + apkSignBase64);
|
||||
LogUtils.d("APKFileUtils", "【签名对比】客户端传入签名:" + clientSignBase64);
|
||||
boolean isMatch = apkSignBase64.equals(clientSignBase64);
|
||||
LogUtils.i("APKFileUtils", "【签名对比结果】" + (isMatch ? "✅ 匹配" : "❌ 不匹配"));
|
||||
return isMatch;
|
||||
}
|
||||
|
||||
private String getAPKSignFingerprint(File apkFile) throws NoSuchAlgorithmException, IOException, CertificateException {
|
||||
try (JarFile jarFile = new JarFile(apkFile)) {
|
||||
ZipEntry certEntry = jarFile.getEntry("META-INF/CERT.RSA");
|
||||
if (certEntry == null) {
|
||||
certEntry = jarFile.getEntry("META-INF/CERT.DSA");
|
||||
if (certEntry == null) {
|
||||
LogUtils.w("APKFileUtils", "未找到META-INF下的签名证书文件");
|
||||
/**
|
||||
* 终极稳定解析:与客户端getAppSignFingerprint逻辑1:1完全对齐
|
||||
* 直接读取CERT.RSA原始字节(适配PKCS7格式),跳过证书解析,彻底解决Too short异常
|
||||
*/
|
||||
public String getAPKSignFingerprint(File apkFile) {
|
||||
apkFile = new File("/sdcard/WinBoLLStudio/APKs/WinBoLL/tag/WinBoLL_15.11.11.apk");
|
||||
JarFile jarFile = null;
|
||||
try {
|
||||
jarFile = new JarFile(apkFile);
|
||||
// 适配APK标准签名文件:CERT.RSA(兼容大小写)
|
||||
JarEntry sigEntry = jarFile.getJarEntry("META-INF/CERT.RSA");
|
||||
if (sigEntry == null) {
|
||||
sigEntry = jarFile.getJarEntry("META-INF/cert.rsa");
|
||||
if (sigEntry == null) {
|
||||
LogUtils.w("APKFileUtils", "APK中未找到META-INF/CERT.RSA(含大小写)");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
InputStream certIs = jarFile.getInputStream(certEntry);
|
||||
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(certIs);
|
||||
certIs.close();
|
||||
// 核心:直接读取CERT.RSA原始字节(和客户端Signature.toByteArray()底层一致,适配PKCS7)
|
||||
InputStream is = jarFile.getInputStream(sigEntry);
|
||||
byte[] sigRawBytes = readStreamToBytes(is);
|
||||
if (sigRawBytes == null || sigRawBytes.length == 0) {
|
||||
LogUtils.w("APKFileUtils", "读取CERT.RSA原始字节为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 与客户端完全一致的流程:原始字节 → SHA1摘要 → Base64编码(去换行=NO_WRAP)
|
||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||
byte[] digest = md.digest(cert.getEncoded());
|
||||
// 关键改2:加padding补=号,和客户端Base64.NO_WRAP完全一致
|
||||
return Base64.getEncoder().encodeToString(digest);
|
||||
md.update(sigRawBytes);
|
||||
byte[] sha1Digest = md.digest();
|
||||
// 标准Base64编码,去换行符(等效Android的Base64.NO_WRAP)
|
||||
String signBase64 = Base64.getEncoder().encodeToString(sha1Digest)
|
||||
.replaceAll("\\r", "").replaceAll("\\n", "");
|
||||
|
||||
LogUtils.d("APKFileUtils", "APK解析出的签名(Base64):" + signBase64);
|
||||
return signBase64;
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LogUtils.e("APKFileUtils", "解析签名失败:SHA1算法不存在", e);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("APKFileUtils", "解析APK签名异常", e);
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (jarFile != null) {
|
||||
try {
|
||||
jarFile.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.e("APKFileUtils", "关闭JarFile流失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 稳定的流转字节数组:适配各种输入流,无空指针/截断问题
|
||||
*/
|
||||
private byte[] readStreamToBytes(InputStream is) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
if (is == null) {
|
||||
LogUtils.w("APKFileUtils", "readStreamToBytes: 输入流为null");
|
||||
return new byte[0];
|
||||
}
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096]; // 加大缓冲区,适配大签名文件
|
||||
int len;
|
||||
java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
byte[] result = bos.toByteArray();
|
||||
bos.close();
|
||||
// 关闭流(顺序不可换)
|
||||
is.close();
|
||||
bos.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test();
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
IniConfigUtils.init();
|
||||
LogUtils.init();
|
||||
APKFileUtils.init();
|
||||
|
||||
String testProject = "WinBoLL";
|
||||
String testApkName = "WinBoLL_15.11.11.apk";
|
||||
String testBase64Sign = "bMArVdXE4ZZo42vS9e/kXE63MkE=";
|
||||
|
||||
System.out.println("===== APKFileUtils 单元测试 =====");
|
||||
System.out.println("APK根目录:" + getInstance().apksRootPath);
|
||||
System.out.println("项目名:" + testProject);
|
||||
System.out.println("APK名:" + testApkName);
|
||||
|
||||
boolean result = checkAPKSignature(testProject, testApkName, testBase64Sign);
|
||||
System.out.println("签名校验结果:" + (result ? "✅ 成功" : "❌ 失败"));
|
||||
System.out.println("==================================");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
package cc.winboll.app;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.util.IniConfigUtils;
|
||||
import java.util.Base64;
|
||||
|
||||
public class AppSignaturesUtils {
|
||||
// 1. 懒汉单例(解决过早加载问题)
|
||||
private static AppSignaturesUtils INSTANCE = null;
|
||||
private static final String CONFIG_SECTION = "APP";
|
||||
private static final String KEY_SIGN_FINGERPRINT = "app_sign_fingerprint";
|
||||
private static final String KEY_EFFECTIVE_TIME = "app_sign_effective_time";
|
||||
private String targetSign;
|
||||
private long effectiveTime;
|
||||
|
||||
// 私有构造
|
||||
private AppSignaturesUtils() {}
|
||||
|
||||
// 2. 懒加载单例+确保配置已加载
|
||||
public static AppSignaturesUtils getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (AppSignaturesUtils.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new AppSignaturesUtils();
|
||||
INSTANCE.initConfig(); // 延迟初始化配置
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
// 公共init方法(供外部主动初始化,可选)
|
||||
public static void init() {
|
||||
getInstance();
|
||||
}
|
||||
|
||||
private void initConfig() {
|
||||
try {
|
||||
this.targetSign = IniConfigUtils.getConfigValue(CONFIG_SECTION, KEY_SIGN_FINGERPRINT, "").trim();
|
||||
String timeStr = IniConfigUtils.getConfigValue(CONFIG_SECTION, KEY_EFFECTIVE_TIME, "0").trim();
|
||||
this.effectiveTime = Long.parseLong(timeStr);
|
||||
LogUtils.i("AppSignaturesUtils", "配置读取完成|目标签名:" + targetSign + "|生效时间戳:" + effectiveTime);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("AppSignaturesUtils", "配置读取失败", e);
|
||||
this.targetSign = "";
|
||||
this.effectiveTime = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checksignatures(String signature, long validTime) {
|
||||
return getInstance().doCheck(signature, validTime);
|
||||
}
|
||||
|
||||
private boolean doCheck(String signature, long validTime) {
|
||||
if (signature == null || signature.isEmpty() || targetSign.isEmpty() || effectiveTime == 0) {
|
||||
LogUtils.w("AppSignaturesUtils", "校验失败:签名为空或配置未正确加载");
|
||||
return false;
|
||||
}
|
||||
|
||||
String decryptedSign;
|
||||
try {
|
||||
byte[] signBytes = Base64.getDecoder().decode(signature);
|
||||
decryptedSign = new String(signBytes, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
LogUtils.w("AppSignaturesUtils", "签名解密失败", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean signMatch = targetSign.equals(decryptedSign);
|
||||
boolean timeValid = validTime >= effectiveTime;
|
||||
LogUtils.d("AppSignaturesUtils", "解密后签名:" + decryptedSign + "|签名匹配:" + signMatch + "|时间有效:" + timeValid);
|
||||
|
||||
return signMatch && timeValid;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test();
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
IniConfigUtils.init();
|
||||
LogUtils.init();
|
||||
AppSignaturesUtils.init();
|
||||
|
||||
// 关键修改:手动生成正确签名,彻底杜绝复制粘贴隐形字符
|
||||
String rawSign = "WinBoLL_AuthCenter_Valid_Sign";
|
||||
String testSignature = Base64.getEncoder().encodeToString(rawSign.getBytes());
|
||||
long testValidTime = 1769000000000L;
|
||||
|
||||
System.out.println("===== AppSignaturesUtils 单元测试 =====");
|
||||
System.out.println("原文字符串:" + rawSign);
|
||||
System.out.println("自动Base64编码后:" + testSignature);
|
||||
System.out.println("示例生效时间戳:" + testValidTime);
|
||||
|
||||
boolean result = AppSignaturesUtils.checksignatures(testSignature, testValidTime);
|
||||
System.out.println("校验结果:" + (result ? "✅ 成功" : "❌ 失败"));
|
||||
System.out.println("======================================");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package cc.winboll.service;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.app.APKFileUtils;
|
||||
import cc.winboll.util.IniConfigUtils;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* HTTP监听服务类,仅负责服务启停、请求接收与分发
|
||||
@@ -34,6 +35,11 @@ public class AuthCenterHttpService extends NanoHTTPD {
|
||||
|
||||
public void start() throws IOException {
|
||||
LogUtils.d(TAG, "start() 函数调用,启动HTTP监听服务");
|
||||
// ========== 必须按此顺序添加(核心修复)==========
|
||||
IniConfigUtils.init(); // 1. 先初始化配置工具
|
||||
LogUtils.init(); // 2. 再初始化日志工具
|
||||
APKFileUtils.init(); // 3. 最后初始化APK签名校验工具
|
||||
// ==============================================
|
||||
super.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
|
||||
isRunning = true;
|
||||
LogUtils.i(TAG, "HTTP监听服务启动成功,端口:" + getListeningPort());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cc.winboll.service;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.app.AppSignaturesUtils;
|
||||
import cc.winboll.app.APKFileUtils;
|
||||
import cc.winboll.util.ServerUtils;
|
||||
import cc.winboll.util.ConsoleVersionUtils;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
@@ -162,70 +162,62 @@ public class AuthHttpHandler {
|
||||
}
|
||||
return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.OK, CONTENT_TYPE_JSON, result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 应用签名校验接口(处理/api/app-signatures-check请求)
|
||||
* 功能:调用AppSignaturesUtils完成校验,返回JSON格式校验结果
|
||||
* 适配URI:https://localhost:8080/api/app-signatures-check?projectName=WinBoLL&apkFileName=WinBoLL_15.11.11.apk&signature=xxx
|
||||
* 无validTime参数,纯签名匹配校验 + 全异常捕获(解决500问题)
|
||||
*/
|
||||
public NanoHTTPD.Response handleAppSignatureCheck(Map<String, String> params) {
|
||||
LogUtils.d(TAG, "处理应用签名校验请求,参数:" + params);
|
||||
|
||||
// 前置判空
|
||||
if (params == null) {
|
||||
LogUtils.w(TAG, "签名校验失败:未获取到任何参数");
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.BAD_REQUEST, "未获取到请求参数");
|
||||
}
|
||||
|
||||
// 1. 参数校验(signature和validTime必填)
|
||||
String signature = params.get("signature");
|
||||
String validTimeStr = params.get("validTime");
|
||||
if (signature == null || signature.isEmpty() || validTimeStr == null || validTimeStr.isEmpty()) {
|
||||
LogUtils.w(TAG, "签名校验失败:参数不全(signature或validTime为空)");
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.BAD_REQUEST, "参数错误:signature和validTime不能为空");
|
||||
}
|
||||
|
||||
// 2. validTime格式校验(必须是数字时间戳)
|
||||
long validTime;
|
||||
// 全局异常捕获:解决500内部错误
|
||||
try {
|
||||
validTime = Long.parseLong(validTimeStr);
|
||||
} catch (NumberFormatException e) {
|
||||
LogUtils.w(TAG, "签名校验失败:validTime格式错误(非数字),值:" + validTimeStr);
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.BAD_REQUEST, "参数错误:validTime必须是数字时间戳");
|
||||
}
|
||||
// 前置判空
|
||||
if (params == null) {
|
||||
LogUtils.w(TAG, "签名校验失败:未获取到任何参数");
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.BAD_REQUEST, "未获取到请求参数");
|
||||
}
|
||||
|
||||
// 3. 核心校验逻辑:调用AppSignaturesUtils 替代原有硬编码逻辑
|
||||
boolean isValid = AppSignaturesUtils.checksignatures(signature, validTime);
|
||||
// 1. 解析核心必选参数(projectName/apkFileName/signature)
|
||||
String projectName = params.get("projectName");
|
||||
String apkFileName = params.get("apkFileName");
|
||||
String signature = params.get("signature");
|
||||
|
||||
// 4. Base64解密(仅用于日志输出,不影响校验逻辑)
|
||||
String decryptedSign = "";
|
||||
try {
|
||||
byte[] signBytes = Base64.getDecoder().decode(signature);
|
||||
decryptedSign = new String(signBytes, "UTF-8");
|
||||
// 2. 必选参数非空校验
|
||||
if (projectName == null || projectName.isEmpty()
|
||||
|| apkFileName == null || apkFileName.isEmpty()
|
||||
|| signature == null || signature.isEmpty()) {
|
||||
LogUtils.w(TAG, "签名校验失败:必选参数不全(projectName/apkFileName/signature不能为空)");
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||
"参数错误:projectName、apkFileName、signature为必填参数");
|
||||
}
|
||||
|
||||
// 3. 核心校验:调用APKFileUtils完成APK签名精准匹配
|
||||
boolean isValid = APKFileUtils.checkAPKSignature(projectName, apkFileName, signature);
|
||||
|
||||
// 4. 日志输出详情(便于问题排查)
|
||||
LogUtils.d(TAG, String.format("签名校验结果:%s | 项目名:%s | APK文件名:%s | 客户端签名:%s",
|
||||
isValid ? "✅ 成功" : "❌ 失败", projectName, apkFileName, signature));
|
||||
|
||||
// 5. 构建响应结果(与APP端预期格式一致,字段简洁无冗余)
|
||||
String msg = isValid ? "应用签名校验通过,为合法应用" : "应用签名校验失败:APK签名与客户端传入签名不匹配";
|
||||
int code = isValid ? 200 : 403;
|
||||
|
||||
String responseJson = String.format(
|
||||
"{\"code\":%d,\"msg\":\"%s\",\"data\":{\"valid\":%b,\"projectName\":\"%s\",\"apkFileName\":\"%s\",\"signature\":\"%s\"}}",
|
||||
code, msg, isValid, projectName, apkFileName, signature
|
||||
);
|
||||
return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.OK, CONTENT_TYPE_JSON, responseJson);
|
||||
} catch (IllegalStateException e) {
|
||||
// 捕获APKFileUtils未初始化异常(最常见原因)
|
||||
LogUtils.e(TAG, "签名校验失败:APKFileUtils未初始化,请在服务启动时调用APKFileUtils.init()", e);
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.INTERNAL_ERROR, "服务内部异常:APKFileUtils未初始化");
|
||||
} catch (Exception e) {
|
||||
decryptedSign = "解密失败";
|
||||
// 捕获所有其他异常,打印完整堆栈(定位根因)
|
||||
LogUtils.e(TAG, "签名校验失败:服务内部异常", e);
|
||||
return buildErrorResponse(NanoHTTPD.Response.Status.INTERNAL_ERROR, "服务内部异常:" + e.getMessage());
|
||||
}
|
||||
|
||||
// 5. 构建响应结果
|
||||
String msg;
|
||||
if (isValid) {
|
||||
msg = "应用签名校验通过,为合法应用";
|
||||
LogUtils.d(TAG, "签名校验通过:" + msg + ",解密后签名:" + decryptedSign + ",时间戳:" + validTime);
|
||||
} else {
|
||||
msg = "应用签名校验失败(签名不匹配或时间不满足生效要求)";
|
||||
LogUtils.w(TAG, "签名校验失败:" + msg + ",解密后签名:" + decryptedSign + ",时间戳:" + validTime);
|
||||
}
|
||||
|
||||
// 6. 返回JSON响应(与APP端预期格式一致,字段完整)
|
||||
String responseJson = String.format(
|
||||
"{\"code\":%d,\"msg\":\"%s\",\"data\":{\"valid\":%b,\"signature\":\"%s\",\"decryptedSign\":\"%s\",\"validTime\":%d}}",
|
||||
isValid ? 200 : 403,
|
||||
msg,
|
||||
isValid,
|
||||
signature,
|
||||
decryptedSign,
|
||||
validTime
|
||||
);
|
||||
return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.OK, CONTENT_TYPE_JSON, responseJson);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user