1use crate::error::GorError;
7use crate::host::Host;
8use serde::Deserialize;
9
10#[derive(Debug, Deserialize)]
12pub struct UserResponse {
13 pub login: String,
15}
16
17pub fn verify_token(host: &Host, token: &str) -> Result<String, GorError> {
36 let client = reqwest::blocking::Client::new();
37 let url = host.api_url("/user");
38
39 tracing::info!("Verifying token with GET /user");
40 let response = client
41 .get(&url)
42 .header("Accept", "application/vnd.github+json")
43 .header("Authorization", format!("Bearer {token}"))
44 .header("User-Agent", concat!("gor/", env!("CARGO_PKG_VERSION")))
45 .send()
46 .map_err(GorError::Http)?;
47
48 let status = response.status();
49 if status == reqwest::StatusCode::UNAUTHORIZED {
50 return Err(GorError::Auth(
51 "token is invalid or expired (HTTP 401)".to_string(),
52 ));
53 }
54 if status == reqwest::StatusCode::FORBIDDEN {
55 return Err(GorError::Auth(
56 "token lacks required permissions (HTTP 403)".to_string(),
57 ));
58 }
59 if !status.is_success() {
60 let body = response.text().unwrap_or_default();
61 return Err(GorError::Auth(format!(
62 "token verification failed ({status}): {body}"
63 )));
64 }
65
66 let user: UserResponse = response
67 .json()
68 .map_err(|e| GorError::Auth(format!("failed to parse user response: {e}")))?;
69
70 Ok(user.login)
71}
72
73pub fn read_token_from_stdin() -> Result<String, GorError> {
89 use std::io::Read;
90 let mut buffer = String::new();
91 std::io::stdin()
92 .read_to_string(&mut buffer)
93 .map_err(GorError::Io)?;
94 Ok(buffer.trim().to_string())
95}