Skip to content

Commit

Permalink
Refactoring + Improved String Normalization + Added the `/decode_auto…
Browse files Browse the repository at this point in the history
…`, `/decode_auto/{charset}`, `/decode_quoted_printable` and `/decode_quoted_printable/{charset}`
  • Loading branch information
DK26 committed Jul 27, 2021
1 parent a5ae1da commit a3d8939
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 36 deletions.
8 changes: 6 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ lazy_static! {

}

pub const DEFAULT_ENCODING : &'static str = "utf-8";
pub const DEFAULT_CHARSET : &'static str = "utf-8";

#[actix_web::main]
async fn main() -> std::io::Result<()> {
Expand Down Expand Up @@ -184,11 +184,15 @@ async fn main() -> std::io::Result<()> {
.service(services::unescape)
// .service(services::form_test)
// .service(services::json_test)
.service(services::unescape_decode)
.service(services::unescape_charset)
.service(services::decode_base64)
.service(services::decode_base64_charset)
.service(services::decode_mime_header)
.service(services::decode_mime_header_rfc822)
.service(services::decode_quoted_printable)
.service(services::decode_quoted_printable_charset)
.service(services::decode_auto)
.service(services::decode_auto_charset)
.service(services::regex_capture_group)
})
.server_hostname(&CFG.service.server_hostname)
Expand Down
87 changes: 59 additions & 28 deletions src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use actix_web::{
use mailparse::parse_header;

use crate::utils;
use crate::DEFAULT_ENCODING;
use crate::DEFAULT_CHARSET;
use crate::PATTERNS_CACHE;

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -38,14 +38,14 @@ pub async fn unescape(req_body: String) -> impl Responder {

let unescaped_req_body = utils::unescape_as_bytes(&req_body).expect("Unable to unescape request's body.");

let response = utils::attempt_decode(&unescaped_req_body, &DEFAULT_ENCODING).unwrap();
let response = utils::attempt_decode(&unescaped_req_body, &DEFAULT_CHARSET).unwrap();

HttpResponse::Ok().body(response)

}

#[post("/unescape/{charset}")]
pub async fn unescape_decode(web::Path((charset,)): web::Path<(String,)>, req_body: String) -> impl Responder {
pub async fn unescape_charset(web::Path((charset,)): web::Path<(String,)>, req_body: String) -> impl Responder {

let unescaped_req_body = utils::unescape_as_bytes(&req_body).expect("Unable to unescape request's body.");

Expand All @@ -55,12 +55,46 @@ pub async fn unescape_decode(web::Path((charset,)): web::Path<(String,)>, req_bo

}

#[post("/decode_quoted_printable")]
pub async fn decode_quoted_printable(req_body: String) -> impl Responder {

// let response = match quoted_printable::decode(&req_body, quoted_printable::ParseMode::Robust) {
// Ok(v) => {
// utils::attempt_decode(&v, &DEFAULT_CHARSET).unwrap()
// },
// Err(_) => {
// return HttpResponse::Ok().body(req_body)
// }
// };

let response = utils::decode_quoted_printable(req_body,&DEFAULT_CHARSET);

HttpResponse::Ok().body(response)

}

#[post("/decode_quoted_printable/{charset}")]
pub async fn decode_quoted_printable_charset(web::Path((charset,)): web::Path<(String,)>, req_body: String) -> impl Responder {

let response = match quoted_printable::decode(&req_body, quoted_printable::ParseMode::Robust) {
Ok(v) => {
utils::attempt_decode(&v, &charset).unwrap()
},
Err(_) => {
return HttpResponse::Ok().body(req_body)
}
};

HttpResponse::Ok().body(response)

}

#[post("/decode_base64")]
pub async fn decode_base64(req_body: String) -> impl Responder {

let raw_payload = base64::decode(&req_body).expect("Unable to decode base64.");

let response = utils::attempt_decode(&raw_payload, &DEFAULT_ENCODING).unwrap();
let response = utils::attempt_decode(&raw_payload, &DEFAULT_CHARSET).unwrap();

HttpResponse::Ok().body(response)

Expand All @@ -80,7 +114,7 @@ pub async fn decode_base64_charset(web::Path((charset,)): web::Path<(String,)>,
#[post("/decode_mime_header")]
pub async fn decode_mime_header(req_body: String) -> impl Responder {

let normalized_req_body = utils::normalize_mime(&req_body);
let normalized_req_body = utils::normalize_str(&req_body);

// let response: String = normalized_req_body.lines()
// .map(|x| {
Expand All @@ -92,29 +126,7 @@ pub async fn decode_mime_header(req_body: String) -> impl Responder {
// .map(|x| utils::attempt_decode(&x, &DEFAULT_ENCODING).unwrap())
// .collect();

let mut response = String::new();

for line in normalized_req_body.lines() {

let trimmed_line = line.trim_start();

if trimmed_line.starts_with("=?") && trimmed_line.ends_with("?=") {

let prefixed_line = format!(":{}", trimmed_line);
let (parsed, _) = parse_header(prefixed_line.as_bytes()).unwrap();
response.push_str(&parsed.get_value())

} else {

if trimmed_line.contains("\\x") || trimmed_line.contains("\\u") {
let unescaped_line_bytes = utils::unescape_as_bytes(&trimmed_line).expect("Unable to unescape request's body.");
let unescaped_line = utils::attempt_decode(&unescaped_line_bytes, &DEFAULT_ENCODING).unwrap();
response.push_str(&unescaped_line)
} else {
response.push_str(&trimmed_line)
}
}
}
let response = utils::decode_mime_header(&normalized_req_body);

HttpResponse::Ok().body(response)

Expand All @@ -129,6 +141,25 @@ pub async fn decode_mime_header_rfc822(req_body: web::Bytes) -> impl Responder {

}

#[post("/decode_auto")]
pub async fn decode_auto(req_body: String) -> impl Responder {

let response = utils::auto_decode(req_body, DEFAULT_CHARSET);

HttpResponse::Ok().body(response)

}

#[post("/decode_auto/{charset}")]
pub async fn decode_auto_charset(web::Path((charset,)): web::Path<(String,)>, req_body: String) -> impl Responder {

let response = utils::auto_decode(req_body, &charset);

HttpResponse::Ok().body(response)

}


#[post("/regex_capture_group")]
pub async fn regex_capture_group(request: web::Json<RegexData>) -> impl Responder {

Expand Down
78 changes: 72 additions & 6 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::char;
use base64::DecodeError;
use quoted_printable::QuotedPrintableError;
use regex::Regex;
use crate::DEFAULT_CHARSET;

// use std::string::FromUtf8Error;
use encoding::{
Expand Down Expand Up @@ -396,21 +397,86 @@ pub fn attempt_decode(src: &[u8], encoding: &str) -> DecodingResult {

}

pub fn normalize_mime(mime: &str) -> String {
pub fn normalize_str(string: &str) -> String {

let mime = mime
let normalized_string = string
.replace(r"\\", "\\")
.replace(r"\n","\n")
.replace(r"\r","\r")
.replace(r"\t","\t")
.replace(r"\=", "=")
.replace(" =?", "\r\n=?")
.replace("?= ", "?=\r\n");
mime
.replace(" =?", " \r\n=?")
.replace("?= ", "?=\r\n ");

normalized_string

}

pub fn decode_mime_header(src: &str) -> String {

let mut result = String::new();

for line in src.lines() {

let trimmed_line = line.trim_start();

if trimmed_line.starts_with("=?") && trimmed_line.ends_with("?=") {

let prefixed_line = format!(":{}", trimmed_line);
let (parsed, _) = mailparse::parse_header(prefixed_line.as_bytes()).unwrap();

result.push_str(&parsed.get_value())

} else {

if trimmed_line.contains("\\x") || trimmed_line.contains("\\u") {

let unescaped_line_bytes = unescape_as_bytes(&trimmed_line).unwrap();
let unescaped_line = attempt_decode(&unescaped_line_bytes, &DEFAULT_CHARSET).unwrap();

result.push_str(&unescaped_line)

} else { result.push_str(&trimmed_line) }

}

}

result

}

pub fn decode_quoted_printable(src: String, charset: &str) -> String {
match quoted_printable::decode(&src, quoted_printable::ParseMode::Robust) {
Ok(v) => {
attempt_decode(&v, &charset).unwrap()
},
Err(_) => {
src
}
}
}

pub fn auto_decode(src: String, charset: &str) -> String {

let src_normalized = normalize_str(&src);

// Sketch
let src_normalized_upper = src_normalized.to_uppercase();

if src_normalized_upper.contains("?Q?") || src_normalized_upper.contains("?B?") {

decode_mime_header(&src_normalized)

} else if src_normalized.contains("\\x") || src_normalized.contains("\\u") {

let unescaped_bytes = unescape_as_bytes(&src_normalized).unwrap();

attempt_decode(&unescaped_bytes, charset).unwrap()

} else {
decode_quoted_printable(src, charset)
}
}

enum MimeEncoding {
Base64Encoding,
Expand Down

0 comments on commit a3d8939

Please sign in to comment.