393 lines
10 KiB
Rust
393 lines
10 KiB
Rust
#![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
#[macro_use]
|
|
extern crate rocket;
|
|
|
|
use request_mirror::schema::{history, pair_records};
|
|
use rocket::{data, request, Outcome, Request, Data};
|
|
use rocket::data::FromDataSimple;
|
|
use rocket::request::FromRequest;
|
|
use rocket_contrib::templates::Template;
|
|
use serde::Serialize;
|
|
use rocket::http::{Cookie, Cookies, Status};
|
|
use uuid::Uuid;
|
|
use std::io::Read;
|
|
use request_mirror::models::*;
|
|
use diesel::prelude::*;
|
|
use request_mirror::*;
|
|
|
|
#[derive(Serialize, Debug, Clone)]
|
|
enum PairType {
|
|
Header,
|
|
Cookie,
|
|
Query,
|
|
Body
|
|
}
|
|
|
|
#[derive(Serialize, Debug, Clone)]
|
|
struct Pair {
|
|
key: String,
|
|
value: String
|
|
}
|
|
|
|
#[derive(Serialize, Debug, Clone)]
|
|
struct RequestInfo {
|
|
header: Vec<Pair>,
|
|
cookies: Vec<Pair>,
|
|
query: Vec<Pair>
|
|
}
|
|
|
|
#[derive(Serialize, Debug, Clone)]
|
|
struct RequestBody(String);
|
|
|
|
#[derive(Debug)]
|
|
enum ApiError {
|
|
}
|
|
#[derive(Serialize)]
|
|
|
|
struct ErrorContext {
|
|
error_msg: String
|
|
}
|
|
|
|
// Always use a limit to prevent DoS attacks.
|
|
const LIMIT: u64 = 256;
|
|
|
|
impl<'a, 'r> FromRequest<'a, 'r> for RequestInfo {
|
|
type Error = ApiError;
|
|
|
|
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
|
let mut req_cookies = request.cookies();
|
|
|
|
for row in req_cookies.iter() {
|
|
println!("{}: {}", row.name(), row.value());
|
|
}
|
|
// Initially set cookie
|
|
if req_cookies.get(&"mirror-id").is_none() {
|
|
|
|
let new_uuid = Uuid::new_v4().to_string();
|
|
|
|
println!("Creating new cookie");
|
|
|
|
req_cookies.add(Cookie::new("mirror-id", new_uuid.clone()));
|
|
|
|
let address = if request.client_ip().is_some() {
|
|
request.client_ip().unwrap().to_string()
|
|
} else {
|
|
"Unknown".to_string()
|
|
};
|
|
|
|
let connection = &mut establish_connection();
|
|
|
|
create_client(connection, &address, &new_uuid);
|
|
}
|
|
|
|
let mut header: Vec<Pair> = vec![];
|
|
let mut cookies: Vec<Pair> = vec![];
|
|
let mut query: Vec<Pair> = vec![];
|
|
|
|
// Compile header
|
|
for row in request.headers().clone().into_iter() {
|
|
let key: String = row.name().to_string();
|
|
let value: String = row.value().to_string();
|
|
|
|
header.push(Pair{key:key, value:value});
|
|
}
|
|
|
|
// Compile cookies
|
|
for row in req_cookies.iter() {
|
|
let key: String = row.name().to_string();
|
|
let value: String = row.value().to_string();
|
|
|
|
cookies.push(Pair{key:key, value:value});
|
|
}
|
|
|
|
// Compile query
|
|
let request_query = request.raw_query_items();
|
|
if request_query.is_some() {
|
|
for row in request_query.unwrap() {
|
|
let (key, value) = row.key_value_decoded();
|
|
|
|
query.push(Pair{key:key, value:value});
|
|
}
|
|
}
|
|
|
|
Outcome::Success(RequestInfo{
|
|
header: header,
|
|
cookies: cookies,
|
|
query: query
|
|
})
|
|
}
|
|
}
|
|
|
|
impl FromDataSimple for RequestBody {
|
|
type Error = String;
|
|
|
|
fn from_data(_req: &Request, data: Data) -> data::Outcome<Self, String> {
|
|
// Read the data into a String.
|
|
let mut string = String::new();
|
|
if let Err(e) = data.open().take(LIMIT).read_to_string(&mut string) {
|
|
return Outcome::Failure((Status::InternalServerError, format!("{:?}", e)));
|
|
}
|
|
|
|
// Return successfully.
|
|
Outcome::Success(RequestBody(string))
|
|
}
|
|
}
|
|
|
|
#[get("/")]
|
|
fn index(_info: RequestInfo) -> Template {
|
|
|
|
//Redirect::to("/test")
|
|
|
|
#[derive(Serialize)]
|
|
struct Context{
|
|
}
|
|
|
|
Template::render("index", Context {})
|
|
}
|
|
|
|
#[get("/test")]
|
|
fn test_get(request: RequestInfo, cookies: Cookies) -> Template {
|
|
|
|
println!("{request:?}");
|
|
|
|
let cookie_id = cookies.get("mirror-id");
|
|
|
|
if cookie_id.is_some() {
|
|
let connection = &mut establish_connection();
|
|
let history_id = create_history_record(connection, cookie_id.unwrap().value(), "Get");
|
|
|
|
println!("Creating header Records for {history_id}");
|
|
|
|
for row in &request.header {
|
|
create_pair_record(connection, history_id, PairType::Header as i32, &row.key, &row.value);
|
|
}
|
|
|
|
println!("Creating cookie Records for {history_id}");
|
|
|
|
for row in &request.cookies {
|
|
create_pair_record(connection, history_id, PairType::Cookie as i32, &row.key, &row.value);
|
|
}
|
|
|
|
println!("Creating query Records for {history_id}");
|
|
|
|
for row in &request.query {
|
|
create_pair_record(connection, history_id, PairType::Query as i32, &row.key, &row.value);
|
|
}
|
|
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct Context<'a> {
|
|
request_type: &'a str,
|
|
header: Vec<Pair>,
|
|
cookies: Vec<Pair>,
|
|
query: Vec<Pair>,
|
|
}
|
|
|
|
let context = Context {
|
|
request_type: "Get",
|
|
header: request.header,
|
|
cookies: request.cookies,
|
|
query: request.query
|
|
};
|
|
|
|
Template::render("request_details", context)
|
|
}
|
|
|
|
#[post("/test", data = "<body>")]
|
|
fn test_post(body: RequestBody, request: RequestInfo, cookies: Cookies) -> Template {
|
|
|
|
println!("{request:?}");
|
|
|
|
println!("Input: {}", body.0);
|
|
|
|
let cookie_id = cookies.get("mirror-id");
|
|
|
|
if cookie_id.is_some() {
|
|
let connection = &mut establish_connection();
|
|
let history_id = create_history_record(connection, cookie_id.unwrap().value(), "Post");
|
|
|
|
println!("Creating header Records for {history_id}");
|
|
|
|
for row in &request.header {
|
|
create_pair_record(connection, history_id, PairType::Header as i32, &row.key, &row.value);
|
|
}
|
|
|
|
println!("Creating cookie Records for {history_id}");
|
|
|
|
for row in &request.cookies {
|
|
create_pair_record(connection, history_id, PairType::Cookie as i32, &row.key, &row.value);
|
|
}
|
|
|
|
println!("Creating query Records for {history_id}");
|
|
|
|
for row in &request.query {
|
|
create_pair_record(connection, history_id, PairType::Query as i32, &row.key, &row.value);
|
|
}
|
|
|
|
println!("Creating body Records for {history_id}");
|
|
create_pair_record(connection, history_id, PairType::Body as i32, "body", &body.0.clone());
|
|
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct Context<'a> {
|
|
request_type: &'a str,
|
|
header: Vec<Pair>,
|
|
cookies: Vec<Pair>,
|
|
query: Vec<Pair>,
|
|
body: String
|
|
}
|
|
|
|
let context = Context {
|
|
request_type: "Post",
|
|
header: request.header,
|
|
cookies: request.cookies,
|
|
query: request.query,
|
|
body: body.0
|
|
};
|
|
|
|
Template::render("request_details", context)
|
|
}
|
|
|
|
#[get("/history")]
|
|
fn history_req(cookies: Cookies) -> Template {
|
|
|
|
let cookie_id = cookies.get("mirror-id");
|
|
|
|
let cookie_id = cookie_id.unwrap().value();
|
|
println!("Client ID: {}", cookie_id);
|
|
|
|
let connection = &mut establish_connection();
|
|
let results = history::dsl::history
|
|
.filter(history::client_id.eq(cookie_id.to_string()))
|
|
.select(HistoryRecord::as_select())
|
|
.load(connection)
|
|
.expect("Error loading clients");
|
|
|
|
for record in results.iter() {
|
|
println!("{:?}", record);
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct History {
|
|
pub id: i32,
|
|
pub client_id: String,
|
|
pub request_type: String,
|
|
pub timestamp: String
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct Context {
|
|
history_records: Vec<History>
|
|
}
|
|
|
|
let mut history_records: Vec<History> = Vec::new();
|
|
|
|
for history_rec in results {
|
|
history_records.push(
|
|
History {
|
|
id: history_rec.id,
|
|
client_id: history_rec.client_id,
|
|
request_type: history_rec.request_type,
|
|
timestamp: history_rec.timestamp.format("%Y-%m-%d %H:%M:%S UTC").to_string()
|
|
}
|
|
);
|
|
}
|
|
|
|
Template::render("history", Context{
|
|
history_records: history_records
|
|
})
|
|
|
|
}
|
|
|
|
#[get("/history/<history_id>")]
|
|
fn history_details(history_id: i32, cookies: Cookies) -> Template {
|
|
|
|
let cookie_id = cookies.get("mirror-id");
|
|
|
|
let cookie_id = cookie_id.unwrap().value();
|
|
println!("Client ID: {}", cookie_id);
|
|
|
|
let connection = &mut establish_connection();
|
|
let results: Vec<HistoryRecord> = history::dsl::history
|
|
.filter(history::id.eq(&history_id))
|
|
.filter(history::client_id.eq(cookie_id.to_string()))
|
|
.select(HistoryRecord::as_select())
|
|
.load(connection)
|
|
.expect("Error loading history records");
|
|
|
|
if results.len() <= 0 {
|
|
|
|
// Error
|
|
return Template::render(
|
|
"error",
|
|
ErrorContext{ error_msg: "No Results Found. You may be unauthorized...".to_string() }
|
|
);
|
|
}
|
|
|
|
let connection = &mut establish_connection();
|
|
|
|
let pairs: Vec<PairRecord> = pair_records::dsl::pair_records
|
|
.filter(pair_records::history_id.eq(history_id))
|
|
.select(PairRecord::as_select())
|
|
.load(connection)
|
|
.expect("Error loading history records");
|
|
|
|
let body: String = match &pairs.iter().filter(|res| res.pair_type == PairType::Body as i32).last() {
|
|
Some(pair) => pair.value.clone(),
|
|
_ => "".to_string()
|
|
};
|
|
|
|
let header: Vec<&PairRecord> = pairs.iter()
|
|
.filter(|res: &&PairRecord| res.pair_type == PairType::Header as i32)
|
|
.map(|res: &PairRecord| res)
|
|
.collect();
|
|
|
|
let cookies: Vec<&PairRecord> = pairs.iter()
|
|
.filter(|res: &&PairRecord| res.pair_type == PairType::Cookie as i32)
|
|
.map(|res: &PairRecord| res)
|
|
.collect();
|
|
|
|
let query: Vec<&PairRecord> = pairs.iter()
|
|
.filter(|res: &&PairRecord| res.pair_type == PairType::Query as i32)
|
|
.map(|res: &PairRecord| res)
|
|
.collect();
|
|
|
|
#[derive(Serialize)]
|
|
struct Context<'a> {
|
|
request_type: String,
|
|
body: String,
|
|
header: Vec<&'a PairRecord>,
|
|
cookies: Vec<&'a PairRecord>,
|
|
query: Vec<&'a PairRecord>,
|
|
}
|
|
|
|
Template::render(
|
|
"request_details",
|
|
Context{
|
|
request_type: results[0].request_type.clone(),
|
|
body: body.to_string(),
|
|
header: header,
|
|
cookies: cookies,
|
|
query: query
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
#[catch(404)]
|
|
fn not_found(req: &Request) -> String {
|
|
print!("{}", req);
|
|
format!("Oh no! We couldn't find the requested path '{}'", req.uri())
|
|
}
|
|
|
|
fn main() {
|
|
rocket::ignite()
|
|
.register(catchers![not_found])
|
|
.mount("/", routes![index, test_get, test_post, history_req, history_details])
|
|
.attach(Template::fairing())
|
|
.launch();
|
|
} |