i broke everything oh no

This commit is contained in:
sam 2023-10-19 17:24:08 +02:00
parent 26de7b3cc4
commit 2843aec125
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
8 changed files with 170 additions and 216 deletions

248
Cargo.lock generated
View file

@ -141,9 +141,11 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core",
"axum-macros",
"bitflags 1.3.2", "bitflags 1.3.2",
"bytes", "bytes",
"futures-util", "futures-util",
"headers",
"http", "http",
"http-body", "http-body",
"hyper", "hyper",
@ -184,6 +186,18 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "axum-macros"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.69" version = "0.3.69"
@ -293,28 +307,6 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "chrono-tz"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1369bc6b9e9a7dfdae2055f6ec151fe9c554a9d23d357c0237cee2e25eaabb7"
dependencies = [
"chrono",
"chrono-tz-build",
"phf",
]
[[package]]
name = "chrono-tz-build"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2f5ebdc942f57ed96d560a6d1a459bae5851102a25d5bf89dc04ae453e31ecf"
dependencies = [
"parse-zoneinfo",
"phf",
"phf_codegen",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.6" version = "4.4.6"
@ -437,21 +429,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "deunicode"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71dbf1bf89c23e9cd1baf5e654f622872655f195b36588dc9dc38f7eda30758c"
dependencies = [
"deunicode 1.4.1",
]
[[package]]
name = "deunicode"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"
@ -672,17 +649,6 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "globwalk"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
dependencies = [
"bitflags 1.3.2",
"ignore",
"walkdir",
]
[[package]] [[package]]
name = "handlebars" name = "handlebars"
version = "4.4.0" version = "4.4.0"
@ -718,6 +684,30 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "headers"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
dependencies = [
"base64",
"bytes",
"headers-core",
"http",
"httpdate",
"mime",
"sha1",
]
[[package]]
name = "headers-core"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
dependencies = [
"http",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.4.1"
@ -806,15 +796,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humansize"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
dependencies = [
"libm",
]
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.27" version = "0.14.27"
@ -871,23 +852,6 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "ignore"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
dependencies = [
"globset",
"lazy_static",
"log",
"memchr",
"regex",
"same-file",
"thread_local",
"walkdir",
"winapi-util",
]
[[package]] [[package]]
name = "imgboard" name = "imgboard"
version = "0.1.0" version = "0.1.0"
@ -898,10 +862,10 @@ dependencies = [
"dotenvy", "dotenvy",
"eyre", "eyre",
"handlebars", "handlebars",
"headers",
"rust-embed", "rust-embed",
"serde", "serde",
"sqlx", "sqlx",
"tera",
"tokio", "tokio",
"tower-http", "tower-http",
"tracing", "tracing",
@ -1178,15 +1142,6 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "parse-zoneinfo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.14" version = "1.0.14"
@ -1253,44 +1208,6 @@ dependencies = [
"sha2", "sha2",
] ]
[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.3" version = "1.1.3"
@ -1703,12 +1620,6 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.9" version = "0.4.9"
@ -1718,15 +1629,6 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "slug"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
dependencies = [
"deunicode 0.4.5",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.11.1" version = "1.11.1"
@ -2055,28 +1957,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "tera"
version = "1.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8"
dependencies = [
"chrono",
"chrono-tz",
"globwalk",
"humansize",
"lazy_static",
"percent-encoding",
"pest",
"pest_derive",
"rand",
"regex",
"serde",
"serde_json",
"slug",
"unic-segment",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.49" version = "1.0.49"
@ -2284,56 +2164,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-segment"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23"
dependencies = [
"unic-ucd-segment",
]
[[package]]
name = "unic-ucd-segment"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.13" version = "0.3.13"

View file

@ -6,16 +6,16 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
axum = { version = "0.6.20", features = ["tracing"] } axum = { version = "0.6.20", features = ["tracing", "macros", "headers"] }
chrono = { version = "0.4.31", features = ["serde"] } chrono = { version = "0.4.31", features = ["serde"] }
clap = { version = "4.4.6", features = ["derive", "env"] } clap = { version = "4.4.6", features = ["derive", "env"] }
dotenvy = "0.15.7" dotenvy = "0.15.7"
eyre = "0.6.8" eyre = "0.6.8"
handlebars = { version = "4.4.0", features = ["rust-embed", "dir_source"] } handlebars = { version = "4.4.0", features = ["rust-embed", "dir_source"] }
headers = "0.3.9"
rust-embed = "8.0.0" rust-embed = "8.0.0"
serde = { version = "1.0.189", features = ["derive"] } serde = { version = "1.0.189", features = ["derive"] }
sqlx = { version = "0.7.2", features = ["runtime-tokio", "tls-rustls", "postgres", "macros", "migrate", "chrono"] } sqlx = { version = "0.7.2", features = ["runtime-tokio", "tls-rustls", "postgres", "macros", "migrate", "chrono"] }
tera = "1.19.1"
tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
tower-http = { version = "0.4.4", features = ["trace"] } tower-http = { version = "0.4.4", features = ["trace"] }
tracing = "0.1.39" tracing = "0.1.39"

49
src/extractor.rs Normal file
View file

@ -0,0 +1,49 @@
use axum::{
async_trait,
extract::{FromRef, FromRequestParts},
http::{request::Parts, StatusCode},
RequestPartsExt, TypedHeader,
};
use headers::Cookie;
use tracing::error;
use crate::{model::user::User, state::AppState};
pub struct ExtractUserToken(pub Option<User>);
#[async_trait]
impl<S> FromRequestParts<S> for ExtractUserToken
where
AppState: FromRef<S>,
S: Send + Sync,
{
type Rejection = (StatusCode, &'static str);
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let state = match parts.extract_with_state::<AppState, _>(state).await {
Ok(s) => s,
Err(why) => {
error!("Getting state: {}", why);
return Err((StatusCode::INTERNAL_SERVER_ERROR, "Internal server error"));
}
};
let cookie = match parts.extract::<TypedHeader<Cookie>>().await {
Ok(cookie) => cookie,
Err(err) => {
error!("Getting cookie header: {}", err);
return Ok(ExtractUserToken(None));
},
};
let user = match cookie.get("imgboard-token") {
Some(_token) => {
// TODO: get from token
None
},
None => None,
};
Ok(ExtractUserToken(user))
}
}

View file

@ -1,4 +1,5 @@
pub mod config; pub mod config;
pub mod extractor;
pub mod model; pub mod model;
pub mod pages; pub mod pages;
pub mod state; pub mod state;
@ -20,7 +21,7 @@ use crate::state::AppState;
use crate::templates::handlebars; use crate::templates::handlebars;
use crate::pages::index::index; use crate::pages::index::index;
use crate::pages::user::get_user; use crate::pages::user::{get_user, get_user_new};
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
@ -53,6 +54,7 @@ async fn main() -> Result<()> {
let app = Router::new() let app = Router::new()
.route("/", get(index)) .route("/", get(index))
.route("/users/:id", get(get_user)) .route("/users/:id", get(get_user))
.route("/users/new", get(get_user_new))
.layer(TraceLayer::new_for_http()) .layer(TraceLayer::new_for_http())
.with_state(state); .with_state(state);

View file

@ -27,7 +27,7 @@ impl Serialize for Role {
S: Serializer, S: Serializer,
{ {
serializer.serialize_str(match self { serializer.serialize_str(match self {
Role::Viewer => "viwer", Role::Viewer => "viewer",
Role::Editor => "editor", Role::Editor => "editor",
Role::Manager => "manager", Role::Manager => "manager",
Role::Admin => "admin", Role::Admin => "admin",

View file

@ -1,14 +1,15 @@
use std::sync::Arc; use std::{collections::BTreeMap, sync::Arc};
use axum::{ use axum::{
extract::{Path, State}, extract::{Path, State},
response::IntoResponse, response::IntoResponse,
}; };
use sqlx::query_as; use sqlx::{query, query_as};
use tracing::error; use tracing::error;
use crate::{ use crate::{
model::user::User, extractor::ExtractUserToken,
model::user::{Role, User},
state::AppState, state::AppState,
templates::{Page, PageData}, templates::{Page, PageData},
}; };
@ -38,3 +39,50 @@ pub async fn get_user(
.render("error.hbs", &PageData { user: Some(user) }), .render("error.hbs", &PageData { user: Some(user) }),
) )
} }
pub async fn get_user_new(
State(state): State<Arc<AppState>>,
ExtractUserToken(user): ExtractUserToken,
) -> impl IntoResponse {
if user.is_some()
&& match user.as_ref().unwrap().role {
Role::Viewer => false,
Role::Editor => false,
Role::Manager => false,
Role::Admin => true,
}
{
// Admins can create accounts
// Handlebars expects *some* value when rendering a template, so just pass an empty BTreeMap
let map = BTreeMap::<&str, &str>::new();
return Page::new(state.hbs.render("new_user.hbs", &map));
} else if user.is_some() {
// No permissions to create account
return Page::new(
state
.hbs
.render::<PageData>("error.hbs", &Default::default()),
);
}
// Else, let the user create a new account if no accounts exist yet
let count = match query!(r#"SELECT COUNT(id) FROM users"#)
.fetch_one(&state.pool)
.await
{
Ok(r) => r.count.unwrap_or(0),
Err(why) => {
error!("Getting user count: {}", why);
return Page::new(
state
.hbs
.render::<PageData>("error.hbs", &Default::default()),
);
}
};
let mut map = BTreeMap::new();
map.insert("count", count);
Page::new(state.hbs.render("new_user.hbs", &map))
}

View file

@ -1,6 +1,21 @@
use axum::{extract::{FromRef, FromRequestParts}, async_trait, http::request::Parts};
use sqlx::{postgres::Postgres, Pool}; use sqlx::{postgres::Postgres, Pool};
#[derive(Clone, FromRef)]
pub struct AppState { pub struct AppState {
pub pool: Pool<Postgres>, pub pool: Pool<Postgres>,
pub hbs: handlebars::Handlebars<'static>, pub hbs: handlebars::Handlebars<'static>,
} }
#[async_trait]
impl<S> FromRequestParts<S> for AppState
where
Self: FromRef<S>,
S: Send + Sync,
{
type Rejection = &'static str;
async fn from_request_parts(_parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
Ok(Self::from_ref(state))
}
}

10
templates/new_user.hbs Normal file
View file

@ -0,0 +1,10 @@
{{#*inline "page"}}
<h1>New user</h1>
<form method="POST">
<label>Username <input type="text" name="username" /></label>
<label>Password <input type="password" name="password" /></label>
<label>Confirm password <input type="password" name="password2" /></label>
<input type="submit" value="Create account" />
</form>
{{/inline}}
{{> root.hbs}}