diff --git a/README.md b/README.md index 56e8fcaf..adcf90b9 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 30) `Landroid/net/TetheringManager$TetheringEventCallback;->onTetherableInterfaceRegexpsChanged(Landroid/net/TetheringManager$TetheringInterfaceRegexps;)V,blocked` * (since API 30) `Landroid/net/TetheringManager;->TETHERING_WIGIG:I,blocked` * (since API 31) `Landroid/net/wifi/SoftApInfo;->getApInstanceIdentifier()Ljava/lang/String;,blocked` +* (since API 31) `Landroid/net/wifi/WifiClient;->getApInstanceIdentifier()Ljava/lang/String;,blocked` * (prior to API 30) `Landroid/net/wifi/WifiConfiguration$KeyMgmt;->FT_PSK:I,lo-prio,max-target-o` * (prior to API 30) `Landroid/net/wifi/WifiConfiguration$KeyMgmt;->WPA_PSK_SHA256:I,blocked` * (since API 23, prior to API 30) `Landroid/net/wifi/WifiConfiguration;->AP_BAND_2GHZ:I,lo-prio,max-target-o` diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt index 4170bcd9..f9d52876 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt @@ -6,7 +6,6 @@ import android.content.ClipData import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import android.net.MacAddress import android.os.Build import android.os.Parcelable import android.provider.Settings @@ -27,10 +26,7 @@ import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding import be.mygod.vpnhotspot.net.TetherType import be.mygod.vpnhotspot.net.TetheringManager -import be.mygod.vpnhotspot.net.wifi.SoftApCapability -import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat -import be.mygod.vpnhotspot.net.wifi.SoftApInfo -import be.mygod.vpnhotspot.net.wifi.WifiApManager +import be.mygod.vpnhotspot.net.wifi.* import be.mygod.vpnhotspot.root.WifiApCommands import be.mygod.vpnhotspot.util.format import be.mygod.vpnhotspot.util.joinToSpanned @@ -182,12 +178,18 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(), this.capability = capability data.notifyChange() } - override fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) { + @RequiresApi(30) + override fun onBlockedClientConnecting(client: Parcelable, blockedReason: Int) { + @Suppress("NAME_SHADOWING") + val client = WifiClient(client) + val macAddress = client.macAddress + var name = macAddress.toString() + if (BuildCompat.isAtLeastS()) client.apInstanceIdentifier?.let { name += "%$it" } val reason = WifiApManager.clientBlockLookup(blockedReason, true) - Timber.i("$client blocked from connecting: $reason ($blockedReason)") - SmartSnackbar.make(parent.getString(R.string.tethering_manage_wifi_client_blocked, client, reason)).apply { + Timber.i("$name blocked from connecting: $reason ($blockedReason)") + SmartSnackbar.make(parent.getString(R.string.tethering_manage_wifi_client_blocked, name, reason)).apply { action(R.string.tethering_manage_wifi_copy_mac) { - app.clipboard.setPrimaryClip(ClipData.newPlainText(null, client.toString())) + app.clipboard.setPrimaryClip(ClipData.newPlainText(null, macAddress.toString())) } }.show() } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt index 1b6e0d73..ccec77cf 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt @@ -20,28 +20,26 @@ value class SoftApInfo(val inner: Parcelable) { @get:RequiresApi(31) private val getWifiStandard by lazy { clazz.getDeclaredMethod("getWifiStandard") } @get:RequiresApi(31) - private val getApInstanceIdentifier by lazy @TargetApi(31) { - UnblockCentral.SoftApInfo_getApInstanceIdentifier(clazz) - } + private val getApInstanceIdentifier by lazy @TargetApi(31) { UnblockCentral.getApInstanceIdentifier(clazz) } @get:RequiresApi(31) private val getAutoShutdownTimeoutMillis by lazy { clazz.getDeclaredMethod("getAutoShutdownTimeoutMillis") } val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { clazz } } - val frequency get() = getFrequency.invoke(inner) as Int - val bandwidth get() = getBandwidth.invoke(inner) as Int + val frequency get() = getFrequency(inner) as Int + val bandwidth get() = getBandwidth(inner) as Int @get:RequiresApi(31) - val bssid get() = getBssid.invoke(inner) as MacAddress + val bssid get() = getBssid(inner) as MacAddress @get:RequiresApi(31) - val wifiStandard get() = getWifiStandard.invoke(inner) as Int + val wifiStandard get() = getWifiStandard(inner) as Int @get:RequiresApi(31) val apInstanceIdentifier get() = try { - getApInstanceIdentifier.invoke(inner) as? String + getApInstanceIdentifier(inner) as? String } catch (e: ReflectiveOperationException) { Timber.w(e) null } @get:RequiresApi(31) - val autoShutdownTimeoutMillis get() = getAutoShutdownTimeoutMillis.invoke(inner) as Long + val autoShutdownTimeoutMillis get() = getAutoShutdownTimeoutMillis(inner) as Long } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt index 7d9354cf..16e11e06 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt @@ -81,7 +81,7 @@ object WifiApManager { fun onNumClientsChanged(numClients: Int) { } @RequiresApi(30) - fun onConnectedClientsChanged(clients: List) { + fun onConnectedClientsChanged(clients: List) { @Suppress("DEPRECATION") onNumClientsChanged(clients.size) } @@ -93,7 +93,7 @@ object WifiApManager { fun onCapabilityChanged(capability: Parcelable) { } @RequiresApi(30) - fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) { } + fun onBlockedClientConnecting(client: Parcelable, blockedReason: Int) { } } @RequiresApi(28) val failureReasonLookup = ConstantLookup("SAP_START_FAILURE_", @@ -112,10 +112,6 @@ object WifiApManager { WifiManager::class.java.getDeclaredMethod("unregisterSoftApCallback", interfaceSoftApCallback) } - private val getMacAddress by lazy { - Class.forName("android.net.wifi.WifiClient").getDeclaredMethod("getMacAddress") - } - @RequiresApi(28) fun registerSoftApCallback(callback: SoftApCallbackCompat, executor: Executor): Any { val proxy = Proxy.newProxyInstance(interfaceSoftApCallback.classLoader, @@ -140,18 +136,19 @@ object WifiApManager { } "onConnectedClientsChanged" -> @TargetApi(30) { if (Build.VERSION.SDK_INT < 30) Timber.w(Exception("Unexpected onConnectedClientsChanged")) + @Suppress("UNCHECKED_CAST") callback.onConnectedClientsChanged(when (noArgs) { - 1 -> args!![0] as? Iterable<*> ?: return null + 1 -> args!![0] as List 2 -> { Timber.w(Exception("Unexpected onConnectedClientsChanged API 31+")) // dispatchInfoChanged(args!![0]) - args!![1] as? Iterable<*> ?: return null + args!![1] as List } else -> { Timber.w("Unexpected args for $name: ${args?.contentToString()}") return null } - }.map { getMacAddress(it) as MacAddress }) + }) } "onInfoChanged" -> @TargetApi(30) { if (noArgs != 1) Timber.w("Unexpected args for $name: ${args?.contentToString()}") @@ -179,7 +176,7 @@ object WifiApManager { "onBlockedClientConnecting" -> @TargetApi(30) { if (Build.VERSION.SDK_INT < 30) Timber.w(Exception("Unexpected onBlockedClientConnecting")) if (noArgs != 2) Timber.w("Unexpected args for $name: ${args?.contentToString()}") - callback.onBlockedClientConnecting(getMacAddress(args!![0]) as MacAddress, args[1] as Int) + callback.onBlockedClientConnecting(args!![0] as Parcelable, args[1] as Int) } else -> callSuper(interfaceSoftApCallback, proxy, method, args) } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiClient.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiClient.kt new file mode 100644 index 00000000..57edc1a3 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiClient.kt @@ -0,0 +1,28 @@ +package be.mygod.vpnhotspot.net.wifi + +import android.annotation.TargetApi +import android.net.MacAddress +import android.os.Parcelable +import androidx.annotation.RequiresApi +import be.mygod.vpnhotspot.util.UnblockCentral +import timber.log.Timber + +@JvmInline +@RequiresApi(30) +value class WifiClient(val inner: Parcelable) { + companion object { + private val clazz by lazy { Class.forName("android.net.wifi.WifiClient") } + private val getMacAddress by lazy { clazz.getDeclaredMethod("getMacAddress") } + @get:RequiresApi(31) + private val getApInstanceIdentifier by lazy @TargetApi(31) { UnblockCentral.getApInstanceIdentifier(clazz) } + } + + val macAddress get() = getMacAddress(inner) as MacAddress + @get:RequiresApi(31) + val apInstanceIdentifier get() = try { + getApInstanceIdentifier(inner) as? String + } catch (e: ReflectiveOperationException) { + Timber.w(e) + null + } +} diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt b/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt index b3d72dfc..23c6bbd1 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt @@ -32,7 +32,7 @@ object WifiApCommands { } @Parcelize @RequiresApi(30) - data class OnConnectedClientsChanged(val clients: List) : SoftApCallbackParcel() { + data class OnConnectedClientsChanged(val clients: List) : SoftApCallbackParcel() { override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) = callback.onConnectedClientsChanged(clients) } @@ -49,7 +49,7 @@ object WifiApCommands { } @Parcelize @RequiresApi(30) - data class OnBlockedClientConnecting(val client: MacAddress, val blockedReason: Int) : SoftApCallbackParcel() { + data class OnBlockedClientConnecting(val client: Parcelable, val blockedReason: Int) : SoftApCallbackParcel() { override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) = callback.onBlockedClientConnecting(client, blockedReason) } @@ -73,7 +73,7 @@ object WifiApCommands { override fun onNumClientsChanged(numClients: Int) = push(SoftApCallbackParcel.OnNumClientsChanged(numClients)) @RequiresApi(30) - override fun onConnectedClientsChanged(clients: List) = + override fun onConnectedClientsChanged(clients: List) = push(SoftApCallbackParcel.OnConnectedClientsChanged(clients)) @RequiresApi(30) override fun onInfoChanged(info: List) = push(SoftApCallbackParcel.OnInfoChanged(info)) @@ -81,7 +81,7 @@ object WifiApCommands { override fun onCapabilityChanged(capability: Parcelable) = push(SoftApCallbackParcel.OnCapabilityChanged(capability)) @RequiresApi(30) - override fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) = + override fun onBlockedClientConnecting(client: Parcelable, blockedReason: Int) = push(SoftApCallbackParcel.OnBlockedClientConnecting(client, blockedReason)) }) { scope.launch { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt b/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt index 2eceab4e..a61d802d 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt @@ -26,7 +26,5 @@ object UnblockCentral { } @RequiresApi(31) - fun SoftApInfo_getApInstanceIdentifier(clazz: Class<*>) = init.let { - clazz.getDeclaredMethod("getApInstanceIdentifier") - } + fun getApInstanceIdentifier(clazz: Class<*>) = init.let { clazz.getDeclaredMethod("getApInstanceIdentifier") } }