summaryrefslogtreecommitdiffhomepage
path: root/android/lib
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-12-01 08:45:31 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2026-01-30 12:34:08 +0100
commit033b631f6e3b855cca5529ec5b0192d35b3b07e4 (patch)
treebb788f2232f7f747d6519b4f7036fe096572dda3 /android/lib
parent7648af6b7c4a23554b41191f38c95221974d2954 (diff)
downloadmullvadvpn-hackday-wire.tar.xz
mullvadvpn-hackday-wire.zip
Everything works except eventshackday-wire
Diffstat (limited to 'android/lib')
-rw-r--r--android/lib/daemon-grpc/build.gradle.kts61
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt403
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/FromDomain.kt390
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt969
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/LogInterceptor.kt16
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/ManagedChannel.kt16
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/TunnelingUnixSocket.java58
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/UnixDomainSocketFactory.kt58
8 files changed, 999 insertions, 972 deletions
diff --git a/android/lib/daemon-grpc/build.gradle.kts b/android/lib/daemon-grpc/build.gradle.kts
index 587d4300c6..63af19a2c2 100644
--- a/android/lib/daemon-grpc/build.gradle.kts
+++ b/android/lib/daemon-grpc/build.gradle.kts
@@ -1,55 +1,31 @@
-import com.google.protobuf.gradle.proto
-
plugins {
alias(libs.plugins.mullvad.android.library)
alias(libs.plugins.kotlin.parcelize)
- alias(libs.plugins.protobuf.core)
alias(libs.plugins.junit5.android)
+ alias(libs.plugins.wire)
}
android {
namespace = "net.mullvad.mullvadvpn.lib.daemon.grpc"
- sourceSets {
+ /*sourceSets {
getByName("main") {
proto { srcDir("${rootProject.projectDir}/../mullvad-management-interface/proto") }
}
- }
+ }*/
kotlin { compilerOptions { freeCompilerArgs.add("-XXLanguage:+WhenGuards") } }
}
-protobuf {
- protoc { artifact = libs.plugins.protobuf.protoc.get().toString() }
- plugins {
- val grpcPluginPath = System.getenv("PROTOC_GEN_GRPC_JAVA_PLUGIN")
- create("java") {
- if (grpcPluginPath != null) {
- path = grpcPluginPath
- } else {
- artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString()
- }
- }
- create("grpc") {
- if (grpcPluginPath != null) {
- path = grpcPluginPath
- } else {
- artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString()
- }
- }
- create("grpckt") {
- artifact = libs.plugins.grpc.protoc.gen.grpc.kotlin.get().toString() + ":jdk8@jar"
- }
- }
- generateProtoTasks {
- all().forEach {
- it.plugins {
- create("java") { option("lite") }
- create("grpc") { option("lite") }
- create("grpckt") { option("lite") }
- }
- it.builtins { create("kotlin") { option("lite") } }
- }
+wire {
+ sourcePath { srcDir("${rootProject.projectDir}/../mullvad-management-interface/proto") }
+
+ kotlin {
+ android = true
+ rpcRole = "client"
+ rpcCallStyle = "blocking"
+ explicitStreamingCalls = true
+ emitProtoReader32 = true
}
}
@@ -63,12 +39,13 @@ dependencies {
implementation(libs.kotlinx.coroutines)
implementation(libs.kotlinx.coroutines.android)
- implementation(libs.grpc.okhttp)
- implementation(libs.grpc.android)
- implementation(libs.grpc.stub)
- implementation(libs.grpc.kotlin.stub)
- implementation(libs.grpc.protobuf.lite)
- implementation(libs.protobuf.kotlin.lite)
+ implementation(libs.wire.runtime)
+ implementation(libs.wire.grpc)
+ implementation(libs.junixsocket.core)
+ // implementation(libs.junixsocket.native.android)
+ implementation("com.kohlschutter.junixsocket:junixsocket-native-android:2.10.1@aar")
+ implementation(libs.okhttp.logging.interceptor)
+ implementation(libs.jnr.unixsocket)
implementation(libs.arrow)
implementation(libs.arrow.optics)
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt
index 00a8ba3fc9..0061be8f25 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt
@@ -1,6 +1,5 @@
package net.mullvad.mullvadvpn.lib.daemon.grpc
-import android.net.LocalSocketAddress
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensure
@@ -8,20 +7,17 @@ import arrow.optics.copy
import arrow.optics.dsl.index
import arrow.optics.typeclasses.Index
import co.touchlab.kermit.Logger
-import com.google.protobuf.Empty
-import io.grpc.ConnectivityState
-import io.grpc.Status
-import io.grpc.StatusException
-import io.grpc.android.UdsChannelBuilder
+import com.squareup.wire.GrpcClient
import java.io.File
import java.net.InetAddress
import java.util.Map.entry
+import java.util.concurrent.TimeUnit
import java.util.logging.Level
import java.util.logging.Logger as JavaLogger
+import kotlin.getValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
-import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
@@ -30,19 +26,24 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import mullvad_daemon.management_interface.ManagementInterface
-import mullvad_daemon.management_interface.ManagementServiceGrpcKt
+import mullvad_daemon.management_interface.BoolValue
+import mullvad_daemon.management_interface.Device
+import mullvad_daemon.management_interface.DeviceRemoval
+import mullvad_daemon.management_interface.ManagementServiceClient
+import mullvad_daemon.management_interface.NewCustomList
+import mullvad_daemon.management_interface.StringValue
+import mullvad_daemon.management_interface.UInt32Value
import net.mullvad.mullvadvpn.lib.daemon.grpc.mapper.fromDomain
import net.mullvad.mullvadvpn.lib.daemon.grpc.mapper.toDomain
import net.mullvad.mullvadvpn.lib.daemon.grpc.util.AndroidLoggingHandler
-import net.mullvad.mullvadvpn.lib.daemon.grpc.util.LogInterceptor
+import net.mullvad.mullvadvpn.lib.daemon.grpc.util.UnixDomainSocketFactory
import net.mullvad.mullvadvpn.lib.daemon.grpc.util.connectivityFlow
import net.mullvad.mullvadvpn.lib.model.AccountData
import net.mullvad.mullvadvpn.lib.model.AccountNumber
@@ -66,7 +67,7 @@ import net.mullvad.mullvadvpn.lib.model.CustomListName
import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions
import net.mullvad.mullvadvpn.lib.model.DeleteCustomListError
import net.mullvad.mullvadvpn.lib.model.DeleteDeviceError
-import net.mullvad.mullvadvpn.lib.model.Device
+import net.mullvad.mullvadvpn.lib.model.Device as ModelDevice
import net.mullvad.mullvadvpn.lib.model.DeviceId
import net.mullvad.mullvadvpn.lib.model.DeviceState as ModelDeviceState
import net.mullvad.mullvadvpn.lib.model.DeviceUpdateError
@@ -144,6 +145,10 @@ import net.mullvad.mullvadvpn.lib.model.state
import net.mullvad.mullvadvpn.lib.model.udp2tcp
import net.mullvad.mullvadvpn.lib.model.wireguardConstraints
import net.mullvad.mullvadvpn.lib.model.wireguardPort
+import okhttp3.OkHttpClient
+import okhttp3.Protocol
+import okhttp3.logging.HttpLoggingInterceptor
+import org.newsclub.net.unix.AFUNIXSocketAddress
@Suppress("TooManyFunctions", "LargeClass")
class ManagementService(
@@ -154,33 +159,21 @@ class ManagementService(
private var job: Job? = null
// We expect daemon to create the rpc socket file on the path provided on initialisation
- @Suppress("DEPRECATION")
- private val channel =
- UdsChannelBuilder.forPath(
- rpcSocketFile.absolutePath,
- LocalSocketAddress.Namespace.FILESYSTEM,
- )
- // Workaround for handling WiFi with proxy
- // https://github.com/grpc/grpc-java/issues/11922
- .proxyDetector { null }
- .build()
+ @Suppress("DEPRECATION") private val channel = socketClient(rpcSocketFile)
val connectionState: StateFlow<GrpcConnectivityState> =
channel
.connectivityFlow()
- .map(ConnectivityState::toDomain)
.onEach { Logger.i("ManagementService connection state: $it") }
- .stateIn(scope, SharingStarted.Eagerly, channel.getState(false).toDomain())
+ .stateIn(scope, SharingStarted.Eagerly, GrpcConnectivityState.Ready)
- private val grpc by lazy {
- ManagementServiceGrpcKt.ManagementServiceCoroutineStub(channel)
- .withExecutor(Dispatchers.IO.asExecutor())
- .let {
- if (extensiveLogging) {
- it.withInterceptors(LogInterceptor())
- } else it
- }
- .withWaitForReady()
+ private val grpc: ManagementServiceClient by lazy {
+ GrpcClient.Builder()
+ .client(channel)
+ .baseUrl("http://localhost/")
+ .minMessageToCompress(Long.MAX_VALUE)
+ .build()
+ .create(ManagementServiceClient::class)
}
private val _mutableDeviceState = MutableStateFlow<ModelDeviceState?>(null)
@@ -231,33 +224,47 @@ class ManagementService(
job = null
}
- fun enterIdle() = channel.enterIdle()
+ fun enterIdle() = { /*NO-OP*/ }
+ @Suppress("DEPRECATION")
private suspend fun subscribeEvents() =
withContext(Dispatchers.IO) {
launch {
- grpc.eventsListen(Empty.getDefaultInstance()).collect { event ->
+ val channel = grpc.EventsListen().executeIn(this, Unit)
+ // channels.first.send(Unit)
+ /*launch {
+ while(true) {
+ getInitialServiceState()
+ delay(100)
+ }
+ }*/
+ /*launch {
+ val c = grpc.EventsListen().executeBlocking(request = Unit)
+ Logger.d("LOLZ R ${c.read()}")
+ }*/
+ // launch { Logger.d("LOLZ ${channel.receive()}") }
+ channel.receiveAsFlow().collect { event ->
if (extensiveLogging) {
Logger.v("Event: $event")
}
@Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA")
- when (event.eventCase) {
- ManagementInterface.DaemonEvent.EventCase.TUNNEL_STATE ->
- _mutableTunnelState.update { event.tunnelState.toDomain() }
- ManagementInterface.DaemonEvent.EventCase.SETTINGS ->
+ when {
+ event.tunnel_state != null ->
+ _mutableTunnelState.update { event.tunnel_state.toDomain() }
+ event.settings != null ->
_mutableSettings.update { event.settings.toDomain() }
- ManagementInterface.DaemonEvent.EventCase.RELAY_LIST ->
- _mutableRelayList.update { event.relayList.toDomain() }
- ManagementInterface.DaemonEvent.EventCase.VERSION_INFO ->
- _mutableVersionInfo.update { event.versionInfo.toDomain() }
- ManagementInterface.DaemonEvent.EventCase.DEVICE ->
- _mutableDeviceState.update { event.device.newState.toDomain() }
- ManagementInterface.DaemonEvent.EventCase.NEW_ACCESS_METHOD -> {
- _mutableCurrentAccessMethod.update { event.newAccessMethod.toDomain() }
+ event.relay_list != null ->
+ _mutableRelayList.update { event.relay_list.toDomain() }
+ event.version_info != null ->
+ _mutableVersionInfo.update { event.version_info.toDomain() }
+ event.device != null && event.device.new_state != null ->
+ _mutableDeviceState.update { event.device.new_state.toDomain() }
+ event.new_access_method != null -> {
+ _mutableCurrentAccessMethod.update {
+ event.new_access_method.toDomain()
+ }
}
- ManagementInterface.DaemonEvent.EventCase.REMOVE_DEVICE -> {}
- ManagementInterface.DaemonEvent.EventCase.LEAK_INFO -> {}
- ManagementInterface.DaemonEvent.EventCase.EVENT_NOT_SET -> {}
+ event.remove_device != null -> {}
}
}
}
@@ -265,20 +272,19 @@ class ManagementService(
}
suspend fun getDevice(): Either<GetDeviceStateError, ModelDeviceState> =
- Either.catch { grpc.getDevice(Empty.getDefaultInstance()) }
+ Either.catch { grpc.GetDevice().execute(Unit) }
.map { it.toDomain() }
.onLeft { Logger.e("Get device error") }
.mapLeft { GetDeviceStateError.Unknown(it) }
suspend fun updateDevice(): Either<DeviceUpdateError, Unit> =
- Either.catch { grpc.updateDevice(Empty.getDefaultInstance()) }
- .mapEmpty()
+ Either.catch { grpc.UpdateDevice().execute(Unit) }
.onLeft { Logger.e("Update device error") }
.mapLeft { DeviceUpdateError(it) }
- suspend fun getDeviceList(token: AccountNumber): Either<GetDeviceListError, List<Device>> =
- Either.catch { grpc.listDevices(token.value.toStringValue()) }
- .map { it.devicesList.map(ManagementInterface.Device::toDomain) }
+ suspend fun getDeviceList(token: AccountNumber): Either<GetDeviceListError, List<ModelDevice>> =
+ Either.catch { grpc.ListDevices().execute(token.value.toStringValue()) }
+ .map { it.devices.map(Device::toDomain) }
.onLeft { Logger.e("Get device list error") }
.mapLeft { GetDeviceListError.Unknown(it) }
@@ -287,64 +293,63 @@ class ManagementService(
deviceId: DeviceId,
): Either<DeleteDeviceError, Unit> =
Either.catch {
- grpc.removeDevice(
- ManagementInterface.DeviceRemoval.newBuilder()
- .setAccountNumber(token.value)
- .setDeviceId(deviceId.value.toString())
- .build()
- )
+ grpc
+ .RemoveDevice()
+ .execute(
+ DeviceRemoval(
+ account_number = token.value,
+ device_id = deviceId.value.toString(),
+ )
+ )
}
- .mapEmpty()
.onLeft { Logger.e("Remove device error") }
.mapLeft { DeleteDeviceError.Unknown(it) }
suspend fun connect(): Either<ConnectError, Boolean> =
- Either.catch { grpc.connectTunnel(Empty.getDefaultInstance()).value }
+ Either.catch { grpc.ConnectTunnel().execute(Unit).toBool() }
.onLeft { Logger.e("Connect error") }
.mapLeft(ConnectError::Unknown)
suspend fun disconnect(): Either<ConnectError, Boolean> =
- Either.catch { grpc.disconnectTunnel(Empty.getDefaultInstance()).value }
+ Either.catch { grpc.DisconnectTunnel().execute(Unit).toBool() }
.onLeft { Logger.e("Disconnect error") }
.mapLeft(ConnectError::Unknown)
suspend fun reconnect(): Either<ConnectError, Boolean> =
- Either.catch { grpc.reconnectTunnel(Empty.getDefaultInstance()).value }
+ Either.catch { grpc.ReconnectTunnel().execute(Unit).toBool() }
.onLeft { Logger.e("Reconnect error") }
.mapLeft(ConnectError::Unknown)
private suspend fun getTunnelState(): ModelTunnelState =
- grpc.getTunnelState(Empty.getDefaultInstance()).toDomain()
+ grpc.GetTunnelState().execute(Unit).toDomain()
- private suspend fun getSettings(): ModelSettings =
- grpc.getSettings(Empty.getDefaultInstance()).toDomain()
+ private suspend fun getSettings(): ModelSettings = grpc.GetSettings().execute(Unit).toDomain()
private suspend fun getDeviceState(): ModelDeviceState =
- grpc.getDevice(Empty.getDefaultInstance()).toDomain()
+ grpc.GetDevice().execute(Unit).toDomain()
private suspend fun getRelayList(): ModelRelayList =
- grpc.getRelayLocations(Empty.getDefaultInstance()).toDomain()
+ grpc.GetRelayLocations().execute(Unit).toDomain()
// On release build this will return error until services have published the new beta, daemon
// will get 404 until the api have been published, thus we need to ignore error downstream.
private suspend fun getVersionInfo(): Either<GetVersionInfoError, ModelAppVersionInfo> =
- Either.catch { grpc.getVersionInfo(Empty.getDefaultInstance()).toDomain() }
+ Either.catch { grpc.GetVersionInfo().execute(Unit).toDomain() }
.onLeft { Logger.e("Get version info error") }
.mapLeft { GetVersionInfoError.Unknown(it) }
private suspend fun getCurrentApiAccessMethod(): ApiAccessMethodSetting =
- grpc.getCurrentApiAccessMethod(Empty.getDefaultInstance()).toDomain()
+ grpc.GetCurrentApiAccessMethod().execute(Unit).toDomain()
suspend fun logoutAccount(): Either<LogoutAccountError, Unit> =
- Either.catch { grpc.logoutAccount(Empty.getDefaultInstance()) }
+ Either.catch { grpc.LogoutAccount().execute(Unit) }
.onLeft { Logger.e("Logout account error") }
.mapLeft(LogoutAccountError::Unknown)
- .mapEmpty()
suspend fun loginAccount(accountNumber: AccountNumber): Either<LoginAccountError, Unit> =
- Either.catch { grpc.loginAccount(accountNumber.value.toStringValue()) }
+ Either.catch { grpc.LoginAccount().execute(accountNumber.value.toStringValue()) }
.mapLeftStatus {
- when (it.status.code) {
+ /*when (it.status.code) {
Status.Code.UNAUTHENTICATED -> LoginAccountError.InvalidAccount
Status.Code.RESOURCE_EXHAUSTED if it.status.isTooManyRequests() ->
LoginAccountError.TooManyAttempts
@@ -357,21 +362,20 @@ class ManagementService(
Logger.e("Unknown login account error")
LoginAccountError.Unknown(it)
}
- }
+ }*/
+ LoginAccountError.InvalidAccount
}
- .mapEmpty()
suspend fun clearAccountHistory(): Either<ClearAccountHistoryError, Unit> =
- Either.catch { grpc.clearAccountHistory(Empty.getDefaultInstance()) }
+ Either.catch { grpc.ClearAccountHistory().execute(Unit) }
.onLeft { Logger.e("Clear account history error") }
.mapLeft(ClearAccountHistoryError::Unknown)
- .mapEmpty()
suspend fun getAccountHistory(): Either<GetAccountHistoryError, AccountNumber?> =
Either.catch {
- val history = grpc.getAccountHistory(Empty.getDefaultInstance())
- if (history.hasNumber()) {
- AccountNumber(history.number.value)
+ val history = grpc.GetAccountHistory().execute(Unit)
+ if (history.number != null) {
+ AccountNumber(history.number.value_)
} else {
null
}
@@ -396,26 +400,30 @@ class ManagementService(
accountNumber: AccountNumber
): Either<GetAccountDataError, AccountData> =
Either.catch {
- grpc.getAccountData(accountNumber.value.toStringValue()).toDomain(accountNumber)
+ grpc
+ .GetAccountData()
+ .execute(accountNumber.value.toStringValue())
+ .toDomain(accountNumber)
}
.onLeft { Logger.e("Get account data error") }
.mapLeft(GetAccountDataError::Unknown)
suspend fun createAccount(): Either<CreateAccountError, AccountNumber> =
Either.catch {
- val accountNumberStringValue = grpc.createNewAccount(Empty.getDefaultInstance())
- AccountNumber(accountNumberStringValue.value)
+ val accountNumberStringValue = grpc.CreateNewAccount().execute(Unit)
+ AccountNumber(accountNumberStringValue.value_)
}
.onLeft { Logger.e("Create account error") }
.mapLeftStatus {
- when (it.status.code) {
+ /*when (it.status.code) {
Status.Code.RESOURCE_EXHAUSTED -> CreateAccountError.TooManyAttempts
Status.Code.UNAVAILABLE -> CreateAccountError.ApiUnreachable
Status.Code.DEADLINE_EXCEEDED -> CreateAccountError.TimeOut
else -> {
CreateAccountError.Unknown(it)
}
- }
+ }*/
+ CreateAccountError.TooManyAttempts
}
suspend fun updateDnsContentBlockers(
@@ -425,27 +433,24 @@ class ManagementService(
val currentDnsOptions = getSettings().tunnelOptions.dnsOptions
val newDefaultDnsOptions = update(currentDnsOptions.defaultOptions)
val updated = DnsOptions.defaultOptions.set(currentDnsOptions, newDefaultDnsOptions)
- grpc.setDnsOptions(updated.fromDomain())
+ grpc.SetDnsOptions().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set dns state error") }
.mapLeft(SetDnsOptionsError::Unknown)
- .mapEmpty()
suspend fun setDnsOptions(dnsOptions: ModelDnsOptions): Either<SetDnsOptionsError, Unit> =
- Either.catch { grpc.setDnsOptions(dnsOptions.fromDomain()) }
+ Either.catch { grpc.SetDnsOptions().execute(dnsOptions.fromDomain()) }
.onLeft { Logger.e("Set dns options error") }
.mapLeft(SetDnsOptionsError::Unknown)
- .mapEmpty()
suspend fun setDnsState(dnsState: ModelDnsState): Either<SetDnsOptionsError, Unit> =
Either.catch {
val currentDnsOptions = getSettings().tunnelOptions.dnsOptions
val updated = DnsOptions.state.set(currentDnsOptions, dnsState)
- grpc.setDnsOptions(updated.fromDomain())
+ grpc.SetDnsOptions().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set dns state error") }
.mapLeft(SetDnsOptionsError::Unknown)
- .mapEmpty()
suspend fun setCustomDns(index: Int, address: InetAddress): Either<SetDnsOptionsError, Unit> =
Either.catch {
@@ -455,11 +460,10 @@ class ManagementService(
.index(Index.list(), index)
.set(currentDnsOptions, address)
- grpc.setDnsOptions(updatedDnsOptions.fromDomain())
+ grpc.SetDnsOptions().execute(updatedDnsOptions.fromDomain())
}
.onLeft { Logger.e("Set custom dns error") }
.mapLeft(SetDnsOptionsError::Unknown)
- .mapEmpty()
suspend fun addCustomDns(address: InetAddress): Either<SetDnsOptionsError, Int> =
Either.catch {
@@ -473,7 +477,7 @@ class ManagementService(
if (currentDnsOptions.customOptions.addresses.isEmpty()) DnsState.Custom
else currentDnsOptions.state
}
- grpc.setDnsOptions(updatedDnsOptions.fromDomain())
+ grpc.SetDnsOptions().execute(updatedDnsOptions.fromDomain())
updatedDnsOptions.customOptions.addresses.lastIndex
}
.onLeft { Logger.e("Add custom dns error") }
@@ -493,35 +497,27 @@ class ManagementService(
if (mutableAddresses.isEmpty()) DnsState.Default
else currentDnsOptions.state
}
- grpc.setDnsOptions(updatedDnsOptions.fromDomain())
+ grpc.SetDnsOptions().execute(updatedDnsOptions.fromDomain())
}
.onLeft { Logger.e("Delete custom dns error") }
.mapLeft(SetDnsOptionsError::Unknown)
- .mapEmpty()
suspend fun setWireguardMtu(value: Int): Either<SetWireguardMtuError, Unit> =
- Either.catch { grpc.setWireguardMtu(value.toUInt32Value()) }
+ Either.catch { grpc.SetWireguardMtu().execute(value.toUInt32Value()) }
.onLeft { Logger.e("Set wireguard mtu error") }
.mapLeft(SetWireguardMtuError::Unknown)
- .mapEmpty()
suspend fun resetWireguardMtu(): Either<SetWireguardMtuError, Unit> =
- Either.catch {
- grpc.setWireguardMtu(
- ManagementInterface.UInt32Value.newBuilder().clearValue().build()
- )
- }
+ Either.catch { grpc.SetWireguardMtu().execute(UInt32Value()) }
.onLeft { Logger.e("Reset wireguard mtu error") }
.mapLeft(SetWireguardMtuError::Unknown)
- .mapEmpty()
suspend fun setWireguardQuantumResistant(
value: ModelQuantumResistantState
): Either<SetWireguardQuantumResistantError, Unit> =
- Either.catch { grpc.setQuantumResistantTunnel(value.toDomain()) }
+ Either.catch { grpc.SetQuantumResistantTunnel().execute(value.fromDomain()) }
.onLeft { Logger.e("Set wireguard quantum resistant error") }
.mapLeft(SetWireguardQuantumResistantError::Unknown)
- .mapEmpty()
suspend fun setObfuscation(value: ObfuscationMode): Either<SetObfuscationOptionsError, Unit> =
Either.catch {
@@ -531,11 +527,10 @@ class ManagementService(
) {
value
}
- grpc.setObfuscationSettings(updatedObfuscationSettings.fromDomain())
+ grpc.SetObfuscationSettings().execute(updatedObfuscationSettings.fromDomain())
}
.onLeft { Logger.e("Set obfuscation error") }
.mapLeft(SetObfuscationOptionsError::Unknown)
- .mapEmpty()
suspend fun setWireguardObfuscationPort(
portConstraint: Constraint<Port>
@@ -545,11 +540,10 @@ class ManagementService(
ObfuscationSettings.wireguardPort.modify(getSettings().obfuscationSettings) {
portConstraint
}
- grpc.setObfuscationSettings(updatedSettings.fromDomain())
+ grpc.SetObfuscationSettings().execute(updatedSettings.fromDomain())
}
.onLeft { Logger.e("Set wireguard port error") }
.mapLeft(SetObfuscationOptionsError::Unknown)
- .mapEmpty()
suspend fun setUdp2TcpObfuscationPort(
portConstraint: Constraint<Port>
@@ -559,11 +553,10 @@ class ManagementService(
ObfuscationSettings.udp2tcp.modify(getSettings().obfuscationSettings) {
it.copy(port = portConstraint)
}
- grpc.setObfuscationSettings(updatedSettings.fromDomain())
+ grpc.SetObfuscationSettings().execute(updatedSettings.fromDomain())
}
.onLeft { Logger.e("Set obfuscation port error") }
.mapLeft(SetObfuscationOptionsError::Unknown)
- .mapEmpty()
suspend fun setShadowsocksObfuscationPort(
portConstraint: Constraint<Port>
@@ -573,26 +566,22 @@ class ManagementService(
ObfuscationSettings.shadowsocks.modify(getSettings().obfuscationSettings) {
it.copy(port = portConstraint)
}
- grpc.setObfuscationSettings(updatedSettings.fromDomain())
+ grpc.SetObfuscationSettings().execute(updatedSettings.fromDomain())
}
.mapLeft(SetObfuscationOptionsError::Unknown)
- .mapEmpty()
suspend fun setAllowLan(allow: Boolean): Either<SetAllowLanError, Unit> =
- Either.catch { grpc.setAllowLan(allow.toBoolValue()) }
+ Either.catch { grpc.SetAllowLan().execute(allow.toBoolValue()) }
.onLeft { Logger.e("Set allow lan error") }
.mapLeft(SetAllowLanError::Unknown)
- .mapEmpty()
suspend fun setDaitaEnabled(enabled: Boolean): Either<SetDaitaSettingsError, Unit> =
- Either.catch { grpc.setEnableDaita(enabled.toBoolValue()) }
+ Either.catch { grpc.SetEnableDaita().execute(enabled.toBoolValue()) }
.mapLeft(SetDaitaSettingsError::Unknown)
- .mapEmpty()
suspend fun setDaitaDirectOnly(enabled: Boolean): Either<SetDaitaSettingsError, Unit> =
- Either.catch { grpc.setDaitaDirectOnly(enabled.toBoolValue()) }
+ Either.catch { grpc.SetDaitaDirectOnly().execute(enabled.toBoolValue()) }
.mapLeft(SetDaitaSettingsError::Unknown)
- .mapEmpty()
suspend fun setRelayLocation(location: ModelRelayItemId): Either<SetRelayLocationError, Unit> =
Either.catch {
@@ -602,11 +591,10 @@ class ManagementService(
currentRelaySettings,
Constraint.Only(location),
)
- grpc.setRelaySettings(updatedRelaySettings.fromDomain())
+ grpc.SetRelaySettings().execute(updatedRelaySettings.fromDomain())
}
.onLeft { Logger.e("Set relay location error") }
.mapLeft(SetRelayLocationError::Unknown)
- .mapEmpty()
suspend fun setRelayLocationMultihop(
isMultihopEnabled: Boolean,
@@ -628,73 +616,73 @@ class ManagementService(
isMultihopEnabled
}
}
- grpc.setRelaySettings(updatedRelaySettings.fromDomain())
+ grpc.SetRelaySettings().execute(updatedRelaySettings.fromDomain())
}
.onLeft { Logger.e("Set relay multihop error") }
.mapLeft(SetRelayLocationError::Unknown)
- .mapEmpty()
suspend fun createCustomList(
name: CustomListName,
locations: List<GeoLocationId> = emptyList(),
): Either<CreateCustomListError, CustomListId> =
Either.catch {
- grpc.createCustomList(
- ManagementInterface.NewCustomList.newBuilder()
- .setName(name.value)
- .addAllLocations(locations.map(GeoLocationId::fromDomain))
- .build()
- )
+ grpc
+ .CreateCustomList()
+ .execute(
+ NewCustomList(
+ name = name.value,
+ locations = locations.map(GeoLocationId::fromDomain),
+ )
+ )
}
- .map { CustomListId(it.value) }
+ .map { CustomListId(it.value_) }
.mapLeftStatus {
- when (it.status.code) {
+ /*when (it.status.code) {
Status.Code.ALREADY_EXISTS -> CustomListAlreadyExists
else -> {
Logger.e("Unknown create custom list error")
UnknownCustomListError(it)
}
- }
+ }*/
+ CustomListAlreadyExists
}
suspend fun updateCustomList(customList: ModelCustomList): Either<UpdateCustomListError, Unit> =
- Either.catch { grpc.updateCustomList(customList.fromDomain()) }
+ Either.catch { grpc.UpdateCustomList().execute(customList.fromDomain()) }
.mapLeftStatus {
- when (it.status.code) {
+ /*when (it.status.code) {
Status.Code.ALREADY_EXISTS -> NameAlreadyExists(customList.name)
else -> {
Logger.e("Unknown update custom list error")
UnknownCustomListError(it)
}
- }
+ }*/
+ NameAlreadyExists(customList.name)
}
- .mapEmpty()
suspend fun deleteCustomList(id: CustomListId): Either<DeleteCustomListError, Unit> =
- Either.catch { grpc.deleteCustomList(id.value.toStringValue()) }
+ Either.catch { grpc.DeleteCustomList().execute(id.value.toStringValue()) }
.onLeft { Logger.e("Delete custom list error") }
.mapLeft(::UnknownCustomListError)
- .mapEmpty()
suspend fun clearAllRelayOverrides(): Either<ClearAllOverridesError, Unit> =
- Either.catch { grpc.clearAllRelayOverrides(Empty.getDefaultInstance()) }
+ Either.catch { grpc.ClearAllRelayOverrides().execute(Unit) }
.onLeft { Logger.e("Clear all relay overrides error") }
.mapLeft(ClearAllOverridesError::Unknown)
- .mapEmpty()
suspend fun applySettingsPatch(json: String): Either<SettingsPatchError, Unit> =
- Either.catch { grpc.applyJsonSettings(json.toStringValue()) }
+ Either.catch { grpc.ApplyJsonSettings().execute(json.toStringValue()) }
.mapLeftStatus {
- when (it.status.code) {
+ /*when (it.status.code) {
// Currently we only get invalid argument errors from daemon via gRPC
Status.Code.INVALID_ARGUMENT -> SettingsPatchError.ParsePatch
else -> {
Logger.e("Unknown apply settings patch error")
SettingsPatchError.ApplyPatch
}
- }
+ }*/
+ SettingsPatchError.ApplyPatch
}
- .mapEmpty()
suspend fun setOwnershipAndProviders(
ownershipConstraint: Constraint<ModelOwnership>,
@@ -709,11 +697,10 @@ class ManagementService(
RelayConstraints.ownership set ownershipConstraint
}
}
- grpc.setRelaySettings(updated.fromDomain())
+ grpc.SetRelaySettings().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set ownership and providers error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun setOwnership(
ownership: Constraint<ModelOwnership>
@@ -721,11 +708,10 @@ class ManagementService(
Either.catch {
val relaySettings = getSettings().relaySettings
val updated = RelaySettings.relayConstraints.ownership.set(relaySettings, ownership)
- grpc.setRelaySettings(updated.fromDomain())
+ grpc.SetRelaySettings().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set ownership error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun setProviders(
providersConstraint: Constraint<Providers>
@@ -734,18 +720,17 @@ class ManagementService(
val relaySettings = getSettings().relaySettings
val updated =
RelaySettings.relayConstraints.providers.set(relaySettings, providersConstraint)
- grpc.setRelaySettings(updated.fromDomain())
+ grpc.SetRelaySettings().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set providers error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun submitVoucher(
voucher: VoucherCode
): Either<RedeemVoucherError, RedeemVoucherSuccess> =
- Either.catch { grpc.submitVoucher(voucher.value.toStringValue()).toDomain() }
+ Either.catch { grpc.SubmitVoucher().execute(voucher.value.toStringValue()).toDomain() }
.mapLeftStatus {
- when (it.status.code) {
+ /*when (it.status.code) {
Status.Code.INVALID_ARGUMENT,
Status.Code.NOT_FOUND -> RedeemVoucherError.InvalidVoucher
Status.Code.ALREADY_EXISTS,
@@ -755,95 +740,89 @@ class ManagementService(
Logger.e("Unknown submit voucher error")
RedeemVoucherError.Unknown(it)
}
- }
+ }*/
+ RedeemVoucherError.Unknown(Throwable())
}
suspend fun initializePlayPurchase(): Either<PlayPurchaseInitError, PlayPurchasePaymentToken> =
- Either.catch { grpc.initPlayPurchase(Empty.getDefaultInstance()).toDomain() }
+ Either.catch { grpc.InitPlayPurchase().execute(Unit).toDomain() }
.onLeft { Logger.e("Initialize play purchase error") }
.mapLeft { PlayPurchaseInitError.OtherError }
suspend fun verifyPlayPurchase(purchase: PlayPurchase): Either<PlayPurchaseVerifyError, Unit> =
- Either.catch { grpc.verifyPlayPurchase(purchase.fromDomain()) }
+ Either.catch { grpc.VerifyPlayPurchase().execute(purchase.fromDomain()) }
.onLeft { Logger.e("Verify play purchase error") }
.mapLeft { PlayPurchaseVerifyError.OtherError }
- .mapEmpty()
suspend fun addSplitTunnelingApp(app: AppId): Either<AddSplitTunnelingAppError, Unit> =
- Either.catch { grpc.addSplitTunnelApp(app.value.toStringValue()) }
+ Either.catch { grpc.AddSplitTunnelApp().execute(app.value.toStringValue()) }
.onLeft { Logger.e("Add split tunneling app error") }
.mapLeft(AddSplitTunnelingAppError::Unknown)
- .mapEmpty()
suspend fun removeSplitTunnelingApp(app: AppId): Either<RemoveSplitTunnelingAppError, Unit> =
- Either.catch { grpc.removeSplitTunnelApp(app.value.toStringValue()) }
+ Either.catch { grpc.RemoveSplitTunnelApp().execute(app.value.toStringValue()) }
.onLeft { Logger.e("Remove split tunneling app error") }
.mapLeft(RemoveSplitTunnelingAppError::Unknown)
- .mapEmpty()
suspend fun setSplitTunnelingState(
enabled: Boolean
): Either<RemoveSplitTunnelingAppError, Unit> =
- Either.catch { grpc.setSplitTunnelState(enabled.toBoolValue()) }
+ Either.catch { grpc.SetSplitTunnelState().execute(enabled.toBoolValue()) }
.onLeft { Logger.e("Set split tunneling state error") }
.mapLeft(RemoveSplitTunnelingAppError::Unknown)
- .mapEmpty()
suspend fun getWebsiteAuthToken(): Either<Throwable, WebsiteAuthToken> =
- Either.catch { grpc.getWwwAuthToken(Empty.getDefaultInstance()) }
+ Either.catch { grpc.GetWwwAuthToken().execute(Unit) }
.onLeft { Logger.e("Get website auth token error") }
- .map { WebsiteAuthToken.fromString(it.value) }
+ .map { WebsiteAuthToken.fromString(it.value_) }
suspend fun addApiAccessMethod(
newAccessMethodSetting: NewAccessMethodSetting
): Either<AddApiAccessMethodError, ApiAccessMethodId> =
- Either.catch { grpc.addApiAccessMethod(newAccessMethodSetting.fromDomain()) }
+ Either.catch { grpc.AddApiAccessMethod().execute(newAccessMethodSetting.fromDomain()) }
.onLeft { Logger.e("Add api access method error") }
.mapLeft(AddApiAccessMethodError::Unknown)
- .map { ApiAccessMethodId.fromString(it.value) }
+ .map { ApiAccessMethodId.fromString(it.value_) }
suspend fun removeApiAccessMethod(
apiAccessMethodId: ApiAccessMethodId
): Either<RemoveApiAccessMethodError, Unit> =
- Either.catch { grpc.removeApiAccessMethod(apiAccessMethodId.fromDomain()) }
+ Either.catch { grpc.RemoveApiAccessMethod().execute(apiAccessMethodId.fromDomain()) }
.onLeft { Logger.e("Remove api access method error") }
.mapLeft(RemoveApiAccessMethodError::Unknown)
- .mapEmpty()
suspend fun setApiAccessMethod(
apiAccessMethodId: ApiAccessMethodId
): Either<SetApiAccessMethodError, Unit> =
- Either.catch { grpc.setApiAccessMethod(apiAccessMethodId.fromDomain()) }
+ Either.catch { grpc.SetApiAccessMethod().execute(apiAccessMethodId.fromDomain()) }
.onLeft { Logger.e("Set api access method error") }
.mapLeft(SetApiAccessMethodError::Unknown)
- .mapEmpty()
suspend fun updateApiAccessMethod(
apiAccessMethodSetting: ApiAccessMethodSetting
): Either<UpdateApiAccessMethodError, Unit> =
- Either.catch { grpc.updateApiAccessMethod(apiAccessMethodSetting.fromDomain()) }
+ Either.catch { grpc.UpdateApiAccessMethod().execute(apiAccessMethodSetting.fromDomain()) }
.onLeft { Logger.e("Update api access method error") }
.mapLeft(::UnknownApiAccessMethodError)
- .mapEmpty()
suspend fun testCustomApiAccessMethod(
customProxy: ApiAccessMethod.CustomProxy
): Either<TestApiAccessMethodError, Unit> =
- Either.catch { grpc.testCustomApiAccessMethod(customProxy.fromDomain()) }
+ Either.catch { grpc.TestCustomApiAccessMethod().execute(customProxy.fromDomain()) }
.onLeft { Logger.e("Test custom api access method error") }
.mapLeftStatus { TestApiAccessMethodError.Grpc }
.map { result ->
- either { ensure(result.value) { TestApiAccessMethodError.CouldNotAccess } }
+ either { ensure(result.value_) { TestApiAccessMethodError.CouldNotAccess } }
}
suspend fun testApiAccessMethodById(
apiAccessMethodId: ApiAccessMethodId
): Either<TestApiAccessMethodError, Unit> =
- Either.catch { grpc.testApiAccessMethodById(apiAccessMethodId.fromDomain()) }
+ Either.catch { grpc.TestApiAccessMethodById().execute(apiAccessMethodId.fromDomain()) }
.onLeft { Logger.e("Test api access method error") }
.mapLeftStatus { TestApiAccessMethodError.Grpc }
.map { result ->
- either { ensure(result.value) { TestApiAccessMethodError.CouldNotAccess } }
+ either { ensure(result.value_) { TestApiAccessMethodError.CouldNotAccess } }
}
suspend fun setMultihop(enabled: Boolean): Either<SetWireguardConstraintsError, Unit> =
@@ -854,11 +833,10 @@ class ManagementService(
relaySettings,
enabled,
)
- grpc.setRelaySettings(updated.fromDomain())
+ grpc.SetRelaySettings().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set multihop error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun setEntryLocation(
entryLocation: RelayItemId
@@ -870,11 +848,10 @@ class ManagementService(
relaySettings,
Constraint.Only(entryLocation),
)
- grpc.setRelaySettings(updated.fromDomain())
+ grpc.SetRelaySettings().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set multihop error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun setDeviceIpVersion(
ipVersion: Constraint<IpVersion>
@@ -886,27 +863,22 @@ class ManagementService(
relaySettings,
ipVersion,
)
- grpc.setRelaySettings(updated.fromDomain())
+ grpc.SetRelaySettings().execute(updated.fromDomain())
}
.onLeft { Logger.e("Set multihop error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun setIpv6Enabled(enabled: Boolean): Either<SetDaitaSettingsError, Unit> =
- Either.catch { grpc.setEnableIpv6(enabled.toBoolValue()) }
+ Either.catch { grpc.SetEnableIpv6().execute(enabled.toBoolValue()) }
.mapLeft(SetDaitaSettingsError::Unknown)
- .mapEmpty()
suspend fun setRecentsEnabled(enabled: Boolean): Either<SetWireguardConstraintsError, Unit> =
- Either.catch { grpc.setEnableRecents(enabled.toBoolValue()) }
+ Either.catch { grpc.SetEnableRecents().execute(enabled.toBoolValue()) }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
suspend fun updateRelayLocations(): Either<UpdateRelayLocationsError, Unit> =
- Either.catch { grpc.updateRelayLocations(Empty.getDefaultInstance()) }
+ Either.catch { grpc.UpdateRelayLocations().execute(Unit) }
.mapLeft(UpdateRelayLocationsError::Unknown)
- .mapEmpty()
-
suspend fun setMultihopAndEntryLocation(
isMultihopEnabled: Boolean,
@@ -921,23 +893,20 @@ class ManagementService(
WireguardConstraints.isMultihopEnabled set isMultihopEnabled
}
}
- grpc.setRelaySettings(updatedRelaySettings.fromDomain())
+ grpc.SetRelaySettings().execute(updatedRelaySettings.fromDomain())
}
.onLeft { Logger.e("Set multihop error") }
.mapLeft(SetWireguardConstraintsError::Unknown)
- .mapEmpty()
- private fun Boolean.toBoolValue() =
- ManagementInterface.BoolValue.newBuilder().setValue(this).build()
+ private fun Boolean.toBoolValue() = BoolValue(this)
- private fun String.toStringValue() =
- ManagementInterface.StringValue.newBuilder().setValue(this).build()
+ private fun String.toStringValue() = StringValue(this)
- private fun Int.toUInt32Value() = ManagementInterface.UInt32Value.newBuilder().setValue(this).build()
+ private fun Int.toUInt32Value() = UInt32Value(this)
- private fun <A> Either<A, Empty>.mapEmpty() = map {}
+ private fun BoolValue.toBool() = this.value_
- private inline fun <B, C> Either<Throwable, B>.mapLeftStatus(
+ /*private inline fun <B, C> Either<Throwable, B>.mapLeftStatus(
f: (StatusException) -> C
): Either<C, B> = mapLeft {
if (it is StatusException) {
@@ -945,9 +914,35 @@ class ManagementService(
} else {
throw it
}
+ }*/
+
+ private inline fun <B, C> Either<Throwable, B>.mapLeftStatus(f: (Any) -> C): Either<C, B> =
+ mapLeft {
+ f(it)
+ }
+
+ private fun socketClient(rpcSocketFile: File): OkHttpClient {
+ val addr = AFUNIXSocketAddress.of(rpcSocketFile)
+
+ return OkHttpClient.Builder()
+ .socketFactory(socketFactory = UnixDomainSocketFactory(addr))
+ // .socketFactory(socketFactory =
+ // AFSocketFactory.FixedAddressSocketFactory(rpcSocketFile))
+ // .callTimeout(java.time.Duration.ofMinutes(1))
+ .callTimeout(timeout = 0, TimeUnit.MILLISECONDS)
+ .readTimeout(timeout = 0, TimeUnit.MILLISECONDS)
+ .connectTimeout(timeout = 0, TimeUnit.MILLISECONDS)
+ .writeTimeout(timeout = 0, TimeUnit.MILLISECONDS)
+ .webSocketCloseTimeout(timeout = 0, TimeUnit.MILLISECONDS)
+ .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE))
+ .addInterceptor(
+ HttpLoggingInterceptor { message -> Logger.withTag("grpc").d(message) }
+ .also { it.level = HttpLoggingInterceptor.Level.BODY }
+ )
+ .build()
}
- private fun Status.isTooManyRequests() = description == TOO_MANY_REQUESTS
+ // private fun Status.isTooManyRequests() = description == TOO_MANY_REQUESTS
companion object {
const val ENABLE_TRACE_LOGGING = false
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/FromDomain.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/FromDomain.kt
index b0b846a4f8..97437db637 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/FromDomain.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/FromDomain.kt
@@ -1,47 +1,68 @@
package net.mullvad.mullvadvpn.lib.daemon.grpc.mapper
-import mullvad_daemon.management_interface.ManagementInterface
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethod
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodSetting
+import mullvad_daemon.management_interface.AccessMethod
+import mullvad_daemon.management_interface.AccessMethodSetting
+import mullvad_daemon.management_interface.ApiAccessMethodSettings
+import mullvad_daemon.management_interface.CustomDnsOptions
+import mullvad_daemon.management_interface.CustomList
+import mullvad_daemon.management_interface.CustomProxy
+import mullvad_daemon.management_interface.DefaultDnsOptions
+import mullvad_daemon.management_interface.DnsOptions
+import mullvad_daemon.management_interface.GeographicLocationConstraint
+import mullvad_daemon.management_interface.IpVersion
+import mullvad_daemon.management_interface.LocationConstraint
+import mullvad_daemon.management_interface.NewAccessMethodSetting
+import mullvad_daemon.management_interface.NormalRelaySettings
+import mullvad_daemon.management_interface.ObfuscationSettings
+import mullvad_daemon.management_interface.Ownership
+import mullvad_daemon.management_interface.PlayPurchase
+import mullvad_daemon.management_interface.PlayPurchasePaymentToken
+import mullvad_daemon.management_interface.QuantumResistantState
+import mullvad_daemon.management_interface.RelaySettings
+import mullvad_daemon.management_interface.Shadowsocks
+import mullvad_daemon.management_interface.Socks5Remote
+import mullvad_daemon.management_interface.SocksAuth
+import mullvad_daemon.management_interface.UUID
+import mullvad_daemon.management_interface.WireguardConstraints
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethod as ModelApiAccessMethod
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId as ModelApiAccessMethodId
import net.mullvad.mullvadvpn.lib.model.Constraint
-import net.mullvad.mullvadvpn.lib.model.CustomDnsOptions
-import net.mullvad.mullvadvpn.lib.model.CustomList
+import net.mullvad.mullvadvpn.lib.model.CustomDnsOptions as ModelCustomDnsOptions
+import net.mullvad.mullvadvpn.lib.model.CustomList as ModelCustomList
import net.mullvad.mullvadvpn.lib.model.CustomListId
-import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions
-import net.mullvad.mullvadvpn.lib.model.DnsOptions
-import net.mullvad.mullvadvpn.lib.model.DnsState
+import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions as ModelDefaultDnsOptions
+import net.mullvad.mullvadvpn.lib.model.DnsOptions as ModelDnsOptions
+import net.mullvad.mullvadvpn.lib.model.DnsState as ModelDnsState
import net.mullvad.mullvadvpn.lib.model.GeoLocationId
-import net.mullvad.mullvadvpn.lib.model.IpVersion
-import net.mullvad.mullvadvpn.lib.model.NewAccessMethodSetting
+import net.mullvad.mullvadvpn.lib.model.IpVersion as ModelIpVersion
+import net.mullvad.mullvadvpn.lib.model.NewAccessMethodSetting as ModelNewAccessMethodSetting
+import net.mullvad.mullvadvpn.lib.model.ObfuscationMode as ModelObfuscationMode
import net.mullvad.mullvadvpn.lib.model.ObfuscationMode
-import net.mullvad.mullvadvpn.lib.model.ObfuscationSettings
-import net.mullvad.mullvadvpn.lib.model.Ownership
-import net.mullvad.mullvadvpn.lib.model.PlayPurchase
-import net.mullvad.mullvadvpn.lib.model.PlayPurchasePaymentToken
+import net.mullvad.mullvadvpn.lib.model.ObfuscationSettings as ModelObfuscationSettings
+import net.mullvad.mullvadvpn.lib.model.Ownership as ModelOwnership
+import net.mullvad.mullvadvpn.lib.model.PlayPurchase as ModelPlayPurchase
+import net.mullvad.mullvadvpn.lib.model.PlayPurchasePaymentToken as ModelPlayPurchasePaymentToken
import net.mullvad.mullvadvpn.lib.model.Port
import net.mullvad.mullvadvpn.lib.model.Providers
+import net.mullvad.mullvadvpn.lib.model.QuantumResistantState as ModelQuantumResistantState
import net.mullvad.mullvadvpn.lib.model.RelayItemId
-import net.mullvad.mullvadvpn.lib.model.RelaySettings
-import net.mullvad.mullvadvpn.lib.model.ShadowsocksObfuscationSettings
-import net.mullvad.mullvadvpn.lib.model.SocksAuth
+import net.mullvad.mullvadvpn.lib.model.RelaySettings as ModelRelaySettings
+import net.mullvad.mullvadvpn.lib.model.ShadowsocksObfuscationSettings as ModelShadowsocksObfuscationSettings
+import net.mullvad.mullvadvpn.lib.model.SocksAuth as ModelSocksAuth
import net.mullvad.mullvadvpn.lib.model.Udp2TcpObfuscationSettings
-import net.mullvad.mullvadvpn.lib.model.WireguardConstraints
+import net.mullvad.mullvadvpn.lib.model.WireguardConstraints as ModelWireguardConstraints
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodSetting as ModelApiAccessMethodSetting
-internal fun Constraint<RelayItemId>.fromDomain(): ManagementInterface.LocationConstraint =
- ManagementInterface.LocationConstraint.newBuilder()
- .apply {
- when (this@fromDomain) {
- is Constraint.Any -> {}
- is Constraint.Only -> {
- when (val relayItemId = value) {
- is CustomListId -> setCustomList(relayItemId.value)
- is GeoLocationId -> setLocation(relayItemId.fromDomain())
- }
- }
+internal fun Constraint<RelayItemId>.fromDomain(): LocationConstraint =
+ when (this@fromDomain) {
+ is Constraint.Any -> LocationConstraint()
+ is Constraint.Only -> {
+ when (val relayItemId = value) {
+ is CustomListId -> LocationConstraint(custom_list = relayItemId.value)
+ is GeoLocationId -> LocationConstraint(location = relayItemId.fromDomain())
}
}
- .build()
+ }
internal fun Constraint<Providers>.fromDomain(): List<String> =
when (this) {
@@ -49,225 +70,172 @@ internal fun Constraint<Providers>.fromDomain(): List<String> =
is Constraint.Only -> value.map { it.value }
}
-internal fun DnsOptions.fromDomain(): ManagementInterface.DnsOptions =
- ManagementInterface.DnsOptions.newBuilder()
- .setState(state.fromDomain())
- .setCustomOptions(customOptions.fromDomain())
- .setDefaultOptions(defaultOptions.fromDomain())
- .build()
+internal fun ModelDnsOptions.fromDomain(): DnsOptions =
+ DnsOptions(
+ state = state.fromDomain(),
+ custom_options = customOptions.fromDomain(),
+ default_options = defaultOptions.fromDomain(),
+ )
-internal fun DnsState.fromDomain(): ManagementInterface.DnsOptions.DnsState =
+internal fun ModelDnsState.fromDomain(): DnsOptions.DnsState =
when (this) {
- DnsState.Default -> ManagementInterface.DnsOptions.DnsState.DEFAULT
- DnsState.Custom -> ManagementInterface.DnsOptions.DnsState.CUSTOM
+ ModelDnsState.Default -> DnsOptions.DnsState.DEFAULT
+ ModelDnsState.Custom -> DnsOptions.DnsState.CUSTOM
}
-internal fun CustomDnsOptions.fromDomain(): ManagementInterface.CustomDnsOptions =
- ManagementInterface.CustomDnsOptions.newBuilder()
- .addAllAddresses(addresses.map { it.hostAddress })
- .build()
+internal fun ModelCustomDnsOptions.fromDomain(): CustomDnsOptions =
+ CustomDnsOptions(addresses = addresses.mapNotNull { it.hostAddress })
-internal fun DefaultDnsOptions.fromDomain(): ManagementInterface.DefaultDnsOptions =
- ManagementInterface.DefaultDnsOptions.newBuilder()
- .setBlockAds(blockAds)
- .setBlockGambling(blockGambling)
- .setBlockMalware(blockMalware)
- .setBlockTrackers(blockTrackers)
- .setBlockAdultContent(blockAdultContent)
- .setBlockSocialMedia(blockSocialMedia)
- .build()
+internal fun ModelDefaultDnsOptions.fromDomain(): DefaultDnsOptions =
+ DefaultDnsOptions(
+ block_ads = blockAds,
+ block_gambling = blockGambling,
+ block_malware = blockMalware,
+ block_trackers = blockTrackers,
+ block_adult_content = blockAdultContent,
+ block_social_media = blockSocialMedia,
+ )
-internal fun ObfuscationSettings.fromDomain(): ManagementInterface.ObfuscationSettings =
- ManagementInterface.ObfuscationSettings.newBuilder()
- .setSelectedObfuscation(selectedObfuscationMode.fromDomain())
- .setUdp2Tcp(udp2tcp.fromDomain())
- .setShadowsocks(shadowsocks.fromDomain())
- .setWireguardPort(wireguardPort.fromDomain())
- .build()
+internal fun ModelObfuscationSettings.fromDomain(): ObfuscationSettings =
+ ObfuscationSettings(
+ selected_obfuscation = selectedObfuscationMode.fromDomain(),
+ udp2tcp = udp2tcp.fromDomain(),
+ shadowsocks = shadowsocks.fromDomain(),
+ wireguard_port = wireguardPort.fromDomain(),
+ )
-internal fun ObfuscationMode.fromDomain():
- ManagementInterface.ObfuscationSettings.SelectedObfuscation =
+internal fun ModelObfuscationMode.fromDomain(): ObfuscationSettings.SelectedObfuscation =
when (this) {
- ObfuscationMode.Udp2Tcp ->
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.UDP2TCP
- ObfuscationMode.Shadowsocks ->
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.SHADOWSOCKS
- ObfuscationMode.WireguardPort ->
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.WIREGUARD_PORT
- ObfuscationMode.Quic -> ManagementInterface.ObfuscationSettings.SelectedObfuscation.QUIC
- ObfuscationMode.Lwo -> ManagementInterface.ObfuscationSettings.SelectedObfuscation.LWO
- ObfuscationMode.Auto -> ManagementInterface.ObfuscationSettings.SelectedObfuscation.AUTO
- ObfuscationMode.Off -> ManagementInterface.ObfuscationSettings.SelectedObfuscation.OFF
+ ObfuscationMode.Udp2Tcp -> ObfuscationSettings.SelectedObfuscation.UDP2TCP
+ ObfuscationMode.Shadowsocks -> ObfuscationSettings.SelectedObfuscation.SHADOWSOCKS
+ ObfuscationMode.WireguardPort -> ObfuscationSettings.SelectedObfuscation.WIREGUARD_PORT
+ ObfuscationMode.Quic -> ObfuscationSettings.SelectedObfuscation.QUIC
+ ObfuscationMode.Lwo -> ObfuscationSettings.SelectedObfuscation.LWO
+ ObfuscationMode.Auto -> ObfuscationSettings.SelectedObfuscation.AUTO
+ ObfuscationMode.Off -> ObfuscationSettings.SelectedObfuscation.OFF
}
-internal fun Udp2TcpObfuscationSettings.fromDomain():
- ManagementInterface.ObfuscationSettings.Udp2TcpObfuscation =
+internal fun Udp2TcpObfuscationSettings.fromDomain(): ObfuscationSettings.Udp2TcpObfuscation =
when (val port = port) {
- is Constraint.Any ->
- ManagementInterface.ObfuscationSettings.Udp2TcpObfuscation.newBuilder()
- .clearPort()
- .build()
- is Constraint.Only ->
- ManagementInterface.ObfuscationSettings.Udp2TcpObfuscation.newBuilder()
- .setPort(port.value.value)
- .build()
+ is Constraint.Any -> ObfuscationSettings.Udp2TcpObfuscation(port = null)
+ is Constraint.Only -> ObfuscationSettings.Udp2TcpObfuscation(port.value.value)
}
-internal fun Constraint<Port>.fromDomain(): ManagementInterface.ObfuscationSettings.WireguardPort =
+internal fun Constraint<Port>.fromDomain(): ObfuscationSettings.WireguardPort =
when (this) {
- is Constraint.Any ->
- ManagementInterface.ObfuscationSettings.WireguardPort.newBuilder().clearPort()
- is Constraint.Only ->
- ManagementInterface.ObfuscationSettings.WireguardPort.newBuilder()
- .setPort(this.value.value)
- }.build()
+ is Constraint.Any -> ObfuscationSettings.WireguardPort(port = null)
+ is Constraint.Only -> ObfuscationSettings.WireguardPort(this.value.value)
+ }
-internal fun GeoLocationId.fromDomain(): ManagementInterface.GeographicLocationConstraint =
- ManagementInterface.GeographicLocationConstraint.newBuilder()
- .apply {
- when (val id = this@fromDomain) {
- is GeoLocationId.Country -> setCountry(id.code)
- is GeoLocationId.City -> setCountry(id.country.code).setCity(id.code)
- is GeoLocationId.Hostname ->
- setCountry(id.country.code).setCity(id.city.code).setHostname(id.code)
- }
- }
- .build()
+internal fun GeoLocationId.fromDomain(): GeographicLocationConstraint =
+ when (val id = this) {
+ is GeoLocationId.Country -> GeographicLocationConstraint(id.code)
+ is GeoLocationId.City ->
+ GeographicLocationConstraint(country = id.country.code, city = id.code)
+ is GeoLocationId.Hostname ->
+ GeographicLocationConstraint(
+ country = id.country.code,
+ city = id.city.code,
+ hostname = id.code,
+ )
+ }
-internal fun CustomList.fromDomain(): ManagementInterface.CustomList =
- ManagementInterface.CustomList.newBuilder()
- .setId(id.value)
- .setName(name.value)
- .addAllLocations(locations.map { it.fromDomain() })
- .build()
+internal fun ModelWireguardConstraints.fromDomain(): WireguardConstraints =
+ WireguardConstraints(
+ use_multihop = isMultihopEnabled,
+ entry_location = entryLocation.fromDomain(),
+ ip_version = ipVersion.getOrNull()?.fromDomain(),
+ )
-internal fun WireguardConstraints.fromDomain(): ManagementInterface.WireguardConstraints =
- ManagementInterface.WireguardConstraints.newBuilder()
- .setUseMultihop(isMultihopEnabled)
- .setEntryLocation(entryLocation.fromDomain())
- .apply {
- when (val ipVersion = this@fromDomain.ipVersion) {
- is Constraint.Any -> clearIpVersion()
- is Constraint.Only -> setIpVersion(ipVersion.value.fromDomain())
- }
- }
- .build()
+internal fun ModelCustomList.fromDomain(): CustomList =
+ CustomList(id = id.value, name = name.value, locations = locations.map { it.fromDomain() })
-internal fun Ownership.fromDomain(): ManagementInterface.Ownership =
+internal fun ModelOwnership.fromDomain(): Ownership =
when (this) {
- Ownership.MullvadOwned -> ManagementInterface.Ownership.MULLVAD_OWNED
- Ownership.Rented -> ManagementInterface.Ownership.RENTED
+ ModelOwnership.MullvadOwned -> Ownership.MULLVAD_OWNED
+ ModelOwnership.Rented -> Ownership.RENTED
}
-internal fun RelaySettings.fromDomain(): ManagementInterface.RelaySettings =
- ManagementInterface.RelaySettings.newBuilder()
- .setNormal(
- ManagementInterface.NormalRelaySettings.newBuilder()
- .setWireguardConstraints(relayConstraints.wireguardConstraints.fromDomain())
- .setLocation(relayConstraints.location.fromDomain())
- .setOwnership(relayConstraints.ownership.fromDomain())
- .addAllProviders(relayConstraints.providers.fromDomain())
- .build()
- )
- .build()
+internal fun ModelRelaySettings.fromDomain(): RelaySettings =
+ RelaySettings(
+ normal =
+ NormalRelaySettings(
+ wireguard_constraints = relayConstraints.wireguardConstraints.fromDomain(),
+ location = relayConstraints.location.fromDomain(),
+ ownership = relayConstraints.ownership.fromDomain(),
+ providers = relayConstraints.providers.fromDomain(),
+ )
+ )
-internal fun Constraint<Ownership>.fromDomain(): ManagementInterface.Ownership =
+internal fun Constraint<ModelOwnership>.fromDomain(): Ownership =
when (this) {
- Constraint.Any -> ManagementInterface.Ownership.ANY
+ Constraint.Any -> Ownership.ANY
is Constraint.Only -> value.fromDomain()
}
-internal fun PlayPurchasePaymentToken.fromDomain(): ManagementInterface.PlayPurchasePaymentToken =
- ManagementInterface.PlayPurchasePaymentToken.newBuilder().setToken(value).build()
+internal fun ModelPlayPurchasePaymentToken.fromDomain(): PlayPurchasePaymentToken =
+ PlayPurchasePaymentToken(value)
-internal fun PlayPurchase.fromDomain(): ManagementInterface.PlayPurchase =
- ManagementInterface.PlayPurchase.newBuilder()
- .setPurchaseToken(purchaseToken.fromDomain())
- .setProductId(productId)
- .build()
+internal fun ModelPlayPurchase.fromDomain(): PlayPurchase =
+ PlayPurchase(purchase_token = purchaseToken.fromDomain(), product_id = productId)
-internal fun NewAccessMethodSetting.fromDomain(): ManagementInterface.NewAccessMethodSetting =
- ManagementInterface.NewAccessMethodSetting.newBuilder()
- .setName(name.value)
- .setEnabled(enabled)
- .setAccessMethod(
- ManagementInterface.AccessMethod.newBuilder().setCustom(apiAccessMethod.fromDomain())
- )
- .build()
+internal fun ModelNewAccessMethodSetting.fromDomain(): NewAccessMethodSetting =
+ NewAccessMethodSetting(
+ name = name.value,
+ enabled = enabled,
+ access_method = AccessMethod(custom = apiAccessMethod.fromDomain()),
+ )
-internal fun ApiAccessMethod.fromDomain(): ManagementInterface.AccessMethod =
- ManagementInterface.AccessMethod.newBuilder()
- .let {
- when (this) {
- ApiAccessMethod.Direct ->
- it.setDirect(ManagementInterface.AccessMethod.Direct.getDefaultInstance())
- ApiAccessMethod.Bridges ->
- it.setBridges(ManagementInterface.AccessMethod.Bridges.getDefaultInstance())
- is ApiAccessMethod.CustomProxy -> it.setCustom(fromDomain())
- is ApiAccessMethod.EncryptedDns ->
- it.setEncryptedDnsProxy(
- ManagementInterface.AccessMethod.EncryptedDnsProxy.getDefaultInstance()
- )
- }
- }
- .build()
+internal fun ModelApiAccessMethodSetting.fromDomain(): AccessMethodSetting =
+ AccessMethodSetting(
+ id = id.fromDomain(),
+ name = name.value,
+ enabled = enabled,
+ access_method = apiAccessMethod.fromDomain(),
+ )
-internal fun ApiAccessMethod.CustomProxy.fromDomain(): ManagementInterface.CustomProxy =
- ManagementInterface.CustomProxy.newBuilder()
- .let {
- when (this) {
- is ApiAccessMethod.CustomProxy.Shadowsocks -> it.setShadowsocks(fromDomain())
- is ApiAccessMethod.CustomProxy.Socks5Remote -> it.setSocks5Remote(fromDomain())
- }
- }
- .build()
+internal fun ModelApiAccessMethod.fromDomain(): AccessMethod =
+ when (this) {
+ ModelApiAccessMethod.Direct -> AccessMethod(direct = AccessMethod.Direct())
+ ModelApiAccessMethod.Bridges -> AccessMethod(bridges = AccessMethod.Bridges())
+ ModelApiAccessMethod.EncryptedDns ->
+ AccessMethod(encrypted_dns_proxy = AccessMethod.EncryptedDnsProxy())
+ is ModelApiAccessMethod.CustomProxy -> AccessMethod(custom = fromDomain())
+ }
-internal fun ApiAccessMethod.CustomProxy.Socks5Remote.fromDomain():
- ManagementInterface.Socks5Remote =
- ManagementInterface.Socks5Remote.newBuilder().setIp(ip).setPort(port.value).let {
- auth?.let { auth -> it.setAuth(auth.fromDomain()) }
- it.build()
+internal fun ModelApiAccessMethod.CustomProxy.fromDomain(): CustomProxy =
+ when (this) {
+ is ModelApiAccessMethod.CustomProxy.Shadowsocks -> CustomProxy(shadowsocks = fromDomain())
+ is ModelApiAccessMethod.CustomProxy.Socks5Remote -> CustomProxy(socks5remote = fromDomain())
}
-internal fun SocksAuth.fromDomain(): ManagementInterface.SocksAuth =
- ManagementInterface.SocksAuth.newBuilder().setUsername(username).setPassword(password).build()
+internal fun ModelSocksAuth.fromDomain(): SocksAuth =
+ SocksAuth(username = username, password = password)
-internal fun ApiAccessMethod.CustomProxy.Shadowsocks.fromDomain(): ManagementInterface.Shadowsocks =
- ManagementInterface.Shadowsocks.newBuilder()
- .setIp(ip)
- .setCipher(cipher.label)
- .setPort(port.value)
- .let {
- if (password != null) {
- it.setPassword(password)
- }
- it.build()
- }
+internal fun ModelApiAccessMethod.CustomProxy.Shadowsocks.fromDomain(): Shadowsocks =
+ Shadowsocks(ip = ip, cipher = cipher.label, port = port.value, password = password ?: "")
-internal fun ApiAccessMethodId.fromDomain(): ManagementInterface.UUID =
- ManagementInterface.UUID.newBuilder().setValue(value.toString()).build()
+internal fun ModelApiAccessMethodId.fromDomain(): UUID = UUID(value.toString())
-internal fun ApiAccessMethodSetting.fromDomain(): ManagementInterface.AccessMethodSetting =
- ManagementInterface.AccessMethodSetting.newBuilder()
- .setName(name.value)
- .setId(id.fromDomain())
- .setEnabled(enabled)
- .setAccessMethod(apiAccessMethod.fromDomain())
- .build()
+internal fun ModelApiAccessMethod.CustomProxy.Socks5Remote.fromDomain(): Socks5Remote =
+ Socks5Remote(ip = ip, port = port.value, auth = auth?.fromDomain())
-internal fun ShadowsocksObfuscationSettings.fromDomain():
- ManagementInterface.ObfuscationSettings.Shadowsocks =
+internal fun ModelShadowsocksObfuscationSettings.fromDomain(): ObfuscationSettings.Shadowsocks =
when (val port = port) {
- is Constraint.Any ->
- ManagementInterface.ObfuscationSettings.Shadowsocks.newBuilder().clearPort().build()
- is Constraint.Only ->
- ManagementInterface.ObfuscationSettings.Shadowsocks.newBuilder()
- .setPort(port.value.value)
- .build()
+ is Constraint.Any -> ObfuscationSettings.Shadowsocks(port = null)
+ is Constraint.Only -> ObfuscationSettings.Shadowsocks(port = port.value.value)
+ }
+
+internal fun ModelIpVersion.fromDomain(): IpVersion =
+ when (this) {
+ ModelIpVersion.IPV4 -> IpVersion.V4
+ ModelIpVersion.IPV6 -> IpVersion.V6
}
-internal fun IpVersion.fromDomain(): ManagementInterface.IpVersion =
+internal fun ModelQuantumResistantState.fromDomain(): QuantumResistantState =
when (this) {
- IpVersion.IPV4 -> ManagementInterface.IpVersion.V4
- IpVersion.IPV6 -> ManagementInterface.IpVersion.V6
+ ModelQuantumResistantState.On ->
+ QuantumResistantState(state = QuantumResistantState.State.ON)
+ ModelQuantumResistantState.Off ->
+ QuantumResistantState(state = QuantumResistantState.State.OFF)
}
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
index 97216a9c37..51a0fc0908 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
@@ -2,196 +2,231 @@
package net.mullvad.mullvadvpn.lib.daemon.grpc.mapper
-import io.grpc.ConnectivityState
import java.net.InetAddress
import java.net.InetSocketAddress
import java.time.Instant
import java.time.ZoneId
import java.util.UUID
-import mullvad_daemon.management_interface.ManagementInterface
-import mullvad_daemon.management_interface.entryLocationOrNull
-import mullvad_daemon.management_interface.locationOrNull
-import mullvad_daemon.management_interface.recentsOrNull
-import net.mullvad.mullvadvpn.lib.daemon.grpc.GrpcConnectivityState
+import kotlin.collections.sorted
+import mullvad_daemon.management_interface.AccessMethod
+import mullvad_daemon.management_interface.AccessMethodSetting
+import mullvad_daemon.management_interface.AccountData
+import mullvad_daemon.management_interface.AfterDisconnect
+import mullvad_daemon.management_interface.ApiAccessMethodSettings
+import mullvad_daemon.management_interface.AppVersionInfo
+import mullvad_daemon.management_interface.CustomDnsOptions
+import mullvad_daemon.management_interface.CustomList
+import mullvad_daemon.management_interface.CustomProxy
+import mullvad_daemon.management_interface.DaitaSettings
+import mullvad_daemon.management_interface.DefaultDnsOptions
+import mullvad_daemon.management_interface.Device
+import mullvad_daemon.management_interface.DeviceState
+import mullvad_daemon.management_interface.DnsOptions
+import mullvad_daemon.management_interface.ErrorState
+import mullvad_daemon.management_interface.FeatureIndicator
+import mullvad_daemon.management_interface.FeatureIndicators
+import mullvad_daemon.management_interface.GeoIpLocation
+import mullvad_daemon.management_interface.GeographicLocationConstraint
+import mullvad_daemon.management_interface.IpVersion
+import mullvad_daemon.management_interface.LocationConstraint
+import mullvad_daemon.management_interface.NormalRelaySettings
+import mullvad_daemon.management_interface.ObfuscationEndpoint
+import mullvad_daemon.management_interface.ObfuscationSettings
+import mullvad_daemon.management_interface.Ownership
+import mullvad_daemon.management_interface.PlayPurchasePaymentToken
+import mullvad_daemon.management_interface.PortRange
+import mullvad_daemon.management_interface.QuantumResistantState
+import mullvad_daemon.management_interface.Recent
+import mullvad_daemon.management_interface.Recents
+import mullvad_daemon.management_interface.Relay
+import mullvad_daemon.management_interface.RelayList
+import mullvad_daemon.management_interface.RelayListCity
+import mullvad_daemon.management_interface.RelayListCountry
+import mullvad_daemon.management_interface.RelayOverride
+import mullvad_daemon.management_interface.RelaySettings
+import mullvad_daemon.management_interface.Settings
+import mullvad_daemon.management_interface.Shadowsocks
+import mullvad_daemon.management_interface.Socks5Remote
+import mullvad_daemon.management_interface.SocksAuth
+import mullvad_daemon.management_interface.SplitTunnelSettings
+import mullvad_daemon.management_interface.TransportProtocol
+import mullvad_daemon.management_interface.TunnelEndpoint
+import mullvad_daemon.management_interface.TunnelOptions
+import mullvad_daemon.management_interface.TunnelState
+import mullvad_daemon.management_interface.VoucherSubmission
+import mullvad_daemon.management_interface.WireguardConstraints
+import mullvad_daemon.management_interface.WireguardEndpointData
import net.mullvad.mullvadvpn.lib.daemon.grpc.RelayNameComparator
-import net.mullvad.mullvadvpn.lib.model.AccountData
+import net.mullvad.mullvadvpn.lib.model.AccountData as ModelAccountData
import net.mullvad.mullvadvpn.lib.model.AccountId
-import net.mullvad.mullvadvpn.lib.model.AccountNumber
-import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethod
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName
-import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodSetting
+import net.mullvad.mullvadvpn.lib.model.AccountNumber as ModelAccountNumber
+import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect as ModelActionAfterDisconnect
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethod as ModelApiAccessMethod
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId as ModelApiAccessMethodId
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName as ModelApiAccessMethodName
+import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodSetting as ModelApiAccessMethodSetting
import net.mullvad.mullvadvpn.lib.model.AppId
-import net.mullvad.mullvadvpn.lib.model.AppVersionInfo
-import net.mullvad.mullvadvpn.lib.model.AuthFailedError
-import net.mullvad.mullvadvpn.lib.model.Cipher
+import net.mullvad.mullvadvpn.lib.model.AppVersionInfo as ModelAppVersionInfo
+import net.mullvad.mullvadvpn.lib.model.AuthFailedError as ModelAuthFailedError
+import net.mullvad.mullvadvpn.lib.model.Cipher as ModelCipher
+import net.mullvad.mullvadvpn.lib.model.Constraint as ModelConstraint
import net.mullvad.mullvadvpn.lib.model.Constraint
-import net.mullvad.mullvadvpn.lib.model.CustomDnsOptions
-import net.mullvad.mullvadvpn.lib.model.CustomList
-import net.mullvad.mullvadvpn.lib.model.CustomListId
-import net.mullvad.mullvadvpn.lib.model.CustomListName
-import net.mullvad.mullvadvpn.lib.model.DaitaSettings
-import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions
-import net.mullvad.mullvadvpn.lib.model.Device
-import net.mullvad.mullvadvpn.lib.model.DeviceId
-import net.mullvad.mullvadvpn.lib.model.DeviceState
-import net.mullvad.mullvadvpn.lib.model.DnsOptions
-import net.mullvad.mullvadvpn.lib.model.DnsState
-import net.mullvad.mullvadvpn.lib.model.Endpoint
-import net.mullvad.mullvadvpn.lib.model.ErrorState
-import net.mullvad.mullvadvpn.lib.model.ErrorStateCause
-import net.mullvad.mullvadvpn.lib.model.FeatureIndicator
-import net.mullvad.mullvadvpn.lib.model.GeoIpLocation
-import net.mullvad.mullvadvpn.lib.model.GeoLocationId
-import net.mullvad.mullvadvpn.lib.model.IpVersion
-import net.mullvad.mullvadvpn.lib.model.Mtu
-import net.mullvad.mullvadvpn.lib.model.ObfuscationEndpoint
+import net.mullvad.mullvadvpn.lib.model.CustomDnsOptions as ModelCustomDnsOptions
+import net.mullvad.mullvadvpn.lib.model.CustomList as ModelCustomList
+import net.mullvad.mullvadvpn.lib.model.CustomListId as ModelCustomListId
+import net.mullvad.mullvadvpn.lib.model.CustomListName as ModelCustomListName
+import net.mullvad.mullvadvpn.lib.model.DaitaSettings as ModelDaitaSettings
+import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions as ModelDefaultDnsOptions
+import net.mullvad.mullvadvpn.lib.model.Device as ModelDevice
+import net.mullvad.mullvadvpn.lib.model.DeviceId as ModelDeviceId
+import net.mullvad.mullvadvpn.lib.model.DeviceState as ModelDeviceState
+import net.mullvad.mullvadvpn.lib.model.DnsOptions as ModelDnsOptions
+import net.mullvad.mullvadvpn.lib.model.DnsState as ModelDnsState
+import net.mullvad.mullvadvpn.lib.model.Endpoint as ModelEndpoint
+import net.mullvad.mullvadvpn.lib.model.ErrorState as ModelErrorState
+import net.mullvad.mullvadvpn.lib.model.ErrorStateCause as ModelErrorStateCause
+import net.mullvad.mullvadvpn.lib.model.FeatureIndicator as ModelFeatureIndicator
+import net.mullvad.mullvadvpn.lib.model.GeoIpLocation as ModelGeoIpLocation
+import net.mullvad.mullvadvpn.lib.model.GeoLocationId as ModelGeoLocationId
+import net.mullvad.mullvadvpn.lib.model.IpVersion as ModelIpVersion
+import net.mullvad.mullvadvpn.lib.model.Mtu as ModelMtu
+import net.mullvad.mullvadvpn.lib.model.ObfuscationEndpoint as ModelObfuscationEndpoint
+import net.mullvad.mullvadvpn.lib.model.ObfuscationMode as ModelObfuscationMode
import net.mullvad.mullvadvpn.lib.model.ObfuscationMode
-import net.mullvad.mullvadvpn.lib.model.ObfuscationSettings
-import net.mullvad.mullvadvpn.lib.model.ObfuscationType
-import net.mullvad.mullvadvpn.lib.model.Ownership
-import net.mullvad.mullvadvpn.lib.model.ParameterGenerationError
-import net.mullvad.mullvadvpn.lib.model.PlayPurchasePaymentToken
+import net.mullvad.mullvadvpn.lib.model.ObfuscationSettings as ModelObfuscationSettings
+import net.mullvad.mullvadvpn.lib.model.ObfuscationType as ModelObfuscationType
+import net.mullvad.mullvadvpn.lib.model.Ownership as ModelOwnership
+import net.mullvad.mullvadvpn.lib.model.ParameterGenerationError as ModelParameterGenerationError
+import net.mullvad.mullvadvpn.lib.model.PlayPurchasePaymentToken as ModelPlayPurchasePaymentToken
+import net.mullvad.mullvadvpn.lib.model.Port as ModelPort
import net.mullvad.mullvadvpn.lib.model.Port
-import net.mullvad.mullvadvpn.lib.model.PortRange
+import net.mullvad.mullvadvpn.lib.model.PortRange as ModelPortRange
+import net.mullvad.mullvadvpn.lib.model.ProviderId as ModelProviderId
import net.mullvad.mullvadvpn.lib.model.ProviderId
-import net.mullvad.mullvadvpn.lib.model.Providers
-import net.mullvad.mullvadvpn.lib.model.QuantumResistantState
+import net.mullvad.mullvadvpn.lib.model.Providers as ModelProviders
+import net.mullvad.mullvadvpn.lib.model.QuantumResistantState as ModelQuantumResistantState
import net.mullvad.mullvadvpn.lib.model.Quic
-import net.mullvad.mullvadvpn.lib.model.Recent
-import net.mullvad.mullvadvpn.lib.model.Recents
-import net.mullvad.mullvadvpn.lib.model.RedeemVoucherSuccess
-import net.mullvad.mullvadvpn.lib.model.RelayConstraints
-import net.mullvad.mullvadvpn.lib.model.RelayItem
-import net.mullvad.mullvadvpn.lib.model.RelayItemId
-import net.mullvad.mullvadvpn.lib.model.RelayList
-import net.mullvad.mullvadvpn.lib.model.RelayOverride
-import net.mullvad.mullvadvpn.lib.model.RelaySettings
-import net.mullvad.mullvadvpn.lib.model.Settings
-import net.mullvad.mullvadvpn.lib.model.ShadowsocksObfuscationSettings
-import net.mullvad.mullvadvpn.lib.model.SocksAuth
-import net.mullvad.mullvadvpn.lib.model.SplitTunnelSettings
-import net.mullvad.mullvadvpn.lib.model.TransportProtocol
-import net.mullvad.mullvadvpn.lib.model.TunnelEndpoint
-import net.mullvad.mullvadvpn.lib.model.TunnelOptions
-import net.mullvad.mullvadvpn.lib.model.TunnelState
-import net.mullvad.mullvadvpn.lib.model.Udp2TcpObfuscationSettings
-import net.mullvad.mullvadvpn.lib.model.WireguardConstraints
-import net.mullvad.mullvadvpn.lib.model.WireguardEndpointData
+import net.mullvad.mullvadvpn.lib.model.Recent as ModelRecent
+import net.mullvad.mullvadvpn.lib.model.Recents as ModelRecents
+import net.mullvad.mullvadvpn.lib.model.RedeemVoucherSuccess as ModelRedeemVoucherSuccess
+import net.mullvad.mullvadvpn.lib.model.RelayConstraints as ModelRelayConstraints
+import net.mullvad.mullvadvpn.lib.model.RelayItem as ModelRelayItem
+import net.mullvad.mullvadvpn.lib.model.RelayItemId as ModelRelayItemId
+import net.mullvad.mullvadvpn.lib.model.RelayList as ModelRelayList
+import net.mullvad.mullvadvpn.lib.model.RelayOverride as ModelRelayOverride
+import net.mullvad.mullvadvpn.lib.model.RelaySettings as ModelRelaySettings
+import net.mullvad.mullvadvpn.lib.model.Settings as ModelSettings
+import net.mullvad.mullvadvpn.lib.model.ShadowsocksObfuscationSettings as ModelShadowsocksObfuscationSettings
+import net.mullvad.mullvadvpn.lib.model.SocksAuth as ModelSocksAuth
+import net.mullvad.mullvadvpn.lib.model.SplitTunnelSettings as ModelSplitTunnelSettings
+import net.mullvad.mullvadvpn.lib.model.TransportProtocol as ModelTransportProtocol
+import net.mullvad.mullvadvpn.lib.model.TunnelEndpoint as ModelTunnelEndpoint
+import net.mullvad.mullvadvpn.lib.model.TunnelOptions as ModelTunnelOptions
+import net.mullvad.mullvadvpn.lib.model.TunnelState as ModelTunnelState
+import net.mullvad.mullvadvpn.lib.model.Udp2TcpObfuscationSettings as ModelUdp2TcpObfuscationSettings
+import net.mullvad.mullvadvpn.lib.model.WireguardConstraints as ModelWireguardConstraints
+import net.mullvad.mullvadvpn.lib.model.WireguardEndpointData as ModelWireguardEndpointData
-internal fun ManagementInterface.TunnelState.toDomain(): TunnelState =
- when (stateCase!!) {
- ManagementInterface.TunnelState.StateCase.DISCONNECTED -> disconnected.toDomain()
- ManagementInterface.TunnelState.StateCase.CONNECTING -> connecting.toDomain()
- ManagementInterface.TunnelState.StateCase.CONNECTED -> connected.toDomain()
- ManagementInterface.TunnelState.StateCase.DISCONNECTING -> disconnecting.toDomain()
- ManagementInterface.TunnelState.StateCase.ERROR -> error.toDomain()
- ManagementInterface.TunnelState.StateCase.STATE_NOT_SET ->
- TunnelState.Disconnected(location = disconnected.disconnectedLocation.toDomain())
+internal fun TunnelState.toDomain(): ModelTunnelState =
+ when {
+ disconnected != null -> disconnected.toDomain()
+ connecting != null -> connecting.toDomain()
+ connected != null -> connected.toDomain()
+ disconnecting != null -> disconnecting.toDomain()
+ error != null -> error.toDomain()
+ else -> error("Tunnelstate not supported")
}
-private fun ManagementInterface.TunnelState.Connecting.toDomain(): TunnelState.Connecting =
- TunnelState.Connecting(
- endpoint = relayInfo.tunnelEndpoint.toDomain(),
- location =
- if (relayInfo.hasLocation()) {
- relayInfo.location.toDomain()
- } else null,
- featureIndicators = featureIndicators.toDomain(),
+private fun TunnelState.Connecting.toDomain(): ModelTunnelState.Connecting =
+ ModelTunnelState.Connecting(
+ endpoint = relay_info?.tunnel_endpoint?.toDomain(),
+ location = relay_info?.location?.toDomain(),
+ featureIndicators = feature_indicators?.toDomain() ?: emptyList(),
)
-private fun ManagementInterface.TunnelState.Disconnected.toDomain(): TunnelState.Disconnected =
- TunnelState.Disconnected(
- location =
- if (hasDisconnectedLocation()) {
- disconnectedLocation.toDomain()
- } else null
- )
+private fun TunnelState.Disconnected.toDomain(): ModelTunnelState.Disconnected =
+ ModelTunnelState.Disconnected(location = disconnected_location?.toDomain())
-private fun ManagementInterface.TunnelState.Connected.toDomain(): TunnelState.Connected =
- TunnelState.Connected(
- endpoint = relayInfo.tunnelEndpoint.toDomain(),
- location =
- if (relayInfo.hasLocation()) {
- relayInfo.location.toDomain()
- } else {
- null
- },
- featureIndicators = featureIndicators.toDomain(),
+private fun TunnelState.Connected.toDomain(): ModelTunnelState.Connected =
+ ModelTunnelState.Connected(
+ endpoint = relay_info!!.tunnel_endpoint!!.toDomain(),
+ location = relay_info.location?.toDomain(),
+ featureIndicators = feature_indicators?.toDomain() ?: emptyList(),
)
-private fun ManagementInterface.TunnelState.Disconnecting.toDomain(): TunnelState.Disconnecting =
- TunnelState.Disconnecting(actionAfterDisconnect = afterDisconnect.toDomain())
+private fun TunnelState.Disconnecting.toDomain(): ModelTunnelState.Disconnecting =
+ ModelTunnelState.Disconnecting(actionAfterDisconnect = after_disconnect.toDomain())
-private fun ManagementInterface.TunnelState.Error.toDomain(): TunnelState.Error {
+private fun TunnelState.Error.toDomain(): ModelTunnelState.Error {
val otherAlwaysOnAppError =
- errorState.let {
- if (it.hasOtherAlwaysOnAppError()) {
- ErrorStateCause.OtherAlwaysOnApp(it.otherAlwaysOnAppError.appName)
+ error_state?.let {
+ if (it.other_always_on_app_error != null) {
+ ModelErrorStateCause.OtherAlwaysOnApp(it.other_always_on_app_error.app_name)
} else {
null
}
}
val invalidDnsServers =
- errorState.let {
- if (it.hasInvalidDnsServersError()) {
- ErrorStateCause.InvalidDnsServers(
- it.invalidDnsServersError.ipAddrsList.toList().map { InetAddress.getByName(it) }
+ error_state?.let {
+ if (it.invalid_dns_servers_error != null) {
+ ModelErrorStateCause.InvalidDnsServers(
+ it.invalid_dns_servers_error.ip_addrs.map { address ->
+ InetAddress.getByName(address)
+ }
)
} else {
null
}
}
- return TunnelState.Error(
+ return ModelTunnelState.Error(
errorState =
- errorState.toDomain(
+ error_state!!.toDomain(
otherAlwaysOnApp = otherAlwaysOnAppError,
invalidDnsServers = invalidDnsServers,
)
)
}
-internal fun ManagementInterface.GeoIpLocation.toDomain(): GeoIpLocation =
- GeoIpLocation(
+internal fun GeoIpLocation.toDomain(): ModelGeoIpLocation =
+ ModelGeoIpLocation(
ipv4 =
- if (hasIpv4()) {
+ if (ipv4 != null) {
InetAddress.getByName(ipv4)
} else {
null
},
ipv6 =
- if (hasIpv6()) {
+ if (ipv6 != null) {
InetAddress.getByName(ipv6)
} else {
null
},
country = country,
- city = if (hasCity()) city else null,
+ city = city,
latitude = latitude,
longitude = longitude,
- hostname = if (hasHostname()) hostname else null,
- entryHostname = if (hasEntryHostname()) entryHostname else null,
+ hostname = hostname,
+ entryHostname = entry_hostname,
)
-internal fun ManagementInterface.TunnelEndpoint.toDomain(): TunnelEndpoint =
- TunnelEndpoint(
+internal fun TunnelEndpoint.toDomain(): ModelTunnelEndpoint =
+ ModelTunnelEndpoint(
endpoint =
- Endpoint(address = address.toInetSocketAddress(), protocol = protocol.toDomain()),
+ ModelEndpoint(address = address.toInetSocketAddress(), protocol = protocol.toDomain()),
entryEndpoint =
- if (hasEntryEndpoint()) {
- Endpoint(
- address = entryEndpoint.address.toInetSocketAddress(),
- protocol = entryEndpoint.protocol.toDomain(),
+ if (entry_endpoint != null) {
+ ModelEndpoint(
+ address = entry_endpoint.address.toInetSocketAddress(),
+ protocol = entry_endpoint.protocol.toDomain(),
)
} else {
null
},
- quantumResistant = quantumResistant,
+ quantumResistant = quantum_resistant,
obfuscation =
- if (hasObfuscation() && obfuscation.hasSingle()) {
+ if (obfuscation != null && obfuscation.single != null) {
obfuscation.single.toDomain()
} else {
null
@@ -199,14 +234,14 @@ internal fun ManagementInterface.TunnelEndpoint.toDomain(): TunnelEndpoint =
daita = daita,
)
-internal fun ManagementInterface.ObfuscationEndpoint.toDomain(): ObfuscationEndpoint =
- ObfuscationEndpoint(
+internal fun ObfuscationEndpoint.toDomain(): ModelObfuscationEndpoint =
+ ModelObfuscationEndpoint(
endpoint =
- Endpoint(
- address = endpoint.address.toInetSocketAddress(),
+ ModelEndpoint(
+ address = endpoint!!.address.toInetSocketAddress(),
protocol = endpoint.protocol.toDomain(),
),
- obfuscationType = obfuscationType.toDomain(),
+ obfuscationType = obfuscation_type.toDomain(),
)
private fun String.toInetAddress(): InetAddress = InetAddress.getByName(this)
@@ -218,540 +253,474 @@ private fun String.toInetSocketAddress(): InetSocketAddress {
return InetSocketAddress(InetAddress.getByName(ipPart), portPart.toInt())
}
-internal fun ManagementInterface.ObfuscationEndpoint.ObfuscationType.toDomain(): ObfuscationType =
+internal fun ObfuscationEndpoint.ObfuscationType.toDomain(): ModelObfuscationType =
when (this) {
- ManagementInterface.ObfuscationEndpoint.ObfuscationType.UDP2TCP -> ObfuscationType.Udp2Tcp
- ManagementInterface.ObfuscationEndpoint.ObfuscationType.SHADOWSOCKS ->
- ObfuscationType.Shadowsocks
- ManagementInterface.ObfuscationEndpoint.ObfuscationType.QUIC -> ObfuscationType.Quic
- ManagementInterface.ObfuscationEndpoint.ObfuscationType.LWO -> ObfuscationType.Lwo
- ManagementInterface.ObfuscationEndpoint.ObfuscationType.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized obfuscation type")
+ ObfuscationEndpoint.ObfuscationType.UDP2TCP -> ModelObfuscationType.Udp2Tcp
+ ObfuscationEndpoint.ObfuscationType.SHADOWSOCKS -> ModelObfuscationType.Shadowsocks
+ ObfuscationEndpoint.ObfuscationType.QUIC -> ModelObfuscationType.Quic
+ ObfuscationEndpoint.ObfuscationType.LWO -> ModelObfuscationType.Lwo
}
-internal fun ManagementInterface.TransportProtocol.toDomain(): TransportProtocol =
+internal fun TransportProtocol.toDomain(): ModelTransportProtocol =
when (this) {
- ManagementInterface.TransportProtocol.TCP -> TransportProtocol.Tcp
- ManagementInterface.TransportProtocol.UDP -> TransportProtocol.Udp
- ManagementInterface.TransportProtocol.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized transport protocol")
+ TransportProtocol.TCP -> ModelTransportProtocol.Tcp
+ TransportProtocol.UDP -> ModelTransportProtocol.Udp
}
-internal fun ManagementInterface.AfterDisconnect.toDomain(): ActionAfterDisconnect =
+internal fun AfterDisconnect.toDomain(): ModelActionAfterDisconnect =
when (this) {
- ManagementInterface.AfterDisconnect.NOTHING -> ActionAfterDisconnect.Nothing
- ManagementInterface.AfterDisconnect.RECONNECT -> ActionAfterDisconnect.Reconnect
- ManagementInterface.AfterDisconnect.BLOCK -> ActionAfterDisconnect.Block
- ManagementInterface.AfterDisconnect.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized action after disconnect")
+ AfterDisconnect.NOTHING -> ModelActionAfterDisconnect.Nothing
+ AfterDisconnect.RECONNECT -> ModelActionAfterDisconnect.Reconnect
+ AfterDisconnect.BLOCK -> ModelActionAfterDisconnect.Block
}
-internal fun ManagementInterface.ErrorState.toDomain(
- otherAlwaysOnApp: ErrorStateCause.OtherAlwaysOnApp?,
- invalidDnsServers: ErrorStateCause.InvalidDnsServers?,
-): ErrorState =
- ErrorState(
+internal fun ErrorState.toDomain(
+ otherAlwaysOnApp: ModelErrorStateCause.OtherAlwaysOnApp?,
+ invalidDnsServers: ModelErrorStateCause.InvalidDnsServers?,
+): ModelErrorState =
+ ModelErrorState(
cause =
- when (cause!!) {
- ManagementInterface.ErrorState.Cause.AUTH_FAILED ->
- ErrorStateCause.AuthFailed(authFailedError.toDomain())
- ManagementInterface.ErrorState.Cause.IPV6_UNAVAILABLE ->
- ErrorStateCause.Ipv6Unavailable
- ManagementInterface.ErrorState.Cause.SET_FIREWALL_POLICY_ERROR ->
- policyError.toDomain()
- ManagementInterface.ErrorState.Cause.SET_DNS_ERROR -> ErrorStateCause.DnsError
- ManagementInterface.ErrorState.Cause.START_TUNNEL_ERROR ->
- ErrorStateCause.StartTunnelError
- ManagementInterface.ErrorState.Cause.TUNNEL_PARAMETER_ERROR ->
- ErrorStateCause.TunnelParameterError(parameterError.toDomain())
- ManagementInterface.ErrorState.Cause.IS_OFFLINE -> ErrorStateCause.IsOffline
- ManagementInterface.ErrorState.Cause.SPLIT_TUNNEL_ERROR ->
- ErrorStateCause.StartTunnelError
- ManagementInterface.ErrorState.Cause.UNRECOGNIZED,
- ManagementInterface.ErrorState.Cause.NEED_FULL_DISK_PERMISSIONS,
- ManagementInterface.ErrorState.Cause.CREATE_TUNNEL_DEVICE ->
+ when (cause) {
+ ErrorState.Cause.AUTH_FAILED ->
+ ModelErrorStateCause.AuthFailed(auth_failed_error.toDomain())
+ ErrorState.Cause.IPV6_UNAVAILABLE -> ModelErrorStateCause.Ipv6Unavailable
+ ErrorState.Cause.SET_FIREWALL_POLICY_ERROR if policy_error != null ->
+ policy_error.toDomain()
+ ErrorState.Cause.SET_DNS_ERROR -> ModelErrorStateCause.DnsError
+ ErrorState.Cause.START_TUNNEL_ERROR -> ModelErrorStateCause.StartTunnelError
+ ErrorState.Cause.TUNNEL_PARAMETER_ERROR ->
+ ModelErrorStateCause.TunnelParameterError(parameter_error.toDomain())
+ ErrorState.Cause.IS_OFFLINE -> ModelErrorStateCause.IsOffline
+ ErrorState.Cause.SPLIT_TUNNEL_ERROR -> ModelErrorStateCause.StartTunnelError
+ ErrorState.Cause.NEED_FULL_DISK_PERMISSIONS,
+ ErrorState.Cause.CREATE_TUNNEL_DEVICE ->
throw IllegalArgumentException("Unrecognized error state cause")
- ManagementInterface.ErrorState.Cause.NOT_PREPARED -> ErrorStateCause.NotPrepared
- ManagementInterface.ErrorState.Cause.OTHER_ALWAYS_ON_APP -> otherAlwaysOnApp!!
- ManagementInterface.ErrorState.Cause.OTHER_LEGACY_ALWAYS_ON_VPN ->
- ErrorStateCause.OtherLegacyAlwaysOnApp
- ManagementInterface.ErrorState.Cause.INVALID_DNS_SERVERS -> invalidDnsServers!!
+ ErrorState.Cause.NOT_PREPARED -> ModelErrorStateCause.NotPrepared
+ ErrorState.Cause.OTHER_ALWAYS_ON_APP -> otherAlwaysOnApp!!
+ ErrorState.Cause.OTHER_LEGACY_ALWAYS_ON_VPN ->
+ ModelErrorStateCause.OtherLegacyAlwaysOnApp
+ ErrorState.Cause.INVALID_DNS_SERVERS -> invalidDnsServers!!
+ else -> error("Invalid error state cause $cause")
},
- isBlocking = !hasBlockingError(),
+ isBlocking = blocking_error != null,
)
-private fun ManagementInterface.ErrorState.AuthFailedError.toDomain(): AuthFailedError =
+private fun ErrorState.AuthFailedError.toDomain(): ModelAuthFailedError =
when (this) {
- ManagementInterface.ErrorState.AuthFailedError.UNKNOWN -> AuthFailedError.Unknown
- ManagementInterface.ErrorState.AuthFailedError.INVALID_ACCOUNT ->
- AuthFailedError.InvalidAccount
- ManagementInterface.ErrorState.AuthFailedError.EXPIRED_ACCOUNT ->
- AuthFailedError.ExpiredAccount
- ManagementInterface.ErrorState.AuthFailedError.TOO_MANY_CONNECTIONS ->
- AuthFailedError.TooManyConnections
- ManagementInterface.ErrorState.AuthFailedError.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized auth failed error")
+ ErrorState.AuthFailedError.UNKNOWN -> ModelAuthFailedError.Unknown
+ ErrorState.AuthFailedError.INVALID_ACCOUNT -> ModelAuthFailedError.InvalidAccount
+ ErrorState.AuthFailedError.EXPIRED_ACCOUNT -> ModelAuthFailedError.ExpiredAccount
+ ErrorState.AuthFailedError.TOO_MANY_CONNECTIONS -> ModelAuthFailedError.TooManyConnections
}
-internal fun ManagementInterface.ErrorState.FirewallPolicyError.toDomain():
- ErrorStateCause.FirewallPolicyError =
- when (type!!) {
- ManagementInterface.ErrorState.FirewallPolicyError.ErrorType.GENERIC ->
- ErrorStateCause.FirewallPolicyError.Generic
- ManagementInterface.ErrorState.FirewallPolicyError.ErrorType.LOCKED,
- ManagementInterface.ErrorState.FirewallPolicyError.ErrorType.UNRECOGNIZED ->
+internal fun ErrorState.FirewallPolicyError.toDomain(): ModelErrorStateCause.FirewallPolicyError =
+ when (type) {
+ ErrorState.FirewallPolicyError.ErrorType.GENERIC ->
+ ModelErrorStateCause.FirewallPolicyError.Generic
+ ErrorState.FirewallPolicyError.ErrorType.LOCKED ->
throw IllegalArgumentException("Unrecognized firewall policy error")
}
-internal fun ManagementInterface.ErrorState.GenerationError.toDomain(): ParameterGenerationError =
+internal fun ErrorState.GenerationError.toDomain(): ModelParameterGenerationError =
when (this) {
- ManagementInterface.ErrorState.GenerationError.NO_MATCHING_RELAY_ENTRY ->
- ParameterGenerationError.NoMatchingRelayEntry
- ManagementInterface.ErrorState.GenerationError.NO_MATCHING_RELAY_EXIT ->
- ParameterGenerationError.NoMatchingRelayExit
- ManagementInterface.ErrorState.GenerationError.NO_MATCHING_RELAY ->
- ParameterGenerationError.NoMatchingRelay
- ManagementInterface.ErrorState.GenerationError.NO_MATCHING_BRIDGE_RELAY ->
- ParameterGenerationError.NoMatchingBridgeRelay
- ManagementInterface.ErrorState.GenerationError.CUSTOM_TUNNEL_HOST_RESOLUTION_ERROR ->
- ParameterGenerationError.CustomTunnelHostResolutionError
- ManagementInterface.ErrorState.GenerationError.NETWORK_IPV4_UNAVAILABLE ->
- ParameterGenerationError.Ipv4_Unavailable
- ManagementInterface.ErrorState.GenerationError.NETWORK_IPV6_UNAVAILABLE ->
- ParameterGenerationError.Ipv6_Unavailable
- ManagementInterface.ErrorState.GenerationError.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized parameter generation error")
+ ErrorState.GenerationError.NO_MATCHING_RELAY_ENTRY ->
+ ModelParameterGenerationError.NoMatchingRelayEntry
+ ErrorState.GenerationError.NO_MATCHING_RELAY_EXIT ->
+ ModelParameterGenerationError.NoMatchingRelayExit
+ ErrorState.GenerationError.NO_MATCHING_RELAY ->
+ ModelParameterGenerationError.NoMatchingRelay
+ ErrorState.GenerationError.NO_MATCHING_BRIDGE_RELAY ->
+ ModelParameterGenerationError.NoMatchingBridgeRelay
+ ErrorState.GenerationError.CUSTOM_TUNNEL_HOST_RESOLUTION_ERROR ->
+ ModelParameterGenerationError.CustomTunnelHostResolutionError
+ ErrorState.GenerationError.NETWORK_IPV4_UNAVAILABLE ->
+ ModelParameterGenerationError.Ipv4_Unavailable
+ ErrorState.GenerationError.NETWORK_IPV6_UNAVAILABLE ->
+ ModelParameterGenerationError.Ipv6_Unavailable
}
-internal fun ManagementInterface.Settings.toDomain(): Settings =
- Settings(
- relaySettings = relaySettings.toDomain(),
- obfuscationSettings = obfuscationSettings.toDomain(),
- customLists = customLists.customListsList.map { it.toDomain() },
- allowLan = allowLan,
- tunnelOptions = tunnelOptions.toDomain(),
- relayOverrides = relayOverridesList.map { it.toDomain() },
- showBetaReleases = showBetaReleases,
- splitTunnelSettings = splitTunnel.toDomain(),
- apiAccessMethodSettings = apiAccessMethods.toDomain(),
- recents = recentsOrNull.toDomain(),
+internal fun Settings.toDomain(): ModelSettings =
+ ModelSettings(
+ relaySettings = relay_settings!!.toDomain(),
+ obfuscationSettings = obfuscation_settings!!.toDomain(),
+ customLists = custom_lists?.custom_lists?.map { it.toDomain() } ?: emptyList(),
+ allowLan = allow_lan,
+ tunnelOptions = tunnel_options!!.toDomain(),
+ relayOverrides = relay_overrides.map { it.toDomain() },
+ showBetaReleases = show_beta_releases,
+ splitTunnelSettings = split_tunnel!!.toDomain(),
+ apiAccessMethodSettings = api_access_methods!!.toDomain(),
+ recents = recents.toDomain(),
)
-internal fun ManagementInterface.RelayOverride.toDomain(): RelayOverride =
- RelayOverride(
+internal fun RelayOverride.toDomain(): ModelRelayOverride =
+ ModelRelayOverride(
hostname = hostname,
- ipv4AddressIn = if (hasIpv4AddrIn()) InetAddress.getByName(ipv4AddrIn) else null,
- ipv6AddressIn = if (hasIpv6AddrIn()) InetAddress.getByName(ipv6AddrIn) else null,
+ ipv4AddressIn = if (ipv4_addr_in != null) InetAddress.getByName(ipv4_addr_in) else null,
+ ipv6AddressIn = if (ipv6_addr_in != null) InetAddress.getByName(ipv6_addr_in) else null,
)
-internal fun ManagementInterface.RelaySettings.toDomain(): RelaySettings =
- when (endpointCase) {
- ManagementInterface.RelaySettings.EndpointCase.CUSTOM ->
- throw IllegalArgumentException("CustomTunnelEndpoint is not supported")
- ManagementInterface.RelaySettings.EndpointCase.NORMAL -> RelaySettings(normal.toDomain())
- ManagementInterface.RelaySettings.EndpointCase.ENDPOINT_NOT_SET ->
- throw IllegalArgumentException("RelaySettings endpoint not set")
+internal fun RelaySettings.toDomain(): ModelRelaySettings =
+ when {
+ custom != null -> throw IllegalArgumentException("CustomTunnelEndpoint is not supported")
+ normal != null -> ModelRelaySettings(normal.toDomain())
else -> throw NullPointerException("RelaySettings endpoint is null")
}
-internal fun ManagementInterface.NormalRelaySettings.toDomain(): RelayConstraints =
- RelayConstraints(
- location = locationOrNull?.toDomain() ?: Constraint.Any,
- providers = providersList.toDomain(),
+internal fun NormalRelaySettings.toDomain(): ModelRelayConstraints =
+ ModelRelayConstraints(
+ location = location?.toDomain() ?: ModelConstraint.Any,
+ providers = providers.toDomain(),
ownership = ownership.toDomain(),
- wireguardConstraints = wireguardConstraints.toDomain(),
+ wireguardConstraints = wireguard_constraints!!.toDomain(),
)
-internal fun ManagementInterface.LocationConstraint.toDomain(): Constraint<RelayItemId> =
- when (typeCase) {
- ManagementInterface.LocationConstraint.TypeCase.CUSTOM_LIST ->
- Constraint.Only(CustomListId(customList))
- ManagementInterface.LocationConstraint.TypeCase.LOCATION ->
- Constraint.Only(location.toDomain())
- ManagementInterface.LocationConstraint.TypeCase.TYPE_NOT_SET -> Constraint.Any
+internal fun LocationConstraint.toDomain(): ModelConstraint<ModelRelayItemId> =
+ when {
+ custom_list != null -> ModelConstraint.Only(ModelCustomListId(custom_list))
+ location != null -> ModelConstraint.Only(location.toDomain())
else -> throw IllegalArgumentException("Invalid location constraint")
}
@Suppress("ReturnCount")
-internal fun ManagementInterface.GeographicLocationConstraint.toDomain(): GeoLocationId {
- val country = GeoLocationId.Country(country)
- if (!hasCity()) {
+internal fun GeographicLocationConstraint.toDomain(): ModelGeoLocationId {
+ val country = ModelGeoLocationId.Country(country)
+ if (city == null) {
return country
}
- val city = GeoLocationId.City(country, city)
- if (!hasHostname()) {
+ val city = ModelGeoLocationId.City(country, city)
+ if (hostname == null) {
return city
}
- return GeoLocationId.Hostname(city, hostname)
+ return ModelGeoLocationId.Hostname(city, hostname)
}
-internal fun List<String>.toDomain(): Constraint<Providers> =
- if (isEmpty()) Constraint.Any else Constraint.Only(map { ProviderId(it) }.toSet())
+internal fun List<String>.toDomain(): ModelConstraint<ModelProviders> =
+ if (isEmpty()) ModelConstraint.Any
+ else ModelConstraint.Only(map { ModelProviderId(it) }.toSet())
-internal fun ManagementInterface.WireguardConstraints.toDomain(): WireguardConstraints =
- WireguardConstraints(
- isMultihopEnabled = useMultihop,
- entryLocation = entryLocationOrNull?.toDomain() ?: Constraint.Any,
+internal fun WireguardConstraints.toDomain(): ModelWireguardConstraints =
+ ModelWireguardConstraints(
+ isMultihopEnabled = use_multihop,
+ entryLocation = entry_location?.toDomain() ?: ModelConstraint.Any,
ipVersion =
- if (hasIpVersion()) {
- Constraint.Only(ipVersion.toDomain())
+ if (ip_version != null) {
+ ModelConstraint.Only(ip_version.toDomain())
} else {
- Constraint.Any
+ ModelConstraint.Any
},
)
-internal fun ManagementInterface.Ownership.toDomain(): Constraint<Ownership> =
+internal fun Ownership.toDomain(): ModelConstraint<ModelOwnership> =
when (this) {
- ManagementInterface.Ownership.ANY -> Constraint.Any
- ManagementInterface.Ownership.MULLVAD_OWNED -> Constraint.Only(Ownership.MullvadOwned)
- ManagementInterface.Ownership.RENTED -> Constraint.Only(Ownership.Rented)
- ManagementInterface.Ownership.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized ownership")
+ Ownership.ANY -> ModelConstraint.Any
+ Ownership.MULLVAD_OWNED -> ModelConstraint.Only(ModelOwnership.MullvadOwned)
+ Ownership.RENTED -> ModelConstraint.Only(ModelOwnership.Rented)
}
-internal fun ManagementInterface.ObfuscationSettings.toDomain(): ObfuscationSettings =
- ObfuscationSettings(
- selectedObfuscationMode = selectedObfuscation.toDomain(),
- udp2tcp = udp2Tcp.toDomain(),
- shadowsocks = shadowsocks.toDomain(),
- wireguardPort = wireguardPort.toDomain(),
+internal fun ObfuscationSettings.toDomain(): ModelObfuscationSettings =
+ ModelObfuscationSettings(
+ selectedObfuscationMode = selected_obfuscation.toDomain(),
+ udp2tcp = udp2tcp!!.toDomain(),
+ shadowsocks = shadowsocks!!.toDomain(),
+ wireguardPort = wireguard_port!!.toDomain(),
)
-internal fun ManagementInterface.ObfuscationSettings.SelectedObfuscation.toDomain():
- ObfuscationMode =
+internal fun ObfuscationSettings.SelectedObfuscation.toDomain(): ModelObfuscationMode =
when (this) {
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.AUTO -> ObfuscationMode.Auto
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.OFF -> ObfuscationMode.Off
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.UDP2TCP ->
- ObfuscationMode.Udp2Tcp
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.SHADOWSOCKS ->
- ObfuscationMode.Shadowsocks
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.QUIC -> ObfuscationMode.Quic
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.LWO -> ObfuscationMode.Lwo
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.WIREGUARD_PORT ->
- ObfuscationMode.WireguardPort
- ManagementInterface.ObfuscationSettings.SelectedObfuscation.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized selected obfuscation")
+ ObfuscationSettings.SelectedObfuscation.AUTO -> ObfuscationMode.Auto
+ ObfuscationSettings.SelectedObfuscation.OFF -> ObfuscationMode.Off
+ ObfuscationSettings.SelectedObfuscation.UDP2TCP -> ObfuscationMode.Udp2Tcp
+ ObfuscationSettings.SelectedObfuscation.SHADOWSOCKS -> ObfuscationMode.Shadowsocks
+ ObfuscationSettings.SelectedObfuscation.QUIC -> ObfuscationMode.Quic
+ ObfuscationSettings.SelectedObfuscation.LWO -> ObfuscationMode.Lwo
+ ObfuscationSettings.SelectedObfuscation.WIREGUARD_PORT -> ObfuscationMode.WireguardPort
}
-internal fun ManagementInterface.ObfuscationSettings.Udp2TcpObfuscation.toDomain():
- Udp2TcpObfuscationSettings =
- if (hasPort()) {
- Udp2TcpObfuscationSettings(Constraint.Only(Port(port)))
+internal fun ObfuscationSettings.Udp2TcpObfuscation.toDomain(): ModelUdp2TcpObfuscationSettings =
+ if (port != null) {
+ ModelUdp2TcpObfuscationSettings(Constraint.Only(Port(port)))
} else {
- Udp2TcpObfuscationSettings(Constraint.Any)
+ ModelUdp2TcpObfuscationSettings(ModelConstraint.Any)
}
-internal fun ManagementInterface.ObfuscationSettings.Shadowsocks.toDomain():
- ShadowsocksObfuscationSettings =
- if (hasPort()) {
- ShadowsocksObfuscationSettings(Constraint.Only(Port(port)))
+internal fun ObfuscationSettings.Shadowsocks.toDomain(): ModelShadowsocksObfuscationSettings =
+ if (port != null) {
+ ModelShadowsocksObfuscationSettings(Constraint.Only(Port(port)))
} else {
- ShadowsocksObfuscationSettings(Constraint.Any)
+ ModelShadowsocksObfuscationSettings(Constraint.Any)
}
-internal fun ManagementInterface.ObfuscationSettings.WireguardPort.toDomain(): Constraint<Port> =
- if (hasPort()) {
+internal fun ObfuscationSettings.WireguardPort.toDomain(): Constraint<Port> =
+ if (port != null) {
Constraint.Only(Port(port))
} else {
Constraint.Any
}
-internal fun ManagementInterface.CustomList.toDomain(): CustomList =
- CustomList(
- id = CustomListId(id),
- name = CustomListName.fromString(name),
- locations = locationsList.map { it.toDomain() },
+internal fun CustomList.toDomain(): ModelCustomList =
+ ModelCustomList(
+ id = ModelCustomListId(id),
+ name = ModelCustomListName.fromString(name),
+ locations = locations.map { it.toDomain() },
)
-internal fun ManagementInterface.TunnelOptions.toDomain(): TunnelOptions =
- TunnelOptions(
- mtu = if (hasMtu()) Mtu(mtu) else null,
- quantumResistant = quantumResistant.toDomain(),
- daitaSettings = daita.toDomain(),
- dnsOptions = dnsOptions.toDomain(),
- enableIpv6 = enableIpv6,
+internal fun TunnelOptions.toDomain(): ModelTunnelOptions =
+ ModelTunnelOptions(
+ mtu = if (mtu != null) ModelMtu(mtu) else null,
+ quantumResistant = quantum_resistant!!.toDomain(),
+ daitaSettings = daita!!.toDomain(),
+ dnsOptions = dns_options!!.toDomain(),
+ enableIpv6 = enable_ipv6,
)
-internal fun ManagementInterface.DaitaSettings.toDomain(): DaitaSettings =
- DaitaSettings(enabled = enabled, directOnly = directOnly)
+internal fun DaitaSettings.toDomain(): ModelDaitaSettings =
+ ModelDaitaSettings(enabled = enabled, directOnly = direct_only)
-internal fun ManagementInterface.QuantumResistantState.toDomain(): QuantumResistantState =
+internal fun QuantumResistantState.toDomain(): ModelQuantumResistantState =
when (state) {
- ManagementInterface.QuantumResistantState.State.ON -> QuantumResistantState.On
- ManagementInterface.QuantumResistantState.State.OFF -> QuantumResistantState.Off
- ManagementInterface.QuantumResistantState.State.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized quantum resistant state")
- else -> throw NullPointerException("Quantum resistant state is null")
+ QuantumResistantState.State.ON -> ModelQuantumResistantState.On
+ QuantumResistantState.State.OFF -> ModelQuantumResistantState.Off
}
-internal fun ManagementInterface.DnsOptions.toDomain(): DnsOptions =
- DnsOptions(
+internal fun DnsOptions.toDomain(): ModelDnsOptions =
+ ModelDnsOptions(
state = state.toDomain(),
- defaultOptions = defaultOptions.toDomain(),
- customOptions = customOptions.toDomain(),
+ defaultOptions = default_options!!.toDomain(),
+ customOptions = custom_options!!.toDomain(),
)
-internal fun ManagementInterface.DnsOptions.DnsState.toDomain(): DnsState =
+internal fun DnsOptions.DnsState.toDomain(): ModelDnsState =
when (this) {
- ManagementInterface.DnsOptions.DnsState.DEFAULT -> DnsState.Default
- ManagementInterface.DnsOptions.DnsState.CUSTOM -> DnsState.Custom
- ManagementInterface.DnsOptions.DnsState.UNRECOGNIZED ->
- throw IllegalArgumentException("Unrecognized dns state")
+ DnsOptions.DnsState.DEFAULT -> ModelDnsState.Default
+ DnsOptions.DnsState.CUSTOM -> ModelDnsState.Custom
}
-internal fun ManagementInterface.DefaultDnsOptions.toDomain() =
- DefaultDnsOptions(
- blockAds = blockAds,
- blockMalware = blockMalware,
- blockAdultContent = blockAdultContent,
- blockGambling = blockGambling,
- blockSocialMedia = blockSocialMedia,
- blockTrackers = blockTrackers,
+internal fun DefaultDnsOptions.toDomain() =
+ ModelDefaultDnsOptions(
+ blockAds = block_ads,
+ blockMalware = block_malware,
+ blockAdultContent = block_adult_content,
+ blockGambling = block_gambling,
+ blockSocialMedia = block_social_media,
+ blockTrackers = block_trackers,
)
-internal fun ManagementInterface.CustomDnsOptions.toDomain() =
- CustomDnsOptions(addressesList.map { InetAddress.getByName(it) })
-
-internal fun QuantumResistantState.toDomain(): ManagementInterface.QuantumResistantState =
- ManagementInterface.QuantumResistantState.newBuilder()
- .setState(
- when (this) {
- QuantumResistantState.On -> ManagementInterface.QuantumResistantState.State.ON
- QuantumResistantState.Off -> ManagementInterface.QuantumResistantState.State.OFF
- }
- )
- .build()
+internal fun CustomDnsOptions.toDomain() =
+ ModelCustomDnsOptions(addresses.map { InetAddress.getByName(it) })
-internal fun ManagementInterface.AppVersionInfo.toDomain(): AppVersionInfo =
- AppVersionInfo(
- supported = supported,
- suggestedUpgrade = if (hasSuggestedUpgrade()) suggestedUpgrade.version else null,
- )
+internal fun AppVersionInfo.toDomain(): ModelAppVersionInfo =
+ ModelAppVersionInfo(supported = supported, suggestedUpgrade = suggested_upgrade?.version)
-internal fun ConnectivityState.toDomain(): GrpcConnectivityState =
- when (this) {
- ConnectivityState.CONNECTING -> GrpcConnectivityState.Connecting
- ConnectivityState.READY -> GrpcConnectivityState.Ready
- ConnectivityState.IDLE -> GrpcConnectivityState.Idle
- ConnectivityState.TRANSIENT_FAILURE -> GrpcConnectivityState.TransientFailure
- ConnectivityState.SHUTDOWN -> GrpcConnectivityState.Shutdown
- }
+/*internal fun ConnectivityState.toDomain(): GrpcConnectivityState =
+when (this) {
+ ConnectivityState.CONNECTING -> GrpcConnectivityState.Connecting
+ ConnectivityState.READY -> GrpcConnectivityState.Ready
+ ConnectivityState.IDLE -> GrpcConnectivityState.Idle
+ ConnectivityState.TRANSIENT_FAILURE -> GrpcConnectivityState.TransientFailure
+ ConnectivityState.SHUTDOWN -> GrpcConnectivityState.Shutdown
+}*/
-internal fun ManagementInterface.RelayList.toDomain(): RelayList =
- RelayList(countriesList.toDomain(), endpointData.toDomain())
+internal fun RelayList.toDomain(): ModelRelayList =
+ ModelRelayList(countries.toDomain(), endpoint_data!!.toDomain())
-internal fun ManagementInterface.WireguardEndpointData.toDomain(): WireguardEndpointData =
- WireguardEndpointData(
- portRangesList.map { it.toDomain() },
- shadowsocksPortRangesList.map { it.toDomain() },
+internal fun WireguardEndpointData.toDomain(): ModelWireguardEndpointData =
+ ModelWireguardEndpointData(
+ port_ranges.map { it.toDomain() },
+ shadowsocks_port_ranges.map { it.toDomain() },
)
-internal fun ManagementInterface.PortRange.toDomain(): PortRange = PortRange(first..last)
+internal fun PortRange.toDomain(): ModelPortRange = ModelPortRange(first..last)
/**
- * Convert from a list of ManagementInterface.RelayListCountry to a model.RelayList. Non-wireguard
- * relays are filtered out. So are also cities that only contains non-wireguard relays and countries
- * that does not have any cities. Countries, cities and relays are ordered by name.
+ * Convert from a list of RelayListCountry to a model.RelayList. Non-wireguard relays are filtered
+ * out. So are also cities that only contains non-wireguard relays and countries that does not have
+ * any cities. Countries, cities and relays are ordered by name.
*/
-internal fun List<ManagementInterface.RelayListCountry>.toDomain():
- List<RelayItem.Location.Country> =
- map(ManagementInterface.RelayListCountry::toDomain)
- .filter { it.cities.isNotEmpty() }
- .sortedBy { it.name }
+internal fun List<RelayListCountry>.toDomain(): List<ModelRelayItem.Location.Country> =
+ map(RelayListCountry::toDomain).filter { it.cities.isNotEmpty() }.sortedBy { it.name }
-internal fun ManagementInterface.RelayListCountry.toDomain(): RelayItem.Location.Country {
- val countryCode = GeoLocationId.Country(code)
- return RelayItem.Location.Country(
+internal fun RelayListCountry.toDomain(): ModelRelayItem.Location.Country {
+ val countryCode = ModelGeoLocationId.Country(code)
+ return ModelRelayItem.Location.Country(
countryCode,
name,
- citiesList
+ cities
.map { city -> city.toDomain(countryCode) }
.filter { it.relays.isNotEmpty() }
.sortedBy { it.name },
)
}
-internal fun ManagementInterface.RelayListCity.toDomain(
- countryCode: GeoLocationId.Country
-): RelayItem.Location.City {
- val cityCode = GeoLocationId.City(countryCode, code)
- return RelayItem.Location.City(
+internal fun RelayListCity.toDomain(
+ countryCode: ModelGeoLocationId.Country
+): ModelRelayItem.Location.City {
+ val cityCode = ModelGeoLocationId.City(countryCode, code)
+ return ModelRelayItem.Location.City(
name = name,
id = cityCode,
- relays = relaysList.map { it.toDomain(cityCode) }.sortedWith(RelayNameComparator),
+ relays = relays.map { it.toDomain(cityCode) }.sortedWith(RelayNameComparator),
)
}
-internal fun ManagementInterface.Relay.toDomain(
- cityCode: GeoLocationId.City
-): RelayItem.Location.Relay =
- RelayItem.Location.Relay(
- id = GeoLocationId.Hostname(cityCode, hostname),
+internal fun Relay.toDomain(cityCode: ModelGeoLocationId.City): ModelRelayItem.Location.Relay =
+ ModelRelayItem.Location.Relay(
+ id = ModelGeoLocationId.Hostname(cityCode, hostname),
active = active,
provider = ProviderId(provider),
- ownership = if (owned) Ownership.MullvadOwned else Ownership.Rented,
- daita = endpointData.daita,
- quic =
- if (endpointData.hasQuic()) {
- endpointData.quic.toDomain()
- } else {
- null
- },
- lwo = endpointData.lwo,
+ ownership = if (owned) ModelOwnership.MullvadOwned else ModelOwnership.Rented,
+ daita = endpoint_data?.daita ?: false,
+ quic = endpoint_data?.quic?.toDomain(),
+ lwo = endpoint_data?.lwo ?: false,
)
-private fun ManagementInterface.Relay.WireguardEndpoint.Quic.toDomain(): Quic =
- Quic(inAddresses = addrInList.map { it.toInetAddress() })
+private fun Relay.WireguardEndpoint.Quic.toDomain(): Quic =
+ Quic(inAddresses = addr_in.map { it.toInetAddress() })
private fun Instant.atDefaultZone() = atZone(ZoneId.systemDefault())
-internal fun ManagementInterface.Device.toDomain(): Device =
- Device(DeviceId.fromString(id), name, Instant.ofEpochSecond(created.seconds).atDefaultZone())
+internal fun Device.toDomain(): ModelDevice =
+ ModelDevice(ModelDeviceId.fromString(id), name, created!!.atDefaultZone())
-internal fun ManagementInterface.DeviceState.toDomain(): DeviceState =
+internal fun DeviceState.toDomain(): ModelDeviceState =
when (state) {
- ManagementInterface.DeviceState.State.LOGGED_IN ->
- DeviceState.LoggedIn(AccountNumber(device.accountNumber), device.device.toDomain())
- ManagementInterface.DeviceState.State.LOGGED_OUT -> DeviceState.LoggedOut
- ManagementInterface.DeviceState.State.REVOKED -> DeviceState.Revoked
- ManagementInterface.DeviceState.State.UNRECOGNIZED ->
- throw IllegalArgumentException("Non valid device state")
+ DeviceState.State.LOGGED_IN if device != null && device.device != null ->
+ ModelDeviceState.LoggedIn(
+ ModelAccountNumber(device.account_number),
+ device.device.toDomain(),
+ )
+ DeviceState.State.LOGGED_OUT -> ModelDeviceState.LoggedOut
+ DeviceState.State.REVOKED -> ModelDeviceState.Revoked
else -> throw NullPointerException("Device state is null")
}
-internal fun ManagementInterface.AccountData.toDomain(accountNumber: AccountNumber): AccountData =
- AccountData(
+internal fun AccountData.toDomain(accountNumber: ModelAccountNumber): ModelAccountData =
+ ModelAccountData(
id = AccountId(UUID.fromString(id)),
accountNumber = accountNumber,
- expiryDate = Instant.ofEpochSecond(expiry.seconds).atDefaultZone(),
+ expiryDate = expiry!!.atDefaultZone(),
)
-internal fun ManagementInterface.VoucherSubmission.toDomain(): RedeemVoucherSuccess =
- RedeemVoucherSuccess(
- timeAdded = secondsAdded,
- newExpiryDate = Instant.ofEpochSecond(newExpiry.seconds).atDefaultZone(),
+internal fun VoucherSubmission.toDomain(): ModelRedeemVoucherSuccess =
+ ModelRedeemVoucherSuccess(
+ timeAdded = seconds_added,
+ newExpiryDate = new_expiry!!.atDefaultZone(),
)
-internal fun ManagementInterface.SplitTunnelSettings.toDomain(): SplitTunnelSettings =
- SplitTunnelSettings(
- enabled = enableExclusions,
- excludedApps = appsList.map { AppId(it) }.toSet(),
+internal fun SplitTunnelSettings.toDomain(): ModelSplitTunnelSettings =
+ ModelSplitTunnelSettings(
+ enabled = enable_exclusions,
+ excludedApps = apps.map { AppId(it) }.toSet(),
)
-internal fun ManagementInterface.PlayPurchasePaymentToken.toDomain(): PlayPurchasePaymentToken =
- PlayPurchasePaymentToken(value = token)
+internal fun PlayPurchasePaymentToken.toDomain(): ModelPlayPurchasePaymentToken =
+ ModelPlayPurchasePaymentToken(value = token)
-internal fun ManagementInterface.ApiAccessMethodSettings.toDomain(): List<ApiAccessMethodSetting> =
- buildList {
+internal fun ApiAccessMethodSettings.toDomain(): List<ModelApiAccessMethodSetting> = buildList {
+ if (direct != null) {
add(direct.toDomain())
- add(mullvadBridges.toDomain())
- add(encryptedDnsProxy.toDomain())
- addAll(customList.map { it.toDomain() })
}
+ if (mullvad_bridges != null) {
+ add(mullvad_bridges.toDomain())
+ }
+ if (encrypted_dns_proxy != null) {
+ add(encrypted_dns_proxy.toDomain())
+ }
+ addAll(custom.map { it.toDomain() })
+}
-internal fun ManagementInterface.AccessMethodSetting.toDomain(): ApiAccessMethodSetting =
- ApiAccessMethodSetting(
- id = ApiAccessMethodId.fromString(id.value),
- name = ApiAccessMethodName.fromString(name),
+internal fun AccessMethodSetting.toDomain(): ModelApiAccessMethodSetting =
+ ModelApiAccessMethodSetting(
+ id = ModelApiAccessMethodId.fromString(id!!.value_),
+ name = ModelApiAccessMethodName.fromString(name),
enabled = enabled,
- apiAccessMethod = accessMethod.toDomain(),
+ apiAccessMethod = access_method.toDomain(),
)
-internal fun ManagementInterface.AccessMethod.toDomain(): ApiAccessMethod =
+internal fun AccessMethod?.toDomain(): ModelApiAccessMethod =
when {
- hasDirect() -> ApiAccessMethod.Direct
- hasBridges() -> ApiAccessMethod.Bridges
- hasEncryptedDnsProxy() -> ApiAccessMethod.EncryptedDns
- hasCustom() -> custom.toDomain()
+ this == null -> error("Access method is null")
+ direct != null -> ModelApiAccessMethod.Direct
+ bridges != null -> ModelApiAccessMethod.Bridges
+ encrypted_dns_proxy != null -> ModelApiAccessMethod.EncryptedDns
+ custom != null -> custom.toDomain()
else -> error("Type not found")
}
-internal fun ManagementInterface.CustomProxy.toDomain(): ApiAccessMethod.CustomProxy =
+internal fun CustomProxy.toDomain(): ModelApiAccessMethod.CustomProxy =
when {
- hasShadowsocks() -> shadowsocks.toDomain()
- hasSocks5Remote() -> socks5Remote.toDomain()
- hasSocks5Local() -> error("Socks5 local not supported")
+ shadowsocks != null -> shadowsocks.toDomain()
+ socks5remote != null -> socks5remote.toDomain()
+ socks5local != null -> error("Socks5 local not supported")
else -> error("Custom proxy not found")
}
-internal fun ManagementInterface.Shadowsocks.toDomain(): ApiAccessMethod.CustomProxy.Shadowsocks =
- ApiAccessMethod.CustomProxy.Shadowsocks(
+internal fun Shadowsocks.toDomain(): ModelApiAccessMethod.CustomProxy.Shadowsocks =
+ ModelApiAccessMethod.CustomProxy.Shadowsocks(
ip = ip,
- port = Port(port),
+ port = ModelPort(port),
password = password,
- cipher = Cipher.fromString(cipher),
+ cipher = ModelCipher.fromString(cipher),
)
-internal fun ManagementInterface.Socks5Remote.toDomain(): ApiAccessMethod.CustomProxy.Socks5Remote =
- ApiAccessMethod.CustomProxy.Socks5Remote(
+internal fun Socks5Remote.toDomain(): ModelApiAccessMethod.CustomProxy.Socks5Remote =
+ ModelApiAccessMethod.CustomProxy.Socks5Remote(
ip = ip,
- port = Port(port),
- auth =
- if (hasAuth()) {
- auth.toDomain()
- } else {
- null
- },
+ port = ModelPort(port),
+ auth = auth?.toDomain(),
)
-internal fun ManagementInterface.SocksAuth.toDomain(): SocksAuth =
- SocksAuth(username = username, password = password)
+internal fun SocksAuth.toDomain(): ModelSocksAuth =
+ ModelSocksAuth(username = username, password = password)
-internal fun ManagementInterface.FeatureIndicators.toDomain(): List<FeatureIndicator> =
- activeFeaturesList.map { it.toDomain() }.sorted()
+internal fun FeatureIndicators.toDomain(): List<ModelFeatureIndicator> =
+ active_features.map { it.toDomain() }.sorted()
@Suppress("ComplexMethod")
-internal fun ManagementInterface.FeatureIndicator.toDomain() =
+internal fun FeatureIndicator.toDomain(): ModelFeatureIndicator =
when (this) {
- ManagementInterface.FeatureIndicator.QUANTUM_RESISTANCE ->
- FeatureIndicator.QUANTUM_RESISTANCE
- ManagementInterface.FeatureIndicator.SPLIT_TUNNELING -> FeatureIndicator.SPLIT_TUNNELING
- ManagementInterface.FeatureIndicator.UDP_2_TCP -> FeatureIndicator.UDP_2_TCP
- ManagementInterface.FeatureIndicator.LAN_SHARING -> FeatureIndicator.LAN_SHARING
- ManagementInterface.FeatureIndicator.DNS_CONTENT_BLOCKERS ->
- FeatureIndicator.DNS_CONTENT_BLOCKERS
- ManagementInterface.FeatureIndicator.CUSTOM_DNS -> FeatureIndicator.CUSTOM_DNS
- ManagementInterface.FeatureIndicator.SERVER_IP_OVERRIDE ->
- FeatureIndicator.SERVER_IP_OVERRIDE
- ManagementInterface.FeatureIndicator.CUSTOM_MTU -> FeatureIndicator.CUSTOM_MTU
- ManagementInterface.FeatureIndicator.DAITA -> FeatureIndicator.DAITA
- ManagementInterface.FeatureIndicator.SHADOWSOCKS -> FeatureIndicator.SHADOWSOCKS
- ManagementInterface.FeatureIndicator.MULTIHOP -> FeatureIndicator.MULTIHOP
- ManagementInterface.FeatureIndicator.DAITA_MULTIHOP -> FeatureIndicator.DAITA_MULTIHOP
- ManagementInterface.FeatureIndicator.QUIC -> FeatureIndicator.QUIC
- ManagementInterface.FeatureIndicator.LWO -> FeatureIndicator.LWO
- ManagementInterface.FeatureIndicator.WIREGUARD_PORT -> FeatureIndicator.WIREGUARD_PORT
- ManagementInterface.FeatureIndicator.LOCKDOWN_MODE,
- ManagementInterface.FeatureIndicator.UNRECOGNIZED ->
- error("Feature not supported ${this.name}")
+ FeatureIndicator.QUANTUM_RESISTANCE -> ModelFeatureIndicator.QUANTUM_RESISTANCE
+ FeatureIndicator.SPLIT_TUNNELING -> ModelFeatureIndicator.SPLIT_TUNNELING
+ FeatureIndicator.UDP_2_TCP -> ModelFeatureIndicator.UDP_2_TCP
+ FeatureIndicator.LAN_SHARING -> ModelFeatureIndicator.LAN_SHARING
+ FeatureIndicator.DNS_CONTENT_BLOCKERS -> ModelFeatureIndicator.DNS_CONTENT_BLOCKERS
+ FeatureIndicator.CUSTOM_DNS -> ModelFeatureIndicator.CUSTOM_DNS
+ FeatureIndicator.SERVER_IP_OVERRIDE -> ModelFeatureIndicator.SERVER_IP_OVERRIDE
+ FeatureIndicator.CUSTOM_MTU -> ModelFeatureIndicator.CUSTOM_MTU
+ FeatureIndicator.DAITA -> ModelFeatureIndicator.DAITA
+ FeatureIndicator.SHADOWSOCKS -> ModelFeatureIndicator.SHADOWSOCKS
+ FeatureIndicator.MULTIHOP -> ModelFeatureIndicator.MULTIHOP
+ FeatureIndicator.DAITA_MULTIHOP -> ModelFeatureIndicator.DAITA_MULTIHOP
+ FeatureIndicator.QUIC -> ModelFeatureIndicator.QUIC
+ FeatureIndicator.LWO -> ModelFeatureIndicator.LWO
+ FeatureIndicator.WIREGUARD_PORT -> ModelFeatureIndicator.WIREGUARD_PORT
+ FeatureIndicator.LOCKDOWN_MODE -> error("Feature not supported ${this.name}")
}
-internal fun ManagementInterface.IpVersion.toDomain() =
+internal fun IpVersion.toDomain() =
when (this) {
- ManagementInterface.IpVersion.V4 -> IpVersion.IPV4
- ManagementInterface.IpVersion.V6 -> IpVersion.IPV6
- ManagementInterface.IpVersion.UNRECOGNIZED -> error("Not supported ${this.name}")
+ IpVersion.V4 -> ModelIpVersion.IPV4
+ IpVersion.V6 -> ModelIpVersion.IPV6
}
-internal fun ManagementInterface.Recents?.toDomain(): Recents =
+internal fun Recents?.toDomain(): ModelRecents =
if (this != null) {
- Recents.Enabled(recentsList.map { it.toDomain() })
+ ModelRecents.Enabled(recents = recents.map { it.toDomain() })
} else {
- Recents.Disabled
+ ModelRecents.Disabled
}
-internal fun ManagementInterface.Recent.toDomain(): Recent =
- when (typeCase) {
- ManagementInterface.Recent.TypeCase.MULTIHOP ->
- Recent.Multihop(
- entry = (multihop.entry.toDomain() as Constraint.Only).value,
- exit = (multihop.exit.toDomain() as Constraint.Only).value,
+internal fun Recent.toDomain(): ModelRecent =
+ when {
+ multihop != null ->
+ ModelRecent.Multihop(
+ entry = (multihop.entry!!.toDomain() as ModelConstraint.Only).value,
+ exit = (multihop.exit!!.toDomain() as ModelConstraint.Only).value,
)
- ManagementInterface.Recent.TypeCase.SINGLEHOP ->
- Recent.Singlehop((singlehop.toDomain() as Constraint.Only).value)
+ singlehop != null ->
+ ModelRecent.Singlehop((singlehop.toDomain() as ModelConstraint.Only).value)
- ManagementInterface.Recent.TypeCase.TYPE_NOT_SET -> error("Recent type must be set")
+ else -> error("Recent type must be set")
}
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/LogInterceptor.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/LogInterceptor.kt
index 1bff85300f..ccc775fc2b 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/LogInterceptor.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/LogInterceptor.kt
@@ -1,19 +1,21 @@
package net.mullvad.mullvadvpn.lib.daemon.grpc.util
import co.touchlab.kermit.Logger
-import io.grpc.CallOptions
-import io.grpc.Channel
-import io.grpc.ClientCall
-import io.grpc.ClientInterceptor
-import io.grpc.MethodDescriptor
+import okhttp3.Interceptor
+import okhttp3.Response
-internal class LogInterceptor : ClientInterceptor {
- override fun <ReqT : Any?, RespT : Any?> interceptCall(
+internal class LogInterceptor : Interceptor {
+ /*override fun <ReqT : Any?, RespT : Any?> interceptCall(
method: MethodDescriptor<ReqT, RespT>?,
callOptions: CallOptions?,
next: Channel?,
): ClientCall<ReqT, RespT> {
Logger.v("Intercepted call: ${method?.fullMethodName}")
return next!!.newCall(method, callOptions)
+ }*/
+
+ override fun intercept(chain: Interceptor.Chain): Response {
+ Logger.v("Intercepted call: ${chain.request()}")
+ return chain.proceed(chain.request()).also { Logger.v("Intercepted response $it") }
}
}
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/ManagedChannel.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/ManagedChannel.kt
index 8ce5a10876..e5f8f27972 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/ManagedChannel.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/ManagedChannel.kt
@@ -1,16 +1,15 @@
package net.mullvad.mullvadvpn.lib.daemon.grpc.util
-import co.touchlab.kermit.Logger
-import io.grpc.ConnectivityState
-import io.grpc.ManagedChannel
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.suspendCancellableCoroutine
+import net.mullvad.mullvadvpn.lib.daemon.grpc.GrpcConnectivityState
+import okhttp3.OkHttpClient
-internal fun ManagedChannel.connectivityFlow(): Flow<ConnectivityState> {
+internal fun OkHttpClient.connectivityFlow(): Flow<GrpcConnectivityState> {
return callbackFlow {
- var currentState = getState(false)
+ send(GrpcConnectivityState.Ready)
+ /*var currentState = getState(false)
while (isActive) {
// Check that we are active before sending
@@ -23,6 +22,7 @@ internal fun ManagedChannel.connectivityFlow(): Flow<ConnectivityState> {
}
}
}
- }
+ }*/
+ awaitClose {}
}
}
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/TunnelingUnixSocket.java b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/TunnelingUnixSocket.java
new file mode 100644
index 0000000000..7082f0c434
--- /dev/null
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/TunnelingUnixSocket.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.mullvad.mullvadvpn.lib.daemon.grpc.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import jnr.unixsocket.UnixSocket;
+import jnr.unixsocket.UnixSocketAddress;
+import jnr.unixsocket.UnixSocketChannel;
+
+/**
+ * Subtype UNIX socket for a higher-fidelity impersonation of TCP sockets. This is named "tunneling"
+ * because it assumes the ultimate destination has a hostname and port.
+ */
+final class TunnelingUnixSocket extends UnixSocket {
+ private final File path;
+ private InetSocketAddress inetSocketAddress;
+
+ TunnelingUnixSocket(File path, UnixSocketChannel channel) {
+ super(channel);
+ this.path = path;
+ }
+
+ TunnelingUnixSocket(File path, UnixSocketChannel channel, InetSocketAddress address) {
+ this(path, channel);
+ this.inetSocketAddress = address;
+ }
+
+ @Override public void connect(SocketAddress endpoint) throws IOException {
+ this.inetSocketAddress = (InetSocketAddress) endpoint;
+ super.connect(new UnixSocketAddress(path), 0);
+ }
+
+ @Override public void connect(SocketAddress endpoint, int timeout) throws IOException {
+ this.inetSocketAddress = (InetSocketAddress) endpoint;
+ super.connect(new UnixSocketAddress(path), timeout);
+ }
+
+ @Override public InetAddress getInetAddress() {
+ return inetSocketAddress.getAddress();
+ }
+}
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/UnixDomainSocketFactory.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/UnixDomainSocketFactory.kt
new file mode 100644
index 0000000000..019f47ce76
--- /dev/null
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/util/UnixDomainSocketFactory.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.mullvad.mullvadvpn.lib.daemon.grpc.util
+
+import java.net.InetAddress
+import java.net.Socket
+import java.net.SocketAddress
+import javax.net.SocketFactory
+import org.newsclub.net.unix.AFSocketAddress
+
+/** Impersonate TCP-style SocketFactory over UNIX domain sockets. */
+class UnixDomainSocketFactory(private val addr: SocketAddress) : SocketFactory() {
+
+ override fun createSocket(): Socket {
+ val socket = AFSocketAddress.mapOrFail(addr).getAddressFamily().newSocket()
+ socket.forceConnectAddress(addr)
+ return socket
+ }
+
+ override fun createSocket(host: String?, port: Int): Socket {
+ return createSocket()
+ }
+
+ override fun createSocket(
+ host: String,
+ port: Int,
+ localHost: InetAddress,
+ localPort: Int,
+ ): Socket {
+ return createSocket(host, port)
+ }
+
+ override fun createSocket(host: InetAddress?, port: Int): Socket {
+ return createSocket()
+ }
+
+ override fun createSocket(
+ host: InetAddress?,
+ port: Int,
+ localAddress: InetAddress?,
+ localPort: Int,
+ ): Socket {
+ return createSocket(host, port)
+ }
+}