ones-oidc 0.3.5

ONES OpenID Connect client for Rust
Documentation
use log::debug;
use serde::{Deserialize, Serialize};
use super::errors::WellKnownApplicationsError;
use super::http_client::default_client;
use super::CoreProviderMetadata;

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub enum ApplicationType {
    Server,
    ServerMatrix,
    ServerDiscourse,
    ServerOauth2,
    ServerBlockchain,
    Client,
    ClientOidc,
    ClientKyc,
}

fn hostname_to_url(hostname: &str, issuer_url: &str) -> String {
    if issuer_url.starts_with("https://") {
        format!("https://{}", hostname)
    } else {
        format!("http://{}", hostname)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ApplicationsWellKnown {
    pub id: String,
    pub r#type: ApplicationType,
    pub name: String,
    pub description: Option<String>,
    pub ipv4: Option<String>,
    pub hostname: String,
    #[serde(alias = "clientIdentifier")]
    pub client_identifier: Option<String>,
    #[serde(alias = "chainId")]
    pub chain_id: Option<String>,
    #[serde(alias = "contractCheckBalance")]
    pub contract_check_balance: Option<String>,
    #[serde(alias = "isHidden")]
    pub is_hidden: Option<bool>,
}

/**
 * Get the url for the application
 */
impl ApplicationsWellKnown {
    pub fn url(&self, issuer_url: &str) -> String {
        hostname_to_url(&self.hostname, issuer_url)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ApplicationsWellKnownResponse {
    applications: Vec<ApplicationsWellKnown>,
    total: u64,
}

/// Get the applications well-known
pub async fn get_applications_well_known(
    provider_metadata: &CoreProviderMetadata,
    device_access_token: &str,
) -> Result<ApplicationsWellKnownResponse, WellKnownApplicationsError> {
    let client = default_client()?;
    let url = provider_metadata
        .issuer()
        .trim_end_matches("/oidc")
        .to_string()
        + "/applications/.well-known?limit=1000";
    let response = client
        .get(url)
        .header("Authorization", format!("Bearer {}", device_access_token))
        .send()
        .await?
        .error_for_status()?
        .json::<ApplicationsWellKnownResponse>()
        .await?;

    Ok(response)
}

/// Get the application well-known by client identifier
pub async fn get_well_known_application_by_client_identifier(
    provider_metadata: &CoreProviderMetadata,
    device_access_token: &str,
    client_identifier: &str,
) -> Result<ApplicationsWellKnown, WellKnownApplicationsError> {
    let response = get_applications_well_known(provider_metadata, device_access_token).await?;
    let filtered_applications: Vec<ApplicationsWellKnown> = response
        .applications
        .clone()
        .into_iter()
        .filter(|app| {
            app.client_identifier
                .as_ref()
                .map_or(false, |id| id == client_identifier)
        })
        .collect();
    if filtered_applications.is_empty() {
        debug!(
            "No application found with client_identifier '{}'. Available applications: {:#?}",
            client_identifier, response.applications
        );
        return Err(WellKnownApplicationsError::NotFound);
    }

    Ok(filtered_applications[0].clone())
}