diff --git a/Cargo.lock b/Cargo.lock index 9269a68..6f64c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -809,18 +809,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", -] - [[package]] name = "globset" version = "0.4.18" @@ -1397,13 +1385,10 @@ dependencies = [ "displaydoc", "notify-debouncer-full", "password-auth", - "rand 0.9.2", "serde", - "serde_json", "sqlx", "tera", "thiserror 2.0.17", - "time", "tokio", "tower-livereload", "tower-sessions", @@ -1469,7 +1454,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand", "smallvec", "zeroize", ] @@ -1567,9 +1552,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a2a4764cc1f8d961d802af27193c6f4f0124bd0e76e8393cf818e18880f0524" dependencies = [ "argon2", - "getrandom 0.2.17", + "getrandom", "password-hash", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -1579,7 +1564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1679,7 +1664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.5", + "rand", ] [[package]] @@ -1772,12 +1757,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - [[package]] name = "rand" version = "0.8.5" @@ -1785,18 +1764,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", + "rand_chacha", + "rand_core", ] [[package]] @@ -1806,17 +1775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", + "rand_core", ] [[package]] @@ -1825,16 +1784,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", + "getrandom", ] [[package]] @@ -1916,7 +1866,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core 0.6.4", + "rand_core", "signature", "spki", "subtle", @@ -2081,7 +2031,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2259,7 +2209,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand", "rsa", "serde", "sha1", @@ -2298,7 +2248,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.5", + "rand", "serde", "serde_json", "sha2", @@ -2407,7 +2357,7 @@ dependencies = [ "percent-encoding", "pest", "pest_derive", - "rand 0.8.5", + "rand", "regex", "serde", "serde_json", @@ -2466,30 +2416,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde_core", + "serde", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2647,7 +2597,7 @@ dependencies = [ "futures", "http", "parking_lot", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror 2.0.17", @@ -2853,15 +2803,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "wasite" version = "0.1.0" @@ -3140,12 +3081,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" - [[package]] name = "writeable" version = "0.6.2" diff --git a/nixie-server/Cargo.toml b/nixie-server/Cargo.toml index f87a6a8..9be0ebb 100644 --- a/nixie-server/Cargo.toml +++ b/nixie-server/Cargo.toml @@ -23,6 +23,3 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] } tera = "1.20.1" notify-debouncer-full = "0.6.0" tower-livereload = "0.10.2" -time = "0.3.45" -rand = "0.9.2" -serde_json.workspace = true diff --git a/nixie-server/migrations/20260123170914_create_api_keys.down.sql b/nixie-server/migrations/20260123170914_create_api_keys.down.sql deleted file mode 100644 index ede83eb..0000000 --- a/nixie-server/migrations/20260123170914_create_api_keys.down.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Add migration script here - -DROP TABLE IF EXISTS api_keys; diff --git a/nixie-server/migrations/20260123170914_create_api_keys.up.sql b/nixie-server/migrations/20260123170914_create_api_keys.up.sql deleted file mode 100644 index 369a104..0000000 --- a/nixie-server/migrations/20260123170914_create_api_keys.up.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Add migration script here - -CREATE TABLE IF NOT EXISTS api_keys -( - id INTEGER PRIMARY KEY NOT NULL, - user_id INTEGER NOT NULL REFERENCES users(id), - token TEXT NOT NULL, - name TEXT NOT NULL, - expiration_date TEXT NOT NULL, - permissions TEXT NOT NULL, - revoked BOOLEAN NOT NULL -); diff --git a/nixie-server/src/main.rs b/nixie-server/src/main.rs index 2effe30..27be1d7 100644 --- a/nixie-server/src/main.rs +++ b/nixie-server/src/main.rs @@ -9,6 +9,7 @@ use axum::response::IntoResponse; use axum::routing::get; use axum_login::AuthManagerLayerBuilder; use axum_login::AuthnBackend; +use axum_login::login_required; use displaydoc::Display; use notify_debouncer_full::DebouncedEvent; use notify_debouncer_full::notify::EventKind; @@ -27,25 +28,20 @@ use tower_sessions_sqlx_store::SqliteStore; use tracing::error; use tracing_subscriber::EnvFilter; -pub mod settings; pub mod users; pub type WebResult = Result; -pub type TemplatedHtml = Html; #[derive(Debug, Error, Display)] pub enum AppError { /// An error occurred while templating Tera(#[from] tera::Error), - - /// An error occurred while interacting with the database - Sqlx(#[from] sqlx::Error), } impl IntoResponse for AppError { fn into_response(self) -> axum::response::Response { let mut error_context = Context::new(); - error_context.insert("error", &format!("{self:?}")); + error_context.insert("error", &self.to_string()); ( StatusCode::INTERNAL_SERVER_ERROR, Html( @@ -154,8 +150,9 @@ async fn run() -> anyhow::Result<()> { let reloader = livereload.reloader(); let app = Router::new() + .route("/protected", get(show_protected)) + .route_layer(login_required!(Backend, login_url = "/login")) .merge(users::routes()) - .merge(settings::routes()) .route("/", get(show_index)) .layer(auth_layer) .layer(livereload) @@ -202,7 +199,7 @@ async fn run() -> anyhow::Result<()> { } async fn show_index(renderer: Renderer) -> WebResult> { - renderer.render_template("index.tera.html", None) + renderer.render_template("index.tera.html", None).map(Html) } async fn shutdown_signal(handle: AbortHandle) { @@ -237,7 +234,7 @@ impl Renderer { &self, name: &str, context: impl Into>, - ) -> WebResult> { + ) -> WebResult { let mut main_context = Context::default(); if let Some(user) = self.auth.user.as_ref() { main_context.insert("logged_in", &true); @@ -246,6 +243,14 @@ impl Renderer { main_context.extend(context.into().unwrap_or_default()); - Ok(Html(TERA.read().unwrap().render(name, &main_context)?)) + Ok(TERA.read().unwrap().render(name, &main_context)?) } } + +async fn show_protected(renderer: Renderer) -> Html { + Html( + renderer + .render_template("protected.tera.html", None) + .unwrap(), + ) +} diff --git a/nixie-server/src/settings/mod.rs b/nixie-server/src/settings/mod.rs deleted file mode 100644 index f815848..0000000 --- a/nixie-server/src/settings/mod.rs +++ /dev/null @@ -1,147 +0,0 @@ -use axum::Form; -use axum::Router; -use axum::extract::State; -use axum::response::IntoResponse; -use axum::response::Redirect; -use axum::routing::get; -use axum::routing::post; -use axum_login::login_required; -use password_auth::generate_hash; -use rand::distr::Alphanumeric; -use rand::distr::SampleString; -use rand::rng; -use serde::Deserialize; -use serde::Serialize; -use sqlx::prelude::FromRow; -use tera::Context; -use time::Date; -use time::Duration; -use time::OffsetDateTime; -use time::Time; - -use crate::AppState; -use crate::AuthSession; -use crate::Renderer; -use crate::TemplatedHtml; -use crate::WebResult; - -pub fn routes() -> Router { - Router::new() - .route("/settings", get(show_settings)) - .route("/settings/change_password", get(show_change_password)) - .route("/settings/change_password", post(do_change_password)) - .route("/settings/api_keys", get(show_api_keys)) - .route("/settings/new_api_key", post(create_new_api_key)) - .route("/settings/revoke_api_key", post(revoke_api_key)) - .route_layer(login_required!(crate::Backend, login_url = "/login")) -} - -async fn show_settings(renderer: Renderer) -> WebResult { - renderer.render_template("settings/index.tera.html", None) -} - -async fn show_change_password(renderer: Renderer) -> WebResult { - renderer.render_template("settings/change_password.tera.html", None) -} - -async fn do_change_password() {} - -#[derive(Debug, FromRow, Serialize)] -pub struct ApiKey { - id: i64, - user_id: i64, - token: Vec, - name: String, - expiration_date: OffsetDateTime, - permissions: String, - revoked: bool, -} - -async fn show_api_keys( - renderer: Renderer, - app_state: State, - auth: AuthSession, -) -> WebResult { - let mut context = Context::new(); - - let api_keys: Vec = sqlx::query_as("SELECT * FROM api_keys WHERE user_id = ?") - .bind(auth.user.unwrap().id()) - .fetch_all(&app_state.db) - .await?; - - context.insert("api_keys", &api_keys.into_iter().map(|key| { - serde_json::json! {{ - "id": key.id, - "name": key.name, - "revoked": key.revoked, - "expiration_date": key.expiration_date.format(&time::format_description::well_known::iso8601::Iso8601::DATE).unwrap(), - }} - }).collect::>()); - - context.insert( - "one_year_date", - &OffsetDateTime::now_utc() - .replace_year(OffsetDateTime::now_utc().year() + 1) - .unwrap() - .format(&time::format_description::well_known::iso8601::Iso8601::DATE) - .unwrap(), - ); - - renderer.render_template("settings/api_keys.tera.html", context) -} - -#[derive(Debug, Deserialize)] -struct NewApiKeyForm { - name: String, - expiration_date: String, -} - -async fn create_new_api_key( - app_state: State, - auth: AuthSession, - new_api_key: Form, -) -> WebResult { - let values = Alphanumeric.sample_string(&mut rng(), 32); - let token = tokio::task::spawn_blocking(|| generate_hash(values)) - .await - .unwrap(); - - let expiration_date = Date::parse( - &new_api_key.expiration_date, - &time::format_description::well_known::Iso8601::DATE, - ) - .unwrap(); - - let expiration_date = - OffsetDateTime::new_utc(expiration_date, Time::from_hms(0, 0, 0).unwrap()); - - sqlx::query("INSERT INTO api_keys (user_id, token, name, expiration_date, permissions, revoked) VALUES (?, ?, ?, ?, ?, false)") - .bind(auth.user.unwrap().id()) - .bind(token) - .bind(new_api_key.name.clone()) - .bind(expiration_date) - .bind("") - .execute(&app_state.db) - .await?; - - Ok(Redirect::to("/settings/api_keys")) -} - -#[derive(Debug, Deserialize)] -struct RevokeApiKeyForm { - api_key_id: i64, -} - -async fn revoke_api_key( - app_state: State, - auth: AuthSession, - revoke_api_key: Form, -) -> WebResult { - sqlx::query("UPDATE api_keys SET revoked = true, token = \"\" WHERE id = ? AND user_id = ?") - .bind(revoke_api_key.api_key_id) - .bind(auth.user.unwrap().id()) - .execute(&app_state.db) - .await?; - - Ok(Redirect::to("/settings/api_keys")) -} diff --git a/nixie-server/src/users/login.rs b/nixie-server/src/users/login.rs index f0e77bf..9d5a575 100644 --- a/nixie-server/src/users/login.rs +++ b/nixie-server/src/users/login.rs @@ -10,7 +10,9 @@ use crate::UserCredentials; use crate::WebResult; pub async fn show_login(renderer: Renderer) -> WebResult> { - renderer.render_template("users/login.tera.html", None) + renderer + .render_template("users/login.tera.html", None) + .map(Html) } pub async fn do_login( diff --git a/nixie-server/src/users/register.rs b/nixie-server/src/users/register.rs index 572de1c..2684bec 100644 --- a/nixie-server/src/users/register.rs +++ b/nixie-server/src/users/register.rs @@ -11,7 +11,9 @@ use crate::UserCredentials; use crate::WebResult; pub async fn show_register(renderer: Renderer) -> WebResult> { - renderer.render_template("users/register.tera.html", None) + renderer + .render_template("users/register.tera.html", None) + .map(Html) } pub async fn do_register( diff --git a/nixie-server/templates/inputs.tera.html b/nixie-server/templates/inputs.tera.html index 8699ae2..c05724c 100644 --- a/nixie-server/templates/inputs.tera.html +++ b/nixie-server/templates/inputs.tera.html @@ -1,6 +1,6 @@ -{% macro text_input(label, name, id="",type="text",value="") %} +{% macro text_input(label, name, id="",type="text") %}
- +
{% endmacro text_input %} diff --git a/nixie-server/templates/internal_error.tera.html b/nixie-server/templates/internal_error.tera.html deleted file mode 100644 index c810531..0000000 --- a/nixie-server/templates/internal_error.tera.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "base.tera.html" %} -{% import "inputs.tera.html" as inputs %} - -{% block title %} -Home -{% endblock title %} - -{% block content %} -
-

There was an internal error

-

- {{ error }} -

- -
- -

- This error usually indicates that the problem is not on your side. -
- Additional information was logged for the operator. -
- Feel free to try again later. -

-
-{% endblock content %} diff --git a/nixie-server/templates/settings/api_keys.tera.html b/nixie-server/templates/settings/api_keys.tera.html deleted file mode 100644 index fc10891..0000000 --- a/nixie-server/templates/settings/api_keys.tera.html +++ /dev/null @@ -1,69 +0,0 @@ -{% extends "base.tera.html" %} -{% import "inputs.tera.html" as inputs %} - -{% block title %} -API Keys - {{ current_user.username }} -{% endblock title %} - -{% block content %} -
-
- {% include "settings/sidebar.tera.html" %} -
-
-

API Keys

-
- {{ inputs::text_input(label="Name", name="name", id="name", type="text") }} - {{ inputs::text_input(label="Expiration Date", name="expiration_date", id="expiration_date", type="date", value=one_year_date)}} -
- -
-
- -
- -

Current API Tokens

- - - - - - - - - - - - {% for api_key in api_keys %} - - - - - - - {% endfor %} - -
NameActiveExpiration DateActions
{{ api_key.name}} - {% if api_key.revoked %} - No Longer Active - {% else %} - Currently Active - {% endif %} - {{ api_key.expiration_date }} - {% if api_key.revoked %} - A revoked API Key cannot be revived - {% else %} -
- - -
- {% endif %} -
- -
-
-{% endblock content %} diff --git a/nixie-server/templates/settings/change_password.tera.html b/nixie-server/templates/settings/change_password.tera.html deleted file mode 100644 index a119c43..0000000 --- a/nixie-server/templates/settings/change_password.tera.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "base.tera.html" %} -{% import "inputs.tera.html" as inputs %} - -{% block title %} -Change Password - {{ current_user.username }} -{% endblock title %} - -{% block content %} -
-
- {% include "settings/sidebar.tera.html" %} -
-
-

Change Password

-
- {{ inputs::text_input(label="Old Password", name="old_password", id="old_password", type="password") }} - {{ inputs::text_input(label="New Password", name="password", id="password", type="password") }} - {{ inputs::text_input(label="Repeat New Password", name="confirm_password", id="confirm_password", type="password") }} -
- -
-
-
-
-{% endblock content %} diff --git a/nixie-server/templates/settings/index.tera.html b/nixie-server/templates/settings/index.tera.html deleted file mode 100644 index 2f50f1f..0000000 --- a/nixie-server/templates/settings/index.tera.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "base.tera.html" %} -{% import "inputs.tera.html" as inputs %} - -{% block title %} -Settings - {{ current_user.username }} -{% endblock title %} - -{% block content %} -
-
- {% include "settings/sidebar.tera.html" %} -
-
-

THIS IS YOUR MAIN SETTINGS WOOHOOOO

- -

Your username is: {{ current_user.username }}

-
-
-{% endblock content %} diff --git a/nixie-server/templates/settings/sidebar.tera.html b/nixie-server/templates/settings/sidebar.tera.html deleted file mode 100644 index d32f35e..0000000 --- a/nixie-server/templates/settings/sidebar.tera.html +++ /dev/null @@ -1,12 +0,0 @@ -

Settings

-