From 0d9991c55713b413424b53a67416d4433f106219 Mon Sep 17 00:00:00 2001 From: shockrah Date: Tue, 22 Mar 2022 20:01:19 -0700 Subject: [PATCH] !* Splitting up the admin module This is primarily for organizational reasons however it should make things easier to track as the complexity increases with features getting filled out. --- .gitignore | 1 + api/src/admin.rs | 95 --------------------------------------- api/src/admin/apikey.rs | 46 +++++++++++++++++++ api/src/admin/mod.rs | 39 ++++++++++++++++ api/src/admin/response.rs | 4 ++ 5 files changed, 90 insertions(+), 95 deletions(-) delete mode 100644 api/src/admin.rs create mode 100644 api/src/admin/apikey.rs create mode 100644 api/src/admin/mod.rs create mode 100644 api/src/admin/response.rs diff --git a/.gitignore b/.gitignore index 562662b..2ad4d82 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ aws/playbooks/hosts ts/dist/ ts/node_modules/ +.vscode/settings.json diff --git a/api/src/admin.rs b/api/src/admin.rs deleted file mode 100644 index f92a373..0000000 --- a/api/src/admin.rs +++ /dev/null @@ -1,95 +0,0 @@ -#[cfg(feature = "admin")] -// This module deals with all the routes which are protected by an api key -// Without a proper api key sent to the server these routes will -// respond with a 401 UNAUTHORIZED response - -// Below is the implementation required to have custom api keys which -// allow people to actually use the service -use std::env; -use std::collections::HashMap; -use rocket::serde::Serialize; -use rocket::serde::json::Json; -use rocket_dyn_templates::Template; -use rocket::request::{self, Outcome, Request, FromRequest}; -use rocket::http::Status; -use crate::db; -use crate::page; - -lazy_static! { - static ref DB_PATH: String = { - env::var("DB_PATH").unwrap_or("keys.db".into()) - }; -} - -#[derive(Serialize)] -struct ActionResponse(&'static str); - -pub struct ApiKey { - uid: String, - key: String -} - -#[derive(Debug)] -pub enum ApiKeyError { - Missing, - Invalid, -} - - -#[rocket::async_trait] -impl<'r> FromRequest<'r> for ApiKey { - type Error = ApiKeyError; - async fn from_request(req: &'r Request<'_>) -> Outcome { - let key = req.headers().get_one("ADMIN-API-KEY"); - let uid = req.headers().get_one("ADMIN-API-UID"); - - if key.is_none() || uid.is_none() { - return Outcome::Failure((Status::Forbidden, ApiKeyError::Missing)); - } - - let (key, uid) = (key.unwrap(), uid.unwrap()); - - println!("Path to use for db file {:?}", DB_PATH.to_string()); - let db = db::Database::load(DB_PATH.as_str().into()).unwrap(); - if let Some(stored) = db.get(uid) { - if stored == key { - return Outcome::Success(ApiKey { - key: key.into(), - uid: uid.into() - }) - } - return Outcome::Failure((Status::Forbidden, ApiKeyError::Invalid)) - } - - return Outcome::Failure((Status::Forbidden, ApiKeyError::Invalid)) - } -} - - -#[get("/dashboard")] -pub async fn login_dashboard() -> Template { - // This page is basically just a login form - // However the rest of the form is present on this page, just hidden - let h: HashMap = HashMap::new(); // does not allocate - return Template::render("admin", &h); -} - -#[post("/dashboard")] -pub async fn dashboard(_key: ApiKey) -> Json { - // API Key auth'd for us so we don't need to bother checking, - // this just serves to confirm the credentials are correct - Json(ActionResponse("ok")) -} - - -#[post("/upload-video?&")] -async fn updload_video(_key: ApiKey, category: String, filename: String) -> &'static str { - todo!() -} - -#[delete("/remove-video?&")] -async fn remove_video(_key: ApiKey, category: String, filename: String) -> &'static str { - todo!() -} - - diff --git a/api/src/admin/apikey.rs b/api/src/admin/apikey.rs new file mode 100644 index 0000000..fd1ac5a --- /dev/null +++ b/api/src/admin/apikey.rs @@ -0,0 +1,46 @@ +use rocket::request::{Outcome, Request, FromRequest}; +use rocket::async_trait; +use rocket::http::Status; + +use crate::db::{self, DB_PATH}; + +pub struct ApiKey { + uid: String, + key: String +} + +#[derive(Debug)] +pub enum ApiKeyError { + Missing, + Invalid, +} + + +#[async_trait] +impl<'r> FromRequest<'r> for ApiKey { + type Error = ApiKeyError; + async fn from_request(req: &'r Request<'_>) -> Outcome { + let key = req.headers().get_one("ADMIN-API-KEY"); + let uid = req.headers().get_one("ADMIN-API-UID"); + + if key.is_none() || uid.is_none() { + return Outcome::Failure((Status::Forbidden, ApiKeyError::Missing)); + } + + let (key, uid) = (key.unwrap(), uid.unwrap()); + + println!("Path to use for db file {:?}", DB_PATH.to_string()); + let db = db::Database::load(DB_PATH.as_str().into()).unwrap(); + if let Some(stored) = db.get(uid) { + if stored == key { + return Outcome::Success(ApiKey { + key: key.into(), + uid: uid.into() + }) + } + return Outcome::Failure((Status::Forbidden, ApiKeyError::Invalid)) + } + + return Outcome::Failure((Status::Forbidden, ApiKeyError::Invalid)) + } +} diff --git a/api/src/admin/mod.rs b/api/src/admin/mod.rs new file mode 100644 index 0000000..6c2e7d5 --- /dev/null +++ b/api/src/admin/mod.rs @@ -0,0 +1,39 @@ +#[cfg(feature = "admin")] + +mod apikey; +mod response; + +use std::collections::HashMap; +use apikey::ApiKey; +use response::ActionResponse; +use rocket::serde::json::Json; + + + +use rocket_dyn_templates::Template; + +#[get("/dashboard")] +pub async fn login_dashboard() -> Template { + // This page is basically just a login form + // However the rest of the form is present on this page, just hidden + let h: HashMap = HashMap::new(); // does not allocate + return Template::render("admin", &h); +} + +#[post("/dashboard")] +pub async fn dashboard(_key: ApiKey) -> Json { + // API Key auth'd for us so we don't need to bother checking, + // this just serves to confirm the credentials are correct + Json(ActionResponse("ok")) +} + + +#[post("/upload-video?&")] +async fn updload_video(_key: ApiKey, category: String, filename: String) -> &'static str { + todo!() +} + +#[delete("/remove-video?&")] +async fn remove_video(_key: ApiKey, category: String, filename: String) -> &'static str { + todo!() +} diff --git a/api/src/admin/response.rs b/api/src/admin/response.rs new file mode 100644 index 0000000..b207fed --- /dev/null +++ b/api/src/admin/response.rs @@ -0,0 +1,4 @@ +use serde::Serialize; + +#[derive(Serialize)] +pub struct ActionResponse(pub &'static str);