use super::PendingAuthorization;
use super::pkce::{Pkce, generate_state};
use crate::error::Result;
use crate::model::Domain;
use serde::Serialize;
use serde_with::skip_serializing_none;
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize)]
pub struct AuthorizationUrl {
response_type: &'static str,
pub client_id: String,
pub redirect_uri: String,
code_challenge_method: &'static str,
pub code_challenge: String,
pub scope: Option<String>,
pub username: Option<String>,
pub state: Option<String>,
}
impl AuthorizationUrl {
pub fn generated(client_id: impl Into<String>, redirect_uri: impl Into<String>) -> Self {
Self::new(client_id, redirect_uri, String::new())
}
pub fn new(
client_id: impl Into<String>,
redirect_uri: impl Into<String>,
code_challenge: impl Into<String>,
) -> Self {
Self {
response_type: "code",
client_id: client_id.into(),
redirect_uri: redirect_uri.into(),
code_challenge_method: "S256",
code_challenge: code_challenge.into(),
scope: None,
username: None,
state: None,
}
}
pub fn scope(mut self, scope: impl Into<String>) -> Self {
self.scope = Some(scope.into());
self
}
pub fn username(mut self, username: impl Into<String>) -> Self {
self.username = Some(username.into());
self
}
pub fn state(mut self, state: impl Into<String>) -> Self {
self.state = Some(state.into());
self
}
pub fn start(mut self) -> Result<(url::Url, PendingAuthorization)> {
let pkce = Pkce::generate();
let state = generate_state();
self.code_challenge = pkce.challenge().to_string();
self.state = Some(state.clone());
let url = self.to_url()?;
let pending =
PendingAuthorization::new(pkce.verifier(), state, self.client_id, self.redirect_uri);
Ok((url, pending))
}
pub fn to_url(&self) -> Result<url::Url> {
let base_url = format!("https://{}", Domain::Lichess.as_ref());
let mut url = url::Url::parse(&base_url).expect("invalid base url");
{
let mut query_pairs = url.query_pairs_mut();
let query_serializer = serde_urlencoded::Serializer::new(&mut query_pairs);
self.serialize(query_serializer)?;
}
url.set_path("/oauth");
Ok(url)
}
}