Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package com.gatecontrol.android.ui.settings

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gatecontrol.android.R
import com.gatecontrol.android.data.LicenseRepository
import com.gatecontrol.android.data.SetupRepository
import com.gatecontrol.android.data.SettingsRepository
import com.gatecontrol.android.network.ApiClientProvider
import com.gatecontrol.android.tunnel.WgConfigValidator
import com.gatecontrol.android.network.UpdateCheckResponse
import com.gatecontrol.android.common.Validation
import org.json.JSONArray
Expand Down Expand Up @@ -414,8 +416,12 @@ class SettingsViewModel @Inject constructor(
val input = context.contentResolver.openInputStream(uri)
val config = input?.bufferedReader()?.readText() ?: return@launch
input.close()
if (!config.contains("[Interface]") || !config.contains("PrivateKey")) {
_uiState.update { it.copy(error = "Invalid WireGuard config file") }
val validation = WgConfigValidator.validate(config)
if (!validation.ok) {
Timber.w("importConfigFromUri rejected: %s", validation.errors.joinToString(", "))
_uiState.update {
it.copy(error = context.getString(R.string.setup_invalid_config))
}
return@launch
}
setupRepository.saveWireGuardConfig(config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package com.gatecontrol.android.ui.setup

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gatecontrol.android.R
import com.gatecontrol.android.data.SetupRepository
import com.gatecontrol.android.network.ApiClientProvider
import com.gatecontrol.android.network.RegisterRequest
import com.gatecontrol.android.tunnel.WgConfigValidator
import android.content.Context
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
Expand Down Expand Up @@ -184,9 +186,14 @@ class SetupViewModel @Inject constructor(
fun importConfig(configText: String) {
viewModelScope.launch {
try {
if (configText.isBlank() || !configText.contains("[Interface]")) {
val validation = WgConfigValidator.validate(configText)
if (!validation.ok) {
Timber.w("importConfig rejected: %s", validation.errors.joinToString(", "))
_uiState.update {
it.copy(statusMessage = "Invalid WireGuard config", statusType = StatusType.ERROR)
it.copy(
statusMessage = context.getString(R.string.setup_invalid_config),
statusType = StatusType.ERROR,
)
}
return@launch
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
<string name="setup_registering">Registriere&#8230;</string>
<string name="setup_success">Erfolgreich registriert!</string>
<string name="setup_error">Registrierung fehlgeschlagen: %1$s</string>
<string name="setup_invalid_config">Ungültige WireGuard-Konfiguration</string>

<!-- Logs -->
<string name="logs_title">Protokolle</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
<string name="setup_registering">Registering&#8230;</string>
<string name="setup_success">Successfully registered!</string>
<string name="setup_error">Registration failed: %1$s</string>
<string name="setup_invalid_config">Invalid WireGuard config</string>

<!-- Logs -->
<string name="logs_title">Logs</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ class SetupViewModelTest {

@Test
fun `importConfig saves valid WireGuard config`() = runTest {
val config = "[Interface]\nPrivateKey=abc\nAddress=10.0.0.1/32\n\n[Peer]\nPublicKey=xyz"
val config = "[Interface]\nPrivateKey = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=\nAddress = 10.8.0.5/32\n\n[Peer]\nPublicKey = c2VydmVycHVibGlja2V5YmFzZTY0ZW5jb2RlZHh5eiE=\nEndpoint = vpn.example.com:51820\nAllowedIPs = 0.0.0.0/0"

viewModel.uiState.test {
awaitItem()
Expand Down
4 changes: 4 additions & 0 deletions core/tunnel/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ dependencies {
testRuntimeOnly(libs.junit5.engine)
testImplementation(libs.mockk)
testImplementation(libs.coroutines.test)
// Lightweight JSON parser for loading the vendored WG-config golden fixtures
// in unit tests. No standalone JSON lib is in the version catalog and the
// org.json reference impl is dependency-free and JVM-friendly for unit tests.
testImplementation(libs.org.json)
}

kapt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ data class TunnelConfig(
fun parse(raw: String): TunnelConfig {
require(raw.isNotBlank()) { "Config input must not be empty" }

val validation = WgConfigValidator.validate(raw)
require(validation.ok) {
"Invalid WireGuard config: ${validation.errors.joinToString(", ")}"
}

val lines = raw.lines()
.map { it.trim() }
.filter { it.isNotEmpty() && !it.startsWith("#") }
Expand Down
Loading
Loading