1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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() {
}
}
}
|