Loading core/src/main/kotlin/at/bitfire/davdroid/network/OAuthInterceptor.kt +32 −7 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import at.bitfire.davdroid.BuildConfig import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import foundation.e.accountmanager.token.MurenaTokenManager import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationException import net.openid.appauth.AuthorizationService Loading Loading @@ -69,6 +70,20 @@ class OAuthInterceptor @AssistedInject constructor( // if possible, use cached access token val authState = readAuthState() ?: return null val authorizationException = authState.authorizationException if (authorizationException != null && MurenaTokenManager.isInvalidGrant(authorizationException)) { throw AuthorizationException.TokenRequestErrors.INVALID_GRANT } val expiresAt = authState.accessTokenExpirationTime if (expiresAt != null) { val refreshDeadline = expiresAt - MurenaTokenManager.earlyTriggerTime if (refreshDeadline <= System.currentTimeMillis()) { logger.info("Token expired or near expiry, refreshing immediately.") authState.needsTokenRefresh = true } } if (authState.isAuthorized && authState.accessToken != null && !authState.needsTokenRefresh) { if (BuildConfig.DEBUG) // log sensitive information (refresh/access token) only in debug builds logger.log(Level.FINEST, "Using cached AuthState", authState.jsonSerializeString()) Loading @@ -85,13 +100,23 @@ class OAuthInterceptor @AssistedInject constructor( if (BuildConfig.DEBUG) logger.log(Level.FINEST, "Got new AuthState", authState.jsonSerializeString()) when { accessToken != null -> { // persist updated AuthState writeAuthState(authState) accessTokenFuture.complete(accessToken) } if (ex != null) ex != null -> { logger.log(Level.WARNING, "Token refresh failed: $ex") accessTokenFuture.completeExceptionally(ex) else if (accessToken != null) accessTokenFuture.complete(accessToken) } else -> { // Unexpected: neither token nor exception. treat as failure. accessTokenFuture.completeExceptionally(IllegalStateException("No token, no exception")) } } } accessTokenFuture.join() Loading core/src/main/kotlin/foundation/e/accountmanager/token/MurenaTokenManager.kt +1 −1 Original line number Diff line number Diff line Loading @@ -190,7 +190,7 @@ object MurenaTokenManager { } // Checks whether the given AuthorizationException indicates an invalid grant (requires re-login). private fun isInvalidGrant(ex: AuthorizationException?): Boolean { fun isInvalidGrant(ex: AuthorizationException?): Boolean { val invalidGrant = AuthorizationException.TokenRequestErrors.INVALID_GRANT return ex?.code == invalidGrant.code && ex.error == invalidGrant.error } Loading Loading
core/src/main/kotlin/at/bitfire/davdroid/network/OAuthInterceptor.kt +32 −7 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import at.bitfire.davdroid.BuildConfig import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import foundation.e.accountmanager.token.MurenaTokenManager import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationException import net.openid.appauth.AuthorizationService Loading Loading @@ -69,6 +70,20 @@ class OAuthInterceptor @AssistedInject constructor( // if possible, use cached access token val authState = readAuthState() ?: return null val authorizationException = authState.authorizationException if (authorizationException != null && MurenaTokenManager.isInvalidGrant(authorizationException)) { throw AuthorizationException.TokenRequestErrors.INVALID_GRANT } val expiresAt = authState.accessTokenExpirationTime if (expiresAt != null) { val refreshDeadline = expiresAt - MurenaTokenManager.earlyTriggerTime if (refreshDeadline <= System.currentTimeMillis()) { logger.info("Token expired or near expiry, refreshing immediately.") authState.needsTokenRefresh = true } } if (authState.isAuthorized && authState.accessToken != null && !authState.needsTokenRefresh) { if (BuildConfig.DEBUG) // log sensitive information (refresh/access token) only in debug builds logger.log(Level.FINEST, "Using cached AuthState", authState.jsonSerializeString()) Loading @@ -85,13 +100,23 @@ class OAuthInterceptor @AssistedInject constructor( if (BuildConfig.DEBUG) logger.log(Level.FINEST, "Got new AuthState", authState.jsonSerializeString()) when { accessToken != null -> { // persist updated AuthState writeAuthState(authState) accessTokenFuture.complete(accessToken) } if (ex != null) ex != null -> { logger.log(Level.WARNING, "Token refresh failed: $ex") accessTokenFuture.completeExceptionally(ex) else if (accessToken != null) accessTokenFuture.complete(accessToken) } else -> { // Unexpected: neither token nor exception. treat as failure. accessTokenFuture.completeExceptionally(IllegalStateException("No token, no exception")) } } } accessTokenFuture.join() Loading
core/src/main/kotlin/foundation/e/accountmanager/token/MurenaTokenManager.kt +1 −1 Original line number Diff line number Diff line Loading @@ -190,7 +190,7 @@ object MurenaTokenManager { } // Checks whether the given AuthorizationException indicates an invalid grant (requires re-login). private fun isInvalidGrant(ex: AuthorizationException?): Boolean { fun isInvalidGrant(ex: AuthorizationException?): Boolean { val invalidGrant = AuthorizationException.TokenRequestErrors.INVALID_GRANT return ex?.code == invalidGrant.code && ex.error == invalidGrant.error } Loading