/ backend / src / services / oauth_client_service.rs
oauth_client_service.rs
  1  use rand::{distributions::Alphanumeric, thread_rng, Rng};
  2  use rocket::State;
  3  use sqlx::types::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::{oauth_client::OauthClient, oauth_scope::OauthScope},
 11      util::accounts_error::AccountsError,
 12  };
 13  
 14  const CLIENT_ID_LENGTH: usize = 32;
 15  const CLIENT_SECRET_LENGTH: usize = 128;
 16  
 17  #[derive(Debug, thiserror::Error)]
 18  pub enum OauthClientError {
 19      #[error("Sqlx error: `{0}`")]
 20      SqlxError(#[from] sqlx::Error),
 21      #[error("Accounts error: `{0}`")]
 22      AccountsError(#[from] AccountsError),
 23      #[error("The Oauth client name is already taken")]
 24      ClientNameTaken,
 25      #[error("The provided ID is not a valid UUID")]
 26      InvalidId,
 27      #[error("No client with that ID exists")]
 28      ClientIdNotFound,
 29  }
 30  
 31  pub async fn get_oauth_clients(
 32      db_pool: &State<sqlx::Pool<DB>>,
 33  ) -> Result<Vec<OauthClient>, OauthClientError> {
 34      let mut transaction = new_transaction(db_pool).await?;
 35  
 36      match oauth_client_repository::get_all(&mut transaction).await {
 37          Ok(clients) => Ok(clients),
 38          Err(err) => {
 39              error!("Failed to get oauth clients, err: {}", err);
 40              Err(err.into())
 41          }
 42      }
 43  }
 44  
 45  pub async fn create_oauth_client(
 46      db_pool: &State<sqlx::Pool<DB>>,
 47      client_name: &String,
 48      redirect_uri: &String,
 49      scopes: &[OauthScope],
 50  ) -> Result<OauthClient, OauthClientError> {
 51      let mut transaction = new_transaction(db_pool).await?;
 52  
 53      // Check if the name is taken already
 54      match oauth_client_repository::get_by_client_name(&mut transaction, client_name.clone()).await {
 55          Ok(None) => {}
 56          Ok(Some(_)) => return Err(OauthClientError::ClientNameTaken),
 57          Err(err) => {
 58              error!("Failed to get client by name, err: {}", err);
 59              Err(err)?;
 60          }
 61      };
 62  
 63      let client_id: String = thread_rng()
 64          .sample_iter(&Alphanumeric)
 65          .take(CLIENT_ID_LENGTH)
 66          .map(char::from)
 67          .collect();
 68  
 69      let client_secret: String = thread_rng()
 70          .sample_iter(&Alphanumeric)
 71          .take(CLIENT_SECRET_LENGTH)
 72          .map(char::from)
 73          .collect();
 74  
 75      let oauth_client = oauth_client_repository::insert(
 76          &mut transaction,
 77          &client_id,
 78          &client_secret,
 79          client_name,
 80          redirect_uri,
 81      )
 82      .await?;
 83  
 84      for scope in scopes.iter() {
 85          client_scope_repository::insert(&mut transaction, &oauth_client, scope).await?;
 86      }
 87  
 88      transaction.commit().await?;
 89  
 90      Ok(oauth_client)
 91  }
 92  
 93  pub async fn delete_oauth_client(
 94      db_pool: &State<sqlx::Pool<DB>>,
 95      client_id: &str,
 96  ) -> Result<(), OauthClientError> {
 97      let client_id = Uuid::parse_str(client_id).map_err(|err| {
 98          error!("Failed to parse oauth client id as UUID, err {}", err);
 99          OauthClientError::InvalidId
100      })?;
101  
102      let mut transaction = new_transaction(db_pool).await?;
103  
104      let client = oauth_client_repository::find_by_id(&mut transaction, &client_id)
105          .await?
106          .ok_or(OauthClientError::ClientIdNotFound)?;
107  
108      let client_scopes =
109          client_scope_repository::get_all_for_client(&mut transaction, &client).await?;
110  
111      for client_scope in client_scopes.iter() {
112          user_client_consented_scope_repository::delete_by_client_scope(
113              &mut transaction,
114              client_scope,
115          )
116          .await?;
117          client_scope_repository::delete(&mut transaction, client_scope).await?;
118      }
119  
120      user_client_consent_repository::delete_by_client(&mut transaction, &client).await?;
121  
122      oauth_client_repository::delete(&mut transaction, &client)
123          .await?
124          .ok_or(OauthClientError::ClientIdNotFound)?;
125  
126      transaction.commit().await?;
127  
128      Ok(())
129  }