use crate::common::syntax::CLIENT_ID_SYNTAX;
use async_trait::async_trait;
#[derive(Debug, Clone)]
pub struct Client {
pub client_id: String,
pub redirect_uris: Vec<String>,
pub confidential: bool,
}
impl Client {
pub fn is_valid(&self) -> bool {
if self.client_id.trim().is_empty() {
return false;
}
if !CLIENT_ID_SYNTAX.is_match(&self.client_id) {
return false;
}
if self.redirect_uris.is_empty() {
return false;
}
true
}
pub fn has_redirect_uri(&self, redirect_uri: &str) -> bool {
self.redirect_uris.contains(&redirect_uri.to_string())
}
}
#[async_trait]
pub trait ClientProvider<Extras = ()>: 'static + Send + Sync {
type Error;
async fn get_client_by_id(&self, client_id: &str) -> Result<Option<Client>, Self::Error>;
async fn allow_client_scopes(
&self,
client: &Client,
requested_scopes: Vec<String>,
) -> Result<Vec<String>, Self::Error>;
async fn verify_client_secret(
&self,
client: &Client,
client_secret: &str,
) -> Result<bool, Self::Error>;
}
#[cfg(test)]
mod test {
use crate::common::model::Client;
#[test]
fn test_client_is_valid() {
let client = Client {
client_id: "client_id".to_string(),
redirect_uris: vec!["http://localhost".to_string()],
confidential: false,
};
assert!(client.is_valid());
}
#[test]
fn test_client_with_multiple_redirect_uris_is_valid() {
let client = Client {
client_id: "client_id".to_string(),
redirect_uris: vec![
"http://localhost".to_string(),
"http://localhost:8080".to_string(),
],
confidential: false,
};
assert!(client.is_valid());
}
#[test]
fn test_client_without_client_id_is_invalid() {
let client = Client {
client_id: "".to_string(),
redirect_uris: vec!["http://localhost".to_string()],
confidential: false,
};
assert!(!client.is_valid());
}
#[test]
fn test_client_with_blank_client_id_is_invalid() {
let client = Client {
client_id: " \t\n".to_string(),
redirect_uris: vec!["http://localhost".to_string()],
confidential: false,
};
assert!(!client.is_valid());
}
#[test]
fn test_client_without_redirect_uris_is_invalid() {
let client = Client {
client_id: "client_id".to_string(),
redirect_uris: vec![],
confidential: false,
};
assert!(!client.is_valid());
}
}