mirror of
https://github.com/wgtunnel/android.git
synced 2026-07-03 14:07:49 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a569974beb | |||
| 87bc89b6f1 | |||
| c343220e96 | |||
| 5447ec73f7 | |||
| a2b8eb5b0b | |||
| ee3fcabcf1 |
@@ -97,7 +97,7 @@ jobs:
|
||||
|
||||
- name: Get checksum
|
||||
id: checksum
|
||||
run: echo "checksum=$(apksigner verify -print-certs ${{ steps.apk-path.outputs.path }} | grep -Po "(?<=SHA-256 digest:) .*")" | awk '{$1=$1};1' >> $GITHUB_OUTPUT
|
||||
run: echo "checksum=$(apksigner verify -print-certs ${{ steps.apk-path.outputs.path }} | grep -Po "(?<=SHA-256 digest:) .*" | tr -d "[:blank:]")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Append checksum
|
||||
id: append_checksum
|
||||
@@ -105,8 +105,9 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
body: >
|
||||
<br /> SHA256 Checksum: <br /> ```${{ steps.checksum.outputs.checksum }}```
|
||||
body: |
|
||||
SHA256 fingerprint:
|
||||
```${{ steps.checksum.outputs.checksum }}```
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: ${{ github.ref_name }}
|
||||
draft: false
|
||||
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
|
||||
- name: Get checksum
|
||||
id: checksum
|
||||
run: echo "checksum=$(apksigner verify -print-certs ${{ steps.apk-path.outputs.path }} | grep -Po "(?<=SHA-256 digest:) .*")" | awk '{$1=$1};1' >> $GITHUB_OUTPUT
|
||||
run: echo "checksum=$(apksigner verify -print-certs ${{ steps.apk-path.outputs.path }} | grep -Po "(?<=SHA-256 digest:) .*" | tr -d "[:blank:]")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Append checksum
|
||||
id: append_checksum
|
||||
@@ -111,8 +111,9 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
body: >
|
||||
<br /> SHA256 Checksum: <br /> ```${{ steps.checksum.outputs.checksum }}```
|
||||
body: |
|
||||
SHA256 fingerprint:
|
||||
```${{ steps.checksum.outputs.checksum }}```
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: ${{ github.ref_name }}
|
||||
draft: false
|
||||
|
||||
@@ -12,6 +12,10 @@ android {
|
||||
namespace = Constants.APP_ID
|
||||
compileSdk = Constants.TARGET_SDK
|
||||
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = Constants.APP_ID
|
||||
minSdk = Constants.MIN_SDK
|
||||
@@ -25,8 +29,6 @@ android {
|
||||
getByName("debug").assets.srcDirs(files("$projectDir/schemas")) // Room
|
||||
}
|
||||
|
||||
resourceConfigurations.addAll(listOf("en"))
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables { useSupportLibrary = true }
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ class NotificationActionReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent?) = goAsync {
|
||||
try {
|
||||
//TODO fix for manual start changes when enabled
|
||||
serviceManager.stopVpnService(context)
|
||||
serviceManager.stopVpnServiceForeground(context)
|
||||
delay(Constants.TOGGLE_TUNNEL_DELAY)
|
||||
serviceManager.startVpnServiceForeground(context)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -3,5 +3,6 @@ package com.zaneschepke.wireguardautotunnel.service.foreground
|
||||
enum class Action {
|
||||
START,
|
||||
START_FOREGROUND,
|
||||
STOP
|
||||
STOP,
|
||||
STOP_FOREGROUND
|
||||
}
|
||||
|
||||
+3
-14
@@ -24,7 +24,7 @@ open class ForegroundService : LifecycleService() {
|
||||
when (action) {
|
||||
Action.START.name,
|
||||
Action.START_FOREGROUND.name -> startService(intent.extras)
|
||||
|
||||
Action.STOP.name, Action.STOP_FOREGROUND.name -> stopService()
|
||||
Constants.ALWAYS_ON_VPN_ACTION -> {
|
||||
Timber.i("Always-on VPN starting service")
|
||||
startService(intent.extras)
|
||||
@@ -37,16 +37,9 @@ open class ForegroundService : LifecycleService() {
|
||||
"with a null intent. It has been probably restarted by the system.",
|
||||
)
|
||||
}
|
||||
// by returning this we make sure the service is restarted if the system kills the service
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Timber.d("The service has been destroyed")
|
||||
stopService()
|
||||
}
|
||||
|
||||
protected open fun startService(extras: Bundle?) {
|
||||
if (isServiceStarted) return
|
||||
Timber.d("Starting ${this.javaClass.simpleName}")
|
||||
@@ -55,12 +48,8 @@ open class ForegroundService : LifecycleService() {
|
||||
|
||||
protected open fun stopService() {
|
||||
Timber.d("Stopping ${this.javaClass.simpleName}")
|
||||
try {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
stopSelf()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
}
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
stopSelf()
|
||||
isServiceStarted = false
|
||||
}
|
||||
}
|
||||
|
||||
+12
-3
@@ -23,9 +23,8 @@ class ServiceManager(private val appDataRepository: AppDataRepository) {
|
||||
intent.component?.javaClass
|
||||
try {
|
||||
when (action) {
|
||||
Action.START_FOREGROUND -> context.startForegroundService(intent)
|
||||
Action.START -> context.startService(intent)
|
||||
Action.STOP -> context.stopService(intent)
|
||||
Action.START_FOREGROUND, Action.STOP_FOREGROUND -> context.startForegroundService(intent)
|
||||
Action.START, Action.STOP -> context.startService(intent)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e.message)
|
||||
@@ -46,6 +45,16 @@ class ServiceManager(private val appDataRepository: AppDataRepository) {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun stopVpnServiceForeground(context: Context, isManualStop: Boolean = false) {
|
||||
if (isManualStop) onManualStop()
|
||||
Timber.i("Stopping vpn service")
|
||||
actionOnService(
|
||||
Action.STOP_FOREGROUND,
|
||||
context,
|
||||
WireGuardTunnelService::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun stopVpnService(context: Context, isManualStop: Boolean = false) {
|
||||
if (isManualStop) onManualStop()
|
||||
Timber.i("Stopping vpn service")
|
||||
|
||||
+14
-14
@@ -18,6 +18,7 @@ import com.zaneschepke.wireguardautotunnel.service.notification.NotificationServ
|
||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService
|
||||
import com.zaneschepke.wireguardautotunnel.util.Constants
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -56,7 +57,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
|
||||
private val networkEventsFlow = MutableStateFlow(WatcherState())
|
||||
|
||||
private lateinit var watcherJob: Job
|
||||
private var watcherJob: Job? = null
|
||||
|
||||
private var wakeLock: PowerManager.WakeLock? = null
|
||||
private val tag = this.javaClass.name
|
||||
@@ -74,11 +75,6 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
stopService()
|
||||
}
|
||||
|
||||
override fun startService(extras: Bundle?) {
|
||||
super.startService(extras)
|
||||
try {
|
||||
@@ -139,8 +135,10 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
}
|
||||
|
||||
private fun cancelWatcherJob() {
|
||||
if (this::watcherJob.isInitialized) {
|
||||
watcherJob.cancel()
|
||||
try {
|
||||
watcherJob?.cancel()
|
||||
} catch (e : CancellationException) {
|
||||
Timber.i("Watcher job cancelled")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +234,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
}
|
||||
if (results.contains(false)) {
|
||||
Timber.i("Restarting VPN for ping failure")
|
||||
serviceManager.stopVpnService(this)
|
||||
serviceManager.stopVpnServiceForeground(this)
|
||||
delay(Constants.VPN_RESTART_DELAY)
|
||||
serviceManager.startVpnServiceForeground(this)
|
||||
delay(Constants.PING_COOLDOWN)
|
||||
@@ -324,7 +322,9 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
)
|
||||
val ssid = wifiService.getNetworkName(it.networkCapabilities)
|
||||
ssid?.let {
|
||||
Timber.i("Detected SSID: $ssid")
|
||||
if(it.contains(Constants.UNREADABLE_SSID)) {
|
||||
Timber.w("SSID unreadable: missing permissions")
|
||||
} else Timber.i("Detected valid SSID")
|
||||
appDataRepository.appState.setCurrentSsid(ssid)
|
||||
networkEventsFlow.value =
|
||||
networkEventsFlow.value.copy(
|
||||
@@ -381,7 +381,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
|
||||
watcherState.isTunnelOffOnMobileDataConditionMet() -> {
|
||||
Timber.i("$autoTunnel - tunnel off on mobile data met, turning vpn off")
|
||||
serviceManager.stopVpnService(this)
|
||||
serviceManager.stopVpnServiceForeground(this)
|
||||
}
|
||||
|
||||
watcherState.isTunnelNotWifiNamePreferredMet(watcherState.currentNetworkSSID) -> {
|
||||
@@ -407,17 +407,17 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
||||
|
||||
watcherState.isTrustedWifiConditionMet() -> {
|
||||
Timber.i("$autoTunnel - tunnel off on trusted wifi condition met, turning vpn off")
|
||||
serviceManager.stopVpnService(this)
|
||||
serviceManager.stopVpnServiceForeground(this)
|
||||
}
|
||||
|
||||
watcherState.isTunnelOffOnWifiConditionMet() -> {
|
||||
Timber.i("$autoTunnel - tunnel off on wifi condition met, turning vpn off")
|
||||
serviceManager.stopVpnService(this)
|
||||
serviceManager.stopVpnServiceForeground(this)
|
||||
}
|
||||
|
||||
watcherState.isTunnelOffOnNoConnectivityMet() -> {
|
||||
Timber.i("$autoTunnel - tunnel off on no connectivity met, turning vpn off")
|
||||
serviceManager.stopVpnService(this)
|
||||
serviceManager.stopVpnServiceForeground(this)
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
+7
-8
@@ -16,10 +16,12 @@ import com.zaneschepke.wireguardautotunnel.util.Constants
|
||||
import com.zaneschepke.wireguardautotunnel.util.handshakeStatus
|
||||
import com.zaneschepke.wireguardautotunnel.util.mapPeerStats
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -35,7 +37,7 @@ class WireGuardTunnelService : ForegroundService() {
|
||||
@Inject
|
||||
lateinit var notificationService: NotificationService
|
||||
|
||||
private lateinit var job: Job
|
||||
private var job: Job? = null
|
||||
|
||||
private var didShowConnected = false
|
||||
|
||||
@@ -49,11 +51,6 @@ class WireGuardTunnelService : ForegroundService() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
}
|
||||
|
||||
override fun startService(extras: Bundle?) {
|
||||
super.startService(extras)
|
||||
cancelJob()
|
||||
@@ -182,8 +179,10 @@ class WireGuardTunnelService : ForegroundService() {
|
||||
}
|
||||
|
||||
private fun cancelJob() {
|
||||
if (this::job.isInitialized) {
|
||||
job.cancel()
|
||||
try {
|
||||
job?.cancel()
|
||||
} catch (e : CancellationException) {
|
||||
Timber.i("Tunnel job cancelled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ class ShortcutsActivity : ComponentActivity() {
|
||||
this@ShortcutsActivity, tunnelConfig?.id, isManualStart = true,
|
||||
)
|
||||
|
||||
Action.STOP.name -> serviceManager.stopVpnService(
|
||||
Action.STOP.name -> serviceManager.stopVpnServiceForeground(
|
||||
this@ShortcutsActivity,
|
||||
isManualStop = true,
|
||||
)
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ class TunnelControlTile : TileService() {
|
||||
scope.launch {
|
||||
try {
|
||||
if (vpnService.getState() == Tunnel.State.UP) {
|
||||
serviceManager.stopVpnService(
|
||||
serviceManager.stopVpnServiceForeground(
|
||||
this@TunnelControlTile,
|
||||
isManualStop = true,
|
||||
)
|
||||
|
||||
+6
-3
@@ -10,6 +10,7 @@ import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
|
||||
import com.zaneschepke.wireguardautotunnel.module.Kernel
|
||||
import com.zaneschepke.wireguardautotunnel.module.Userspace
|
||||
import com.zaneschepke.wireguardautotunnel.util.Constants
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -33,7 +34,7 @@ constructor(
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
private lateinit var statsJob: Job
|
||||
private var statsJob: Job? = null
|
||||
|
||||
private var backend: Backend = userspaceBackend
|
||||
|
||||
@@ -134,8 +135,10 @@ constructor(
|
||||
}
|
||||
}
|
||||
if (state == State.DOWN) {
|
||||
if (this::statsJob.isInitialized) {
|
||||
statsJob.cancel()
|
||||
try {
|
||||
statsJob?.cancel()
|
||||
} catch (e : CancellationException) {
|
||||
Timber.i("Stats job cancelled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,12 +118,12 @@ constructor(
|
||||
fun readLogCatOutput() =
|
||||
viewModelScope.launch(viewModelScope.coroutineContext + Dispatchers.IO) {
|
||||
launch {
|
||||
Logcatter.logs {
|
||||
Logcatter.logs(callback = {
|
||||
logs.add(it)
|
||||
if (logs.size > Constants.LOG_BUFFER_SIZE) {
|
||||
logs.removeRange(0, (logs.size - Constants.LOG_BUFFER_SIZE).toInt())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,17 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Home
|
||||
import androidx.compose.material.icons.rounded.QuestionMark
|
||||
import androidx.compose.material.icons.rounded.Settings
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavItem
|
||||
import com.zaneschepke.wireguardautotunnel.util.StringValue
|
||||
|
||||
sealed class Screen(val route: String) {
|
||||
data object Main : Screen("main") {
|
||||
val navItem =
|
||||
BottomNavItem(
|
||||
name = "Tunnels",
|
||||
name = WireGuardAutoTunnel.instance.getString(R.string.tunnels),
|
||||
route = route,
|
||||
icon = Icons.Rounded.Home,
|
||||
)
|
||||
@@ -19,7 +23,7 @@ sealed class Screen(val route: String) {
|
||||
data object Settings : Screen("settings") {
|
||||
val navItem =
|
||||
BottomNavItem(
|
||||
name = "Settings",
|
||||
name = WireGuardAutoTunnel.instance.getString(R.string.settings),
|
||||
route = route,
|
||||
icon = Icons.Rounded.Settings,
|
||||
)
|
||||
@@ -28,7 +32,7 @@ sealed class Screen(val route: String) {
|
||||
data object Support : Screen("support") {
|
||||
val navItem =
|
||||
BottomNavItem(
|
||||
name = "Support",
|
||||
name = WireGuardAutoTunnel.instance.getString(R.string.support),
|
||||
route = route,
|
||||
icon = Icons.Rounded.QuestionMark,
|
||||
)
|
||||
|
||||
+6
-1
@@ -28,7 +28,12 @@ fun ConfigurationToggle(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(label, textAlign = TextAlign.Start)
|
||||
Text(label, textAlign = TextAlign.Start, modifier = Modifier
|
||||
.weight(
|
||||
weight = 1.0f,
|
||||
fill = false,
|
||||
),
|
||||
softWrap = true)
|
||||
Switch(
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
|
||||
+25
-2
@@ -71,8 +71,12 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
@@ -124,6 +128,25 @@ fun MainScreen(
|
||||
val sheetState = rememberModalBottomSheetState()
|
||||
var showBottomSheet by remember { mutableStateOf(false) }
|
||||
|
||||
// Nested scroll for control FAB
|
||||
val nestedScrollConnection = remember {
|
||||
object : NestedScrollConnection {
|
||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
||||
// Hide FAB
|
||||
if (available.y < -1) {
|
||||
isVisible.value = false
|
||||
}
|
||||
// Show FAB
|
||||
if (available.y > 1) {
|
||||
isVisible.value = true
|
||||
}
|
||||
|
||||
return Offset.Zero
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var showDeleteTunnelAlertDialog by remember { mutableStateOf(false) }
|
||||
var selectedTunnel by remember { mutableStateOf<TunnelConfig?>(null) }
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
@@ -377,8 +400,8 @@ fun MainScreen(
|
||||
verticalArrangement = Arrangement.Top,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.overscroll(ScrollableDefaults.overscrollEffect()),
|
||||
.fillMaxSize()
|
||||
.overscroll(ScrollableDefaults.overscrollEffect()).nestedScroll(nestedScrollConnection),
|
||||
state = rememberLazyListState(0, uiState.tunnels.count()),
|
||||
userScrollEnabled = true,
|
||||
reverseLayout = false,
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
|
||||
+23
-3
@@ -37,6 +37,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
@@ -122,7 +123,13 @@ fun SupportScreen(
|
||||
Text(
|
||||
stringResource(id = R.string.docs_description),
|
||||
textAlign = TextAlign.Justify,
|
||||
modifier = Modifier.padding(start = 10.dp),
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp)
|
||||
.weight(
|
||||
weight = 1.0f,
|
||||
fill = false,
|
||||
),
|
||||
softWrap = true
|
||||
)
|
||||
}
|
||||
Icon(
|
||||
@@ -270,8 +277,21 @@ fun SupportScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(25.dp),
|
||||
) {
|
||||
Text("Version: ${BuildConfig.VERSION_NAME}", modifier = Modifier.focusable())
|
||||
Text("Mode: ${if (uiState.settings.isKernelEnabled) "Kernel" else "Userspace"}")
|
||||
val version = buildAnnotatedString {
|
||||
append(stringResource(id = R.string.version))
|
||||
append(": ")
|
||||
append(BuildConfig.VERSION_NAME)
|
||||
}
|
||||
val mode = buildAnnotatedString {
|
||||
append(stringResource(R.string.mode))
|
||||
append(": ")
|
||||
when(uiState.settings.isKernelEnabled){
|
||||
true -> append(stringResource(id = R.string.kernel))
|
||||
false -> append(stringResource(id = R.string.userspace))
|
||||
}
|
||||
}
|
||||
Text(version.text, modifier = Modifier.focusable())
|
||||
Text(mode.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,4 +35,6 @@ object Constants {
|
||||
|
||||
const val TUNNEL_EXTRA_KEY = "tunnelId"
|
||||
|
||||
const val UNREADABLE_SSID = "<unknown ssid>"
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
unqualifiedResLocale=en-US
|
||||
@@ -0,0 +1,191 @@
|
||||
<resources>
|
||||
<string name="app_name">WG Tunnel</string>
|
||||
<string name="vpn_channel_id">VPN Kanalı</string>
|
||||
<string name="vpn_channel_name">VPN Bildirim Kanalı</string>
|
||||
<string name="watcher_channel_id">İzleyici Kanalı</string>
|
||||
<string name="watcher_channel_name">İzleyici Bildirim Kanalı</string>
|
||||
<string name="foreground_file">FOREGROUND_FILE</string>
|
||||
<string name="github_url" translatable="false">https://github.com/zaneschepke/wgtunnel/issues</string>
|
||||
<string name="docs_url" translatable="false">https://zaneschepke.com/wgtunnel-docs/overview.html</string>
|
||||
<string name="privacy_policy_url" translatable="false">https://zaneschepke.com/wgtunnel-docs/privacypolicy.html</string>
|
||||
<string name="error_file_extension">Dosya bir .conf veya .zip değil</string>
|
||||
<string name="turn_off_tunnel">Eylem tünelin kapalı olmasını gerektiriyor</string>
|
||||
<string name="no_tunnels">Henüz tünel eklenmedi!</string>
|
||||
<string name="tunnel_exists">Tünel adı zaten var</string>
|
||||
<string name="discord_url" translatable="false">https://discord.gg/rbRRNh6H7V</string>
|
||||
<string name="watcher_notification_title">Bildirim Hizmeti</string>
|
||||
<string name="watcher_notification_text_active">Ağ durumu değişikliklerini izleme: etkin</string>
|
||||
<string name="watcher_notification_text_paused">Ağ durumu değişikliklerini izleme: duraklatıldı</string>
|
||||
<string name="tunnel_start_title">VPN bağlandı</string>
|
||||
<string name="tunnel_start_text">Tünele bağlı</string>
|
||||
<string name="vpn_permission_required">Uygulamanın düzgün çalışması için VPN izni gereklidir. Bu izin başlatılmıyorsa, lütfen resmi WireGuard mobil uygulaması için telefon ayarlarınızda \"Her zaman açık VPN\" i devre dışı bırakın ve tekrar deneyin.</string>
|
||||
<string name="notification_permission_required">Bildirim izni gerekli.</string>
|
||||
<string name="open_settings">Ayarları Aç</string>
|
||||
<string name="add_trusted_ssid">Güvenilir wifi adı ekleyin</string>
|
||||
<string name="tunnels">Tüneller</string>
|
||||
<string name="enable_auto_tunnel">Otomatik tünellemeyi başlat</string>
|
||||
<string name="disable_auto_tunnel">Otomatik tünellemeyi durdur</string>
|
||||
<string name="tunnel_mobile_data">Mobil veri üzerinde tünel</string>
|
||||
<string name="background_location_reason">Arka planda Wi-Fi SSID\'yi almak için \"Her zaman izin ver\" konum izni gereklidir. Bu özellik için izin gereklidir.</string>
|
||||
<string name="location_permission_reason">Bu özelliğin düzgün çalışması için konum izni gereklidir.</string>
|
||||
<string name="one_tunnel_required">Bu özelliği kullanmak için en az bir tünel gereklidir</string>
|
||||
<string name="retry">"Yeniden dene"</string>
|
||||
<string name="privacy_policy">Gizlilik Politikasını Görüntüle</string>
|
||||
<string name="okay">Tamam</string>
|
||||
<string name="tunnel_on_ethernet">Ethernet üzerinde tünel</string>
|
||||
<string name="prominent_background_location_message">Bu özellik, uygulama kapalıyken bile Wi-Fi SSID izlemesini etkinleştirmek için arka plan konumu izni gerektirir. Daha fazla bilgi için lütfen Destek ekranında bağlantısı verilen Gizlilik Politikasına bakın.</string>
|
||||
<string name="prominent_background_location_title">Arka Plan Konum Açıklaması</string>
|
||||
<string name="thank_you">WG Tunnel\'i kullandığınız için teşekkür ederiz!</string>
|
||||
<string name="trusted_ssid_empty_description">SSID girin</string>
|
||||
<string name="trusted_ssid_value_description">SSID\'yi Gönder</string>
|
||||
<string name="config_validation" translatable="false">[Interface]</string>
|
||||
<string name="add_tunnels_text">Dosyadan veya ZIP\'ten ekle</string>
|
||||
<string name="open_file">Dosya Aç</string>
|
||||
<string name="add_from_qr">QR kodundan ekle</string>
|
||||
<string name="qr_scan">QR Tarama</string>
|
||||
<string name="tunnel_edit">Tünel Düzenleme</string>
|
||||
<string name="tunnel_name">Tünel Adı</string>
|
||||
<string name="add_tunnel">Tünel Ekle</string>
|
||||
<string name="exclude">Hariç tut</string>
|
||||
<string name="include">Dahil et</string>
|
||||
<string name="tunnel_all">Tünel tüm uygulamalar</string>
|
||||
<string name="config_changes_saved">Yapılandırma değişiklikleri kaydedildi.</string>
|
||||
<string name="save_changes">Kaydet</string>
|
||||
<string name="icon">Simge</string>
|
||||
<string name="no_thanks">Hayır, teşekkürler</string>
|
||||
<string name="turn_on">Aç</string>
|
||||
<string name="map">Harita</string>
|
||||
<string name="bad_config">Hatalı yapılandırma. Lütfen tekrar deneyin.</string>
|
||||
<string name="config_interface">Arayüz</string>
|
||||
<string name="public_key">Genel anahtar</string>
|
||||
<string name="barcode_downloading">Barkod UI modülünün indirilmesi bekleniyor.</string>
|
||||
<string name="barcode_downloading_message">Barkod modülü indiriliyor. Tekrar deneyin.</string>
|
||||
<string name="addresses">Adresler</string>
|
||||
<string name="dns_servers">DNS sunucuları</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="peer">Akran</string>
|
||||
<string name="allowed_ips">İzin verilen IP\'ler</string>
|
||||
<string name="endpoint">Uç nokta</string>
|
||||
<string name="transfer">Nakil</string>
|
||||
<string name="last_handshake">Son tokalaşma</string>
|
||||
<string name="name">Ad</string>
|
||||
<string name="restart">Tüneli Yeniden Başlat</string>
|
||||
<string name="vpn_connection_failed">Bağlantı kurulamadı</string>
|
||||
<string name="failed_connection_to">- ile bağlantı kurulamadı</string>
|
||||
<string name="initial_connection_failure_message">30 saniye boyunca yanıt alınamadıktan sonra sunucuya bağlanmaya çalışılıyor.</string>
|
||||
<string name="lost_connection_failure_message">Bir dakikadan fazla yanıt alınamadıktan sonra sunucuya yeniden bağlanmaya çalışılıyor.</string>
|
||||
<string name="always_on_vpn_support">Her Zaman Açık VPN\'e İzin Ver</string>
|
||||
<string name="select_tunnel_message">Lütfen önce bir tünel seçin</string>
|
||||
<string name="location_services_not_detected">Konum Hizmetleri Algılanmadı</string>
|
||||
<string name="check_again">Tekrar kontrol et</string>
|
||||
<string name="detecting_location_services_disabled">Konum Hizmetlerini Algılama devre dışı</string>
|
||||
<string name="precise_location_message">Bu özellik, Wi-Fi SSID adına erişmek için kesin konum gerektirir. Lütfen kesin konumu buradan veya uygulama ayarlarından etkinleştirin.</string>
|
||||
<string name="request">İstek</string>
|
||||
<string name="toggle_vpn">VPN\'i aç/kapat</string>
|
||||
<string name="no_tunnel_available">Tünel yok</string>
|
||||
<string name="hint_search_packages">Paket ara</string>
|
||||
<string name="clear_icon">Simgeyi Temizle</string>
|
||||
<string name="search_icon">Simge Ara</string>
|
||||
<string name="attempt_connection">Bağlantı kurulmaya çalışılıyor..</string>
|
||||
<string name="vpn_starting">VPN başlatılıyor</string>
|
||||
<string name="db_name">wg-tunnel-db</string>
|
||||
<string name="scanning_qr">QR taranıyor</string>
|
||||
<string name="qr_result_failed">QR taraması başarısız oldu</string>
|
||||
<string name="none">Güvenilir wifi adı yok</string>
|
||||
<string name="never">Asla</string>
|
||||
<string name="stream_failed">Dosya akışı açılamadı.</string>
|
||||
<string name="other">Diğer</string>
|
||||
<string name="auto_tunneling">Otomatik tünelleme</string>
|
||||
<string name="select_tunnel">Kullanılacak tüneli seçin</string>
|
||||
<string name="vpn_on">VPN açık</string>
|
||||
<string name="vpn_off">VPN kapalı</string>
|
||||
<string name="default_vpn_on">Birincil VPN açık</string>
|
||||
<string name="default_vpn_off">Birincil VPN kapalı</string>
|
||||
<string name="create_import">Sıfırdan oluştur</string>
|
||||
<string name="turn_off_auto">Eylem, otomatik tünelin devre dışı bırakılmasını veya duraklatılmasını gerektirir</string>
|
||||
<string name="turn_on_tunnel">Eylem aktif tünel gerektirir</string>
|
||||
<string name="add_peer">Akran ekle</string>
|
||||
<string name="done">Bitti</string>
|
||||
<string name="interface_">Arayüz</string>
|
||||
<string name="rotate_keys">Tuşları döndür</string>
|
||||
<string name="private_key">Özel anahtar</string>
|
||||
<string name="copy_public_key">Genel anahtarı kopyala</string>
|
||||
<string name="base64_key">base64 anahtarı</string>
|
||||
<string name="comma_separated_list">virgülle ayrılmış liste</string>
|
||||
<string name="listen_port">Portu dinle</string>
|
||||
<string name="random">(rastgele)</string>
|
||||
<string name="optional">(isteğe bağlı)</string>
|
||||
<string name="optional_no_recommend">(isteğe bağlı, önerilmez)</string>
|
||||
<string name="preshared_key">Ön paylaşımlı anahtar</string>
|
||||
<string name="seconds">saniye</string>
|
||||
<string name="persistent_keepalive">Kalıcı canlı tutma</string>
|
||||
<string name="cancel">İptal</string>
|
||||
<string name="error_authentication_failed">Kimlik doğrulama başarısız oldu</string>
|
||||
<string name="error_authorization_failed">Yetkilendirilemedi</string>
|
||||
<string name="enabled_app_shortcuts">Uygulama kısayollarını etkinleştir</string>
|
||||
<string name="export_configs">Yapılandırmaları dışa aktar</string>
|
||||
<string name="battery_saver">Pil tasarrufu (beta)</string>
|
||||
<string name="location_services_required">Gerekli konum hizmetleri</string>
|
||||
<string name="background_location_required">Arka plan konumu gerekli</string>
|
||||
<string name="precise_location_required">Kesin konum gerekli</string>
|
||||
<string name="unknown_error">Bilinmeyen bir hata oluştu</string>
|
||||
<string name="exported_configs_message">Yapılandırmalar indirmelere aktarıldı</string>
|
||||
<string name="tunnel_on_wifi">Güvenilmeyen kablosuz internet bağlantısında tünel</string>
|
||||
<string name="my_email" translatable="false">support@zaneschepke.com</string>
|
||||
<string name="email_subject">WG Tunnel Desteği</string>
|
||||
<string name="email_chooser">Bir e-posta gönderin…</string>
|
||||
<string name="go">git</string>
|
||||
<string name="docs_description">Belgeleri okuyun</string>
|
||||
<string name="discord_description">Topluluğa katılın</string>
|
||||
<string name="email_description">Bana e-posta gönder</string>
|
||||
<string name="support_help_text">Sorun yaşıyorsanız, iyileştirme fikirleriniz varsa veya sadece etkileşimde bulunmak istiyorsanız, aşağıdaki kaynaklar mevcuttur:</string>
|
||||
<string name="kernel">Çekirdek</string>
|
||||
<string name="use_kernel">Çekirdek modülünü kullan</string>
|
||||
<string name="error_ssid_exists">SSID zaten var</string>
|
||||
<string name="error_root_denied">Kök kabuğu reddedildi</string>
|
||||
<string name="error_no_file_explorer">Yüklü dosya gezgini yok</string>
|
||||
<string name="error_no_scan">Kod taranmadı</string>
|
||||
<string name="error_invalid_code">Geçersiz QR kodu</string>
|
||||
<string name="error_none">Hata yok</string>
|
||||
<string name="error_file_read">Dosya okunamadı</string>
|
||||
<string name="location_service_missing">Konum Hizmetleri Algılanmadı</string>
|
||||
<string name="location_services_missing_message">Uygulama, cihazınızda etkinleştirilen herhangi bir konum hizmeti algılamıyor. Cihaza bağlı olarak bu, güvenilmeyen wifi özelliğinin wifi adını okuyamamasına neden olabilir. Yine de devam etmek ister misiniz?</string>
|
||||
<string name="auto_tunnel_title">Otomatik Tünel Hizmeti</string>
|
||||
<string name="delete_tunnel">Tüneli sil</string>
|
||||
<string name="delete_tunnel_message">Bu tüneli silmek istediğinizden emin misiniz?</string>
|
||||
<string name="yes">Evet</string>
|
||||
<string name="resume">Devam et</string>
|
||||
<string name="pause">Duraklat</string>
|
||||
<string name="paused">duraklatıldı</string>
|
||||
<string name="active">aktif</string>
|
||||
<string name="tunneling_apps">Tünelleme uygulamaları</string>
|
||||
<string name="included">dahil</string>
|
||||
<string name="excluded">hariç</string>
|
||||
<string name="all">tümü</string>
|
||||
<string name="always_on_disabled">Her zaman açık VPN bir tünel başlatmaya çalıştı, ancak bu özellik ayarlarda devre dışı bırakıldı.</string>
|
||||
<string name="no_email_detected">E-posta uygulaması algılanmadı</string>
|
||||
<string name="no_browser_detected">Tarayıcı algılanmadı</string>
|
||||
<string name="logs_saved">İndirilenlere kaydedilen günlükler</string>
|
||||
<string name="open_issue">Bir sorun açın</string>
|
||||
<string name="read_logs">Günlükleri okuyun</string>
|
||||
<string name="auto">(otomatik)</string>
|
||||
<string name="config_parse_error">Yapılandırma ayrıştırılamadı</string>
|
||||
<string name="incorrect_pin">PIN kodu yanlış</string>
|
||||
<string name="pin_created">Pin başarıyla oluşturuldu</string>
|
||||
<string name="enter_pin">PIN kodunuzu girin</string>
|
||||
<string name="create_pin">PIN kodu oluştur</string>
|
||||
<string name="enable_app_lock">Uygulama kilidi etkinleştirildi</string>
|
||||
<string name="restart_on_ping">Ping başarısız olduğunda yeniden başlat (beta)</string>
|
||||
<string name="mobile_data_tunnel">Mobil veri tüneli olarak ayarla</string>
|
||||
<string name="set_primary_tunnel">Birincil tünel olarak ayarla</string>
|
||||
<string name="use_tunnel_on_wifi_name">Wifi adında tünel kullan</string>
|
||||
<string name="no_wifi_names_configured">Bu tünel için yapılandırılmış wifi adı yok</string>
|
||||
<string name="general">Genel</string>
|
||||
<string name="edit_tunnel">Tüneli düzenle</string>
|
||||
<string name="tunnel">Tünel</string>
|
||||
<string name="disabled">devre dışı</string>
|
||||
<string name="auto_on">Otomatik ayarlamayı sürdür</string>
|
||||
<string name="auto_off">Otomatik ayarlamayı duraklat</string>
|
||||
<string name="auto_tun_on">Otomatik tüneli sürdür</string>
|
||||
<string name="auto_tun_off">Otomatik tüneli duraklat</string>
|
||||
</resources>
|
||||
@@ -135,7 +135,7 @@
|
||||
<string name="email_subject">WG Tunnel Support</string>
|
||||
<string name="email_chooser">Send an email…</string>
|
||||
<string name="go">go</string>
|
||||
<string name="docs_description">Read the docs (WIP)</string>
|
||||
<string name="docs_description">Read the docs</string>
|
||||
<string name="discord_description">Join the community</string>
|
||||
<string name="email_description">Send me an email</string>
|
||||
<string name="support_help_text">If you are experiencing issues, have improvement ideas, or just want to engage, the following resources are available:</string>
|
||||
@@ -188,4 +188,9 @@
|
||||
<string name="auto_off">Pause auto tun</string>
|
||||
<string name="auto_tun_on">Resume auto-tunnel</string>
|
||||
<string name="auto_tun_off">Pause auto-tunnel</string>
|
||||
<string name="version">Version</string>
|
||||
<string name="mode">Mode</string>
|
||||
<string name="userspace">Userspace</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="support">Support</string>
|
||||
</resources>
|
||||
@@ -1,7 +1,7 @@
|
||||
object Constants {
|
||||
const val VERSION_NAME = "3.4.1"
|
||||
const val VERSION_NAME = "3.4.2"
|
||||
const val JVM_TARGET = "17"
|
||||
const val VERSION_CODE = 34100
|
||||
const val VERSION_CODE = 34200
|
||||
const val TARGET_SDK = 34
|
||||
const val MIN_SDK = 26
|
||||
const val APP_ID = "com.zaneschepke.wireguardautotunnel"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
What's new:
|
||||
- Fix stop tunnel regression
|
||||
- Add logs obfuscation
|
||||
- Add hide FAB on scroll
|
||||
- Add Turkish localization
|
||||
@@ -20,7 +20,7 @@ pinLockCompose = "1.0.3"
|
||||
roomVersion = "2.6.1"
|
||||
timber = "5.0.1"
|
||||
tunnel = "1.0.20230706"
|
||||
androidGradlePlugin = "8.4.0-rc01"
|
||||
androidGradlePlugin = "8.4.0-rc02"
|
||||
kotlin = "1.9.23"
|
||||
ksp = "1.9.23-1.0.19"
|
||||
composeBom = "2024.03.00"
|
||||
|
||||
@@ -3,14 +3,29 @@ package com.zaneschepke.logcatter
|
||||
import com.zaneschepke.logcatter.model.LogMessage
|
||||
|
||||
object Logcatter {
|
||||
fun logs(callback: (input: LogMessage) -> Unit) {
|
||||
|
||||
private val findKeyRegex = """[A-Za-z0-9+/]{42}[AEIMQUYcgkosw480]=""".toRegex()
|
||||
private val findIpv6AddressRegex = """(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))""".toRegex()
|
||||
private val findIpv4AddressRegex = """((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}""".toRegex()
|
||||
private val findTunnelNameRegex = """(?<=tunnel ).*?(?= UP| DOWN)""".toRegex()
|
||||
|
||||
|
||||
fun logs(callback: (input: LogMessage) -> Unit, obfuscator: (log : String) -> String = { log -> this.obfuscator(log)}){
|
||||
clear()
|
||||
Runtime.getRuntime().exec("logcat -v epoch")
|
||||
.inputStream
|
||||
.bufferedReader()
|
||||
.useLines { lines ->
|
||||
lines.forEach { callback(LogMessage.from(it)) }
|
||||
lines.forEach { callback(LogMessage.from(obfuscator(it))) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun obfuscator(log : String) : String {
|
||||
return findKeyRegex.replace(log, "<crypto-key>").let { first ->
|
||||
findIpv6AddressRegex.replace(first, "<ipv6-address>").let { second ->
|
||||
findTunnelNameRegex.replace(second, "<tunnel>")
|
||||
}
|
||||
}.let{ last -> findIpv4AddressRegex.replace(last,"<ipv4-address>") }
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
|
||||
Reference in New Issue
Block a user