Skip to main content

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::TenantModelAdmin,
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) =
16                    Regex::new(&format!("^{}$", redirect_pattern.replace("*", "(.+)")))
17            {
18                pattern.is_match(redirect_url)
19            } else {
20                false
21            }
22        })
23    });
24
25    k.is_some() && !redirect_url.is_empty()
26}
27
28pub async fn set_user_password<Repo: Repository>(
29    repo: &Repo,
30    tenant: &TenantId,
31    user_email: &str,
32    user_id: &str,
33    password: &str,
34) -> Result<(), OperationOutcomeError> {
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(),
45            feedback,
46        ));
47    }
48
49    TenantModelAdmin::<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}