use crate::types::jwk::JsonWebKey;
use crate::{AccessToken, AuthorizationCode};
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
use base64::Engine;
use oauth2::helpers::deserialize_space_delimited_vec;
use rand::{thread_rng, Rng};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use url::Url;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;
pub(crate) mod jwk;
pub(crate) mod jwks;
pub(crate) mod localized;
#[cfg(test)]
mod tests;
pub trait ApplicationType: Debug + DeserializeOwned + Serialize + 'static {}
pub trait AuthDisplay: AsRef<str> + Debug + DeserializeOwned + Serialize + 'static {}
pub trait AuthPrompt: AsRef<str> + 'static {}
pub trait ClaimName: Debug + DeserializeOwned + Serialize + 'static {}
pub trait ClaimType: Debug + DeserializeOwned + Serialize + 'static {}
pub trait ClientAuthMethod: Debug + DeserializeOwned + Serialize + 'static {}
pub trait GrantType: Debug + DeserializeOwned + Serialize + 'static {}
#[derive(Clone, Debug, Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum SigningError {
#[error("Crypto error")]
CryptoError,
#[error("Unsupported signature algorithm: {0}")]
UnsupportedAlg(String),
#[error("Other error: {0}")]
Other(String),
}
pub trait ResponseMode: Debug + DeserializeOwned + Serialize + 'static {}
pub trait ResponseType: AsRef<str> + Debug + DeserializeOwned + Serialize + 'static {
fn to_oauth2(&self) -> oauth2::ResponseType;
}
pub trait SubjectIdentifierType: Debug + DeserializeOwned + Serialize + 'static {}
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AuthenticationContextClass(String)
];
impl AsRef<str> for AuthenticationContextClass {
fn as_ref(&self) -> &str {
self
}
}
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AuthenticationMethodReference(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AccessTokenHash(String)
impl {
pub fn from_token<K>(
access_token: &AccessToken,
alg: &K::SigningAlgorithm,
key: &K,
) -> Result<Self, SigningError>
where
K: JsonWebKey,
{
key.hash_bytes(access_token.secret().as_bytes(), alg)
.map(|hash| Self::new(BASE64_URL_SAFE_NO_PAD.encode(&hash[0..hash.len() / 2])))
.map_err(SigningError::UnsupportedAlg)
}
}
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AddressCountry(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AddressLocality(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AddressPostalCode(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AddressRegion(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
Audience(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
AuthorizationCodeHash(String)
impl {
pub fn from_code<K>(
code: &AuthorizationCode,
alg: &K::SigningAlgorithm,
key: &K,
) -> Result<Self, SigningError>
where
K: JsonWebKey,
{
key.hash_bytes(code.secret().as_bytes(), alg)
.map(|hash| Self::new(BASE64_URL_SAFE_NO_PAD.encode(&hash[0..hash.len() / 2])))
.map_err(SigningError::UnsupportedAlg)
}
}
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
ClientName(String)
];
new_url_type![
ClientConfigUrl
];
new_url_type![
ClientUrl
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
ClientContactEmail(String)
];
new_url_type![
EndSessionUrl
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserBirthday(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserEmail(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserFamilyName(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserGivenName(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserMiddleName(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserName(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserNickname(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserPhoneNumber(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserPictureUrl(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserProfileUrl(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserTimezone(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserWebsiteUrl(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
EndUserUsername(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
FormattedAddress(String)
];
new_url_type![
InitiateLoginUrl
];
new_url_type![
IssuerUrl
impl {
pub fn join(&self, suffix: &str) -> Result<Url, url::ParseError> {
if let Some('/') = self.1.chars().next_back() {
Url::parse(&(self.1.clone() + suffix))
} else {
Url::parse(&(self.1.clone() + "/" + suffix))
}
}
}
];
new_secret_type![
#[derive(Clone, Deserialize, Serialize)]
LoginHint(String)
];
new_secret_type![
#[derive(Clone, Deserialize, Serialize)]
LogoutHint(String)
];
new_url_type![
LogoUrl
];
new_secret_type![
#[derive(Clone, Deserialize, Serialize)]
Nonce(String)
impl {
pub fn new_random() -> Self {
Nonce::new_random_len(16)
}
pub fn new_random_len(num_bytes: u32) -> Self {
let random_bytes: Vec<u8> = (0..num_bytes).map(|_| thread_rng().gen::<u8>()).collect();
Nonce::new(BASE64_URL_SAFE_NO_PAD.encode(random_bytes))
}
}
];
new_url_type![
OpPolicyUrl
];
new_url_type![
OpTosUrl
];
new_url_type![
PolicyUrl
];
new_url_type![
PostLogoutRedirectUrl
];
new_secret_type![
#[derive(Clone, Deserialize, Serialize)]
RegistrationAccessToken(String)
];
new_url_type![
RegistrationUrl
];
new_url_type![
RequestUrl
];
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct ResponseTypes<RT: ResponseType>(
#[serde(
deserialize_with = "deserialize_space_delimited_vec",
serialize_with = "crate::helpers::serialize_space_delimited_vec"
)]
Vec<RT>,
);
impl<RT: ResponseType> ResponseTypes<RT> {
pub fn new(s: Vec<RT>) -> Self {
ResponseTypes::<RT>(s)
}
}
impl<RT: ResponseType> Deref for ResponseTypes<RT> {
type Target = Vec<RT>;
fn deref(&self) -> &Vec<RT> {
&self.0
}
}
new_url_type![
SectorIdentifierUrl
];
new_url_type![
ServiceDocUrl
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
StreetAddress(String)
];
new_type![
#[derive(Deserialize, Hash, Ord, PartialOrd, Serialize)]
SubjectIdentifier(String)
];
new_url_type![
ToSUrl
];