Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 47 additions & 23 deletions src/alerts/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,48 +198,36 @@ impl Target {
pub fn mask(self) -> Value {
match self.target {
TargetType::Slack(slack_web_hook) => {
let endpoint = slack_web_hook.endpoint.to_string();
let masked_endpoint = if endpoint.len() > 20 {
format!("{}********", &endpoint[..20])
} else {
"********".to_string()
};
json!({
"name":self.name,
"type":"slack",
"endpoint":masked_endpoint,
"endpoint":format!("{}://********", slack_web_hook.endpoint.scheme()),
"id":self.id
})
}
TargetType::Other(other_web_hook) => {
let endpoint = other_web_hook.endpoint.to_string();
let masked_endpoint = if endpoint.len() > 20 {
format!("{}********", &endpoint[..20])
} else {
"********".to_string()
};
let safe_headers: HashMap<String, String> = other_web_hook
.headers
.into_keys()
.map(|k| (k, "********".to_string()))
.collect();
json!({
"name":self.name,
"type":"webhook",
"endpoint":masked_endpoint,
"headers":other_web_hook.headers,
"endpoint": format!("{}://********", other_web_hook.endpoint.scheme()),
"headers":safe_headers,
"skipTlsCheck":other_web_hook.skip_tls_check,
"id":self.id
})
}
TargetType::AlertManager(alert_manager) => {
let endpoint = alert_manager.endpoint.to_string();
let masked_endpoint = if endpoint.len() > 20 {
format!("{}********", &endpoint[..20])
} else {
"********".to_string()
};
let endpoint = format!("{}://********", alert_manager.endpoint.scheme());
if let Some(auth) = alert_manager.auth {
let password = "********";
json!({
"name":self.name,
"type":"webhook",
"endpoint":masked_endpoint,
"endpoint":endpoint,
"username":auth.username,
"password":password,
"skipTlsCheck":alert_manager.skip_tls_check,
Expand All @@ -249,7 +237,7 @@ impl Target {
json!({
"name":self.name,
"type":"webhook",
"endpoint":masked_endpoint,
"endpoint":endpoint,
"username":Value::Null,
"password":Value::Null,
"skipTlsCheck":alert_manager.skip_tls_check,
Expand Down Expand Up @@ -652,3 +640,39 @@ pub struct Auth {
username: String,
password: String,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_masked_target_hides_secrets() {
let target = Target {
name: "test-target".into(),
id: Ulid::new(),
tenant: None,
target: TargetType::AlertManager(AlertManager {
endpoint: "https://internal.corp/api".parse().unwrap(),
auth: Some(Auth {
username: "admin".into(),
password: "SuperSecretPassword123".into(),
}),
skip_tls_check: false,
}),
};

let masked = target.mask();

let masked_str = serde_json::to_string(&masked).unwrap();

// These assertions MUST pass, or the build fails
assert!(
!masked_str.contains("SuperSecretPassword123"),
"Password leaked in masked response!"
);
assert!(
masked_str.contains("********"),
"Expected redaction marker not found!"
);
}
}
14 changes: 5 additions & 9 deletions src/handlers/http/targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ pub async fn post(
// add to the map
TARGETS.update(target.clone()).await?;

// Ok(web::Json(target.mask()))
Ok(web::Json(target))
Ok(web::Json(target.mask()))
}

// GET /targets
Expand All @@ -54,7 +53,7 @@ pub async fn list(req: HttpRequest) -> Result<impl Responder, AlertError> {
.list(&tenant_id)
.await?
.into_iter()
// .map(|t| t.mask())
.map(|t| t.mask())
.collect_vec();

Ok(web::Json(list))
Expand All @@ -66,8 +65,7 @@ pub async fn get(req: HttpRequest, target_id: Path<Ulid>) -> Result<impl Respond
let tenant_id = get_tenant_id_from_request(&req);
let target = TARGETS.get_target_by_id(&target_id, &tenant_id).await?;

// Ok(web::Json(target.mask()))
Ok(web::Json(target))
Ok(web::Json(target.mask()))
}

// PUT /targets/{target_id}
Expand Down Expand Up @@ -95,8 +93,7 @@ pub async fn update(
// add to the map
TARGETS.update(target.clone()).await?;

// Ok(web::Json(target.mask()))
Ok(web::Json(target))
Ok(web::Json(target.mask()))
}

// DELETE /targets/{target_id}
Expand All @@ -105,6 +102,5 @@ pub async fn delete(req: HttpRequest, target_id: Path<Ulid>) -> Result<impl Resp
let tenant_id = get_tenant_id_from_request(&req);
let target = TARGETS.delete(&target_id, &tenant_id).await?;

// Ok(web::Json(target.mask()))
Ok(web::Json(target))
Ok(web::Json(target.mask()))
}
Loading