177 lines
6.2 KiB
Rust
177 lines
6.2 KiB
Rust
#[macro_use]
|
|
extern crate rocket;
|
|
use rocket::{form::Form, State, Request, Response, http::Header};
|
|
use rocket::fairing::{Fairing, Info, Kind};
|
|
|
|
use uuid::Uuid;
|
|
use rand::Rng;
|
|
|
|
use argon2::{
|
|
password_hash::{
|
|
rand_core::OsRng,
|
|
PasswordHash, PasswordHasher, PasswordVerifier, SaltString
|
|
},
|
|
Argon2
|
|
};
|
|
|
|
use std::env;
|
|
|
|
mod database;
|
|
use crate::database::*;
|
|
|
|
mod structures;
|
|
use crate::structures::*;
|
|
|
|
|
|
pub struct CORS;
|
|
|
|
#[rocket::async_trait]
|
|
impl Fairing for CORS {
|
|
fn info(&self) -> Info {
|
|
Info {
|
|
name: "Attaching CORS headers to responses",
|
|
kind: Kind::Response
|
|
}
|
|
}
|
|
|
|
async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) {
|
|
response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
|
|
response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
|
|
response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
|
|
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
|
|
}
|
|
}
|
|
|
|
#[post("/api/new", data = "<request>")]
|
|
fn new_product(db: &State<sled::Db>, argon2: &State<Argon2>, salt: &State<SaltString>, request: Form<ProductRequest>) -> String {
|
|
let password = request.password.as_bytes();
|
|
let hashed_password = argon2.hash_password(password, &salt.as_ref()).unwrap().to_string();
|
|
let mut admin_password = env::var("ADMIN_PASSWD").unwrap();
|
|
admin_password = argon2.hash_password(admin_password.as_bytes(), &salt.as_ref()).unwrap().to_string();
|
|
|
|
println!("salt is: {}\n hashed password is: {}\nadmin password is: {}", &salt.as_ref(), hashed_password, admin_password);
|
|
|
|
if hashed_password == admin_password {
|
|
let new_product: Product = Product {
|
|
short_name: request.short_name.clone(),
|
|
full_name: request.full_name.clone(),
|
|
price_usd: request.price_usd,
|
|
stock: request.stock,
|
|
};
|
|
register_product(db, &new_product.short_name, &new_product);
|
|
let new = read_product(db, &request.short_name).unwrap().unwrap();
|
|
return format!(
|
|
"registered new produt {} ${}. There are {} left in stock.",
|
|
new.full_name, new.price_usd, new.stock
|
|
);
|
|
};
|
|
|
|
return format!("wrong password!");
|
|
}
|
|
|
|
#[post("/api/order", data = "<order>")]
|
|
fn new_order(order: Form<OrderRequest<'_>>) -> String {
|
|
let mut rng = rand::thread_rng();
|
|
let to_hash = format!("{}{}{}", order.user_message.to_string(), order.encryption_key.to_string(), rng.gen::<f64>().to_string());
|
|
let db_order: Order = Order {
|
|
name: order.name.to_string(),
|
|
message: order.user_message.to_string(),
|
|
encryption_key: order.encryption_key.to_string(),
|
|
email: order.email.to_string(),
|
|
payment_type: order.payment_type.clone(),
|
|
uuid: Uuid::new_v5(&Uuid::NAMESPACE_X500, to_hash.as_bytes()),
|
|
};
|
|
make_order(&db_order);
|
|
format!("Thank you for ordering from Catgirl Pharmacy!\nYour order Uuid is {}", db_order.uuid.to_hyphenated().to_string())
|
|
}
|
|
|
|
#[get("/api/order/<uuid>")]
|
|
fn order_info(uuid: &str) -> String {
|
|
let order = read_order(uuid).unwrap().unwrap();
|
|
format!("Uuid: {}\nName: {}\nEmail: {}\nMessage: {}\nEncryption Key: {}\nPayment Type: {:?}",
|
|
order.uuid,
|
|
order.name,
|
|
order.email,
|
|
order.message,
|
|
order.encryption_key,
|
|
order.payment_type
|
|
)
|
|
}
|
|
|
|
#[post("/api/orders", data="<auth>")]
|
|
fn all_orders(auth: Form<Authenticate>, argon2: &State<Argon2>, salt: &State<SaltString>) -> String {
|
|
let entered_password = auth.password.as_bytes();
|
|
let hashed_password = argon2.hash_password(entered_password, &salt.as_ref()).unwrap().to_string();
|
|
let mut admin_password = env::var("ADMIN_PASSWD").unwrap();
|
|
admin_password = argon2.hash_password(admin_password.as_bytes(), &salt.as_ref()).unwrap().to_string();
|
|
|
|
if admin_password == hashed_password {
|
|
let all_orders = read_all_orders();
|
|
let mut return_string = String::new();
|
|
for x in &all_orders {
|
|
return_string = format!("{}\n{:?}",return_string, x);
|
|
}
|
|
|
|
return return_string;
|
|
} else {
|
|
return "wrong password".to_string();
|
|
}
|
|
}
|
|
|
|
#[post("/api/update", data = "<update>")]
|
|
fn update_product(db: &State<sled::Db>, argon2: &State<Argon2>, salt: &State<SaltString>, update: Form<Update<'_>>) -> String {
|
|
let password = update.password.as_bytes();
|
|
let hashed_password = argon2.hash_password(password, &salt.as_ref()).unwrap().to_string();
|
|
let mut admin_password = env::var("ADMIN_PASSWD").unwrap();
|
|
admin_password = argon2.hash_password(admin_password.as_bytes(), &salt.as_ref()).unwrap().to_string();
|
|
|
|
if admin_password == hashed_password {
|
|
|
|
match update.field {
|
|
"price_usd" => {
|
|
let mut new_product = read_product(db, &update.product).unwrap().unwrap();
|
|
new_product.price_usd = update.value;
|
|
register_product(db, &update.product, &new_product);
|
|
return "price changed".to_string();
|
|
}
|
|
"stock" => {
|
|
let mut new_product = read_product(db, &update.product).unwrap().unwrap();
|
|
new_product.stock = update.value as u32;
|
|
register_product(db, &update.product, &new_product);
|
|
return "stock changed".to_string();
|
|
}
|
|
_ => return "field not found".to_string(),
|
|
}
|
|
};
|
|
return "wrong password".to_string();
|
|
}
|
|
|
|
#[get("/api/stock/<product>")]
|
|
fn get_stock(db: &State<sled::Db>, product: &str) -> String {
|
|
read_product(db, &product)
|
|
.unwrap()
|
|
.unwrap()
|
|
.stock
|
|
.to_string()
|
|
}
|
|
|
|
#[get("/api/price/<product>")]
|
|
fn get_price(db: &State<sled::Db>, product: &str) -> String {
|
|
read_product(db, &product)
|
|
.unwrap()
|
|
.unwrap()
|
|
.price_usd
|
|
.to_string()
|
|
}
|
|
|
|
#[launch]
|
|
fn rocket() -> _ {
|
|
rocket::build()
|
|
.manage(database::open())
|
|
.manage(Argon2::default())
|
|
.manage(SaltString::generate(&mut OsRng))
|
|
.mount("/",
|
|
routes![get_stock, get_price, new_order, order_info, all_orders, new_product, update_product])
|
|
.attach(CORS)
|
|
}
|