feat: more optimization Hikka authorization

This commit is contained in:
Lorg0n 2024-10-17 22:25:48 +03:00
parent 9eeed9f050
commit f39e947ece
4 changed files with 25 additions and 64 deletions

View file

@ -151,14 +151,6 @@ class Hikka(id: Long) : BaseTracker(id, "Hikka"), DeletableTracker {
interceptor.setAuth(null)
}
fun getIfAuthExpired(): Boolean {
return trackPreferences.trackAuthExpired(this).get()
}
fun setAuthExpired() {
trackPreferences.trackAuthExpired(this).set(true)
}
fun saveOAuth(oAuth: HKOAuth?) {
trackPreferences.trackToken(this).set(json.encodeToString(oAuth))
}

View file

@ -174,12 +174,20 @@ class HikkaApi(
.appendQueryParameter("scope", SCOPE)
.build()
fun refreshTokenRequest(hkOAuth: HKOAuth): Request {
fun refreshTokenRequest(accessToken: String): Request {
val headers = Headers.Builder()
.add("auth", hkOAuth.accessToken)
.add("auth", accessToken)
.build()
return GET("$BASE_API_URL/user/me", headers = headers)
return GET("$BASE_API_URL/user/me", headers = headers) // Any request with auth
}
fun authTokenInfo(accessToken: String): Request {
val headers = Headers.Builder()
.add("auth", accessToken)
.build()
return GET("$BASE_API_URL/auth/token/info", headers = headers)
}
}
}

View file

@ -1,31 +1,33 @@
package eu.kanade.tachiyomi.data.track.hikka
import eu.kanade.tachiyomi.data.track.hikka.dto.HKAuthTokenInfo
import eu.kanade.tachiyomi.data.track.hikka.dto.HKOAuth
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.Response
import org.json.JSONObject
import uy.kohesive.injekt.injectLazy
import java.io.IOException
class HikkaInterceptor(private val hikka: Hikka) : Interceptor {
private val json: Json by injectLazy()
private var oauth: HKOAuth? = hikka.loadOAuth()
private val tokenExpired get() = hikka.getIfAuthExpired()
override fun intercept(chain: Interceptor.Chain): Response {
if (tokenExpired) {
throw HKTokenExpired()
}
val originalRequest = chain.request()
if (oauth?.isExpired() == true) {
refreshToken(chain)
}
val currAuth = oauth ?: throw Exception("Not authenticated with Hikka")
if (oauth == null) {
throw IOException("User is not authenticated")
if (currAuth.isExpired()) {
val refreshTokenResponse = chain.proceed(HikkaApi.refreshTokenRequest(currAuth.accessToken))
if (!refreshTokenResponse.isSuccessful)
refreshTokenResponse.close()
val authTokenInfoResponse = chain.proceed(HikkaApi.authTokenInfo(currAuth.accessToken))
if (!authTokenInfoResponse.isSuccessful)
authTokenInfoResponse.close()
val authTokenInfo = json.decodeFromString<HKAuthTokenInfo>(authTokenInfoResponse.body.string())
setAuth(HKOAuth(oauth!!.accessToken, authTokenInfo.expiration))
}
val authRequest = originalRequest.newBuilder()
@ -40,41 +42,4 @@ class HikkaInterceptor(private val hikka: Hikka) : Interceptor {
this.oauth = oauth
hikka.saveOAuth(oauth)
}
private fun refreshToken(chain: Interceptor.Chain): HKOAuth = synchronized(this) {
if (tokenExpired) throw HKTokenExpired()
oauth?.takeUnless { it.isExpired() }?.let { return@synchronized it }
val response = try {
chain.proceed(HikkaApi.refreshTokenRequest(oauth!!))
} catch (_: Throwable) {
throw HKTokenRefreshFailed()
}
if (response.code != 200) {
hikka.setAuthExpired()
throw HKTokenExpired()
}
return runCatching {
if (response.isSuccessful && oauth != null) {
val responseBody = response.body?.string() ?: return@runCatching null
val jsonObject = JSONObject(responseBody)
val secret = oauth!!.accessToken
val expiration = jsonObject.getLong("expiration")
HKOAuth(secret, expiration)
} else {
response.close()
null
}
}.getOrNull()?.also {
this.oauth = it
hikka.saveOAuth(it)
} ?: throw HKTokenRefreshFailed()
}
}
class HKTokenRefreshFailed : IOException("Hikka: Failed to refresh account token")
class HKTokenExpired : IOException("Hikka: Login has expired")

View file

@ -1,17 +1,13 @@
package eu.kanade.tachiyomi.data.track.hikka.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class HKOAuth(
@SerialName("secret")
val accessToken: String,
@SerialName("expiration")
val expiration: Long,
) {
fun isExpired(): Boolean {
return (expiration - 7200) < (System.currentTimeMillis() / 1000)
return (expiration - 43200) < (System.currentTimeMillis() / 1000)
}
}