diff --git a/app/src/main/kotlin/at/bitfire/davdroid/network/HttpClient.kt b/app/src/main/kotlin/at/bitfire/davdroid/network/HttpClient.kt index d61ba172aaa8769b9f91b9414e5f20795a12bc7b..114dc2527e668e8e65dd7539e7b3200528df0ba8 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/network/HttpClient.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/network/HttpClient.kt @@ -6,12 +6,10 @@ package at.bitfire.davdroid.network import android.accounts.Account import android.content.Context -import android.os.Build import android.security.KeyChain import at.bitfire.cert4android.CustomCertManager import at.bitfire.dav4jvm.BasicDigestAuthHandler import at.bitfire.dav4jvm.UrlUtils -import at.bitfire.davdroid.BuildConfig import at.bitfire.davdroid.OpenIdUtils import at.bitfire.davdroid.db.Credentials import at.bitfire.davdroid.log.Logger @@ -27,7 +25,13 @@ import dagger.hilt.components.SingletonComponent import kotlinx.coroutines.flow.MutableStateFlow import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationService -import okhttp3.* +import okhttp3.Cache +import okhttp3.ConnectionSpec +import okhttp3.CookieJar +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.Protocol +import okhttp3.Response import okhttp3.brotli.BrotliInterceptor import okhttp3.internal.tls.OkHostnameVerifier import okhttp3.logging.HttpLoggingInterceptor @@ -37,11 +41,14 @@ import java.net.Proxy import java.net.Socket import java.security.KeyStore import java.security.Principal -import java.text.SimpleDateFormat -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit import java.util.logging.Level -import javax.net.ssl.* +import javax.net.ssl.KeyManager +import javax.net.ssl.SSLContext +import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509ExtendedKeyManager +import javax.net.ssl.X509TrustManager class HttpClient private constructor( val okHttpClient: OkHttpClient, @@ -90,10 +97,14 @@ class HttpClient private constructor( override fun close() { try { - okHttpClient.cache?.close() authService?.dispose() + okHttpClient.cache?.close() } catch (e: Exception) { - Logger.log.log(Level.INFO, "failed to clear resource on close httpClient", e) + Logger.log.log( + Level.WARNING, + "Failed to clear resource on closing OkHttpClient or disposing AuthorizationService", + e + ) } } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/network/OAuthModule.kt b/app/src/main/kotlin/at/bitfire/davdroid/network/OAuthModule.kt index e8c10421afad2f1ec170c65427a5f5d056df6230..90c3aa7eceabf8915e67d2b0147e2639ef93a991 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/network/OAuthModule.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/network/OAuthModule.kt @@ -5,6 +5,7 @@ package at.bitfire.davdroid.network import android.content.Context +import at.bitfire.davdroid.Constants import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -28,6 +29,8 @@ object OAuthModule { (url.openConnection() as HttpURLConnection).apply { setRequestProperty("User-Agent", HttpClient.UserAgentInterceptor.userAgent) } - }.build() + } + .setBrowserMatcher { it.packageName == Constants.E_BROWSER_PACKAGE_NAME } + .build() ) -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt index c231ae4a399ead2ca72e8e28499a78b7bc8132f2..bd812cbe31f3decc1b20931a22c42097265ffcd5 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt @@ -51,6 +51,7 @@ abstract class DefaultAccountAuthenticatorService : Service(), OnAccountsUpdateL @InstallIn(SingletonComponent::class) interface DefaultAccountAuthenticatorServiceEntryPoint { fun appDatabase(): AppDatabase + fun authorizationService(): AuthorizationService } companion object { @@ -220,7 +221,9 @@ abstract class DefaultAccountAuthenticatorService : Service(), OnAccountsUpdateL val clientSecretString = accountManager.getUserData(account, AccountSettings.KEY_CLIENT_SECRET) val clientSecret = OpenIdUtils.getClientAuthentication(clientSecretString) - val authorizationService = AuthorizationService(context) + val authorizationService = + EntryPointAccessors.fromApplication(context, DefaultAccountAuthenticatorServiceEntryPoint::class.java) + .authorizationService() authorizationService.performTokenRequest( tokenRequest, @@ -249,7 +252,7 @@ abstract class DefaultAccountAuthenticatorService : Service(), OnAccountsUpdateL try { authorizationService.dispose() } catch (e: Exception) { - Logger.log.log(Level.INFO, "failed to dispose oidc authorizationService", e) + Logger.log.log(Level.WARNING, "Failed to dispose AuthorizationService", e) } } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncManager.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncManager.kt index ae3b479bb536e8fb19ad9d56f7d7aa04cee9baa8..d1394b3d7723366c75cb5ba05c5e47c76d2a0231 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncManager.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncManager.kt @@ -16,20 +16,40 @@ import android.provider.CalendarContract import android.provider.ContactsContract import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat -import at.bitfire.dav4jvm.* -import at.bitfire.dav4jvm.exception.* +import at.bitfire.dav4jvm.DavCollection +import at.bitfire.dav4jvm.DavResource +import at.bitfire.dav4jvm.Error +import at.bitfire.dav4jvm.MultiResponseCallback +import at.bitfire.dav4jvm.Response +import at.bitfire.dav4jvm.exception.ConflictException +import at.bitfire.dav4jvm.exception.DavException +import at.bitfire.dav4jvm.exception.ForbiddenException +import at.bitfire.dav4jvm.exception.GoneException +import at.bitfire.dav4jvm.exception.HttpException +import at.bitfire.dav4jvm.exception.NotFoundException +import at.bitfire.dav4jvm.exception.PreconditionFailedException +import at.bitfire.dav4jvm.exception.ServiceUnavailableException +import at.bitfire.dav4jvm.exception.UnauthorizedException import at.bitfire.dav4jvm.property.GetCTag import at.bitfire.dav4jvm.property.GetETag import at.bitfire.dav4jvm.property.ScheduleTag import at.bitfire.dav4jvm.property.SyncToken -import at.bitfire.davdroid.* +import at.bitfire.davdroid.Constants +import at.bitfire.davdroid.InvalidAccountException +import at.bitfire.davdroid.OpenIdUtils +import at.bitfire.davdroid.R import at.bitfire.davdroid.db.AppDatabase import at.bitfire.davdroid.db.Credentials import at.bitfire.davdroid.db.SyncState import at.bitfire.davdroid.db.SyncStats import at.bitfire.davdroid.log.Logger import at.bitfire.davdroid.network.HttpClient -import at.bitfire.davdroid.resource.* +import at.bitfire.davdroid.resource.LocalAddressBook +import at.bitfire.davdroid.resource.LocalCollection +import at.bitfire.davdroid.resource.LocalContact +import at.bitfire.davdroid.resource.LocalEvent +import at.bitfire.davdroid.resource.LocalResource +import at.bitfire.davdroid.resource.LocalTask import at.bitfire.davdroid.settings.AccountSettings import at.bitfire.davdroid.ui.DebugInfoActivity import at.bitfire.davdroid.ui.NetworkUtils @@ -45,7 +65,11 @@ import dagger.hilt.EntryPoint import dagger.hilt.InstallIn import dagger.hilt.android.EntryPointAccessors import dagger.hilt.components.SingletonComponent -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationService import okhttp3.HttpUrl @@ -60,7 +84,9 @@ import java.net.ConnectException import java.net.HttpURLConnection import java.security.cert.CertificateException import java.time.Instant -import java.util.* +import java.util.LinkedList +import java.util.Locale +import java.util.ServiceLoader import java.util.concurrent.Executors import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.ThreadPoolExecutor @@ -87,6 +113,7 @@ abstract class SyncManager, out CollectionType: L @InstallIn(SingletonComponent::class) interface SyncManagerEntryPoint { fun appDatabase(): AppDatabase + fun authorizationService(): AuthorizationService } enum class SyncAlgorithm { @@ -194,7 +221,10 @@ abstract class SyncManager, out CollectionType: L val clientSecretString = accountSettings.credentials().clientSecret val clientSecret = OpenIdUtils.getClientAuthentication(clientSecretString) - val authorizationService = AuthorizationService(context) + val authorizationService = + EntryPointAccessors.fromApplication(context, SyncManagerEntryPoint::class.java) + .authorizationService() + authorizationService.performTokenRequest(tokenRequest, clientSecret) { tokenResponse, ex -> authState.update(tokenResponse, ex) accountSettings.credentials( @@ -1070,4 +1100,4 @@ abstract class SyncManager, out CollectionType: L handler(ex, local, remote) } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt index 9d640a2fb0c6fb90823b758d3d1536eb55f56cf7..aa0bebad5bad46df550532be0f5ab51832acc684 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt @@ -31,6 +31,7 @@ import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.db.Credentials import at.bitfire.davdroid.log.Logger import at.bitfire.davdroid.ui.NetworkUtils +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import net.openid.appauth.AuthState.AuthStateAction @@ -42,6 +43,7 @@ import org.json.JSONObject import java.net.URI import java.util.logging.Level +@AndroidEntryPoint abstract class OpenIdAuthenticationBaseFragment(private val identityProvider: IdentityProvider) : Fragment() { diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt index fc4eb66a90b0f5bd2b0e2333e53e01e892e144d2..139c0aa7bf325952533e04dd8a23625bd5522d1d 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt @@ -22,11 +22,10 @@ import android.content.Intent import android.os.Build import androidx.annotation.WorkerThread import androidx.lifecycle.AndroidViewModel -import at.bitfire.davdroid.Constants import at.bitfire.davdroid.OpenIdUtils import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.log.Logger -import net.openid.appauth.AppAuthConfiguration +import dagger.hilt.android.lifecycle.HiltViewModel import net.openid.appauth.AuthState import net.openid.appauth.AuthState.AuthStateAction import net.openid.appauth.AuthorizationException @@ -45,31 +44,24 @@ import java.net.HttpURLConnection import java.net.URL import java.nio.charset.StandardCharsets import java.util.logging.Level +import javax.inject.Inject -class OpenIdAuthenticationViewModel(application: Application) : AndroidViewModel(application) { - +@HiltViewModel +class OpenIdAuthenticationViewModel @Inject constructor( + application: Application, private val authorizationService: AuthorizationService +) : AndroidViewModel(application) { + private var authState: AuthState? = null var identityProvider: IdentityProvider? = null - init { - val appAuthConfig = AppAuthConfiguration.Builder() - .setBrowserMatcher { - it.packageName == Constants.E_BROWSER_PACKAGE_NAME - } - .build() - - authorizationService = AuthorizationService(getApplication(), appAuthConfig) - } - override fun onCleared() { super.onCleared() try { authorizationService.dispose() } catch (e: Exception) { - Logger.log.log(Level.INFO, "failed to dispose oidc authorizationService", e) + Logger.log.log(Level.WARNING, "Failed to dispose AuthorizationService", e) } - } fun getAuthState(): AuthState { diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/signout/OpenIdEndSessionActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/signout/OpenIdEndSessionActivity.kt index a3b5cfe94276e1cf35c8966aff2735bc5943197d..72b8b4a195bb185c33274cd4173eda603f0f5171 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/signout/OpenIdEndSessionActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/signout/OpenIdEndSessionActivity.kt @@ -17,22 +17,24 @@ package at.bitfire.davdroid.ui.signout import android.accounts.AccountManager -import android.app.Activity import android.os.Bundle -import at.bitfire.davdroid.Constants +import androidx.appcompat.app.AppCompatActivity import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.log.Logger import at.bitfire.davdroid.settings.AccountSettings -import net.openid.appauth.AppAuthConfiguration +import dagger.hilt.android.AndroidEntryPoint import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationService import net.openid.appauth.AuthorizationServiceConfiguration import net.openid.appauth.EndSessionRequest import java.util.logging.Level +import javax.inject.Inject -class OpenIdEndSessionActivity : Activity() { +@AndroidEntryPoint +class OpenIdEndSessionActivity : AppCompatActivity() { - private var authorizationService: AuthorizationService? = null + @Inject + lateinit var authorizationService: AuthorizationService override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -67,12 +69,6 @@ class OpenIdEndSessionActivity : Activity() { configuration: AuthorizationServiceConfiguration, authState: AuthState ) { - val appAuthConfig = AppAuthConfiguration.Builder() - .setBrowserMatcher { - it.packageName == Constants.E_BROWSER_PACKAGE_NAME - } - .build() - authorizationService = AuthorizationService(applicationContext, appAuthConfig) val identityProvider = IdentityProvider.retrieveByAccountType(this, accountType) ?: return val redirectUri = identityProvider.logoutRedirectUri @@ -92,13 +88,12 @@ class OpenIdEndSessionActivity : Activity() { startActivity(intent) } - override fun onDestroy() { - super.onDestroy() - + override fun onStop() { + super.onStop() try { - authorizationService?.dispose() + authorizationService.dispose() } catch (e: Exception) { - Logger.log.log(Level.INFO, "failed to dispose oidc authorizationService", e) + Logger.log.log(Level.WARNING, "Failed to dispose AuthorizationService", e) } } }