Compare commits

..

No commits in common. "80bca69e5eedfb29aeab1e1534bd1a8a1e5d28d0" and "1c96977e0a18b40f3f73053dec4765b8675e455f" have entirely different histories.

7 changed files with 802 additions and 982 deletions

1677
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -15,14 +15,14 @@ actix-web-actors = "4.1.0"
argon2 = "0.4.1" argon2 = "0.4.1"
askama = "0.11.1" askama = "0.11.1"
askama_actix = "0.13" askama_actix = "0.13"
base64 = "0.22" base64 = "0.13"
bytes = "1.1.0" bytes = "1.1.0"
bytesize = "2" bytesize = "1.1.0"
crc32fast = "1.3.2" crc32fast = "1.3.2"
dotenvy = "0.15" dotenvy = "0.15"
env_logger = "0.11.3" env_logger = "0.11.3"
futures-core = "0.3" futures-core = "0.3"
inotify = "0.11" inotify = "0.10"
jsondb = "0.4.0" jsondb = "0.4.0"
libc = "0.2" libc = "0.2"
log = "0.4" log = "0.4"
@ -34,8 +34,8 @@ rand = "0.8.5"
sanitise-file-name = "1.0.0" sanitise-file-name = "1.0.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_with = { version = "3", features = ["time_0_3"] } serde_with = { version = "2", features = ["time_0_3"] }
thiserror = "2" thiserror = "1"
time = "0.3.9" time = "0.3.9"
tokio = { version = "1.17.0", features = ["full"] } tokio = { version = "1.17.0", features = ["full"] }
unicode-normalization = "0.1.19" unicode-normalization = "0.1.19"

24
flake.lock generated
View file

@ -6,11 +6,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1758695884, "lastModified": 1754290399,
"narHash": "sha256-rnHjtBRkcwRkrUZxg0RqN1qWTG+QC/gj4vn9uzEkBww=", "narHash": "sha256-KwYm1/FeLqP9uE4Sbw+j2nI2/ErNbc9Mn+LPcrEOpX0=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "9cdb79384d02234fb2868eba6c7d390253ef6f83", "rev": "f53ddf7518d85d59b58df6e9955b25b0ac25f569",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -21,11 +21,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1758427187, "lastModified": 1753939845,
"narHash": "sha256-pHpxZ/IyCwoTQPtFIAG2QaxuSm8jWzrzBGjwQZIttJc=", "narHash": "sha256-K2ViRJfdVGE8tpJejs8Qpvvejks1+A4GQej/lBk5y7I=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "554be6495561ff07b6c724047bdd7e0716aa7b46", "rev": "94def634a20494ee057c76998843c015909d6311",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -37,11 +37,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1758427187, "lastModified": 1754214453,
"narHash": "sha256-pHpxZ/IyCwoTQPtFIAG2QaxuSm8jWzrzBGjwQZIttJc=", "narHash": "sha256-Q/I2xJn/j1wpkGhWkQnm20nShYnG7TI99foDBpXm1SY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "554be6495561ff07b6c724047bdd7e0716aa7b46", "rev": "5b09dc45f24cf32316283e62aec81ffee3c3e376",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -61,11 +61,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1758620797, "lastModified": 1754218780,
"narHash": "sha256-Ly4rHgrixFMBnkbMursVt74mxnntnE6yVdF5QellJ+A=", "narHash": "sha256-M+bLCsYRYA7iudlZkeOf+Azm/1TUvihIq51OKia6KJ8=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "905641f3520230ad6ef421bcf5da9c6b49f2479b", "rev": "8d75311400a108d7ffe17dc9c38182c566952e6e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -290,13 +290,12 @@ pub(crate) fn new_live_reader(
file: File, file: File,
storage_path: PathBuf, storage_path: PathBuf,
) -> impl Stream<Item = Result<Bytes, Error>> { ) -> impl Stream<Item = Result<Bytes, Error>> {
let inotify = Inotify::init().expect("failed to init inotify"); let mut inotify = Inotify::init().expect("failed to init inotify");
inotify inotify
.watches() .add_watch(storage_path, WatchMask::MODIFY | WatchMask::CLOSE_WRITE)
.add(storage_path, WatchMask::MODIFY | WatchMask::CLOSE_WRITE)
.expect("Failed to add inotify watch"); .expect("Failed to add inotify watch");
let events = inotify let events = inotify
.into_event_stream([0; 1024]) .event_stream([0; 1024])
.expect("failed to set up event stream"); .expect("failed to set up event stream");
LiveFileReader { LiveFileReader {
size, size,

View file

@ -15,7 +15,6 @@ use actix_web::{
use actix_web_actors::ws; use actix_web_actors::ws;
use argon2::{Argon2, PasswordVerifier}; use argon2::{Argon2, PasswordVerifier};
use askama_actix::{Template, TemplateToResponse}; use askama_actix::{Template, TemplateToResponse};
use base64::prelude::*;
use bytesize::ByteSize; use bytesize::ByteSize;
use log::{error, warn}; use log::{error, warn};
use password_hash::PasswordHashString; use password_hash::PasswordHashString;
@ -396,16 +395,13 @@ async fn main() -> std::io::Result<()> {
let admin_password_hash: PasswordHashString = env_or_panic("TRANSBEAM_ADMIN_PASSWORD_HASH"); let admin_password_hash: PasswordHashString = env_or_panic("TRANSBEAM_ADMIN_PASSWORD_HASH");
let cookie_secret_base64: String = env_or_panic("TRANSBEAM_COOKIE_SECRET"); let cookie_secret_base64: String = env_or_panic("TRANSBEAM_COOKIE_SECRET");
let cookie_key = cookie::Key::from( let cookie_key =
&BASE64_STANDARD cookie::Key::from(&base64::decode(&cookie_secret_base64).unwrap_or_else(|_| {
.decode(&cookie_secret_base64) panic!(
.unwrap_or_else(|_| { "Value {} for TRANSBEAM_COOKIE_SECRET is not valid base64",
panic!( cookie_secret_base64
"Value {} for TRANSBEAM_COOKIE_SECRET is not valid base64", )
cookie_secret_base64 }));
)
}),
);
let state_file: PathBuf = match std::env::var("TRANSBEAM_STATE_FILE") { let state_file: PathBuf = match std::env::var("TRANSBEAM_STATE_FILE") {
Ok(v) => v Ok(v) => v

View file

@ -3,7 +3,6 @@ use jsondb::JsonDb;
pub mod prelude { pub mod prelude {
pub use std::collections::HashMap; pub use std::collections::HashMap;
use bytesize::ByteSize;
pub use jsondb::Schema; pub use jsondb::Schema;
pub use serde::{Deserialize, Serialize}; pub use serde::{Deserialize, Serialize};
pub use serde_with::serde_as; pub use serde_with::serde_as;
@ -14,11 +13,7 @@ pub mod prelude {
fn size(&self) -> u64; fn size(&self) -> u64;
fn formatted_size(&self) -> String { fn formatted_size(&self) -> String {
ByteSize(self.size()) bytesize::to_string(self.size(), false).replace(' ', "")
.display()
.si()
.to_string()
.replace(' ', "")
} }
} }
} }

View file

@ -1,4 +1,4 @@
use std::{collections::HashSet, fs::File, io::Write, path::Component, path::Path}; use std::{collections::HashSet, fs::File, io::Write, path::Path, path::Component};
use actix::{fut::future::ActorFutureExt, Actor, ActorContext, AsyncContext, StreamHandler}; use actix::{fut::future::ActorFutureExt, Actor, ActorContext, AsyncContext, StreamHandler};
use actix_http::ws::{CloseReason, Item}; use actix_http::ws::{CloseReason, Item};
@ -30,32 +30,28 @@ fn sanitise_path_component(name: &str, extension_length: usize) -> String {
sanitise_with_options( sanitise_with_options(
&name, &name,
&SanOptions { &SanOptions {
length_limit: SanOptions::DEFAULT length_limit: SanOptions::DEFAULT.length_limit.saturating_sub(extension_length),
.length_limit
.saturating_sub(extension_length),
..SanOptions::DEFAULT ..SanOptions::DEFAULT
}, },
) )
} }
fn sanitise_path(path: &str) -> String { fn sanitise_path(path: &str) -> String {
let mut san_path = Path::new(path) let mut san_path = Path::new(path).components().rfold(String::new(), |subpath, c| {
.components() if subpath.len() >= SanOptions::DEFAULT.length_limit*8 {
.rfold(String::new(), |subpath, c| { return subpath;
if subpath.len() >= SanOptions::DEFAULT.length_limit * 8 { }
return subpath; if let Component::Normal(s) = c {
let mut component = sanitise_path_component(&s.to_string_lossy(), 0);
if !subpath.is_empty() {
component.push('/');
component.push_str(&subpath);
} }
if let Component::Normal(s) = c { component
let mut component = sanitise_path_component(&s.to_string_lossy(), 0); } else {
if !subpath.is_empty() { subpath
component.push('/'); }
component.push_str(&subpath); });
}
component
} else {
subpath
}
});
if san_path.is_empty() { if san_path.is_empty() {
san_path.push('_'); san_path.push('_');
} }
@ -310,9 +306,8 @@ impl Uploader {
if files.len() > 1 { if files.len() > 1 {
info!("Wrapping in zipfile generator"); info!("Wrapping in zipfile generator");
let now = OffsetDateTime::now_utc(); let now = OffsetDateTime::now_utc();
let collection_name = collection_name let collection_name =
.map(|f| sanitise_path_component(&f, 4)) collection_name.map(|f| sanitise_path_component(&f, 4)).unwrap_or_else(|| {
.unwrap_or_else(|| {
super::APP_NAME.to_owned() super::APP_NAME.to_owned()
+ &now.format(FILENAME_DATE_FORMAT).unwrap() + &now.format(FILENAME_DATE_FORMAT).unwrap()
}); });