oauth_consent_service.rs
1 use std::collections::HashSet; 2 3 use uuid::Uuid; 4 5 use crate::{ 6 db::{ 7 client_scope_repository, new_transaction, oauth_client_repository, 8 user_client_consent_repository, user_client_consented_scope_repository, DB, 9 }, 10 models::{client_scope::ClientScope, oauth_scope::OauthScope}, 11 util::accounts_error::AccountsError, 12 }; 13 14 use super::oauth_authorization_service::validate_scopes; 15 16 #[derive(Debug, thiserror::Error)] 17 pub enum ConsentError { 18 #[error("Accounts error")] 19 AccountsError(#[from] AccountsError), 20 #[error("Sqlx error")] 21 SqlxError(#[from] sqlx::Error), 22 #[error("There is no client with that client_id")] 23 NoClientWithId, 24 #[error("The client has not been registered for one or more of the requested scopes")] 25 ClientNotRegisteredForScope, 26 } 27 28 pub async fn consent_to_client_scopes( 29 db_pool: &sqlx::Pool<DB>, 30 client_id: &str, 31 account_id: Uuid, 32 requested_scopes: HashSet<OauthScope>, 33 ) -> Result<(), ConsentError> { 34 let mut transaction = new_transaction(db_pool).await?; 35 36 let client = oauth_client_repository::get_by_client_id(&mut transaction, client_id) 37 .await? 38 .ok_or(ConsentError::NoClientWithId)?; 39 40 let scopes = client_scope_repository::get_all_for_client(&mut transaction, &client).await?; 41 if !validate_scopes(&requested_scopes, &scopes) { 42 return Err(ConsentError::ClientNotRegisteredForScope); 43 } 44 45 let consented_scopes: Vec<ClientScope> = scopes 46 .into_iter() 47 .filter(|s| requested_scopes.contains(&s.scope)) 48 .collect(); 49 50 let user_client_consent = if let Some(consent) = 51 user_client_consent_repository::get_by_client_and_account( 52 &mut transaction, 53 &client, 54 &account_id, 55 ) 56 .await? 57 { 58 consent 59 } else { 60 user_client_consent_repository::insert(&mut transaction, &client, &account_id).await? 61 }; 62 63 let already_consented = client_scope_repository::consented_by_user_for_client( 64 &mut transaction, 65 &client, 66 &user_client_consent, 67 ) 68 .await?; 69 70 for scope in consented_scopes 71 .into_iter() 72 .filter(|s| !already_consented.contains(s)) 73 { 74 user_client_consented_scope_repository::insert( 75 &mut transaction, 76 &user_client_consent, 77 &scope, 78 ) 79 .await?; 80 } 81 82 transaction.commit().await?; 83 84 Ok(()) 85 }