From 84a882392a7e768fb5f5484e7dbf1b45950cca14 Mon Sep 17 00:00:00 2001 From: asonix Date: Wed, 27 Mar 2024 16:57:22 -0500 Subject: [PATCH 1/4] Start threading upload configuration into ingest --- Cargo.lock | 3 +- Cargo.toml | 2 +- src/error.rs | 9 +- src/error_code.rs | 3 + src/ingest.rs | 19 ++-- src/{ => ingest}/validate.rs | 2 + src/{ => ingest}/validate/exiftool.rs | 0 src/{ => ingest}/validate/ffmpeg.rs | 0 src/{ => ingest}/validate/magick.rs | 0 src/lib.rs | 129 ++++++++++++++++++++------ src/queue.rs | 5 + src/queue/process.rs | 7 +- 12 files changed, 141 insertions(+), 38 deletions(-) rename src/{ => ingest}/validate.rs (99%) rename src/{ => ingest}/validate/exiftool.rs (100%) rename src/{ => ingest}/validate/ffmpeg.rs (100%) rename src/{ => ingest}/validate/magick.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 5704963..64896d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,8 +22,7 @@ dependencies = [ [[package]] name = "actix-form-data" version = "0.7.0-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0588d156cb871d8c237d55ce398e2a65727370fb98352ba5b65c15a2f834b0f" +source = "git+https://git.asonix.dog/asonix/actix-form-data#1c88a70021df9b8b394c2d9aee1265c5ef55d59b" dependencies = [ "actix-multipart", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index ca38916..70ccc5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ poll-timer-warnings = [] random-errors = ["dep:nanorand"] [dependencies] -actix-form-data = "0.7.0-beta.6" +actix-form-data = { version = "0.7.0-beta.6", git = "https://git.asonix.dog/asonix/actix-form-data" } actix-web = { version = "4.0.0", default-features = false, features = ["rustls-0_22"] } async-trait = "0.1.51" barrel = { version = "0.7.0", features = ["pg"] } diff --git a/src/error.rs b/src/error.rs index 5529499..b6cb1cc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -82,7 +82,7 @@ pub(crate) enum UploadError { Io(#[from] std::io::Error), #[error("Error validating upload")] - Validation(#[from] crate::validate::ValidationError), + Validation(#[from] crate::ingest::ValidationError), #[error("Error in store")] Store(#[source] crate::store::StoreError), @@ -111,6 +111,9 @@ pub(crate) enum UploadError { #[error("Invalid job popped from job queue: {1}")] InvalidJob(#[source] serde_json::Error, String), + #[error("Error parsing upload query")] + InvalidUploadQuery(#[source] actix_web::error::QueryPayloadError), + #[error("pict-rs is in read-only mode")] ReadOnly, @@ -209,6 +212,7 @@ impl UploadError { Self::ProcessTimeout => ErrorCode::COMMAND_TIMEOUT, Self::FailedExternalValidation => ErrorCode::FAILED_EXTERNAL_VALIDATION, Self::InvalidJob(_, _) => ErrorCode::INVALID_JOB, + Self::InvalidUploadQuery(_) => ErrorCode::INVALID_UPLOAD_QUERY, #[cfg(feature = "random-errors")] Self::RandomError => ErrorCode::RANDOM_ERROR, } @@ -248,7 +252,7 @@ impl ResponseError for Error { fn status_code(&self) -> StatusCode { match self.kind() { Some(UploadError::Upload(actix_form_data::Error::FileSize)) - | Some(UploadError::Validation(crate::validate::ValidationError::Filesize)) => { + | Some(UploadError::Validation(crate::ingest::ValidationError::Filesize)) => { StatusCode::PAYLOAD_TOO_LARGE } Some( @@ -261,6 +265,7 @@ impl ResponseError for Error { )) | UploadError::Repo(crate::repo::RepoError::AlreadyClaimed) | UploadError::Validation(_) + | UploadError::InvalidUploadQuery(_) | UploadError::UnsupportedProcessExtension | UploadError::ReadOnly | UploadError::FailedExternalValidation diff --git a/src/error_code.rs b/src/error_code.rs index 9e9b936..46a7652 100644 --- a/src/error_code.rs +++ b/src/error_code.rs @@ -147,6 +147,9 @@ impl ErrorCode { pub(crate) const INVALID_JOB: ErrorCode = ErrorCode { code: "invalid-job", }; + pub(crate) const INVALID_UPLOAD_QUERY: ErrorCode = ErrorCode { + code: "invalid-upload-query", + }; #[cfg(feature = "random-errors")] pub(crate) const RANDOM_ERROR: ErrorCode = ErrorCode { code: "random-error", diff --git a/src/ingest.rs b/src/ingest.rs index 3d5004b..983b1d8 100644 --- a/src/ingest.rs +++ b/src/ingest.rs @@ -1,3 +1,6 @@ +mod hasher; +mod validate; + use std::{cell::RefCell, rc::Rc, sync::Arc, time::Duration}; use crate::{ @@ -9,16 +12,17 @@ use crate::{ repo::{Alias, ArcRepo, DeleteToken, Hash}, state::State, store::Store, + UploadQuery, }; use actix_web::web::Bytes; use futures_core::Stream; use reqwest::Body; - use tracing::{Instrument, Span}; -mod hasher; use hasher::Hasher; +pub(crate) use validate::ValidationError; + #[derive(Debug)] pub(crate) struct Session { repo: ArcRepo, @@ -31,6 +35,7 @@ pub(crate) struct Session { async fn process_ingest( state: &State, stream: impl Stream>, + upload_query: &UploadQuery, ) -> Result< ( InternalFormat, @@ -54,9 +59,10 @@ where let permit = crate::process_semaphore().acquire().await?; tracing::trace!("Validating bytes"); - let (input_type, process_read) = crate::validate::validate_bytes_stream(state, bytes) - .with_poll_timer("validate-bytes-stream") - .await?; + let (input_type, process_read) = + validate::validate_bytes_stream(state, bytes, &upload_query.limits) + .with_poll_timer("validate-bytes-stream") + .await?; let process_read = if let Some(operations) = state.config.media.preprocess_steps() { if let Some(format) = input_type.processable_format() { @@ -159,6 +165,7 @@ pub(crate) async fn ingest( state: &State, stream: impl Stream>, declared_alias: Option, + upload_query: &UploadQuery, ) -> Result where S: Store, @@ -166,7 +173,7 @@ where let (input_type, identifier, details, hash_state) = if state.config.server.danger_dummy_mode { dummy_ingest(state, stream).await? } else { - process_ingest(state, stream) + process_ingest(state, stream, upload_query) .with_poll_timer("ingest-future") .await? }; diff --git a/src/validate.rs b/src/ingest/validate.rs similarity index 99% rename from src/validate.rs rename to src/ingest/validate.rs index 5460553..4d23bb2 100644 --- a/src/validate.rs +++ b/src/ingest/validate.rs @@ -14,6 +14,7 @@ use crate::{ future::WithPollTimer, process::{Process, ProcessRead}, state::State, + UploadLimits, }; #[derive(Debug, thiserror::Error)] @@ -60,6 +61,7 @@ const MEGABYTES: usize = 1024 * 1024; pub(crate) async fn validate_bytes_stream( state: &State, bytes: BytesStream, + upload_limits: &UploadLimits, ) -> Result<(InternalFormat, ProcessRead), Error> { if bytes.is_empty() { return Err(ValidationError::Empty.into()); diff --git a/src/validate/exiftool.rs b/src/ingest/validate/exiftool.rs similarity index 100% rename from src/validate/exiftool.rs rename to src/ingest/validate/exiftool.rs diff --git a/src/validate/ffmpeg.rs b/src/ingest/validate/ffmpeg.rs similarity index 100% rename from src/validate/ffmpeg.rs rename to src/ingest/validate/ffmpeg.rs diff --git a/src/validate/magick.rs b/src/ingest/validate/magick.rs similarity index 100% rename from src/validate/magick.rs rename to src/ingest/validate/magick.rs diff --git a/src/lib.rs b/src/lib.rs index 5395e56..eed4d54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,6 @@ mod stream; mod sync; mod tls; mod tmp_file; -mod validate; use actix_form_data::{Field, Form, FormData, Multipart, Value}; use actix_web::{ @@ -59,6 +58,7 @@ use std::{ marker::PhantomData, path::Path, path::PathBuf, + rc::Rc, sync::{Arc, OnceLock}, time::{Duration, SystemTime}, }; @@ -147,22 +147,64 @@ async fn ensure_details_identifier( } } +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(default)] +struct UploadLimits { + max_width: Option, + max_height: Option, + max_area: Option, + max_frame_count: Option, + max_file_size: Option, + allow_image: bool, + allow_animation: bool, + allow_video: bool, +} + +impl Default for UploadLimits { + fn default() -> Self { + Self { + max_width: None, + max_height: None, + max_area: None, + max_frame_count: None, + max_file_size: None, + allow_image: true, + allow_animation: true, + allow_video: true, + } + } +} + +#[derive(Clone, Default, Debug, serde::Deserialize, serde::Serialize)] +struct UploadQuery { + #[serde(flatten)] + limits: UploadLimits, + + #[serde(with = "tuple_vec_map", flatten)] + operations: Vec<(String, String)>, +} + struct Upload(Value, PhantomData); impl FormData for Upload { type Item = Session; type Error = Error; - fn form(req: &HttpRequest) -> Form { + fn form(req: &HttpRequest) -> Result, Self::Error> { let state = req .app_data::>>() .expect("No state in request") .clone(); + let web::Query(upload_query) = web::Query::::from_query(req.query_string()) + .map_err(UploadError::InvalidUploadQuery)?; + + let upload_query = Rc::new(upload_query); + // Create a new Multipart Form validator // // This form is expecting a single array field, 'images' with at most 10 files in it - Form::new() + Ok(Form::new() .max_files(state.config.server.max_file_count) .max_file_size(state.config.media.max_file_size * MEGABYTES) .transform_error(transform_error) @@ -170,6 +212,7 @@ impl FormData for Upload { "images", Field::array(Field::file(move |filename, _, stream| { let state = state.clone(); + let upload_query = upload_query.clone(); metrics::counter!(crate::init_metrics::FILES, "upload" => "inline") .increment(1); @@ -184,13 +227,13 @@ impl FormData for Upload { let stream = crate::stream::from_err(stream); - ingest::ingest(&state, stream, None).await + ingest::ingest(&state, stream, None, &upload_query).await } .with_poll_timer("file-upload") .instrument(span), ) })), - ) + )) } fn extract(value: Value) -> Result { @@ -204,16 +247,21 @@ impl FormData for Import { type Item = Session; type Error = Error; - fn form(req: &actix_web::HttpRequest) -> Form { + fn form(req: &actix_web::HttpRequest) -> Result, Self::Error> { let state = req .app_data::>>() .expect("No state in request") .clone(); + let web::Query(upload_query) = web::Query::::from_query(req.query_string()) + .map_err(UploadError::InvalidUploadQuery)?; + + let upload_query = Rc::new(upload_query); + // Create a new Multipart Form validator for internal imports // // This form is expecting a single array field, 'images' with at most 10 files in it - Form::new() + Ok(Form::new() .max_files(state.config.server.max_file_count) .max_file_size(state.config.media.max_file_size * MEGABYTES) .transform_error(transform_error) @@ -221,6 +269,7 @@ impl FormData for Import { "images", Field::array(Field::file(move |filename, _, stream| { let state = state.clone(); + let upload_query = upload_query.clone(); metrics::counter!(crate::init_metrics::FILES, "import" => "inline") .increment(1); @@ -235,14 +284,19 @@ impl FormData for Import { let stream = crate::stream::from_err(stream); - ingest::ingest(&state, stream, Some(Alias::from_existing(&filename))) - .await + ingest::ingest( + &state, + stream, + Some(Alias::from_existing(&filename)), + &upload_query, + ) + .await } .with_poll_timer("file-import") .instrument(span), ) })), - ) + )) } fn extract(value: Value) -> Result @@ -320,16 +374,16 @@ impl FormData for BackgroundedUpload { type Item = Backgrounded; type Error = Error; - fn form(req: &actix_web::HttpRequest) -> Form { - // Create a new Multipart Form validator for backgrounded uploads - // - // This form is expecting a single array field, 'images' with at most 10 files in it + fn form(req: &actix_web::HttpRequest) -> Result, Self::Error> { let state = req .app_data::>>() .expect("No state in request") .clone(); - Form::new() + // Create a new Multipart Form validator for backgrounded uploads + // + // This form is expecting a single array field, 'images' with at most 10 files in it + Ok(Form::new() .max_files(state.config.server.max_file_count) .max_file_size(state.config.media.max_file_size * MEGABYTES) .transform_error(transform_error) @@ -357,7 +411,7 @@ impl FormData for BackgroundedUpload { .instrument(span), ) })), - ) + )) } fn extract(value: Value) -> Result @@ -372,6 +426,7 @@ impl FormData for BackgroundedUpload { async fn upload_backgrounded( Multipart(BackgroundedUpload(value, _)): Multipart>, state: web::Data>, + web::Query(upload_query): web::Query, ) -> Result { let images = value .map() @@ -389,7 +444,14 @@ async fn upload_backgrounded( let upload_id = image.result.upload_id().expect("Upload ID exists"); let identifier = image.result.identifier().expect("Identifier exists"); - queue::queue_ingest(&state.repo, identifier, upload_id, None).await?; + queue::queue_ingest( + &state.repo, + identifier, + upload_id, + None, + upload_query.clone(), + ) + .await?; files.push(serde_json::json!({ "upload_id": upload_id.to_string(), @@ -462,11 +524,21 @@ struct UrlQuery { backgrounded: bool, } +#[derive(Debug, serde::Deserialize)] +struct DownloadQuery { + #[serde(flatten)] + url_query: UrlQuery, + + #[serde(flatten)] + upload_query: UploadQuery, +} + async fn ingest_inline( stream: impl Stream>, state: &State, + upload_query: &UploadQuery, ) -> Result<(Alias, DeleteToken, Details), Error> { - let session = ingest::ingest(state, stream, None).await?; + let session = ingest::ingest(state, stream, None, upload_query).await?; let alias = session.alias().expect("alias should exist").to_owned(); @@ -480,15 +552,18 @@ async fn ingest_inline( /// download an image from a URL #[tracing::instrument(name = "Downloading file", skip(state))] async fn download( - query: web::Query, + web::Query(DownloadQuery { + url_query, + upload_query, + }): web::Query, state: web::Data>, ) -> Result { - let stream = download_stream(&query.url, &state).await?; + let stream = download_stream(&url_query.url, &state).await?; - if query.backgrounded { - do_download_backgrounded(stream, state).await + if url_query.backgrounded { + do_download_backgrounded(stream, state, upload_query).await } else { - do_download_inline(stream, &state).await + do_download_inline(stream, &state, &upload_query).await } } @@ -518,10 +593,11 @@ async fn download_stream( async fn do_download_inline( stream: impl Stream>, state: &State, + upload_query: &UploadQuery, ) -> Result { metrics::counter!(crate::init_metrics::FILES, "download" => "inline").increment(1); - let (alias, delete_token, details) = ingest_inline(stream, state).await?; + let (alias, delete_token, details) = ingest_inline(stream, state, upload_query).await?; Ok(HttpResponse::Created().json(&serde_json::json!({ "msg": "ok", @@ -537,6 +613,7 @@ async fn do_download_inline( async fn do_download_backgrounded( stream: impl Stream>, state: web::Data>, + upload_query: UploadQuery, ) -> Result { metrics::counter!(crate::init_metrics::FILES, "download" => "background").increment(1); @@ -545,7 +622,7 @@ async fn do_download_backgrounded( let upload_id = backgrounded.upload_id().expect("Upload ID exists"); let identifier = backgrounded.identifier().expect("Identifier exists"); - queue::queue_ingest(&state.repo, identifier, upload_id, None).await?; + queue::queue_ingest(&state.repo, identifier, upload_id, None, upload_query).await?; backgrounded.disarm(); @@ -1212,7 +1289,7 @@ async fn proxy_alias_from_query( } else if !state.config.server.read_only { let stream = download_stream(proxy.as_str(), state).await?; - let (alias, _, _) = ingest_inline(stream, state).await?; + let (alias, _, _) = ingest_inline(stream, state, &Default::default()).await?; state.repo.relate_url(proxy, alias.clone()).await?; diff --git a/src/queue.rs b/src/queue.rs index 42da976..96cebf8 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -7,6 +7,7 @@ use crate::{ serde_str::Serde, state::State, store::Store, + UploadQuery, }; use std::{ @@ -56,6 +57,8 @@ enum Process { identifier: String, upload_id: Serde, declared_alias: Option>, + #[serde(default)] + upload_query: UploadQuery, }, Generate { target_format: InputProcessableFormat, @@ -158,11 +161,13 @@ pub(crate) async fn queue_ingest( identifier: &Arc, upload_id: UploadId, declared_alias: Option, + upload_query: UploadQuery, ) -> Result<(), Error> { let job = serde_json::to_value(Process::Ingest { identifier: identifier.to_string(), declared_alias: declared_alias.map(Serde::new), upload_id: Serde::new(upload_id), + upload_query, }) .map_err(UploadError::PushJob)?; repo.push(PROCESS_QUEUE, job, None).await?; diff --git a/src/queue/process.rs b/src/queue/process.rs index 653ca26..76ff626 100644 --- a/src/queue/process.rs +++ b/src/queue/process.rs @@ -12,6 +12,7 @@ use crate::{ serde_str::Serde, state::State, store::Store, + UploadQuery, }; use std::{path::PathBuf, sync::Arc}; @@ -37,12 +38,14 @@ where identifier, upload_id, declared_alias, + upload_query, } => { process_ingest( state, Arc::from(identifier), Serde::into_inner(upload_id), declared_alias.map(Serde::into_inner), + upload_query, ) .with_poll_timer("process-ingest") .await? @@ -110,6 +113,7 @@ async fn process_ingest( unprocessed_identifier: Arc, upload_id: UploadId, declared_alias: Option, + upload_query: UploadQuery, ) -> JobResult where S: Store + 'static, @@ -129,7 +133,8 @@ where let stream = crate::stream::from_err(state2.store.to_stream(&ident, None, None).await?); - let session = crate::ingest::ingest(&state2, stream, declared_alias).await?; + let session = + crate::ingest::ingest(&state2, stream, declared_alias, &upload_query).await?; Ok(session) as Result } From 55bc4b64c1d0533b39ad6add8a98b9eecb257c8f Mon Sep 17 00:00:00 2001 From: asonix Date: Wed, 27 Mar 2024 19:00:54 -0500 Subject: [PATCH 2/4] Add per-upload validations and per-upload preprocess steps --- Cargo.toml | 2 +- flake.nix | 2 ++ src/error.rs | 13 +++++--- src/error_code.rs | 10 +++++-- src/ingest.rs | 8 ++++- src/ingest/validate.rs | 67 +++++++++++++++++++++++++++++++++++++----- src/lib.rs | 52 ++++++++++++++++++++------------ src/serde_str.rs | 13 +++++++- 8 files changed, 133 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 70ccc5e..c08e1ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,8 +58,8 @@ rustls-channel-resolver = "0.2.0" rustls-pemfile = "2.0.0" rusty-s3 = "0.5.0" serde = { version = "1.0", features = ["derive"] } -serde-tuple-vec-map = "1.0.1" serde_json = "1.0" +serde-tuple-vec-map = "1.0.1" serde_urlencoded = "0.7.1" sha2 = "0.10.0" sled = { version = "0.34.7" } diff --git a/flake.nix b/flake.nix index 9224cf2..f475255 100644 --- a/flake.nix +++ b/flake.nix @@ -33,11 +33,13 @@ cargo-outdated certstrap clippy + curl diesel-cli exiftool ffmpeg_6-full garage imagemagick + jq minio-client rust-analyzer rustc diff --git a/src/error.rs b/src/error.rs index b6cb1cc..d5731c9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -111,8 +111,11 @@ pub(crate) enum UploadError { #[error("Invalid job popped from job queue: {1}")] InvalidJob(#[source] serde_json::Error, String), - #[error("Error parsing upload query")] - InvalidUploadQuery(#[source] actix_web::error::QueryPayloadError), + #[error("Invalid query supplied")] + InvalidQuery(#[source] actix_web::error::QueryPayloadError), + + #[error("Invalid json supplied")] + InvalidJson(#[source] actix_web::error::JsonPayloadError), #[error("pict-rs is in read-only mode")] ReadOnly, @@ -212,7 +215,8 @@ impl UploadError { Self::ProcessTimeout => ErrorCode::COMMAND_TIMEOUT, Self::FailedExternalValidation => ErrorCode::FAILED_EXTERNAL_VALIDATION, Self::InvalidJob(_, _) => ErrorCode::INVALID_JOB, - Self::InvalidUploadQuery(_) => ErrorCode::INVALID_UPLOAD_QUERY, + Self::InvalidQuery(_) => ErrorCode::INVALID_QUERY, + Self::InvalidJson(_) => ErrorCode::INVALID_JSON, #[cfg(feature = "random-errors")] Self::RandomError => ErrorCode::RANDOM_ERROR, } @@ -265,7 +269,8 @@ impl ResponseError for Error { )) | UploadError::Repo(crate::repo::RepoError::AlreadyClaimed) | UploadError::Validation(_) - | UploadError::InvalidUploadQuery(_) + | UploadError::InvalidQuery(_) + | UploadError::InvalidJson(_) | UploadError::UnsupportedProcessExtension | UploadError::ReadOnly | UploadError::FailedExternalValidation diff --git a/src/error_code.rs b/src/error_code.rs index 46a7652..5e3f2ef 100644 --- a/src/error_code.rs +++ b/src/error_code.rs @@ -100,6 +100,9 @@ impl ErrorCode { pub(crate) const VIDEO_DISABLED: ErrorCode = ErrorCode { code: "video-disabled", }; + pub(crate) const MEDIA_DISALLOWED: ErrorCode = ErrorCode { + code: "media-disallowed", + }; pub(crate) const HTTP_CLIENT_ERROR: ErrorCode = ErrorCode { code: "http-client-error", }; @@ -147,8 +150,11 @@ impl ErrorCode { pub(crate) const INVALID_JOB: ErrorCode = ErrorCode { code: "invalid-job", }; - pub(crate) const INVALID_UPLOAD_QUERY: ErrorCode = ErrorCode { - code: "invalid-upload-query", + pub(crate) const INVALID_QUERY: ErrorCode = ErrorCode { + code: "invalid-query", + }; + pub(crate) const INVALID_JSON: ErrorCode = ErrorCode { + code: "invalid-json", }; #[cfg(feature = "random-errors")] pub(crate) const RANDOM_ERROR: ErrorCode = ErrorCode { diff --git a/src/ingest.rs b/src/ingest.rs index 983b1d8..d8fb592 100644 --- a/src/ingest.rs +++ b/src/ingest.rs @@ -64,7 +64,13 @@ where .with_poll_timer("validate-bytes-stream") .await?; - let process_read = if let Some(operations) = state.config.media.preprocess_steps() { + let operations = if upload_query.operations.is_empty() { + state.config.media.preprocess_steps() + } else { + Some(upload_query.operations.as_ref()) + }; + + let process_read = if let Some(operations) = operations { if let Some(format) = input_type.processable_format() { let (_, magick_args) = crate::processor::build_chain(operations, format.file_extension())?; diff --git a/src/ingest/validate.rs b/src/ingest/validate.rs index 4d23bb2..10fc8d2 100644 --- a/src/ingest/validate.rs +++ b/src/ingest/validate.rs @@ -39,6 +39,9 @@ pub(crate) enum ValidationError { #[error("Video is disabled")] VideoDisabled, + + #[error("Media type wasn't allowed for this upload")] + MediaDisallowed, } impl ValidationError { @@ -51,6 +54,7 @@ impl ValidationError { Self::Empty => ErrorCode::VALIDATE_FILE_EMPTY, Self::Filesize => ErrorCode::VALIDATE_FILE_SIZE, Self::VideoDisabled => ErrorCode::VIDEO_DISABLED, + Self::MediaDisallowed => ErrorCode::MEDIA_DISALLOWED, } } } @@ -76,14 +80,16 @@ pub(crate) async fn validate_bytes_stream( .with_poll_timer("discover-bytes-stream") .await?; + validate_upload(bytes.len(), width, height, frames, upload_limits)?; + match &input { - InputFile::Image(input) => { + InputFile::Image(input) if *upload_limits.allow_image => { let (format, process) = process_image_command(state, *input, bytes.len(), width, height).await?; Ok((format, process.drive_with_stream(bytes.into_io_stream()))) } - InputFile::Animation(input) => { + InputFile::Animation(input) if *upload_limits.allow_animation => { let (format, process) = process_animation_command( state, *input, @@ -96,20 +102,67 @@ pub(crate) async fn validate_bytes_stream( Ok((format, process.drive_with_stream(bytes.into_io_stream()))) } - InputFile::Video(input) => { + InputFile::Video(input) if *upload_limits.allow_video => { let (format, process_read) = process_video(state, bytes, *input, width, height, frames.unwrap_or(1)).await?; Ok((format, process_read)) } + _ => Err(ValidationError::MediaDisallowed.into()), } } +fn validate_upload( + size: usize, + width: u16, + height: u16, + frames: Option, + upload_limits: &UploadLimits, +) -> Result<(), ValidationError> { + if upload_limits + .max_width + .is_some_and(|max_width| width > *max_width) + { + return Err(ValidationError::Width); + } + + if upload_limits + .max_height + .is_some_and(|max_height| height > *max_height) + { + return Err(ValidationError::Height); + } + + if upload_limits + .max_frame_count + .zip(frames) + .is_some_and(|(max_frame_count, frames)| frames > *max_frame_count) + { + return Err(ValidationError::Frames); + } + + if upload_limits + .max_area + .is_some_and(|max_area| u32::from(width) * u32::from(height) > *max_area) + { + return Err(ValidationError::Area); + } + + if upload_limits + .max_file_size + .is_some_and(|max_file_size| size > *max_file_size * MEGABYTES) + { + return Err(ValidationError::Filesize); + } + + Ok(()) +} + #[tracing::instrument(skip(state))] async fn process_image_command( state: &State, input: ImageInput, - length: usize, + size: usize, width: u16, height: u16, ) -> Result<(InternalFormat, Process), Error> { @@ -124,7 +177,7 @@ async fn process_image_command( if u32::from(width) * u32::from(height) > validations.max_area { return Err(ValidationError::Area.into()); } - if length > validations.max_file_size * MEGABYTES { + if size > validations.max_file_size * MEGABYTES { return Err(ValidationError::Filesize.into()); } @@ -174,14 +227,14 @@ fn validate_animation( async fn process_animation_command( state: &State, input: AnimationFormat, - length: usize, + size: usize, width: u16, height: u16, frames: u32, ) -> Result<(InternalFormat, Process), Error> { let validations = &state.config.media.animation; - validate_animation(length, width, height, frames, validations)?; + validate_animation(size, width, height, frames, validations)?; let AnimationOutput { format, diff --git a/src/lib.rs b/src/lib.rs index eed4d54..8120625 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,14 +150,14 @@ async fn ensure_details_identifier( #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(default)] struct UploadLimits { - max_width: Option, - max_height: Option, - max_area: Option, - max_frame_count: Option, - max_file_size: Option, - allow_image: bool, - allow_animation: bool, - allow_video: bool, + max_width: Option>, + max_height: Option>, + max_area: Option>, + max_frame_count: Option>, + max_file_size: Option>, + allow_image: Serde, + allow_animation: Serde, + allow_video: Serde, } impl Default for UploadLimits { @@ -168,9 +168,9 @@ impl Default for UploadLimits { max_area: None, max_frame_count: None, max_file_size: None, - allow_image: true, - allow_animation: true, - allow_video: true, + allow_image: Serde::new(true), + allow_animation: Serde::new(true), + allow_video: Serde::new(true), } } } @@ -197,7 +197,7 @@ impl FormData for Upload { .clone(); let web::Query(upload_query) = web::Query::::from_query(req.query_string()) - .map_err(UploadError::InvalidUploadQuery)?; + .map_err(UploadError::InvalidQuery)?; let upload_query = Rc::new(upload_query); @@ -254,7 +254,7 @@ impl FormData for Import { .clone(); let web::Query(upload_query) = web::Query::::from_query(req.query_string()) - .map_err(UploadError::InvalidUploadQuery)?; + .map_err(UploadError::InvalidQuery)?; let upload_query = Rc::new(upload_query); @@ -426,8 +426,10 @@ impl FormData for BackgroundedUpload { async fn upload_backgrounded( Multipart(BackgroundedUpload(value, _)): Multipart>, state: web::Data>, - web::Query(upload_query): web::Query, + upload_query: web::Query, ) -> Result { + let upload_query = upload_query.into_inner(); + let images = value .map() .and_then(|mut m| m.remove("images")) @@ -552,12 +554,14 @@ async fn ingest_inline( /// download an image from a URL #[tracing::instrument(name = "Downloading file", skip(state))] async fn download( - web::Query(DownloadQuery { - url_query, - upload_query, - }): web::Query, + download_query: web::Query, state: web::Data>, ) -> Result { + let DownloadQuery { + url_query, + upload_query, + } = download_query.into_inner(); + let stream = download_stream(&url_query.url, &state).await?; if url_query.backgrounded { @@ -1574,6 +1578,16 @@ fn build_client() -> Result { .build()) } +fn query_config() -> web::QueryConfig { + web::QueryConfig::default() + .error_handler(|err, _| Error::from(UploadError::InvalidQuery(err)).into()) +} + +fn json_config() -> web::JsonConfig { + web::JsonConfig::default() + .error_handler(|err, _| Error::from(UploadError::InvalidJson(err)).into()) +} + fn configure_endpoints( config: &mut web::ServiceConfig, state: State, @@ -1581,6 +1595,8 @@ fn configure_endpoints( extra_config: F, ) { config + .app_data(query_config()) + .app_data(json_config()) .app_data(web::Data::new(state.clone())) .app_data(web::Data::new(process_map.clone())) .route("/healthz", web::get().to(healthz::)) diff --git a/src/serde_str.rs b/src/serde_str.rs index 6b7962f..21e3344 100644 --- a/src/serde_str.rs +++ b/src/serde_str.rs @@ -3,7 +3,7 @@ use std::{ str::FromStr, }; -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct Serde { inner: T, } @@ -44,6 +44,17 @@ impl DerefMut for Serde { } } +impl Default for Serde +where + T: Default, +{ + fn default() -> Self { + Serde { + inner: T::default(), + } + } +} + impl FromStr for Serde where T: FromStr, From 4b46f1ae2aed57d9e49507c7f4cf990153d94f74 Mon Sep 17 00:00:00 2001 From: asonix Date: Wed, 27 Mar 2024 19:10:58 -0500 Subject: [PATCH 3/4] Use stable actix-form-data --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64896d4..daed9e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,8 +21,9 @@ dependencies = [ [[package]] name = "actix-form-data" -version = "0.7.0-beta.6" -source = "git+https://git.asonix.dog/asonix/actix-form-data#1c88a70021df9b8b394c2d9aee1265c5ef55d59b" +version = "0.7.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2355a841a5d9a6c616d6a4f31336064116d206e6c1830de22730f983613a05" dependencies = [ "actix-multipart", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index c08e1ad..4f7152c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ poll-timer-warnings = [] random-errors = ["dep:nanorand"] [dependencies] -actix-form-data = { version = "0.7.0-beta.6", git = "https://git.asonix.dog/asonix/actix-form-data" } +actix-form-data = "0.7.0-beta.7" actix-web = { version = "4.0.0", default-features = false, features = ["rustls-0_22"] } async-trait = "0.1.51" barrel = { version = "0.7.0", features = ["pg"] } From 3211ce459e34a41c5703f84b14b024a92ac3e9bd Mon Sep 17 00:00:00 2001 From: asonix Date: Wed, 27 Mar 2024 19:11:41 -0500 Subject: [PATCH 4/4] Update dependencies (minor & point) --- Cargo.lock | 238 +++++++++++++++++++++++++++-------------------------- 1 file changed, 122 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index daed9e5..4ed835b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "futures-core", "futures-sink", @@ -48,7 +48,7 @@ dependencies = [ "actix-utils", "ahash", "base64", - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "bytestring", "derive_more", @@ -232,9 +232,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -245,9 +245,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -317,9 +317,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "async-stream" @@ -340,18 +340,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -362,9 +362,9 @@ checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "axum" @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -475,9 +475,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ "serde", ] @@ -511,9 +511,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytestring" @@ -538,9 +538,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -550,9 +550,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.2" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -572,14 +572,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -590,9 +590,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "color-eyre" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "color-spantrace", @@ -802,11 +802,11 @@ dependencies = [ [[package]] name = "diesel" -version = "2.1.4" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62c6fcf842f17f8c78ecf7c81d75c5ce84436b41ee07e03f490fbb5f5a8731d8" +checksum = "03fc05c17098f21b89bc7d98fe1dd3cce2c11c2ad8e145f2a44fe08ed28eb559" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "diesel_derives", "itoa", @@ -836,22 +836,22 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81c5131a2895ef64741dad1d483f358c2a229a3a2d1b256778cdc5e146db64d4" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] name = "diesel_derives" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" +checksum = "5d02eecb814ae714ffe61ddc2db2dd03e6c49a42e269b5001355500d431cce0c" dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -860,7 +860,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -1019,7 +1019,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -1098,9 +1098,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -1108,7 +1108,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1149,6 +1149,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -1317,9 +1323,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1361,9 +1367,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1458,15 +1464,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "metrics" -version = "0.22.1" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd71d9db2e4287c3407fa04378b8c2ee570aebe0854431562cdd89ca091854f4" +checksum = "2be3cbd384d4e955b231c895ce10685e3d8260c5ccffae898c96c723b0772835" dependencies = [ "ahash", "portable-atomic", @@ -1480,7 +1486,7 @@ checksum = "9bf4e7146e30ad172c42c39b3246864bd2d3c6396780711a1baf749cfe423e21" dependencies = [ "base64", "hyper", - "indexmap 2.2.5", + "indexmap 2.2.6", "ipnet", "metrics", "metrics-util", @@ -1491,9 +1497,9 @@ dependencies = [ [[package]] name = "metrics-util" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece71ab046dcf45604e573329966ec1db5ff4b81cfa170a924ff4c959ab5451a" +checksum = "8b07a5eb561b8cbc16be2d216faf7757f9baf3bfb94dbb0fae3df8387a5bb47f" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1846,7 +1852,7 @@ dependencies = [ "reqwest", "reqwest-middleware", "reqwest-tracing", - "rustls 0.22.2", + "rustls 0.22.3", "rustls-channel-resolver", "rustls-pemfile 2.1.1", "rusty-s3", @@ -1894,7 +1900,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -1976,9 +1982,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -2003,7 +2009,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -2085,7 +2091,7 @@ version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", ] [[package]] @@ -2128,7 +2134,7 @@ dependencies = [ "postgres", "regex", "serde", - "siphasher 1.0.0", + "siphasher 1.0.1", "thiserror", "time", "tokio", @@ -2148,19 +2154,19 @@ dependencies = [ "quote", "refinery-core", "regex", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2180,7 +2186,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2191,15 +2197,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.25" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eea5a9eb898d3783f17c6407670e3592fd174cb81a10e51d4c37f49450b9946" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64", "bytes", @@ -2241,9 +2247,9 @@ dependencies = [ [[package]] name = "reqwest-middleware" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a3e86aa6053e59030e7ce2d2a3b258dd08fc2d337d52f73f6cb480f5858690" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" dependencies = [ "anyhow", "async-trait", @@ -2256,9 +2262,9 @@ dependencies = [ [[package]] name = "reqwest-tracing" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0152176687dd5cfe7f507ac1cb1a491c679cfe483afd133a7db7aaea818bb3" +checksum = "190838e54153d7a7e2ea98851304b3ce92daeabf14c54d32b01b84a3e636f683" dependencies = [ "anyhow", "async-trait", @@ -2301,7 +2307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64", - "bitflags 2.4.2", + "bitflags 2.5.0", "serde", "serde_derive", ] @@ -2335,9 +2341,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" dependencies = [ "log", "ring", @@ -2354,7 +2360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbd1941204442f051576a9a7ea8e8db074ad7fd43db1eb3378c3633f9f9e166" dependencies = [ "nanorand", - "rustls 0.22.2", + "rustls 0.22.3", ] [[package]] @@ -2378,9 +2384,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" [[package]] name = "rustls-webpki" @@ -2507,14 +2513,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -2608,9 +2614,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "siphasher" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ac45299ccbd390721be55b412d41931911f654fa99e2cb8bfb57184b2061fe" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "sketches-ddsketch" @@ -2646,9 +2652,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2735,9 +2741,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -2752,20 +2758,20 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "system-configuration" -version = "0.6.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags 2.4.2", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ "core-foundation-sys", "libc", @@ -2782,22 +2788,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -2894,7 +2900,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -2931,7 +2937,7 @@ checksum = "0ea13f22eda7127c827983bdaf0d7fff9df21c8817bab02815ac277a21143677" dependencies = [ "futures", "ring", - "rustls 0.22.2", + "rustls 0.22.3", "tokio", "tokio-postgres", "tokio-rustls 0.25.0", @@ -2954,16 +2960,16 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.22.2", + "rustls 0.22.3", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -3001,9 +3007,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.10" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", @@ -3022,11 +3028,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.6" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -3154,7 +3160,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -3311,9 +3317,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "atomic", "getrandom", @@ -3384,7 +3390,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -3418,7 +3424,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3724,7 +3730,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ] [[package]] @@ -3744,5 +3750,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.55", ]