/ backend / src / services / oauth_consent_service.rs
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  }