bamboo_agent/agent/llm/providers/copilot/auth/
device_code.rs1use reqwest::Client;
2use serde::Deserialize;
3
4const GITHUB_CLIENT_ID: &str = "Iv1.b507a08c87ecfe98";
5const DEVICE_CODE_URL: &str = "https://github.com/login/device/code";
6
7#[derive(Debug, Deserialize)]
9pub struct DeviceCodeResponse {
10 pub device_code: String,
11 pub user_code: String,
12 pub verification_uri: String,
13 #[serde(rename = "expires_in")]
14 pub expires_in: u64,
15 pub interval: u64,
16}
17
18pub async fn get_device_code(client: &Client) -> Result<DeviceCodeResponse, String> {
20 let params = [("client_id", GITHUB_CLIENT_ID), ("scope", "read:user")];
21
22 let response = client
23 .post(DEVICE_CODE_URL)
24 .header("Accept", "application/json")
25 .header("User-Agent", "BambooCopilot/1.0")
26 .form(¶ms)
27 .send()
28 .await
29 .map_err(|e| format!("Failed to request device code: {}", e))?;
30
31 let status = response.status();
32 if !status.is_success() {
33 let text = response.text().await.unwrap_or_default();
34 return Err(format!(
35 "Device code request failed: HTTP {} - {}",
36 status, text
37 ));
38 }
39
40 let device_code: DeviceCodeResponse = response
41 .json()
42 .await
43 .map_err(|e| format!("Failed to parse device code response: {}", e))?;
44
45 Ok(device_code)
46}
47
48pub fn present_device_code(device_code: &DeviceCodeResponse) {
50 println!("\n╔════════════════════════════════════════════════════════════╗");
51 println!("║ 🔐 GitHub Copilot Authorization Required ║");
52 println!("╚════════════════════════════════════════════════════════════╝");
53 println!();
54 println!(" 1. Open your browser and navigate to:");
55 println!(" {}", device_code.verification_uri);
56 println!();
57 println!(" 2. Enter the following code:");
58 println!();
59 println!(" ┌─────────────────────────┐");
60 println!(" │ {:^23} │", device_code.user_code);
61 println!(" └─────────────────────────┘");
62 println!();
63 println!(" 3. Click 'Authorize' and wait...");
64 println!();
65 println!(
66 " ⏳ Waiting for authorization (expires in {} seconds)...",
67 device_code.expires_in
68 );
69 println!();
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_github_client_id() {
78 assert_eq!(GITHUB_CLIENT_ID, "Iv1.b507a08c87ecfe98");
79 }
80}