From 51cc6c182e231bd2434508581097a8d0dadf26eb Mon Sep 17 00:00:00 2001 From: NovaFox161 Date: Thu, 31 Aug 2023 13:48:19 -0500 Subject: [PATCH] GoogleAuth component now fully using kotlin coroutines --- .../discal/cam/endpoints/v1/GetEndpoint.kt | 3 +- .../discal/cam/google/GoogleAuth.kt | 48 ++++++------------- .../entities/google/DisCalGoogleCredential.kt | 45 ----------------- 3 files changed, 16 insertions(+), 80 deletions(-) delete mode 100644 core/src/main/kotlin/org/dreamexposure/discal/core/entities/google/DisCalGoogleCredential.kt diff --git a/cam/src/main/kotlin/org/dreamexposure/discal/cam/endpoints/v1/GetEndpoint.kt b/cam/src/main/kotlin/org/dreamexposure/discal/cam/endpoints/v1/GetEndpoint.kt index 6c1f702b8..b152d438e 100644 --- a/cam/src/main/kotlin/org/dreamexposure/discal/cam/endpoints/v1/GetEndpoint.kt +++ b/cam/src/main/kotlin/org/dreamexposure/discal/cam/endpoints/v1/GetEndpoint.kt @@ -1,7 +1,6 @@ package org.dreamexposure.discal.cam.endpoints.v1 import discord4j.common.util.Snowflake -import kotlinx.coroutines.reactor.awaitSingle import org.dreamexposure.discal.cam.google.GoogleAuth import org.dreamexposure.discal.core.annotations.Authentication import org.dreamexposure.discal.core.business.CalendarService @@ -25,7 +24,7 @@ class GetEndpoint( CalendarHost.GOOGLE -> { if (guild == null) { // Internal (owned by DisCal, should never go bad) - googleAuth.requestNewAccessToken(id).awaitSingle() + googleAuth.requestNewAccessToken(id) } else { // External (owned by user) val calendar = calendarService.getCalendar(guild, id) ?: return null diff --git a/cam/src/main/kotlin/org/dreamexposure/discal/cam/google/GoogleAuth.kt b/cam/src/main/kotlin/org/dreamexposure/discal/cam/google/GoogleAuth.kt index 56b5e746e..5f7a78d40 100644 --- a/cam/src/main/kotlin/org/dreamexposure/discal/cam/google/GoogleAuth.kt +++ b/cam/src/main/kotlin/org/dreamexposure/discal/cam/google/GoogleAuth.kt @@ -3,7 +3,6 @@ package org.dreamexposure.discal.cam.google import com.google.api.client.http.HttpStatusCodes.STATUS_CODE_BAD_REQUEST import com.google.api.client.http.HttpStatusCodes.STATUS_CODE_OK import kotlinx.coroutines.reactor.awaitSingle -import kotlinx.coroutines.reactor.mono import okhttp3.FormBody import okhttp3.Request import org.dreamexposure.discal.cam.json.google.ErrorData @@ -12,7 +11,6 @@ import org.dreamexposure.discal.core.business.CalendarService import org.dreamexposure.discal.core.business.CredentialService import org.dreamexposure.discal.core.config.Config import org.dreamexposure.discal.core.crypto.AESEncryption -import org.dreamexposure.discal.core.entities.google.DisCalGoogleCredential import org.dreamexposure.discal.core.exceptions.AccessRevokedException import org.dreamexposure.discal.core.exceptions.EmptyNotAllowedException import org.dreamexposure.discal.core.exceptions.NotFoundException @@ -24,28 +22,16 @@ import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT import org.dreamexposure.discal.core.utils.GlobalVal.HTTP_CLIENT import org.dreamexposure.discal.core.utils.GlobalVal.JSON_FORMAT import org.springframework.stereotype.Component -import reactor.core.publisher.Flux import reactor.core.publisher.Mono import reactor.core.scheduler.Schedulers import java.time.Instant -import kotlin.system.exitProcess @Component class GoogleAuth( private val credentialService: CredentialService, private val calendarService: CalendarService, ) { - private final val CREDENTIALS: Flux // TODO: Refactor as kc - - init { - val credCount = Config.SECRET_GOOGLE_CREDENTIAL_COUNT.getInt() - - CREDENTIALS = Flux.range(0, credCount) - .flatMap { mono { credentialService.getCredential(it) } } - .map(::DisCalGoogleCredential) - .doOnError { exitProcess(1) } - .cache() - } + private final val aes: AESEncryption = AESEncryption(Config.SECRET_GOOGLE_CREDENTIAL_KEY.getString()) suspend fun requestNewAccessToken(calendar: Calendar): CredentialData? { val aes = AESEncryption(calendar.secrets.privateKey) @@ -66,24 +52,20 @@ class GoogleAuth( return refreshedCredential } - fun requestNewAccessToken(credentialId: Int): Mono { // TODO: Refactor as kc - return CREDENTIALS - .filter { it.credential.credentialNumber == credentialId } - .next() - .switchIfEmpty(Mono.error(NotFoundException())) - .flatMap { credential -> - if (!credential.expired()) { - return@flatMap credential.getAccessToken() - .map { CredentialData(it, credential.credential.expiresAt) } - } - - credential.getRefreshToken() - .flatMap { mono { doAccessTokenRequest(it) } } - .flatMap { credential.setAccessToken(it.accessToken).thenReturn(it) } - .doOnNext { credential.credential.expiresAt = it.validUntil } - .flatMap(mono { credentialService.updateCredential(credential.credential) }::thenReturn) - }.switchIfEmpty(Mono.error(EmptyNotAllowedException())) + suspend fun requestNewAccessToken(credentialId: Int): CredentialData { + val credential = credentialService.getCredential(credentialId) ?: throw NotFoundException() + if (!credential.expiresAt.isExpiredTtl()) { + val accessToken = aes.decrypt(credential.encryptedAccessToken).awaitSingle() + return CredentialData(accessToken, credential.expiresAt) + } + + val refreshToken = aes.decrypt(credential.encryptedRefreshToken).awaitSingle() + val refreshedCredentialData = doAccessTokenRequest(refreshToken) ?: throw EmptyNotAllowedException() + credential.encryptedAccessToken = aes.encrypt(refreshedCredentialData.accessToken).awaitSingle() + credential.expiresAt = refreshedCredentialData.validUntil.minusSeconds(60) // Add a minute of wiggle room + credentialService.updateCredential(credential) + return refreshedCredentialData } private suspend fun doAccessTokenRequest(refreshToken: String): CredentialData? { @@ -124,7 +106,7 @@ class GoogleAuth( throw AccessRevokedException() } else { LOGGER.error(DEFAULT, "[Google] Error requesting new access token | ${response.code} | ${response.message} | $body") - return null + null } } else -> { diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/entities/google/DisCalGoogleCredential.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/entities/google/DisCalGoogleCredential.kt deleted file mode 100644 index 7464a98f1..000000000 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/entities/google/DisCalGoogleCredential.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.dreamexposure.discal.core.entities.google - -import org.dreamexposure.discal.core.config.Config -import org.dreamexposure.discal.core.crypto.AESEncryption -import org.dreamexposure.discal.core.`object`.new.Credential -import reactor.core.publisher.Mono -import java.time.Instant - -data class DisCalGoogleCredential( - val credential: Credential, -) { - private val aes: AESEncryption = AESEncryption(Config.SECRET_GOOGLE_CREDENTIAL_KEY.getString()) - private var access: String? = null - private var refresh: String? = null - - fun getRefreshToken(): Mono { - if (refresh != null) return Mono.justOrEmpty(refresh) - return aes.decrypt(credential.encryptedRefreshToken) - .doOnNext { refresh = it } - } - - fun getAccessToken(): Mono { - if (access != null) return Mono.justOrEmpty(access) - return aes.decrypt(credential.encryptedAccessToken) - .doOnNext { access = it } - } - - fun setRefreshToken(token: String): Mono { - refresh = token - //credentialData.encryptedRefreshToken = aes.encrypt(token) - return aes.encrypt(token) - .doOnNext { credential.encryptedRefreshToken = it } - .then() - } - - fun setAccessToken(token: String): Mono { - access = token - //credentialData.encryptedAccessToken = aes.encrypt(token) - return aes.encrypt(token) - .doOnNext { credential.encryptedAccessToken = it } - .then() - } - - fun expired() = Instant.now().isAfter(credential.expiresAt) -}