mirror of
https://github.com/DreamExposure/DisCal-Discord-Bot.git
synced 2026-05-08 02:10:05 -05:00
Fix encryption race condition (#119)
This commit is contained in:
@@ -6,8 +6,6 @@ import org.dreamexposure.discal.core.`object`.network.discal.CredentialData
|
||||
import org.dreamexposure.discal.core.annotations.Authentication
|
||||
import org.dreamexposure.discal.core.database.DatabaseManager
|
||||
import org.dreamexposure.discal.core.enums.calendar.CalendarHost
|
||||
import org.dreamexposure.discal.core.logger.LOGGER
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
@@ -33,8 +31,6 @@ class GetEndpoint {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.doOnError {
|
||||
LOGGER.error(DEFAULT, "Access token grant failure", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.dreamexposure.discal.core.database.DatabaseManager
|
||||
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
|
||||
import org.dreamexposure.discal.core.logger.LOGGER
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal.HTTP_CLIENT
|
||||
@@ -40,16 +41,21 @@ object GoogleAuth {
|
||||
}
|
||||
|
||||
fun requestNewAccessToken(calendarData: CalendarData): Mono<CredentialData> {
|
||||
val aes = AESEncryption(calendarData.privateKey)
|
||||
if (!calendarData.expired()) {
|
||||
return Mono.just(CredentialData(aes.decrypt(calendarData.encryptedAccessToken), calendarData.expiresAt))
|
||||
}
|
||||
return Mono.just(AESEncryption(calendarData.privateKey)).flatMap { aes ->
|
||||
if (!calendarData.expired()) {
|
||||
return@flatMap aes.decrypt(calendarData.encryptedAccessToken)
|
||||
.map { CredentialData(it, calendarData.expiresAt) }
|
||||
}
|
||||
|
||||
return doAccessTokenRequest(aes.decrypt(calendarData.encryptedRefreshToken)).flatMap { data ->
|
||||
calendarData.encryptedAccessToken = aes.encrypt(data.accessToken)
|
||||
calendarData.expiresAt = data.validUntil
|
||||
aes.decrypt(calendarData.encryptedRefreshToken)
|
||||
.flatMap(this::doAccessTokenRequest)
|
||||
.flatMap { data ->
|
||||
//calendarData.encryptedAccessToken = aes.encrypt(data.accessToken)
|
||||
calendarData.expiresAt = data.validUntil
|
||||
|
||||
DatabaseManager.updateCalendar(calendarData).thenReturn(data)
|
||||
aes.encrypt(data.accessToken)
|
||||
.then(DatabaseManager.updateCalendar(calendarData).thenReturn(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,19 +63,18 @@ object GoogleAuth {
|
||||
return CREDENTIALS
|
||||
.filter { it.credentialData.credentialNumber == credentialId }
|
||||
.next()
|
||||
.switchIfEmpty(Mono.error(NotFoundException()))
|
||||
.flatMap { credential ->
|
||||
if (!credential.expired()) {
|
||||
return@flatMap Mono.just(
|
||||
CredentialData(credential.getAccessToken(), credential.credentialData.expiresAt)
|
||||
)
|
||||
return@flatMap credential.getAccessToken()
|
||||
.map { CredentialData(it, credential.credentialData.expiresAt) }
|
||||
}
|
||||
|
||||
doAccessTokenRequest(credential.getRefreshToken()).flatMap { data ->
|
||||
credential.setAccessToken(data.accessToken)
|
||||
credential.credentialData.expiresAt = data.validUntil
|
||||
|
||||
DatabaseManager.updateCredentialData(credential.credentialData).thenReturn(data)
|
||||
}
|
||||
credential.getRefreshToken()
|
||||
.flatMap(this::doAccessTokenRequest)
|
||||
.flatMap { credential.setAccessToken(it.accessToken).thenReturn(it) }
|
||||
.doOnNext { credential.credentialData.expiresAt = it.validUntil }
|
||||
.flatMap { DatabaseManager.updateCredentialData(credential.credentialData).thenReturn(it) }
|
||||
}.switchIfEmpty(Mono.error(EmptyNotAllowedException()))
|
||||
|
||||
}
|
||||
@@ -104,6 +109,8 @@ object GoogleAuth {
|
||||
response.body?.close()
|
||||
response.close()
|
||||
|
||||
LOGGER.error("[Google] Int Cred bad Request: $body")
|
||||
|
||||
if (body.error == "invalid_grant") {
|
||||
LOGGER.debug(DEFAULT, "[Google] Access to resource has been revoked")
|
||||
Mono.error<CredentialData>(AccessRevokedException())
|
||||
|
||||
+12
-7
@@ -5,12 +5,14 @@ import org.dreamexposure.discal.core.`object`.google.GoogleCredentialData
|
||||
import org.dreamexposure.discal.core.`object`.google.InternalGoogleAuthPoll
|
||||
import org.dreamexposure.discal.core.crypto.AESEncryption
|
||||
import org.dreamexposure.discal.core.database.DatabaseManager
|
||||
import org.dreamexposure.discal.core.exceptions.EmptyNotAllowedException
|
||||
import org.dreamexposure.discal.core.exceptions.google.GoogleAuthCancelException
|
||||
import org.dreamexposure.discal.core.logger.LOGGER
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal
|
||||
import org.dreamexposure.discal.core.wrapper.google.GoogleAuthWrapper
|
||||
import org.json.JSONObject
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.function.TupleUtils
|
||||
import java.time.Instant
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
@@ -57,7 +59,7 @@ object GoogleInternalAuthHandler {
|
||||
//Handle access denied
|
||||
LOGGER.debug(GlobalVal.DEFAULT, "[!GDC!] Access denied for credential: ${poll.credNumber}")
|
||||
|
||||
Mono.error<GoogleAuthCancelException>(GoogleAuthCancelException())
|
||||
Mono.error(GoogleAuthCancelException())
|
||||
}
|
||||
GlobalVal.STATUS_BAD_REQUEST, GlobalVal.STATUS_PRECONDITION_REQUIRED -> {
|
||||
//See if auth is pending, if so, just reschedule.
|
||||
@@ -93,14 +95,17 @@ object GoogleInternalAuthHandler {
|
||||
val aprGrant = JSONObject(responseBody)
|
||||
val aes = AESEncryption(BotSettings.CREDENTIALS_KEY.get())
|
||||
|
||||
val encryptedRefresh = aes.encrypt(aprGrant.getString("refresh_token"))
|
||||
val encryptedAccess = aes.encrypt(aprGrant.getString("access_token"))
|
||||
val expiresAt = Instant.now().plusSeconds(aprGrant.getLong("expires_in"))
|
||||
val refreshMono = aes.encrypt(aprGrant.getString("refresh_token"))
|
||||
val accessMono = aes.encrypt(aprGrant.getString("access_token"))
|
||||
|
||||
val creds = GoogleCredentialData(poll.credNumber, encryptedRefresh, encryptedAccess, expiresAt)
|
||||
Mono.zip(refreshMono, accessMono).flatMap<GoogleAuthCancelException?>(TupleUtils.function { refresh, access ->
|
||||
val expiresAt = Instant.now().plusSeconds(aprGrant.getLong("expires_in"))
|
||||
|
||||
DatabaseManager.updateCredentialData(creds)
|
||||
.then(Mono.error(GoogleAuthCancelException()))
|
||||
val creds = GoogleCredentialData(poll.credNumber, refresh, access, expiresAt)
|
||||
|
||||
DatabaseManager.updateCredentialData(creds)
|
||||
.then(Mono.error(GoogleAuthCancelException()))
|
||||
}).onErrorResume(EmptyNotAllowedException::class.java) { Mono.error(GoogleAuthCancelException()) }
|
||||
}
|
||||
else -> {
|
||||
//Unknown network error...
|
||||
|
||||
Reference in New Issue
Block a user