🔒 Adds authentication

This commit is contained in:
Daniel Svitan 2025-05-11 09:29:47 +02:00
parent d5bb5089da
commit 1413ed58b9
6 changed files with 98 additions and 3 deletions

2
backend/.env Normal file
View File

@ -0,0 +1,2 @@
DB_PATH=./db.sqlite
API_KEY=p123

26
backend/.gitignore vendored
View File

@ -1 +1,25 @@
/target .env
*.sqlite
### Rust template
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
#Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

3
backend/Cargo.lock generated
View File

@ -87,6 +87,8 @@ dependencies = [
"dotenv", "dotenv",
"rocket", "rocket",
"rusqlite", "rusqlite",
"serde",
"serde_json",
] ]
[[package]] [[package]]
@ -960,6 +962,7 @@ dependencies = [
"rocket_codegen", "rocket_codegen",
"rocket_http", "rocket_http",
"serde", "serde",
"serde_json",
"state", "state",
"tempfile", "tempfile",
"time", "time",

View File

@ -4,6 +4,8 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
rocket = "0.5.1" rocket = { version = "0.5.0-rc.2", features = ["json"] }
dotenv = "0.15.0" dotenv = "0.15.0"
rusqlite = { version = "0.35.0", features = ["bundled"] } rusqlite = { version = "0.35.0", features = ["bundled"] }
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.88"

56
backend/src/auth.rs Normal file
View File

@ -0,0 +1,56 @@
use rocket::Response;
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome, Request};
use serde::Serialize;
use serde_json::json;
use std::io::Cursor;
pub struct ApiKey {}
#[derive(Serialize)]
pub struct GenericResponse {
pub message: String,
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for ApiKey {
type Error = Response<'r>;
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Response<'r>> {
fn is_valid(key: &str) -> bool {
key == dotenv::var("API_KEY").unwrap()
}
match req.headers().get_one("Authorization") {
None => {
let body = json!(GenericResponse {
message: "auth token not found".to_string()
})
.to_string();
Outcome::Error((
Status::Unauthorized,
Response::build()
.status(Status::Unauthorized)
.sized_body(body.len(), Cursor::new(body))
.finalize(),
))
}
Some(key) if is_valid(key) => Outcome::Success(ApiKey {}),
Some(_) => {
let body = json!(GenericResponse {
message: "invalid auth token".to_string()
})
.to_string();
Outcome::Error((
Status::Unauthorized,
Response::build()
.status(Status::Unauthorized)
.sized_body(body.len(), Cursor::new(body))
.finalize(),
))
}
}
}
}

View File

@ -1,6 +1,8 @@
mod db; mod db;
mod auth;
use dotenv; use dotenv;
use auth::ApiKey;
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
@ -10,11 +12,17 @@ async fn index() -> &'static str {
"Hello World!" "Hello World!"
} }
#[get("/hi")]
async fn hello(api_key: ApiKey) -> &'static str {
"Hi!"
}
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
let db_path = dotenv::var("DB_PATH").expect("DB_PATH is not set"); let db_path = dotenv::var("DB_PATH").expect("DB_PATH is not set");
dotenv::var("API_KEY").expect("API_KEY is not set");
let db = db::Conn::new(&db_path); let db = db::Conn::new(&db_path);
rocket::build().mount("/", routes![index]) rocket::build().mount("/", routes![index, hello])
} }