use serde::{Deserialize, Serialize};
use crate::client::Client;
use crate::error::Result;
#[derive(Debug, Clone, Serialize)]
pub struct SecurityScanUrlRequest {
pub url: String,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct SecurityScanHtmlRequest {
pub html: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible_text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct SecurityReportRequest {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SecurityScanResponse {
pub assessment: SecurityAssessment,
#[serde(default)]
pub request_id: String,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct SecurityAssessment {
#[serde(default)]
pub url: String,
#[serde(default)]
pub threat_level: String,
#[serde(default)]
pub threat_score: f64,
#[serde(default)]
pub findings: Vec<SecurityFinding>,
#[serde(default)]
pub hidden_text_length: i32,
#[serde(default)]
pub visible_text_length: i32,
#[serde(default)]
pub hidden_ratio: f64,
#[serde(default)]
pub summary: String,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct SecurityFinding {
#[serde(default)]
pub category: String,
#[serde(default)]
pub pattern: String,
#[serde(default)]
pub content: String,
#[serde(default)]
pub location: String,
#[serde(default)]
pub threat: String,
#[serde(default)]
pub confidence: f64,
#[serde(default)]
pub description: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SecurityCheckResponse {
#[serde(default)]
pub url: String,
#[serde(default)]
pub blocked: bool,
#[serde(default)]
pub threat_level: Option<String>,
#[serde(default)]
pub threat_score: Option<f64>,
#[serde(default)]
pub categories: Option<Vec<String>>,
#[serde(default)]
pub first_seen: Option<String>,
#[serde(default)]
pub last_seen: Option<String>,
#[serde(default)]
pub report_count: Option<i32>,
#[serde(default)]
pub status: Option<String>,
#[serde(default)]
pub message: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SecurityBlocklistResponse {
#[serde(default)]
pub entries: Vec<SecurityBlocklistEntry>,
#[serde(default)]
pub count: i32,
#[serde(default)]
pub status: String,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct SecurityBlocklistEntry {
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub url: String,
#[serde(default)]
pub status: String,
#[serde(default)]
pub threat_level: String,
#[serde(default)]
pub threat_score: f64,
#[serde(default)]
pub categories: Vec<String>,
#[serde(default)]
pub findings_count: i32,
#[serde(default)]
pub hidden_ratio: f64,
#[serde(default)]
pub first_seen: Option<String>,
#[serde(default)]
pub summary: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SecurityReportResponse {
#[serde(default)]
pub url: String,
#[serde(default)]
pub status: String,
#[serde(default)]
pub message: String,
#[serde(default)]
pub threat_level: Option<String>,
}
impl Client {
pub async fn security_scan_url(&self, url: &str) -> Result<SecurityScanResponse> {
let req = SecurityScanUrlRequest { url: url.to_string() };
let (resp, _) = self.post_json("/qai/v1/security/scan-url", &req).await?;
Ok(resp)
}
pub async fn security_scan_html(&self, req: &SecurityScanHtmlRequest) -> Result<SecurityScanResponse> {
let (resp, _) = self.post_json("/qai/v1/security/scan-html", req).await?;
Ok(resp)
}
pub async fn security_check(&self, url: &str) -> Result<SecurityCheckResponse> {
let encoded = urlencoding::encode(url);
let (resp, _) = self.get_json(&format!("/qai/v1/security/check?url={}", encoded)).await?;
Ok(resp)
}
pub async fn security_blocklist(&self, status: Option<&str>) -> Result<SecurityBlocklistResponse> {
let path = match status {
Some(s) => format!("/qai/v1/security/blocklist?status={}", s),
None => "/qai/v1/security/blocklist".into(),
};
let (resp, _) = self.get_json(&path).await?;
Ok(resp)
}
pub async fn security_report(&self, req: &SecurityReportRequest) -> Result<SecurityReportResponse> {
let (resp, _) = self.post_json("/qai/v1/security/report", req).await?;
Ok(resp)
}
}