Add (untested) get_url_for_private_file
This commit is contained in:
parent
3e6a05cd04
commit
9e1f613aae
@ -9,7 +9,7 @@ use ariadne::ids::DecodingError;
|
|||||||
#[error("{}", .error_type)]
|
#[error("{}", .error_type)]
|
||||||
pub struct OAuthError {
|
pub struct OAuthError {
|
||||||
#[source]
|
#[source]
|
||||||
pub error_type: OAuthErrorType,
|
pub error_type: Box<OAuthErrorType>,
|
||||||
|
|
||||||
pub state: Option<String>,
|
pub state: Option<String>,
|
||||||
pub valid_redirect_uri: Option<ValidatedRedirectUri>,
|
pub valid_redirect_uri: Option<ValidatedRedirectUri>,
|
||||||
@ -32,7 +32,7 @@ impl OAuthError {
|
|||||||
/// See: IETF RFC 6749 4.1.2.1 (https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1)
|
/// See: IETF RFC 6749 4.1.2.1 (https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1)
|
||||||
pub fn error(error_type: impl Into<OAuthErrorType>) -> Self {
|
pub fn error(error_type: impl Into<OAuthErrorType>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
error_type: error_type.into(),
|
error_type: Box::new(error_type.into()),
|
||||||
valid_redirect_uri: None,
|
valid_redirect_uri: None,
|
||||||
state: None,
|
state: None,
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ impl OAuthError {
|
|||||||
valid_redirect_uri: &ValidatedRedirectUri,
|
valid_redirect_uri: &ValidatedRedirectUri,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
error_type: err.into(),
|
error_type: Box::new(err.into()),
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
valid_redirect_uri: Some(valid_redirect_uri.clone()),
|
valid_redirect_uri: Some(valid_redirect_uri.clone()),
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ impl OAuthError {
|
|||||||
|
|
||||||
impl actix_web::ResponseError for OAuthError {
|
impl actix_web::ResponseError for OAuthError {
|
||||||
fn status_code(&self) -> StatusCode {
|
fn status_code(&self) -> StatusCode {
|
||||||
match self.error_type {
|
match *self.error_type {
|
||||||
OAuthErrorType::AuthenticationError(_)
|
OAuthErrorType::AuthenticationError(_)
|
||||||
| OAuthErrorType::FailedScopeParse(_)
|
| OAuthErrorType::FailedScopeParse(_)
|
||||||
| OAuthErrorType::ScopesTooBroad
|
| OAuthErrorType::ScopesTooBroad
|
||||||
|
@ -101,7 +101,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert!(validated.is_err_and(|e| matches!(
|
assert!(validated.is_err_and(|e| matches!(
|
||||||
e.error_type,
|
*e.error_type,
|
||||||
OAuthErrorType::RedirectUriNotConfigured(_)
|
OAuthErrorType::RedirectUriNotConfigured(_)
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use chrono::Utc;
|
|||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct MockHost(());
|
pub struct MockHost(());
|
||||||
@ -47,6 +48,15 @@ impl FileHost for MockHost {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_url_for_private_file(
|
||||||
|
&self,
|
||||||
|
file_name: &str,
|
||||||
|
_expiry: Duration,
|
||||||
|
) -> Result<String, FileHostingError> {
|
||||||
|
let cdn_url = dotenvy::var("CDN_URL").unwrap();
|
||||||
|
Ok(format!("{cdn_url}/private/{file_name}"))
|
||||||
|
}
|
||||||
|
|
||||||
async fn delete_file(
|
async fn delete_file(
|
||||||
&self,
|
&self,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
mod mock;
|
mod mock;
|
||||||
@ -10,8 +11,8 @@ pub use s3_host::S3Host;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum FileHostingError {
|
pub enum FileHostingError {
|
||||||
#[error("S3 error: {0}")]
|
#[error("S3 error when {0}: {1}")]
|
||||||
S3Error(String),
|
S3Error(&'static str, s3::error::S3Error),
|
||||||
#[error("File system error in file hosting: {0}")]
|
#[error("File system error in file hosting: {0}")]
|
||||||
FileSystemError(#[from] std::io::Error),
|
FileSystemError(#[from] std::io::Error),
|
||||||
#[error("Invalid Filename")]
|
#[error("Invalid Filename")]
|
||||||
@ -51,6 +52,12 @@ pub trait FileHost {
|
|||||||
file_bytes: Bytes,
|
file_bytes: Bytes,
|
||||||
) -> Result<UploadFileData, FileHostingError>;
|
) -> Result<UploadFileData, FileHostingError>;
|
||||||
|
|
||||||
|
async fn get_url_for_private_file(
|
||||||
|
&self,
|
||||||
|
file_name: &str,
|
||||||
|
expiry: Duration,
|
||||||
|
) -> Result<String, FileHostingError>;
|
||||||
|
|
||||||
async fn delete_file(
|
async fn delete_file(
|
||||||
&self,
|
&self,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
|
@ -10,6 +10,7 @@ use s3::bucket::Bucket;
|
|||||||
use s3::creds::Credentials;
|
use s3::creds::Credentials;
|
||||||
use s3::region::Region;
|
use s3::region::Region;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
pub struct S3Host {
|
pub struct S3Host {
|
||||||
public_bucket: Bucket,
|
public_bucket: Bucket,
|
||||||
@ -46,16 +47,12 @@ impl S3Host {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.map_err(|_| {
|
.map_err(|e| {
|
||||||
FileHostingError::S3Error(
|
FileHostingError::S3Error("creating credentials", e.into())
|
||||||
"Error while creating credentials".to_string(),
|
|
||||||
)
|
|
||||||
})?,
|
})?,
|
||||||
)
|
)
|
||||||
.map_err(|_| {
|
.map_err(|e| {
|
||||||
FileHostingError::S3Error(
|
FileHostingError::S3Error("creating Bucket instance", e)
|
||||||
"Error while creating Bucket instance".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if bucket_uses_path_style {
|
if bucket_uses_path_style {
|
||||||
@ -100,11 +97,7 @@ impl FileHost for S3Host {
|
|||||||
content_type,
|
content_type,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|e| FileHostingError::S3Error("uploading file", e))?;
|
||||||
FileHostingError::S3Error(format!(
|
|
||||||
"Error while uploading file {file_name} to S3: {err}"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(UploadFileData {
|
Ok(UploadFileData {
|
||||||
file_name: file_name.to_string(),
|
file_name: file_name.to_string(),
|
||||||
@ -118,6 +111,25 @@ impl FileHost for S3Host {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_url_for_private_file(
|
||||||
|
&self,
|
||||||
|
file_name: &str,
|
||||||
|
expiry: Duration,
|
||||||
|
) -> Result<String, FileHostingError> {
|
||||||
|
let url = self
|
||||||
|
.private_bucket
|
||||||
|
.presign_get(
|
||||||
|
format!("/{file_name}"),
|
||||||
|
expiry.as_secs().try_into().unwrap(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
FileHostingError::S3Error("generating presigned URL", e)
|
||||||
|
})?;
|
||||||
|
Ok(url)
|
||||||
|
}
|
||||||
|
|
||||||
async fn delete_file(
|
async fn delete_file(
|
||||||
&self,
|
&self,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
@ -126,11 +138,7 @@ impl FileHost for S3Host {
|
|||||||
self.get_bucket(file_publicity)
|
self.get_bucket(file_publicity)
|
||||||
.delete_object(format!("/{file_name}"))
|
.delete_object(format!("/{file_name}"))
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|e| FileHostingError::S3Error("deleting file", e))?;
|
||||||
FileHostingError::S3Error(format!(
|
|
||||||
"Error while deleting file {file_name} to S3: {err}"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(DeleteFileData {
|
Ok(DeleteFileData {
|
||||||
file_name: file_name.to_string(),
|
file_name: file_name.to_string(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user