malwaredb_server/utils/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use std::fmt::LowerHex;
4use std::path::PathBuf;
5
6/// Create a relative path from a hash with a given depth, such that for the given depth,
7/// those beginning values of the hash are sub-directories.
8pub trait HashPath {
9    /// Get the path object from the hash with the requested sub-directory depth
10    fn hashed_path(self, depth: usize) -> PathBuf;
11}
12
13// TODO: Fix so this can be used with `String`
14// https://github.com/malwaredb/malwaredb-rs/issues/60
15impl<T> HashPath for T
16where
17    T: AsRef<[u8]> + IntoIterator,
18    T::Item: LowerHex,
19{
20    fn hashed_path(self, depth: usize) -> PathBuf {
21        let mut path = PathBuf::new();
22        let the_hash = hex::encode(&self);
23        for (index, value) in self.into_iter().enumerate() {
24            path.push(format!("{value:02x}"));
25            if index >= depth - 1 {
26                break;
27            }
28        }
29        path.push(the_hash);
30        path
31    }
32}
33
34#[cfg(test)]
35mod test {
36    use super::HashPath;
37    use md5::Md5;
38    use sha1::Sha1;
39    use sha2::{Digest, Sha256, Sha384, Sha512};
40
41    const THE_STRING: &[u8] = b"hello world pretend this is a file!";
42
43    #[test]
44    fn test_sha512_path() {
45        let mut hasher = Sha512::new();
46        hasher.update(THE_STRING);
47
48        let result = hasher.finalize();
49        assert_eq!(
50            "0f/84/0f84de02c2c3942e2c1b22819a8381270b5476574d8df50fa4b307cc61ffe45193ab7e4f9cdd4fa5a6c4abf8948e3220a8925c58a089473a4790533f50c79d7d",
51            result.hashed_path(2).to_str().unwrap()
52        );
53        assert_eq!(
54            "0f/84/de/0f84de02c2c3942e2c1b22819a8381270b5476574d8df50fa4b307cc61ffe45193ab7e4f9cdd4fa5a6c4abf8948e3220a8925c58a089473a4790533f50c79d7d",
55            result.hashed_path(3).to_str().unwrap()
56        );
57    }
58
59    #[test]
60    fn test_sha384_path() {
61        let mut hasher = Sha384::new();
62        hasher.update(THE_STRING);
63
64        let result = hasher.finalize();
65        assert_eq!(
66            "e4/05/e405fb66b64771f44efe0f16f7d98a2787cdd34f2ec481b3fefa5a458b2526b258a862ff55bb0c62bbfcee425629bc1e",
67            result.hashed_path(2).to_str().unwrap()
68        );
69        assert_eq!(
70            "e4/05/fb/e405fb66b64771f44efe0f16f7d98a2787cdd34f2ec481b3fefa5a458b2526b258a862ff55bb0c62bbfcee425629bc1e",
71            result.hashed_path(3).to_str().unwrap()
72        );
73    }
74
75    #[test]
76    fn test_sha256_path() {
77        let mut hasher = Sha256::new();
78        hasher.update(THE_STRING);
79
80        let result = hasher.finalize();
81        assert_eq!(
82            "12/77/1277be37873848472bcd3b58f76e70d4b01bf792b3e1bb8022f410d40804ab7e",
83            result.hashed_path(2).to_str().unwrap()
84        );
85        assert_eq!(
86            "12/77/be/1277be37873848472bcd3b58f76e70d4b01bf792b3e1bb8022f410d40804ab7e",
87            result.hashed_path(3).to_str().unwrap()
88        );
89    }
90
91    #[test]
92    fn test_sha1_path() {
93        let mut hasher = Sha1::new();
94        hasher.update(THE_STRING);
95
96        let result = hasher.finalize();
97        assert_eq!(
98            "d1/ed/d1ed345c982dd7bd8a260457fa2c0e59ed22f804",
99            result.hashed_path(2).to_str().unwrap()
100        );
101        assert_eq!(
102            "d1/ed/34/d1ed345c982dd7bd8a260457fa2c0e59ed22f804",
103            result.hashed_path(3).to_str().unwrap()
104        );
105    }
106
107    #[test]
108    fn test_md5_path() {
109        let mut hasher = Md5::new();
110        hasher.update(THE_STRING);
111
112        let result = hasher.finalize();
113        assert_eq!(
114            "a7/a9/a7a938a65a579cb64f632a90eff9862b",
115            result.hashed_path(2).to_str().unwrap()
116        );
117        assert_eq!(
118            "a7/a9/38/a7a938a65a579cb64f632a90eff9862b",
119            result.hashed_path(3).to_str().unwrap()
120        );
121    }
122}