Compare commits
No commits in common. "main" and "Build_Artifacts" have entirely different histories.
main
...
Build_Arti
|
|
@ -9,7 +9,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: self-hosted
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: docker build . -t raspberrypi99/request-mirror
|
- run: docker build . -t raspberrypi99/request-mirror
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
name: Build and Publish Test Docker Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "test"]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "test" ]
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: docker build . -t raspberrypi99/request-mirror
|
|
||||||
- name: Dockerize
|
|
||||||
if: success()
|
|
||||||
uses: manusa/actions-publish-docker@v1.1.2
|
|
||||||
with:
|
|
||||||
name: raspberrypi99/request-mirror
|
|
||||||
tag: test
|
|
||||||
username: ${{ secrets.docker_hub_username }}
|
|
||||||
password: ${{ secrets.docker_hub_password }}
|
|
||||||
|
|
@ -2,16 +2,18 @@ name: Build and Test Rust
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main", "test"]
|
branches: [ "main" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main", "test" ]
|
branches: [ "main" ]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
runs-on: self-hosted
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -24,4 +26,10 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --release --verbose
|
run: cargo build --release --verbose
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --release --verbose
|
run: cargo test --release --verbose
|
||||||
|
- name: Upload a Build Artifact
|
||||||
|
uses: actions/upload-artifact@v4.3.4
|
||||||
|
with:
|
||||||
|
name: linux-build
|
||||||
|
path: target/release/request-mirror
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
|
|
@ -1,27 +1,26 @@
|
||||||
[package]
|
[package]
|
||||||
name = "request-mirror"
|
name = "request-mirror"
|
||||||
version = "0.1.3"
|
version = "0.1.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.34"
|
||||||
diesel = { version = "2.2.6", features = ["postgres", "chrono"] }
|
diesel = { version = "2.1.4", features = ["postgres", "chrono"] }
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
regex = "1.11.1"
|
regex = "1.10.5"
|
||||||
rocket = { version = "0.5.1", features = ["tls"] }
|
rocket = { version = "0.5.1", features = ["tls"] }
|
||||||
serde = { version = "1.0.217", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
serde_json = "1.0.137"
|
serde_json = "1.0.114"
|
||||||
tokio = { version = "1.43.0", features = ["full"] }
|
tokio = { version = "1.36.0", features = ["full"] }
|
||||||
time = "0.3.37"
|
|
||||||
|
|
||||||
[dependencies.rocket_dyn_templates]
|
[dependencies.rocket_dyn_templates]
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
features = ["handlebars"]
|
features = ["handlebars"]
|
||||||
|
|
||||||
[dependencies.uuid]
|
[dependencies.uuid]
|
||||||
version = "1.12.1"
|
version = "1.7.0"
|
||||||
features = [
|
features = [
|
||||||
"v4", # Lets you generate random UUIDs
|
"v4", # Lets you generate random UUIDs
|
||||||
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
FROM rustlang/rust:nightly AS builder
|
FROM rustlang/rust:nightly as builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
COPY Cargo.toml .
|
COPY Cargo.toml .
|
||||||
COPY Cargo.lock .
|
COPY Cargo.lock .
|
||||||
RUN cargo install --path .
|
RUN cargo install --path .
|
||||||
|
|
||||||
FROM rustlang/rust:nightly AS runner
|
FROM rustlang/rust:nightly as runner
|
||||||
COPY migrations /migrations
|
COPY migrations /migrations
|
||||||
RUN cargo install diesel_cli --no-default-features --features postgres
|
RUN cargo install diesel_cli --no-default-features --features postgres
|
||||||
RUN apt update && apt upgrade -y && apt install -y libpq-dev libc6
|
RUN apt update && apt install -y libpq-dev libc6
|
||||||
COPY --from=builder /usr/local/cargo/bin/request-mirror /usr/local/bin/request-mirror
|
COPY --from=builder /usr/local/cargo/bin/request-mirror /usr/local/bin/request-mirror
|
||||||
COPY ./templates /templates
|
COPY ./templates /templates
|
||||||
COPY .env.docker /.env
|
COPY .env.docker /.env
|
||||||
|
|
|
||||||
107
README.md
107
README.md
|
|
@ -6,8 +6,9 @@ This application provides a web ui for sending get/post requests and provides a
|
||||||

|

|
||||||
|
|
||||||
## TODO:
|
## TODO:
|
||||||
|
- Update Readme
|
||||||
N/a
|
- Document
|
||||||
|
- Develop Pipelines
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
|
@ -50,104 +51,6 @@ Then push the image
|
||||||
docker push raspberrypi99/request-mirror:latest
|
docker push raspberrypi99/request-mirror:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development Environment
|
## Deploying to azure
|
||||||
|
|
||||||
During development, you'll want to use a few tools to help work on this project.
|
TODO
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ansible Playbook
|
|
||||||
|
|
||||||
You can get access to an ansible playbook and associated files by checking out the following repository
|
|
||||||
|
|
||||||
[https://github.com/RaspberryProgramming/CamsAnsibleLibrary/](https://github.com/RaspberryProgramming/CamsAnsibleLibrary)
|
|
||||||
|
|
||||||
You can clone the repository
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/RaspberryProgramming/CamsAnsibleLibrary
|
|
||||||
|
|
||||||
cd CamsAnsibleLibrary/Request\ Mirror/
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, you can create your "inventory" file
|
|
||||||
|
|
||||||
```
|
|
||||||
[request-mirror-host]
|
|
||||||
10.1.2.3
|
|
||||||
```
|
|
||||||
|
|
||||||
If you haven't already, setup an ssh key so you can automatically log into your remote host as root. If you decide to use a user with sudo privileges you may need to modify the playbook on your own.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook request_mirror_deployment.yml -i inventory
|
|
||||||
```
|
|
||||||
|
|
||||||
If you need to enter a root password, you can add the -K argument
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook request_mirror_deployment.yml -i inventory -K
|
|
||||||
```
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@ services:
|
||||||
- 80:80
|
- 80:80
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=postgres://postgres:Password123@postgres/request_mirror_db
|
- DATABASE_URL=postgres://postgres:Password123@postgres/request_mirror_db
|
||||||
# Set COOKIE_EXPIRATION in weeks
|
|
||||||
# - COOKIE_EXPIRATION=52
|
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
|
||||||
42
src/lib.rs
42
src/lib.rs
|
|
@ -3,7 +3,6 @@ pub mod schema;
|
||||||
|
|
||||||
use chrono::offset::Utc;
|
use chrono::offset::Utc;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use rocket::http::CookieJar;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
use models::{
|
use models::{
|
||||||
|
|
@ -47,38 +46,6 @@ pub fn establish_connection() -> PgConnection {
|
||||||
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
|
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns default cookie expiration in weeks
|
|
||||||
///
|
|
||||||
/// This value can be set by modifying an environment variable or setting in the .env file.
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
///
|
|
||||||
/// ```rust,ignore
|
|
||||||
/// use request_mirror::establish_connection;
|
|
||||||
///
|
|
||||||
/// let connection = establish_connection();
|
|
||||||
/// ```
|
|
||||||
pub fn cookie_expiration() -> i64 {
|
|
||||||
|
|
||||||
let key: &str = "COOKIE_EXPIRATION";
|
|
||||||
let expiration: i64;
|
|
||||||
match env::var(key) {
|
|
||||||
Ok(val) => {
|
|
||||||
match val.parse::<i64>() {
|
|
||||||
Ok(v) => expiration = v,
|
|
||||||
Err(e) => expiration = 52
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_e) => {
|
|
||||||
dotenv().ok();
|
|
||||||
|
|
||||||
expiration = 52;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expiration
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to create a new client in the database. You need to pass a connection, the ip and client_id
|
/// Used to create a new client in the database. You need to pass a connection, the ip and client_id
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
|
|
@ -162,12 +129,3 @@ pub fn ownership_exists(client_id: &str, owner_id: &str, connection: &mut PgConn
|
||||||
|
|
||||||
ownerships.len() > 0
|
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
135
src/main.rs
135
src/main.rs
|
|
@ -9,7 +9,6 @@ use rocket::outcome::Outcome;
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use rocket::http::{Cookie, CookieJar, Status};
|
use rocket::http::{Cookie, CookieJar, Status};
|
||||||
use time::{Duration, OffsetDateTime};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use request_mirror::models::*;
|
use request_mirror::models::*;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
@ -62,14 +61,7 @@ impl<'r> FromRequest<'r> for RequestInfo {
|
||||||
let new_uuid = Uuid::new_v4().to_string();
|
let new_uuid = Uuid::new_v4().to_string();
|
||||||
println!("Creating new cookie");
|
println!("Creating new cookie");
|
||||||
|
|
||||||
let mut cookie = Cookie::new("mirror-id", new_uuid.clone());
|
req_cookies.add(Cookie::new("mirror-id", new_uuid.clone()));
|
||||||
let mut now = OffsetDateTime::now_utc();
|
|
||||||
|
|
||||||
now += Duration::weeks(cookie_expiration()); // Default expiration is 52 weeks
|
|
||||||
|
|
||||||
cookie.set_expires(now);
|
|
||||||
|
|
||||||
req_cookies.add(cookie);
|
|
||||||
|
|
||||||
let address = if req.client_ip().is_some() {
|
let address = if req.client_ip().is_some() {
|
||||||
req.client_ip().unwrap().to_string()
|
req.client_ip().unwrap().to_string()
|
||||||
|
|
@ -160,27 +152,30 @@ fn index(_info: RequestInfo) -> Template {
|
||||||
#[get("/test")]
|
#[get("/test")]
|
||||||
fn test_get(request: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
fn test_get(request: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
||||||
|
|
||||||
let client_id = get_cookie("mirror-id", cookies);
|
let client_id = cookies.get("mirror-id");
|
||||||
|
|
||||||
// create new database records for this request
|
// If the cookie exists, create new database records for this request
|
||||||
let connection = &mut establish_connection();
|
if client_id.is_some() {
|
||||||
|
let connection = &mut establish_connection();
|
||||||
|
|
||||||
// Create new history record and retrieve new history_id
|
// Create new history record and retrieve new history_id
|
||||||
let history_id = create_history_record(connection, &client_id, "Get");
|
let history_id = create_history_record(connection, client_id.unwrap().value(), "Get");
|
||||||
|
|
||||||
// Create header pair records
|
// Create header pair records
|
||||||
for row in &request.header {
|
for row in &request.header {
|
||||||
create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value);
|
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 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
|
// Define context for the template
|
||||||
|
|
@ -209,32 +204,35 @@ fn test_get(request: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
||||||
#[post("/test", data = "<body>")]
|
#[post("/test", data = "<body>")]
|
||||||
fn test_post(body: RequestBody, request: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
fn test_post(body: RequestBody, request: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
||||||
|
|
||||||
let client_id = get_cookie("mirror-id", cookies);
|
let client_id = cookies.get("mirror-id");
|
||||||
|
|
||||||
// Create new database records for this request
|
// If the cookie exists, create new database records for this request
|
||||||
let connection = &mut establish_connection();
|
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, "Post");
|
// 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 header pair records
|
||||||
create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value);
|
for row in &request.header {
|
||||||
}
|
create_pair_record(connection, history_id, PairType::Header, &row.key, &row.value);
|
||||||
|
}
|
||||||
|
|
||||||
// Create cookie pair records
|
// Create cookie pair records
|
||||||
for row in &request.cookies {
|
for row in &request.cookies {
|
||||||
create_pair_record(connection, history_id, PairType::Cookie, &row.key, &row.value);
|
create_pair_record(connection, history_id, PairType::Cookie, &row.key, &row.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create query pair records
|
// Create query pair records
|
||||||
for row in &request.query {
|
for row in &request.query {
|
||||||
create_pair_record(connection, history_id, PairType::Query, &row.key, &row.value);
|
create_pair_record(connection, history_id, PairType::Query, &row.key, &row.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a pair record for body of the request
|
// Create a pair record for body of the request
|
||||||
println!("Creating body Records for {history_id}");
|
println!("Creating body Records for {history_id}");
|
||||||
create_pair_record(connection, history_id, PairType::Body, "body", &body.0.clone());
|
create_pair_record(connection, history_id, PairType::Body, "body", &body.0.clone());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Define context for the template
|
// Define context for the template
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
@ -262,10 +260,10 @@ fn test_post(body: RequestBody, request: RequestInfo, cookies: &CookieJar<'_>) -
|
||||||
/// Request function that returns a history of requests that the current client has made
|
/// 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
|
/// The user can click a history_id and view the request itself
|
||||||
#[get("/history")]
|
#[get("/history")]
|
||||||
fn history_req(_info: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
fn history_req(cookies: &CookieJar<'_>) -> Template {
|
||||||
|
|
||||||
// Get the client_id from the cookies
|
// Get the client_id from the cookies
|
||||||
let client_id = get_cookie("mirror-id", cookies);
|
let client_id = cookies.get("mirror-id").unwrap().value();
|
||||||
|
|
||||||
let connection = &mut establish_connection();
|
let connection = &mut establish_connection();
|
||||||
|
|
||||||
|
|
@ -277,7 +275,7 @@ fn history_req(_info: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
||||||
.expect("Error loading clients");
|
.expect("Error loading clients");
|
||||||
|
|
||||||
// Get ownership relationships
|
// Get ownership relationships
|
||||||
let ownerships: Vec<Ownership> = get_ownerships(&client_id, connection);
|
let ownerships: Vec<Ownership> = get_ownerships(client_id, connection);
|
||||||
|
|
||||||
// Add any records that owned clients have
|
// Add any records that owned clients have
|
||||||
for ownership in ownerships {
|
for ownership in ownerships {
|
||||||
|
|
@ -327,14 +325,14 @@ fn history_req(_info: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
||||||
/// request that was recorded to the database.
|
/// request that was recorded to the database.
|
||||||
/// This includes the body of a post request, headers, cookies and query parameters.
|
/// This includes the body of a post request, headers, cookies and query parameters.
|
||||||
#[get("/history/<history_id>")]
|
#[get("/history/<history_id>")]
|
||||||
fn history_details(history_id: i64, _info: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
fn history_details(history_id: i64, cookies: &CookieJar<'_>) -> Template {
|
||||||
|
|
||||||
let client_id = get_cookie("mirror-id", cookies);
|
let client_id = cookies.get("mirror-id").unwrap().value();
|
||||||
|
|
||||||
let connection: &mut PgConnection = &mut establish_connection();
|
let connection: &mut PgConnection = &mut establish_connection();
|
||||||
|
|
||||||
// Get owned client ids
|
// Get owned client ids
|
||||||
let owned_clients: Vec<String> = get_ownerships(&client_id, connection)
|
let owned_clients: Vec<String> = get_ownerships(client_id, connection)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x|x.client_id.to_string())
|
.map(|x|x.client_id.to_string())
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
@ -417,33 +415,26 @@ fn history_details(history_id: i64, _info: RequestInfo, cookies: &CookieJar<'_>)
|
||||||
#[get("/ownership_registration")]
|
#[get("/ownership_registration")]
|
||||||
fn ownership_registration(info: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
fn ownership_registration(info: RequestInfo, cookies: &CookieJar<'_>) -> Template {
|
||||||
|
|
||||||
let host_pair = info.header.iter().find(|&h| h.key == "host").unwrap();
|
let client_id = cookies.get("mirror-id").unwrap().value().to_string();
|
||||||
let client_id = get_cookie("mirror-id", cookies);
|
|
||||||
let owner_id_pair = info.find_query_key("owner_id");
|
let owner_id_pair = info.find_query_key("owner_id");
|
||||||
let mut disp_owner_reg = false;
|
let mut disp_owner_reg = false;
|
||||||
let mut failed_owner_reg = false;
|
|
||||||
let re = Regex::new(r"^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$").unwrap();
|
let re = Regex::new(r"^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$").unwrap();
|
||||||
let connection: &mut PgConnection = &mut establish_connection();
|
let connection: &mut PgConnection = &mut establish_connection();
|
||||||
let ownerships: Vec<Ownership> = get_ownerships(&client_id, connection);
|
let ownerships: Vec<Ownership> = get_ownerships(&client_id, connection);
|
||||||
|
|
||||||
let owner_id = match owner_id_pair {
|
let owner_id = match owner_id_pair {
|
||||||
Some(v) => v.value.trim().to_string(),
|
Some(v) => v.value.to_string(),
|
||||||
None => "".to_string()
|
None => "".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
if
|
if
|
||||||
owner_id_pair.is_some()
|
owner_id_pair.is_some() &&
|
||||||
{
|
|
||||||
if
|
|
||||||
re.is_match(&owner_id) &&
|
re.is_match(&owner_id) &&
|
||||||
owner_id != client_id &&
|
owner_id != client_id &&
|
||||||
!ownership_exists(&client_id, &owner_id, connection)
|
!ownership_exists(&client_id, &owner_id, connection)
|
||||||
{
|
{
|
||||||
create_owner_record(connection, owner_id.clone(), client_id.clone());
|
create_owner_record(connection, owner_id.clone(), client_id.clone());
|
||||||
disp_owner_reg = true;
|
disp_owner_reg = true;
|
||||||
} else {
|
|
||||||
failed_owner_reg = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
@ -451,18 +442,14 @@ fn ownership_registration(info: RequestInfo, cookies: &CookieJar<'_>) -> Templat
|
||||||
client_id: String,
|
client_id: String,
|
||||||
owner_id: String,
|
owner_id: String,
|
||||||
disp_owner_reg: bool,
|
disp_owner_reg: bool,
|
||||||
failed_owner_reg: bool,
|
ownerships: Vec<Ownership>
|
||||||
ownerships: Vec<Ownership>,
|
|
||||||
host: String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Template::render("ownership_registration", Context {
|
Template::render("ownership_registration", Context {
|
||||||
client_id,
|
client_id,
|
||||||
owner_id,
|
owner_id,
|
||||||
disp_owner_reg,
|
disp_owner_reg,
|
||||||
failed_owner_reg,
|
ownerships
|
||||||
ownerships,
|
|
||||||
host: host_pair.value.to_string()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
<title>Request Mirror - Error</title>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="d-flex flex-column">
|
<body class="d-flex flex-column">
|
||||||
|
|
@ -19,7 +18,7 @@
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" aria-current="page" href="/">Home</a>
|
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/test">Test Page</a>
|
<a class="nav-link" href="/test">Test Page</a>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
<title>Request Mirror - History</title>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="d-flex flex-column">
|
<body class="d-flex flex-column">
|
||||||
|
|
@ -19,13 +19,13 @@
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" aria-current="page" href="/">Home</a>
|
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/test">Test Page</a>
|
<a class="nav-link" href="/test">Test Page</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/history">History</a>
|
<a class="nav-link" href="/history">History</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/ownership_registration">Ownership Registration</a>
|
<a class="nav-link" href="/ownership_registration">Ownership Registration</a>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
<title>Request Mirror - Home</title>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
<title>Request Mirror - Ownership Registration</title>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="d-flex flex-column">
|
<body class="d-flex flex-column">
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" aria-current="page" href="/">Home</a>
|
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/test">Test Page</a>
|
<a class="nav-link" href="/test">Test Page</a>
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
<a class="nav-link" href="/history">History</a>
|
<a class="nav-link" href="/history">History</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/ownership_registration">Ownership Registration</a>
|
<a class="nav-link" href="/ownership_registration">Ownership Registration</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -36,27 +36,19 @@
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="body" class="p-5">
|
<div id="body" class="p-5">
|
||||||
<p>
|
<h3>Your Client ID: {{client_id}}</h3>
|
||||||
<h5>
|
|
||||||
Your Client ID:
|
|
||||||
</h5>
|
|
||||||
<button id="client_id" class="border-0 bg-transparent" onclick="copy_content(event)" data-bs-toggle="tooltip"
|
|
||||||
data-bs-title="Click To Copy">
|
|
||||||
{{client_id}}
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<h5>
|
|
||||||
Registration Link:
|
|
||||||
</h5>
|
|
||||||
<button id="reg_link" class="border-0 bg-transparent" onclick="copy_content(event)" data-bs-toggle="tooltip"
|
|
||||||
data-bs-title="Click To Copy">
|
|
||||||
{{host}}/ownership_registration?owner_id={{client_id}}
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h5>Owned Clients</h5>
|
<form target="/owner_registration">
|
||||||
<table class="table table-striped m-1">
|
<h5>Ownership Registration</h5>
|
||||||
|
<input type="text" name="owner_id">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{{#if disp_owner_reg}}
|
||||||
|
<p>Registered new owner {{owner_id}} for {{client_id}}</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<h3>Owned Clients</h3>
|
||||||
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Client ID</th>
|
<th>Client ID</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -68,82 +60,10 @@
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<form action="/ownership_registration" method="get">
|
|
||||||
<h5>Ownership Registration</h5>
|
|
||||||
<div class="p-1">
|
|
||||||
<h6>Instructions:</h6>
|
|
||||||
<p>
|
|
||||||
Copy the Client ID from the browser you'd like to see your requests. Paste it into the Owner ID Form and
|
|
||||||
submit.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
This will allow the other client to access any requests you've made in the history page.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If you'd like to register a new owner on a client that doesn't have access to this html form, you can make the
|
|
||||||
request directly
|
|
||||||
by making an http/https request to the registration link above. Click it to copy to your clipboard.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3 ms-1 me-1">
|
|
||||||
<label for="owner_id" class="form-label">Owner ID</label>
|
|
||||||
<input class="form-control" type="text" name="owner_id">
|
|
||||||
</div>
|
|
||||||
<div class="">
|
|
||||||
<button type="submit" class="btn btn-primary mb-3">Submit</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{{#if disp_owner_reg}}
|
|
||||||
<p>Registered new owner {{owner_id}} for {{client_id}}</p>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if failed_owner_reg}}
|
|
||||||
<p>Failed to register {{owner_id}} for {{client_id}}.</p>
|
|
||||||
<p>This may have ocurred because the owner_id does not exist, is already registered as an owner, or that it is the same as the client_id.</p>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
|
||||||
<div id="clipboard_toast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
|
||||||
<div class="toast-header">
|
|
||||||
<svg class="bd-placeholder-img rounded me-2" width="20" height="20" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
aria-hidden="true" preserveAspectRatio="xMidYMid slice" focusable="false">
|
|
||||||
<rect width="100%" height="100%" fill="#007aff"></rect>
|
|
||||||
</svg>
|
|
||||||
<strong class="me-auto">Clipboard</strong>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="toast-body">
|
|
||||||
Copied to Clipboard.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||||
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<script>
|
|
||||||
function copy_content(event) {
|
|
||||||
// Get the text field
|
|
||||||
var copyText = document.getElementById(event.target.id);
|
|
||||||
|
|
||||||
// Copy the text inside the text field
|
|
||||||
navigator.clipboard.writeText(copyText.innerText);
|
|
||||||
|
|
||||||
const toastLiveExample = document.getElementById('clipboard_toast')
|
|
||||||
|
|
||||||
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
|
|
||||||
toastBootstrap.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
|
||||||
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
<title>Request Mirror - Request Details</title>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="d-flex flex-column">
|
<body class="d-flex flex-column">
|
||||||
|
|
@ -19,10 +18,10 @@
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" aria-current="page" href="/">Home</a>
|
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/test">Test Page</a>
|
<a class="nav-link" href="/test">Test Page</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/history">History</a>
|
<a class="nav-link" href="/history">History</a>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue