mirror of
https://github.com/railwayapp/cli
synced 2026-04-21 14:07:23 +00:00
feat: Handle 2FA enforcement error gracefully (#759)
When a workspace has 2FA enforcement enabled and the user hasn't set up 2FA, display a user-friendly error message with the workspace name and a direct link to the account security page.
This commit is contained in:
parent
2925ccc490
commit
a2e106b5bc
2 changed files with 46 additions and 4 deletions
|
|
@ -67,11 +67,26 @@ pub async fn post_graphql<Q: GraphQLQuery, U: reqwest::IntoUrl>(
|
|||
}
|
||||
let res: GraphQLResponse<Q::ResponseData> = response.json().await?;
|
||||
if let Some(errors) = res.errors {
|
||||
if errors[0].message.to_lowercase().contains("not authorized") {
|
||||
let error = &errors[0];
|
||||
if error.message.to_lowercase().contains("not authorized") {
|
||||
// Handle unauthorized errors in a custom way
|
||||
Err(RailwayError::Unauthorized)
|
||||
} else if error.message == "Two Factor Authentication Required" {
|
||||
// Extract workspace name from extensions if available
|
||||
let workspace_name = error
|
||||
.extensions
|
||||
.as_ref()
|
||||
.and_then(|ext| ext.get("workspaceName"))
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("this workspace")
|
||||
.to_string();
|
||||
let security_url = get_security_url();
|
||||
Err(RailwayError::TwoFactorEnforcementRequired(
|
||||
workspace_name,
|
||||
security_url,
|
||||
))
|
||||
} else {
|
||||
Err(RailwayError::GraphQLError(errors[0].message.clone()))
|
||||
Err(RailwayError::GraphQLError(error.message.clone()))
|
||||
}
|
||||
} else if let Some(data) = res.data {
|
||||
Ok(data)
|
||||
|
|
@ -80,6 +95,15 @@ pub async fn post_graphql<Q: GraphQLQuery, U: reqwest::IntoUrl>(
|
|||
}
|
||||
}
|
||||
|
||||
fn get_security_url() -> String {
|
||||
let host = match Configs::get_environment_id() {
|
||||
Environment::Production => "railway.com",
|
||||
Environment::Staging => "railway-staging.com",
|
||||
Environment::Dev => "railway-develop.com",
|
||||
};
|
||||
format!("https://{}/account/security", host)
|
||||
}
|
||||
|
||||
/// Like post_graphql, but removes null values from the variables object before sending.
|
||||
///
|
||||
/// This is needed because graphql-client 0.14.0 has a bug where skip_serializing_none
|
||||
|
|
@ -110,10 +134,25 @@ pub async fn post_graphql_skip_none<Q: GraphQLQuery, U: reqwest::IntoUrl>(
|
|||
}
|
||||
let res: GraphQLResponse<Q::ResponseData> = response.json().await?;
|
||||
if let Some(errors) = res.errors {
|
||||
if errors[0].message.to_lowercase().contains("not authorized") {
|
||||
let error = &errors[0];
|
||||
if error.message.to_lowercase().contains("not authorized") {
|
||||
Err(RailwayError::Unauthorized)
|
||||
} else if error.message == "Two Factor Authentication Required" {
|
||||
// Extract workspace name from extensions if available
|
||||
let workspace_name = error
|
||||
.extensions
|
||||
.as_ref()
|
||||
.and_then(|ext| ext.get("workspaceName"))
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("this workspace")
|
||||
.to_string();
|
||||
let security_url = get_security_url();
|
||||
Err(RailwayError::TwoFactorEnforcementRequired(
|
||||
workspace_name,
|
||||
security_url,
|
||||
))
|
||||
} else {
|
||||
Err(RailwayError::GraphQLError(errors[0].message.clone()))
|
||||
Err(RailwayError::GraphQLError(error.message.clone()))
|
||||
}
|
||||
} else if let Some(data) = res.data {
|
||||
Ok(data)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ pub enum RailwayError {
|
|||
#[error("2FA code is incorrect. Please try again.")]
|
||||
InvalidTwoFactorCode,
|
||||
|
||||
#[error("Two-factor authentication is required for workspace \"{0}\".\nEnable 2FA at: {1}")]
|
||||
TwoFactorEnforcementRequired(String, String),
|
||||
|
||||
#[error("Could not find a variable to connect to the service with. Looking for \"{0}\".")]
|
||||
ConnectionVariableNotFound(String),
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue