use std::collections::HashMap; use serde::Deserialize; use crate::{ api, query::{self, use_query}, }; pub(crate) const DEVICE_LOGIN_FLOW_URL: &str = "https://github.com/login/device"; #[derive(Clone)] pub struct CreateDeviceCode; #[derive(Deserialize)] pub(crate) struct DeviceCodeResponse { pub device_code: String, pub user_code: String, pub vertification_uri: Option, pub expires_in: u16, pub interval: u16, } impl query::QueryFn for CreateDeviceCode { type Data = DeviceCodeResponse; type Error = api::Error; type Context = api::QueryContext; fn key(&self) -> &'static str { "auth.device_code" } async fn run(&self, c: &Self::Context) -> Result { let res = c .http .post(format!( "https://github.com/login/device/code?client_id={}", c.github.client_id )) .header("Accept", "application/json") .send() .await?; api::parse_response(res).await } } #[derive(Clone)] pub struct RequestAccessToken { pub device_code: String, } #[derive(Deserialize)] pub struct RequestAccessTokenResponse { pub access_token: String, pub token_type: String, pub scope: String, } impl query::QueryFn for RequestAccessToken { type Data = RequestAccessTokenResponse; type Error = api::Error; type Context = api::QueryContext; fn key(&self) -> &'static str { "auth.access_token" } async fn run(&self, c: &Self::Context) -> Result { let mut params = HashMap::new(); params.insert("client_id", c.github.client_id); params.insert("device_code", &self.device_code); params.insert("grant_type", "urn:ietf:params:oauth:grant-type:device_code"); let res = c .http .post(format!( "https://github.com/login/oauth/access_token?client_id={}&device_code={}", c.github.client_id, self.device_code )) .form(¶ms) .send() .await?; api::parse_response(res).await } }