fix: add more oauth2 checks

This commit is contained in:
Zomatree
2025-06-29 01:12:24 +01:00
parent 11eee02cfe
commit 5a5f84f207
7 changed files with 26 additions and 8 deletions

View File

@@ -49,6 +49,7 @@ auto_derived_partial!(
auto_derived!( auto_derived!(
#[derive(Copy, Hash)] #[derive(Copy, Hash)]
#[serde(rename = "lowercase")]
pub enum OAuth2Scope { pub enum OAuth2Scope {
Identify, Identify,
Full, Full,

View File

@@ -123,4 +123,14 @@ pub async fn add_code_challange(token: &str, code_challenge: &str) -> Result<()>
.map_err(|_| create_error!(InternalError))?; .map_err(|_| create_error!(InternalError))?;
Ok(()) Ok(())
}
pub async fn get_code_challange(token: &str) -> Result<Option<String>> {
let mut conn = redis_kiss::get_connection()
.await
.map_err(|_| create_error!(InternalError))?;
conn.get(format!("oauth2:{token}:code_challenge"))
.await
.map_err(|_| create_error!(InternalError))
} }

View File

@@ -77,6 +77,7 @@ auto_derived!(
} }
#[derive(Copy, Hash)] #[derive(Copy, Hash)]
#[cfg_attr(feature = "serde", serde(rename = "lowercase"))]
pub enum OAuth2Scope { pub enum OAuth2Scope {
Identify, Identify,
Full, Full,

View File

@@ -1,4 +1,3 @@
use revolt_database::BotOauth2;
use revolt_database::{util::reference::Reference, Database, PartialBot, User}; use revolt_database::{util::reference::Reference, Database, PartialBot, User};
use revolt_models::v0::{self, DataEditBot}; use revolt_models::v0::{self, DataEditBot};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};

View File

@@ -17,6 +17,10 @@ pub async fn auth(
user: User, user: User,
info: v0::OAuth2AuthorizationForm, info: v0::OAuth2AuthorizationForm,
) -> Result<Json<v0::OAuth2AuthorizeAuthResponse>> { ) -> Result<Json<v0::OAuth2AuthorizeAuthResponse>> {
if user.bot.is_some() {
return Err(create_error!(IsBot));
};
let bot = Reference::from_unchecked(info.client_id.clone()) let bot = Reference::from_unchecked(info.client_id.clone())
.as_bot(db) .as_bot(db)
.await?; .await?;

View File

@@ -13,6 +13,10 @@ pub async fn info(
user: User, user: User,
info: v0::OAuth2AuthorizationForm, info: v0::OAuth2AuthorizationForm,
) -> Result<Json<v0::OAuth2AuthorizeInfoResponse>> { ) -> Result<Json<v0::OAuth2AuthorizeInfoResponse>> {
if user.bot.is_some() {
return Err(create_error!(IsBot));
};
let bot = Reference::from_unchecked(info.client_id.to_string()).as_bot(db).await?; let bot = Reference::from_unchecked(info.client_id.to_string()).as_bot(db).await?;
let bot_user = Reference::from_unchecked(bot.id.clone()).as_user(db).await?; let bot_user = Reference::from_unchecked(bot.id.clone()).as_user(db).await?;
let public_bot = bot.clone().into_public_bot(bot_user); let public_bot = bot.clone().into_public_bot(bot_user);

View File

@@ -35,13 +35,9 @@ pub async fn token(
return Err(create_error!(NotAuthenticated)) return Err(create_error!(NotAuthenticated))
} }
} else if let Some((code_verifier, method)) = info.code_verifier.as_ref().zip(claims.code_challange_method) { } else if let Some((code_verifier, method)) = info.code_verifier.as_ref().zip(claims.code_challange_method) {
let mut conn = redis_kiss::get_connection() let Some(server_code_challenge) = oauth2::get_code_challange(&info.code).await? else {
.await return Err(create_error!(NotAuthenticated))
.map_err(|_| create_error!(InternalError))?; };
let server_code_challenge = conn.get::<_, String>(format!("oauth2:{}:code_challenge", &info.code))
.await
.map_err(|_| create_error!(InternalError))?;
let is_valid = match method { let is_valid = match method {
v0::OAuth2CodeChallangeMethod::Plain => &server_code_challenge == code_verifier, v0::OAuth2CodeChallangeMethod::Plain => &server_code_challenge == code_verifier,
@@ -51,6 +47,8 @@ pub async fn token(
if !is_valid { if !is_valid {
return Err(create_error!(NotAuthenticated)) return Err(create_error!(NotAuthenticated))
} }
} else {
return Err(create_error!(NotAuthenticated))
} }
if claims.client_id != info.client_id || claims.exp < Utc::now().timestamp() { if claims.client_id != info.client_id || claims.exp < Utc::now().timestamp() {
@@ -81,6 +79,7 @@ pub async fn token(
})) }))
}, },
v0::OAuth2GrantType::Implicit => { v0::OAuth2GrantType::Implicit => {
// token is already an access token so this endpoint does not need to be called - in theory this should be unreachable
Err(create_error!(InvalidOperation)) Err(create_error!(InvalidOperation))
} }
} }