From dc3917b05018cb32e2451d9eaed242036c5e7512 Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Tue, 28 Jan 2025 21:23:07 -0600 Subject: wip: auth --- src/auth/device_code.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/auth/device_code.rs (limited to 'src/auth/device_code.rs') diff --git a/src/auth/device_code.rs b/src/auth/device_code.rs new file mode 100644 index 0000000..087ff27 --- /dev/null +++ b/src/auth/device_code.rs @@ -0,0 +1,103 @@ +use std::ops::Add; +use std::time::Duration; +use futures::TryFutureExt; +use reqwest::Client; +use serde::{Deserialize, Serialize}; +use tokio::time::{Instant, MissedTickBehavior}; +use super::AuthError; +use crate::util::USER_AGENT; + +pub struct DeviceCodeAuthBuilder { + client_id: Option, + scope: Option, + url: Option +} + +#[derive(Serialize, Debug)] +struct DeviceCodeRequest { + client_id: String, + scope: String, + response_type: String +} + +#[derive(Deserialize, Debug)] +struct DeviceCodeResponse { + device_code: String, + user_code: String, + verification_uri: String, + expires_in: u64, + interval: u64, + message: Option +} + +impl DeviceCodeAuthBuilder { + pub fn new() -> DeviceCodeAuthBuilder { + DeviceCodeAuthBuilder { + client_id: None, + scope: None, + url: None + } + } + + pub fn client_id(mut self, client_id: &str) -> Self { + self.client_id = Some(client_id.to_owned()); + self + } + + pub fn scope(mut self, scope: &str) -> Self { + self.scope = Some(scope.to_owned()); + self + } + + pub fn url(mut self, url: &str) -> Self { + self.url = Some(url.to_owned()); + self + } + + pub async fn begin(self, client: Client) -> Result { + let scope = self.scope.expect("scope is not optional"); + let client_id = self.client_id.expect("client_id is not optional"); + let url = self.url.expect("url is not optional"); + + let device_code: DeviceCodeResponse = client.post(&url) + .header(reqwest::header::USER_AGENT, USER_AGENT) + .header(reqwest::header::ACCEPT, "application/json") + .form(&DeviceCodeRequest { + client_id, + scope, + response_type: "device_code".into() + }) + .send().await + .and_then(|r| r.error_for_status()) + .map_err(|e| AuthError::Request { what: "requesting device code auth", error: e })? + .json().await.map_err(|e| AuthError::Request { what: "receiving device code auth", error: e })?; + + let now = Instant::now(); + Ok(DeviceCodeAuth { + client, + start: now, + interval: Duration::from_secs(device_code.interval + 1), + expire_time: now.add(Duration::from_secs(device_code.expires_in)), + info: dbg!(device_code) + }) + } +} + +pub struct DeviceCodeAuth { + client: Client, + start: Instant, + interval: Duration, + expire_time: Instant, + info: DeviceCodeResponse +} + +impl DeviceCodeAuth { + async fn drive(&self) { + let mut i = tokio::time::interval_at(self.start, self.interval); + i.set_missed_tick_behavior(MissedTickBehavior::Skip); + + while self.expire_time.elapsed().is_zero() { + + } + } +} -- cgit v1.2.3-70-g09d2