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) interceptor.setAuth(null)
} }
fun getIfAuthExpired(): Boolean {
return trackPreferences.trackAuthExpired(this).get()
}
fun setAuthExpired() {
trackPreferences.trackAuthExpired(this).set(true)
}
fun saveOAuth(oAuth: HKOAuth?) { fun saveOAuth(oAuth: HKOAuth?) {
trackPreferences.trackToken(this).set(json.encodeToString(oAuth)) trackPreferences.trackToken(this).set(json.encodeToString(oAuth))
} }

View file

@ -174,12 +174,20 @@ class HikkaApi(
.appendQueryParameter("scope", SCOPE) .appendQueryParameter("scope", SCOPE)
.build() .build()
fun refreshTokenRequest(hkOAuth: HKOAuth): Request { fun refreshTokenRequest(accessToken: String): Request {
val headers = Headers.Builder() val headers = Headers.Builder()
.add("auth", hkOAuth.accessToken) .add("auth", accessToken)
.build() .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 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 eu.kanade.tachiyomi.data.track.hikka.dto.HKOAuth
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import org.json.JSONObject
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
class HikkaInterceptor(private val hikka: Hikka) : Interceptor { class HikkaInterceptor(private val hikka: Hikka) : Interceptor {
private val json: Json by injectLazy() private val json: Json by injectLazy()
private var oauth: HKOAuth? = hikka.loadOAuth() private var oauth: HKOAuth? = hikka.loadOAuth()
private val tokenExpired get() = hikka.getIfAuthExpired()
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
if (tokenExpired) {
throw HKTokenExpired()
}
val originalRequest = chain.request() val originalRequest = chain.request()
if (oauth?.isExpired() == true) { val currAuth = oauth ?: throw Exception("Not authenticated with Hikka")
refreshToken(chain)
}
if (oauth == null) { if (currAuth.isExpired()) {
throw IOException("User is not authenticated") 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() val authRequest = originalRequest.newBuilder()
@ -40,41 +42,4 @@ class HikkaInterceptor(private val hikka: Hikka) : Interceptor {
this.oauth = oauth this.oauth = oauth
hikka.saveOAuth(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 package eu.kanade.tachiyomi.data.track.hikka.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class HKOAuth( data class HKOAuth(
@SerialName("secret")
val accessToken: String, val accessToken: String,
@SerialName("expiration")
val expiration: Long, val expiration: Long,
) { ) {
fun isExpired(): Boolean { fun isExpired(): Boolean {
return (expiration - 7200) < (System.currentTimeMillis() / 1000) return (expiration - 43200) < (System.currentTimeMillis() / 1000)
} }
} }