1pub use action::Action;
2pub use filter::Filter;
3pub use handler::*;
4use hyper::{header, header::HeaderValue, Body, Request, Response, StatusCode};
5use log::*;
6use mitm_core::mitm::RequestOrResponse;
7use std::vec::Vec;
8
9mod action;
10mod cache;
11mod filter;
12mod handler;
13
14#[derive(Debug, Clone)]
15pub struct Rule {
16 pub filters: Vec<Filter>,
17 pub actions: Vec<Action>,
18
19 pub url: Option<String>,
20}
21
22impl Rule {
23 pub async fn do_req(&mut self, req: Request<Body>) -> RequestOrResponse {
24 let url = req.uri().to_string();
25 self.url = Some(url.clone());
26 let mut tmp_req = req;
27
28 for action in &self.actions {
29 match action {
30 Action::Reject => {
31 info!("[Reject] {}", url);
32 let res = Response::builder()
33 .status(StatusCode::BAD_GATEWAY)
34 .body(Body::default())
35 .unwrap();
36
37 return RequestOrResponse::Response(res);
38 }
39
40 Action::Redirect(target) => {
41 if target.contains('$') {
42 for filter in self.filters.clone() {
43 if let Filter::UrlRegex(re) = filter {
44 let target = cache::get_regex(&re)
45 .replace(tmp_req.uri().to_string().as_str(), target.as_str())
46 .to_string();
47 if let Ok(target_url) = HeaderValue::from_str(target.as_str()) {
48 let mut res = Response::builder()
49 .status(StatusCode::FOUND)
50 .body(Body::default())
51 .unwrap();
52 res.headers_mut().insert(header::LOCATION, target_url);
53 info!("[Redirect] {} -> {}", url, target);
54 return RequestOrResponse::Response(res);
55 }
56 }
57 }
58 }
59 if let Ok(target_url) = HeaderValue::from_str(target.as_str()) {
60 let mut res = Response::builder()
61 .status(StatusCode::FOUND)
62 .body(Body::default())
63 .unwrap();
64 res.headers_mut().insert(header::LOCATION, target_url);
65 info!("[Redirect] {} -> {}", url, target);
66 return RequestOrResponse::Response(res);
67 };
68 }
69
70 Action::ModifyRequest(modify) => {
71 info!("[ModifyRequest] {}", url);
72 match modify.modify_req(tmp_req).await {
73 Some(new_req) => tmp_req = new_req,
74 None => {
75 return RequestOrResponse::Response(
76 Response::builder()
77 .status(StatusCode::BAD_REQUEST)
78 .body(Body::default())
79 .unwrap(),
80 );
81 }
82 }
83 }
84
85 Action::LogReq => {
86 info!("[LogRequest] {}", url);
87 action::log_req(&tmp_req).await;
88 }
89
90 #[cfg(feature = "js")]
91 Action::Js(ref code) => {
92 info!("[LogRequest] {}", url);
93 if let Ok(req) = action::js::modify_req(code, tmp_req).await {
94 return RequestOrResponse::Request(req);
95 } else {
96 return RequestOrResponse::Response(
97 Response::builder()
98 .status(StatusCode::BAD_REQUEST)
99 .body(Body::default())
100 .unwrap(),
101 );
102 }
103 }
104 _ => {}
105 }
106 }
107
108 RequestOrResponse::Request(tmp_req)
109 }
110
111 pub async fn do_res(&self, res: Response<Body>) -> Response<Body> {
112 let url = self.url.clone().unwrap_or_default();
113 let mut tmp_res = res;
114
115 for action in &self.actions {
116 match action {
117 Action::ModifyResponse(modify) => {
118 info!("[ModifyResponse] {}", url);
119 tmp_res = modify.modify_res(tmp_res).await
120 }
121 Action::LogRes => {
122 info!("[LogResponse] {}", url);
123 action::log_res(&tmp_res).await;
124 }
125
126 #[cfg(feature = "js")]
127 Action::Js(ref code) => {
128 info!("[LogResponse] {}", url);
129 if let Ok(res) = action::js::modify_res(code, tmp_res).await {
130 return res;
131 } else {
132 return Response::builder()
133 .status(StatusCode::BAD_REQUEST)
134 .body(Body::default())
135 .unwrap();
136 }
137 }
138 _ => {}
139 }
140 }
141
142 tmp_res
143 }
144}