mirror of
https://github.com/wgtunnel/android.git
synced 2026-06-02 00:29:08 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9124fcc133 | |||
| fed9537f5c |
@@ -85,7 +85,10 @@ data class TunnelConfig(
|
||||
|
||||
fun tunnelConfFromQuick(amQuick: String, name: String? = null): TunnelConfig {
|
||||
val config = Config.parseQuickString(amQuick)
|
||||
return TunnelConfig(name = name ?: config.defaultName(), quickConfig = amQuick)
|
||||
return TunnelConfig(
|
||||
name = config.name ?: name ?: config.defaultName(),
|
||||
quickConfig = amQuick,
|
||||
)
|
||||
}
|
||||
|
||||
fun generateDefaultGlobalConfig(): TunnelConfig {
|
||||
|
||||
+15
-2
@@ -34,7 +34,6 @@ import io.ktor.client.request.prepareGet
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.time.Instant
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
@@ -335,7 +334,9 @@ class SharedAppViewModel(
|
||||
fun exportSelectedTunnels(uri: Uri?) = intent {
|
||||
val selectedTunnels = tunnelsUiState.value.selectedTunnels
|
||||
val files = createConfFiles(selectedTunnels)
|
||||
val shareFileName = "wgtunnel-export_${Instant.now().epochSecond}.zip"
|
||||
|
||||
val shareFileName = createExportFileName(selectedTunnels.size)
|
||||
|
||||
val onFailure = { action: Throwable ->
|
||||
intent {
|
||||
postSideEffect(
|
||||
@@ -349,6 +350,7 @@ class SharedAppViewModel(
|
||||
}
|
||||
Unit
|
||||
}
|
||||
|
||||
fileUtils
|
||||
.createNewShareFile(shareFileName)
|
||||
.onSuccess {
|
||||
@@ -366,6 +368,17 @@ class SharedAppViewModel(
|
||||
.onFailure(onFailure)
|
||||
}
|
||||
|
||||
private fun createExportFileName(tunnelCount: Int): String {
|
||||
val timestamp =
|
||||
java.time.LocalDateTime.now()
|
||||
.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm"))
|
||||
|
||||
return when (tunnelCount) {
|
||||
1 -> "WGTunnel_Export_$timestamp.zip"
|
||||
else -> "WGTunnel_Export_${timestamp}_${tunnelCount}_Tunnels.zip"
|
||||
}
|
||||
}
|
||||
|
||||
fun setScreenRecordingSecurity(to: Boolean) = intent {
|
||||
settingsRepository.updateScreenRecordingSecurity(to)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ fun allowedLicenseUrls(): List<String> {
|
||||
"https://github.com/RikkaApps/Shizuku-API/blob/master/LICENSE",
|
||||
"https://github.com/rafi0101/Android-Room-Database-Backup/blob/master/LICENSE",
|
||||
"https://opensource.org/license/mit",
|
||||
"https://www.bouncycastle.org/licence.html",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
[versions]
|
||||
app="5.0.0"
|
||||
accompanist = "0.37.3"
|
||||
activityCompose = "1.13.0"
|
||||
androidx-junit = "1.3.0"
|
||||
@@ -44,7 +43,7 @@ storage = "1.6.0"
|
||||
ktfmt = "0.26.0"
|
||||
licensee = "1.14.1"
|
||||
lifecycleViewmodelNavigation3 = "2.10.0"
|
||||
parser = "1.0.7"
|
||||
parser = "1.1.0"
|
||||
relinker = "1.4.5"
|
||||
libsu = "6.0.0"
|
||||
jetbrainsKotlinJvm = "2.3.21"
|
||||
@@ -200,7 +199,6 @@ libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
kotlinxSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
androidLibrary = { id = "com.android.library", version.ref = "androidGradlePlugin" }
|
||||
|
||||
@@ -153,6 +153,7 @@ func parseUpstream(upstreamURL string) (network, address string, err error) {
|
||||
shared.LogDebug("DNS", "Parsing upstream URL: %s", upstreamURL)
|
||||
u := upstreamURL
|
||||
if !strings.Contains(u, "://") {
|
||||
u = normalizeHostPort(u)
|
||||
u = "udp://" + u
|
||||
}
|
||||
parsed, err := url.Parse(u)
|
||||
@@ -229,6 +230,8 @@ func resolveServerAddrs(
|
||||
defaultPort string,
|
||||
underlying string,
|
||||
) ([]string, string, error) {
|
||||
address = normalizeHostPort(address)
|
||||
|
||||
host, port, err := net.SplitHostPort(address)
|
||||
if err != nil {
|
||||
host = address
|
||||
@@ -379,7 +382,8 @@ func buildTransport(
|
||||
return nil, fmt.Errorf("no addresses resolved for DoH server")
|
||||
}
|
||||
|
||||
// Custom dialer that tries servers in order (IPv4 → IPv6)
|
||||
// Custom dialer that tries servers in order
|
||||
// tries ipv4 first and then ipv6
|
||||
dialer := GetDialer(bypass)
|
||||
transport := &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, _ string) (net.Conn, error) {
|
||||
@@ -447,6 +451,35 @@ func buildTransport(
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeHostPort makes sure raw IPv6 is correctly bracketed.
|
||||
func normalizeHostPort(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" || strings.Contains(s, "://") || strings.Contains(s, "]") {
|
||||
return s
|
||||
}
|
||||
if strings.Count(s, ":") < 2 {
|
||||
return s // definitely not IPv6
|
||||
}
|
||||
|
||||
lastColon := strings.LastIndexByte(s, ':')
|
||||
potentialHost := s[:lastColon]
|
||||
potentialPort := s[lastColon+1:]
|
||||
|
||||
if ip := net.ParseIP(potentialHost); ip != nil && ip.To4() == nil {
|
||||
if potentialPort != "" {
|
||||
return "[" + potentialHost + "]:" + potentialPort
|
||||
}
|
||||
return "[" + potentialHost + "]"
|
||||
}
|
||||
|
||||
// fallback with no port
|
||||
if ip := net.ParseIP(s); ip != nil && ip.To4() == nil {
|
||||
return "[" + s + "]"
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func GetDialer(bypass bool) *net.Dialer {
|
||||
if !bypass {
|
||||
return &net.Dialer{LocalAddr: nil}
|
||||
|
||||
Reference in New Issue
Block a user