diff --git a/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt b/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt index 366ed564..62b3150e 100644 --- a/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt +++ b/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt @@ -172,6 +172,8 @@ class FileManager(private val application: Application, private val prefs: Prefe val preferencesMap: MutableMap = mutableMapOf() preferencesMap[Preferences.SOCKS_ADDR] = prefs.socksAddress preferencesMap[Preferences.SOCKS_PORT] = prefs.socksPort + preferencesMap[Preferences.SOCKS_USER] = prefs.socksUsername + preferencesMap[Preferences.SOCKS_PASS] = prefs.socksPassword preferencesMap[Preferences.DNS_IPV4] = prefs.dnsIpv4 preferencesMap[Preferences.DNS_IPV6] = prefs.dnsIpv6 preferencesMap[Preferences.IPV6] = prefs.ipv6 @@ -309,6 +311,16 @@ class FileManager(private val application: Application, private val prefs: Prefe } } + value = preferencesMap[Preferences.SOCKS_USER] + if (value is String) { + prefs.socksUsername = (value as String?)!! + } + + value = preferencesMap[Preferences.SOCKS_PASS] + if (value is String) { + prefs.socksPassword = (value as String?)!! + } + value = preferencesMap[Preferences.DNS_IPV4] if (value is String) { prefs.dnsIpv4 = (value as String?)!! diff --git a/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt b/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt index 075c1f09..87f83300 100644 --- a/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt +++ b/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt @@ -112,11 +112,17 @@ class Preferences(context: Context) { setValueInProvider(SOCKS_PORT, port.toString()) } - val socksUsername: String + var socksUsername: String get() = getPrefData(SOCKS_USER).first ?: "" + set(user) { + setValueInProvider(SOCKS_USER, user) + } - val socksPassword: String + var socksPassword: String get() = getPrefData(SOCKS_PASS).first ?: "" + set(pass) { + setValueInProvider(SOCKS_PASS, pass) + } var dnsIpv4: String get() = getPrefData(DNS_IPV4).first ?: "8.8.8.8" diff --git a/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt b/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt index 8c08d043..8437fdbe 100644 --- a/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt +++ b/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt @@ -383,6 +383,32 @@ fun SettingsScreen( scope = scope ) + EditableListItemWithBottomSheet( + headline = stringResource(R.string.socks_user), + currentValue = settingsState.socksUser.value, + onValueConfirmed = { newValue -> mainViewModel.updateSocksUser(newValue) }, + label = stringResource(R.string.socks_user), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), + isError = !settingsState.socksUser.isValid, + errorMessage = settingsState.socksUser.error, + enabled = !vpnDisabled, + sheetState = sheetState, + scope = scope + ) + + EditableListItemWithBottomSheet( + headline = stringResource(R.string.socks_pass), + currentValue = settingsState.socksPass.value, + onValueConfirmed = { newValue -> mainViewModel.updateSocksPass(newValue) }, + label = stringResource(R.string.socks_pass), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + isError = !settingsState.socksPass.isValid, + errorMessage = settingsState.socksPass.error, + enabled = !vpnDisabled, + sheetState = sheetState, + scope = scope + ) + EditableListItemWithBottomSheet( headline = stringResource(R.string.dns_ipv4), currentValue = settingsState.dnsIpv4.value, diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 820446ea..de1280ec 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -84,6 +84,8 @@ class MainViewModel(application: Application) : private val _settingsState = MutableStateFlow( SettingsState( socksPort = InputFieldState(prefs.socksPort.toString()), + socksUser = InputFieldState(prefs.socksUsername), + socksPass = InputFieldState(prefs.socksPassword), dnsIpv4 = InputFieldState(prefs.dnsIpv4), dnsIpv6 = InputFieldState(prefs.dnsIpv6), switches = SwitchStates( @@ -165,6 +167,9 @@ class MainViewModel(application: Application) : init { Log.d(TAG, "MainViewModel initialized.") + + setupGlobalSocksAuthenticator() + viewModelScope.launch(Dispatchers.IO) { _isServiceEnabled.value = isServiceRunning(application, TProxyService::class.java) @@ -177,6 +182,8 @@ class MainViewModel(application: Application) : private fun updateSettingsState() { _settingsState.value = _settingsState.value.copy( socksPort = InputFieldState(prefs.socksPort.toString()), + socksUser = InputFieldState(prefs.socksUsername), + socksPass = InputFieldState(prefs.socksPassword), dnsIpv4 = InputFieldState(prefs.dnsIpv4), dnsIpv6 = InputFieldState(prefs.dnsIpv6), switches = SwitchStates( @@ -226,6 +233,21 @@ class MainViewModel(application: Application) : } } + private fun setupGlobalSocksAuthenticator() { + java.net.Authenticator.setDefault(object : java.net.Authenticator() { + override fun getPasswordAuthentication(): java.net.PasswordAuthentication? { + val user = prefs.socksUsername + val pass = prefs.socksPassword + + return if (user.isNotEmpty() || pass.isNotEmpty()) { + java.net.PasswordAuthentication(user, pass.toCharArray()) + } else { + null + } + } + }) + } + fun setControlMenuClickable(isClickable: Boolean) { _controlMenuClickable.value = isClickable } @@ -409,6 +431,46 @@ class MainViewModel(application: Application) : } } + fun updateSocksUser(userString: String): Boolean { + val byteCount = userString.toByteArray(Charsets.UTF_8).size + return if (byteCount <= 255) { + prefs.socksUsername = userString + _settingsState.value = _settingsState.value.copy( + socksUser = InputFieldState(userString) + ) + true + } else { + _settingsState.value = _settingsState.value.copy( + socksUser = InputFieldState( + value = userString, + error = "Username length must not exceed 255 bytes", + isValid = false + ) + ) + false + } + } + + fun updateSocksPass(passString: String): Boolean { + val byteCount = passString.toByteArray(Charsets.UTF_8).size + return if (byteCount <= 255) { + prefs.socksPassword = passString + _settingsState.value = _settingsState.value.copy( + socksPass = InputFieldState(passString) + ) + true + } else { + _settingsState.value = _settingsState.value.copy( + socksPass = InputFieldState( + value = passString, + error = "Password length must not exceed 255 bytes", + isValid = false + ) + ) + false + } + } + fun updateDnsIpv4(ipv4Addr: String): Boolean { val matcher = IPV4_PATTERN.matcher(ipv4Addr) return if (matcher.matches()) { diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt index b13724ea..34f59587 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt @@ -33,6 +33,8 @@ data class FileStates( data class SettingsState( val socksPort: InputFieldState, + val socksUser: InputFieldState, + val socksPass: InputFieldState, val dnsIpv4: InputFieldState, val dnsIpv6: InputFieldState, val switches: SwitchStates, diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 9ae459cc..019e2a67 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -1,6 +1,7 @@ Port SOCKS Target + Kata Sandi SOCKS DNS IPv4 DNS IPv6 IPv6 @@ -119,4 +120,5 @@ Terang Gelap Otomatis + "Pengguna SOCKS " diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index e494f3fe..64532f46 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -1,6 +1,7 @@ Целевой порт SOCKS + Пароль SOCKS DNS IPv4 DNS IPv6 IPv6 @@ -119,4 +120,5 @@ Светлая Тёмная Автоматически + Пользователь SOCKS diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 191832c1..ff78e747 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1,6 +1,7 @@ 目标Socks端口 + "SOCKS 密码 " DNS IPv4 DNS IPv6 IPv6 @@ -119,4 +120,5 @@ 浅色 深色 自动 + SOCKS 用户 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ce1b012..2e459a48 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,6 +6,8 @@ https://github.com/lhear/v2ray-rules-dat/releases/latest/download/geosite.dat http://www.gstatic.com/generate_204 Target SOCKS Port + SOCKS User + SOCKS Pass DNS IPv4 DNS IPv6 IPv6