-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathauth.rs
More file actions
140 lines (119 loc) · 4.5 KB
/
auth.rs
File metadata and controls
140 lines (119 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::path::PathBuf;
use crate::service; // Assuming service::create_client is needed
// Configuration structure
#[derive(Serialize, Deserialize, Debug, Default)]
struct Config {
cli_id: Option<String>,
}
// Helper function to get the config file path
fn get_config_path() -> Result<PathBuf> {
dirs::home_dir()
.map(|mut path| {
path.push(".popcorn.yaml");
path
})
.ok_or_else(|| anyhow!("Could not find home directory"))
}
// Helper function to load config
fn load_config() -> Result<Config> {
let path = get_config_path()?;
if !path.exists() {
return Ok(Config::default());
}
let file = File::open(path)?;
serde_yaml::from_reader(file).map_err(|e| anyhow!("Failed to parse config file: {}", e))
}
// Helper function to save config
fn save_config(config: &Config) -> Result<()> {
let path = get_config_path()?;
let file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true) // Overwrite existing file
.open(path)?;
serde_yaml::to_writer(file, config).map_err(|e| anyhow!("Failed to write config file: {}", e))
}
// Structure for the API response
#[derive(Deserialize)]
struct AuthInitResponse {
state: String, // This is the cli_id
}
// Function to handle the login logic
pub async fn run_auth(reset: bool, auth_provider: &str) -> Result<()> {
println!("Attempting authentication via {}...", auth_provider);
let popcorn_api_url = std::env::var("POPCORN_API_URL")
.map_err(|_| anyhow!("POPCORN_API_URL environment variable not set"))?;
let client = service::create_client(None)?;
let init_url = format!("{}/auth/init?provider={}", popcorn_api_url, auth_provider);
println!("Requesting CLI ID from {}", init_url);
let init_resp = client.get(&init_url).send().await?;
let status = init_resp.status();
if !status.is_success() {
let error_text = init_resp.text().await?;
return Err(anyhow!(
"Failed to initialize auth ({}): {}",
status,
error_text
));
}
let auth_init_data: AuthInitResponse = init_resp.json().await?;
let cli_id = auth_init_data.state;
println!("Received CLI ID: {}", cli_id);
let state_json = serde_json::json!({
"cli_id": cli_id,
"is_reset": reset
})
.to_string();
let state_b64 = base64_url::encode(&state_json);
let auth_url = match auth_provider {
"discord" => {
let base_auth_url = "https://discord.com/oauth2/authorize?client_id=1361364685491802243&response_type=code&redirect_uri=https%3A%2F%2Fdiscord-cluster-manager-1f6c4782e60a.herokuapp.com%2Fauth%2Fcli%2Fdiscord&scope=identify";
format!("{}&state={}", base_auth_url, state_b64)
}
"github" => {
let client_id = "Ov23lieFd2onYk4OnKIR";
let redirect_uri =
"https://discord-cluster-manager-1f6c4782e60a.herokuapp.com/auth/cli/github";
let encoded_redirect_uri = urlencoding::encode(redirect_uri);
format!(
"https://github.com/login/oauth/authorize?client_id={}&state={}&redirect_uri={}",
client_id, state_b64, encoded_redirect_uri
)
}
_ => {
return Err(anyhow!(
"Unsupported authentication provider: {}",
auth_provider
))
}
};
println!(
"\n>>> Please open the following URL in your browser to log in via {}:",
auth_provider
);
println!("{}", auth_url);
println!("\nWaiting for you to complete the authentication in your browser...");
println!(
"After successful authentication with {}, the CLI ID will be saved.",
auth_provider
);
if webbrowser::open(&auth_url).is_err() {
println!(
"Could not automatically open the browser. Please copy the URL above and paste it manually."
);
}
// Save the cli_id to config file optimistically
let mut config = load_config().unwrap_or_default();
config.cli_id = Some(cli_id.clone());
save_config(&config)?;
println!(
"\nSuccessfully initiated authentication. Your CLI ID ({}) has been saved to {}. To use the CLI on different machines, you can copy the config file.",
cli_id,
get_config_path()?.display()
);
println!("You can now use other commands that require authentication.");
Ok(())
}