malwaredb 0.3.2

Service for storing malicious, benign, or unknown files and related metadata and relationships.
// SPDX-License-Identifier: Apache-2.0

use malwaredb_server::State;

use std::process::ExitCode;

use anyhow::ensure;
use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime};
use clap::{Parser, ValueHint};

/// Grant a group access to a data source
#[derive(Clone, Debug, Parser, PartialEq)]
pub struct AddGroup {
    /// Group ID
    #[arg(short, long)]
    pub gid: u32,

    /// Source ID
    #[arg(short, long)]
    pub sid: u32,
}

impl AddGroup {
    pub async fn execute(&self, state: State) -> anyhow::Result<ExitCode> {
        let groups = state.db_type.list_groups().await?;
        ensure!(
            groups.iter().any(|g| g.id == self.gid),
            "Group ID {} is not valid.",
            self.gid
        );

        let sources = state.db_type.list_sources().await?;
        ensure!(
            sources.iter().any(|s| s.id == self.sid),
            "Source ID {} is not valid.",
            self.sid
        );

        state
            .db_type
            .add_group_to_source(self.gid, self.sid)
            .await?;
        Ok(ExitCode::SUCCESS)
    }
}

/// Create a new source
#[derive(Clone, Debug, Parser, PartialEq)]
pub struct Create {
    /// Name
    #[arg(long)]
    pub name: String,

    /// Description
    #[arg(long)]
    pub description: Option<String>,

    /// This source's URL
    #[arg(long, value_hint = ValueHint::Url)]
    pub url: Option<String>,

    /// First acquisition date in 'YYYY-MM-DD' format
    #[arg(long)]
    pub date: NaiveDate,

    /// Whether or not the data in this source can be shared externally
    #[arg(long)]
    pub releasable: bool,

    /// Are the files from this source known to be malware or otherwise malicious?
    #[arg(long)]
    pub malicious: Option<bool>,
}

impl Create {
    pub async fn execute(&self, state: State) -> anyhow::Result<ExitCode> {
        // The known time
        let time = NaiveTime::default();
        // Naive date time, with no time zone information
        let datetime = NaiveDateTime::new(self.date, time);

        let sid = state
            .db_type
            .create_source(
                &self.name,
                self.description.as_deref(),
                self.url.as_deref(),
                datetime.and_local_timezone(Local).unwrap(),
                self.releasable,
                self.malicious,
            )
            .await?;
        println!("Source {} created with ID {sid}", self.name);

        Ok(ExitCode::SUCCESS)
    }
}

/// List sources
#[derive(Clone, Debug, Parser, PartialEq)]
pub struct List {}

impl List {
    pub async fn execute(&self, state: State) -> anyhow::Result<ExitCode> {
        for source in state.db_type.list_sources().await? {
            println!("{source}");
        }
        Ok(ExitCode::SUCCESS)
    }
}