add token auth
This commit is contained in:
parent
9e9c48e5dd
commit
21fe567ba6
9 changed files with 152 additions and 13 deletions
1
config.toml
Normal file
1
config.toml
Normal file
|
@ -0,0 +1 @@
|
|||
allowed_tokens = ["password"]
|
|
@ -8,6 +8,8 @@ services:
|
|||
- mongodb
|
||||
volumes:
|
||||
- ./itemdb/items:/itemdb
|
||||
- ./locations:/locations
|
||||
- ./config.toml:/config.toml
|
||||
environment:
|
||||
- "DB_URI=mongodb://user:pass@mongodb:27017"
|
||||
- "DB=cdb"
|
||||
|
|
23
src/config.rs
Normal file
23
src/config.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Config {
|
||||
/// Allowed tokens for access
|
||||
pub allowed_tokens: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
allowed_tokens: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_config() -> Config {
|
||||
if let Ok(content) = std::fs::read_to_string("./config.toml") {
|
||||
return toml::from_str(&content).unwrap();
|
||||
}
|
||||
|
||||
Config::default()
|
||||
}
|
|
@ -6,6 +6,7 @@ use location::Location;
|
|||
use rocket::routes as route;
|
||||
use rocket::{http::Method, launch};
|
||||
|
||||
mod config;
|
||||
mod db;
|
||||
mod item;
|
||||
mod json_store;
|
||||
|
@ -54,6 +55,8 @@ async fn rocket() -> _ {
|
|||
location.1.clone().add(location.0).await;
|
||||
}
|
||||
|
||||
let config = config::get_config();
|
||||
|
||||
rocket::build()
|
||||
.mount(
|
||||
"/",
|
||||
|
@ -77,5 +80,6 @@ async fn rocket() -> _ {
|
|||
)
|
||||
.manage(itemdb)
|
||||
.manage(locations)
|
||||
.manage(config)
|
||||
.attach(cors)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ use rocket::{get, post, State};
|
|||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::check_auth;
|
||||
use crate::config::Config;
|
||||
use crate::routes::Token;
|
||||
use crate::variant::Variant;
|
||||
use crate::{
|
||||
db::ItemDB,
|
||||
|
@ -20,7 +23,9 @@ pub struct DemandForm {
|
|||
|
||||
/// Consumes a Transaction with Price and Destination
|
||||
#[post("/demand", data = "<f>")]
|
||||
pub async fn demand_route(f: Json<DemandForm>) -> FallibleApiResponse {
|
||||
pub async fn demand_route(f: Json<DemandForm>, t: Token, c: &State<Config>) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
Variant::demand(
|
||||
&f.uuid,
|
||||
f.price
|
||||
|
@ -41,7 +46,11 @@ pub async fn demand_log_route(
|
|||
item_id: &str,
|
||||
variant_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?
|
||||
|
|
|
@ -5,16 +5,22 @@ use rocket::{get, State};
|
|||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
check_auth,
|
||||
config::Config,
|
||||
json_store::JSONStore,
|
||||
location::Location,
|
||||
routes::{api_error, FallibleApiResponse},
|
||||
routes::{api_error, FallibleApiResponse, Token},
|
||||
};
|
||||
|
||||
#[get("/location/<id>")]
|
||||
pub async fn location_info(
|
||||
id: &str,
|
||||
locations: &State<JSONStore<Location>>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let loc = locations
|
||||
.get(id)
|
||||
.ok_or_else(|| api_error("No location with that ID"))?;
|
||||
|
@ -49,7 +55,13 @@ async fn location_api_resolve(
|
|||
}
|
||||
|
||||
#[get("/locations")]
|
||||
pub async fn locations_list(locations: &State<JSONStore<Location>>) -> FallibleApiResponse {
|
||||
pub async fn locations_list(
|
||||
locations: &State<JSONStore<Location>>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let mut lst = Vec::with_capacity(locations.len());
|
||||
|
||||
for id in locations.deref().keys() {
|
||||
|
@ -60,7 +72,13 @@ pub async fn locations_list(locations: &State<JSONStore<Location>>) -> FallibleA
|
|||
}
|
||||
|
||||
#[get("/location_map")]
|
||||
pub async fn locations_info(locations: &State<JSONStore<Location>>) -> FallibleApiResponse {
|
||||
pub async fn locations_info(
|
||||
locations: &State<JSONStore<Location>>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let mut root_locations = HashMap::new();
|
||||
|
||||
for loc in locations.inner().deref() {
|
||||
|
|
|
@ -14,7 +14,10 @@ use rocket::get;
|
|||
use rocket::State;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::check_auth;
|
||||
use crate::config::Config;
|
||||
use crate::db::ItemDB;
|
||||
use crate::routes::Token;
|
||||
use crate::transaction::Transaction;
|
||||
|
||||
use super::api_error;
|
||||
|
@ -22,14 +25,23 @@ use crate::routes::FallibleApiResponse;
|
|||
|
||||
/// Returns a JSON response with all items in the database.
|
||||
#[get("/items")]
|
||||
pub fn get_items_route(itemdb: &State<ItemDB>) -> serde_json::Value {
|
||||
pub fn get_items_route(itemdb: &State<ItemDB>, t: Token, c: &State<Config>) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let items = itemdb.items();
|
||||
json!({"items": items})
|
||||
Ok(json!({"items": items}))
|
||||
}
|
||||
|
||||
/// Return an API Response for an `Item`
|
||||
#[get("/item/<item_id>")]
|
||||
pub fn item_route(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiResponse {
|
||||
pub fn item_route(
|
||||
item_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let item = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?;
|
||||
|
@ -38,7 +50,14 @@ pub fn item_route(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiResponse
|
|||
|
||||
/// Returns all variants of an Item
|
||||
#[get("/item/<item_id>/variants")]
|
||||
pub fn item_variants_page(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiResponse {
|
||||
pub fn item_variants_page(
|
||||
item_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let item = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?;
|
||||
|
@ -52,7 +71,13 @@ pub fn item_variants_page(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiR
|
|||
|
||||
/// Returns an API Response for a `Transaction`
|
||||
#[get("/transaction/<transaction>")]
|
||||
pub async fn transaction_route(transaction: &str) -> FallibleApiResponse {
|
||||
pub async fn transaction_route(
|
||||
transaction: &str,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let t = Transaction::get(transaction)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No transaction with this UUID"))?;
|
||||
|
@ -66,7 +91,11 @@ pub async fn unique_field_route(
|
|||
variant_id: &str,
|
||||
field: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?
|
||||
|
|
|
@ -3,6 +3,9 @@ use rocket::{get, post, State};
|
|||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::check_auth;
|
||||
use crate::config::Config;
|
||||
use crate::routes::Token;
|
||||
use crate::{
|
||||
db::ItemDB,
|
||||
routes::{api_error, FallibleApiResponse},
|
||||
|
@ -21,8 +24,14 @@ pub struct SupplyForm {
|
|||
|
||||
/// Route for supply action. Creates a new Transaction for the specified Item Variant.
|
||||
#[post("/supply", data = "<form>")]
|
||||
pub async fn supply_route(form: Json<SupplyForm>, itemdb: &State<ItemDB>) -> FallibleApiResponse {
|
||||
println!("{form:?}");
|
||||
pub async fn supply_route(
|
||||
form: Json<SupplyForm>,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(&form.item)
|
||||
.ok_or_else(item_does_not_exist_error)?
|
||||
|
@ -49,7 +58,11 @@ pub async fn supply_log_route(
|
|||
item_id: &str,
|
||||
variant_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?
|
||||
|
@ -63,7 +76,14 @@ pub async fn supply_log_route(
|
|||
|
||||
/// Returns current active Transactions for Item
|
||||
#[get("/item/<item_id>/inventory")]
|
||||
pub async fn inventory_route(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiResponse {
|
||||
pub async fn inventory_route(
|
||||
item_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?;
|
||||
|
@ -79,7 +99,11 @@ pub async fn inventory_route_variant(
|
|||
item_id: &str,
|
||||
variant_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?
|
||||
|
@ -97,7 +121,11 @@ pub async fn variant_stat_route(
|
|||
item_id: &str,
|
||||
variant_id: &str,
|
||||
itemdb: &State<ItemDB>,
|
||||
t: Token,
|
||||
c: &State<Config>,
|
||||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let variant = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use rocket::response::status::BadRequest;
|
||||
use rocket::{
|
||||
http::Status, outcome::Outcome, request::FromRequest, response::status::BadRequest, Request,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub mod item;
|
||||
|
@ -11,3 +13,26 @@ fn api_error(msg: &str) -> ApiError {
|
|||
"error": msg
|
||||
}))
|
||||
}
|
||||
|
||||
pub struct Token(pub String);
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! check_auth {
|
||||
($t:ident, $c:ident) => {
|
||||
if !$c.allowed_tokens.contains(&$t.0) {
|
||||
return Err(api_error("Unauthorized"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[rocket::async_trait]
|
||||
impl<'r> FromRequest<'r> for Token {
|
||||
type Error = ();
|
||||
|
||||
async fn from_request(request: &'r Request<'_>) -> rocket::request::Outcome<Self, Self::Error> {
|
||||
match request.headers().get_one("token") {
|
||||
Some(key) => Outcome::Success(Token(key.to_string())),
|
||||
None => Outcome::Error((Status::Unauthorized, ())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue