pub mod digest;
use chrono::serde::ts_seconds_option;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
pub const MDB_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const USER_LOGIN_URL: &str = "/v1/users/getkey";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GetAPIKeyRequest {
pub user: String,
pub password: String,
}
pub const USER_LOGOUT_URL: &str = "/v1/users/clearkey";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GetAPIKeyResponse {
pub key: Option<String>,
pub message: Option<String>,
}
pub const USER_INFO_URL: &str = "/v1/users/info";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GetUserInfoResponse {
pub id: i32,
pub username: String,
pub groups: Vec<String>,
pub sources: Vec<String>,
pub is_admin: bool,
}
pub const SERVER_INFO: &str = "/v1/server/info";
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct ServerInfo {
pub os_name: String,
pub os_version: String,
pub memory_used: String,
pub mdb_version: String,
pub db_version: String,
pub db_size: String,
pub num_samples: u64,
pub num_users: u32,
pub uptime: String,
}
pub const SUPPORTED_FILE_TYPES: &str = "/v1/server/types";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SupportedFileType {
pub name: String,
pub magic: Vec<String>,
pub is_executable: bool,
pub description: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SupportedFileTypes {
pub types: Vec<SupportedFileType>,
pub message: Option<String>,
}
pub const GET_SOURCES: &str = "/v1/sources/list";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmptyAuthenticatingPost {
pub key: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SourceInfo {
pub id: u64,
pub name: String,
pub description: Option<String>,
pub url: Option<String>,
#[serde(with = "ts_seconds_option")]
pub first_acquisition: Option<DateTime<Utc>>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Sources {
pub sources: Vec<SourceInfo>,
pub message: Option<String>,
}
pub const UPLOAD_SAMPLE: &str = "/v1/samples/upload";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NewSample {
pub file_name: String,
pub key: String,
pub source_id: u32,
pub file_contents_b64: String,
pub sha256: String,
}
pub const DOWNLOAD_SAMPLE: &str = "/v1/samples/download";
pub const DOWNLOAD_SAMPLE_CART: &str = "/v1/samples/download/cart";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DownloadSampleRequest {
pub key: String,
pub hash: digest::HashType,
}
pub const SAMPLE_REPORT: &str = "/v1/samples/report";
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct Report {
pub md5: String,
pub sha1: String,
pub sha256: String,
pub sha384: String,
pub sha512: String,
pub lzjd: Option<String>,
pub tlsh: Option<String>,
pub ssdeep: Option<String>,
pub sdhash: Option<String>,
pub humanhash: Option<String>,
pub filecommand: Option<String>,
pub bytes: u32,
pub size: String,
pub entropy: f32,
}
impl Display for Report {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Size: {} bytes, or {}", self.bytes, self.size)?;
writeln!(f, "Entropy: {}", self.entropy)?;
if let Some(filecmd) = &self.filecommand {
writeln!(f, "File command: {filecmd}")?;
}
writeln!(f, "MD5: {}", self.md5)?;
writeln!(f, "SHA-1: {}", self.sha1)?;
writeln!(f, "SHA256: {}", self.sha256)
}
}
pub const SIMILAR_SAMPLES: &str = "/v1/samples/similar";
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[non_exhaustive]
pub enum SimilarityHashType {
SSDeep,
SDHash,
LZJD,
TLSH,
PEHash,
ImportHash,
FuzzyImportHash,
}
impl SimilarityHashType {
pub fn get_table_field_simfunc(&self) -> (&'static str, Option<&'static str>) {
match self {
SimilarityHashType::SSDeep => ("file.ssdeep", Some("fuzzy_hash_compare")),
SimilarityHashType::SDHash => ("file.sdhash", Some("sdhash_compare")),
SimilarityHashType::LZJD => ("file.lzjd", Some("lzjd_compare")),
SimilarityHashType::TLSH => ("file.tlsh", Some("tlsh_compare")),
SimilarityHashType::PEHash => ("executable.pehash", None),
SimilarityHashType::ImportHash => ("executable.importhash", None),
SimilarityHashType::FuzzyImportHash => {
("executable.importhashfuzzy", Some("fuzzy_hash_compare"))
}
}
}
}
impl Display for SimilarityHashType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SimilarityHashType::SSDeep => write!(f, "SSDeep"),
SimilarityHashType::SDHash => write!(f, "SDHash"),
SimilarityHashType::LZJD => write!(f, "LZJD"),
SimilarityHashType::TLSH => write!(f, "TLSH"),
SimilarityHashType::PEHash => write!(f, "PeHash"),
SimilarityHashType::ImportHash => write!(f, "Import Hash (IMPHASH)"),
SimilarityHashType::FuzzyImportHash => write!(f, "Fuzzy Import hash"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SimilarSamplesRequest {
pub key: String,
pub hash: Vec<(SimilarityHashType, String)>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SimilarSample {
pub sha256: String,
pub algorithms: Vec<(SimilarityHashType, f32)>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SimilarSamplesResponse {
pub results: Vec<SimilarSample>,
pub message: Option<String>,
}
pub const LIST_LABELS: &str = "/v1/labels";
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Label {
pub id: u64,
pub name: String,
pub parent: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Labels(pub Vec<Label>);
impl Labels {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Display for Labels {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_empty() {
return writeln!(f, "No labels.");
}
for label in &self.0 {
let parent = if let Some(parent) = &label.parent {
format!(", parent: {parent}")
} else {
String::new()
};
writeln!(f, "{}: {}{parent}", label.id, label.name)?;
}
Ok(())
}
}