ares/decoders/
base64_url_decoder.rs1use 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
15pub struct Base64URLDecoder;
34
35impl Crack for Decoder<Base64URLDecoder> {
36 fn new() -> Decoder<Base64URLDecoder> {
37 Decoder {
38 name: "Base64 URL",
39 description: "Modified Base64 for URL variants exist (such as base64url in RFC 4648), where the '+' and '/' characters of standard Base64 are respectively replaced by '-' and '_', so that using URL encoders/decoders is no longer necessary.",
40 link: "https://en.wikipedia.org/wiki/Base64#URL_applications",
41 tags: vec!["base64_url", "base64", "url", "decoder", "base"],
42 popularity: 0.9,
43 phantom: std::marker::PhantomData,
44 }
45 }
46
47 fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
51 trace!("Trying base64_url with text {:?}", text);
52 let decoded_text = decode_base64_url_no_error_handling(text);
53 let mut results = CrackResult::new(self, text.to_string());
54
55 if decoded_text.is_none() {
56 debug!("Failed to decode base64_url because Base64URLDecoder::decode_base64_url_no_error_handling returned None");
57 return results;
58 }
59
60 let decoded_text = decoded_text.unwrap();
61 if !check_string_success(&decoded_text, text) {
62 info!(
63 "Failed to decode base64_url because check_string_success returned false on string {}",
64 decoded_text
65 );
66 return results;
67 }
68
69 let checker_result = checker.check(&decoded_text);
70 results.unencrypted_text = Some(vec![decoded_text]);
71
72 results.update_checker(&checker_result);
73
74 results
75 }
76 fn get_tags(&self) -> &Vec<&str> {
78 &self.tags
79 }
80 fn get_name(&self) -> &str {
82 self.name
83 }
84}
85
86fn decode_base64_url_no_error_handling(text: &str) -> Option<String> {
88 base64::decode_engine(
91 text.as_bytes(),
92 &base64::engine::fast_portable::FastPortable::from(
93 &base64::alphabet::URL_SAFE,
94 base64::engine::fast_portable::PAD,
95 ),
96 )
97 .ok()
98 .map(|inner| String::from_utf8(inner).ok())?
99}
100
101#[cfg(test)]
102mod tests {
103 use super::Base64URLDecoder;
104 use crate::{
105 checkers::{
106 athena::Athena,
107 checker_type::{Check, Checker},
108 CheckerTypes,
109 },
110 decoders::interface::{Crack, Decoder},
111 };
112
113 fn get_athena_checker() -> CheckerTypes {
115 let athena_checker = Checker::<Athena>::new();
116 CheckerTypes::CheckAthena(athena_checker)
117 }
118
119 #[test]
120 fn base64_url_decodes_successfully() {
121 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
124 let result = base64_url_decoder.crack(
125 "aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8_ZXhhbXBsZT10ZXN0",
126 &get_athena_checker(),
127 );
128 assert_eq!(
129 result.unencrypted_text.unwrap()[0],
130 "https://www.google.com/?example=test"
131 );
132 }
133
134 #[test]
135 fn base64_url_decodes_regular_base64_successfully() {
136 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
139 let result = base64_url_decoder.crack(
140 "VGhpcyBpcyBkZWNvZGFibGUgYnkgYm90aCBCYXNlNjQgYW5kIEJhc2U2NCBVUkw=",
141 &get_athena_checker(),
142 );
143 assert_eq!(
144 result.unencrypted_text.unwrap()[0],
145 "This is decodable by both Base64 and Base64 URL"
146 );
147 }
148
149 #[test]
150 fn base64_url_handles_regular_base64_with_plus_signs() {
151 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
155 let result = base64_url_decoder
156 .crack(
157 "VGhpcyBpc24ndCA+Pj4+IGRlY29kYWJsZSBieSBCYXNlNjQgVVJM",
158 &get_athena_checker(),
159 )
160 .unencrypted_text;
161 assert!(result.is_none());
162 }
163
164 #[test]
165 fn base64_url_handles_regular_base64_with_slashes() {
166 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
170 let result = base64_url_decoder
171 .crack(
172 "aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8/ZXhhbXBsZT10ZXN0",
173 &get_athena_checker(),
174 )
175 .unencrypted_text;
176 assert!(result.is_none());
177 }
178
179 #[test]
180 fn base64_url_handles_panics() {
181 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
184 let result = base64_url_decoder
185 .crack(
186 "hello my name is panicky mc panic face!",
187 &get_athena_checker(),
188 )
189 .unencrypted_text;
190 assert!(result.is_none());
191 }
192
193 #[test]
194 fn base64_url_handles_panic_if_empty_string() {
195 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
198 let result = base64_url_decoder
199 .crack("", &get_athena_checker())
200 .unencrypted_text;
201 assert!(result.is_none());
202 }
203
204 #[test]
205 fn base64_url_handles_panic_if_emoji() {
206 let base64_url_decoder = Decoder::<Base64URLDecoder>::new();
209 let result = base64_url_decoder
210 .crack("😂", &get_athena_checker())
211 .unencrypted_text;
212 assert!(result.is_none());
213 }
214}