haste_server/auth_n/oidc/
utilities.rs

1use haste_fhir_model::r4::generated::{resources::ClientApplication, terminology::IssueType};
2use haste_fhir_operation_error::OperationOutcomeError;
3use haste_jwt::TenantId;
4use haste_repository::{
5    Repository,
6    admin::TenantAuthAdmin,
7    types::user::{CreateUser, UpdateUser},
8};
9use regex::Regex;
10
11pub fn is_valid_redirect_url(redirect_url: &str, client: &ClientApplication) -> bool {
12    let k = client.redirectUri.as_ref().and_then(|redirect_uris| {
13        redirect_uris.iter().find(|redirect_pattern| {
14            if let Some(redirect_pattern) = redirect_pattern.value.as_ref()
15                && let Ok(pattern) = Regex::new(&redirect_pattern.replace("*", "(.+)"))
16            {
17                pattern.is_match(redirect_url)
18            } else {
19                false
20            }
21        })
22    });
23
24    k.is_some() && !redirect_url.is_empty()
25}
26
27pub async fn set_user_password<Repo: Repository>(
28    repo: &Repo,
29    tenant: &TenantId,
30    user_email: &str,
31    user_id: &str,
32    password: &str,
33) -> Result<(), OperationOutcomeError> {
34    // In a real implementation, you would hash the password here
35    let password_strength = zxcvbn::zxcvbn(password, &[user_email]);
36
37    if u8::from(password_strength.score()) < 3 {
38        let feedback = password_strength
39            .feedback()
40            .map(|f| format!("{}", f))
41            .unwrap_or_default();
42
43        return Err(OperationOutcomeError::fatal(
44            IssueType::Security(None),
45            feedback,
46        ));
47    }
48
49    TenantAuthAdmin::<CreateUser, _, _, _, String>::update(
50        repo,
51        &tenant,
52        UpdateUser {
53            id: user_id.to_string(),
54            password: Some(password.to_string()),
55            email: None,
56            role: None,
57            method: None,
58            provider_id: None,
59        },
60    )
61    .await?;
62
63    Ok(())
64}