use super::{AuthenticationData, EveJwtClaims, EveJwtKey};
use crate::{
auth::{EveJwtKeys, EveSsoMetaData},
error::Error,
Esi,
EsiResult,
LOGIN_MEMBERS,
LOGIN_URLS,
SSO_META_DATA_URL,
};
use jsonwebtoken::{DecodingKey, TokenData, Validation};
use oauth2::{
AuthorizationCode,
CsrfToken,
EmptyExtraTokenFields,
RefreshToken,
Scope,
StandardTokenResponse,
};
use reqwest::{redirect::Policy, ClientBuilder};
impl Esi {
pub fn create_login_url(&self, scopes: Vec<Scope>) -> EsiResult<AuthenticationData> {
let (eve_oauth_url, csrf_token) = self
.token_client
.authorize_url(CsrfToken::new_random)
.add_scopes(scopes)
.url();
Ok(AuthenticationData {
login_url: eve_oauth_url.to_string(),
state: csrf_token.secret().to_string(),
})
}
pub async fn get_token(
&self,
code: String,
) -> EsiResult<StandardTokenResponse<EmptyExtraTokenFields, oauth2::basic::BasicTokenType>> {
let http_client = ClientBuilder::new().redirect(Policy::none()).build()?;
match self
.token_client
.exchange_code(AuthorizationCode::new(code.to_string()))
.request_async(&http_client)
.await
{
Ok(token) => Ok(token),
Err(err) => Err(Error::new(500, err.to_string())),
}
}
pub async fn refresh_token(
&self,
refresh_token: String,
) -> EsiResult<StandardTokenResponse<EmptyExtraTokenFields, oauth2::basic::BasicTokenType>> {
let http_client = ClientBuilder::new().redirect(Policy::none()).build()?;
match self
.token_client
.exchange_refresh_token(&RefreshToken::new(refresh_token))
.request_async(&http_client)
.await
{
Ok(token) => Ok(token),
Err(err) => Err(Error::new(500, err.to_string())),
}
}
pub async fn validate_token(&self, token: &str) -> EsiResult<TokenData<EveJwtClaims>> {
async fn get_eve_jwt_keys(esi: &Esi) -> EsiResult<EveJwtKeys> {
let res: EveSsoMetaData = esi
.client
.get(SSO_META_DATA_URL)
.send()
.await?
.json()
.await?;
let response = esi.client.get(res.jwks_uri).send().await?.json().await?;
Ok(response)
}
fn select_key(keys: Vec<EveJwtKey>) -> Option<EveJwtKey> {
for key in keys {
if let EveJwtKey::RS256 {
e: _,
kid: _,
kty: _,
n: _,
r#use: _,
} = &key
{
return Some(key);
}
}
None
}
let jwk_keys = get_eve_jwt_keys(self).await?;
let jwk_key = match select_key(jwk_keys.keys) {
Some(key) => key,
None => return Err(Error::new(500, "Failed to find RS256 key".to_string())),
};
let jwk_n: String;
let jwk_e: String;
if let EveJwtKey::RS256 {
e,
kid: _,
kty: _,
n,
r#use: _,
} = jwk_key
{
jwk_n = n;
jwk_e = e;
} else {
return Err(Error::new(500, "Failed to find RS256 key".to_string()));
}
let mut validation = Validation::new(jsonwebtoken::Algorithm::RS256);
validation.set_audience(&LOGIN_MEMBERS);
validation.set_issuer(&LOGIN_URLS);
let decoding_key = &DecodingKey::from_rsa_components(&jwk_n, &jwk_e)?;
let token = jsonwebtoken::decode::<EveJwtClaims>(&token, decoding_key, &validation)?;
Ok(token)
}
}