summaryrefslogtreecommitdiffstats
path: root/src/auth/device_code.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/auth/device_code.rs')
-rw-r--r--src/auth/device_code.rs103
1 files changed, 103 insertions, 0 deletions
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<String>,
+ scope: Option<String>,
+ url: Option<String>
+}
+
+#[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<String>
+}
+
+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<DeviceCodeAuth, AuthError> {
+ 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() {
+
+ }
+ }
+}