game_manager_lib\utils/
oauth.rs1use crate::constants::OAUTH_CALLBACK_TIMEOUT_SECS;
7use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
8use rand::{distr::Alphanumeric, Rng};
9use sha2::{Digest, Sha256};
10use std::{sync::mpsc, thread, time::Duration};
11use tiny_http::{Response, Server};
12use url::Url;
13
14pub struct PkceChallenge {
16 pub verifier: String,
17 pub challenge: String,
18}
19
20impl PkceChallenge {
21 pub fn generate() -> Self {
22 let verifier: String = rand::rng()
23 .sample_iter(&Alphanumeric)
24 .take(64)
25 .map(char::from)
26 .collect();
27
28 let hash = Sha256::digest(verifier.as_bytes());
29 let challenge = URL_SAFE_NO_PAD.encode(hash);
30
31 Self {
32 verifier,
33 challenge,
34 }
35 }
36}
37
38pub fn wait_for_auth_code(port: u16) -> Result<String, String> {
41 let address = format!("127.0.0.1:{}", port);
42 let server =
44 Server::http(&address).map_err(|e| format!("Porta ocupada ou erro de rede: {}", e))?;
45
46 let (tx, rx) = mpsc::channel::<String>();
47
48 thread::spawn(move || {
49 if let Ok(Some(request)) =
51 server.recv_timeout(Duration::from_secs(OAUTH_CALLBACK_TIMEOUT_SECS))
52 {
53 let url_string = format!("http://localhost{}", request.url());
55 if let Ok(url) = Url::parse(&url_string) {
56 if let Some((_, code)) = url.query_pairs().find(|(k, _)| k == "code") {
58 let _ = tx.send(code.to_string());
59
60 let html = "
62 <html>
63 <body style='background:#1a1a1a; color:#fff; font-family:sans-serif; text-align:center; padding-top:50px;'>
64 <h1 style='color:#4ade80'>Login Concluído!</h1>
65 <p>Você já pode fechar esta janela e voltar para o Playlite.</p>
66 <script>window.close();</script>
67 </body>
68 </html>
69 ";
70 let _ = request.respond(
71 Response::from_string(html).with_header(
72 tiny_http::Header::from_bytes(&b"Content-Type"[..], &b"text/html"[..])
73 .unwrap(),
74 ),
75 );
76 return;
77 }
78 }
79 let _ = request.respond(Response::from_string("Erro: Código não encontrado."));
81 }
82 });
83
84 rx.recv_timeout(Duration::from_secs(OAUTH_CALLBACK_TIMEOUT_SECS))
86 .map_err(|_| "Tempo limite de login excedido.".to_string())
87}