use crate::checkers::CheckerTypes;
use crate::decoders::interface::check_string_success;
use super::crack_results::CrackResult;
use super::interface::Crack;
use super::interface::Decoder;
use log::{debug, info, trace};
pub struct MorseCodeDecoder;
impl Crack for Decoder<MorseCodeDecoder> {
fn new() -> Decoder<MorseCodeDecoder> {
Decoder {
name: "Morse Code",
description: "Morse code is a method used in telecommunication to encode text characters as standardized sequences of two different signal durations, called dots and dashes, or dits and dahs.",
link: "https://en.wikipedia.org/wiki/Morse_code",
tags: vec!["morseCode", "decoder", "signals"],
popularity: 0.5,
phantom: std::marker::PhantomData,
}
}
fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
trace!("Trying Morse Code with text {:?}", text);
let text = normalise_morse_string(text);
let decoded_text: Option<String> = text.split(' ').map(morse_to_alphanumeric).collect();
trace!("Decoded text for morse code: {:?}", decoded_text);
let mut results = CrackResult::new(self, text.to_string());
if decoded_text.is_none() {
debug!("Failed to decode Morse Code because a character was not in the dictionary");
return results;
}
let decoded_text = decoded_text.unwrap();
if !check_string_success(&decoded_text, &text) {
info!(
"Failed to decode morse code because check_string_success returned false on string {}",
decoded_text
);
return results;
}
let checker_result = checker.check(&decoded_text);
results.unencrypted_text = Some(vec![decoded_text]);
results.update_checker(&checker_result);
results
}
fn get_tags(&self) -> &Vec<&str> {
&self.tags
}
fn get_name(&self) -> &str {
self.name
}
}
fn normalise_morse_string(text: &str) -> String {
text.to_lowercase()
.replace(['\n', '\r'], "")
.replace("\\n", "")
.replace("\\r", "")
.replace('\\', "")
}
fn morse_to_alphanumeric(text: &str) -> Option<&str> {
trace!("Starting to map morse code to alphanumeric");
let result = match text {
".-" => "A",
"-..." => "B",
"-.-." => "C",
"-.." => "D",
"." => "E",
"..-." => "F",
"--." => "G",
"...." => "H",
".." => "I",
".---" => "J",
"-.-" => "K",
".-.." => "L",
"--" => "M",
"-." => "N",
"---" => "O",
".--." => "P",
"--.-" => "Q",
".-." => "R",
"..." => "S",
"-" => "T",
"..-" => "U",
"...-" => "V",
".--" => "W",
"-..-" => "X",
"-.--" => "Y",
"--.." => "Z",
".----" => "1",
"..---" => "2",
"...--" => "3",
"....-" => "4",
"....." => "5",
"-...." => "6",
"--..." => "7",
"---.." => "8",
"----." => "9",
"-----" => "0",
".-..." => "&",
".--.-." => "@",
"---..." => ":",
"--..--" => ",",
".-.-.-" => ".",
".----." => "'",
".-..-." => "\"",
"..--.." => "?",
"-..-." => "/",
"-...-" => "=",
".-.-." => "+",
"-....-" => "-",
"-.--." => "(",
"-.--.-" => ")",
"/" => " ",
"-.-.--" => "!",
" " => " ",
"" => "",
"\n" => " ",
"\r" => " ",
_ => return None,
};
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::checkers::athena::Athena;
use crate::checkers::checker_type::{Check, Checker};
use crate::checkers::CheckerTypes;
use crate::decoders::interface::Crack;
fn get_athena_checker() -> CheckerTypes {
let athena_checker = Checker::<Athena>::new();
CheckerTypes::CheckAthena(athena_checker)
}
#[test]
fn test_morse_code() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
".---- ----. ..--- .-.-.- .---- -.... ---.. .-.-.- ----- .-.-.- .----",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "192.168.0.1");
}
#[test]
fn test_morse_code_new_line() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
".---- ----. ..--- .-.-.- .---- -.... ---.. .-.-.- ----- .-.-.- .----\n",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "192.168.0.1");
}
#[test]
fn test_morse_code_new_line_with_space() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
".---- ----. ..--- .-.-.- .---- -.... ---.. .-.-.- ----- .-.-.- .---- \n",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "192.168.0.1");
}
#[test]
fn test_morse_code_carrage_arrage_return_with_space() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
".---- ----. ..--- .-.-.- .---- -.... ---.. .-.-.- ----- .-.-.- .---- \r",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "192.168.0.1");
}
#[test]
fn test_morse_code_both_new_line_and_carrage_return() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
".---- ----. \n..--- .-.-.- \r.---- -.... ---.. .-.-.- ----- .-.-.- .---- \r",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "192.168.0.1");
}
#[test]
#[ignore]
fn test_morse_code_backslash() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
r".... . .-.. .-.. ---\.-- --- .-. .-.. -.. -.-.--",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "hello world!");
}
#[test]
#[ignore]
fn test_morse_code_line_feed() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
r".... . .-.. .-.. ---
.-- --- .-. .-.. -.. -.-.--",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "hello world!");
}
#[test]
#[ignore]
fn test_morse_code_comma() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
r".... . .-.. .-.. ---,.-- --- .-. .-.. -.. -.-.--",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "hello world!");
}
#[test]
#[ignore]
fn test_morse_code_colon() {
let decoder = Decoder::<MorseCodeDecoder>::new();
let result = decoder.crack(
r".... . .-.. .-.. ---:.-- --- .-. .-.. -.. -.-.--",
&get_athena_checker(),
);
assert_eq!(result.unencrypted_text.unwrap()[0], "hello world!");
}
}