diff --git a/Cargo.lock b/Cargo.lock index 9ed1fda..bed4760 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1863,6 +1863,26 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "thiserror" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.48", +] + [[package]] name = "thread_local" version = "1.0.1" @@ -2259,6 +2279,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.1", + "thiserror", "tracing", "tracing-log", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 16c29b9..67777fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ rocket = "0.4" rocket_oauth2 = "0.4" serde = { version = "^1", features = ["derive"] } serde_json = "^1" +thiserror = "1" tracing = "0.1" tracing-subscriber = "0.2" tracing-log = "0.1" diff --git a/src/api.rs b/src/api.rs index f77aafb..31abd5b 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,15 +1,89 @@ -use crate::{schema, models, MainDatabase}; +use crate::{jwt, models, schema, MainDatabase}; +use color_eyre::eyre::Report; use diesel::prelude::*; +use rocket::http::{ContentType, Status}; +use rocket::request::{self, FromRequest, Request}; +use rocket::response::Responder; +use rocket::Outcome; +use rocket::Response; use rocket_contrib::{json::Json, uuid::Uuid}; +use std::io::Cursor; -#[tracing::instrument(skip(conn))] +#[tracing::instrument] #[get("/user/")] -pub fn get_user(conn: MainDatabase, uuid: Uuid) -> Json { - use schema::users::dsl::users; - let result = users - .find(uuid.into_inner()) - .get_result::(&*conn) - .expect("to find user"); +pub fn get_user(user: models::User, uuid: Uuid) -> Result> { + if uuid != user.id { + return Err(Error::LackPermissions); + } - Json(result) + Ok(Json(user)) +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("internal database error: {0}")] + Database(#[from] diesel::result::Error), + + #[error("bad or no authorization")] + BadOrNoAuth, + + #[error("you lack needed permissions")] + LackPermissions, + + #[error("internal server error")] + InternalServerError(#[from] Report), +} + +impl<'a> Responder<'a> for Error { + fn respond_to(self, _: &Request) -> ::std::result::Result, Status> { + match self { + Error::Database(why) => Response::build() + .header(ContentType::Plain) + .status(Status::InternalServerError) + .sized_body(Cursor::new(format!("{}", why))) + .ok(), + Error::BadOrNoAuth | Error::LackPermissions => Response::build() + .header(ContentType::Plain) + .status(Status::Unauthorized) + .sized_body(Cursor::new(format!("{}", self))) + .ok(), + Error::InternalServerError(why) => Response::build() + .header(ContentType::Plain) + .status(Status::InternalServerError) + .sized_body(Cursor::new(format!("{}", why))) + .ok(), + } + } +} + +#[derive(Debug)] +pub enum AuthError { + BadCount, + Missing, + Invaild, +} + +pub type Result = std::result::Result; + +impl<'a, 'r> FromRequest<'a, 'r> for models::User { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> request::Outcome { + let keys: Vec<_> = request.headers().get("authorization").collect(); + match keys.len() { + 0 => Outcome::Failure((Status::BadRequest, ())), + 1 => { + let tok = keys[0].to_string(); + let conn = request.guard::()?; + match jwt::verify(tok, conn) { + Err(why) => { + tracing::error!("JWT verification error: {}", why); + Outcome::Failure((Status::Unauthorized, ())) + } + Ok(user) => Outcome::Success(user), + } + } + _ => Outcome::Failure((Status::BadRequest, ())), + } + } } diff --git a/src/jwt.rs b/src/jwt.rs index 534c735..af8ccfb 100644 --- a/src/jwt.rs +++ b/src/jwt.rs @@ -47,8 +47,8 @@ pub fn verify(token: String, conn: MainDatabase) -> Result { .find(uuid::Uuid::parse_str(&jti)?) .get_result::(&*conn)?; - if tok.deleted_at.is_none() { - return Err(eyre!("token was deleted")); + if tok.deleted_at.is_some() { + return Err(eyre!("token was deleted at {}", tok.deleted_at.unwrap())); } if tok.user_id != uid { diff --git a/src/main.rs b/src/main.rs index 3fed461..e911807 100644 --- a/src/main.rs +++ b/src/main.rs @@ -119,7 +119,8 @@ fn main() -> Result<()> { color_eyre::install()?; tracing_subscriber::fmt::init(); - tracing::trace!("JWT secret: {:?}", *jwt::SECRET); + let _ = *jwt::SECRET; + rocket::ignite() .attach(OAuth2::::fairing("gitea")) .attach(MainDatabase::fairing())