Check and limit file upload sizes
This commit is contained in:
parent
1099a80c79
commit
5dbafa6dbd
5 changed files with 84 additions and 9 deletions
5
IDEAS.md
5
IDEAS.md
|
@ -1,7 +1,6 @@
|
|||
# First release
|
||||
- Only allow file extension renaming on upload with `-f` flag
|
||||
- Check for file expiry everywhere
|
||||
- Soft limit uploads to 1GB and 2GB
|
||||
- On download, mention a wrong or missing password with a HTTP 401 response
|
||||
- Remember all uploaded files, make files listable
|
||||
- Incognito mode, to not remember files `--incognito`
|
||||
- Automatically get owner token, from file history when setting password
|
||||
|
@ -12,7 +11,7 @@
|
|||
|
||||
# Other ideas
|
||||
- Box errors
|
||||
- On download, mention a wrong or missing password with a HTTP 401 response
|
||||
- Only allow file extension renaming on upload with `-f` flag
|
||||
- Implement error handling everywhere properly
|
||||
- Quick upload/download without `upload` or `download` subcommands?
|
||||
- Flag to explicitly delete file after download
|
||||
|
|
5
api/src/config.rs
Normal file
5
api/src/config.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
/// The recommended maximum upload size in bytes.
|
||||
pub const UPLOAD_SIZE_MAX_RECOMMENDED: u64 = 1_073_741_824;
|
||||
|
||||
/// The maximum upload size in bytes.
|
||||
pub const UPLOAD_SIZE_MAX: u64 = 2_147_483_648;
|
|
@ -16,6 +16,7 @@ pub extern crate url;
|
|||
|
||||
pub mod action;
|
||||
mod api;
|
||||
pub mod config;
|
||||
pub mod crypto;
|
||||
mod ext;
|
||||
pub mod file;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
|
@ -5,17 +6,24 @@ use clap::ArgMatches;
|
|||
use failure::{err_msg, Fail};
|
||||
use ffsend_api::action::params::ParamsDataBuilder;
|
||||
use ffsend_api::action::upload::Upload as ApiUpload;
|
||||
use ffsend_api::config::{UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_RECOMMENDED};
|
||||
use ffsend_api::reqwest::Client;
|
||||
|
||||
use cmd::matcher::{
|
||||
Matcher,
|
||||
upload::UploadMatcher,
|
||||
};
|
||||
use cmd::matcher::{Matcher, MainMatcher, UploadMatcher};
|
||||
use error::ActionError;
|
||||
use progress::ProgressBar;
|
||||
use util::open_url;
|
||||
use util::{
|
||||
ErrorHintsBuilder,
|
||||
format_bytes,
|
||||
open_url,
|
||||
print_error,
|
||||
print_error_msg,
|
||||
prompt_yes,
|
||||
quit,
|
||||
quit_error_msg,
|
||||
};
|
||||
#[cfg(feature = "clipboard")]
|
||||
use util::{print_error, set_clipboard};
|
||||
use util::set_clipboard;
|
||||
|
||||
/// A file upload action.
|
||||
pub struct Upload<'a> {
|
||||
|
@ -34,12 +42,52 @@ impl<'a> Upload<'a> {
|
|||
// TODO: create a trait for this method
|
||||
pub fn invoke(&self) -> Result<(), ActionError> {
|
||||
// Create the command matchers
|
||||
let matcher_main = MainMatcher::with(self.cmd_matches).unwrap();
|
||||
let matcher_upload = UploadMatcher::with(self.cmd_matches).unwrap();
|
||||
|
||||
// Get API parameters
|
||||
let path = Path::new(matcher_upload.file()).to_path_buf();
|
||||
let host = matcher_upload.host();
|
||||
|
||||
// TODO: ensure the file exists and is accessible
|
||||
|
||||
// Get the file size to warn about large files
|
||||
if let Ok(size) = File::open(&path)
|
||||
.and_then(|f| f.metadata())
|
||||
.map(|m| m.len())
|
||||
{
|
||||
if size > UPLOAD_SIZE_MAX && !matcher_main.force() {
|
||||
// The file is too large, show an error and quit
|
||||
quit_error_msg(
|
||||
format!(
|
||||
"The file size is {}, bigger than the maximum allowed of {}",
|
||||
format_bytes(size),
|
||||
format_bytes(UPLOAD_SIZE_MAX),
|
||||
),
|
||||
ErrorHintsBuilder::default()
|
||||
.force(true)
|
||||
.verbose(false)
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
} else if size > UPLOAD_SIZE_MAX_RECOMMENDED && !matcher_main.force() {
|
||||
// The file is larger than the recommended maximum, warn
|
||||
eprintln!(
|
||||
"The file size is {}, bigger than the recommended maximum of {}",
|
||||
format_bytes(size),
|
||||
format_bytes(UPLOAD_SIZE_MAX_RECOMMENDED),
|
||||
);
|
||||
|
||||
// Prompt the user to continue, quit if the user answered no
|
||||
if !prompt_yes("Continue uploading?", Some(true), &matcher_main) {
|
||||
println!("Upload cancelled");
|
||||
quit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print_error_msg("Failed to check the file size, ignoring");
|
||||
}
|
||||
|
||||
// Create a reqwest client
|
||||
let client = Client::new();
|
||||
|
||||
|
|
|
@ -48,6 +48,15 @@ pub fn print_error<E: Fail>(err: E) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Print the given error message in a proper format for the user,
|
||||
/// with it's causes.
|
||||
pub fn print_error_msg<S>(err: S)
|
||||
where
|
||||
S: AsRef<str> + Display + Debug + Sync + Send + 'static
|
||||
{
|
||||
print_error(err_msg(err).compat());
|
||||
}
|
||||
|
||||
/// Quit the application regularly.
|
||||
pub fn quit() -> ! {
|
||||
exit(0);
|
||||
|
@ -393,3 +402,16 @@ pub fn ensure_owner_token(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the given number of bytes readable for humans.
|
||||
pub fn format_bytes(bytes: u64) -> String {
|
||||
let bytes = bytes as f64;
|
||||
let kb = 1024f64;
|
||||
match bytes {
|
||||
bytes if bytes >= kb.powf(4_f64) => format!("{:.*} TiB", 2, bytes / kb.powf(4_f64)),
|
||||
bytes if bytes >= kb.powf(3_f64) => format!("{:.*} GiB", 2, bytes / kb.powf(3_f64)),
|
||||
bytes if bytes >= kb.powf(2_f64) => format!("{:.*} MiB", 2, bytes / kb.powf(2_f64)),
|
||||
bytes if bytes >= kb => format!("{:.*} KiB", 2, bytes / kb),
|
||||
_ => format!("{:.*} B", 0, bytes),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue