headless_lms_server/programs/seed/
seed_oauth_clients.rs1use std::str::FromStr;
2
3use headless_lms_models::{
4 library::oauth::{Digest, GrantTypeName, pkce},
5 oauth_client,
6};
7use sqlx::{Pool, Postgres};
8use uuid::Uuid;
9
10pub struct SeedOAuthClientsResult {
11 pub client_db_id: Uuid,
12}
13
14const TEST_CLIENT_IDS: &[&str] = &["test-client-id", "test-client-id-2", "test-client-id-3"];
15
16pub async fn seed_oauth_clients(db_pool: Pool<Postgres>) -> anyhow::Result<SeedOAuthClientsResult> {
17 info!("Inserting OAuth Clients");
18 let secret =
19 Digest::from_str("396b544a35b29f7d613452a165dcaebf4d71b80e981e687e91ce6d9ba9679cb2")
20 .unwrap(); let mut conn = db_pool.acquire().await?;
22 let mut redirect_uris: Vec<String> = (8765..=8784)
25 .map(|p| format!("http://127.0.0.1:{p}/callback"))
26 .collect();
27 redirect_uris.push("https://localhost.emobix.co.uk:8443/test/a/testing/callback".to_string());
28
29 for client_id in TEST_CLIENT_IDS {
31 let updated = sqlx::query(
32 "UPDATE oauth_clients SET redirect_uris = $1, updated_at = now() WHERE client_id = $2 AND deleted_at IS NULL",
33 )
34 .bind(&redirect_uris)
35 .bind(*client_id)
36 .execute(&mut *conn)
37 .await?;
38 if updated.rows_affected() > 0 {
39 info!(
40 "Updated redirect_uris for existing OAuth client {}",
41 client_id
42 );
43 }
44 }
45
46 let scopes = vec![
47 "openid".to_string(),
48 "profile".to_string(),
49 "email".to_string(),
50 "offline_access".to_string(),
51 ];
52 let allowed_grant_types = vec![
53 GrantTypeName::AuthorizationCode,
54 GrantTypeName::RefreshToken,
55 ];
56 let pkce_methods_allowed = vec![pkce::PkceMethod::S256];
57
58 let new_client_parms = oauth_client::NewClientParams {
59 client_name: "Test Client",
60 application_type: oauth_client::ApplicationType::Web,
61 client_id: "test-client-id",
62 client_secret: Some(&secret), client_secret_expires_at: None,
64 redirect_uris: redirect_uris.as_slice(),
65 allowed_grant_types: &allowed_grant_types,
66 scopes: scopes.as_slice(),
67 origin: "http://localhost",
68 bearer_allowed: true,
69 pkce_methods_allowed: &pkce_methods_allowed,
70 post_logout_redirect_uris: None,
71 require_pkce: true,
72 token_endpoint_auth_method: oauth_client::TokenEndpointAuthMethod::ClientSecretPost,
73 };
74
75 let client = if let Some(existing) =
76 oauth_client::OAuthClient::find_by_client_id_optional(&mut conn, "test-client-id").await?
77 {
78 existing
79 } else {
80 oauth_client::OAuthClient::insert(&mut conn, new_client_parms).await?
81 };
82
83 let new_client_parms_2 = oauth_client::NewClientParams {
84 client_name: "Test Client 2",
85 application_type: oauth_client::ApplicationType::Web,
86 client_id: "test-client-id-2",
87 client_secret: Some(&secret), client_secret_expires_at: None,
89 redirect_uris: redirect_uris.as_slice(),
90 allowed_grant_types: &allowed_grant_types,
91 scopes: scopes.as_slice(),
92 origin: "http://localhost",
93 bearer_allowed: true,
94 pkce_methods_allowed: &pkce_methods_allowed,
95 post_logout_redirect_uris: None,
96 require_pkce: false,
97 token_endpoint_auth_method: oauth_client::TokenEndpointAuthMethod::ClientSecretPost,
98 };
99 if oauth_client::OAuthClient::find_by_client_id_optional(&mut conn, "test-client-id-2")
100 .await?
101 .is_none()
102 {
103 let _client_2 = oauth_client::OAuthClient::insert(&mut conn, new_client_parms_2).await?;
104 }
105
106 let new_client_parms_3 = oauth_client::NewClientParams {
107 client_name: "Test Client 3",
108 application_type: oauth_client::ApplicationType::Web,
109 client_id: "test-client-id-3",
110 client_secret: Some(&secret), client_secret_expires_at: None,
112 redirect_uris: redirect_uris.as_slice(),
113 allowed_grant_types: &allowed_grant_types,
114 scopes: scopes.as_slice(),
115 origin: "http://localhost",
116 bearer_allowed: true,
117 pkce_methods_allowed: &pkce_methods_allowed,
118 post_logout_redirect_uris: None,
119 require_pkce: false,
120 token_endpoint_auth_method: oauth_client::TokenEndpointAuthMethod::ClientSecretPost,
121 };
122 if oauth_client::OAuthClient::find_by_client_id_optional(&mut conn, "test-client-id-3")
123 .await?
124 .is_none()
125 {
126 let _client_3 = oauth_client::OAuthClient::insert(&mut conn, new_client_parms_3).await?;
127 }
128
129 Ok(SeedOAuthClientsResult {
130 client_db_id: client.id,
131 })
132}