Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd200546 authored by Fahim Salam Chowdhury's avatar Fahim Salam Chowdhury 👽 Committed by Hasib Prince
Browse files

feat: add flag to detect authFailure on performSync stage

parent 4dde5a60
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -124,6 +124,8 @@ class AccountSettings(
        const val COOKIE_KEY = NCAccountUtils.Constants.KEY_OKHTTP_COOKIES
        const val COOKIE_SEPARATOR = NCAccountUtils.Constants.OKHTTP_COOKIE_SEPARATOR

        const val AUTH_EXCEPTION_DETECTED = "auth_exception_detected"

        /** Static property to indicate whether AccountSettings migration is currently running.
         * **Access must be `synchronized` with `AccountSettings::class.java`.** */
        @Volatile
@@ -647,6 +649,21 @@ class AccountSettings(
        ).isNullOrBlank()
    }

    fun noAuthExceptionDetected(): Boolean {
        return accountManager.getUserData(
            account,
            AUTH_EXCEPTION_DETECTED
        ).isNullOrBlank()
    }

    fun updateAuthExceptionDetectedStatus(detected: Boolean) {
        accountManager.setUserData(
            account,
            AUTH_EXCEPTION_DETECTED,
            if (detected) true.toString() else null
        )
    }

    fun clearCookie() {
        accountManager.setUserData(account, COOKIE_KEY, null)
        accountManager.setUserData(
+19 −14
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L

    companion object {
        const val DEBUG_INFO_MAX_RESOURCE_DUMP_SIZE = 100*FileUtils.ONE_KB.toInt()

        const val UNAUTHORIZED_NOTIFICATION_TAG = "Unauthorized"
        const val MAX_MULTIGET_RESOURCES = 10

        const val DEFAULT_RETRY_AFTER = 5
@@ -207,16 +207,6 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
                )
            )

            accountSettings.credentials(
                Credentials(
                    account.name,
                    null,
                    authState,
                    null,
                    clientSecret = clientSecretString
                )
            )

            executor.execute {
                performSync(DEFAULT_RETRY_AFTER, DEFAULT_SECOND_RETRY_AFTER, DEFAULT_MAX_RETRY_TIME)
            }
@@ -233,6 +223,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
     * @param maxRetryTime optional param, in seconds. On unhandled exception, max time the method should retry.
     */
    fun performSync(retryAfter: Int, secondRetryAfter: Int, maxRetryTime: Int) {

        // dismiss previous error notifications
        notificationManager.cancel(notificationTag, NotificationUtils.NOTIFY_SYNC_ERROR)

@@ -354,6 +345,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
            else
                Logger.log.info("Remote collection didn't change, no reason to sync")
        }, { e, local, remote ->
            Logger.log.info("SyncManager exception: $e")
            when (e) {
                // sync was cancelled or account has been removed: re-throw to SyncAdapterService (now BaseSyncer)
                is InterruptedException,
@@ -385,6 +377,12 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
                    return@unwrapExceptions
                }

                is UnauthorizedException -> {
                    Logger.log.log(Level.WARNING, "Got 401 Unauthorized", e)
                    notifyException(e, local, remote)
                    return@unwrapExceptions
                }

                // all others
                else -> {
                    // sometimes sync is kicked in when no network is not available.
@@ -842,6 +840,8 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L

    private fun notifyException(e: Throwable, local: ResourceType?, remote: HttpUrl?) {
        val message: String
        var title: String = localCollection.title
        var tag: String = notificationTag

        when (e) {
            is IOException,
@@ -851,11 +851,13 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
                syncResult.stats.numIoExceptions++
            }
            is UnauthorizedException -> {
                title = context.getString(R.string.sync_error_authentification_failed_title, accountSettings.credentials().userName)
                tag = UNAUTHORIZED_NOTIFICATION_TAG
                message = context.getString(R.string.sync_error_authentication_failed)
                syncResult.stats.numAuthExceptions++

                // persistent session cookie is present. Probably the session is outDated. no need to show the notification
                if (accountSettings.containsPersistentCookie()) {
                if (accountSettings.containsPersistentCookie() && accountSettings.noAuthExceptionDetected()) {
                    Logger.log.log(Level.FINE, "Authorization error. Session outDated")
                    return
                }
@@ -887,6 +889,8 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
            }
        }

        Logger.log.info("Notification sent")

        val contentIntent: Intent
        var viewItemAction: NotificationCompat.Action? = null

@@ -920,7 +924,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L

        val builder = NotificationUtils.newBuilder(context, channel)
        builder .setSmallIcon(R.drawable.ic_sync_problem_notify)
                .setContentTitle(localCollection.title)
                .setContentTitle(title)
                .setContentText(message)
                .setStyle(NotificationCompat.BigTextStyle(builder).bigText(message))
                .setSubText(mainAccount.name)
@@ -930,7 +934,8 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
                .setCategory(NotificationCompat.CATEGORY_ERROR)
        viewItemAction?.let { builder.addAction(it) }

        notificationManager.notifyIfPossible(notificationTag, NotificationUtils.NOTIFY_SYNC_ERROR, builder.build())

        notificationManager.notifyIfPossible(tag, NotificationUtils.NOTIFY_SYNC_ERROR, builder.build())
    }

    private fun buildDebugInfoIntent(e: Throwable, local: ResourceType?, remote: HttpUrl?) =
+4 −0
Original line number Diff line number Diff line
@@ -363,6 +363,7 @@ class SyncWorker @AssistedInject constructor(
        val isCookiePresent = accountSettings.containsPersistentCookie()

        try {
            Logger.log.log(Level.INFO, "Starting onPerformSync for $account")
            syncThread = Thread.currentThread()
            syncer.onPerformSync(account, extras.toTypedArray(), authority, provider, result)
        } catch (e: SecurityException) {
@@ -383,6 +384,7 @@ class SyncWorker @AssistedInject constructor(
            if (isCookiePresent && result.stats.numAuthExceptions > 0) {
                // probably the session is outDated. retry without the sessionCookie
                accountSettings.clearCookie()
                accountSettings.updateAuthExceptionDetectedStatus(detected = true)
                return Result.retry()
            }

@@ -435,6 +437,8 @@ class SyncWorker @AssistedInject constructor(
            }
        }

        accountSettings.updateAuthExceptionDetectedStatus(detected = false)
        Logger.log.info("Sync completed successfully")
        return Result.success()
    }

+2 −1
Original line number Diff line number Diff line
@@ -538,7 +538,8 @@
    <string name="sync_error_permissions_text">Additional permissions required</string>
    <string name="sync_error_tasks_too_old">%s too old</string>
    <string name="sync_error_tasks_required_version">Minimum required version: %1$s</string>
    <string name="sync_error_authentication_failed">Authentication failed (check login credentials)</string>
    <string name="sync_error_authentification_failed_title">Your account %1$s</string>
    <string name="sync_error_authentication_failed">Your login/password is incorrect, please login again.</string>
    <string name="sync_error_io">Network or I/O error – %s</string>
    <string name="sync_error_http_dav">HTTP server error – %s</string>
    <string name="sync_error_local_storage">Local storage error – %s</string>