assemblyline_models/types/
ssdeep.rs1use serde_with::{DeserializeFromStr, SerializeDisplay};
2use struct_metadata::Described;
3#[cfg(feature = "rand")]
4use rand::RngExt;
5
6
7use crate::{ElasticMeta, ModelError};
8
9
10
11#[derive(SerializeDisplay, DeserializeFromStr, Described, PartialEq, Eq, Debug, Clone)]
13#[metadata_type(ElasticMeta)]
14#[metadata(mapping="text", analyzer="text_fuzzy")]
15pub struct SSDeepHash(String);
16
17impl std::fmt::Display for SSDeepHash {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 f.write_str(&self.0)
20 }
21}
22
23pub fn is_ssdeep_char(value: char) -> bool {
24 value.is_ascii_alphanumeric() || value == '/' || value == '+'
25}
26
27pub fn is_ssdeep_hash(value: &str) -> bool {
28 let (numbers, hashes) = match value.split_once(":") {
30 Some(value) => value,
31 None => return false
32 };
33 let (hasha, hashb) = match hashes.split_once(":") {
34 Some(value) => value,
35 None => return false
36 };
37 if numbers.is_empty() || numbers.len() > 18 || numbers.chars().any(|c|!c.is_ascii_digit()) {
38 return false
39 }
40 if hasha.len() > 64 || hasha.chars().any(|c|!is_ssdeep_char(c)) {
41 return false
42 }
43 if hashb.len() > 64 || hashb.chars().any(|c|!is_ssdeep_char(c)) {
44 return false
45 }
46 return true
47}
48
49impl std::str::FromStr for SSDeepHash {
50 type Err = ModelError;
51
52 fn from_str(s: &str) -> Result<Self, Self::Err> {
53 if is_ssdeep_hash(s) {
54 Ok(SSDeepHash(s.to_owned()))
55 } else {
56 Err(ModelError::InvalidSSDeep(s.to_owned()))
57 }
58 }
59}
60
61#[cfg(feature = "rand")]
62impl rand::distr::Distribution<SSDeepHash> for rand::distr::StandardUniform {
63 fn sample<R: rand::prelude::Rng + ?Sized>(&self, rng: &mut R) -> SSDeepHash {
64 use rand::distr::{Alphanumeric, SampleString};
65 let mut output = String::new();
66 output += &rng.random_range(0..10000).to_string();
67 output += ":";
68 let len = rng.random_range(0..64);
69 output += &Alphanumeric.sample_string(rng, len);
70 output += ":";
71 let len = rng.random_range(0..64);
72 output += &Alphanumeric.sample_string(rng, len);
73 SSDeepHash(output)
74 }
75}