use zettoit style

This commit is contained in:
Paul Zinselmeyer 2023-11-06 21:53:45 +01:00
parent c1727442d9
commit 8e7ad058f6
10 changed files with 233 additions and 67 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "server/static/zettoit-style"]
path = server/static/zettoit-style
url = https://git2.zettoit.eu/zettoit/style

126
Cargo.lock generated
View file

@ -306,12 +306,14 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"rand", "rand",
"render", "render",
"sailfish",
"serde", "serde",
"sha3", "sha3",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-util", "tokio-util",
"toml 0.8.2", "toml 0.8.2",
"tower-http",
] ]
[[package]] [[package]]
@ -845,6 +847,18 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" 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]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -1063,6 +1077,15 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.9" version = "0.2.9"
@ -1085,6 +1108,12 @@ dependencies = [
"pin-project-lite", "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]] [[package]]
name = "httparse" name = "httparse"
version = "1.8.0" version = "1.8.0"
@ -1262,6 +1291,12 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "itoap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.64" version = "0.3.64"
@ -1366,6 +1401,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 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]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -1844,6 +1889,15 @@ dependencies = [
"bitflags 1.3.2", "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]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.4.1" version = "0.4.1"
@ -2082,6 +2136,44 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 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]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -2595,6 +2687,31 @@ dependencies = [
"tracing", "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]] [[package]]
name = "tower-layer" name = "tower-layer"
version = "0.3.2" version = "0.3.2"
@ -2639,6 +2756,15 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 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]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.13" version = "0.3.13"

View file

@ -39,7 +39,8 @@
src = pkgs.lib.cleanSourceWith { src = pkgs.lib.cleanSourceWith {
src = craneLib.path ./.; src = craneLib.path ./.;
filter = path: type: filter = path: type:
(pkgs.lib.hasSuffix "\.md" path) || (pkgs.lib.hasSuffix "\.stpl" path) ||
(pkgs.lib.hasInfix "static" path) ||
(craneLib.filterCargoSources path type) (craneLib.filterCargoSources path type)
; ;
}; };
@ -55,6 +56,11 @@
bin = craneLib.buildPackage (commonArgs // { bin = craneLib.buildPackage (commonArgs // {
inherit cargoArtifacts; inherit cargoArtifacts;
pname = "bin"; pname = "bin";
installPhaseCommand = ''
mkdir -p $out/bin
cp target/release/bin $out/bin/bin
cp -r server/static $out/static
'';
}); });
binctl = craneLib.buildPackage (commonArgs // { binctl = craneLib.buildPackage (commonArgs // {
inherit cargoArtifacts; inherit cargoArtifacts;

View file

@ -21,6 +21,8 @@ markdown = "0.3"
axum_oidc = {git="https://git2.zettoit.eu/pfz4/axum_oidc"} axum_oidc = {git="https://git2.zettoit.eu/pfz4/axum_oidc"}
log = "0.4" log = "0.4"
env_logger = "0.10" env_logger = "0.10"
sailfish = "0.8.3"
tower-http = { version="0.4.4", features=["fs"], default-features=false }
chacha20 = "0.9" chacha20 = "0.9"
sha3 = "0.10" sha3 = "0.10"

View file

@ -38,6 +38,9 @@ pub enum Error {
#[error("forbidden")] #[error("forbidden")]
Forbidden, Forbidden,
#[error("render error: {0:?}")]
Tempalte(#[from] sailfish::RenderError),
} }
impl IntoResponse for Error { impl IntoResponse for Error {

View file

@ -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=<seconds_to_live>` 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
```

View file

@ -1,11 +1,13 @@
#![deny(clippy::unwrap_used)] #![deny(clippy::unwrap_used)]
use duration_str::{deserialize_option_duration, parse_std}; use duration_str::{deserialize_option_duration, parse_std};
use sailfish::TemplateOnce;
use std::{ use std::{
borrow::Borrow, borrow::Borrow,
env, env,
str::FromStr, str::FromStr,
time::{Duration, SystemTime, UNIX_EPOCH}, time::{Duration, SystemTime, UNIX_EPOCH},
}; };
use tower_http::services::ServeDir;
use axum::{ use axum::{
async_trait, async_trait,
@ -155,6 +157,7 @@ async fn main() {
.delete(delete_bin), .delete(delete_bin),
) )
.route("/:id/delete", get(delete_bin_interactive).post(delete_bin)) .route("/:id/delete", get(delete_bin_interactive).post(delete_bin))
.nest_service("/static", ServeDir::new("static"))
.with_state(state); .with_state(state);
axum::Server::bind(&"[::]:8080".parse().expect("valid listen address")) axum::Server::bind(&"[::]:8080".parse().expect("valid listen address"))
.serve(app.into_make_service()) .serve(app.into_make_service())
@ -239,24 +242,7 @@ async fn delete_bin_interactive(
_: Path<String>, _: Path<String>,
_: OidcExtractor<EmptyAdditionalClaims>, _: OidcExtractor<EmptyAdditionalClaims>,
) -> HandlerResult<impl IntoResponse> { ) -> HandlerResult<impl IntoResponse> {
let body = html! { Ok(Html(DeleteTemplate.render_once()?))
<html>
<head>
<title>{"zettoit bin"}</title>
<link rel={"icon"} type={"image/svg"} href={"https://static.zettoit.eu/img/zettoit-logo.svg"}/>
</head>
<body style={"font-family: monospace; background-color: black; color: white;"}>
<div style={"margin: auto; max-width: 80ch;"}>
<h2>{"Confirm Deletion"}</h2>
<p>{"The bin will be deleted. All data will be permanently lost."}</p>
<form method={"post"}>
<button type={"submit"}>{"Delete"}</button>
</form>
</div>
</body>
</html>
};
Ok(Html(body))
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -387,31 +373,16 @@ async fn get_item(
let nonce = Nonce::from_hex(&metadata.nonce)?; let nonce = Nonce::from_hex(&metadata.nonce)?;
if std::fs::metadata(&path).is_err() { if std::fs::metadata(&path).is_err() {
let body = include_str!("item_explanation.md").replace( Ok((
"<bin_url>", StatusCode::ACCEPTED,
&format!("{}{}", app_state.application_base, phrase), Html(
); IndexTemplate {
bin_url: &format!("{}{}", app_state.application_base, phrase),
let body = markdown::to_html(&body); }
let body = html! { .render_once()?,
<html> ),
<head> )
<title>{"zettoit bin"}</title> .into_response())
<link rel={"icon"} type={"image/svg"} href={"https://static.zettoit.eu/img/zettoit-logo.svg"}/>
</head>
<body style={"font-family: monospace; background-color: black; color: white;"}>
<div style={"margin: auto; max-width: 80ch;"}>
{raw!(body.as_str())}
<h2>{"Browser upload"}</h2>
<form method={"post"} enctype={"multipart/form-data"}>
<input type={"file"} name={"file"}>{}</input>
<button type={"submit"}>{"Upload"}</button>
</form>
</div>
</body>
</html>
};
Ok((StatusCode::ACCEPTED, Html(body)).into_response())
} else { } else {
//TODO(pfz4): Maybe add link handling //TODO(pfz4): Maybe add link handling
let file = File::open(&path).await?; 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;

@ -0,0 +1 @@
Subproject commit 6de783bed1960fc6ba3a06dc56f8999459817795

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>zettoit bin</title>
<link rel="icon" type="image/svg" href="/static/zettoit-style/zettoit.svg"/>
<link rel="stylesheet" href="/static/zettoit-style/zettoit.css"/>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<main>
<h1>Confirm Deletion</h1>
<p>The bin will be deleted. All data will be permanently lost.</p>
<form method="post">
<button type="submit">Delete</button>
</form>
</main>
<a class="watermark" href="https://git2.zettoit.eu/zettoit"><img src="/static/zettoit-style/zettoit.svg" alt="zettoIT Logo"></a>
</body>
</html>

View file

@ -0,0 +1,48 @@
<html>
<head>
<title>zettoit bin</title>
<link rel="icon" type="image/svg" href="/static/zettoit-style/zettoit.svg"/>
<link rel="stylesheet" href="/static/zettoit-style/zettoit.css"/>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<main>
<h1>zettoIT bin</h1>
<p>
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.
</p>
<p>To change the default expiration date, you can use the `?ttl=<seconds_to_live>` parameter.</p>
<p>After uploading data, you can access it by accessing <%= bin_url %> with an optional file extension that suits the data that you uploaded.</p>
<h1>Upload a image</h1>
<pre>
$ curl -H "Content-Type: image/png" -T my-image.png <%= bin_url %>`
</pre>
<h1>Upload a big file</h1>
<pre>
$ curl -X POST -H "Content-Type: application/gzip" -T my-file.tar.gz <%= bin_url %>
</pre>
<h1>Pipe into curl</h1>
<pre>
$ tar -cz my-files | curl -H "Content-Type: application/gzip" -T - <%= bin_url %>
</pre>
<h1>Encryption</h1>
<pre>
$ 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
</pre>
<h1>Browser upload</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file"></input>
<button type="submit">Upload</button>
</form>
</main>
<a class="watermark" href="https://git2.zettoit.eu/zettoit"><img src="/static/zettoit-style/zettoit.svg" alt="zettoIT Logo"></a>
</body>
</html>