|
|
@@ -0,0 +1,379 @@
|
|
|
+package com.systemvalidation;
|
|
|
+
|
|
|
+import android.util.Log;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.io.OutputStream;
|
|
|
+import java.io.PrintWriter;
|
|
|
+import java.net.Socket;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.MessageDigest;
|
|
|
+import java.security.NoSuchAlgorithmException;
|
|
|
+import org.json.JSONObject;
|
|
|
+import org.json.JSONException;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 客户端连接处理器
|
|
|
+ * 处理来自电脑的ADB连接请求
|
|
|
+ */
|
|
|
+class ClientHandler implements Runnable {
|
|
|
+ private static final String TAG = "ClientHandler";
|
|
|
+ private static final int SESSION_TIMEOUT = 300000; // 5分钟
|
|
|
+
|
|
|
+ private final Socket clientSocket;
|
|
|
+ private final SystemValidationService service;
|
|
|
+ private String currentDeviceCode = null;
|
|
|
+ private long lastActivityTime;
|
|
|
+
|
|
|
+ public ClientHandler(Socket socket, SystemValidationService service) {
|
|
|
+ this.clientSocket = socket;
|
|
|
+ this.service = service;
|
|
|
+ this.lastActivityTime = System.currentTimeMillis();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ Log.i(TAG, "开始处理客户端连接");
|
|
|
+
|
|
|
+ try (
|
|
|
+ BufferedReader reader = new BufferedReader(
|
|
|
+ new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8)
|
|
|
+ );
|
|
|
+ PrintWriter writer = new PrintWriter(
|
|
|
+ clientSocket.getOutputStream(), true
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ // 设置超时
|
|
|
+ clientSocket.setSoTimeout(30000);
|
|
|
+
|
|
|
+ String requestLine;
|
|
|
+ while ((requestLine = reader.readLine()) != null) {
|
|
|
+ lastActivityTime = System.currentTimeMillis();
|
|
|
+
|
|
|
+ if (requestLine.trim().isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Log.d(TAG, "收到请求: " + requestLine);
|
|
|
+
|
|
|
+ try {
|
|
|
+ JSONObject request = new JSONObject(requestLine);
|
|
|
+ String response = processRequest(request);
|
|
|
+ writer.println(response);
|
|
|
+ writer.flush();
|
|
|
+
|
|
|
+ Log.d(TAG, "发送响应: " + response);
|
|
|
+ } catch (JSONException e) {
|
|
|
+ Log.w(TAG, "请求JSON格式错误: " + requestLine, e);
|
|
|
+ sendError(writer, "INVALID_JSON", "JSON格式错误");
|
|
|
+ } catch (Exception e) {
|
|
|
+ Log.e(TAG, "处理请求异常", e);
|
|
|
+ sendError(writer, "INTERNAL_ERROR", "内部服务器错误");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查会话是否超时
|
|
|
+ if (currentDeviceCode != null &&
|
|
|
+ System.currentTimeMillis() - lastActivityTime > SESSION_TIMEOUT) {
|
|
|
+ Log.i(TAG, "会话超时,断开连接");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ Log.i(TAG, "客户端连接关闭或异常: " + e.getMessage());
|
|
|
+ } catch (Exception e) {
|
|
|
+ Log.e(TAG, "客户端处理异常", e);
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ clientSocket.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ Log.w(TAG, "关闭客户端Socket失败", e);
|
|
|
+ }
|
|
|
+ Log.i(TAG, "客户端连接处理完成");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理请求
|
|
|
+ */
|
|
|
+ private String processRequest(JSONObject request) throws JSONException {
|
|
|
+ String action = request.optString("action", "");
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+
|
|
|
+ switch (action) {
|
|
|
+ case "handshake":
|
|
|
+ return handleHandshake(request);
|
|
|
+ case "verify":
|
|
|
+ return handleVerify(request);
|
|
|
+ case "security_action":
|
|
|
+ return handleSecurityAction(request);
|
|
|
+ case "get_status":
|
|
|
+ return handleGetStatus(request);
|
|
|
+ case "generate_device_code":
|
|
|
+ return handleGenerateDeviceCode(request);
|
|
|
+ default:
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "UNKNOWN_ACTION");
|
|
|
+ response.put("message", "未知的操作类型: " + action);
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理握手请求
|
|
|
+ */
|
|
|
+ private String handleHandshake(JSONObject request) throws JSONException {
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+
|
|
|
+ String protocolVersion = request.optString("protocol_version", "1.0");
|
|
|
+ String clientType = request.optString("client_type", "unknown");
|
|
|
+
|
|
|
+ Log.i(TAG, "握手请求 - 协议版本: " + protocolVersion + ", 客户端类型: " + clientType);
|
|
|
+
|
|
|
+ response.put("status", "success");
|
|
|
+ response.put("service", "SystemValidationService");
|
|
|
+ response.put("version", "1.0");
|
|
|
+ response.put("protocol_version", protocolVersion);
|
|
|
+ response.put("timestamp", System.currentTimeMillis());
|
|
|
+ response.put("supported_actions", new String[]{
|
|
|
+ "handshake", "verify", "security_action", "get_status", "generate_device_code"
|
|
|
+ });
|
|
|
+
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理设备验证请求
|
|
|
+ */
|
|
|
+ private String handleVerify(JSONObject request) throws JSONException {
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+
|
|
|
+ String deviceCode = request.optString("device_code", "");
|
|
|
+ if (deviceCode.isEmpty()) {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "MISSING_DEVICE_CODE");
|
|
|
+ response.put("message", "缺少设备码参数");
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证设备码
|
|
|
+ boolean isValid = service.verifyDevice(deviceCode);
|
|
|
+
|
|
|
+ if (isValid) {
|
|
|
+ currentDeviceCode = deviceCode;
|
|
|
+ response.put("status", "success");
|
|
|
+ response.put("verified", true);
|
|
|
+ response.put("session_id", generateSessionId(deviceCode));
|
|
|
+ response.put("timestamp", System.currentTimeMillis());
|
|
|
+ response.put("message", "设备验证成功");
|
|
|
+
|
|
|
+ Log.i(TAG, "设备验证成功: " + deviceCode.substring(0, 16) + "...");
|
|
|
+ } else {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "VERIFICATION_FAILED");
|
|
|
+ response.put("verified", false);
|
|
|
+ response.put("message", "设备验证失败");
|
|
|
+
|
|
|
+ Log.w(TAG, "设备验证失败: " + deviceCode.substring(0, 16) + "...");
|
|
|
+ }
|
|
|
+
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理安全操作请求
|
|
|
+ */
|
|
|
+ private String handleSecurityAction(JSONObject request) throws JSONException {
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+
|
|
|
+ // 检查是否已验证
|
|
|
+ if (currentDeviceCode == null) {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "UNAUTHORIZED");
|
|
|
+ response.put("message", "需要先验证设备");
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ int action = request.optInt("action", 0);
|
|
|
+ String confirmation = request.optString("confirmation", "");
|
|
|
+
|
|
|
+ // 对于危险操作需要确认
|
|
|
+ if (action == 2) { // 深度锁机
|
|
|
+ if (!confirmation.equals("CONFIRM_DEEP_LOCK")) {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "CONFIRMATION_REQUIRED");
|
|
|
+ response.put("message", "深度锁机需要确认,发送确认码: CONFIRM_DEEP_LOCK");
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行安全操作
|
|
|
+ boolean result = service.executeSecurityAction(
|
|
|
+ SystemValidationService.SecurityAction.fromValue(action)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ response.put("status", "success");
|
|
|
+ response.put("action", action);
|
|
|
+ response.put("executed", true);
|
|
|
+ response.put("timestamp", System.currentTimeMillis());
|
|
|
+
|
|
|
+ String actionName = getActionName(action);
|
|
|
+ response.put("message", "安全操作执行成功: " + actionName);
|
|
|
+
|
|
|
+ Log.i(TAG, "安全操作执行成功: " + actionName);
|
|
|
+ } else {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "ACTION_FAILED");
|
|
|
+ response.put("executed", false);
|
|
|
+ response.put("message", "安全操作执行失败");
|
|
|
+
|
|
|
+ Log.w(TAG, "安全操作执行失败: " + action);
|
|
|
+ }
|
|
|
+
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理状态获取请求
|
|
|
+ */
|
|
|
+ private String handleGetStatus(JSONObject request) throws JSONException {
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+
|
|
|
+ SystemValidationService.ServiceStatus status = service.getServiceStatus();
|
|
|
+
|
|
|
+ response.put("status", "success");
|
|
|
+ response.put("service_status", new JSONObject(status.toJson()));
|
|
|
+ response.put("client_authenticated", currentDeviceCode != null);
|
|
|
+ response.put("session_active", currentDeviceCode != null);
|
|
|
+ response.put("last_activity", lastActivityTime);
|
|
|
+ response.put("current_time", System.currentTimeMillis());
|
|
|
+
|
|
|
+ if (currentDeviceCode != null) {
|
|
|
+ response.put("device_code_masked", currentDeviceCode.substring(0, 16) + "..." +
|
|
|
+ currentDeviceCode.substring(currentDeviceCode.length() - 8));
|
|
|
+ }
|
|
|
+
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理设备码生成请求
|
|
|
+ */
|
|
|
+ private String handleGenerateDeviceCode(JSONObject request) throws JSONException {
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+
|
|
|
+ String deviceId = request.optString("device_id", "");
|
|
|
+ String salt = request.optString("salt", String.valueOf(System.currentTimeMillis()));
|
|
|
+
|
|
|
+ if (deviceId.isEmpty()) {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "MISSING_DEVICE_ID");
|
|
|
+ response.put("message", "缺少设备ID参数");
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ String deviceCode = generateDeviceCode(deviceId, salt);
|
|
|
+
|
|
|
+ response.put("status", "success");
|
|
|
+ response.put("device_code", deviceCode);
|
|
|
+ response.put("device_id", deviceId);
|
|
|
+ response.put("salt", salt);
|
|
|
+ response.put("timestamp", System.currentTimeMillis());
|
|
|
+ response.put("algorithm", "SHA-256");
|
|
|
+ response.put("message", "设备码生成成功");
|
|
|
+
|
|
|
+ Log.i(TAG, "设备码生成成功: " + deviceCode.substring(0, 16) + "...");
|
|
|
+ } catch (NoSuchAlgorithmException e) {
|
|
|
+ response.put("status", "error");
|
|
|
+ response.put("code", "HASH_ERROR");
|
|
|
+ response.put("message", "设备码生成失败: " + e.getMessage());
|
|
|
+
|
|
|
+ Log.e(TAG, "设备码生成失败", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ return response.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成设备码
|
|
|
+ */
|
|
|
+ private String generateDeviceCode(String deviceId, String salt) throws NoSuchAlgorithmException {
|
|
|
+ String data = deviceId + salt + System.currentTimeMillis();
|
|
|
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
|
|
+ byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
|
|
|
+
|
|
|
+ // 转换为十六进制字符串
|
|
|
+ StringBuilder hexString = new StringBuilder();
|
|
|
+ for (byte b : hash) {
|
|
|
+ String hex = Integer.toHexString(0xff & b);
|
|
|
+ if (hex.length() == 1) {
|
|
|
+ hexString.append('0');
|
|
|
+ }
|
|
|
+ hexString.append(hex);
|
|
|
+ }
|
|
|
+
|
|
|
+ return hexString.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成会话ID
|
|
|
+ */
|
|
|
+ private String generateSessionId(String deviceCode) {
|
|
|
+ try {
|
|
|
+ String data = deviceCode + System.currentTimeMillis() + Thread.currentThread().getId();
|
|
|
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
|
|
+ byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
|
|
|
+
|
|
|
+ // 取前16字节作为会话ID
|
|
|
+ StringBuilder sessionId = new StringBuilder();
|
|
|
+ for (int i = 0; i < 16; i++) {
|
|
|
+ String hex = Integer.toHexString(0xff & hash[i]);
|
|
|
+ if (hex.length() == 1) {
|
|
|
+ sessionId.append('0');
|
|
|
+ }
|
|
|
+ sessionId.append(hex);
|
|
|
+ }
|
|
|
+
|
|
|
+ return sessionId.toString();
|
|
|
+ } catch (NoSuchAlgorithmException e) {
|
|
|
+ // 回退到简单方法
|
|
|
+ return "session_" + System.currentTimeMillis() + "_" +
|
|
|
+ deviceCode.substring(0, 8);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取操作名称
|
|
|
+ */
|
|
|
+ private String getActionName(int action) {
|
|
|
+ switch (action) {
|
|
|
+ case 0: return "GET_STATUS";
|
|
|
+ case 1: return "LOCK_TOUCH";
|
|
|
+ case 2: return "DEEP_LOCK";
|
|
|
+ case 3: return "UNLOCK";
|
|
|
+ default: return "UNKNOWN";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送错误响应
|
|
|
+ */
|
|
|
+ private void sendError(PrintWriter writer, String code, String message) {
|
|
|
+ try {
|
|
|
+ JSONObject error = new JSONObject();
|
|
|
+ error.put("status", "error");
|
|
|
+ error.put("code", code);
|
|
|
+ error.put("message", message);
|
|
|
+ error.put("timestamp", System.currentTimeMillis());
|
|
|
+
|
|
|
+ writer.println(error.toString());
|
|
|
+ writer.flush();
|
|
|
+ } catch (JSONException e) {
|
|
|
+ // 如果JSON构建失败,发送简单错误
|
|
|
+ writer.println("{\"status\":\"error\",\"message\":\"内部错误\"}");
|
|
|
+ writer.flush();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|