ares/decoders/
base65536_decoder.rs

1///! Decode a base65536 string
2///! Performs error handling and returns a string
3///! Call base65536_decoder.crack to use. It returns option<String> and check with
4///! `result.is_some()` to see if it returned okay.
5///
6use crate::checkers::CheckerTypes;
7use crate::decoders::interface::check_string_success;
8
9use super::crack_results::CrackResult;
10use super::interface::Crack;
11use super::interface::Decoder;
12
13use log::{debug, info, trace};
14
15/// The base65536 decoder, call:
16/// `let base65536_decoder = Decoder::<Base65536Decoder>::new()` to create a new instance
17/// And then call:
18/// `result = base65536_decoder.crack(input)` to decode a base65536 string
19/// The struct generated by new() comes from interface.rs
20/// ```
21/// use ares::decoders::base65536_decoder::{Base65536Decoder};
22/// use ares::decoders::interface::{Crack, Decoder};
23/// use ares::checkers::{athena::Athena, CheckerTypes, checker_type::{Check, Checker}};
24///
25/// let decode_base65536 = Decoder::<Base65536Decoder>::new();
26/// let athena_checker = Checker::<Athena>::new();
27/// let checker = CheckerTypes::CheckAthena(athena_checker);
28///
29/// let result = decode_base65536.crack("𒅓鹨𖡮𒀠啦ꍢ顡啫𓍱𓁡𠁴唬𓍪鱤啥𖥭𔐠𔕯ᔮ", &checker).unencrypted_text;
30/// assert!(result.is_some());
31/// assert_eq!(result.unwrap()[0], "Sphinx of black quartz, judge my vow.");
32/// ```
33pub struct Base65536Decoder;
34
35impl Crack for Decoder<Base65536Decoder> {
36    fn new() -> Decoder<Base65536Decoder> {
37        Decoder {
38            name: "Base65536",
39            description: "Base65536 is a binary encoding optimised for UTF-32-encoded text. Base65536 uses only \"safe\" Unicode code points - no unassigned code points, no whitespace, no control characters, etc.",
40            link: "https://github.com/qntm/base65536",
41            tags: vec!["base65536", "decoder", "base"],
42            popularity: 0.1,
43            phantom: std::marker::PhantomData,
44        }
45    }
46
47    /// This function does the actual decoding
48    /// It returns an Option<string> if it was successful
49    /// Else the Option returns nothing and the error is logged in Trace
50    fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
51        trace!("Trying base65536 with text {:?}", text);
52        let decoded_text: Option<String> = decode_base65536_no_error_handling(text);
53
54        trace!("Decoded text for base65536: {:?}", decoded_text);
55        let mut results = CrackResult::new(self, text.to_string());
56
57        if decoded_text.is_none() {
58            debug!("Failed to decode base65536 because Base65536Decoder::decode_base65536_no_error_handling returned None");
59            return results;
60        }
61
62        let decoded_text = decoded_text.unwrap();
63        if !check_string_success(&decoded_text, text) {
64            info!(
65                "Failed to decode base65536 because check_string_success returned false on string {}",
66                decoded_text
67            );
68            return results;
69        }
70
71        let checker_result = checker.check(&decoded_text);
72        results.unencrypted_text = Some(vec![decoded_text]);
73
74        results.update_checker(&checker_result);
75
76        results
77    }
78    /// Gets all tags for this decoder
79    fn get_tags(&self) -> &Vec<&str> {
80        &self.tags
81    }
82    /// Gets the name for the current decoder
83    fn get_name(&self) -> &str {
84        self.name
85    }
86}
87
88/// helper function
89fn decode_base65536_no_error_handling(text: &str) -> Option<String> {
90    // Runs the code to decode base65536
91    // Doesn't perform error handling, call from_base65536
92    if let Ok(decoded_text) = base65536::decode(text, false) {
93        return Some(String::from_utf8_lossy(&decoded_text).to_string());
94    }
95    None
96}
97
98#[cfg(test)]
99mod tests {
100    use super::Base65536Decoder;
101    use crate::{
102        checkers::{
103            athena::Athena,
104            checker_type::{Check, Checker},
105            CheckerTypes,
106        },
107        decoders::interface::{Crack, Decoder},
108    };
109
110    // helper for tests
111    fn get_athena_checker() -> CheckerTypes {
112        let athena_checker = Checker::<Athena>::new();
113        CheckerTypes::CheckAthena(athena_checker)
114    }
115
116    #[test]
117    fn base65536_decodes_successfully() {
118        // This tests if Base65536 can decode Base65536 successfully
119        let base65536_decoder = Decoder::<Base65536Decoder>::new();
120        let result = base65536_decoder.crack("𒅓鹨𖡮𒀠啦ꍢ顡啫𓍱𓁡𠁴唬𓍪鱤啥𖥭𔐠𔕯ᔮ", &get_athena_checker());
121        assert_eq!(
122            result.unencrypted_text.unwrap()[0],
123            "Sphinx of black quartz, judge my vow."
124        );
125    }
126
127    #[test]
128    fn base65536_handles_panics() {
129        // This tests if Base65536 can handle panics
130        // It should return None
131        let base65536_decoder = Decoder::<Base65536Decoder>::new();
132        let result = base65536_decoder
133            .crack(
134                "hello my name is panicky mc panic face!",
135                &get_athena_checker(),
136            )
137            .unencrypted_text;
138        assert!(result.is_none());
139    }
140
141    #[test]
142    fn base65536_handles_panic_if_empty_string() {
143        // This tests if Base65536 can handle an empty string
144        // It should return None
145        let base65536_decoder = Decoder::<Base65536Decoder>::new();
146        let result = base65536_decoder
147            .crack("", &get_athena_checker())
148            .unencrypted_text;
149        assert!(result.is_none());
150    }
151
152    #[test]
153    fn base65536_handles_panic_if_emoji() {
154        // This tests if Base65536 can handle an emoji
155        // It should return None
156        let base65536_decoder = Decoder::<Base65536Decoder>::new();
157        let result = base65536_decoder
158            .crack("😂", &get_athena_checker())
159            .unencrypted_text;
160        assert!(result.is_none());
161    }
162}