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 }