diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1a75463 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "server/static/zettoit-style"] + path = server/static/zettoit-style + url = https://git2.zettoit.eu/zettoit/style diff --git a/Cargo.lock b/Cargo.lock index eb3730e..d1cd152 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -306,12 +306,14 @@ dependencies = [ "pin-project-lite", "rand", "render", + "sailfish", "serde", "sha3", "thiserror", "tokio", "tokio-util", "toml 0.8.2", + "tower-http", ] [[package]] @@ -845,6 +847,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "windows-sys", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1063,6 +1077,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "http" version = "0.2.9" @@ -1085,6 +1108,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -1262,6 +1291,12 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "itoap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" + [[package]] name = "js-sys" version = "0.3.64" @@ -1366,6 +1401,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1844,6 +1889,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -2082,6 +2136,44 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "sailfish" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd5f4680149b62b3478f6af08a8f1c37794bc1bc577e28874a4d0c70084d600" +dependencies = [ + "itoap", + "ryu", + "sailfish-macros", + "version_check", +] + +[[package]] +name = "sailfish-compiler" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67087aca4a3886686a88cee6835089c53e6143a0b8c5be01e63e4fe2f6dfe7cb" +dependencies = [ + "filetime", + "home", + "memchr", + "proc-macro2", + "quote", + "serde", + "syn 2.0.38", + "toml 0.8.2", +] + +[[package]] +name = "sailfish-macros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47e31910c5f9230e99992568d05a5968fe4f42a635c3f912c993e9f66a619a5" +dependencies = [ + "proc-macro2", + "sailfish-compiler", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2595,6 +2687,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.2" @@ -2639,6 +2756,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/flake.nix b/flake.nix index c66048e..45b8ad9 100644 --- a/flake.nix +++ b/flake.nix @@ -39,7 +39,8 @@ src = pkgs.lib.cleanSourceWith { src = craneLib.path ./.; filter = path: type: - (pkgs.lib.hasSuffix "\.md" path) || + (pkgs.lib.hasSuffix "\.stpl" path) || + (pkgs.lib.hasInfix "static" path) || (craneLib.filterCargoSources path type) ; }; @@ -55,6 +56,11 @@ bin = craneLib.buildPackage (commonArgs // { inherit cargoArtifacts; pname = "bin"; + installPhaseCommand = '' + mkdir -p $out/bin + cp target/release/bin $out/bin/bin + cp -r server/static $out/static + ''; }); binctl = craneLib.buildPackage (commonArgs // { inherit cargoArtifacts; diff --git a/server/Cargo.toml b/server/Cargo.toml index cfd632e..2010cc5 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -21,6 +21,8 @@ markdown = "0.3" axum_oidc = {git="https://git2.zettoit.eu/pfz4/axum_oidc"} log = "0.4" env_logger = "0.10" +sailfish = "0.8.3" +tower-http = { version="0.4.4", features=["fs"], default-features=false } chacha20 = "0.9" sha3 = "0.10" diff --git a/server/src/error.rs b/server/src/error.rs index 9e90bef..644912e 100644 --- a/server/src/error.rs +++ b/server/src/error.rs @@ -38,6 +38,9 @@ pub enum Error { #[error("forbidden")] Forbidden, + + #[error("render error: {0:?}")] + Tempalte(#[from] sailfish::RenderError), } impl IntoResponse for Error { diff --git a/server/src/item_explanation.md b/server/src/item_explanation.md deleted file mode 100644 index fb1233c..0000000 --- a/server/src/item_explanation.md +++ /dev/null @@ -1,23 +0,0 @@ -# zettoIT bin -An empty bin was created for you. The first HTTP POST or PUT request can upload data. -All following requests can only read the uploaded data. - -To change the default expiration date, you can use the `?ttl=` parameter. - -After uploading data you can access it by accessing with an optional file extension that suits the data that you uploaded. - -## Upload a image -`$ curl -H "Content-Type: image/png" -T my-image.png ` - -## Upload a big file -`$ curl -X POST -H "Content-Type: application/gzip" -T my-file.tar.gz ` - -## Pipe into curl -`$ tar -cz my-files | curl -H "Content-Type: application/gzip" -T - ` - -## Encryption -``` -$ tar -cz my-files | gpg -co tmp.tar.gz -$ curl -H "Content-Type: application/octet-stream" -T tmp.tar.gz -$ curl | gpg -d - | tar -xzf -``` diff --git a/server/src/main.rs b/server/src/main.rs index 296f07e..e55868a 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,11 +1,13 @@ #![deny(clippy::unwrap_used)] use duration_str::{deserialize_option_duration, parse_std}; +use sailfish::TemplateOnce; use std::{ borrow::Borrow, env, str::FromStr, time::{Duration, SystemTime, UNIX_EPOCH}, }; +use tower_http::services::ServeDir; use axum::{ async_trait, @@ -155,6 +157,7 @@ async fn main() { .delete(delete_bin), ) .route("/:id/delete", get(delete_bin_interactive).post(delete_bin)) + .nest_service("/static", ServeDir::new("static")) .with_state(state); axum::Server::bind(&"[::]:8080".parse().expect("valid listen address")) .serve(app.into_make_service()) @@ -239,24 +242,7 @@ async fn delete_bin_interactive( _: Path, _: OidcExtractor, ) -> HandlerResult { - let body = html! { - - - {"zettoit bin"} - - - -
-

{"Confirm Deletion"}

-

{"The bin will be deleted. All data will be permanently lost."}

-
- -
-
- - - }; - Ok(Html(body)) + Ok(Html(DeleteTemplate.render_once()?)) } #[derive(Deserialize)] @@ -387,31 +373,16 @@ async fn get_item( let nonce = Nonce::from_hex(&metadata.nonce)?; if std::fs::metadata(&path).is_err() { - let body = include_str!("item_explanation.md").replace( - "", - &format!("{}{}", app_state.application_base, phrase), - ); - - let body = markdown::to_html(&body); - let body = html! { - - - {"zettoit bin"} - - - -
- {raw!(body.as_str())} -

{"Browser upload"}

-
- {} - -
-
- - - }; - Ok((StatusCode::ACCEPTED, Html(body)).into_response()) + Ok(( + StatusCode::ACCEPTED, + Html( + IndexTemplate { + bin_url: &format!("{}{}", app_state.application_base, phrase), + } + .render_once()?, + ), + ) + .into_response()) } else { //TODO(pfz4): Maybe add link handling let file = File::open(&path).await?; @@ -486,3 +457,13 @@ where } } } + +#[derive(TemplateOnce)] +#[template(path = "index.stpl")] +pub struct IndexTemplate<'a> { + bin_url: &'a str, +} + +#[derive(TemplateOnce)] +#[template(path = "delete.stpl")] +pub struct DeleteTemplate; diff --git a/server/static/zettoit-style b/server/static/zettoit-style new file mode 160000 index 0000000..6de783b --- /dev/null +++ b/server/static/zettoit-style @@ -0,0 +1 @@ +Subproject commit 6de783bed1960fc6ba3a06dc56f8999459817795 diff --git a/server/templates/delete.stpl b/server/templates/delete.stpl new file mode 100644 index 0000000..2600ccc --- /dev/null +++ b/server/templates/delete.stpl @@ -0,0 +1,19 @@ + + + zettoit bin + + + + + + +
+

Confirm Deletion

+

The bin will be deleted. All data will be permanently lost.

+
+ +
+
+ zettoIT Logo + + diff --git a/server/templates/index.stpl b/server/templates/index.stpl new file mode 100644 index 0000000..fb12306 --- /dev/null +++ b/server/templates/index.stpl @@ -0,0 +1,48 @@ + + + zettoit bin + + + + + + +
+

zettoIT bin

+

+ An empty bin was created for you. The first HTTP POST or PUT request can upload data. + All following requests can only read the uploaded data. +

+

To change the default expiration date, you can use the `?ttl=` parameter.

+

After uploading data, you can access it by accessing <%= bin_url %> with an optional file extension that suits the data that you uploaded.

+

Upload a image

+
+$ curl -H "Content-Type: image/png" -T my-image.png <%= bin_url %>`
+            
+ +

Upload a big file

+
+$ curl -X POST -H "Content-Type: application/gzip" -T my-file.tar.gz <%= bin_url %>
+            
+ +

Pipe into curl

+
+$ tar -cz my-files | curl -H "Content-Type: application/gzip" -T - <%= bin_url %>
+            
+ +

Encryption

+
+$ tar -cz my-files | gpg -co tmp.tar.gz
+$ curl -H "Content-Type: application/octet-stream" -T tmp.tar.gz <%= bin_url %>
+$ curl <%= bin_url %> | gpg -d - | tar -xzf
+            
+ +

Browser upload

+
+ + +
+
+ zettoIT Logo + +