diff --git a/libpaket/src/login/constants.rs b/libpaket/src/login/constants.rs index 3b4549e..af6bf31 100644 --- a/libpaket/src/login/constants.rs +++ b/libpaket/src/login/constants.rs @@ -1,16 +1,22 @@ -use super::utils::CodeVerfier; use super::dhl_claims::DHLClaimsOptional; +use super::utils::CodeVerfier; use serde::Serialize; pub fn client_id() -> &'static str { "42ec7de4-e357-4c5d-aa63-f6aae5ca4d8f" } -pub fn redirect_uri() -> &'static str { +pub fn redirect_uri_login() -> &'static str { "dhllogin://de.dhl.paket/login" } +pub fn redirect_uri_logout() -> &'static str { + "dhllogout://de.dhl.paket/logout" +} + pub mod token { + use crate::login::DHLIdToken; + use super::*; pub fn refresh_token_form(refresh_token: &str) -> Vec<(&str, &str)> { @@ -20,7 +26,7 @@ pub mod token { ("client_id", client_id()), ] } - + pub fn authorization_code_form( authorization_code: String, code_verfier: &CodeVerfier, @@ -28,21 +34,33 @@ pub mod token { vec![ ("code".to_string(), authorization_code), ("grant_type".to_string(), "authorization_code".to_string()), - ("redirect_uri".to_string(), redirect_uri().to_string()), + ("redirect_uri".to_string(), redirect_uri_login().to_string()), ("code_verifier".to_string(), code_verfier.code_verfier()), ("client_id".to_string(), client_id().to_string()), ] } - + + pub fn revoke_form( + token: String + ) -> Vec<(String, String)> { + vec![ + ("token".into(), token), + ("client_id".into(), client_id().into()), + ] + } + pub fn user_agent() -> &'static str { "Dalvik/2.1.0 (Linux; U; Android 11; OnePlus 6T Build/RQ3A.211001.001)" } - + pub fn endpoint() -> &'static str { "https://login.dhl.de/af5f9bb6-27ad-4af4-9445-008e7a5cddb8/login/token" } - - + + pub fn endpoint_revoke() -> &'static str { + "https://login.dhl.de/af5f9bb6-27ad-4af4-9445-008e7a5cddb8/login/token/revoke" + } + pub fn headers() -> reqwest::header::HeaderMap { let aaa = vec![ ("Content-Type", "application/x-www-form-urlencoded"), @@ -52,19 +70,43 @@ pub mod token { ("Connection", "Keep-Alive"), ("Accept-Encoding", "gzip"), ]; - + let mut map = reqwest::header::HeaderMap::new(); for bbb in aaa { map.append(bbb.0, bbb.1.parse().unwrap()); } - + map } } +pub mod logout { + use crate::{constants::web_user_agent, login::{ + constants::{client_id, redirect_uri_logout}, + DHLIdToken, + }}; + + pub fn form(id_token: &DHLIdToken) -> Vec<(String, String)> { + vec![ + ("id_token_hint".into(), id_token.to_string()), + ("state".into(), "esnGubTtYjK5ImleO84prQ".into()), + ("client_id".into(), client_id().into()), + ("redirect_uri".into(), redirect_uri_logout().into()), + ] + } + + pub fn endpoint() -> &'static str { + "https://login.dhl.de/af5f9bb6-27ad-4af4-9445-008e7a5cddb8/auth-ui/logout" + } + + pub fn user_agent() -> String { + web_user_agent() + } +} + pub mod webbrowser_authorize { - use crate::constants::web_user_agent; use super::*; + use crate::constants::web_user_agent; pub fn user_agent() -> String { web_user_agent() @@ -112,7 +154,7 @@ pub mod webbrowser_authorize { pub fn authorize_query(nonce: &String, code_verfier: &CodeVerfier) -> Vec<(String, String)> { vec![ - ("redirect_uri".to_string(), redirect_uri().to_string()), + ("redirect_uri".to_string(), redirect_uri_login().to_string()), ("client_id".to_string(), client_id().to_string()), ("response_type".to_string(), "code".to_string()), ("prompt".to_string(), "login".to_string()), diff --git a/libpaket/src/login/mod.rs b/libpaket/src/login/mod.rs index 1243c76..6833048 100644 --- a/libpaket/src/login/mod.rs +++ b/libpaket/src/login/mod.rs @@ -4,12 +4,14 @@ mod openid_response; pub mod openid_token; mod utils; +use constants::redirect_uri_logout; + pub use self::dhl_claims::{DHLCs, DHLIdToken}; pub use self::openid_response::{RefreshToken, TokenResponse}; pub use self::utils::{create_nonce, CodeVerfier}; use super::common::APIResult; -use crate::LibraryResult; +use crate::{LibraryError, LibraryResult}; pub struct OpenIdClient { client: reqwest::Client, @@ -67,4 +69,43 @@ impl OpenIdClient { Ok(parse_json_response_from_apiresult!(res, TokenResponse)) } + + // TODO: Unauthorized not correct error response + pub async fn logout(&self, dhli_token: &DHLIdToken) -> LibraryResult<()> { + let req = self + .client + .get(constants::logout::endpoint()) + .form(constants::logout::form(dhli_token).as_slice()) + .header("Host", "login.dhl.de") + .header("User-Agent", constants::logout::user_agent()) + .build() + .unwrap(); + + let res = self.client.execute(req).await; + let res = parse_response_internal!(res); + + if let Some(value) = res.headers().get("Location") { + if value.to_str().unwrap().starts_with(redirect_uri_logout()) { + Ok(()) + } else { + Err(crate::LibraryError::Unauthorized) + } + } else { + Err(crate::LibraryError::Unauthorized) + } + } + + // TODO: Unauthorized not correct error response + pub async fn revoke(&self, refresh_token: &RefreshToken) -> LibraryResult<()> { + let res = request_post!(self.client, + (constants::token::endpoint()), + .form(constants::token::revoke_form(refresh_token.to_string()).as_slice()) + ); + + if res.status() == 200 { + Ok(()) + } else { + Err(LibraryError::Unauthorized) + } + } }