aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock156
-rw-r--r--server/Cargo.toml2
-rw-r--r--server/src/main.rs7
-rw-r--r--server/src/routes/mod.rs3
-rw-r--r--server/src/routes/ui/account/session/guard.rs56
-rw-r--r--server/src/routes/ui/account/session/mod.rs2
-rw-r--r--server/src/routes/ui/admin/log.rs216
-rw-r--r--server/src/routes/ui/admin/mod.rs38
-rw-r--r--server/src/routes/ui/style/layout.css11
9 files changed, 321 insertions, 170 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 89f4b5a..9482302 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -159,6 +159,12 @@ dependencies = [
]
[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
+[[package]]
name = "async-channel"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -458,16 +464,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
-name = "chashmap"
-version = "2.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45"
-dependencies = [
- "owning_ref",
- "parking_lot 0.4.8",
-]
-
-[[package]]
name = "chrono"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -559,7 +555,7 @@ dependencies = [
"base64",
"hkdf",
"percent-encoding",
- "rand 0.8.5",
+ "rand",
"sha2",
"subtle",
"time 0.3.21",
@@ -629,7 +625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
- "rand_core 0.6.4",
+ "rand_core",
"typenum",
]
@@ -813,12 +809,6 @@ dependencies = [
]
[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-
-[[package]]
name = "futures"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1287,7 +1277,6 @@ dependencies = [
"async-std",
"base64",
"bincode 2.0.0-rc.3",
- "chashmap",
"chrono",
"env_logger",
"futures",
@@ -1297,7 +1286,7 @@ dependencies = [
"log",
"markup",
"once_cell",
- "rand 0.8.5",
+ "rand",
"rocket",
"serde",
"serde_json",
@@ -1306,6 +1295,7 @@ dependencies = [
"tokio",
"tokio-util",
"typed-sled",
+ "vte",
]
[[package]]
@@ -1426,12 +1416,6 @@ dependencies = [
]
[[package]]
-name = "maybe-uninit"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
-
-[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1611,15 +1595,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
-name = "owning_ref"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
-dependencies = [
- "stable_deref_trait",
-]
-
-[[package]]
name = "parking"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1627,16 +1602,6 @@ checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
[[package]]
name = "parking_lot"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
-dependencies = [
- "owning_ref",
- "parking_lot_core 0.2.14",
-]
-
-[[package]]
-name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
@@ -1658,18 +1623,6 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
-dependencies = [
- "libc",
- "rand 0.4.6",
- "smallvec 0.6.14",
- "winapi",
-]
-
-[[package]]
-name = "parking_lot_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
@@ -1678,7 +1631,7 @@ dependencies = [
"instant",
"libc",
"redox_syscall 0.2.16",
- "smallvec 1.10.0",
+ "smallvec",
"winapi",
]
@@ -1691,7 +1644,7 @@ dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.2.16",
- "smallvec 1.10.0",
+ "smallvec",
"windows-sys 0.45.0",
]
@@ -1702,7 +1655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
- "rand_core 0.6.4",
+ "rand_core",
"subtle",
]
@@ -1840,26 +1793,13 @@ dependencies = [
[[package]]
name = "rand"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
-dependencies = [
- "fuchsia-cprng",
- "libc",
- "rand_core 0.3.1",
- "rdrand",
- "winapi",
-]
-
-[[package]]
-name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
- "rand_core 0.6.4",
+ "rand_core",
]
[[package]]
@@ -1869,26 +1809,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core",
]
[[package]]
name = "rand_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-dependencies = [
- "rand_core 0.4.2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
-
-[[package]]
-name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
@@ -1897,15 +1822,6 @@ dependencies = [
]
[[package]]
-name = "rdrand"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
-dependencies = [
- "rand_core 0.3.1",
-]
-
-[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2034,7 +1950,7 @@ dependencies = [
"num_cpus",
"parking_lot 0.12.1",
"pin-project-lite",
- "rand 0.8.5",
+ "rand",
"ref-cast",
"rocket_codegen",
"rocket_http",
@@ -2086,7 +2002,7 @@ dependencies = [
"pin-project-lite",
"ref-cast",
"serde",
- "smallvec 1.10.0",
+ "smallvec",
"stable-pattern",
"state",
"time 0.3.21",
@@ -2278,15 +2194,6 @@ dependencies = [
[[package]]
name = "smallvec"
-version = "0.6.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0"
-dependencies = [
- "maybe-uninit",
-]
-
-[[package]]
-name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
@@ -2317,12 +2224,6 @@ dependencies = [
]
[[package]]
-name = "stable_deref_trait"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
-
-[[package]]
name = "state"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2630,7 +2531,7 @@ dependencies = [
"once_cell",
"regex",
"sharded-slab",
- "smallvec 1.10.0",
+ "smallvec",
"thread_local",
"tracing",
"tracing-core",
@@ -2766,6 +2667,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314"
[[package]]
+name = "vte"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
+dependencies = [
+ "arrayvec",
+ "utf8parse",
+ "vte_generate_state_changes",
+]
+
+[[package]]
+name = "vte_generate_state_changes"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/server/Cargo.toml b/server/Cargo.toml
index d800983..f9ecac2 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -16,10 +16,10 @@ log = "0.4.19"
env_logger = "0.10.0"
anyhow = "1.0.72"
once_cell = "1.18.0"
-chashmap = "2.2.2"
rand = "0.8.5"
base64 = "0.21.2"
chrono = { version = "0.4.26", features = ["serde"] }
+vte = "0.11.1"
argon2 = "0.5.1"
sha2 = "0.10.7"
diff --git a/server/src/main.rs b/server/src/main.rs
index 60b5135..3da0e43 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -5,6 +5,7 @@
*/
#![feature(lazy_cell)]
+use crate::routes::ui::admin::log::enable_logging;
use database::Database;
use federation::Federation;
use jellycommon::config::GlobalConfig;
@@ -22,11 +23,7 @@ pub static CONF: Lazy<GlobalConfig> =
Lazy::new(|| serde_json::from_reader(File::open("data/config.json").unwrap()).unwrap());
fn main() {
- env_logger::builder()
- .filter_level(log::LevelFilter::Info)
- .parse_env("LOG")
- .init();
-
+ enable_logging();
#[cfg(feature = "bypass-auth")]
log::warn!("authentification bypass enabled");
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs
index 1490290..38d0390 100644
--- a/server/src/routes/mod.rs
+++ b/server/src/routes/mod.rs
@@ -22,7 +22,7 @@ use ui::{
settings::{r_account_settings, r_account_settings_post},
},
admin::{
- r_admin_dashboard, r_admin_import, r_admin_invite, r_admin_remove_invite,
+ log::r_admin_log, r_admin_dashboard, r_admin_import, r_admin_invite, r_admin_remove_invite,
r_admin_remove_user,
},
assets::r_item_assets,
@@ -104,6 +104,7 @@ pub fn build_rocket(
r_admin_remove_user,
r_admin_remove_invite,
r_admin_import,
+ r_admin_log,
r_account_settings,
r_account_settings_post,
r_api_version,
diff --git a/server/src/routes/ui/account/session/guard.rs b/server/src/routes/ui/account/session/guard.rs
index e2bc093..19d68ad 100644
--- a/server/src/routes/ui/account/session/guard.rs
+++ b/server/src/routes/ui/account/session/guard.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>
*/
-use super::Session;
+use super::{AdminSession, Session};
use crate::{database::Database, routes::ui::error::MyError};
use anyhow::anyhow;
use log::warn;
use rocket::{
+ async_trait,
+ http::Status,
outcome::Outcome,
request::{self, FromRequest},
Request, State,
@@ -40,31 +42,43 @@ impl Session {
}
}
+#[async_trait]
impl<'r> FromRequest<'r> for Session {
type Error = MyError;
+ async fn from_request<'life0>(
+ request: &'r Request<'life0>,
+ ) -> request::Outcome<Self, Self::Error> {
+ match Session::from_request_ut(request).await {
+ Ok(x) => Outcome::Success(x),
+ Err(e) => {
+ warn!("authentificated route rejected: {e:?}");
+ Outcome::Forward(())
+ }
+ }
+ }
+}
- fn from_request<'life0, 'async_trait>(
+#[async_trait]
+impl<'r> FromRequest<'r> for AdminSession {
+ type Error = MyError;
+ async fn from_request<'life0>(
request: &'r Request<'life0>,
- ) -> core::pin::Pin<
- Box<
- dyn core::future::Future<Output = request::Outcome<Self, Self::Error>>
- + core::marker::Send
- + 'async_trait,
- >,
- >
- where
- 'r: 'async_trait,
- 'life0: 'async_trait,
- Self: 'async_trait,
- {
- Box::pin(async move {
- match Self::from_request_ut(request).await {
- Ok(x) => Outcome::Success(x),
- Err(e) => {
- warn!("authentificated route rejected: {e:?}");
- Outcome::Forward(())
+ ) -> request::Outcome<Self, Self::Error> {
+ match Session::from_request_ut(request).await {
+ Ok(x) => {
+ if x.user.admin {
+ Outcome::Success(AdminSession(x))
+ } else {
+ Outcome::Failure((
+ Status::Unauthorized,
+ MyError(anyhow!("you are not an admin")),
+ ))
}
}
- })
+ Err(e) => {
+ warn!("authentificated route rejected: {e:?}");
+ Outcome::Forward(())
+ }
+ }
}
}
diff --git a/server/src/routes/ui/account/session/mod.rs b/server/src/routes/ui/account/session/mod.rs
index 2a7908f..89592c3 100644
--- a/server/src/routes/ui/account/session/mod.rs
+++ b/server/src/routes/ui/account/session/mod.rs
@@ -15,6 +15,8 @@ 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/routes/ui/admin/log.rs b/server/src/routes/ui/admin/log.rs
new file mode 100644
index 0000000..e264e8f
--- /dev/null
+++ b/server/src/routes/ui/admin/log.rs
@@ -0,0 +1,216 @@
+use crate::{
+ routes::ui::{
+ account::session::AdminSession,
+ error::MyResult,
+ layout::{DynLayoutPage, LayoutPage},
+ },
+ uri,
+};
+use log::Level;
+use rocket::get;
+use std::{
+ collections::VecDeque,
+ fmt::Write,
+ sync::{LazyLock, RwLock},
+};
+
+const MAX_LOG_LEN: usize = 4000;
+
+static LOGGER: LazyLock<Log> = LazyLock::new(Log::new);
+
+pub fn enable_logging() {
+ log::set_logger(&*LOGGER).unwrap();
+ log::set_max_level(log::LevelFilter::Debug);
+}
+
+pub struct Log {
+ inner: env_logger::Logger,
+ log: RwLock<(VecDeque<LogLine>, VecDeque<LogLine>)>,
+}
+
+pub struct LogLine {
+ module: Option<&'static str>,
+ level: Level,
+ message: String,
+}
+
+#[get("/admin/log?<warnonly>")]
+pub fn r_admin_log<'a>(_session: AdminSession, warnonly: bool) -> MyResult<DynLayoutPage<'a>> {
+ Ok(LayoutPage {
+ title: "Log".into(),
+ content: markup::new! {
+ h1 { "Server Log" }
+ a[href=uri!(r_admin_log(!warnonly))] { @if warnonly { "Show everything" } else { "Show only warnings" }}
+ code.log {
+ @let g = LOGGER.log.read().unwrap();
+ table { @for e in if warnonly { g.1.iter() } else { g.0.iter() } {
+ tr[class=format!("level-{:?}", e.level).to_ascii_lowercase()] {
+ td { @format_level(e.level) }
+ td { @e.module }
+ td { @markup::raw(vt100_to_html(&e.message)) }
+ }
+ }}
+ }
+ },
+ ..Default::default()
+ })
+}
+
+impl Log {
+ pub fn new() -> Self {
+ Self {
+ inner: env_logger::builder()
+ .filter_level(log::LevelFilter::Warn)
+ .parse_env("LOG")
+ .build(),
+ log: Default::default(),
+ }
+ }
+ fn should_log(&self, metadata: &log::Metadata) -> bool {
+ let level = metadata.level();
+ level
+ <= match metadata.target() {
+ x if x.starts_with("jellything::") => Level::Debug,
+ x if x.starts_with("rocket::") => Level::Info,
+ _ => Level::Warn,
+ }
+ }
+ fn do_log(&self, record: &log::Record) {
+ let mut w = self.log.write().unwrap();
+ w.0.push_back(LogLine {
+ module: record.module_path_static(),
+ level: record.level(),
+ message: record.args().to_string(),
+ });
+ while w.0.len() > MAX_LOG_LEN {
+ w.0.pop_front();
+ }
+ if record.level() <= Level::Warn {
+ w.1.push_back(LogLine {
+ module: record.module_path_static(),
+ level: record.level(),
+ message: record.args().to_string(),
+ });
+ while w.1.len() > MAX_LOG_LEN {
+ w.1.pop_front();
+ }
+ }
+ }
+}
+
+impl log::Log for Log {
+ fn enabled(&self, metadata: &log::Metadata) -> bool {
+ self.inner.enabled(metadata) || self.should_log(metadata)
+ }
+ fn log(&self, record: &log::Record) {
+ match (record.module_path_static(), record.line()) {
+ // TODO is there a better way to ignore those?
+ (Some("rocket::rocket"), Some(670)) => return,
+ (Some("rocket::server"), Some(401)) => return,
+ _ => {}
+ }
+ if self.inner.enabled(record.metadata()) {
+ self.inner.log(record);
+ }
+ if self.should_log(record.metadata()) {
+ self.do_log(record)
+ }
+ }
+ fn flush(&self) {
+ self.inner.flush();
+ }
+}
+
+fn vt100_to_html(s: &str) -> String {
+ let mut out = HtmlOut::default();
+ let mut st = vte::Parser::new();
+ for b in s.bytes() {
+ st.advance(&mut out, b);
+ }
+ out.s
+}
+
+fn format_level(level: Level) -> impl markup::Render {
+ let (s, c) = match level {
+ Level::Debug => ("DEBUG", "blue"),
+ Level::Error => ("ERROR", "red"),
+ Level::Warn => ("WARN", "yellow"),
+ Level::Info => ("INFO", "green"),
+ Level::Trace => ("TRACE", "lightblue"),
+ };
+ markup::new! { span[style=format!("color:{c}")] {@s} }
+}
+
+pub struct HtmlOut {
+ s: String,
+ color: bool,
+}
+impl Default for HtmlOut {
+ fn default() -> Self {
+ Self {
+ color: false,
+ s: String::new(),
+ }
+ }
+}
+impl HtmlOut {
+ pub fn set_color(&mut self, [r, g, b]: [u8; 3]) {
+ self.reset_color();
+ self.color = true;
+ write!(self.s, "<span style=color:#{:02x}{:02x}{:02x}>", r, g, b).unwrap()
+ }
+ pub fn reset_color(&mut self) {
+ if self.color {
+ write!(self.s, "</span>").unwrap();
+ self.color = false;
+ }
+ }
+}
+impl vte::Perform for HtmlOut {
+ fn print(&mut self, c: char) {
+ match c {
+ 'a'..='z' | 'A'..='Z' | '0'..='9' | ' ' => self.s.push(c),
+ x => write!(self.s, "&#{};", x as u32).unwrap(),
+ }
+ }
+
+ fn execute(&mut self, _byte: u8) {}
+ fn hook(&mut self, _params: &vte::Params, _i: &[u8], _ignore: bool, _a: char) {}
+ fn put(&mut self, _byte: u8) {}
+ fn unhook(&mut self) {}
+ fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {}
+ fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {
+ // self.s += &format!(" {:?} ", (_intermediates, _byte))
+ }
+
+ fn csi_dispatch(
+ &mut self,
+ params: &vte::Params,
+ _intermediates: &[u8],
+ _ignore: bool,
+ action: char,
+ ) {
+ let mut k = params.iter();
+ // self.s += &format!(" {:?} ", (params, action));
+ match action {
+ 'm' => match k.next().unwrap_or(&[0]).get(0).unwrap_or(&0) {
+ c @ (30..=37 | 40..=47) => {
+ let c = if *c >= 40 { *c - 10 } else { *c };
+ self.set_color(match c {
+ 30 => [0, 0, 0],
+ 31 => [255, 0, 0],
+ 32 => [0, 255, 0],
+ 33 => [255, 255, 0],
+ 34 => [0, 0, 255],
+ 35 => [255, 0, 255],
+ 36 => [0, 255, 255],
+ 37 => [255, 255, 255],
+ _ => unreachable!(),
+ });
+ }
+ _ => (),
+ },
+ _ => (),
+ }
+ }
+}
diff --git a/server/src/routes/ui/admin/mod.rs b/server/src/routes/ui/admin/mod.rs
index 0775423..f779700 100644
--- a/server/src/routes/ui/admin/mod.rs
+++ b/server/src/routes/ui/admin/mod.rs
@@ -3,12 +3,15 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2023 metamuffin <metamuffin.org>
*/
+pub mod log;
+
+use super::account::session::AdminSession;
use crate::{
database::Database,
federation::Federation,
import::import,
routes::ui::{
- account::session::Session,
+ admin::log::rocket_uri_macro_r_admin_log,
error::MyResult,
layout::{DynLayoutPage, FlashDisplay, LayoutPage},
},
@@ -21,12 +24,9 @@ use std::time::Instant;
#[get("/admin/dashboard")]
pub fn r_admin_dashboard(
- session: Session,
+ _session: AdminSession,
database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
- if !session.user.admin {
- Err(anyhow!("you not admin"))?
- }
admin_dashboard(database, None)
}
@@ -44,6 +44,10 @@ pub fn admin_dashboard<'a>(
content: markup::new! {
h1 { "Admin Panel" }
@FlashDisplay { flash: flash.clone() }
+ ul {
+ li{a[href=uri!(r_admin_log(true))] { "Server Log (Warnings only)" }}
+ li{a[href=uri!(r_admin_log(false))] { "Server Log (Full) " }}
+ }
h2 { "Library" }
form[method="POST", action=uri!(r_admin_import())] {
input[type="submit", value="(Re-)Import Library"];
@@ -76,13 +80,9 @@ pub fn admin_dashboard<'a>(
#[post("/admin/generate_invite")]
pub fn r_admin_invite(
- session: Session,
+ _session: AdminSession,
database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
- if !session.user.admin {
- Err(anyhow!("you not admin"))?
- }
-
let i = format!("{}", rand::thread_rng().gen::<u128>());
database.invite.insert(&i, &())?;
@@ -96,13 +96,11 @@ pub struct DeleteUser {
#[post("/admin/remove_user", data = "<form>")]
pub fn r_admin_remove_user(
- session: Session,
+ session: AdminSession,
database: &State<Database>,
form: Form<DeleteUser>,
) -> MyResult<DynLayoutPage<'static>> {
- if !session.user.admin {
- Err(anyhow!("you not admin"))?
- }
+ drop(session);
database
.user
.remove(&form.name)?
@@ -118,13 +116,11 @@ pub struct DeleteInvite {
#[post("/admin/remove_invite", data = "<form>")]
pub fn r_admin_remove_invite(
- session: Session,
+ session: AdminSession,
database: &State<Database>,
form: Form<DeleteInvite>,
) -> MyResult<DynLayoutPage<'static>> {
- if !session.user.admin {
- Err(anyhow!("you not admin"))?
- }
+ drop(session);
database
.invite
.remove(&form.invite)?
@@ -135,13 +131,11 @@ pub fn r_admin_remove_invite(
#[post("/admin/import")]
pub async fn r_admin_import(
- session: Session,
+ session: AdminSession,
database: &State<Database>,
federation: &State<Federation>,
) -> MyResult<DynLayoutPage<'static>> {
- if !session.user.admin {
- Err(anyhow!("you not admin"))?
- }
+ drop(session);
let t = Instant::now();
let r = import(&database, &federation).await;
admin_dashboard(
diff --git a/server/src/routes/ui/style/layout.css b/server/src/routes/ui/style/layout.css
index 09da718..e62e59a 100644
--- a/server/src/routes/ui/style/layout.css
+++ b/server/src/routes/ui/style/layout.css
@@ -33,12 +33,13 @@
* {
color: var(--font);
- font-family: "Cantarell", sans-serif;
- font-weight: 500;
-
scrollbar-width: thin;
scrollbar-color: var(--background-light) #0000;
}
+:root {
+ font-family: "Cantarell", sans-serif;
+ font-weight: 500;
+}
body {
background-color: var(--background-dark);
@@ -68,6 +69,10 @@ nav {
align-items: center;
}
+code {
+ font-family: monospace !important;
+}
+
nav a {
border: 0px solid transparent;
border-radius: 5px;