diff options
Diffstat (limited to 'android/lib')
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) + } +} |
