Compare commits

...

5 Commits

Author SHA1 Message Date
Shamicen
f847390354 make black hole host constant 2024-03-30 12:42:03 +01:00
Shamicen
64503fcec9 make black hole port constant 2024-03-30 12:37:35 +01:00
Shamicen
d6b58e9267 change black hole port 2024-03-30 11:53:34 +01:00
Shamicen
9ffb16ed9f handle null credentials 2024-03-30 11:42:00 +01:00
Shamicen
8f63e82b71 implement socks authentication 2024-03-30 11:23:15 +01:00
4 changed files with 92 additions and 53 deletions

View File

@@ -313,6 +313,7 @@ object SettingsAdvancedScreen : SearchableSettings {
),
Preference.PreferenceItem.TextPreference(
title = stringResource(MR.strings.pref_proxy_configuration),
subtitle = stringResource(MR.strings.pref_proxy_configuration_subtitle),
onClick = { showProxyDialog = true },
),
Preference.PreferenceItem.EditTextPreference(
@@ -591,57 +592,53 @@ private fun ProxyConfigDialog(
isError = !port.text.isDigitsOnly(),
)
}
if (proxyTypes[checked] != ProxyType.SOCKS) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = username,
onValueChange = {
newProxy.username = it.text
proxyChanged = newProxy != proxy
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = username,
onValueChange = {
newProxy.username = it.text
proxyChanged = newProxy != proxy
username = it
},
label = { Text(text = stringResource(MR.strings.username)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
singleLine = true,
enabled = proxyTypes[checked] != ProxyType.SOCKS,
)
var hidePassword by remember { mutableStateOf(true) }
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = password,
onValueChange = {
newProxy.password = it.text
proxyChanged = newProxy != proxy
username = it
},
label = { Text(text = stringResource(MR.strings.username)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
singleLine = true,
)
var hidePassword by remember { mutableStateOf(true) }
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = password,
onValueChange = {
newProxy.password = it.text
proxyChanged = newProxy != proxy
password = it
},
label = { Text(text = stringResource(MR.strings.password)) },
trailingIcon = {
IconButton(onClick = { hidePassword = !hidePassword }) {
Icon(
imageVector = if (hidePassword) {
Icons.Filled.Visibility
} else {
Icons.Filled.VisibilityOff
},
contentDescription = null,
)
}
},
visualTransformation = if (hidePassword) {
PasswordVisualTransformation()
} else {
VisualTransformation.None
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done,
),
singleLine = true,
enabled = proxyTypes[checked] != ProxyType.SOCKS,
)
}
password = it
},
label = { Text(text = stringResource(MR.strings.password)) },
trailingIcon = {
IconButton(onClick = { hidePassword = !hidePassword }) {
Icon(
imageVector = if (hidePassword) {
Icons.Filled.Visibility
} else {
Icons.Filled.VisibilityOff
},
contentDescription = null,
)
}
},
visualTransformation = if (hidePassword) {
PasswordVisualTransformation()
} else {
VisualTransformation.None
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done,
),
singleLine = true,
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,

View File

@@ -12,6 +12,7 @@ import okhttp3.brotli.BrotliInterceptor
import okhttp3.logging.HttpLoggingInterceptor
import java.io.File
import java.util.concurrent.TimeUnit
import java.net.Proxy.Type as ProxyType
class NetworkHelper(
private val context: Context,
@@ -71,8 +72,18 @@ class NetworkHelper(
if (proxy.enabled) {
builder.proxy(proxy.getProxy() ?: Proxy.getBlackHoleProxy(context))
proxy.getAuthenticator()?.let { proxyAuthenticator ->
builder.proxyAuthenticator(proxyAuthenticator)
when (proxy.proxyType) {
ProxyType.HTTP -> {
proxy.getOkhttpAuthenticator()?.let { proxyAuthenticator ->
builder.proxyAuthenticator(proxyAuthenticator)
}
}
ProxyType.SOCKS -> {
proxy.setSocksAuthentication()
}
else -> Unit
}
}
}

View File

@@ -12,8 +12,10 @@ import tachiyomi.i18n.MR
import java.net.Inet6Address
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.PasswordAuthentication
import java.net.Proxy.Type
import java.net.UnknownHostException
import java.net.Authenticator as JavaAuthenticator
import java.net.Proxy as JavaProxy
@Serializable
@@ -33,7 +35,7 @@ data class Proxy(
}
}
fun getAuthenticator(): Authenticator? {
fun getOkhttpAuthenticator(): Authenticator? {
if (username?.isBlank() == true && password?.isBlank() == true) return null
return Authenticator { _, response ->
val credential: String = Credentials.basic(username ?: "", password ?: "")
@@ -43,7 +45,35 @@ data class Proxy(
}
}
fun setSocksAuthentication() {
if (username?.isBlank() == true && password?.isBlank() == true) return
System.setProperty("java.net.socks.username", username ?: "")
System.setProperty("java.net.socks.password", password ?: "")
JavaAuthenticator.setDefault(
object : JavaAuthenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication? {
return if (
requestingHost.equals(host, ignoreCase = true) &&
requestingPort == port
) {
PasswordAuthentication(
username ?: "",
password?.toCharArray() ?: "".toCharArray(),
)
} else {
null
}
}
},
)
}
companion object {
private const val BLACK_HOLE_HOST = "100::"
private const val BLACK_HOLE_PORT = 65534
suspend fun testHostValidity(host: String): Boolean = withIOContext {
return@withIOContext try {
InetAddress.getByName(host)
@@ -59,7 +89,7 @@ data class Proxy(
*/
fun getBlackHoleProxy(context: Context): JavaProxy {
context.toast(MR.strings.proxy_host_invalid_warning)
return JavaProxy(Type.SOCKS, InetSocketAddress(Inet6Address.getByName("100::"), 1))
return JavaProxy(Type.SOCKS, InetSocketAddress(Inet6Address.getByName(BLACK_HOLE_HOST), BLACK_HOLE_PORT))
}
}
}

View File

@@ -584,6 +584,7 @@
<string name="pref_verbose_logging_summary">Print verbose logs to system log (reduces app performance)</string>
<string name="pref_debug_info">Debug info</string>
<string name="pref_proxy_configuration">Proxy configuration</string>
<string name="pref_proxy_configuration_subtitle">Webview will not use this proxy</string>
<string name="pref_enable_proxy">Enable Proxy</string>
<string name="port">Port</string>
<string name="host">Host</string>