diff --git a/coreexample/src/main/kotlin/me/proton/android/core/coreexample/di/NetworkModule.kt b/coreexample/src/main/kotlin/me/proton/android/core/coreexample/di/NetworkModule.kt index 9294955f1..e754ed8fe 100644 --- a/coreexample/src/main/kotlin/me/proton/android/core/coreexample/di/NetworkModule.kt +++ b/coreexample/src/main/kotlin/me/proton/android/core/coreexample/di/NetworkModule.kt @@ -36,6 +36,7 @@ import me.proton.core.network.data.ApiManagerFactory import me.proton.core.network.data.ProtonCookieStore import me.proton.core.network.data.client.ClientIdProviderImpl import me.proton.core.network.data.client.ExtraHeaderProviderImpl +import me.proton.core.network.data.di.SharedOkHttpClient import me.proton.core.network.domain.ApiClient import me.proton.core.network.domain.NetworkManager import me.proton.core.network.domain.NetworkPrefs @@ -92,7 +93,8 @@ class NetworkModule { @BaseApiUrl baseApiUrl: String, @DohProviderUrls dohProviderUrls: Array, @CertificatePins certificatePins: Array, - @AlternativeApiPins alternativeApiPins: List + @AlternativeApiPins alternativeApiPins: List, + @SharedOkHttpClient okHttpClient: OkHttpClient ): ApiManagerFactory { return ApiManagerFactory( baseApiUrl, @@ -119,7 +121,8 @@ class NetworkModule { extraHeaderProvider = extraHeaderProvider, clientVersionValidator = clientVersionValidator, dohAlternativesListener = dohAlternativesListener, - dohProviderUrls = dohProviderUrls + dohProviderUrls = dohProviderUrls, + okHttpClient = okHttpClient ) } } @@ -166,9 +169,6 @@ class NetworkCallbacksModule { context.pgpCrypto.updateTime(epochSeconds) } } - - @Provides - fun provideOkHttpClient(): OkHttpClient = OkHttpClient() } @Module diff --git a/human-verification/dagger/build.gradle.kts b/human-verification/dagger/build.gradle.kts index c79df4770..7e135b459 100644 --- a/human-verification/dagger/build.gradle.kts +++ b/human-verification/dagger/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { project(Module.networkDomain), project(Module.cryptoCommon), project(Module.networkData), + project(Module.networkDagger), `room-ktx`, ) diff --git a/human-verification/dagger/src/main/kotlin/me/proton/core/humanverification/dagger/CoreHumanVerificationModule.kt b/human-verification/dagger/src/main/kotlin/me/proton/core/humanverification/dagger/CoreHumanVerificationModule.kt index f20e1b8ba..624d6d8b3 100644 --- a/human-verification/dagger/src/main/kotlin/me/proton/core/humanverification/dagger/CoreHumanVerificationModule.kt +++ b/human-verification/dagger/src/main/kotlin/me/proton/core/humanverification/dagger/CoreHumanVerificationModule.kt @@ -39,6 +39,7 @@ import me.proton.core.humanverification.domain.utils.NetworkRequestOverrider import me.proton.core.humanverification.presentation.HumanVerificationOrchestrator import me.proton.core.humanverification.presentation.utils.HumanVerificationVersion import me.proton.core.network.data.ApiProvider +import me.proton.core.network.data.di.SharedOkHttpClient import me.proton.core.network.domain.humanverification.HumanVerificationListener import me.proton.core.network.domain.humanverification.HumanVerificationProvider import okhttp3.OkHttpClient @@ -56,7 +57,7 @@ public object CoreHumanVerificationModule { @Provides public fun provideNetworkRequestOverrider( - okHttpClient: OkHttpClient, + @SharedOkHttpClient okHttpClient: OkHttpClient, ): NetworkRequestOverrider = NetworkRequestOverriderImpl(okHttpClient) diff --git a/network/dagger/api/network-dagger.api b/network/dagger/api/network-dagger.api index 1c629079b..eac8d296e 100644 --- a/network/dagger/api/network-dagger.api +++ b/network/dagger/api/network-dagger.api @@ -49,3 +49,11 @@ public final class me/proton/core/network/dagger/CoreNetworkModule_ProvideNetwor public static fun provideNetworkPrefs (Lme/proton/core/network/dagger/CoreNetworkModule;Landroid/content/Context;)Lme/proton/core/network/domain/NetworkPrefs; } +public final class me/proton/core/network/dagger/CoreNetworkModule_ProvideOkHttpClientFactory : dagger/internal/Factory { + public fun (Lme/proton/core/network/dagger/CoreNetworkModule;)V + public static fun create (Lme/proton/core/network/dagger/CoreNetworkModule;)Lme/proton/core/network/dagger/CoreNetworkModule_ProvideOkHttpClientFactory; + public synthetic fun get ()Ljava/lang/Object; + public fun get ()Lokhttp3/OkHttpClient; + public static fun provideOkHttpClient (Lme/proton/core/network/dagger/CoreNetworkModule;)Lokhttp3/OkHttpClient; +} + diff --git a/network/dagger/src/main/kotlin/me/proton/core/network/dagger/CoreNetworkModule.kt b/network/dagger/src/main/kotlin/me/proton/core/network/dagger/CoreNetworkModule.kt index c8a14a4bc..2a50cc559 100644 --- a/network/dagger/src/main/kotlin/me/proton/core/network/dagger/CoreNetworkModule.kt +++ b/network/dagger/src/main/kotlin/me/proton/core/network/dagger/CoreNetworkModule.kt @@ -32,9 +32,12 @@ import me.proton.core.network.data.ProtonCookieStore import me.proton.core.network.data.client.ClientVersionValidatorImpl import me.proton.core.network.data.cookie.DiskCookieStorage import me.proton.core.network.data.cookie.MemoryCookieStorage +import me.proton.core.network.data.di.SharedOkHttpClient import me.proton.core.network.domain.NetworkManager import me.proton.core.network.domain.client.ClientVersionValidator import me.proton.core.network.domain.session.SessionProvider +import okhttp3.HttpUrl +import okhttp3.OkHttpClient import javax.inject.Singleton @Module @@ -64,4 +67,9 @@ internal class CoreNetworkModule { @Singleton fun provideApiProvider(apiManagerFactory: ApiManagerFactory, sessionProvider: SessionProvider): ApiProvider = ApiProvider(apiManagerFactory, sessionProvider) + + @Provides + @Singleton + @SharedOkHttpClient + fun provideOkHttpClient(): OkHttpClient = OkHttpClient() } diff --git a/network/data/api/network-data.api b/network/data/api/network-data.api index 3c4f03b94..c69258d09 100644 --- a/network/data/api/network-data.api +++ b/network/data/api/network-data.api @@ -1,6 +1,6 @@ public final class me/proton/core/network/data/ApiManagerFactory { - public fun (Ljava/lang/String;Lme/proton/core/network/domain/ApiClient;Lme/proton/core/network/domain/client/ClientIdProvider;Lme/proton/core/network/domain/server/ServerTimeListener;Lme/proton/core/network/domain/NetworkManager;Lme/proton/core/network/domain/NetworkPrefs;Lme/proton/core/network/domain/session/SessionProvider;Lme/proton/core/network/domain/session/SessionListener;Lme/proton/core/network/domain/humanverification/HumanVerificationProvider;Lme/proton/core/network/domain/humanverification/HumanVerificationListener;Lme/proton/core/network/domain/scopes/MissingScopeListener;Lme/proton/core/network/data/ProtonCookieStore;Lkotlinx/coroutines/CoroutineScope;[Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lme/proton/core/network/domain/client/ExtraHeaderProvider;Lme/proton/core/network/domain/client/ClientVersionValidator;Lme/proton/core/network/domain/serverconnection/DohAlternativesListener;[Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Lme/proton/core/network/domain/ApiClient;Lme/proton/core/network/domain/client/ClientIdProvider;Lme/proton/core/network/domain/server/ServerTimeListener;Lme/proton/core/network/domain/NetworkManager;Lme/proton/core/network/domain/NetworkPrefs;Lme/proton/core/network/domain/session/SessionProvider;Lme/proton/core/network/domain/session/SessionListener;Lme/proton/core/network/domain/humanverification/HumanVerificationProvider;Lme/proton/core/network/domain/humanverification/HumanVerificationListener;Lme/proton/core/network/domain/scopes/MissingScopeListener;Lme/proton/core/network/data/ProtonCookieStore;Lkotlinx/coroutines/CoroutineScope;[Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lme/proton/core/network/domain/client/ExtraHeaderProvider;Lme/proton/core/network/domain/client/ClientVersionValidator;Lme/proton/core/network/domain/serverconnection/DohAlternativesListener;[Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Lme/proton/core/network/domain/ApiClient;Lme/proton/core/network/domain/client/ClientIdProvider;Lme/proton/core/network/domain/server/ServerTimeListener;Lme/proton/core/network/domain/NetworkManager;Lme/proton/core/network/domain/NetworkPrefs;Lme/proton/core/network/domain/session/SessionProvider;Lme/proton/core/network/domain/session/SessionListener;Lme/proton/core/network/domain/humanverification/HumanVerificationProvider;Lme/proton/core/network/domain/humanverification/HumanVerificationListener;Lme/proton/core/network/domain/scopes/MissingScopeListener;Lme/proton/core/network/data/ProtonCookieStore;Lkotlinx/coroutines/CoroutineScope;[Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lme/proton/core/network/domain/client/ExtraHeaderProvider;Lme/proton/core/network/domain/client/ClientVersionValidator;Lme/proton/core/network/domain/serverconnection/DohAlternativesListener;[Ljava/lang/String;Lokhttp3/OkHttpClient;)V + public synthetic fun (Ljava/lang/String;Lme/proton/core/network/domain/ApiClient;Lme/proton/core/network/domain/client/ClientIdProvider;Lme/proton/core/network/domain/server/ServerTimeListener;Lme/proton/core/network/domain/NetworkManager;Lme/proton/core/network/domain/NetworkPrefs;Lme/proton/core/network/domain/session/SessionProvider;Lme/proton/core/network/domain/session/SessionListener;Lme/proton/core/network/domain/humanverification/HumanVerificationProvider;Lme/proton/core/network/domain/humanverification/HumanVerificationListener;Lme/proton/core/network/domain/scopes/MissingScopeListener;Lme/proton/core/network/data/ProtonCookieStore;Lkotlinx/coroutines/CoroutineScope;[Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lme/proton/core/network/domain/client/ExtraHeaderProvider;Lme/proton/core/network/domain/client/ClientVersionValidator;Lme/proton/core/network/domain/serverconnection/DohAlternativesListener;[Ljava/lang/String;Lokhttp3/OkHttpClient;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun create (Lme/proton/core/network/domain/session/SessionId;Lkotlin/reflect/KClass;Ljava/util/List;[Ljava/lang/String;Ljava/util/List;)Lme/proton/core/network/domain/ApiManager; public static synthetic fun create$default (Lme/proton/core/network/data/ApiManagerFactory;Lme/proton/core/network/domain/session/SessionId;Lkotlin/reflect/KClass;Ljava/util/List;[Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lme/proton/core/network/domain/ApiManager; public final fun getBaseOkHttpClient ()Lokhttp3/OkHttpClient; @@ -138,6 +138,9 @@ public final class me/proton/core/network/data/di/Constants { public final fun getDOH_PROVIDERS_URLS ()[Ljava/lang/String; } +public abstract interface annotation class me/proton/core/network/data/di/SharedOkHttpClient : java/lang/annotation/Annotation { +} + public final class me/proton/core/network/data/doh/DnsOverHttpsProviderRFC8484 : me/proton/core/network/domain/DohService { public static final field Companion Lme/proton/core/network/data/doh/DnsOverHttpsProviderRFC8484$Companion; public fun (Lkotlin/jvm/functions/Function0;Ljava/lang/String;Lme/proton/core/network/domain/ApiClient;Lme/proton/core/network/domain/NetworkManager;)V diff --git a/network/data/build.gradle.kts b/network/data/build.gradle.kts index 3a1d9222b..bd0785dc0 100644 --- a/network/data/build.gradle.kts +++ b/network/data/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { `android-annotation`, `apacheCommon-codec`, datastore, + `javax-inject`, `miniDns`, `okHttp-logging`, `retrofit`, diff --git a/network/data/src/main/kotlin/me/proton/core/network/data/ApiManagerFactory.kt b/network/data/src/main/kotlin/me/proton/core/network/data/ApiManagerFactory.kt index 7994088a4..f0189133a 100644 --- a/network/data/src/main/kotlin/me/proton/core/network/data/ApiManagerFactory.kt +++ b/network/data/src/main/kotlin/me/proton/core/network/data/ApiManagerFactory.kt @@ -67,6 +67,7 @@ import kotlin.reflect.KClass * @param cookieStore The storage for cookies. * @param cache [Cache] shared across all user, session, api or call. */ +@Suppress("LongParameterList") class ApiManagerFactory( baseUrl: String, private val apiClient: ApiClient, @@ -87,7 +88,8 @@ class ApiManagerFactory( private val extraHeaderProvider: ExtraHeaderProvider? = null, private val clientVersionValidator: ClientVersionValidator, private val dohAlternativesListener: DohAlternativesListener?, - private val dohProviderUrls: Array = Constants.DOH_PROVIDERS_URLS + private val dohProviderUrls: Array = Constants.DOH_PROVIDERS_URLS, + private val okHttpClient: OkHttpClient ) { private val baseUri = URI(baseUrl) @@ -110,7 +112,7 @@ class ApiManagerFactory( require(clientVersionValidator.validate(apiClient.appVersionHeader)) { "Invalid app version code: ${apiClient.appVersionHeader}." } - OkHttpClient.Builder() + okHttpClient.newBuilder() .cache(cache()) .connectTimeout(apiClient.timeoutSeconds, TimeUnit.SECONDS) .writeTimeout(apiClient.timeoutSeconds, TimeUnit.SECONDS) diff --git a/network/data/src/main/kotlin/me/proton/core/network/data/di/Qualifiers.kt b/network/data/src/main/kotlin/me/proton/core/network/data/di/Qualifiers.kt new file mode 100644 index 000000000..e501f1a63 --- /dev/null +++ b/network/data/src/main/kotlin/me/proton/core/network/data/di/Qualifiers.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Proton Technologies AG + * This file is part of Proton AG and ProtonCore. + * + * ProtonCore is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonCore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonCore. If not, see . + */ + +package me.proton.core.network.data.di + +import javax.inject.Qualifier + +/** Qualifier for a shared (singleton) instance of [okhttp3.OkHttpClient]. + * Whenever you need a custom [okhttp3.OkHttpClient], inject this instance, + * and use [okhttp3.OkHttpClient.newBuilder] to adjust to your own needs. + */ +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class SharedOkHttpClient diff --git a/network/data/src/test/java/me/proton/core/network/data/ApiManagerTests.kt b/network/data/src/test/java/me/proton/core/network/data/ApiManagerTests.kt index 50d9fb712..3e9c3720f 100644 --- a/network/data/src/test/java/me/proton/core/network/data/ApiManagerTests.kt +++ b/network/data/src/test/java/me/proton/core/network/data/ApiManagerTests.kt @@ -161,7 +161,8 @@ internal class ApiManagerTests { scope, cache = { null }, clientVersionValidator = clientVersionValidator, - dohAlternativesListener = null + dohAlternativesListener = null, + okHttpClient = mockk(relaxed = true) ) coEvery { dohService.getAlternativeBaseUrls(any(), any()) } returns listOf(proxy1url) diff --git a/network/data/src/test/java/me/proton/core/network/data/HumanVerificationTests.kt b/network/data/src/test/java/me/proton/core/network/data/HumanVerificationTests.kt index 65c1147cb..d4f5c521c 100644 --- a/network/data/src/test/java/me/proton/core/network/data/HumanVerificationTests.kt +++ b/network/data/src/test/java/me/proton/core/network/data/HumanVerificationTests.kt @@ -175,7 +175,8 @@ internal class HumanVerificationTests { scope, cache = { null }, clientVersionValidator = clientVersionValidator, - dohAlternativesListener = null + dohAlternativesListener = null, + okHttpClient = OkHttpClient() ) every { networkManager.isConnectedToNetwork() } returns isNetworkAvailable diff --git a/network/data/src/test/java/me/proton/core/network/data/ProtonApiBackendTests.kt b/network/data/src/test/java/me/proton/core/network/data/ProtonApiBackendTests.kt index 2efadab69..31daab597 100644 --- a/network/data/src/test/java/me/proton/core/network/data/ProtonApiBackendTests.kt +++ b/network/data/src/test/java/me/proton/core/network/data/ProtonApiBackendTests.kt @@ -144,7 +144,8 @@ internal class ProtonApiBackendTests { scope, cache = { null }, clientVersionValidator = clientVersionValidator, - dohAlternativesListener = null + dohAlternativesListener = null, + okHttpClient = OkHttpClient() ) every { networkManager.isConnectedToNetwork() } returns isNetworkAvailable