diff --git a/Cargo.lock b/Cargo.lock index 81a6319..4a923d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,6 +378,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "content_inspector" version = "0.2.4" @@ -446,6 +452,43 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "difflib" version = "0.4.0" @@ -510,10 +553,12 @@ dependencies = [ "clap_complete", "content_inspector", "digest_auth", + "ed25519-dalek", "form_urlencoded", "futures-util", "glob", "headers", + "hex", "http-body-util", "hyper", "hyper-util", @@ -549,6 +594,30 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -580,6 +649,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "flate2" version = "1.1.1" @@ -1347,6 +1422,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -1879,6 +1964,15 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.9" @@ -1915,6 +2009,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index 51a1e1d..c1a8562 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,8 @@ http-body-util = "0.1" bytes = "1.5" pin-project-lite = "0.2" sha2 = "0.10.8" +ed25519-dalek = "2.2.0" +hex = "0.4.3" [features] default = ["tls"] diff --git a/assets/index.js b/assets/index.js index b87e354..7ddf6fd 100644 --- a/assets/index.js +++ b/assets/index.js @@ -347,6 +347,7 @@ async function setupIndexPage() { const $download = document.querySelector(".download"); $download.href = baseUrl() + "?zip"; $download.title = "Download folder as a .zip file"; + $download.classList.add("dlwt"); $download.classList.remove("hidden"); } @@ -367,6 +368,10 @@ async function setupIndexPage() { renderPathsTableHead(); renderPathsTableBody(); + + if (DATA.user) { + setupDownloadWithToken(); + } } /** @@ -449,13 +454,13 @@ function addPath(file, index) { if (DATA.allow_archive) { actionDownload = `
`; } } else { actionDownload = ` `; } if (DATA.allow_delete) { @@ -530,12 +535,39 @@ async function setupAuth() { $loginBtn.addEventListener("click", async () => { try { await checkAuth(); - } catch {} + } catch { } location.reload(); }); } } +function setupDownloadWithToken() { + document.querySelectorAll("a.dlwt").forEach(link => { + link.addEventListener("click", async e => { + e.preventDefault(); + try { + const link = e.currentTarget || e.target; + const originalHref = link.getAttribute("href"); + const tokengenUrl = new URL(originalHref); + tokengenUrl.searchParams.set("tokengen", ""); + const res = await fetch(tokengenUrl); + if (!res.ok) throw new Error("Failed to fetch token"); + const token = await res.text(); + const downloadUrl = new URL(originalHref); + downloadUrl.searchParams.set("token", token); + const tempA = document.createElement("a"); + tempA.href = downloadUrl.toString(); + tempA.download = ""; + document.body.appendChild(tempA); + tempA.click(); + document.body.removeChild(tempA); + } catch (err) { + alert(`Failed to download, ${err.message}`); + } + }); + }); +} + function setupSearch() { const $searchbar = document.querySelector(".searchbar"); $searchbar.classList.remove("hidden"); @@ -646,7 +678,7 @@ async function setupEditorPage() { $editor.value = decoder.decode(dataView); } } catch (err) { - alert(`Failed get file, ${err.message}`); + alert(`Failed to get file, ${err.message}`); } } diff --git a/src/auth.rs b/src/auth.rs index 0aaa8b5..87b1e42 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -2,11 +2,13 @@ use crate::{args::Args, server::Response, utils::unix_now}; use anyhow::{anyhow, bail, Result}; use base64::{engine::general_purpose::STANDARD, Engine as _}; +use ed25519_dalek::{ed25519::signature::SignerMut, Signature, SigningKey}; use headers::HeaderValue; use hyper::{header::WWW_AUTHENTICATE, Method}; use indexmap::IndexMap; use lazy_static::lazy_static; use md5::Context; +use sha2::{Digest, Sha256}; use std::{ collections::HashMap, path::{Path, PathBuf}, @@ -14,7 +16,8 @@ use std::{ use uuid::Uuid; const REALM: &str = "DUFS"; -const DIGEST_AUTH_TIMEOUT: u32 = 604800; // 7 days +const DIGEST_AUTH_TIMEOUT: u32 = 60 * 60 * 24 * 7; // 7 days +const TOKEN_EXPIRATION: u64 = 1000 * 60 * 60 * 24 * 3; // 3 days lazy_static! { static ref NONCESTARTHASH: Context = { @@ -105,11 +108,21 @@ impl AccessControl { path: &str, method: &Method, authorization: Option<&HeaderValue>, + token: Option<&String>, guard_options: bool, ) -> (Option