mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Port the login server to rust. --------- Co-authored-by: pakrym-oai <pakrym@openai.com>
183 lines
5.4 KiB
Rust
183 lines
5.4 KiB
Rust
use codex_common::CliConfigOverrides;
|
|
use codex_core::config::Config;
|
|
use codex_core::config::ConfigOverrides;
|
|
use codex_login::AuthMode;
|
|
use codex_login::CLIENT_ID;
|
|
use codex_login::CodexAuth;
|
|
use codex_login::LoginServerInfo;
|
|
use codex_login::OPENAI_API_KEY_ENV_VAR;
|
|
use codex_login::ServerOptions;
|
|
use codex_login::login_with_api_key;
|
|
use codex_login::logout;
|
|
use codex_login::run_server_blocking_with_notify;
|
|
use std::env;
|
|
use std::path::Path;
|
|
use std::sync::mpsc;
|
|
|
|
pub async fn login_with_chatgpt(codex_home: &Path) -> std::io::Result<()> {
|
|
let (tx, rx) = mpsc::channel::<LoginServerInfo>();
|
|
let client_id = CLIENT_ID;
|
|
let codex_home = codex_home.to_path_buf();
|
|
tokio::spawn(async move {
|
|
match rx.recv() {
|
|
Ok(LoginServerInfo {
|
|
auth_url,
|
|
actual_port,
|
|
}) => {
|
|
eprintln!(
|
|
"Starting local login server on http://localhost:{actual_port}.\nIf your browser did not open, navigate to this URL to authenticate:\n\n{auth_url}",
|
|
);
|
|
}
|
|
_ => {
|
|
tracing::error!("Failed to receive login server info");
|
|
}
|
|
}
|
|
});
|
|
|
|
tokio::task::spawn_blocking(move || {
|
|
let opts = ServerOptions::new(&codex_home, client_id);
|
|
run_server_blocking_with_notify(opts, Some(tx), None)
|
|
})
|
|
.await
|
|
.map_err(std::io::Error::other)??;
|
|
|
|
eprintln!("Successfully logged in");
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) -> ! {
|
|
let config = load_config_or_exit(cli_config_overrides);
|
|
|
|
match login_with_chatgpt(&config.codex_home).await {
|
|
Ok(_) => {
|
|
eprintln!("Successfully logged in");
|
|
std::process::exit(0);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("Error logging in: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn run_login_with_api_key(
|
|
cli_config_overrides: CliConfigOverrides,
|
|
api_key: String,
|
|
) -> ! {
|
|
let config = load_config_or_exit(cli_config_overrides);
|
|
|
|
match login_with_api_key(&config.codex_home, &api_key) {
|
|
Ok(_) => {
|
|
eprintln!("Successfully logged in");
|
|
std::process::exit(0);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("Error logging in: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! {
|
|
let config = load_config_or_exit(cli_config_overrides);
|
|
|
|
match CodexAuth::from_codex_home(&config.codex_home) {
|
|
Ok(Some(auth)) => match auth.mode {
|
|
AuthMode::ApiKey => match auth.get_token().await {
|
|
Ok(api_key) => {
|
|
eprintln!("Logged in using an API key - {}", safe_format_key(&api_key));
|
|
|
|
if let Ok(env_api_key) = env::var(OPENAI_API_KEY_ENV_VAR) {
|
|
if env_api_key == api_key {
|
|
eprintln!(
|
|
" API loaded from OPENAI_API_KEY environment variable or .env file"
|
|
);
|
|
}
|
|
}
|
|
std::process::exit(0);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("Unexpected error retrieving API key: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
},
|
|
AuthMode::ChatGPT => {
|
|
eprintln!("Logged in using ChatGPT");
|
|
std::process::exit(0);
|
|
}
|
|
},
|
|
Ok(None) => {
|
|
eprintln!("Not logged in");
|
|
std::process::exit(1);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("Error checking login status: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn run_logout(cli_config_overrides: CliConfigOverrides) -> ! {
|
|
let config = load_config_or_exit(cli_config_overrides);
|
|
|
|
match logout(&config.codex_home) {
|
|
Ok(true) => {
|
|
eprintln!("Successfully logged out");
|
|
std::process::exit(0);
|
|
}
|
|
Ok(false) => {
|
|
eprintln!("Not logged in");
|
|
std::process::exit(0);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("Error logging out: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn load_config_or_exit(cli_config_overrides: CliConfigOverrides) -> Config {
|
|
let cli_overrides = match cli_config_overrides.parse_overrides() {
|
|
Ok(v) => v,
|
|
Err(e) => {
|
|
eprintln!("Error parsing -c overrides: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
};
|
|
|
|
let config_overrides = ConfigOverrides::default();
|
|
match Config::load_with_cli_overrides(cli_overrides, config_overrides) {
|
|
Ok(config) => config,
|
|
Err(e) => {
|
|
eprintln!("Error loading configuration: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn safe_format_key(key: &str) -> String {
|
|
if key.len() <= 13 {
|
|
return "***".to_string();
|
|
}
|
|
let prefix = &key[..8];
|
|
let suffix = &key[key.len() - 5..];
|
|
format!("{prefix}***{suffix}")
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::safe_format_key;
|
|
|
|
#[test]
|
|
fn formats_long_key() {
|
|
let key = "sk-proj-1234567890ABCDE";
|
|
assert_eq!(safe_format_key(key), "sk-proj-***ABCDE");
|
|
}
|
|
|
|
#[test]
|
|
fn short_key_returns_stars() {
|
|
let key = "sk-proj-12345";
|
|
assert_eq!(safe_format_key(key), "***");
|
|
}
|
|
}
|