jirust_cli/config/
config_file.rs

1use base64::prelude::*;
2use serde::{Deserialize, Serialize};
3use std::{fs, io::Write};
4use toml::{self, Table, Value};
5
6/// This struct holds the username and api_key for the Jira API.
7#[derive(Debug)]
8pub struct AuthData {
9    username: String,
10    api_key: String,
11}
12
13/// This struct holds the configuration data to use the Jira API (authentication info and Jira base_url).
14#[derive(Debug, Serialize, Deserialize, Clone)]
15pub struct ConfigFile {
16    auth: AuthSection,
17    jira: JiraSection,
18    #[serde(default)]
19    yara: YaraSection,
20}
21
22/// This struct holds the authentication token to be used with the Jira API.
23#[derive(Debug, Serialize, Deserialize, Clone)]
24pub struct AuthSection {
25    auth_token: String,
26}
27
28/// This struct holds the Jira base_url.
29#[derive(Debug, Serialize, Deserialize, Clone)]
30pub struct JiraSection {
31    jira_url: String,
32    standard_resolution: String,
33    standard_resolution_comment: String,
34    transitions_names: Table,
35}
36
37/// This struct holds the YARA scanner configuration.
38#[derive(Debug, Serialize, Deserialize, Clone)]
39pub struct YaraSection {
40    rules_source: String,
41    rules_directory: String,
42    cache_file: String,
43    cache_version_file: String,
44}
45
46/// Implementation of AuthData
47///
48/// # Methods
49/// * `new(username: String, api_key: String) -> AuthData` - creates a new instance of AuthData
50/// * `set_username(username: String)` - sets the username
51/// * `set_api_key(api_key: String)` - sets the api_key
52/// * `get_username() -> String` - gets the username
53/// * `get_api_key() -> String` - gets the api_key
54/// * `to_base64() -> String` - converts the AuthData to a base64 string
55/// * `from_base64(base64_str: String) -> AuthData` - converts a base64 string to an AuthData
56/// * `write_to_file(file: &str) -> Result<(), std::io::Error>` - writes the AuthData to a file
57/// * `read_from_file(file: &str) -> Result<AuthData, std::io::Error>` - reads the AuthData from a file
58impl AuthData {
59    /// Create a new AuthData struct.
60    ///
61    /// # Arguments
62    /// * username - The username to be used for authentication.
63    /// * api_key - The api_key to be used for authentication.
64    ///
65    /// # Returns
66    /// * A new AuthData struct.
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// use jirust_cli::config::config_file::AuthData;
72    ///
73    /// let auth_data = AuthData::new("username".to_string(), "api_key".to_string());
74    /// ```
75    pub fn new(username: String, api_key: String) -> AuthData {
76        AuthData { username, api_key }
77    }
78
79    /// Set the username for the AuthData struct.
80    ///
81    /// # Arguments
82    /// * username - The username to be used for authentication.
83    ///
84    /// # Examples
85    ///
86    /// ```
87    /// use jirust_cli::config::config_file::AuthData;
88    ///
89    /// let mut auth_data = AuthData::new("username".to_string(), "api_key".to_string());
90    /// auth_data.set_username("new_username".to_string());
91    /// ```
92    pub fn set_username(&mut self, username: String) {
93        self.username = username.replace("\n", "");
94    }
95
96    /// Set the api_key for the AuthData struct.
97    ///
98    /// # Arguments
99    /// * api_key - The api_key to be used for authentication.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use jirust_cli::config::config_file::AuthData;
105    ///
106    /// let mut auth_data = AuthData::new("username".to_string(), "api_key".to_string());
107    /// auth_data.set_api_key("new_api_key".to_string());
108    /// ```
109    pub fn set_api_key(&mut self, api_key: String) {
110        self.api_key = api_key.replace("\n", "");
111    }
112
113    /// Encode the username and api_key to base64 to be used in the Authorization header of the request.
114    ///
115    /// # Returns
116    /// * A base64 encoded string of the username and api_key.
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// use jirust_cli::config::config_file::AuthData;
122    ///
123    /// let auth_data = AuthData::new("username".to_string(), "api_key".to_string());
124    /// let base64_encoded = auth_data.to_base64();
125    ///
126    /// assert_eq!(base64_encoded, "dXNlcm5hbWU6YXBpX2tleQ==");
127    /// ```
128    pub fn to_base64(&self) -> String {
129        BASE64_STANDARD.encode(format!("{}:{}", self.username, self.api_key).replace("\n", ""))
130    }
131
132    /// Decode a base64 encoded string to get the username and api_key.
133    ///
134    /// # Arguments
135    /// * encoded - The base64 encoded string to be decoded.
136    ///
137    /// # Returns
138    /// * A tuple containing the username and api_key.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use jirust_cli::config::config_file::AuthData;
144    ///
145    /// let (username, api_key) = AuthData::from_base64("dXNlcm5hbWU6YXBpX2tleQ==");
146    ///
147    /// assert_eq!(username, "username");
148    /// assert_eq!(api_key, "api_key");
149    /// ```
150    pub fn from_base64(encoded: &str) -> (String, String) {
151        let decoded = BASE64_STANDARD
152            .decode(encoded)
153            .expect("Failed to decode base64");
154        let decoded_str = String::from_utf8(decoded).expect("Failed to convert to string");
155        let parts: Vec<&str> = decoded_str.split(':').collect();
156        (parts[0].to_string(), parts[1].to_string())
157    }
158}
159
160/// Implementation of ConfigFile
161///
162/// # Methods
163/// * `new(auth_token: String, jira_url: String) -> ConfigFile` - creates a new instance of ConfigFile
164/// * default() -> ConfigFile - creates a new instance of ConfigFile with default values
165/// * `write_to_file(file: &str) -> Result<(), std::io::Error>` - writes the ConfigFile to a file
166/// * `read_from_file(file: &str) -> Result<ConfigFile, std::io::Error>` - reads the ConfigFile from a file
167/// * `get_auth() -> AuthSection` - gets the AuthSection from the ConfigFile
168/// * `get_jira() -> JiraSection` - gets the JiraSection from the ConfigFile
169/// * `set_auth(auth: AuthSection)` - sets the AuthSection in the ConfigFile
170/// * `set_jira(jira: JiraSection)` - sets the JiraSection in the ConfigFile
171/// * `set_standard_resolution(standard_resolution: String)` - sets the standard_resolution in the ConfigFile
172/// * `get_standard_resolution() -> String` - gets the standard_resolution from the ConfigFile
173/// * `set_standard_resolution_comment(standard_resolution_comment: String)` - sets the standard_resolution_comment in the ConfigFile
174/// * `get_standard_resolution_comment() -> String` - gets the standard_resolution_comment from the Config
175/// * `add_transition_name(key: String, value: String)` - adds a transition_name to the ConfigFile
176/// * `get_transition_name(key: &str) -> Option<String>` - gets a transition_name from the ConfigFile
177impl ConfigFile {
178    /// Create a new ConfigFile struct.
179    ///
180    /// # Arguments
181    /// * auth_token - The authentication token to be used with the Jira API.
182    /// * jira_url - The base_url for the Jira API.
183    /// * standard_resolution - The standard resolution to be used when resolving an issue.
184    /// * standard_resolution_comment - The standard comment to be used when resolving an issue.
185    /// * transitions_names - The transitions names to be used when transitioning an issue.
186    /// * yara - The YARA scanner configuration section.
187    ///
188    /// # Returns
189    /// * A new ConfigFile struct.
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// use jirust_cli::config::config_file::{ConfigFile, YaraSection};
195    /// use toml::Table;
196    ///
197    /// let config = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new(), YaraSection::default());
198    ///
199    /// assert_eq!(config.get_auth_key(), "auth_token");
200    /// assert_eq!(config.get_jira_url(), "jira_url");
201    /// assert_eq!(config.get_standard_resolution(), "standard_resolution");
202    /// assert_eq!(config.get_standard_resolution_comment(), "standard_resolution_comment");
203    /// ```
204    pub fn new(
205        auth_token: String,
206        jira_url: String,
207        standard_resolution: String,
208        standard_resolution_comment: String,
209        transitions_names: Table,
210        yara: YaraSection,
211    ) -> ConfigFile {
212        ConfigFile {
213            auth: AuthSection { auth_token },
214            jira: JiraSection {
215                jira_url,
216                standard_resolution,
217                standard_resolution_comment,
218                transitions_names,
219            },
220            yara,
221        }
222    }
223
224    /// Set the authentication token for the ConfigFile struct.
225    /// This is the token that will be used to authenticate with the Jira API.
226    ///
227    /// # Arguments
228    /// * auth_token - The authentication token to be used with the Jira API.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use jirust_cli::config::config_file::ConfigFile;
234    ///
235    /// let mut config = ConfigFile::default();
236    /// config.set_auth_key("auth_key".to_string());
237    ///
238    /// assert_eq!(config.get_auth_key(), "auth_key");
239    /// ```
240    pub fn set_auth_key(&mut self, auth_token: String) {
241        self.auth.auth_token = auth_token.replace("\n", "");
242    }
243
244    /// Get the authentication token for the ConfigFile struct.
245    /// This is the token that will be used to authenticate with the Jira API.
246    /// This is useful for getting the current value of the authentication token.
247    ///
248    /// # Returns
249    /// * The authentication token to be used with the Jira API.
250    ///
251    /// # Examples
252    ///
253    /// ```
254    /// use jirust_cli::config::config_file::{ConfigFile, YaraSection};
255    /// use toml::Table;
256    ///
257    /// let config = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new(), YaraSection::default());
258    /// let auth_key = config.get_auth_key();
259    ///
260    /// assert_eq!(auth_key, "auth_token");
261    /// ```
262    pub fn get_auth_key(&self) -> &str {
263        &self.auth.auth_token
264    }
265
266    /// Set the Jira URL for the ConfigFile struct.
267    /// This is the base URL for the Jira API.
268    ///
269    /// # Arguments
270    /// * jira_url - The base URL for the Jira API.
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// use jirust_cli::config::config_file::ConfigFile;
276    ///
277    /// let mut config = ConfigFile::default();
278    /// config.set_jira_url("jira_url".to_string());
279    ///
280    /// assert_eq!(config.get_jira_url(), "jira_url");
281    /// ```
282    pub fn set_jira_url(&mut self, jira_url: String) {
283        self.jira.jira_url = jira_url.replace("\n", "");
284    }
285
286    /// Get the Jira URL for the ConfigFile struct.
287    /// This is the base URL for the Jira API.
288    ///
289    /// # Returns
290    /// * The base URL for the Jira API.
291    ///
292    /// # Examples
293    ///
294    /// ```
295    /// use jirust_cli::config::config_file::{ConfigFile, YaraSection};
296    /// use toml::Table;
297    ///
298    /// let config = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new(), YaraSection::default());
299    /// let jira_url = config.get_jira_url();
300    ///
301    /// assert_eq!(jira_url, "jira_url");
302    /// ```
303    pub fn get_jira_url(&self) -> &str {
304        &self.jira.jira_url
305    }
306
307    /// Set the standard resolution for the ConfigFile struct.
308    /// This is the standard resolution that will be used when resolving an issue.
309    ///
310    /// # Arguments
311    /// * standard_resolution - The standard resolution to be used when resolving an issue.
312    ///
313    /// # Examples
314    ///
315    /// ```
316    /// use jirust_cli::config::config_file::ConfigFile;
317    ///
318    /// let mut config = ConfigFile::default();
319    /// config.set_standard_resolution("standard_resolution".to_string());
320    ///
321    /// assert_eq!(config.get_standard_resolution(), "standard_resolution");
322    /// ```
323    pub fn set_standard_resolution(&mut self, standard_resolution: String) {
324        self.jira.standard_resolution = standard_resolution;
325    }
326
327    /// Get the standard resolution for the ConfigFile struct.
328    /// This is the standard resolution that will be used when resolving an issue.
329    ///
330    /// # Returns
331    /// * The standard resolution to be used when resolving an issue.
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// use jirust_cli::config::config_file::{ConfigFile, YaraSection};
337    /// use toml::Table;
338    ///
339    /// let config = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new(), YaraSection::default());
340    /// let standard_resolution = config.get_standard_resolution();
341    ///
342    /// assert_eq!(config.get_standard_resolution(), "standard_resolution");
343    /// ```
344    pub fn get_standard_resolution(&self) -> &String {
345        &self.jira.standard_resolution
346    }
347
348    /// Set the standard resolution comment for the ConfigFile struct.
349    /// This is the standard resolution comment that will be used when resolving an issue.
350    ///
351    /// # Arguments
352    /// * standard_resolution_comment - The standard resolution comment to be used when resolving an issue.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// use jirust_cli::config::config_file::ConfigFile;
358    ///
359    /// let mut config = ConfigFile::default();
360    /// config.set_standard_resolution_comment("standard_resolution_comment".to_string());
361    ///
362    /// assert_eq!(config.get_standard_resolution_comment(), "standard_resolution_comment");
363    /// ```
364    pub fn set_standard_resolution_comment(&mut self, standard_resolution_comment: String) {
365        self.jira.standard_resolution_comment = standard_resolution_comment;
366    }
367
368    /// Get the standard resolution comment for the ConfigFile struct.
369    /// This is the standard resolution comment that will be used when resolving an issue.
370    ///
371    /// # Returns
372    /// * The standard resolution comment to be used when resolving an issue.
373    ///
374    /// # Examples
375    ///
376    /// ```
377    /// use jirust_cli::config::config_file::{ConfigFile, YaraSection};
378    /// use toml::Table;
379    ///
380    /// let config = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new(), YaraSection::default());
381    /// let standard_resolution_comment = config.get_standard_resolution_comment();
382    ///
383    /// assert_eq!(standard_resolution_comment, "standard_resolution_comment");
384    /// ```
385    pub fn get_standard_resolution_comment(&self) -> &String {
386        &self.jira.standard_resolution_comment
387    }
388
389    /// Add a transition name to the ConfigFile struct.
390    /// This is used to store the transition name for a specific transition.
391    /// This is used to transition an issue to a specific state.
392    /// The key is the transition internal identifier and the value is the transition name.
393    ///
394    /// # Arguments
395    /// * key - The transition internal identifier.
396    /// * value - The transition name.
397    ///
398    /// # Examples
399    ///
400    /// ```
401    /// use jirust_cli::config::config_file::ConfigFile;
402    ///
403    /// let mut config = ConfigFile::default();
404    /// config.add_transition_name("transition_key".to_string(), "Transition name".to_string());
405    ///
406    /// assert_eq!(config.get_transition_name("transition_key"), Some(vec!["Transition name".to_string()]));
407    /// ```
408    pub fn add_transition_name(&mut self, key: String, value: String) {
409        let mut existing_value: Vec<Value> = self
410            .jira
411            .transitions_names
412            .get(&key)
413            .and_then(|v| v.as_array())
414            .unwrap_or(&vec![])
415            .iter()
416            .map(|v| Value::String(v.as_str().unwrap().to_string()))
417            .collect();
418        existing_value.push(Value::String(value));
419        self.jira
420            .transitions_names
421            .insert(key, Value::Array(existing_value));
422    }
423
424    /// Get the transition name for a specific transition internal identifier.
425    /// This is used to transition an issue to a specific state.
426    /// The key is the transition internal identifier and the value is the transition name.
427    /// If the transition internal identifier does not exist, None is returned.
428    ///
429    /// # Arguments
430    /// * key - The transition internal identifier.
431    ///
432    /// # Returns
433    /// * The transition name for the specific transition internal identifier.
434    ///
435    /// # Examples
436    ///
437    /// ```
438    /// use jirust_cli::config::config_file::ConfigFile;
439    ///
440    /// let mut config = ConfigFile::default();
441    /// config.add_transition_name("transition_key".to_string(), "Transition name".to_string());
442    ///
443    /// assert_eq!(config.get_transition_name("transition_key"), Some(vec!["Transition name".to_string()]));
444    /// ```
445    pub fn get_transition_name(&self, key: &str) -> Option<Vec<String>> {
446        let tranisitons_names = self
447            .jira
448            .transitions_names
449            .get(key)
450            .and_then(|v| v.as_array());
451        Some(
452            tranisitons_names
453                .unwrap_or(&vec![])
454                .iter()
455                .map(|v| v.as_str().unwrap().to_string())
456                .collect(),
457        )
458    }
459
460    /// Get the YARA section from the ConfigFile struct.
461    ///
462    /// # Returns
463    /// * The YARA section from the ConfigFile.
464    pub fn get_yara_section(&self) -> &YaraSection {
465        &self.yara
466    }
467
468    /// Get the YARA rules source URL from the ConfigFile struct.
469    ///
470    /// # Returns
471    /// * The YARA rules source URL.
472    pub fn get_yara_rules_source(&self) -> &str {
473        &self.yara.rules_source
474    }
475
476    /// Get the YARA rules directory from the ConfigFile struct.
477    ///
478    /// # Returns
479    /// * The YARA rules directory name (relative to ~/.jirust-cli/).
480    pub fn get_yara_rules_directory(&self) -> &str {
481        &self.yara.rules_directory
482    }
483
484    /// Get the YARA cache file from the ConfigFile struct.
485    ///
486    /// # Returns
487    /// * The YARA cache file name (relative to ~/.jirust-cli/).
488    pub fn get_yara_cache_file(&self) -> &str {
489        &self.yara.cache_file
490    }
491
492    /// Get the YARA cache version file from the ConfigFile struct.
493    ///
494    /// # Returns
495    /// * The YARA cache version file name (relative to ~/.jirust-cli/).
496    pub fn get_yara_cache_version_file(&self) -> &str {
497        &self.yara.cache_version_file
498    }
499
500    /// Set the YARA rules source URL for the ConfigFile struct.
501    ///
502    /// # Arguments
503    /// * source - The YARA rules source URL (git repo or zip file).
504    pub fn set_yara_rules_source(&mut self, source: String) {
505        self.yara.rules_source = source;
506    }
507
508    /// Set the YARA rules directory for the ConfigFile struct.
509    ///
510    /// # Arguments
511    /// * directory - The YARA rules directory name (relative to ~/.jirust-cli/).
512    pub fn set_yara_rules_directory(&mut self, directory: String) {
513        self.yara.rules_directory = directory;
514    }
515
516    /// Set the YARA cache file for the ConfigFile struct.
517    ///
518    /// # Arguments
519    /// * file - The YARA cache file name (relative to ~/.jirust-cli/).
520    pub fn set_yara_cache_file(&mut self, file: String) {
521        self.yara.cache_file = file;
522    }
523
524    /// Set the YARA cache version file for the ConfigFile struct.
525    ///
526    /// # Arguments
527    /// * file - The YARA cache version file name (relative to ~/.jirust-cli/).
528    pub fn set_yara_cache_version_file(&mut self, file: String) {
529        self.yara.cache_version_file = file;
530    }
531
532    /// Stores the configuration to a file.
533    /// This will overwrite the file if it already exists.
534    ///
535    /// # Arguments
536    /// * file_path - The path to the file to write the configuration to.
537    ///
538    /// # Returns
539    /// * A Result containing either an empty Ok or an error.
540    ///
541    /// # Examples
542    ///
543    /// ```
544    /// use jirust_cli::config::config_file::{ConfigFile, YaraSection};
545    /// use toml::Table;
546    ///
547    /// let config = ConfigFile::new("auth_token".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new(), YaraSection::default());
548    /// let result = config.write_to_file("config.toml");
549    ///
550    /// assert!(result.is_ok());
551    /// ```
552    pub fn write_to_file(&self, file_path: &str) -> Result<(), std::io::Error> {
553        let mut file = std::fs::OpenOptions::new()
554            .write(true)
555            .create(true)
556            .truncate(true)
557            .open(file_path)
558            .expect("Failed to open file");
559        let toml_str = toml::to_string(self).expect("Failed to serialize toml");
560        file.write_all(toml_str.as_bytes())
561    }
562
563    /// Loads the configuration from a file.
564    /// If the file does not exist, it will return a ConfigFile with default values.
565    /// If the file is not valid toml, it will return an error.
566    /// If the file is valid toml, it will return the ConfigFile.
567    ///
568    /// # Arguments
569    /// * file_path - The path to the file to read the configuration from.
570    ///
571    /// # Returns
572    /// * A Result containing either the ConfigFile or an error.
573    ///
574    /// # Examples
575    ///
576    /// ```
577    /// use jirust_cli::config::config_file::ConfigFile;
578    /// use std::path::Path;
579    ///
580    /// // Try both possible paths to handle different working directories
581    /// let config_path = if Path::new("config_example.toml").exists() {
582    ///     "config_example.toml"
583    /// } else {
584    ///     "jirust-cli/config_example.toml"
585    /// };
586    ///
587    /// let config = ConfigFile::read_from_file(config_path);
588    ///
589    /// assert!(config.clone().is_ok());
590    /// assert_eq!(config.clone().unwrap().get_auth_key(), "auth_key");
591    /// assert_eq!(config.clone().unwrap().get_jira_url(), "jira_url");
592    /// ```
593    pub fn read_from_file(file_path: &str) -> Result<ConfigFile, toml::de::Error> {
594        let config_file_str = fs::read_to_string(file_path)
595            .unwrap_or(toml::to_string(&ConfigFile::default()).unwrap_or("".to_string()));
596        toml::from_str(&config_file_str)
597    }
598}
599
600impl Default for YaraSection {
601    /// Create a new YaraSection struct with default values.
602    /// The default values are:
603    /// - rules_source: "https://github.com/YARAHQ/yara-forge/releases/latest/download/yara-forge-rules-core.zip"
604    /// - rules_directory: "yara-rules"
605    /// - cache_file: "yara_rules.cache"
606    /// - cache_version_file: "yara_rules.cache.version"
607    ///
608    /// # Returns
609    /// * A new YaraSection struct with default values.
610    fn default() -> YaraSection {
611        YaraSection {
612            rules_source: String::from(
613                "https://github.com/YARAHQ/yara-forge/releases/latest/download/yara-forge-rules-core.zip",
614            ),
615            rules_directory: String::from("yara-rules"),
616            cache_file: String::from("yara_rules.cache"),
617            cache_version_file: String::from("yara_rules.cache.version"),
618        }
619    }
620}
621
622impl Default for ConfigFile {
623    /// Create a new ConfigFile struct with default values.
624    /// This is useful for creating a new configuration file.
625    /// The default values can be set using the set methods.
626    /// The default values are:
627    /// - auth_token: ""
628    /// - jira_url: ""
629    /// - standard_resolution: ""
630    /// - standard_resolution_comment: ""
631    /// - transitions_names: Table::new()
632    /// - yara: YaraSection::default()
633    ///
634    /// # Returns
635    /// * A new ConfigFile struct with default values.
636    ///
637    /// # Examples
638    ///
639    /// ```
640    /// use jirust_cli::config::config_file::ConfigFile;
641    /// use toml::Table;
642    ///
643    /// let config = ConfigFile::default();
644    ///
645    /// assert_eq!(config.get_auth_key(), "");
646    /// assert_eq!(config.get_jira_url(), "");
647    /// assert_eq!(config.get_standard_resolution(), "");
648    /// assert_eq!(config.get_standard_resolution_comment(), "");
649    /// ```
650    fn default() -> ConfigFile {
651        ConfigFile {
652            auth: AuthSection {
653                auth_token: String::from(""),
654            },
655            jira: JiraSection {
656                jira_url: String::from(""),
657                standard_resolution: String::from(""),
658                standard_resolution_comment: String::from(""),
659                transitions_names: Table::new(),
660            },
661            yara: YaraSection::default(),
662        }
663    }
664}
665
666impl YaraSection {
667    /// Creates a new YaraSection with the specified configuration.
668    ///
669    /// # Arguments
670    ///
671    /// * `rules_source` - URL or path to YARA rules source (git repository or zip file)
672    /// * `rules_directory` - Directory name where YARA rules will be stored
673    /// * `cache_file` - Filename for the compiled rules cache
674    /// * `cache_version_file` - Filename for tracking the cache version
675    ///
676    /// # Returns
677    ///
678    /// A new `YaraSection` instance with the provided configuration
679    ///
680    /// # Example
681    ///
682    /// ```
683    /// use jirust_cli::config::config_file::YaraSection;
684    ///
685    /// let yara = YaraSection::new(
686    ///     "https://github.com/Yara-Rules/rules.git".to_string(),
687    ///     "yara-rules".to_string(),
688    ///     "yara_rules.cache".to_string(),
689    ///     "yara_rules.cache.version".to_string(),
690    /// );
691    /// ```
692    pub fn new(
693        rules_source: String,
694        rules_directory: String,
695        cache_file: String,
696        cache_version_file: String,
697    ) -> YaraSection {
698        YaraSection {
699            rules_source,
700            rules_directory,
701            cache_file,
702            cache_version_file,
703        }
704    }
705
706    /// Returns the YARA rules source URL or path.
707    ///
708    /// # Returns
709    ///
710    /// A string slice containing the rules source (git URL or zip file URL)
711    pub fn get_rules_source(&self) -> &str {
712        &self.rules_source
713    }
714
715    /// Returns the directory name where YARA rules are stored.
716    ///
717    /// # Returns
718    ///
719    /// A string slice containing the rules directory name
720    pub fn get_rules_directory(&self) -> &str {
721        &self.rules_directory
722    }
723
724    /// Returns the cache filename for compiled YARA rules.
725    ///
726    /// # Returns
727    ///
728    /// A string slice containing the cache filename
729    pub fn get_cache_file(&self) -> &str {
730        &self.cache_file
731    }
732
733    /// Returns the cache version filename.
734    ///
735    /// # Returns
736    ///
737    /// A string slice containing the cache version filename
738    pub fn get_cache_version_file(&self) -> &str {
739        &self.cache_version_file
740    }
741}