diff --git a/Cargo.lock b/Cargo.lock index 4ef32e2..63e3e32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1277,7 +1277,7 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "request-mirror" -version = "0.1.2" +version = "0.1.3" dependencies = [ "chrono", "diesel", diff --git a/Cargo.toml b/Cargo.toml index c2886dd..d0837c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "request-mirror" -version = "0.1.2" +version = "0.1.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 78b44db..02b720f 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,8 @@ This application provides a web ui for sending get/post requests and provides a  ## TODO: - - Update Readme - - Document - - Develop Pipelines + +N/a ## Docker @@ -51,6 +50,71 @@ Then push the image docker push raspberrypi99/request-mirror:latest ``` -## Deploying to azure +## Development Environment -TODO +During development, you'll want to use a few tools to help work on this project. + +First, you'll want to install docker. + +For environments with a GUI: https://docs.docker.com/desktop/ +For environments without a GUI: https://docs.docker.com/engine/install/ + +You can use docker for many things. This project has a set of files for creating and deploying as a docker container. In order to start development, you'll need a postgres container. By default in the .env file, the rust code will attempt to connect a localhost instance of postgres. + +Use the following command to start a postgres container. + +```bash +docker run --name postgres -p 127.0.0.1:5432:5432 -e POSTGRES_PASSWORD=password -e POSTGRES_USER=postgres -e POSTGRES_DB=request_mirror_db -d postgres +``` + +This will start up an instance of postgres to only localhost. Remote computers can't connect to the database. This setup does not use any volumes, meaning that when the container is removed, the data will be gone. If you'd like to add volumes, you can run the following command instead which maps a new postgres-data volume to /var/lib/postgresql/data. + +```bash +docker run --name postgres -p 127.0.0.1:5432:5432 -e POSTGRES_PASSWORD=password -e POSTGRES_USER=postgres -e POSTGRES_DB=request_mirror_db -v postgres-data:/var/lib/postgresql/data -d postgres:latest +``` + +Now that postgres is running, you can now install rust if you haven't already. Follow the instructions on the following site [rustup.rs](https://rustup.rs/) + +Follow the instructions for installing the stable toolchain for rust. You may need to log in and log out after installation. + +**Notice**: Older versions of request mirror used rocket v0.4.x which required the nightly toolchain, please update your repo/fork. + +Next, we can install [diesel](https://diesel.rs/), an ORM and query builder for rust. This is how we deploy tables to our database. Install diesel cli: + +```bash +cargo install diesel_cli --no-default-features --features postgres +``` + +You can deploy the database with the following command: + +**Notice**: If you are not adding a volume to your postgres database, you may need to re-run this step each time you create the postgres docker container. + +```bash +diesel migration run +``` + +Now that the database is ready and rust is installed, we can move onto running the project. + +```bash +cargo run +``` + +You can also run the following to run a release binary + +```bash +cargo run --release +``` + +### Build Docker Image and Run Locally + +You can build the docker image by running the following comand + +```bash +docker build . -t raspberrypi99/request-mirror +``` + +Next, you can run the project using the following command. This can be run even with the development postgres container running. This will open port 80 for the user to connect to. + +```bash +docker compose up -d +``` \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index e835b44..65fbbd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod schema; use chrono::offset::Utc; use diesel::prelude::*; +use rocket::http::CookieJar; use std::env; use dotenvy::dotenv; use models::{ @@ -129,3 +130,12 @@ pub fn ownership_exists(client_id: &str, owner_id: &str, connection: &mut PgConn ownerships.len() > 0 } + +/// Looks for a cookie in the cookiejar. If it is a pending cookie, the pending will be returned as a String. +/// This accounts for if this client hasn't connected before and is making its first request +pub fn get_cookie(key: &str, cookies: &CookieJar<'_>) -> String { + match cookies.get_pending(key) { + Some(v) => v.value().to_string(), + None => cookies.get(key).unwrap().value().to_string() + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 69a19b5..c34b5d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -152,30 +152,27 @@ fn index(_info: RequestInfo) -> Template { #[get("/test")] fn test_get(request: RequestInfo, cookies: &CookieJar<'_>) -> Template { - let client_id = cookies.get("mirror-id"); + let client_id = get_cookie("mirror-id", cookies); - // If the cookie exists, create new database records for this request - if client_id.is_some() { - let connection = &mut establish_connection(); + // create new database records for this request + let connection = &mut establish_connection(); - // Create new history record and retrieve new history_id - let history_id = create_history_record(connection, client_id.unwrap().value(), "Get"); + // Create new history record and retrieve new history_id + let history_id = create_history_record(connection, &client_id, "Get"); - // Create header pair records - for row in &request.header { - create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value); - } - - // Create cookie pair records - for row in &request.cookies { - create_pair_record(connection, history_id, PairType::Cookie, &row.key, &row.value); - } - - // Create query pair records - for row in &request.query { - create_pair_record(connection, history_id, PairType::Query, &row.key, &row.value); - } + // Create header pair records + for row in &request.header { + create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value); + } + // Create cookie pair records + for row in &request.cookies { + create_pair_record(connection, history_id, PairType::Cookie, &row.key, &row.value); + } + + // Create query pair records + for row in &request.query { + create_pair_record(connection, history_id, PairType::Query, &row.key, &row.value); } // Define context for the template @@ -204,36 +201,33 @@ fn test_get(request: RequestInfo, cookies: &CookieJar<'_>) -> Template { #[post("/test", data = "
")] fn test_post(body: RequestBody, request: RequestInfo, cookies: &CookieJar<'_>) -> Template { - let client_id = cookies.get("mirror-id"); + let client_id = get_cookie("mirror-id", cookies); - // If the cookie exists, create new database records for this request - if client_id.is_some() { - let connection = &mut establish_connection(); - - // Create new history record and retrieve new history_id - let history_id = create_history_record(connection, client_id.unwrap().value(), "Post"); - - // Create header pair records - for row in &request.header { - create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value); - } - - // Create cookie pair records - for row in &request.cookies { - create_pair_record(connection, history_id, PairType::Cookie, &row.key, &row.value); - } - - // Create query pair records - for row in &request.query { - create_pair_record(connection, history_id, PairType::Query, &row.key, &row.value); - } - - // Create a pair record for body of the request - println!("Creating body Records for {history_id}"); - create_pair_record(connection, history_id, PairType::Body, "body", &body.0.clone()); - + // Create new database records for this request + let connection = &mut establish_connection(); + + // Create new history record and retrieve new history_id + let history_id = create_history_record(connection, &client_id, "Post"); + + // Create header pair records + for row in &request.header { + create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value); } + // Create cookie pair records + for row in &request.cookies { + create_pair_record(connection, history_id, PairType::Cookie, &row.key, &row.value); + } + + // Create query pair records + for row in &request.query { + create_pair_record(connection, history_id, PairType::Query, &row.key, &row.value); + } + + // Create a pair record for body of the request + println!("Creating body Records for {history_id}"); + create_pair_record(connection, history_id, PairType::Body, "body", &body.0.clone()); + // Define context for the template #[derive(Serialize)] struct Context<'a> { @@ -260,10 +254,10 @@ fn test_post(body: RequestBody, request: RequestInfo, cookies: &CookieJar<'_>) - /// Request function that returns a history of requests that the current client has made /// The user can click a history_id and view the request itself #[get("/history")] -fn history_req(cookies: &CookieJar<'_>) -> Template { +fn history_req(_info: RequestInfo, cookies: &CookieJar<'_>) -> Template { // Get the client_id from the cookies - let client_id = cookies.get("mirror-id").unwrap().value(); + let client_id = get_cookie("mirror-id", cookies); let connection = &mut establish_connection(); @@ -275,7 +269,7 @@ fn history_req(cookies: &CookieJar<'_>) -> Template { .expect("Error loading clients"); // Get ownership relationships - let ownerships: Vec