Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/src/main/kotlin/com/infomaniak/auth/MainApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.annotation.RequiresApi
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import com.infomaniak.auth.data.preferences.SentryPreferences
import com.infomaniak.auth.lib.room.appsettings.AppSettingsDatabase
import com.infomaniak.auth.service.DeviceInfoUpdateWorker
import com.infomaniak.auth.utils.AccountUtils
import com.infomaniak.auth.utils.NotificationUtils
Expand All @@ -48,6 +49,9 @@ open class MainApplication : Application(), Configuration.Provider {
@Inject
lateinit var notificationUtils: NotificationUtils

@Inject
lateinit var db: AppSettingsDatabase // Workaround to ensure it's initialized eagerly, before StrictMode is activated.

Comment thread
LouisCAD marked this conversation as resolved.
@Inject
lateinit var workerFactory: HiltWorkerFactory

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ abstract class AuthenticatorFacade internal constructor() {
val webAuthnRepository = WebAuthnRepository(
authenticatorRequest = AuthenticatorRequest(
httpClient = ApiClientProvider(
scope = scope,
userAgent = userAgent,
routes = routes,
crashReport = crashReport,
Expand Down Expand Up @@ -119,6 +120,7 @@ abstract class AuthenticatorFacade internal constructor() {
val webAuthnRepository = WebAuthnRepository(
authenticatorRequest = AuthenticatorRequest(
httpClient = ApiClientProvider(
scope = scope,
userAgent = userAgent,
routes = routes,
crashReport = crashReport,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ import io.ktor.http.contentLength
import io.ktor.http.contentType
import io.ktor.serialization.kotlinx.json.json
import io.ktor.utils.io.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.async
import kotlinx.io.IOException
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlin.time.Duration.Companion.seconds

internal class ApiClientProvider(
scope: CoroutineScope,
private val userAgent: String,
private val routes: ApiRoutes,
private val crashReport: CrashReportInterface? = null,
Expand All @@ -70,7 +76,10 @@ internal class ApiClientProvider(
useAlternativeNames = false
}

val httpClient = HttpClient(getHttpClientEngine()) {
val httpClient: suspend () -> HttpClient = { httpClientAsync.await() }
Comment thread
LouisCAD marked this conversation as resolved.
private val httpClientAsync = scope.async(Dispatchers.IO, start = CoroutineStart.LAZY) { createHttpClient() }

private fun createHttpClient() = HttpClient(getHttpClientEngine()) {
install(UserAgent) {
agent = userAgent
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ import io.ktor.client.request.post
import io.ktor.client.request.setBody

internal class AuthenticatorRequest(
private val httpClient: HttpClient,
private val httpClient: suspend () -> HttpClient,
private val routes: ApiRoutes,
Comment thread
LouisCAD marked this conversation as resolved.
) {

/**
* Retrieves options (including a challenge) prior to registering a public key credential with [registerPasskey].
*/
suspend fun getPasskeysOptions(token: String): SuccessfulApiResponse<PasskeysOptions> {
return httpClient.get(routes.passkeysOptions()) {
return httpClient().get(routes.passkeysOptions()) {
addAuthenticationHeader(token)
}.decode()
}
Expand All @@ -55,7 +55,7 @@ internal class AuthenticatorRequest(
* after [getPasskeysOptions] is done.
*/
suspend fun registerPasskey(token: String, registerPasskey: RegisterPasskey) {
httpClient.post(routes.registerPasskey()) {
httpClient().post(routes.registerPasskey()) {
addAuthenticationHeader(token)
setBody(registerPasskey)
}
Expand All @@ -65,7 +65,7 @@ internal class AuthenticatorRequest(
* Retrieves the backend-generated challenge, prior to authenticating with [verify].
*/
suspend fun challenge(clientId: String): SuccessfulApiResponse<AuthenticationOptions> {
return httpClient.post(routes.challenge()) {
return httpClient().post(routes.challenge()) {
setBody(mapOf("client_id" to clientId))
}.decode()
}
Expand All @@ -78,7 +78,7 @@ internal class AuthenticatorRequest(
* @return An [AuthResult] that includes an access token.
*/
suspend fun verify(verifyAuthenticationData: VerifyAuthenticationData): SuccessfulApiResponse<AuthResult> {
return httpClient.post(routes.verify()) {
return httpClient().post(routes.verify()) {
setBody(verifyAuthenticationData)
}.decode()
}
Expand All @@ -90,7 +90,7 @@ internal class AuthenticatorRequest(
* @param passkeyId The id of the passkey to delete.
*/
suspend fun deletePasskey(token: String, passkeyId: String) {
httpClient.delete(routes.delete(passkeyId)) {
httpClient().delete(routes.delete(passkeyId)) {
addAuthenticationHeader(token)
}
}
Expand All @@ -102,7 +102,7 @@ internal class AuthenticatorRequest(
* @param userId The id of the user.
*/
suspend fun getMigrationOptions(deviceId: String, userId: Long): SuccessfulApiResponse<MigrationOptions> {
return httpClient.post(routes.migrationsOptions()) {
return httpClient().post(routes.migrationsOptions()) {
setBody(mapOf("device" to deviceId, "id" to userId.toString()))
}.decode()
}
Expand All @@ -122,7 +122,7 @@ internal class AuthenticatorRequest(
sessionId: String,
otpPayload: OtpPayload,
): SuccessfulApiResponse<AuthResult> {
return httpClient.post(routes.verifyMigration(sessionId)) {
return httpClient().post(routes.verifyMigration(sessionId)) {
setBody(otpPayload)
}.decode()
}
Expand All @@ -134,7 +134,7 @@ internal class AuthenticatorRequest(
* @param deviceId ID of the device.
*/
suspend fun completeMigration(token: String, sessionId: String, deviceId: String) {
httpClient.delete(routes.finishMigration(sessionId)) {
httpClient().delete(routes.finishMigration(sessionId)) {
addAuthenticationHeader(token)
setBody(mapOf("device" to deviceId))
}
Expand All @@ -145,7 +145,7 @@ internal class AuthenticatorRequest(
): SuccessfulApiResponse<SharedUserProfile> {
val url = "${routes.userProfile()}&with=security"

return httpClient.get(url) {
return httpClient().get(url) {
addAuthenticationHeader(token)
}.decode()
}
Expand Down
Loading