aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-05-31 03:26:45 +0200
committermetamuffin <metamuffin@disroot.org>2025-05-31 03:26:45 +0200
commit3e834092ba230ee081065a3b80ad227d585b5a13 (patch)
treeb168d1524045716e6922c137f1ad92bdf3f47994
parent3b15caade07e8fbe351fed9aceb3f435bf58368e (diff)
downloadjellything-3e834092ba230ee081065a3b80ad227d585b5a13.tar
jellything-3e834092ba230ee081065a3b80ad227d585b5a13.tar.bz2
jellything-3e834092ba230ee081065a3b80ad227d585b5a13.tar.zst
get rid of admin session; checking manually instead
-rw-r--r--locale/en.ini1
-rw-r--r--logic/src/admin/mod.rs22
-rw-r--r--logic/src/admin/user.rs14
-rw-r--r--logic/src/lib.rs1
-rw-r--r--logic/src/permission.rs18
-rw-r--r--logic/src/session.rs2
-rw-r--r--server/src/api.rs9
-rw-r--r--server/src/helper/session.rs27
-rw-r--r--server/src/ui/admin/log.rs15
-rw-r--r--server/src/ui/admin/mod.rs30
-rw-r--r--server/src/ui/admin/user.rs22
-rw-r--r--ui/src/admin/mod.rs2
12 files changed, 88 insertions, 75 deletions
diff --git a/locale/en.ini b/locale/en.ini
index 944a29d..58433a4 100644
--- a/locale/en.ini
+++ b/locale/en.ini
@@ -106,6 +106,7 @@ prop.vis.reduced=Reduced visibility
admin.dashboard.title=Admin Panel
admin.dashboard.import.inc=Start incremental import
admin.dashboard.import.full=Start full import
+admin.invite_create_success=Invite created: {invite}
page.curr=Page {cur} of {max}
page.prev=Previous page
diff --git a/logic/src/admin/mod.rs b/logic/src/admin/mod.rs
index 804cb2b..d8b21b6 100644
--- a/logic/src/admin/mod.rs
+++ b/logic/src/admin/mod.rs
@@ -7,38 +7,40 @@
pub mod log;
pub mod user;
-use crate::{DATABASE, session::AdminSession};
+use crate::{DATABASE, session::Session};
use anyhow::{Result, anyhow};
use jellyimport::{IMPORT_ERRORS, import_wrap};
use rand::Rng;
use std::time::{Duration, Instant};
use tokio::task::spawn_blocking;
-pub async fn get_import_errors(_session: &AdminSession) -> Vec<String> {
+pub async fn get_import_errors(_session: &Session) -> Vec<String> {
IMPORT_ERRORS.read().await.to_owned()
}
-pub fn list_invites(_session: &AdminSession) -> Result<Vec<String>> {
+pub fn list_invites(session: &Session) -> Result<Vec<String>> {
+ session.assert_admin()?;
DATABASE.list_invites()
}
-pub fn create_invite(_session: &AdminSession) -> Result<String> {
+pub fn create_invite(session: &Session) -> Result<String> {
+ session.assert_admin()?;
let i = format!("{}", rand::rng().random::<u128>());
DATABASE.create_invite(&i)?;
Ok(i)
}
-pub fn delete_invite(_session: &AdminSession, invite: &str) -> Result<()> {
+pub fn delete_invite(session: &Session, invite: &str) -> Result<()> {
+ session.assert_admin()?;
if !DATABASE.delete_invite(invite)? {
Err(anyhow!("invite does not exist"))?;
};
Ok(())
}
-pub async fn update_search_index(_session: &AdminSession) -> Result<()> {
+pub async fn update_search_index(session: &Session) -> Result<()> {
+ session.assert_admin()?;
spawn_blocking(move || DATABASE.search_create_index()).await?
}
-pub async fn do_import(
- _session: &AdminSession,
- incremental: bool,
-) -> Result<(Duration, Result<()>)> {
+pub async fn do_import(session: &Session, incremental: bool) -> Result<(Duration, Result<()>)> {
+ session.assert_admin()?;
let t = Instant::now();
if !incremental {
DATABASE.clear_nodes()?;
diff --git a/logic/src/admin/user.rs b/logic/src/admin/user.rs
index e277077..15356a8 100644
--- a/logic/src/admin/user.rs
+++ b/logic/src/admin/user.rs
@@ -4,25 +4,28 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-use crate::{DATABASE, session::AdminSession};
+use crate::{DATABASE, session::Session};
use anyhow::{Result, anyhow};
use jellycommon::{
api::ApiAdminUsersResponse,
user::{User, UserPermission},
};
-pub fn admin_users(_session: &AdminSession) -> Result<ApiAdminUsersResponse> {
+pub fn admin_users(session: &Session) -> Result<ApiAdminUsersResponse> {
+ session.assert_admin()?;
// TODO dont return useless info like passwords
Ok(ApiAdminUsersResponse {
users: DATABASE.list_users()?,
})
}
-pub fn get_user(_session: &AdminSession, username: &str) -> Result<User> {
+pub fn get_user(session: &Session, username: &str) -> Result<User> {
+ session.assert_admin()?;
DATABASE
.get_user(username)?
.ok_or(anyhow!("user not found"))
}
-pub fn delete_user(_session: &AdminSession, username: &str) -> Result<()> {
+pub fn delete_user(session: &Session, username: &str) -> Result<()> {
+ session.assert_admin()?;
if !DATABASE.delete_user(&username)? {
Err(anyhow!("user did not exist"))?;
}
@@ -35,11 +38,12 @@ pub enum GrantState {
Unset,
}
pub fn update_user_perms(
- _session: &AdminSession,
+ session: &Session,
username: &str,
perm: UserPermission,
action: GrantState,
) -> Result<()> {
+ session.assert_admin()?;
DATABASE.update_user(username, |user| {
match action {
GrantState::Grant => drop(user.permissions.0.insert(perm.clone(), true)),
diff --git a/logic/src/lib.rs b/logic/src/lib.rs
index 9988ed2..0bd44d7 100644
--- a/logic/src/lib.rs
+++ b/logic/src/lib.rs
@@ -16,6 +16,7 @@ pub mod search;
pub mod session;
pub mod stats;
pub mod account;
+pub mod permission;
use anyhow::Context;
use anyhow::Result;
diff --git a/logic/src/permission.rs b/logic/src/permission.rs
new file mode 100644
index 0000000..c23ad41
--- /dev/null
+++ b/logic/src/permission.rs
@@ -0,0 +1,18 @@
+/*
+ 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) 2025 metamuffin <metamuffin.org>
+*/
+
+use crate::session::Session;
+use anyhow::{Result, anyhow};
+
+impl Session {
+ pub fn assert_admin(&self) -> Result<()> {
+ if self.user.admin {
+ Ok(())
+ } else {
+ Err(anyhow!("Permission denied."))
+ }
+ }
+}
diff --git a/logic/src/session.rs b/logic/src/session.rs
index 615694c..6f168e3 100644
--- a/logic/src/session.rs
+++ b/logic/src/session.rs
@@ -22,8 +22,6 @@ pub struct Session {
pub user: User,
}
-pub struct AdminSession(pub Session);
-
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionData {
username: String,
diff --git a/server/src/api.rs b/server/src/api.rs
index d983548..4fecfb6 100644
--- a/server/src/api.rs
+++ b/server/src/api.rs
@@ -7,11 +7,7 @@ use super::ui::error::MyResult;
use crate::helper::{accept::AcceptJson, language::AcceptLanguage, A};
use jellycommon::{user::CreateSessionParams, NodeID};
use jellyimport::asset_token::AssetInner;
-use jellylogic::{
- login::login_logic,
- node::get_nodes_modified_since,
- session::{AdminSession, Session},
-};
+use jellylogic::{login::login_logic, node::get_nodes_modified_since, session::Session};
use jellyui::locale::get_translation_table;
use rocket::{get, post, response::Redirect, serde::json::Json, Either};
use serde_json::{json, Value};
@@ -60,7 +56,8 @@ pub fn r_api_account_login(data: Json<CreateSessionParams>) -> MyResult<Value> {
}
#[get("/api/asset_token_raw/<token>")]
-pub fn r_api_asset_token_raw(_admin: A<AdminSession>, token: &str) -> MyResult<Json<AssetInner>> {
+pub fn r_api_asset_token_raw(session: A<Session>, token: &str) -> MyResult<Json<AssetInner>> {
+ session.0.assert_admin()?;
Ok(Json(AssetInner::deser(token)?))
}
diff --git a/server/src/helper/session.rs b/server/src/helper/session.rs
index 090330b..1417df0 100644
--- a/server/src/helper/session.rs
+++ b/server/src/helper/session.rs
@@ -6,7 +6,7 @@
use super::A;
use crate::ui::error::MyError;
use anyhow::anyhow;
-use jellylogic::session::{bypass_auth_session, token_to_session, AdminSession, Session};
+use jellylogic::session::{bypass_auth_session, token_to_session, Session};
use log::warn;
use rocket::{
async_trait,
@@ -65,28 +65,3 @@ impl<'r> FromRequest<'r> for A<Session> {
}
}
}
-
-#[async_trait]
-impl<'r> FromRequest<'r> for A<AdminSession> {
- type Error = MyError;
- async fn from_request<'life0>(
- request: &'r Request<'life0>,
- ) -> request::Outcome<Self, Self::Error> {
- match session_from_request(request).await {
- Ok(x) => {
- if x.user.admin {
- Outcome::Success(A(AdminSession(x)))
- } else {
- Outcome::Error((
- Status::Unauthorized,
- MyError(anyhow!("you are not an admin")),
- ))
- }
- }
- Err(e) => {
- warn!("authentificated route rejected: {e:?}");
- Outcome::Forward(Status::Unauthorized)
- }
- }
- }
-}
diff --git a/server/src/ui/admin/log.rs b/server/src/ui/admin/log.rs
index f0a85f2..c26b697 100644
--- a/server/src/ui/admin/log.rs
+++ b/server/src/ui/admin/log.rs
@@ -10,7 +10,7 @@ use crate::{
use jellyimport::is_importing;
use jellylogic::{
admin::log::{get_log_buffer, get_log_stream},
- session::AdminSession,
+ session::Session,
};
use jellyui::{
admin::log::{render_log_line, ServerLogPage},
@@ -23,10 +23,11 @@ use serde_json::json;
#[get("/admin/log?<warnonly>", rank = 2)]
pub fn r_admin_log<'a>(
- session: A<AdminSession>,
+ session: A<Session>,
warnonly: bool,
lang: AcceptLanguage,
) -> MyResult<RawHtml<String>> {
+ session.0.assert_admin()?;
let AcceptLanguage(lang) = lang;
let messages = get_log_buffer(warnonly)
.into_iter()
@@ -40,7 +41,7 @@ pub fn r_admin_log<'a>(
RenderInfo {
importing: is_importing(),
session: Some(SessionInfo {
- user: session.0 .0.user,
+ user: session.0.user,
}),
},
lang,
@@ -49,14 +50,18 @@ pub fn r_admin_log<'a>(
#[get("/admin/log?stream&<warnonly>&<html>", rank = 1)]
pub fn r_admin_log_stream(
- _session: A<AdminSession>,
+ session: A<Session>,
ws: WebSocket,
warnonly: bool,
html: bool,
) -> Stream!['static] {
+ // TODO type problems
+ let ok = session.0.assert_admin().is_ok();
let mut stream = get_log_stream(warnonly);
Stream! { ws =>
- if html {
+ if !ok {
+ yield Message::Text("unauthorized".to_string());
+ } else if html {
let _ = ws;
while let Ok(line) = stream.recv().await {
yield Message::Text(render_log_line(&line));
diff --git a/server/src/ui/admin/mod.rs b/server/src/ui/admin/mod.rs
index e3eb2d6..4e07afb 100644
--- a/server/src/ui/admin/mod.rs
+++ b/server/src/ui/admin/mod.rs
@@ -7,7 +7,7 @@ pub mod log;
pub mod user;
use super::error::MyResult;
-use crate::helper::{language::AcceptLanguage, A};
+use crate::helper::{language::AcceptLanguage, RequestInfo, A};
use jellycommon::routes::u_admin_dashboard;
use jellyimport::is_importing;
use jellylogic::{
@@ -15,25 +15,27 @@ use jellylogic::{
create_invite, delete_invite, do_import, get_import_errors, list_invites,
update_search_index,
},
- session::AdminSession,
+ session::Session,
};
use jellyui::{
admin::AdminDashboardPage,
+ locale::tr,
render_page,
scaffold::{RenderInfo, SessionInfo},
};
use rocket::{
form::Form,
get, post,
- response::{content::RawHtml, Redirect},
+ response::{content::RawHtml, Flash, Redirect},
FromForm,
};
#[get("/admin/dashboard")]
pub async fn r_admin_dashboard(
- session: A<AdminSession>,
+ session: A<Session>,
lang: AcceptLanguage,
) -> MyResult<RawHtml<String>> {
+ session.0.assert_admin()?;
let AcceptLanguage(lang) = lang;
let flash = None;
@@ -57,7 +59,7 @@ pub async fn r_admin_dashboard(
RenderInfo {
importing: is_importing(),
session: Some(SessionInfo {
- user: session.0 .0.user,
+ user: session.0.user,
}),
},
lang,
@@ -65,9 +67,12 @@ pub async fn r_admin_dashboard(
}
#[post("/admin/generate_invite")]
-pub async fn r_admin_invite(session: A<AdminSession>) -> MyResult<Redirect> {
- let _ = create_invite(&session.0)?;
- Ok(Redirect::temporary(u_admin_dashboard()))
+pub async fn r_admin_invite(ri: RequestInfo) -> MyResult<Flash<Redirect>> {
+ let i = create_invite(&ri.session)?;
+ Ok(Flash::success(
+ Redirect::to(u_admin_dashboard()),
+ tr(ri.lang, "admin.invite_create_success").replace("{invite}", &i),
+ ))
}
#[derive(FromForm)]
@@ -77,21 +82,24 @@ pub struct DeleteInvite {
#[post("/admin/remove_invite", data = "<form>")]
pub async fn r_admin_remove_invite(
- session: A<AdminSession>,
+ session: A<Session>,
form: Form<DeleteInvite>,
) -> MyResult<Redirect> {
+ session.0.assert_admin()?;
delete_invite(&session.0, &form.invite)?;
Ok(Redirect::temporary(u_admin_dashboard()))
}
#[post("/admin/import?<incremental>")]
-pub async fn r_admin_import(session: A<AdminSession>, incremental: bool) -> MyResult<Redirect> {
+pub async fn r_admin_import(session: A<Session>, incremental: bool) -> MyResult<Redirect> {
+ session.0.assert_admin()?;
do_import(&session.0, incremental).await?.1?;
Ok(Redirect::temporary(u_admin_dashboard()))
}
#[post("/admin/update_search")]
-pub async fn r_admin_update_search(session: A<AdminSession>) -> MyResult<Redirect> {
+pub async fn r_admin_update_search(session: A<Session>) -> MyResult<Redirect> {
+ session.0.assert_admin()?;
update_search_index(&session.0).await?;
Ok(Redirect::temporary(u_admin_dashboard()))
}
diff --git a/server/src/ui/admin/user.rs b/server/src/ui/admin/user.rs
index 27d5256..e8dc332 100644
--- a/server/src/ui/admin/user.rs
+++ b/server/src/ui/admin/user.rs
@@ -12,7 +12,7 @@ use jellycommon::user::UserPermission;
use jellyimport::is_importing;
use jellylogic::{
admin::user::{admin_users, delete_user, get_user, update_user_perms, GrantState},
- session::AdminSession,
+ session::Session,
};
use jellyui::{
admin::user::{AdminUserPage, AdminUsersPage},
@@ -22,7 +22,8 @@ use jellyui::{
use rocket::{form::Form, get, post, response::content::RawHtml, FromForm, FromFormField};
#[get("/admin/users")]
-pub fn r_admin_users(session: A<AdminSession>, lang: AcceptLanguage) -> MyResult<RawHtml<String>> {
+pub fn r_admin_users(session: A<Session>, lang: AcceptLanguage) -> MyResult<RawHtml<String>> {
+ session.0.assert_admin()?;
let AcceptLanguage(lang) = lang;
let r = admin_users(&session.0)?;
Ok(RawHtml(render_page(
@@ -34,7 +35,7 @@ pub fn r_admin_users(session: A<AdminSession>, lang: AcceptLanguage) -> MyResult
RenderInfo {
importing: is_importing(),
session: Some(SessionInfo {
- user: session.0 .0.user,
+ user: session.0.user,
}),
},
lang,
@@ -43,10 +44,11 @@ pub fn r_admin_users(session: A<AdminSession>, lang: AcceptLanguage) -> MyResult
#[get("/admin/user/<name>")]
pub fn r_admin_user<'a>(
- session: A<AdminSession>,
+ session: A<Session>,
name: &'a str,
lang: AcceptLanguage,
) -> MyResult<RawHtml<String>> {
+ session.0.assert_admin()?;
let AcceptLanguage(lang) = lang;
let user = get_user(&session.0, name)?;
@@ -59,7 +61,7 @@ pub fn r_admin_user<'a>(
RenderInfo {
importing: is_importing(),
session: Some(SessionInfo {
- user: session.0 .0.user,
+ user: session.0.user,
}),
},
lang,
@@ -81,11 +83,12 @@ pub enum UrlGrantState {
#[post("/admin/user/<name>/update_permission", data = "<form>")]
pub fn r_admin_user_permission(
- session: A<AdminSession>,
+ session: A<Session>,
form: Form<UserPermissionForm>,
name: &str,
lang: AcceptLanguage,
) -> MyResult<RawHtml<String>> {
+ session.0.assert_admin()?;
let AcceptLanguage(lang) = lang;
let perm = serde_json::from_str::<UserPermission>(&form.permission)
.context("parsing provided permission")?;
@@ -112,7 +115,7 @@ pub fn r_admin_user_permission(
RenderInfo {
importing: is_importing(),
session: Some(SessionInfo {
- user: session.0 .0.user,
+ user: session.0.user,
}),
},
lang,
@@ -121,10 +124,11 @@ pub fn r_admin_user_permission(
#[post("/admin/<name>/remove")]
pub fn r_admin_remove_user(
- session: A<AdminSession>,
+ session: A<Session>,
name: &str,
lang: AcceptLanguage,
) -> MyResult<RawHtml<String>> {
+ session.0.assert_admin()?;
let AcceptLanguage(lang) = lang;
delete_user(&session.0, name)?;
let r = admin_users(&session.0)?;
@@ -138,7 +142,7 @@ pub fn r_admin_remove_user(
RenderInfo {
importing: is_importing(),
session: Some(SessionInfo {
- user: session.0 .0.user,
+ user: session.0.user,
}),
},
lang,
diff --git a/ui/src/admin/mod.rs b/ui/src/admin/mod.rs
index 5898f45..394f1c6 100644
--- a/ui/src/admin/mod.rs
+++ b/ui/src/admin/mod.rs
@@ -7,7 +7,7 @@
pub mod log;
pub mod user;
-use crate::{Page, locale::Language, scaffold::FlashDisplay};
+use crate::{locale::{tr, Language}, scaffold::FlashDisplay, Page};
use jellycommon::routes::{
u_admin_import, u_admin_invite_create, u_admin_invite_remove, u_admin_log,
u_admin_update_search, u_admin_users,