1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::checkers::CheckerTypes;

use super::crack_results::CrackResult;
///! Reverses the input string
///! Performs error handling and returns a string
///! Call reverse_decoder.crack to use. It returns option<String> and check with
///! `result.is_some()` to see if it returned okay.
///
use super::interface::Crack;
use super::interface::Decoder;

use log::trace;
/// The Reverse decoder is a decoder that reverses the input string.
/// ```rust
/// use ares::decoders::reverse_decoder::ReverseDecoder;
/// use ares::decoders::interface::{Crack, Decoder};
/// use ares::config::{set_global_config, Config};
/// use ares::checkers::{athena::Athena, CheckerTypes, checker_type::{Check, Checker}};
///
/// let reversedecoder = Decoder::<ReverseDecoder>::new();
/// let athena_checker = Checker::<Athena>::new();
/// let checker = CheckerTypes::CheckAthena(athena_checker);
///
/// let result = reversedecoder.crack("stac", &checker).unencrypted_text;
/// assert!(result.is_some());
/// assert_eq!(result.unwrap()[0], "cats");
/// ```
pub struct ReverseDecoder;

impl Crack for Decoder<ReverseDecoder> {
    fn new() -> Decoder<ReverseDecoder> {
        Decoder {
            name: "Reverse",
            description: "Reverses a string. stac -> cats",
            link: "http://string-functions.com/reverse.aspx",
            tags: vec!["reverse", "decoder"],
            /// We expect it to take 0.01 seconds to run
            expected_runtime: 0.01,
            expected_success: 1.0,
            /// If it was to fail, we'd expect it to take 0.01 seconds
            failure_runtime: 0.01,
            normalised_entropy: vec![1.0, 10.0],
            // I have never seen a reversed string in a CTF
            // or otherwise
            popularity: 0.2,
            phantom: std::marker::PhantomData,
        }
    }

    /// This function does the actual decoding
    /// It returns an Option<string> if it was successful
    /// Else the Option returns nothing and the error is logged in Trace
    fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
        trace!("Running reverse string");
        let mut result = CrackResult::new(self, text.to_string());
        if text.is_empty() {
            return result;
        }
        let rev_str: String = text.chars().rev().collect();
        let checker_res = checker.check(&rev_str);

        result.unencrypted_text = Some(vec![rev_str]);
        result.update_checker(&checker_res);
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        checkers::{
            athena::Athena,
            checker_type::{Check, Checker},
        },
        decoders::interface::Crack,
    };

    // helper for tests
    fn get_athena_checker() -> CheckerTypes {
        let athena_checker = Checker::<Athena>::new();
        CheckerTypes::CheckAthena(athena_checker)
    }

    #[test]
    fn returns_success() {
        let reverse_decoder = Decoder::<ReverseDecoder>::new();
        let result = reverse_decoder
            .crack("stac", &get_athena_checker())
            .unencrypted_text
            .expect("No unencrypted string for reverse decoder");
        assert_eq!(result[0], "cats");
    }

    #[test]
    fn returns_nothing() {
        let reverse_decoder = Decoder::<ReverseDecoder>::new();
        let result = reverse_decoder
            .crack("", &get_athena_checker())
            .unencrypted_text;
        assert!(result.is_none());
    }
}