Skip to main content

autopulse_service/settings/targets/
autopulse.rs

1use super::{Request, RequestBuilderPerform};
2use crate::settings::path_filter::PathFilter;
3use crate::settings::rewrite::Rewrite;
4use crate::settings::{auth::Auth, targets::TargetProcess};
5use autopulse_database::models::ScanEvent;
6use autopulse_utils::get_url;
7use reqwest::header;
8use serde::{Deserialize, Serialize};
9use tracing::{debug, error};
10
11#[derive(Serialize, Clone, Deserialize)]
12pub struct Autopulse {
13    /// URL to the autopulse instance
14    pub url: String,
15    /// Authentication credentials
16    pub auth: Auth,
17    /// Trigger to hit (must be type: manual) (default: manual)
18    pub trigger: Option<String>,
19    /// Rewrite path for the file
20    pub rewrite: Option<Rewrite>,
21    /// Path filter matched against the target-rewritten path.
22    #[serde(default)]
23    pub filter: PathFilter,
24    /// HTTP request options
25    #[serde(default)]
26    pub request: Request,
27}
28
29impl Autopulse {
30    fn get_client(&self) -> anyhow::Result<reqwest::Client> {
31        let mut headers = header::HeaderMap::new();
32
33        if self.auth.enabled {
34            headers.insert("Authorization", self.auth.to_auth_encoded().parse()?);
35        }
36
37        self.request
38            .client_builder(headers)
39            .build()
40            .map_err(Into::into)
41    }
42
43    async fn scan(&self, ev: &ScanEvent) -> anyhow::Result<()> {
44        let client = self.get_client()?;
45        let trigger = self.trigger.as_deref().unwrap_or("manual");
46        let mut url = get_url(&self.url)?.join(&format!("triggers/{trigger}"))?;
47
48        url.query_pairs_mut()
49            .append_pair("path", &ev.get_path(&self.rewrite));
50
51        if let Some(hash) = &ev.file_hash {
52            url.query_pairs_mut().append_pair("hash", hash);
53        }
54
55        client.get(url).perform().await.map(|_| ())
56    }
57}
58
59impl TargetProcess for Autopulse {
60    async fn process(&self, evs: &[&ScanEvent]) -> anyhow::Result<Vec<String>> {
61        let mut succeeded = Vec::new();
62
63        for ev in evs {
64            match self.scan(ev).await {
65                Ok(()) => {
66                    succeeded.push(ev.id.clone());
67                    debug!("file scanned: {}", ev.get_path(&self.rewrite));
68                }
69                Err(e) => {
70                    error!("error scanning file: {}", e);
71                }
72            }
73        }
74
75        Ok(succeeded)
76    }
77}