diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/connection/ConnectionRequestActivity.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/connection/ConnectionRequestActivity.java index 489c4cf..b906f87 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/connection/ConnectionRequestActivity.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/connection/ConnectionRequestActivity.java @@ -24,6 +24,9 @@ public class ConnectionRequestActivity extends AppCompatActivity { /** 启动本 Activity 时携带的发起方(控制端)设备 ID。 */ public static final String EXTRA_CONTROLLER_ID = "controller_id"; + /** 启动本 Activity 时携带的鉴权类型(NONE=免密连接 / CODE / PASSWORD)。 */ + public static final String EXTRA_AUTH_TYPE = "auth_type"; + /** 无响应自动拒绝的超时时间(毫秒)。 */ private static final long AUTO_REJECT_TIMEOUT = 60_000L; @@ -38,6 +41,8 @@ public class ConnectionRequestActivity extends AppCompatActivity { String controllerId = getIntent() != null ? getIntent().getStringExtra(EXTRA_CONTROLLER_ID) : null; + String authType = getIntent() != null + ? getIntent().getStringExtra(EXTRA_AUTH_TYPE) : null; // 服务实例不存在或缺少必要参数时,直接结束,不做任何连接处理。 if (ScreenCaptureService.getInstance() == null || controllerId == null) { @@ -48,7 +53,13 @@ public class ConnectionRequestActivity extends AppCompatActivity { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.connection_request_title); - builder.setMessage(getString(R.string.connection_request_message, controllerId)); + + // 免密连接时在提示中标注,便于用户知晓无需验证码/密码 + String message = getString(R.string.connection_request_message, controllerId); + if ("NONE".equalsIgnoreCase(authType)) { + message += "\n\n" + getString(R.string.connection_request_mode_none); + } + builder.setMessage(message); builder.setCancelable(false); builder.setPositiveButton(R.string.connection_accept, (d, which) -> onAccept()); diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java index d242bee..e128467 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java @@ -114,6 +114,13 @@ public class MainActivity extends BaseMvvmActivity { + AuthSettings.setNoAuthAllowed(this, isChecked); + binding.tvAuthHint.setText(isChecked ? R.string.allow_no_auth_on : R.string.allow_no_auth_off); + }); + updateUI(false); } diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java index c865f02..34352cd 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java @@ -591,28 +591,40 @@ public class ScreenCaptureService extends Service { ? controllerName : controllerId; pendingOfferSdp = offerSdp; - // 鉴权:动态验证码(CODE) / 固定密码(PASSWORD)。 + // 鉴权模式:免密(NONE) / 动态验证码(CODE) / 固定密码(PASSWORD)。 // 服务器仅做转发,真实校验在此完成(密钥不离开被控端)。 - String authType = message.getAuthType(); - String authValue = message.getAuthValue(); - if (authType != null && !authType.trim().isEmpty()) { - String failReason = verifyAuth(authType.trim(), authValue); - if (failReason == null) { - // 校验通过:自动接受,直接建立连接(无需手动确认) - Log.i(TAG, "Auth passed (" + authType + "), auto-accepting " + controllerId); - mainHandler.post(this::acceptConnection); - } else { - Log.w(TAG, "Auth failed (" + authType + "): " + failReason + " from " + controllerId); - sendAuthRejected(failReason); + String rawAuthType = message.getAuthType(); + String authType = (rawAuthType == null || rawAuthType.trim().isEmpty()) + ? "NONE" : rawAuthType.trim(); + boolean isNoAuth = "NONE".equalsIgnoreCase(authType); + if (isNoAuth) { + // 免密连接:若被控端已关闭免密,则直接拒绝,要求使用验证码/密码 + if (!AuthSettings.isNoAuthAllowed(this)) { + Log.w(TAG, "Reject 免密连接 from " + controllerId + ": 被控端已关闭免密连接"); + sendAuthRejected("被控端已关闭免密连接,请使用动态验证码或固定密码"); + return; } + // 免密连接:弹出手动确认弹窗,由用户决定是否接受 + Log.i(TAG, "免密连接,转交用户手动确认: " + controllerId); + Intent dialogIntent = new Intent(this, ConnectionRequestActivity.class); + dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + dialogIntent.putExtra(ConnectionRequestActivity.EXTRA_CONTROLLER_ID, controllerId); + dialogIntent.putExtra(ConnectionRequestActivity.EXTRA_AUTH_TYPE, "NONE"); + startActivity(dialogIntent); return; } - // 未携带鉴权信息:沿用原有手动确认弹窗 - Intent dialogIntent = new Intent(this, ConnectionRequestActivity.class); - dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - dialogIntent.putExtra(ConnectionRequestActivity.EXTRA_CONTROLLER_ID, controllerId); - startActivity(dialogIntent); + // 携带鉴权信息:被控端本地校验,通过则自动接受 + String authValue = message.getAuthValue(); + String failReason = verifyAuth(authType, authValue); + if (failReason == null) { + // 校验通过:自动接受,直接建立连接(无需手动确认) + Log.i(TAG, "Auth passed (" + authType + "), auto-accepting " + controllerId); + mainHandler.post(this::acceptConnection); + } else { + Log.w(TAG, "Auth failed (" + authType + "): " + failReason + " from " + controllerId); + sendAuthRejected(failReason); + } } /** diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/utils/AuthSettings.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/utils/AuthSettings.java index 9ef75dd..f97021b 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/utils/AuthSettings.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/utils/AuthSettings.java @@ -14,6 +14,8 @@ public class AuthSettings { private static final String PREF_NAME = "controlled_auth_prefs"; private static final String KEY_DYNAMIC_CODE = "dynamic_code"; private static final String KEY_FIXED_PASSWORD = "fixed_password"; + /** 是否允许“免密连接”(被控端手动确认)。默认开启。 */ + private static final String KEY_ALLOW_NO_AUTH = "allow_no_auth"; private static final String CODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -57,4 +59,16 @@ public class AuthSettings { context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .edit().putString(KEY_FIXED_PASSWORD, password == null ? "" : password).apply(); } + + /** 是否允许免密连接(被控端手动确认)。默认开启。 */ + public static boolean isNoAuthAllowed(Context context) { + return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .getBoolean(KEY_ALLOW_NO_AUTH, true); + } + + /** 设置是否允许免密连接。 */ + public static void setNoAuthAllowed(Context context, boolean allowed) { + context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .edit().putBoolean(KEY_ALLOW_NO_AUTH, allowed).apply(); + } } diff --git a/WebRTCControlled/app/src/main/res/layout/activity_main.xml b/WebRTCControlled/app/src/main/res/layout/activity_main.xml index 9eee8e1..833cdd7 100644 --- a/WebRTCControlled/app/src/main/res/layout/activity_main.xml +++ b/WebRTCControlled/app/src/main/res/layout/activity_main.xml @@ -140,6 +140,39 @@ android:textSize="13sp" android:textColor="#888888" /> + + + + + + + + + + + +