mirror of
https://github.com/timvisee/ffsend.git
synced 2025-10-05 18:24:18 +02:00
Extract nonce parsing logic to a module
This commit is contained in:
parent
7ced1f4278
commit
718238b35e
11 changed files with 142 additions and 397 deletions
|
@ -1,18 +1,13 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use reqwest::{Client, StatusCode};
|
||||
|
||||
use api::data::{
|
||||
Error as DataError,
|
||||
OwnedData,
|
||||
};
|
||||
use crypto::b64;
|
||||
use api::nonce::{NonceError, request_auth_nonce};
|
||||
use ext::status_code::StatusCodeExt;
|
||||
use file::remote_file::RemoteFile;
|
||||
|
||||
/// The name of the header that is used for the authentication nonce.
|
||||
const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// An action to delete a remote file.
|
||||
pub struct Delete<'a> {
|
||||
/// The remote file to delete.
|
||||
|
@ -48,40 +43,13 @@ impl<'a> Delete<'a> {
|
|||
}
|
||||
|
||||
/// Fetch the authentication nonce for the file from the remote server.
|
||||
fn fetch_auth_nonce(&self, client: &Client) -> Result<Vec<u8>, AuthError> {
|
||||
// Get the download URL, and parse the nonce
|
||||
let download_url = self.file.download_url(false);
|
||||
let response = client.get(download_url)
|
||||
.send()
|
||||
.map_err(|_| AuthError::NonceReq)?;
|
||||
|
||||
// Validate the status code
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
// TODO: should we check here whether a 404 is returned?
|
||||
// // Handle expired files
|
||||
// if status == FILE_EXPIRED_STATUS {
|
||||
// return Err(Error::Expired);
|
||||
// } else {
|
||||
return Err(AuthError::NonceReqStatus(status, status.err_text()).into());
|
||||
// }
|
||||
}
|
||||
|
||||
// Get the authentication nonce
|
||||
b64::decode(
|
||||
response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.ok_or(AuthError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(AuthError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| AuthError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(AuthError::MalformedNonce)?
|
||||
).map_err(|_| AuthError::MalformedNonce.into())
|
||||
fn fetch_auth_nonce(&self, client: &Client)
|
||||
-> Result<Vec<u8>, PrepareError>
|
||||
{
|
||||
request_auth_nonce(
|
||||
client,
|
||||
self.file.download_url(false),
|
||||
).map_err(|err| PrepareError::Auth(err))
|
||||
}
|
||||
|
||||
/// Send a request to delete the remote file, with the given data.
|
||||
|
@ -142,12 +110,6 @@ impl From<PrepareError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AuthError> for Error {
|
||||
fn from(err: AuthError) -> Error {
|
||||
PrepareError::Auth(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DeleteError> for Error {
|
||||
fn from(err: DeleteError) -> Error {
|
||||
Error::Delete(err)
|
||||
|
@ -167,7 +129,7 @@ pub enum DeleteDataError {
|
|||
pub enum PrepareError {
|
||||
/// Failed to authenticate
|
||||
#[fail(display = "Failed to authenticate")]
|
||||
Auth(#[cause] AuthError),
|
||||
Auth(#[cause] NonceError),
|
||||
|
||||
/// An error occurred while building the deletion data that will be
|
||||
/// send to the server.
|
||||
|
@ -181,31 +143,6 @@ impl From<DataError> for PrepareError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum AuthError {
|
||||
/// Sending the request to gather the authentication encryption nonce
|
||||
/// failed.
|
||||
#[fail(display = "Failed to request authentication nonce")]
|
||||
NonceReq,
|
||||
|
||||
/// The response for fetching the authentication encryption nonce
|
||||
/// indicated an error and wasn't successful.
|
||||
#[fail(display = "Bad HTTP response '{}' while requesting authentication nonce", _1)]
|
||||
NonceReqStatus(StatusCode, String),
|
||||
|
||||
/// No authentication encryption nonce was included in the response
|
||||
/// from the server, it was missing.
|
||||
#[fail(display = "Missing authentication nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The authentication encryption nonce from the response malformed or
|
||||
/// empty.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed authentication nonce")]
|
||||
MalformedNonce,
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum DeleteError {
|
||||
/// Sending the file deletion request failed.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{
|
||||
self,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use reqwest::{Client, StatusCode};
|
||||
|
||||
use ext::status_code::StatusCodeExt;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use std::cmp::max;
|
||||
|
||||
use reqwest::{
|
||||
|
@ -12,13 +10,10 @@ use api::data::{
|
|||
Error as DataError,
|
||||
OwnedData,
|
||||
};
|
||||
use crypto::b64;
|
||||
use api::nonce::{NonceError, request_auth_nonce};
|
||||
use ext::status_code::StatusCodeExt;
|
||||
use file::remote_file::RemoteFile;
|
||||
|
||||
/// The name of the header that is used for the authentication nonce.
|
||||
const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// An action to fetch info of a shared file.
|
||||
pub struct Info<'a> {
|
||||
/// The remote file to fetch the info for.
|
||||
|
@ -54,40 +49,13 @@ impl<'a> Info<'a> {
|
|||
}
|
||||
|
||||
/// Fetch the authentication nonce for the file from the remote server.
|
||||
fn fetch_auth_nonce(&self, client: &Client) -> Result<Vec<u8>, AuthError> {
|
||||
// Get the download URL, and parse the nonce
|
||||
let download_url = self.file.download_url(false);
|
||||
let response = client.get(download_url)
|
||||
.send()
|
||||
.map_err(|_| AuthError::NonceReq)?;
|
||||
|
||||
// Validate the status code
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
// TODO: should we check here whether a 404 is returned?
|
||||
// // Handle expired files
|
||||
// if status == FILE_EXPIRED_STATUS {
|
||||
// return Err(Error::Expired);
|
||||
// } else {
|
||||
return Err(AuthError::NonceReqStatus(status, status.err_text()).into());
|
||||
// }
|
||||
}
|
||||
|
||||
// Get the authentication nonce
|
||||
b64::decode(
|
||||
response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.ok_or(AuthError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(AuthError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| AuthError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(AuthError::MalformedNonce)?
|
||||
).map_err(|_| AuthError::MalformedNonce.into())
|
||||
fn fetch_auth_nonce(&self, client: &Client)
|
||||
-> Result<Vec<u8>, PrepareError>
|
||||
{
|
||||
request_auth_nonce(
|
||||
client,
|
||||
self.file.download_url(false),
|
||||
).map_err(|err| PrepareError::Auth(err))
|
||||
}
|
||||
|
||||
/// Send the request for fetching the remote file info.
|
||||
|
@ -193,12 +161,6 @@ impl From<PrepareError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AuthError> for Error {
|
||||
fn from(err: AuthError) -> Error {
|
||||
PrepareError::Auth(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InfoError> for Error {
|
||||
fn from(err: InfoError) -> Error {
|
||||
Error::Info(err)
|
||||
|
@ -218,7 +180,7 @@ pub enum InfoDataError {
|
|||
pub enum PrepareError {
|
||||
/// Failed authenticating, needed to fetch the info
|
||||
#[fail(display = "Failed to authenticate")]
|
||||
Auth(#[cause] AuthError),
|
||||
Auth(#[cause] NonceError),
|
||||
|
||||
/// An error occurred while building the info data that will be
|
||||
/// send to the server.
|
||||
|
@ -232,31 +194,6 @@ impl From<DataError> for PrepareError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum AuthError {
|
||||
/// Sending the request to gather the authentication encryption nonce
|
||||
/// failed.
|
||||
#[fail(display = "Failed to request authentication nonce")]
|
||||
NonceReq,
|
||||
|
||||
/// The response for fetching the authentication encryption nonce
|
||||
/// indicated an error and wasn't successful.
|
||||
#[fail(display = "Bad HTTP response '{}' while requesting authentication nonce", _1)]
|
||||
NonceReqStatus(StatusCode, String),
|
||||
|
||||
/// No authentication encryption nonce was included in the response
|
||||
/// from the server, it was missing.
|
||||
#[fail(display = "Missing authentication nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The authentication encryption nonce from the response malformed or
|
||||
/// empty.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed authentication nonce")]
|
||||
MalformedNonce,
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum InfoError {
|
||||
/// Sending the request to fetch the file info failed.
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use failure::Error as FailureError;
|
||||
use openssl::symm::decrypt_aead;
|
||||
use reqwest::{Client, StatusCode};
|
||||
use reqwest::header::Authorization;
|
||||
use serde_json;
|
||||
|
||||
use api::nonce::{
|
||||
HEADER_NONCE,
|
||||
header_nonce,
|
||||
NonceError,
|
||||
request_auth_nonce,
|
||||
};
|
||||
use crypto::b64;
|
||||
use crypto::key_set::KeySet;
|
||||
use crypto::sig::signature_encoded;
|
||||
|
@ -13,9 +17,6 @@ use ext::status_code::StatusCodeExt;
|
|||
use file::metadata::Metadata as MetadataData;
|
||||
use file::remote_file::RemoteFile;
|
||||
|
||||
/// The name of the header that is used for the authentication nonce.
|
||||
const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// The HTTP status code that is returned for expired files.
|
||||
const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound;
|
||||
|
||||
|
@ -50,42 +51,14 @@ impl<'a> Metadata<'a> {
|
|||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
/// Fetch the authentication nonce for the file from the Send server.
|
||||
/// Fetch the authentication nonce for the file from the remote server.
|
||||
fn fetch_auth_nonce(&self, client: &Client)
|
||||
-> Result<Vec<u8>, Error>
|
||||
-> Result<Vec<u8>, RequestError>
|
||||
{
|
||||
// Get the download url, and parse the nonce
|
||||
let download_url = self.file.download_url(false);
|
||||
let response = client.get(download_url)
|
||||
.send()
|
||||
.map_err(|_| AuthError::NonceReq)?;
|
||||
|
||||
// Validate the status code
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
// Handle expired files
|
||||
if status == FILE_EXPIRED_STATUS {
|
||||
return Err(Error::Expired);
|
||||
} else {
|
||||
return Err(AuthError::NonceReqStatus(status, status.err_text()).into());
|
||||
}
|
||||
}
|
||||
|
||||
// Get the authentication nonce
|
||||
b64::decode(
|
||||
response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.ok_or(AuthError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(AuthError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| AuthError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(AuthError::MalformedNonce)?
|
||||
).map_err(|_| AuthError::MalformedNonce.into())
|
||||
request_auth_nonce(
|
||||
client,
|
||||
self.file.download_url(false),
|
||||
).map_err(|err| RequestError::Auth(err))
|
||||
}
|
||||
|
||||
/// Create a metadata nonce, and fetch the metadata for the file from the
|
||||
|
@ -119,20 +92,8 @@ impl<'a> Metadata<'a> {
|
|||
}
|
||||
|
||||
// Get the metadata nonce
|
||||
let nonce = b64::decode(
|
||||
response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.ok_or(MetaError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(MetaError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| MetaError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(MetaError::MalformedNonce)?
|
||||
).map_err(|_| MetaError::MalformedNonce)?;
|
||||
let nonce = header_nonce(HEADER_NONCE, &response)
|
||||
.map_err(|err| MetaError::Nonce(err))?;
|
||||
|
||||
// Parse the metadata response, and decrypt it
|
||||
Ok(MetadataResponse::from(
|
||||
|
@ -228,9 +189,9 @@ pub enum Error {
|
|||
Expired,
|
||||
}
|
||||
|
||||
impl From<AuthError> for Error {
|
||||
fn from(err: AuthError) -> Error {
|
||||
Error::Request(RequestError::Auth(err))
|
||||
impl From<RequestError> for Error {
|
||||
fn from(err: RequestError) -> Error {
|
||||
Error::Request(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,38 +205,13 @@ impl From<MetaError> for Error {
|
|||
pub enum RequestError {
|
||||
/// Failed authenticating, in order to fetch the file data.
|
||||
#[fail(display = "Failed to authenticate")]
|
||||
Auth(#[cause] AuthError),
|
||||
Auth(#[cause] NonceError),
|
||||
|
||||
/// Failed to retrieve the file metadata.
|
||||
#[fail(display = "Failed to retrieve file metadata")]
|
||||
Meta(#[cause] MetaError),
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum AuthError {
|
||||
/// Sending the request to gather the authentication encryption nonce
|
||||
/// failed.
|
||||
#[fail(display = "Failed to request authentication nonce")]
|
||||
NonceReq,
|
||||
|
||||
/// The response for fetching the authentication encryption nonce
|
||||
/// indicated an error and wasn't successful.
|
||||
#[fail(display = "Bad HTTP response '{}' while requesting authentication nonce", _1)]
|
||||
NonceReqStatus(StatusCode, String),
|
||||
|
||||
/// No authentication encryption nonce was included in the response
|
||||
/// from the server, it was missing.
|
||||
#[fail(display = "Missing authentication nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The authentication encryption nonce from the response malformed or
|
||||
/// empty.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed authentication nonce")]
|
||||
MalformedNonce,
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum MetaError {
|
||||
/// An error occurred while computing the cryptographic signature used for
|
||||
|
@ -292,16 +228,9 @@ pub enum MetaError {
|
|||
#[fail(display = "Bad HTTP response '{}' while requesting metadata nonce", _1)]
|
||||
NonceReqStatus(StatusCode, String),
|
||||
|
||||
/// No metadata encryption nonce was included in the response from the
|
||||
/// server, it was missing.
|
||||
#[fail(display = "Missing metadata nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The metadata encryption nonce from the response malformed or empty.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed metadata nonce")]
|
||||
MalformedNonce,
|
||||
/// Couldn't parse the metadata encryption nonce.
|
||||
#[fail(display = "Failed to parse the metadata encryption nonce")]
|
||||
Nonce(#[cause] NonceError),
|
||||
|
||||
/// The received metadata is malformed, and couldn't be decoded or
|
||||
/// interpreted.
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use reqwest::{Client, StatusCode};
|
||||
|
||||
use api::data::{
|
||||
Error as DataError,
|
||||
OwnedData,
|
||||
};
|
||||
use crypto::b64;
|
||||
use api::nonce::{NonceError, request_auth_nonce};
|
||||
use ext::status_code::StatusCodeExt;
|
||||
use file::remote_file::RemoteFile;
|
||||
|
||||
/// The name of the header that is used for the authentication nonce.
|
||||
const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// The default download count.
|
||||
pub const PARAMS_DEFAULT_DOWNLOAD: u8 = 1;
|
||||
pub const PARAMS_DEFAULT_DOWNLOAD_STR: &'static str = "1";
|
||||
|
@ -69,43 +64,14 @@ impl<'a> Params<'a> {
|
|||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
/// Fetch the authentication nonce for the file from the Send server.
|
||||
/// Fetch the authentication nonce for the file from the remote server.
|
||||
fn fetch_auth_nonce(&self, client: &Client)
|
||||
-> Result<Vec<u8>, AuthError>
|
||||
-> Result<Vec<u8>, PrepareError>
|
||||
{
|
||||
// Get the download URL, and parse the nonce
|
||||
let download_url = self.file.download_url(false);
|
||||
let response = client.get(download_url)
|
||||
.send()
|
||||
.map_err(|_| AuthError::NonceReq)?;
|
||||
|
||||
// Validate the status code
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
// TODO: should we check here whether a 404 is returned?
|
||||
// // Handle expired files
|
||||
// if status == FILE_EXPIRED_STATUS {
|
||||
// return Err(Error::Expired);
|
||||
// } else {
|
||||
return Err(AuthError::NonceReqStatus(status, status.err_text()).into());
|
||||
// }
|
||||
}
|
||||
|
||||
// Get the authentication nonce
|
||||
b64::decode(
|
||||
response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.ok_or(AuthError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(AuthError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| AuthError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(AuthError::MalformedNonce)?
|
||||
).map_err(|_| AuthError::MalformedNonce.into())
|
||||
request_auth_nonce(
|
||||
client,
|
||||
self.file.download_url(false),
|
||||
).map_err(|err| PrepareError::Auth(err))
|
||||
}
|
||||
|
||||
/// Send the request for changing the parameters.
|
||||
|
@ -219,12 +185,6 @@ impl From<PrepareError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AuthError> for Error {
|
||||
fn from(err: AuthError) -> Error {
|
||||
PrepareError::Auth(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ChangeError> for Error {
|
||||
fn from(err: ChangeError) -> Error {
|
||||
Error::Change(err)
|
||||
|
@ -250,7 +210,7 @@ pub enum ParamsDataError {
|
|||
pub enum PrepareError {
|
||||
/// Failed authenticating, needed to change the parameters.
|
||||
#[fail(display = "Failed to authenticate")]
|
||||
Auth(#[cause] AuthError),
|
||||
Auth(#[cause] NonceError),
|
||||
|
||||
/// An error occurred while building the parameter data that will be send
|
||||
/// to the server.
|
||||
|
@ -264,31 +224,6 @@ impl From<DataError> for PrepareError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum AuthError {
|
||||
/// Sending the request to gather the authentication encryption nonce
|
||||
/// failed.
|
||||
#[fail(display = "Failed to request authentication nonce")]
|
||||
NonceReq,
|
||||
|
||||
/// The response for fetching the authentication encryption nonce
|
||||
/// indicated an error and wasn't successful.
|
||||
#[fail(display = "Bad HTTP response '{}' while requesting authentication nonce", _1)]
|
||||
NonceReqStatus(StatusCode, String),
|
||||
|
||||
/// No authentication encryption nonce was included in the response
|
||||
/// from the server, it was missing.
|
||||
#[fail(display = "Missing authentication nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The authentication encryption nonce from the response malformed or
|
||||
/// empty.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed authentication nonce")]
|
||||
MalformedNonce,
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum ChangeError {
|
||||
/// Sending the request to change the parameters failed.
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
// TODO: define redirect policy
|
||||
|
||||
use reqwest::{Client, StatusCode};
|
||||
|
||||
use api::data::{
|
||||
Error as DataError,
|
||||
OwnedData,
|
||||
};
|
||||
use crypto::b64;
|
||||
use api::nonce::{NonceError, request_auth_nonce};
|
||||
use crypto::key_set::KeySet;
|
||||
use ext::status_code::StatusCodeExt;
|
||||
use file::remote_file::RemoteFile;
|
||||
|
||||
/// The name of the header that is used for the authentication nonce.
|
||||
const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// An action to change a password of an uploaded Send file.
|
||||
pub struct Password<'a> {
|
||||
/// The remote file to change the password for.
|
||||
|
@ -65,41 +60,12 @@ impl<'a> Password<'a> {
|
|||
|
||||
/// Fetch the authentication nonce for the file from the Send server.
|
||||
fn fetch_auth_nonce(&self, client: &Client)
|
||||
-> Result<Vec<u8>, AuthError>
|
||||
-> Result<Vec<u8>, PrepareError>
|
||||
{
|
||||
// Get the download URL, and parse the nonce
|
||||
let download_url = self.file.download_url(false);
|
||||
let response = client.get(download_url)
|
||||
.send()
|
||||
.map_err(|_| AuthError::NonceReq)?;
|
||||
|
||||
// Validate the status code
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
// TODO: should we check here whether a 404 is returned?
|
||||
// // Handle expired files
|
||||
// if status == FILE_EXPIRED_STATUS {
|
||||
// return Err(Error::Expired);
|
||||
// } else {
|
||||
return Err(AuthError::NonceReqStatus(status, status.err_text()).into());
|
||||
// }
|
||||
}
|
||||
|
||||
// Get the authentication nonce
|
||||
b64::decode(
|
||||
response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.ok_or(AuthError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(AuthError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| AuthError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(AuthError::MalformedNonce)?
|
||||
).map_err(|_| AuthError::MalformedNonce.into())
|
||||
request_auth_nonce(
|
||||
client,
|
||||
self.file.download_url(false),
|
||||
).map_err(|err| PrepareError::Auth(err))
|
||||
}
|
||||
|
||||
/// Send the request for changing the file password.
|
||||
|
@ -165,12 +131,6 @@ impl From<PrepareError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AuthError> for Error {
|
||||
fn from(err: AuthError) -> Error {
|
||||
PrepareError::Auth(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ChangeError> for Error {
|
||||
fn from(err: ChangeError) -> Error {
|
||||
Error::Change(err)
|
||||
|
@ -181,7 +141,7 @@ impl From<ChangeError> for Error {
|
|||
pub enum PrepareError {
|
||||
/// Failed authenticating, needed to set a new password.
|
||||
#[fail(display = "Failed to authenticate")]
|
||||
Auth(#[cause] AuthError),
|
||||
Auth(#[cause] NonceError),
|
||||
|
||||
/// Some error occurred while building the data that will be sent.
|
||||
/// The owner token might possibly be missing, the wrapped error will
|
||||
|
@ -196,31 +156,6 @@ impl From<DataError> for PrepareError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum AuthError {
|
||||
/// Sending the request to gather the authentication encryption nonce
|
||||
/// failed.
|
||||
#[fail(display = "Failed to request authentication nonce")]
|
||||
NonceReq,
|
||||
|
||||
/// The response for fetching the authentication encryption nonce
|
||||
/// indicated an error and wasn't successful.
|
||||
#[fail(display = "Bad HTTP response '{}' while requesting authentication nonce", _1)]
|
||||
NonceReqStatus(StatusCode, String),
|
||||
|
||||
/// No authentication encryption nonce was included in the response
|
||||
/// from the server, it was missing.
|
||||
#[fail(display = "Missing authentication nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The authentication encryption nonce from the response malformed or
|
||||
/// empty.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed authentication nonce")]
|
||||
MalformedNonce,
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum ChangeError {
|
||||
/// Sending the request to change the password failed.
|
||||
|
|
|
@ -22,7 +22,7 @@ use url::{
|
|||
Url,
|
||||
};
|
||||
|
||||
use crypto::b64;
|
||||
use api::nonce::{HEADER_NONCE, header_nonce};
|
||||
use crypto::key_set::KeySet;
|
||||
use ext::status_code::StatusCodeExt;
|
||||
use file::remote_file::RemoteFile;
|
||||
|
@ -45,9 +45,6 @@ use super::password::{
|
|||
|
||||
type EncryptedReader = ProgressReader<BufReader<EncryptedFileReader>>;
|
||||
|
||||
/// The name of the header that is used for the authentication nonce.
|
||||
const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// A file upload action to a Send server.
|
||||
pub struct Upload {
|
||||
/// The Send host to upload the file to.
|
||||
|
@ -262,14 +259,7 @@ impl Upload {
|
|||
}
|
||||
|
||||
// Try to get the nonce, don't error on failure
|
||||
let nonce = response.headers()
|
||||
.get_raw(HEADER_AUTH_NONCE)
|
||||
.and_then(|h| h.one())
|
||||
.and_then(|line| String::from_utf8(line.to_vec()).ok())
|
||||
.and_then(|line| line.split_terminator(" ").skip(1).next()
|
||||
.map(|line| line.to_owned())
|
||||
)
|
||||
.and_then(|nonce| b64::decode(&nonce).ok());
|
||||
let nonce = header_nonce(HEADER_NONCE, &response).ok();
|
||||
|
||||
// Decode the response
|
||||
let response: UploadResponse = match response.json() {
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
pub mod data;
|
||||
pub mod nonce;
|
||||
|
|
84
api/src/api/nonce.rs
Normal file
84
api/src/api/nonce.rs
Normal file
|
@ -0,0 +1,84 @@
|
|||
use url::Url;
|
||||
use reqwest::{Client, Response, StatusCode};
|
||||
|
||||
use crypto::b64;
|
||||
use ext::status_code::StatusCodeExt;
|
||||
|
||||
/// The name of the header the nonce is delivered in.
|
||||
pub const HEADER_NONCE: &'static str = "WWW-Authenticate";
|
||||
|
||||
/// Do a new request, and fetch the nonce from the header with the given name.
|
||||
pub fn request_nonce(client: &Client, url: Url, header: &str)
|
||||
-> Result<Vec<u8>, NonceError>
|
||||
{
|
||||
// Make the request
|
||||
let response = client.get(url)
|
||||
.send()
|
||||
.map_err(|_| NonceError::Req)?;
|
||||
|
||||
// Validate the status code
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
// TODO: should we check here whether a 404 is returned?
|
||||
// // Handle expired files
|
||||
// if status == FILE_EXPIRED_STATUS {
|
||||
// return Err(Error::Expired);
|
||||
// } else {
|
||||
return Err(NonceError::ReqStatus(status, status.err_text()).into());
|
||||
// }
|
||||
}
|
||||
|
||||
// Fetch the nonce
|
||||
header_nonce(header, &response)
|
||||
}
|
||||
|
||||
/// Do a new request, and fetch the authentication nonce from the header with
|
||||
/// the given name.
|
||||
pub fn request_auth_nonce(client: &Client, url: Url)
|
||||
-> Result<Vec<u8>, NonceError>
|
||||
{
|
||||
request_nonce(client, url, HEADER_NONCE)
|
||||
}
|
||||
|
||||
/// Get a nonce from a header in the given response.
|
||||
pub fn header_nonce(header: &str, response: &Response)
|
||||
-> Result<Vec<u8>, NonceError>
|
||||
{
|
||||
// Get the authentication nonce
|
||||
b64::decode(
|
||||
response.headers()
|
||||
.get_raw(header)
|
||||
.ok_or(NonceError::NoNonceHeader)?
|
||||
.one()
|
||||
.ok_or(NonceError::MalformedNonce)
|
||||
.and_then(|line| String::from_utf8(line.to_vec())
|
||||
.map_err(|_| NonceError::MalformedNonce)
|
||||
)?
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(NonceError::MalformedNonce)?
|
||||
).map_err(|_| NonceError::MalformedNonce.into())
|
||||
}
|
||||
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum NonceError {
|
||||
/// Sending the request to fetch a nonce failed.
|
||||
#[fail(display = "Failed to request nonce")]
|
||||
Req,
|
||||
|
||||
/// The response for fetching the nonce indicated an error and wasn't
|
||||
/// successful.
|
||||
#[fail(display = "Bad HTTP response '{}' while requesting nonce", _1)]
|
||||
ReqStatus(StatusCode, String),
|
||||
|
||||
/// The nonce header was missing from the request.
|
||||
#[fail(display = "Missing nonce in server response")]
|
||||
NoNonceHeader,
|
||||
|
||||
/// The received nonce could not be parsed, because it was malformed.
|
||||
/// Maybe the server responded with a new format that isn't supported yet
|
||||
/// by this client.
|
||||
#[fail(display = "Received malformed nonce")]
|
||||
MalformedNonce,
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue