mirror of
https://github.com/timvisee/ffsend.git
synced 2025-10-03 17:49:15 +02:00
Prompt password for info, move file checking to metadata action
This commit is contained in:
parent
35c376ab82
commit
c79a2c2298
5 changed files with 71 additions and 54 deletions
|
@ -17,10 +17,6 @@ use crypto::sig::signature_encoded;
|
||||||
use ext::status_code::StatusCodeExt;
|
use ext::status_code::StatusCodeExt;
|
||||||
use file::remote_file::RemoteFile;
|
use file::remote_file::RemoteFile;
|
||||||
use reader::{EncryptedFileWriter, ProgressReporter, ProgressWriter};
|
use reader::{EncryptedFileWriter, ProgressReporter, ProgressWriter};
|
||||||
use super::exists::{
|
|
||||||
Error as ExistsError,
|
|
||||||
Exists as ExistsAction,
|
|
||||||
};
|
|
||||||
use super::metadata::{
|
use super::metadata::{
|
||||||
Error as MetadataError,
|
Error as MetadataError,
|
||||||
Metadata as MetadataAction,
|
Metadata as MetadataAction,
|
||||||
|
@ -65,29 +61,18 @@ impl<'a> Download<'a> {
|
||||||
client: &Client,
|
client: &Client,
|
||||||
reporter: Arc<Mutex<ProgressReporter>>,
|
reporter: Arc<Mutex<ProgressReporter>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Make sure the given file exists
|
|
||||||
if self.check_exists {
|
|
||||||
let exist_response = ExistsAction::new(&self.file)
|
|
||||||
.invoke(&client)?;
|
|
||||||
|
|
||||||
// Return an error if the file does not exist
|
|
||||||
if !exist_response.exists() {
|
|
||||||
return Err(Error::Expired);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure a password is given when it is required
|
|
||||||
if !self.password.is_some() && exist_response.has_password() {
|
|
||||||
return Err(Error::PasswordRequired);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a key set for the file
|
// Create a key set for the file
|
||||||
let mut key = KeySet::from(self.file, self.password.as_ref());
|
let mut key = KeySet::from(self.file, self.password.as_ref());
|
||||||
|
|
||||||
// Fetch the file metadata, update the input vector in the key set
|
// Fetch the file metadata, update the input vector in the key set
|
||||||
let metadata = MetadataAction::new(self.file, self.password.clone())
|
let metadata = MetadataAction::new(
|
||||||
|
self.file,
|
||||||
|
self.password.clone(),
|
||||||
|
self.check_exists,
|
||||||
|
)
|
||||||
.invoke(&client)
|
.invoke(&client)
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
|
MetadataError::PasswordRequired => Error::PasswordRequired,
|
||||||
MetadataError::Expired => Error::Expired,
|
MetadataError::Expired => Error::Expired,
|
||||||
_ => err.into(),
|
_ => err.into(),
|
||||||
})?;
|
})?;
|
||||||
|
@ -258,26 +243,21 @@ impl<'a> Download<'a> {
|
||||||
|
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// An error occurred while checking whether the file exists on the
|
|
||||||
/// server.
|
|
||||||
#[fail(display = "Failed to check whether the file exists")]
|
|
||||||
Exists(#[cause] ExistsError),
|
|
||||||
|
|
||||||
/// An error occurred while fetching the metadata of the file.
|
/// An error occurred while fetching the metadata of the file.
|
||||||
/// This step is required in order to succsessfully decrypt the
|
/// This step is required in order to succsessfully decrypt the
|
||||||
/// file that will be downloaded.
|
/// file that will be downloaded.
|
||||||
#[fail(display = "Failed to fetch file metadata")]
|
#[fail(display = "Failed to fetch file metadata")]
|
||||||
Meta(#[cause] MetadataError),
|
Meta(#[cause] MetadataError),
|
||||||
|
|
||||||
/// A password is required, but was not given.
|
|
||||||
#[fail(display = "Missing password, password required")]
|
|
||||||
PasswordRequired,
|
|
||||||
|
|
||||||
/// The given Send file has expired, or did never exist in the first place.
|
/// The given Send file has expired, or did never exist in the first place.
|
||||||
/// Therefore the file could not be downloaded.
|
/// Therefore the file could not be downloaded.
|
||||||
#[fail(display = "The file has expired or did never exist")]
|
#[fail(display = "The file has expired or did never exist")]
|
||||||
Expired,
|
Expired,
|
||||||
|
|
||||||
|
/// A password is required, but was not given.
|
||||||
|
#[fail(display = "Missing password, password required")]
|
||||||
|
PasswordRequired,
|
||||||
|
|
||||||
/// An error occurred while downloading the file.
|
/// An error occurred while downloading the file.
|
||||||
#[fail(display = "Failed to download the file")]
|
#[fail(display = "Failed to download the file")]
|
||||||
Download(#[cause] DownloadError),
|
Download(#[cause] DownloadError),
|
||||||
|
@ -292,12 +272,6 @@ pub enum Error {
|
||||||
File(String, #[cause] FileError),
|
File(String, #[cause] FileError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ExistsError> for Error {
|
|
||||||
fn from(err: ExistsError) -> Error {
|
|
||||||
Error::Exists(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MetadataError> for Error {
|
impl From<MetadataError> for Error {
|
||||||
fn from(err: MetadataError) -> Error {
|
fn from(err: MetadataError) -> Error {
|
||||||
Error::Meta(err)
|
Error::Meta(err)
|
||||||
|
|
|
@ -12,6 +12,10 @@ use crypto::sig::signature_encoded;
|
||||||
use ext::status_code::StatusCodeExt;
|
use ext::status_code::StatusCodeExt;
|
||||||
use file::metadata::Metadata as MetadataData;
|
use file::metadata::Metadata as MetadataData;
|
||||||
use file::remote_file::RemoteFile;
|
use file::remote_file::RemoteFile;
|
||||||
|
use super::exists::{
|
||||||
|
Error as ExistsError,
|
||||||
|
Exists as ExistsAction,
|
||||||
|
};
|
||||||
|
|
||||||
/// The HTTP status code that is returned for expired files.
|
/// The HTTP status code that is returned for expired files.
|
||||||
const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound;
|
const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound;
|
||||||
|
@ -23,19 +27,43 @@ pub struct Metadata<'a> {
|
||||||
|
|
||||||
/// An optional password to decrypt a protected file.
|
/// An optional password to decrypt a protected file.
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
|
|
||||||
|
/// Check whether the file exists (recommended).
|
||||||
|
check_exists: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Metadata<'a> {
|
impl<'a> Metadata<'a> {
|
||||||
/// Construct a new metadata action.
|
/// Construct a new metadata action.
|
||||||
pub fn new(file: &'a RemoteFile, password: Option<String>) -> Self {
|
pub fn new(
|
||||||
|
file: &'a RemoteFile,
|
||||||
|
password: Option<String>,
|
||||||
|
check_exists: bool,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
file,
|
file,
|
||||||
password,
|
password,
|
||||||
|
check_exists,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoke the metadata action.
|
/// Invoke the metadata action.
|
||||||
pub fn invoke(self, client: &Client) -> Result<MetadataResponse, Error> {
|
pub fn invoke(self, client: &Client) -> Result<MetadataResponse, Error> {
|
||||||
|
// Make sure the given file exists
|
||||||
|
if self.check_exists {
|
||||||
|
let exist_response = ExistsAction::new(&self.file)
|
||||||
|
.invoke(&client)?;
|
||||||
|
|
||||||
|
// Return an error if the file does not exist
|
||||||
|
if !exist_response.exists() {
|
||||||
|
return Err(Error::Expired);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure a password is given when it is required
|
||||||
|
if !self.password.is_some() && exist_response.has_password() {
|
||||||
|
return Err(Error::PasswordRequired);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a key set for the file
|
// Create a key set for the file
|
||||||
let mut key = KeySet::from(self.file, self.password.as_ref());
|
let mut key = KeySet::from(self.file, self.password.as_ref());
|
||||||
|
|
||||||
|
@ -173,6 +201,11 @@ impl<'a> MetadataResponse {
|
||||||
|
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// An error occurred while checking whether the file exists on the
|
||||||
|
/// server.
|
||||||
|
#[fail(display = "Failed to check whether the file exists")]
|
||||||
|
Exists(#[cause] ExistsError),
|
||||||
|
|
||||||
/// A general error occurred while requesting the file data.
|
/// A general error occurred while requesting the file data.
|
||||||
/// This may be because authentication failed, because decrypting the
|
/// This may be because authentication failed, because decrypting the
|
||||||
/// file metadata didn't succeed, or due to some other reason.
|
/// file metadata didn't succeed, or due to some other reason.
|
||||||
|
@ -183,6 +216,16 @@ pub enum Error {
|
||||||
/// Therefore the file could not be downloaded.
|
/// Therefore the file could not be downloaded.
|
||||||
#[fail(display = "The file has expired or did never exist")]
|
#[fail(display = "The file has expired or did never exist")]
|
||||||
Expired,
|
Expired,
|
||||||
|
|
||||||
|
/// A password is required, but was not given.
|
||||||
|
#[fail(display = "Missing password, password required")]
|
||||||
|
PasswordRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ExistsError> for Error {
|
||||||
|
fn from(err: ExistsError) -> Error {
|
||||||
|
Error::Exists(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RequestError> for Error {
|
impl From<RequestError> for Error {
|
||||||
|
|
|
@ -48,6 +48,7 @@ impl<'a> Download<'a> {
|
||||||
let mut password = matcher_download.password();
|
let mut password = matcher_download.password();
|
||||||
|
|
||||||
// Check whether the file requires a password
|
// Check whether the file requires a password
|
||||||
|
// TODO: do not unwrap
|
||||||
let exists = ApiExists::new(&file).invoke(&client).unwrap();
|
let exists = ApiExists::new(&file).invoke(&client).unwrap();
|
||||||
if exists.has_password() != password.is_some() {
|
if exists.has_password() != password.is_some() {
|
||||||
if exists.has_password() {
|
if exists.has_password() {
|
||||||
|
|
|
@ -19,7 +19,7 @@ use cmd::matcher::{
|
||||||
Matcher,
|
Matcher,
|
||||||
info::InfoMatcher,
|
info::InfoMatcher,
|
||||||
};
|
};
|
||||||
use util::print_error;
|
use util::{print_error, prompt_password};
|
||||||
|
|
||||||
/// A file info action.
|
/// A file info action.
|
||||||
pub struct Info<'a> {
|
pub struct Info<'a> {
|
||||||
|
@ -48,34 +48,32 @@ impl<'a> Info<'a> {
|
||||||
|
|
||||||
// Parse the remote file based on the share URL, get the password
|
// Parse the remote file based on the share URL, get the password
|
||||||
let file = RemoteFile::parse_url(url, matcher_info.owner())?;
|
let file = RemoteFile::parse_url(url, matcher_info.owner())?;
|
||||||
let password = matcher_info.password();
|
let mut password = matcher_info.password();
|
||||||
|
|
||||||
// TODO: show an informative error if the owner token isn't set
|
// TODO: show an informative error if the owner token isn't set
|
||||||
|
|
||||||
// Make sure the file exists
|
// Check whether the file exists
|
||||||
let exists_response = ApiExists::new(&file)
|
// TODO: do not unwrap
|
||||||
.invoke(&client)?;
|
let exists = ApiExists::new(&file).invoke(&client).unwrap();
|
||||||
|
if !exists.exists() {
|
||||||
// Make sure the file exists
|
|
||||||
if !exists_response.exists() {
|
|
||||||
return Err(Error::Expired);
|
return Err(Error::Expired);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure a password is given when it is required
|
// Check whether the file requires a password
|
||||||
let has_password = password.is_some();
|
if exists.has_password() != password.is_some() {
|
||||||
if has_password != exists_response.has_password() {
|
if exists.has_password() {
|
||||||
if has_password {
|
println!("This file is protected with a password.");
|
||||||
// TODO: show a proper message here
|
password = Some(prompt_password());
|
||||||
println!("file not password protected, ignoring password");
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: show a propper error here, or prompt for the password
|
println!("Ignoring password, it is not required");
|
||||||
panic!("password required");
|
password = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch both file info and metadata
|
// Fetch both file info and metadata
|
||||||
let info = ApiInfo::new(&file, None).invoke(&client)?;
|
let info = ApiInfo::new(&file, None).invoke(&client)?;
|
||||||
let metadata = ApiMetadata::new(&file, password).invoke(&client)
|
let metadata = ApiMetadata::new(&file, password, false)
|
||||||
|
.invoke(&client)
|
||||||
.map_err(|err| print_error(err.context(
|
.map_err(|err| print_error(err.context(
|
||||||
"Failed to fetch file metadata, showing limited info",
|
"Failed to fetch file metadata, showing limited info",
|
||||||
)))
|
)))
|
||||||
|
|
|
@ -84,6 +84,7 @@ pub fn set_clipboard(content: String) -> Result<(), Box<StdError>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prompt the user to enter a password.
|
/// Prompt the user to enter a password.
|
||||||
|
// TODO: do not prompt if no-interactive
|
||||||
pub fn prompt_password() -> String {
|
pub fn prompt_password() -> String {
|
||||||
match prompt_password_stderr("Password: ") {
|
match prompt_password_stderr("Password: ") {
|
||||||
Ok(password) => password,
|
Ok(password) => password,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue