diff options
author | metamuffin <metamuffin@disroot.org> | 2023-08-01 19:56:38 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-08-01 19:56:38 +0200 |
commit | f7992589cf45c699599a7ee5fc4634c9db16ff87 (patch) | |
tree | 973c2e0bc9d50a9e137f999b3c1f231e8471c4be /server | |
parent | 551e62a6012284823d6b22a9257c3fae07de7fd9 (diff) | |
download | jellything-f7992589cf45c699599a7ee5fc4634c9db16ff87.tar jellything-f7992589cf45c699599a7ee5fc4634c9db16ff87.tar.bz2 jellything-f7992589cf45c699599a7ee5fc4634c9db16ff87.tar.zst |
error format depends on accept header
Diffstat (limited to 'server')
-rw-r--r-- | server/src/config.rs | 3 | ||||
-rw-r--r-- | server/src/database.rs | 14 | ||||
-rw-r--r-- | server/src/routes/api/error.rs | 68 | ||||
-rw-r--r-- | server/src/routes/api/mod.rs | 22 | ||||
-rw-r--r-- | server/src/routes/mod.rs | 4 | ||||
-rw-r--r-- | server/src/routes/ui/account/admin.rs | 10 | ||||
-rw-r--r-- | server/src/routes/ui/account/mod.rs | 37 | ||||
-rw-r--r-- | server/src/routes/ui/account/session/guard.rs | 2 | ||||
-rw-r--r-- | server/src/routes/ui/account/settings.rs | 2 | ||||
-rw-r--r-- | server/src/routes/ui/error.rs | 32 | ||||
-rw-r--r-- | server/src/routes/ui/style/transition.js | 14 |
11 files changed, 74 insertions, 134 deletions
diff --git a/server/src/config.rs b/server/src/config.rs index 0de7e90..0417878 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -4,7 +4,7 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use serde::{Deserialize, Serialize}; -use std::{fs::File, path::PathBuf}; +use std::{collections::HashMap, fs::File, path::PathBuf}; #[derive(Debug, Deserialize, Serialize, Default)] pub struct GlobalConfig { @@ -19,6 +19,7 @@ pub struct GlobalConfig { pub admin_password: String, pub cookie_key: String, pub login_expire: i64, + pub remote_credentials: HashMap<String, (String, String)>, } pub fn load_global_config() -> GlobalConfig { diff --git a/server/src/database.rs b/server/src/database.rs index eb88bda..12a6564 100644 --- a/server/src/database.rs +++ b/server/src/database.rs @@ -5,7 +5,7 @@ */ use crate::{routes::ui::account::hash_password, CONF}; use anyhow::Context; -use jellycommon::{SeekIndex, Node}; +use jellycommon::{Node, SeekIndex}; use log::info; use serde::{Deserialize, Serialize}; use std::path::Path; @@ -14,8 +14,8 @@ use typed_sled::Tree; pub struct Database { pub db: sled::Db, - pub users: Tree<String, User>, - pub invites: Tree<String, ()>, + pub user: Tree<String, User>, + pub invite: Tree<String, ()>, pub node: Tree<String, Node>, pub seek_index: Tree<(String, usize), SeekIndex>, } @@ -34,9 +34,9 @@ impl Database { let db = sled::open(path).context("opening database")?; info!("creating trees"); let r = Ok(Self { - users: Tree::open(&db, "users"), - invites: Tree::open(&db, "invites"), - node: Tree::open(&db, "items"), + user: Tree::open(&db, "user"), + invite: Tree::open(&db, "invite"), + node: Tree::open(&db, "node"), seek_index: Tree::open(&db, "seek_index"), db, }); @@ -44,7 +44,7 @@ impl Database { r } pub fn create_admin(&self) { - self.users + self.user .insert( &CONF.admin_username, &User { diff --git a/server/src/routes/api/error.rs b/server/src/routes/api/error.rs deleted file mode 100644 index a1d0588..0000000 --- a/server/src/routes/api/error.rs +++ /dev/null @@ -1,68 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2023 metamuffin <metamuffin.org> -*/ -// TODO: Slightâ„¢ code duplication with `ui/error.rs` - -use crate::routes::ui::error::MyError; -use rocket::{ - catch, - http::Status, - response::{self, Responder}, - Request, -}; -use serde_json::{json, Value}; -use std::fmt::Display; - -#[catch(default)] -pub fn r_api_catch<'a>(status: Status, _request: &Request) -> Value { - json!({ "error": format!("{status}") }) -} - -pub type ApiResult<T> = Result<T, ApiError>; - -#[derive(Debug)] -pub struct ApiError(pub anyhow::Error); - -impl<'r> Responder<'r, 'static> for ApiError { - fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { - json!({ "error": format!("{}", self.0) }).respond_to(req) - } -} - -impl Display for ApiError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} -impl From<anyhow::Error> for ApiError { - fn from(err: anyhow::Error) -> ApiError { - ApiError(err) - } -} -impl From<std::fmt::Error> for ApiError { - fn from(err: std::fmt::Error) -> ApiError { - ApiError(anyhow::anyhow!("{err}")) - } -} -impl From<std::io::Error> for ApiError { - fn from(err: std::io::Error) -> Self { - ApiError(anyhow::anyhow!("{err}")) - } -} -impl From<sled::Error> for ApiError { - fn from(err: sled::Error) -> Self { - ApiError(anyhow::anyhow!("{err}")) - } -} -impl From<serde_json::Error> for ApiError { - fn from(err: serde_json::Error) -> Self { - ApiError(anyhow::anyhow!("{err}")) - } -} -impl From<MyError> for ApiError { - fn from(value: MyError) -> Self { - Self(value.0) - } -} diff --git a/server/src/routes/api/mod.rs b/server/src/routes/api/mod.rs index d49ecec..b39950c 100644 --- a/server/src/routes/api/mod.rs +++ b/server/src/routes/api/mod.rs @@ -3,11 +3,13 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin <metamuffin.org> */ -pub mod error; -use super::ui::account::{login_logic, LoginForm}; -use crate::{database::Database, routes::api::error::ApiResult}; -use rocket::{get, http::CookieJar, post, response::Redirect, serde::json::Json, State}; +use super::ui::{ + account::{login_logic, LoginForm}, + error::MyResult, +}; +use crate::database::Database; +use rocket::{get, post, response::Redirect, serde::json::Json, State}; use serde_json::{json, Value}; #[get("/api")] @@ -17,15 +19,11 @@ pub fn r_api_root() -> Redirect { #[get("/api/version")] pub fn r_api_version() -> &'static str { - "1" + "2" } #[post("/api/account/login", data = "<data>")] -pub fn r_api_account_login( - database: &State<Database>, - jar: &CookieJar, - data: Json<LoginForm>, -) -> ApiResult<Value> { - login_logic(jar, database, &data.username, &data.password)?; - Ok(json!({ "ok": true })) +pub fn r_api_account_login(database: &State<Database>, data: Json<LoginForm>) -> MyResult<Value> { + let token = login_logic(database, &data.username, &data.password)?; + Ok(json!(token)) } diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index 52918d9..0305104 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -4,7 +4,7 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use crate::{database::Database, routes::ui::error::MyResult, CONF}; -use api::{error::r_api_catch, r_api_account_login, r_api_root, r_api_version}; +use api::{r_api_account_login, r_api_root, r_api_version}; use jellyremuxer::RemuxerContext; use rocket::{ catchers, config::SecretKey, fairing::AdHoc, fs::FileServer, get, http::Header, routes, Build, @@ -24,7 +24,7 @@ use ui::{ }, assets::r_item_assets, browser::r_all_items, - error::r_catch, + error::{r_api_catch, r_catch}, home::{r_home, r_home_unpriv}, node::r_library_node, player::r_player, diff --git a/server/src/routes/ui/account/admin.rs b/server/src/routes/ui/account/admin.rs index d7e5a36..37457b0 100644 --- a/server/src/routes/ui/account/admin.rs +++ b/server/src/routes/ui/account/admin.rs @@ -26,8 +26,8 @@ pub fn r_account_admin_dashboard( } // TODO this doesnt scale, pagination! - let users = database.users.iter().collect::<Result<Vec<_>, _>>()?; - let invites = database.invites.iter().collect::<Result<Vec<_>, _>>()?; + let users = database.user.iter().collect::<Result<Vec<_>, _>>()?; + let invites = database.invite.iter().collect::<Result<Vec<_>, _>>()?; Ok(LayoutPage { title: "Admin Dashboard".to_string(), @@ -69,7 +69,7 @@ pub fn r_account_admin_invite( } let i = format!("{}", rand::thread_rng().gen::<u128>()); - database.invites.insert(&i, &())?; + database.invite.insert(&i, &())?; Ok(LayoutPage { title: "Admin Dashboard".to_string(), @@ -95,7 +95,7 @@ pub fn r_account_admin_remove_user( Err(anyhow!("you not admin"))? } database - .users + .user .remove(&form.name)? .ok_or(anyhow!("user did not exist"))?; @@ -124,7 +124,7 @@ pub fn r_account_admin_remove_invite( Err(anyhow!("you not admin"))? } database - .invites + .invite .remove(&form.invite)? .ok_or(anyhow!("invite did not exist"))?; diff --git a/server/src/routes/ui/account/mod.rs b/server/src/routes/ui/account/mod.rs index 79fa652..f1b243c 100644 --- a/server/src/routes/ui/account/mod.rs +++ b/server/src/routes/ui/account/mod.rs @@ -113,11 +113,11 @@ pub fn r_account_register_post<'a>( None => return Err(format_form_error(form)), }; - if database.invites.remove(&form.invitation).unwrap().is_none() { + if database.invite.remove(&form.invitation).unwrap().is_none() { return Err(MyError(anyhow!("invitation invalid"))); } match database - .users + .user .compare_and_swap( &form.username, None, @@ -151,8 +151,14 @@ pub fn r_account_login_post( Some(v) => v, None => return Err(format_form_error(form)), }; - - login_logic(jar, database, &form.username, &form.password)?; + jar.add( + Cookie::build( + "session", + login_logic(database, &form.username, &form.password)?, + ) + .permanent() + .finish(), + ); Ok(Redirect::found(uri!(r_home()))) } @@ -163,17 +169,12 @@ pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Redirect> { Ok(Redirect::found(uri!(r_home()))) } -pub fn login_logic( - jar: &CookieJar, - database: &Database, - username: &str, - password: &str, -) -> MyResult<()> { +pub fn login_logic(database: &Database, username: &str, password: &str) -> MyResult<String> { // hashing the password regardless if the accounts exists to prevent timing attacks let password = hash_password(username, password); let user = database - .users + .user .get(&username.to_string())? .ok_or(anyhow!("invalid password"))?; @@ -181,16 +182,10 @@ pub fn login_logic( Err(anyhow!("invalid password"))? } - jar.add( - Cookie::build( - "session", - session::token::create(user.name, Duration::days(CONF.login_expire)), - ) - .permanent() - .finish(), - ); - - Ok(()) + Ok(session::token::create( + user.name, + Duration::days(CONF.login_expire), + )) } pub fn format_form_error<T>(form: Form<Contextual<T>>) -> MyError { diff --git a/server/src/routes/ui/account/session/guard.rs b/server/src/routes/ui/account/session/guard.rs index c6f5c29..e2bc093 100644 --- a/server/src/routes/ui/account/session/guard.rs +++ b/server/src/routes/ui/account/session/guard.rs @@ -34,7 +34,7 @@ impl Session { } let db = req.guard::<&State<Database>>().await.unwrap(); - let user = db.users.get(&username)?.ok_or(anyhow!("user not found"))?; + let user = db.user.get(&username)?.ok_or(anyhow!("user not found"))?; Ok(Session { user }) } diff --git a/server/src/routes/ui/account/settings.rs b/server/src/routes/ui/account/settings.rs index 59b10b7..b02c871 100644 --- a/server/src/routes/ui/account/settings.rs +++ b/server/src/routes/ui/account/settings.rs @@ -82,7 +82,7 @@ pub fn r_account_settings_post( }; let mut out = String::new(); - database.users.fetch_and_update(&session.user.name, |k| { + database.user.fetch_and_update(&session.user.name, |k| { k.map(|mut k| { if let Some(password) = &form.password { k.password = hash_password(&session.user.name, password); diff --git a/server/src/routes/ui/error.rs b/server/src/routes/ui/error.rs index 88573a6..190650f 100644 --- a/server/src/routes/ui/error.rs +++ b/server/src/routes/ui/error.rs @@ -7,10 +7,11 @@ use super::layout::{DynLayoutPage, LayoutPage}; use crate::{routes::ui::account::rocket_uri_macro_r_account_login, uri}; use rocket::{ catch, - http::Status, + http::{MediaType, Status}, response::{self, Responder}, Request, }; +use serde_json::{json, Value}; use std::fmt::Display; #[catch(default)] @@ -28,6 +29,11 @@ pub fn r_catch<'a>(status: Status, _request: &Request) -> DynLayoutPage<'a> { } } +#[catch(default)] +pub fn r_api_catch<'a>(status: Status, _request: &Request) -> Value { + json!({ "error": format!("{status}") }) +} + pub type MyResult<T> = Result<T, MyError>; #[derive(Debug)] @@ -35,15 +41,23 @@ pub struct MyError(pub anyhow::Error); impl<'r> Responder<'r, 'static> for MyError { fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { - LayoutPage { - title: "Error".to_string(), - content: markup::new! { - h2 { "An error occured. Nobody is sorry"} - pre.error { @format!("{:?}", self.0) } - }, - ..Default::default() + if req + .accept() + .map(|a| a.preferred().exact_eq(&MediaType::JSON)) + .unwrap_or(true) + { + json!({ "error": format!("{}", self.0) }).respond_to(req) + } else { + LayoutPage { + title: "Error".to_string(), + content: markup::new! { + h2 { "An error occured. Nobody is sorry"} + pre.error { @format!("{:?}", self.0) } + }, + ..Default::default() + } + .respond_to(req) } - .respond_to(req) } } diff --git a/server/src/routes/ui/style/transition.js b/server/src/routes/ui/style/transition.js index 7d39176..df09277 100644 --- a/server/src/routes/ui/style/transition.js +++ b/server/src/routes/ui/style/transition.js @@ -6,14 +6,14 @@ /// <reference lib="dom" /> const duration = 0.2 -globalThis.addEventListener("load", () => { - patch_page() -}) +// globalThis.addEventListener("load", () => { +// patch_page() +// }) -globalThis.addEventListener("popstate", (_e) => { - transition_to(window.location.href, true) - // transition_to(_e.state.href, true) -}) +// globalThis.addEventListener("popstate", (_e) => { +// transition_to(window.location.href, true) +// // transition_to(_e.state.href, true) +// }) function patch_page() { document.querySelectorAll("a").forEach(el => { |