Skip to main content

malwaredb_server/db/
admin.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use chrono::{DateTime, Utc};
4use std::fmt::{Display, Formatter};
5
6/// User record
7#[allow(clippy::struct_excessive_bools)]
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct User {
10    /// User ID, for database relations
11    pub id: u32,
12
13    /// Email address
14    pub email: String,
15
16    /// Username, unique
17    pub uname: String,
18
19    /// First name
20    pub fname: String,
21
22    /// Last name
23    pub lname: String,
24
25    /// Organization, optional
26    pub org: Option<String>,
27
28    /// Phone number, optional
29    pub phone: Option<String>,
30
31    /// If a password is set
32    pub has_password: bool,
33
34    /// If the user has logged in and fetched an API key
35    pub has_api_key: bool,
36
37    /// Creation timestamp
38    pub created: DateTime<Utc>,
39
40    /// User is readonly
41    pub is_readonly: bool,
42
43    /// If the user account if for anonymous access
44    #[cfg(feature = "anonymous")]
45    pub is_anonymous_user: bool,
46}
47
48impl Display for User {
49    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50        let has_password = {
51            if self.has_password {
52                "password set"
53            } else {
54                "no password"
55            }
56        };
57        let has_api_key = {
58            if self.has_api_key {
59                "API key set"
60            } else {
61                "no API key"
62            }
63        };
64        let org = {
65            if let Some(org) = &self.org {
66                format!(" ({org}) ")
67            } else {
68                String::new()
69            }
70        };
71        let phone = {
72            if let Some(ph) = &self.phone {
73                format!(" {ph} ")
74            } else {
75                String::new()
76            }
77        };
78
79        let readonly = if self.is_readonly { " read only" } else { "" };
80
81        let anon = {
82            #[cfg(feature = "anonymous")]
83            if self.is_anonymous_user {
84                " anonymous access account"
85            } else {
86                ""
87            }
88            #[cfg(not(feature = "anonymous"))]
89            ""
90        };
91
92        write!(
93            f,
94            "{}: {} {} {}<{}>,{phone}{org}{has_password}, {has_api_key} created {}{readonly}{anon}",
95            self.id, self.fname, self.lname, self.uname, self.email, self.created
96        )
97    }
98}
99
100/// Group record
101
102#[derive(Clone, Debug)]
103pub struct Group {
104    /// Group ID, for database relations
105    pub id: u32,
106
107    /// Group name
108    pub name: String,
109
110    /// Optional description
111    pub description: Option<String>,
112
113    /// Parent group, if present
114    pub parent: Option<String>,
115
116    /// Members of the group
117    pub members: Vec<User>,
118
119    /// Sources available to the group
120    pub sources: Vec<Source>,
121
122    /// Number of files accessible by the group
123    pub files: u32,
124}
125
126impl Display for Group {
127    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
128        let parent = if let Some(p) = &self.parent {
129            format!("Parent: {p}")
130        } else {
131            String::new()
132        };
133
134        let sources_label = match self.sources.len() {
135            0 => "no sources".into(),
136            1 => "one source".into(),
137            x => format!("{x} sources:"),
138        };
139
140        let members_label = match self.members.len() {
141            0 => "no members".into(),
142            1 => "one member".into(),
143            x => format!("{x} members:"),
144        };
145
146        if let Some(desc) = &self.description {
147            writeln!(
148                f,
149                "{}: {} {parent} {} files -- {desc} {members_label} {sources_label}",
150                self.id, self.name, self.files
151            )?;
152        } else {
153            writeln!(
154                f,
155                "{}: {} {parent} {} files -- {members_label} {sources_label}",
156                self.id, self.name, self.files
157            )?;
158        }
159
160        writeln!(f, "Members:")?;
161        for user in &self.members {
162            writeln!(f, "\t{user}")?;
163        }
164
165        writeln!(f, "Sources:")?;
166        for source in &self.sources {
167            writeln!(f, "\t{source}")?;
168        }
169
170        Ok(())
171    }
172}
173
174/// Source of samples in Malware DB
175#[derive(Clone, Debug, PartialEq, Eq)]
176pub struct Source {
177    /// ID of the source
178    pub id: u32,
179
180    /// Name of the source
181    pub name: String,
182
183    /// Description of the source
184    pub description: Option<String>,
185
186    /// Website of the source, or where the source's data may be found
187    pub url: Option<String>,
188
189    /// Date of first acquisition from the source, or creation date of the source
190    pub date: DateTime<chrono::Local>,
191
192    /// Name of the parent source
193    pub parent: Option<String>,
194
195    /// Amount of files originating from this source
196    pub files: u64,
197
198    /// Number of groups which may access this source
199    pub groups: u32,
200
201    /// Whether this source is known to host malware
202    pub malicious: Option<bool>,
203}
204
205impl Display for Source {
206    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
207        write!(f, "{}: {}", self.id, self.name)?;
208        if let Some(url) = &self.url {
209            write!(f, " {url}")?;
210        }
211        if let Some(desc) = &self.description {
212            write!(f, " {desc}")?;
213        }
214        if let Some(is_malicious) = &self.malicious {
215            write!(f, ", known malicious {is_malicious},")?;
216        }
217        if let Some(parent) = &self.parent {
218            write!(f, ", parent {parent},")?;
219        }
220        write!(f, " {} files and {} groups from {}", self.files, self.groups, self.date)?;
221        Ok(())
222    }
223}