Compare commits
	
		
			No commits in common. "b7185bc31380dca2a52cf2fb53d95c5de8e21e95" and "86db090e2371f0b8be23ef75075d904741ae775f" have entirely different histories.
		
	
	
		
			b7185bc313
			...
			86db090e23
		
	
		
					 4 changed files with 148 additions and 562 deletions
				
			
		
							
								
								
									
										667
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										667
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@ actix = "0.13"
 | 
			
		|||
actix-files = "0.6.0"
 | 
			
		||||
actix-http = "3.0.4"
 | 
			
		||||
actix-session = { version = "0.7.1", features = ["cookie-session"] }
 | 
			
		||||
actix-web = "4.9.0"
 | 
			
		||||
actix-web = "4.0.1"
 | 
			
		||||
actix-web-actors = "4.1.0"
 | 
			
		||||
argon2 = "0.4.1"
 | 
			
		||||
askama = "0.11.1"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,11 +65,11 @@ async def file_loader(files):
 | 
			
		|||
                        file_progress.update(len(data))
 | 
			
		||||
                        yield data
 | 
			
		||||
 | 
			
		||||
async def send(paths, host, password, lifetime, collection_name=None, relpaths=False):
 | 
			
		||||
async def send(paths, host, password, lifetime, collection_name=None):
 | 
			
		||||
    paths = [path for path in paths if path.is_file()]
 | 
			
		||||
    fileMetadata = [
 | 
			
		||||
        {
 | 
			
		||||
            "name": str(path) if relpaths else path.name,
 | 
			
		||||
            "name": path.name,
 | 
			
		||||
            "size": path.stat().st_size,
 | 
			
		||||
            "modtime": math.floor(path.stat().st_mtime * 1000),
 | 
			
		||||
        } for path in paths
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +97,6 @@ parser = argparse.ArgumentParser(description="Upload files to transbeam")
 | 
			
		|||
parser.add_argument("-l", "--lifetime", type=int, default=7, help="Lifetime in days for files (default 7)")
 | 
			
		||||
parser.add_argument("-H", "--host", type=str, default="transbeam.link", help="transbeam host (default transbeam.link)")
 | 
			
		||||
parser.add_argument("-n", "--collection-name", type=str, help="Name for a collection of multiple files")
 | 
			
		||||
parser.add_argument("-R", "--relative-paths", action="store_true", help="Preserve file paths relative to working directory")
 | 
			
		||||
parser.add_argument("files", type=pathlib.Path, nargs="+", help="Files to upload")
 | 
			
		||||
 | 
			
		||||
async def main():
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +105,6 @@ async def main():
 | 
			
		|||
        print("--collection-name is only applicable when multiple files are being uploaded")
 | 
			
		||||
        exit(1)
 | 
			
		||||
    password = getpass.getpass()
 | 
			
		||||
    await send(args.files, args.host, password, args.lifetime, args.collection_name, args.relative_paths)
 | 
			
		||||
    await send(args.files, args.host, password, args.lifetime, args.collection_name)
 | 
			
		||||
 | 
			
		||||
asyncio.run(main())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
use std::{collections::HashSet, fs::File, io::Write, path::Path, path::Component};
 | 
			
		||||
use std::{collections::HashSet, fs::File, io::Write};
 | 
			
		||||
 | 
			
		||||
use actix::{fut::future::ActorFutureExt, Actor, ActorContext, AsyncContext, StreamHandler};
 | 
			
		||||
use actix_http::ws::{CloseReason, Item};
 | 
			
		||||
| 
						 | 
				
			
			@ -22,42 +22,20 @@ const MAX_FILES: usize = 256;
 | 
			
		|||
const FILENAME_DATE_FORMAT: &[time::format_description::FormatItem] =
 | 
			
		||||
    time::macros::format_description!("[year]-[month]-[day]-[hour][minute][second]");
 | 
			
		||||
 | 
			
		||||
/// Sanitises a file or directory name after performing unicode normalization,
 | 
			
		||||
/// Sanitises a filename after performing unicode normalization,
 | 
			
		||||
/// optionally reducing the length limit to leave space for an
 | 
			
		||||
/// extension yet to be added.
 | 
			
		||||
fn sanitise_path_component(name: &str, extension_length: usize) -> String {
 | 
			
		||||
fn sanitise(name: &str, extension_length: usize) -> String {
 | 
			
		||||
    let name = name.nfd().collect::<String>();
 | 
			
		||||
    sanitise_with_options(
 | 
			
		||||
        &name,
 | 
			
		||||
        &SanOptions {
 | 
			
		||||
            length_limit: SanOptions::DEFAULT.length_limit.saturating_sub(extension_length),
 | 
			
		||||
            length_limit: SanOptions::DEFAULT.length_limit - extension_length,
 | 
			
		||||
            ..SanOptions::DEFAULT
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn sanitise_path(path: &str) -> String {
 | 
			
		||||
    let mut san_path = Path::new(path).components().rfold(String::new(), |subpath, c| {
 | 
			
		||||
        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);
 | 
			
		||||
            }
 | 
			
		||||
            component
 | 
			
		||||
        } else {
 | 
			
		||||
            subpath
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    if san_path.is_empty() {
 | 
			
		||||
        san_path.push('_');
 | 
			
		||||
    }
 | 
			
		||||
    san_path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(thiserror::Error, Debug)]
 | 
			
		||||
enum Error {
 | 
			
		||||
    #[error("Failed to parse file metadata")]
 | 
			
		||||
| 
						 | 
				
			
			@ -136,7 +114,7 @@ pub use crate::state::v1::UploadedFile;
 | 
			
		|||
impl UploadedFile {
 | 
			
		||||
    fn new(name: &str, size: u64, modtime: OffsetDateTime) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            name: sanitise_path(name),
 | 
			
		||||
            name: sanitise(name, 0),
 | 
			
		||||
            size,
 | 
			
		||||
            modtime,
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -307,7 +285,7 @@ impl Uploader {
 | 
			
		|||
                        info!("Wrapping in zipfile generator");
 | 
			
		||||
                        let now = OffsetDateTime::now_utc();
 | 
			
		||||
                        let collection_name =
 | 
			
		||||
                            collection_name.map(|f| sanitise_path_component(&f, 4)).unwrap_or_else(|| {
 | 
			
		||||
                            collection_name.map(|f| sanitise(&f, 4)).unwrap_or_else(|| {
 | 
			
		||||
                                super::APP_NAME.to_owned()
 | 
			
		||||
                                    + &now.format(FILENAME_DATE_FORMAT).unwrap()
 | 
			
		||||
                            });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue