1use std::io;
2
3use failure::Error;
4use oauth2::basic::{BasicClient, BasicTokenResponse};
5use oauth2::reqwest::async_http_client;
6use oauth2::{
7 AsyncCodeTokenRequest, AuthorizationCode, CsrfToken, PkceCodeChallenge, PkceCodeVerifier, Scope,
8};
9
10static SCOPE: &str = "https://www.googleapis.com/auth/skyjam";
11
12pub fn stdio_login(url: String) -> String {
16 println!("Open this URL in your browser:\n{}\n", url);
17
18 let mut code = String::new();
19 io::stdin().read_line(&mut code).unwrap();
20
21 code
22}
23
24pub(crate) fn get_oauth_url(client: &BasicClient) -> (String, PkceCodeVerifier) {
26 let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();
27
28 let (authorize_url, _) = client
29 .authorize_url(CsrfToken::new_random)
30 .add_scope(Scope::new(SCOPE.to_string()))
31 .set_pkce_challenge(pkce_code_challenge)
32 .url();
33
34 (authorize_url.to_string(), pkce_code_verifier)
35}
36
37pub(crate) async fn request_token(
38 client: &BasicClient,
39 code: String,
40 verifier: PkceCodeVerifier,
41) -> Result<BasicTokenResponse, Error> {
42 let code = AuthorizationCode::new(code);
43
44 let token = client
45 .exchange_code(code)
46 .set_pkce_verifier(verifier)
47 .request_async(async_http_client)
48 .await?;
49
50 Ok(token)
51}
52
53pub(crate) async fn perform_oauth<H>(
54 client: &BasicClient,
55 handler: H,
56) -> Result<BasicTokenResponse, Error>
57where
58 H: Fn(String) -> String,
59{
60 let (authorize_url, pkce_code_verifier) = get_oauth_url(client);
61
62 let code = handler(authorize_url);
63
64 request_token(client, code, pkce_code_verifier).await
65}