JWT Authorization
This commit is contained in:
@@ -3,10 +3,13 @@ package org.koitharu.kotatsu.sync
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.sync.data.SyncAuthApi
|
||||
import org.koitharu.kotatsu.sync.ui.SyncAuthViewModel
|
||||
|
||||
val syncModule
|
||||
get() = module {
|
||||
|
||||
viewModel { SyncAuthViewModel(androidContext(), get()) }
|
||||
factory { SyncAuthApi(androidContext(), get()) }
|
||||
|
||||
viewModel { SyncAuthViewModel(get()) }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.koitharu.kotatsu.sync.data
|
||||
|
||||
import android.accounts.Account
|
||||
import android.accounts.AccountManager
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Authenticator
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.Route
|
||||
import org.koitharu.kotatsu.R
|
||||
|
||||
class AccountAuthenticator(
|
||||
context: Context,
|
||||
private val account: Account,
|
||||
private val authApi: SyncAuthApi,
|
||||
) : Authenticator {
|
||||
|
||||
private val accountManager = AccountManager.get(context)
|
||||
private val tokenType = context.getString(R.string.account_type_sync)
|
||||
|
||||
override fun authenticate(route: Route?, response: Response): Request? {
|
||||
val newToken = tryRefreshToken() ?: return null
|
||||
accountManager.setAuthToken(account, tokenType, newToken)
|
||||
return response.request.newBuilder()
|
||||
.header("Authorization", "Bearer $newToken")
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun tryRefreshToken() = runCatching {
|
||||
runBlocking {
|
||||
authApi.authenticate(
|
||||
account.name,
|
||||
accountManager.getPassword(account),
|
||||
)
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.koitharu.kotatsu.sync.data
|
||||
|
||||
import android.content.Context
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.parsers.util.await
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import org.koitharu.kotatsu.utils.ext.toRequestBody
|
||||
|
||||
class SyncAuthApi(
|
||||
context: Context,
|
||||
private val okHttpClient: OkHttpClient,
|
||||
) {
|
||||
|
||||
private val baseUrl = context.getString(R.string.url_sync_server)
|
||||
|
||||
suspend fun authenticate(email: String, password: String): String {
|
||||
val body = JSONObject(
|
||||
mapOf("email" to email, "password" to password)
|
||||
).toRequestBody()
|
||||
val request = Request.Builder()
|
||||
.url("$baseUrl/auth")
|
||||
.post(body)
|
||||
.build()
|
||||
val response = okHttpClient.newCall(request).await().parseJson()
|
||||
return response.getString("token")
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ import org.koitharu.kotatsu.core.db.MangaDatabase.Companion.TABLE_MANGA_TAGS
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase.Companion.TABLE_TAGS
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONTo
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import org.koitharu.kotatsu.sync.data.AccountAuthenticator
|
||||
import org.koitharu.kotatsu.sync.data.AccountInterceptor
|
||||
import org.koitharu.kotatsu.sync.data.SyncAuthApi
|
||||
import org.koitharu.kotatsu.utils.GZipInterceptor
|
||||
import org.koitharu.kotatsu.utils.ext.toContentValues
|
||||
import org.koitharu.kotatsu.utils.ext.toJson
|
||||
@@ -40,6 +42,7 @@ class SyncHelper(
|
||||
) {
|
||||
|
||||
private val httpClient = OkHttpClient.Builder()
|
||||
.authenticator(AccountAuthenticator(context, account, SyncAuthApi(context, OkHttpClient())))
|
||||
.addInterceptor(AccountInterceptor(context, account))
|
||||
.addInterceptor(GZipInterceptor())
|
||||
.build()
|
||||
|
||||
@@ -1,44 +1,22 @@
|
||||
package org.koitharu.kotatsu.sync.ui
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.parsers.util.await
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import org.koitharu.kotatsu.sync.data.SyncAuthApi
|
||||
import org.koitharu.kotatsu.sync.domain.SyncAuthResult
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.toRequestBody
|
||||
import java.util.*
|
||||
|
||||
class SyncAuthViewModel(
|
||||
context: Context,
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val api: SyncAuthApi,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val baseUrl = context.getString(R.string.url_sync_server)
|
||||
val onTokenObtained = SingleLiveEvent<SyncAuthResult>()
|
||||
|
||||
fun obtainToken(email: String, password: String) {
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
authenticate(email, password)
|
||||
val token = UUID.randomUUID().toString()
|
||||
val token = api.authenticate(email, password)
|
||||
val result = SyncAuthResult(email, password, token)
|
||||
onTokenObtained.postCall(result)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun authenticate(email: String, password: String) {
|
||||
val body = JSONObject(
|
||||
mapOf("email" to email, "password" to password)
|
||||
).toRequestBody()
|
||||
val request = Request.Builder()
|
||||
.url("$baseUrl/register")
|
||||
.post(body)
|
||||
.build()
|
||||
val response = okHttpClient.newCall(request).await().parseJson()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user