aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/src/lib.rs5
-rw-r--r--server/src/config.rs3
-rw-r--r--server/src/database.rs14
-rw-r--r--server/src/routes/api/error.rs68
-rw-r--r--server/src/routes/api/mod.rs22
-rw-r--r--server/src/routes/mod.rs4
-rw-r--r--server/src/routes/ui/account/admin.rs10
-rw-r--r--server/src/routes/ui/account/mod.rs37
-rw-r--r--server/src/routes/ui/account/session/guard.rs2
-rw-r--r--server/src/routes/ui/account/settings.rs2
-rw-r--r--server/src/routes/ui/error.rs32
-rw-r--r--server/src/routes/ui/style/transition.js14
12 files changed, 79 insertions, 134 deletions
diff --git a/common/src/lib.rs b/common/src/lib.rs
index 81fcfd8..4b3ac81 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -53,6 +53,11 @@ pub enum MediaSource {
Remote { host: String, remote_id: String },
}
+pub enum PublicMediaSource {
+ Local,
+ Remote(String),
+}
+
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LocalTrack {
pub path: PathBuf,
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 => {