diff --git a/src/commands/whoami/mod.rs b/src/commands/whoami/mod.rs index e50a8b1e9..761d712bb 100644 --- a/src/commands/whoami/mod.rs +++ b/src/commands/whoami/mod.rs @@ -3,9 +3,9 @@ use crate::terminal::{emoji, message}; pub fn whoami(user: &GlobalUser) -> Result<(), failure::Error> { // If using email + API key for auth, simply prints out email from config file. - let email: String = match &user.email { - Some(email) => email.to_string(), - None => failure::bail!( + let email: String = match user { + GlobalUser::GlobalKeyAuth { email, .. } => email.to_string(), + GlobalUser::TokenAuth { .. } => failure::bail!( "At the moment, Wrangler cannot get user information for users using API tokens" ), }; diff --git a/src/http.rs b/src/http.rs index dede38f02..876d257f2 100644 --- a/src/http.rs +++ b/src/http.rs @@ -48,24 +48,16 @@ pub fn auth_client(feature: Option<&str>, user: &GlobalUser) -> Client { } fn add_auth_headers<'a>(headers: &'a mut HeaderMap, user: &GlobalUser) { - match &user.api_token { - Some(token) => headers.insert( - "Authorization", - HeaderValue::from_str(&format!("Bearer {}", &token)).unwrap(), - ), - None => { - // fallback to email + API key auth option - match &user.email { - Some(email) => { - headers.insert("X-Auth-Email", HeaderValue::from_str(&email).unwrap()) - } - None => None, - }; - match &user.api_key { - Some(key) => headers.insert("X-Auth-Key", HeaderValue::from_str(&key).unwrap()), - None => None, - }; - None + match user { + GlobalUser::TokenAuth { api_token } => { + headers.insert( + "Authorization", + HeaderValue::from_str(&format!("Bearer {}", &api_token)).unwrap(), + ); } - }; + GlobalUser::GlobalKeyAuth { email, api_key } => { + headers.insert("X-Auth-Email", HeaderValue::from_str(&email).unwrap()); + headers.insert("X-Auth-Key", HeaderValue::from_str(&api_key).unwrap()); + } + } } diff --git a/src/main.rs b/src/main.rs index 9fabb47fe..6dcaea294 100644 --- a/src/main.rs +++ b/src/main.rs @@ -399,39 +399,28 @@ fn run() -> Result<(), failure::Error> { let config_path = Path::new("./wrangler.toml"); if let Some(matches) = matches.subcommand_matches("config") { - let api_key = matches.is_present("api-key"); + // If api-key flag isn't present, use the default auth option (API token) + let default = !matches.is_present("api-key"); - let mut user = GlobalUser { - email: None, - api_key: None, - api_token: None, - }; - - if !api_key { + let user: GlobalUser = if default { // Default: use API token. message::info("Looking to use a Global API Key and email instead? Run \"wrangler config --api-key\". (Not Recommended)"); println!("Enter API token: "); - let mut api_token_str: String = read!("{}\n"); - api_token_str.truncate(api_token_str.trim_end().len()); - if !api_token_str.is_empty() { - user.api_token = Some(api_token_str); - } + let mut api_token: String = read!("{}\n"); + api_token.truncate(api_token.trim_end().len()); + GlobalUser::TokenAuth { api_token } } else { message::warn("We don't recommend using your Global API Key! Please consider using an API Token instead. https://support.cloudflare.com/hc/en-us/articles/200167836-Managing-API-Tokens-and-Keys"); println!("Enter email: "); - let mut email_str: String = read!("{}\n"); - email_str.truncate(email_str.trim_end().len()); - if !email_str.is_empty() { - user.email = Some(email_str); - } + let mut email: String = read!("{}\n"); + email.truncate(email.trim_end().len()); println!("Enter global API key: "); - let mut api_key_str: String = read!("{}\n"); - api_key_str.truncate(api_key_str.trim_end().len()); - if !api_key_str.is_empty() { - user.api_key = Some(api_key_str); - } - } + let mut api_key: String = read!("{}\n"); + api_key.truncate(api_key.trim_end().len()); + + GlobalUser::GlobalKeyAuth { email, api_key } + }; commands::global_config(&user)?; } else if let Some(matches) = matches.subcommand_matches("generate") { diff --git a/src/settings/global_user.rs b/src/settings/global_user.rs index 008fc8eee..21943e842 100644 --- a/src/settings/global_user.rs +++ b/src/settings/global_user.rs @@ -8,11 +8,11 @@ use serde::{Deserialize, Serialize}; use crate::terminal::emoji; use config::{Config, Environment, File}; -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct GlobalUser { - pub email: Option, - pub api_key: Option, - pub api_token: Option, +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +#[serde(untagged)] +pub enum GlobalUser { + TokenAuth { api_token: String }, + GlobalKeyAuth { email: String, api_key: String }, } impl GlobalUser { @@ -23,16 +23,12 @@ impl GlobalUser { impl From for Credentials { fn from(user: GlobalUser) -> Credentials { - if let Some(token) = user.api_token { - return Credentials::UserAuthToken { token: token }; - } - - // fallback to email and global API key. - // If either of the fields below are None, just substitute in an empty string - // and these credentials will trigger the appropriate "missing field" response from the API. - Credentials::UserAuthKey { - key: user.api_key.unwrap_or("".to_string()), - email: user.email.unwrap_or("".to_string()), + match user { + GlobalUser::TokenAuth { api_token } => Credentials::UserAuthToken { token: api_token }, + GlobalUser::GlobalKeyAuth { email, api_key } => Credentials::UserAuthKey { + key: api_key, + email, + }, } } } @@ -89,3 +85,28 @@ pub fn get_global_config_dir() -> Result { info!("Using global config dir: {:?}", global_config_dir); Ok(global_config_dir) } + +#[cfg(test)] +mod tests { + use super::*; + use std::env; + + #[test] + fn it_can_prioritize_token_input() { + // Set all CF_API_TOKEN, CF_EMAIL, and CF_API_KEY. + // This test evaluates whether the GlobalUser returned is + // a GlobalUser::TokenAuth (expected behavior; token + // should be prioritized over email + global API key pair.) + env::set_var("CF_API_TOKEN", "foo"); + env::set_var("CF_EMAIL", "test@cloudflare.com"); + env::set_var("CF_API_KEY", "bar"); + + let user = get_global_config().unwrap(); + assert_eq!( + user, + GlobalUser::TokenAuth { + api_token: "foo".to_string() + } + ); + } +}