Skip to content

Commit

Permalink
Improve session management
Browse files Browse the repository at this point in the history
  • Loading branch information
hegocre committed Sep 8, 2024
1 parent 5223696 commit 205a4de
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 17 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ dependencies {
implementation 'androidx.navigation:navigation-compose:2.8.0'
implementation 'androidx.activity:activity-compose:1.9.2'
implementation 'androidx.biometric:biometric:1.1.0'
implementation "androidx.autofill:autofill:1.1.0"
implementation 'androidx.autofill:autofill:1.1.0'
implementation 'androidx.work:work-runtime-ktx:2.9.1'

//Room dependencies
implementation "androidx.room:room-ktx:$room_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.hegocre.nextcloudpasswords.api
import android.content.Context
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.work.WorkManager
import com.hegocre.nextcloudpasswords.api.encryption.CSEv1Keychain
import com.hegocre.nextcloudpasswords.api.exceptions.PWDv1ChallengeMasterKeyInvalidException
import com.hegocre.nextcloudpasswords.api.exceptions.PWDv1ChallengeMasterKeyNeededException
Expand All @@ -15,6 +16,7 @@ import com.hegocre.nextcloudpasswords.data.password.NewPassword
import com.hegocre.nextcloudpasswords.data.password.Password
import com.hegocre.nextcloudpasswords.data.password.UpdatedPassword
import com.hegocre.nextcloudpasswords.data.user.UserController
import com.hegocre.nextcloudpasswords.services.keepalive.KeepAliveWorker
import com.hegocre.nextcloudpasswords.utils.Error
import com.hegocre.nextcloudpasswords.utils.OkHttpRequest
import com.hegocre.nextcloudpasswords.utils.PreferencesManager
Expand Down Expand Up @@ -57,6 +59,8 @@ class ApiController private constructor(context: Context) {
val sessionOpen: StateFlow<Boolean>
get() = _sessionOpen.asStateFlow()

private val workManager = WorkManager.getInstance(context)

init {
decryptCSEv1Keychain(
preferencesManager.getCSEv1Keychain(),
Expand All @@ -77,22 +81,6 @@ class ApiController private constructor(context: Context) {
serverSettings.postValue(settings)
preferencesManager.setServerSettings(settings)
preferencesManager.setInstanceColor(settings.themeColorPrimary)

var keepAliveDelay = (settings.sessionLifetime * 3 / 4 * 1000).toLong()
while (true) {
sessionCode?.let {
delay(keepAliveDelay)
keepAliveDelay = if (sessionApi.keepAlive(it)) {
Log.i("KeepAlive", "Successfully sent keep alive request")
(settings.sessionLifetime * 3 / 4 * 1000).toLong()
} else {
Log.e("KeepAlive", "Error sending keep alive request")
_sessionOpen.emit(false)
sessionCode = null
5000L
}
} ?: delay(5000L)
}
}
OkHttpRequest.getInstance().allowInsecureRequests =
preferencesManager.getSkipCertificateValidation()
Expand Down Expand Up @@ -215,6 +203,11 @@ class ApiController private constructor(context: Context) {
}
}
sessionCode = newSessionCode
serverSettings.value?.let { settings ->
val keepAliveDelay = (settings.sessionLifetime * 3 / 4 * 1000).toLong()
workManager.cancelAllWorkByTag(KeepAliveWorker.TAG)
workManager.enqueue(KeepAliveWorker.getRequest(keepAliveDelay, newSessionCode))
}

_sessionOpen.emit(true)
return@withContext true
Expand All @@ -236,6 +229,11 @@ class ApiController private constructor(context: Context) {
}
}

suspend fun clearSession() {
_sessionOpen.emit(false)
sessionCode = null
}

/**
* Gets a list of the user passwords via the [PasswordsApi] class. This can only be called when a
* session is open, otherwise an error is thrown.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.hegocre.nextcloudpasswords.services.keepalive

import android.content.Context
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkRequest
import androidx.work.WorkerParameters
import com.hegocre.nextcloudpasswords.api.ApiController
import com.hegocre.nextcloudpasswords.api.SessionApi
import com.hegocre.nextcloudpasswords.data.user.UserController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit

class KeepAliveWorker(context: Context, private val params: WorkerParameters) :
CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val apiController = ApiController.getInstance(applicationContext)
if (!apiController.sessionOpen.value) {
return Result.success()
}

val server = UserController.getInstance(applicationContext).getServer()
val sessionApi = SessionApi.getInstance(server)

val sessionCode = params.inputData.getString(SESSION_CODE_KEY) ?: return Result.failure()
val keepAliveDelay = params.inputData.getLong(KEEPALIVE_DELAY_KEY, -1L)
if (keepAliveDelay == -1L) return Result.failure()

val resultSuccess = withContext(Dispatchers.IO) {
sessionApi.keepAlive(sessionCode)
}

if (resultSuccess) {
WorkManager.getInstance(applicationContext)
.enqueue(getRequest(keepAliveDelay, sessionCode))
return Result.success()
} else {
if (params.runAttemptCount > 2) {
ApiController.getInstance(applicationContext).clearSession()
return Result.failure()
} else {
return Result.retry()
}
}
}

companion object {
private const val SESSION_CODE_KEY = "com.hegocre.nextcloudpasswords.sessionCode"
private const val KEEPALIVE_DELAY_KEY = "com.hegocre.nextcloudpasswords.keepAliveDelay"
const val TAG = "com.hegocre.nextcloudpasswords.keepaliveworker"

fun getRequest(delay: Long, sessionCode: String): WorkRequest {
val data = Data.Builder()
.putString(SESSION_CODE_KEY, sessionCode)
.putLong(KEEPALIVE_DELAY_KEY, delay)
.build()
return OneTimeWorkRequestBuilder<KeepAliveWorker>()
.setInitialDelay(delay, TimeUnit.MILLISECONDS)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, 10L, TimeUnit.SECONDS)
.addTag(TAG)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
}
}
}

0 comments on commit 205a4de

Please sign in to comment.