use crate::models::{Secret, SecretType};
use crate::validators::Validator;
use anyhow::Result;
use reqwest::Client;
pub struct SlackValidator {
client: Client,
}
impl SlackValidator {
pub fn new() -> Self {
Self {
client: Client::builder()
.timeout(std::time::Duration::from_secs(5))
.build()
.unwrap(),
}
}
async fn validate_token(&self, token: &str) -> Result<bool> {
let response = self
.client
.post("https://slack.com/api/auth.test")
.header("Authorization", format!("Bearer {}", token))
.header("Content-Type", "application/x-www-form-urlencoded")
.send()
.await?;
if response.status().is_success() {
let body: serde_json::Value = response.json().await?;
Ok(body.get("ok").and_then(|v| v.as_bool()).unwrap_or(false))
} else {
Ok(false)
}
}
async fn validate_webhook(&self, url: &str) -> Result<bool> {
let response = self.client.post(url).json(&serde_json::json!({})).send().await?;
let status = response.status().as_u16();
Ok(status == 400 || status == 200)
}
}
impl Default for SlackValidator {
fn default() -> Self {
Self::new()
}
}
#[async_trait::async_trait]
impl Validator for SlackValidator {
async fn validate(&self, secret: &Secret) -> Result<bool> {
match secret.secret_type {
SecretType::SlackToken => self.validate_token(&secret.value).await,
SecretType::SlackWebhook => self.validate_webhook(&secret.value).await,
_ => Ok(false),
}
}
fn supports(&self, secret_type: &SecretType) -> bool {
matches!(
secret_type,
SecretType::SlackToken | SecretType::SlackWebhook
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_supports() {
let validator = SlackValidator::new();
assert!(validator.supports(&SecretType::SlackToken));
assert!(validator.supports(&SecretType::SlackWebhook));
assert!(!validator.supports(&SecretType::AwsAccessKey));
}
}