Merge branch 'a1346054-fixes' into master

See https://github.com/timvisee/ffsend/pull/129
This commit is contained in:
timvisee 2021-08-26 16:33:48 +02:00
commit cf8c13afa2
No known key found for this signature in database
GPG key ID: B8DB720BC383E172
18 changed files with 99 additions and 46 deletions

View file

@ -39,7 +39,7 @@ before_script:
rustc --version rustc --version
cargo --version cargo --version
# Check on stable, beta and nightly # Check on stable, beta and nightly
.check-base: &check-base .check-base: &check-base
stage: check stage: check
script: script:

View file

@ -18,7 +18,7 @@ Contributions to the `ffsend` project are welcome!
When contributing new features, alternative implementations or bigger When contributing new features, alternative implementations or bigger
improvements, please first discuss the change you wish to make via an issue improvements, please first discuss the change you wish to make via an issue
or email. or email.
Small changes such as fixed commands, fixed spelling or dependency updates Small changes such as fixed commands, fixed spelling or dependency updates
are always welcome without discussion. are always welcome without discussion.
The `ffsend` repository is primarily hosted on [GitLab][gitlab]. The `ffsend` repository is primarily hosted on [GitLab][gitlab].
@ -115,11 +115,11 @@ members of the project's leadership.
### Attribution ### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][coc-homepage], version 1.4, This Code of Conduct is adapted from the [Contributor Covenant][coc-homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][coc-version] available at [https://contributor-covenant.org/version/1/4][coc-version]
## License ## License
This project is released under the GNU GPL-3.0 license. This project is released under the GNU GPL-3.0 license.
Check out the [LICENSE](LICENSE) file for more information. Check out the [LICENSE](LICENSE) file for more information.
[branch-master]: https://gitlab.com/timvisee/ffsend/tree/master [branch-master]: https://gitlab.com/timvisee/ffsend/tree/master
[gitlab]: https://gitlab.com/timvisee/ffsend [gitlab]: https://gitlab.com/timvisee/ffsend
@ -128,5 +128,5 @@ Check out the [LICENSE](LICENSE) file for more information.
[github]: https://github.com/timvisee/ffsend [github]: https://github.com/timvisee/ffsend
[github-issues]: https://github.com/timvisee/ffsend/issues [github-issues]: https://github.com/timvisee/ffsend/issues
[github-pr]: https://github.com/timvisee/ffsend/pulls [github-pr]: https://github.com/timvisee/ffsend/pulls
[coc-homepage]: http://contributor-covenant.org [coc-homepage]: https://contributor-covenant.org
[coc-version]: http://contributor-covenant.org/version/1/4/ [coc-version]: https://contributor-covenant.org/version/1/4/

55
LICENSE
View file

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@ -619,3 +619,56 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee. copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View file

@ -4,5 +4,5 @@
set -e set -e
echo "Generating all completions using cargo debug binary..." echo "Generating all completions using cargo debug binary..."
cargo run -q -- generate completions all --output $PWD cargo run -q -- generate completions all --output "$PWD"
echo "Done." echo "Done."

View file

@ -9,13 +9,13 @@ if [[ ! $TRAVIS_TAG =~ ^v([0-9]+\.)*[0-9]+$ ]]; then
fi fi
# Ensure the debian architecture is set # Ensure the debian architecture is set
if [[ -z "$DEB_ARCH" ]]; then if [[ -z $DEB_ARCH ]]; then
echo "Error: debian architecture not configured in \$DEB_ARCH" echo "Error: debian architecture not configured in \$DEB_ARCH"
exit 1 exit 1
fi fi
# Define some useful variables # Define some useful variables
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
VERSION=${TRAVIS_TAG:1} VERSION=${TRAVIS_TAG:1}
# Ensure the binary file exists # Ensure the binary file exists
@ -25,23 +25,23 @@ if [[ ! -f "$DIR/../ffsend" ]]; then
fi fi
# Create an application directory, copy the binary into it # Create an application directory, copy the binary into it
mkdir -p $DIR/ffsend-$VERSION mkdir -p "$DIR/ffsend-$VERSION"
cp $DIR/../ffsend $DIR/ffsend-$VERSION/ffsend cp -- "$DIR/../ffsend" "$DIR/ffsend-$VERSION/ffsend"
# Create an application tarbal # Create an application tarbal
cd $DIR/.. cd -- "$DIR/.."
git archive --format tar.gz -o $DIR/ffsend-$VERSION/ffsend-$VERSION.tar.gz $TRAVIS_TAG git archive --format tar.gz -o "$DIR/ffsend-$VERSION/ffsend-$VERSION.tar.gz" "$TRAVIS_TAG"
# Change into the app directory # Change into the app directory
cd $DIR/ffsend-$VERSION cd -- "$DIR/ffsend-$VERSION"
# Build the debian package # Build the debian package
# TODO: define GPG? # TODO: define GPG?
dh_make -e "timvisee@gmail.com" -c gpl3 -f ffsend-$VERSION.tar.gz -s -y dh_make -e "timvisee@gmail.com" -c gpl3 -f "ffsend-$VERSION.tar.gz" -s -y
rm *.ex README.Debian README.source rm -- *.ex README.Debian README.source
# Remove the project tar ball, we're not using it anymore # Remove the project tar ball, we're not using it anymore
rm $DIR/ffsend-$VERSION/ffsend-$VERSION.tar.gz rm -- "$DIR/ffsend-$VERSION/ffsend-$VERSION.tar.gz"
# TODO: configure the debian/control file # TODO: configure the debian/control file
# TODO: configure copyright file # TODO: configure copyright file

View file

@ -2,7 +2,7 @@
# Unlink the ffs alias if it links to ffsend # Unlink the ffs alias if it links to ffsend
if [[ -L /usr/bin/ffs ]] \ if [[ -L /usr/bin/ffs ]] \
&& [[ $(ls -l /usr/bin/ffs | sed -e 's/.* -> //') == "/usr/bin/ffsend" ]]; \ && [[ $(realpath /usr/bin/ffs) == "/usr/bin/ffsend" ]]; \
then then
echo "Removing ffs alias for ffsend..." echo "Removing ffs alias for ffsend..."
unlink /usr/bin/ffs unlink /usr/bin/ffs

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# Ensure svg-term is installed # Ensure svg-term is installed
if ! [ -x "$(command -v svg-term)" ]; then if ! [ -x "$(command -v svg-term)" ]; then

View file

@ -139,7 +139,7 @@ impl<'a> Download<'a> {
{ {
// Allocate an archive file, and update the download and target paths // Allocate an archive file, and update the download and target paths
if extract { if extract {
// TODO: select the extention dynamically // TODO: select the extension dynamically
let archive_extention = ".tar"; let archive_extention = ".tar";
// Allocate a temporary file to download the archive to // Allocate a temporary file to download the archive to
@ -210,7 +210,7 @@ impl<'a> Download<'a> {
/// ///
/// The full path including the name is returned. /// The full path including the name is returned.
/// ///
/// This method will check whether a file is overwitten, and whether /// This method will check whether a file is overwritten, and whether
/// parent directories must be created. /// parent directories must be created.
/// ///
/// The program will quit with an error message if a problem occurs. /// The program will quit with an error message if a problem occurs.
@ -313,7 +313,7 @@ impl<'a> Download<'a> {
// Get the path string // Get the path string
let path = target.to_str(); let path = target.to_str();
// If the path is emtpy, use the working directory with the name hint // If the path is empty, use the working directory with the name hint
let use_workdir = path.map(|path| path.trim().is_empty()).unwrap_or(true); let use_workdir = path.map(|path| path.trim().is_empty()).unwrap_or(true);
if use_workdir { if use_workdir {
match current_dir() { match current_dir() {

View file

@ -24,7 +24,7 @@ impl<'a> Completions<'a> {
let matcher_main = MainMatcher::with(self.cmd_matches).unwrap(); let matcher_main = MainMatcher::with(self.cmd_matches).unwrap();
let matcher_completions = CompletionsMatcher::with(self.cmd_matches).unwrap(); let matcher_completions = CompletionsMatcher::with(self.cmd_matches).unwrap();
// Obtian shells to generate completions for, build application definition // Obtain shells to generate completions for, build application definition
let shells = matcher_completions.shells(); let shells = matcher_completions.shells();
let dir = matcher_completions.output(); let dir = matcher_completions.output();
let quiet = matcher_main.quiet(); let quiet = matcher_main.quiet();

View file

@ -63,7 +63,7 @@ impl<'a> History<'a> {
// Remove history item // Remove history item
if let Some(url) = matcher_history.rm() { if let Some(url) = matcher_history.rm() {
// Remove item, print error if no item with URL was foudn // Remove item, print error if no item with URL was found
match history.remove_url(url) { match history.remove_url(url) {
Ok(removed) if !removed => quit_error_msg( Ok(removed) if !removed => quit_error_msg(
"could not remove item from history, no item matches given URL", "could not remove item from history, no item matches given URL",

View file

@ -50,7 +50,7 @@ fn select_api_version(
)); ));
} }
// Propegate other errors // Propagate other errors
Err(e) => return Err(e), Err(e) => return Err(e),
} }

View file

@ -224,7 +224,7 @@ impl<'a> Upload<'a> {
// Finish the archival process, writes the archive file // Finish the archival process, writes the archive file
archiver.finish().map_err(ArchiveError::Write)?; archiver.finish().map_err(ArchiveError::Write)?;
// Append archive extention to name, set to upload archived file // Append archive extension to name, set to upload archived file
if let Some(ref mut file_name) = file_name { if let Some(ref mut file_name) = file_name {
file_name.push_str(archive_extention); file_name.push_str(archive_extention);
} }
@ -275,7 +275,7 @@ impl<'a> Upload<'a> {
// TODO: set false parameter to authentication state // TODO: set false parameter to authentication state
let max_size = upload_size_max(api_version, auth); let max_size = upload_size_max(api_version, auth);
// Get the file size, fail on emtpy files, warn about large files // Get the file size, fail on empty files, warn about large files
if let Ok(size) = path.metadata().map(|m| m.len()) { if let Ok(size) = path.metadata().map(|m| m.len()) {
// Enforce files not being 0 bytes // Enforce files not being 0 bytes
if size == 0 && !matcher_main.force() { if size == 0 && !matcher_main.force() {

View file

@ -11,7 +11,7 @@ pub struct ArgGenPassphrase {}
impl ArgGenPassphrase { impl ArgGenPassphrase {
/// Generate a cryptographically secure passphrase that is easily /// Generate a cryptographically secure passphrase that is easily
/// rememberable using diceware. /// remembered using diceware.
pub fn gen_passphrase() -> String { pub fn gen_passphrase() -> String {
let mut config = BasicConfig::default(); let mut config = BasicConfig::default();
config.words = PASSPHRASE_WORDS; config.words = PASSPHRASE_WORDS;

View file

@ -8,7 +8,7 @@ pub mod owner;
pub mod password; pub mod password;
pub mod url; pub mod url;
// Re-eexport to arg module // Re-export to arg module
pub use self::api::ArgApi; pub use self::api::ArgApi;
pub use self::basic_auth::ArgBasicAuth; pub use self::basic_auth::ArgBasicAuth;
pub use self::download_limit::ArgDownloadLimit; pub use self::download_limit::ArgDownloadLimit;

View file

@ -35,7 +35,7 @@ impl<'a: 'b, 'b> UploadMatcher<'a> {
let name = self.matches.value_of("name")?; let name = self.matches.value_of("name")?;
// The file name must not be empty // The file name must not be empty
// TODO: allow to force an empty name here, and process emtpy names on downloading // TODO: allow to force an empty name here, and process empty names on downloading
if name.trim().is_empty() { if name.trim().is_empty() {
quit_error_msg( quit_error_msg(
"the file name must not be empty", "the file name must not be empty",
@ -171,7 +171,7 @@ pub enum CopyMode {
} }
impl CopyMode { impl CopyMode {
/// Build the string to copy, based on the given `url` and currend mode. /// Build the string to copy, based on the given `url` and current mode.
pub fn build(&self, url: &str) -> String { pub fn build(&self, url: &str) -> String {
match self { match self {
CopyMode::Url => url.into(), CopyMode::Url => url.into(),

View file

@ -21,7 +21,7 @@ const VERSION_MAX: &str = crate_version!();
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct History { pub struct History {
/// The application version the history file was built with. /// The application version the history file was built with.
/// Used for compatability checking. /// Used for compatibility checking.
version: Option<String>, version: Option<String>,
/// The file history. /// The file history.
@ -224,7 +224,7 @@ impl History {
/// ///
/// If the expiry property is None (thus unknown), the file will be kept. /// If the expiry property is None (thus unknown), the file will be kept.
/// ///
/// The number of exired files is returned. /// The number of expired files is returned.
pub fn gc(&mut self) -> usize { pub fn gc(&mut self) -> usize {
// Get a list of expired files // Get a list of expired files
let expired: Vec<RemoteFile> = self let expired: Vec<RemoteFile> = self

View file

@ -76,7 +76,7 @@ pub enum Error {
#[fail(display = "failed to shorten URL, got bad response")] #[fail(display = "failed to shorten URL, got bad response")]
Response(#[cause] ResponseError), Response(#[cause] ResponseError),
/// The server resonded with a malformed repsonse. /// The server responded with a malformed response.
#[fail(display = "failed to shorten URL, got malformed response")] #[fail(display = "failed to shorten URL, got malformed response")]
Malformed(#[cause] reqwest::Error), Malformed(#[cause] reqwest::Error),

View file

@ -291,13 +291,13 @@ pub fn highlight_info(msg: &str) -> ColoredString {
} }
/// Open the given URL in the users default browser. /// Open the given URL in the users default browser.
/// The browsers exit statis is returned. /// The browsers exit status is returned.
pub fn open_url(url: impl Borrow<Url>) -> Result<ExitStatus, IoError> { pub fn open_url(url: impl Borrow<Url>) -> Result<ExitStatus, IoError> {
open_path(url.borrow().as_str()) open_path(url.borrow().as_str())
} }
/// Open the given path or URL using the program configured on the system. /// Open the given path or URL using the program configured on the system.
/// The program exit statis is returned. /// The program exit status is returned.
pub fn open_path(path: &str) -> Result<ExitStatus, IoError> { pub fn open_path(path: &str) -> Result<ExitStatus, IoError> {
open::that(path) open::that(path)
} }
@ -318,7 +318,7 @@ pub fn set_clipboard(content: String) -> Result<(), ClipboardError> {
/// native clipboard interface only has a lifetime of the application. This means that the /// native clipboard interface only has a lifetime of the application. This means that the
/// clipboard is instantly cleared as soon as this application quits, which is always immediately. /// clipboard is instantly cleared as soon as this application quits, which is always immediately.
/// This limitation is due to security reasons as defined by X11. The alternative binaries we set /// This limitation is due to security reasons as defined by X11. The alternative binaries we set
/// the clipboard with spawn a daemon in the background to keep the clipboad alive until it's /// the clipboard with spawn a daemon in the background to keep the clipboard alive until it's
/// flushed. /// flushed.
#[cfg(feature = "clipboard")] #[cfg(feature = "clipboard")]
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
@ -491,7 +491,7 @@ pub enum ClipboardError {
#[fail(display = "failed to access clipboard using {}", _0)] #[fail(display = "failed to access clipboard using {}", _0)]
BinaryIo(&'static str, #[cause] IoError), BinaryIo(&'static str, #[cause] IoError),
/// `xclip` or `xsel` unexpectetly exited with a non-successful status code. /// `xclip` or `xsel` unexpectedly exited with a non-successful status code.
#[cfg(feature = "clipboard-bin")] #[cfg(feature = "clipboard-bin")]
#[fail( #[fail(
display = "failed to use clipboard, {} exited with status code {}", display = "failed to use clipboard, {} exited with status code {}",
@ -500,8 +500,8 @@ pub enum ClipboardError {
BinaryStatus(&'static str, i32), BinaryStatus(&'static str, i32),
} }
/// Check for an emtpy password in the given `password`. /// Check for an empty password in the given `password`.
/// If the password is emtpy the program will quit with an error unless /// If the password is empty the program will quit with an error unless
/// forced. /// forced.
// TODO: move this to a better module // TODO: move this to a better module
pub fn check_empty_password(password: &str, matcher_main: &MainMatcher) { pub fn check_empty_password(password: &str, matcher_main: &MainMatcher) {
@ -519,7 +519,7 @@ pub fn check_empty_password(password: &str, matcher_main: &MainMatcher) {
/// Prompt the user to enter a password. /// Prompt the user to enter a password.
/// ///
/// If `empty` is `false`, emtpy passwords aren't allowed unless forced. /// If `empty` is `false`, empty passwords aren't allowed unless forced.
pub fn prompt_password(main_matcher: &MainMatcher, optional: bool) -> Option<String> { pub fn prompt_password(main_matcher: &MainMatcher, optional: bool) -> Option<String> {
// Quit with an error if we may not interact // Quit with an error if we may not interact
if !optional && main_matcher.no_interact() { if !optional && main_matcher.no_interact() {
@ -549,7 +549,7 @@ pub fn prompt_password(main_matcher: &MainMatcher, optional: bool) -> Option<Str
} }
} }
// On input error, propegate the error or don't use a password if optional // On input error, propagate the error or don't use a password if optional
Err(err) => { Err(err) => {
if !optional { if !optional {
quit_error( quit_error(
@ -592,7 +592,7 @@ pub fn ensure_password(
return false; return false;
} }
// Check whehter we allow interaction // Check whether we allow interaction
let interact = !main_matcher.no_interact(); let interact = !main_matcher.no_interact();
loop { loop {
@ -761,7 +761,7 @@ pub fn ensure_owner_token(
main_matcher: &MainMatcher, main_matcher: &MainMatcher,
optional: bool, optional: bool,
) -> bool { ) -> bool {
// Check whehter we allow interaction // Check whether we allow interaction
let interact = !main_matcher.no_interact(); let interact = !main_matcher.no_interact();
// Notify that an owner token is required // Notify that an owner token is required
@ -984,7 +984,7 @@ pub fn ensure_enough_space<P: AsRef<Path>>(path: P, size: u64) {
} }
}; };
// Return if enough disk space is avaiable // Return if enough disk space is available
if space >= size { if space >= size {
return; return;
} }