diff --git a/Cargo.toml b/Cargo.toml index bebcc17..8735be7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = ["sdk", "api", "cli"] authors = ["Mahdi "] description = "A file upload/download service" documentation = "" -edition = "2021" +edition = "2024" homepage = "https://github.com/robatipoor/pf" keywords = ["paste", "file", "transfer"] license = "MIT" @@ -22,16 +22,16 @@ opt-level = "z" strip = true [workspace.dependencies] -anyhow = "1.0.81" +anyhow = "1.0.97" argon2 = "0.5.3" -assert_cmd = "2.0.14" -async-stream = "0.3.5" -axum = { version = "0.7.5", features = ["multipart"] } -axum-extra = { version = "0.9.3", features = ["async-read-body"] } +assert_cmd = "2.0.16" +async-stream = "0.3.6" +axum = { version = "0.8.1", features = ["multipart"] } +axum-extra = { version = "0.10.0", features = ["async-read-body"] } hyper = { version = "1.2.0", features = ["full"] } hyper-util = { version = "0.1.3" } -rustls-pemfile = "2.1.1" -tokio = { version = "1.36.0", features = [ +rustls-pemfile = "2.2.0" +tokio = { version = "1.43.0", features = [ "macros", "time", "process", @@ -39,42 +39,42 @@ tokio = { version = "1.36.0", features = [ "rt-multi-thread", "io-std", ] } -tokio-util = { version = "0.7.10", features = ["io"] } -tokio-rustls = "0.26.0" -tower = { version = "0.4.13", features = ["util", "make"] } -tower-http = { version = "0.5.2", features = ["fs", "cors"] } +tokio-util = { version = "0.7.13", features = ["io"] } +tokio-rustls = "0.26.2" +tower = { version = "0.5.2", features = ["util", "make"] } +tower-http = { version = "0.6.2", features = ["fs", "cors"] } tower-service = "0.3.2" -base64 = "0.22.0" +base64 = "0.22.1" bincode = "1.3.3" build_html = "2.4.0" -chrono = { version = "0.4.37", features = ["serde"] } -clap = { version = "4.5.4", features = ["derive"] } -config = { version = "0.14.0", default-features = false, features = ["toml"] } +chrono = { version = "0.4.40", features = ["serde"] } +clap = { version = "4.5.31", features = ["derive"] } +config = { version = "0.15.9", default-features = false, features = ["toml"] } chacha20poly1305 = { version = "0.10.1", features = ["stream"] } -cuid2 = "0.1.2" -fake = { version = "2.9.2", features = ['derive', 'uuid', 'chrono'] } -futures-util = "0.3.30" -indicatif = { version = "0.17.8", features = ["tokio"] } -log = "0.4.21" -mime_guess = "2.0.4" -once_cell = { version = "1.19.0" } -qrcode = "0.14.0" -image = "0.25.0" -rand = "0.8.5" -reqwest = { version = "0.12.2", default-features = false, features = [ +cuid2 = "0.1.4" +fake = { version = "4.0.0", features = ["derive", "chrono"] } +futures-util = "0.3.31" +indicatif = { version = "0.17.11", features = ["tokio"] } +log = "0.4.26" +mime_guess = "2.0.5" +once_cell = { version = "1.20.3" } +qrcode = "0.14.1" +image = "0.25.5" +rand = "0.9.0" +reqwest = { version = "0.12.12", default-features = false, features = [ "json", "multipart", "stream", "rustls-tls", ] } -serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.115" +serde = { version = "1.0.218", features = ["derive"] } +serde_json = "1.0.140" sled = "0.34.7" -strum = { version = "0.26.2", features = ["derive"] } -test-context = "0.3.0" -thiserror = "1.0.58" -tracing = "0.1.40" -tracing-subscriber = "0.3.18" -url = "2.5.0" -garde = { version = "0.18.0", features = ["full"] } +strum = { version = "0.27.1", features = ["derive"] } +test-context = "0.4.1" +thiserror = "2.0.12" +tracing = "0.1.41" +tracing-subscriber = "0.3.19" +url = "2.5.4" +garde = { version = "0.22.0", features = ["full"] } askama = "0.12.1" diff --git a/api/Cargo.toml b/api/Cargo.toml index 7fbc0a6..426050b 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pf-api" version = "0.1.0" -edition = "2021" +edition = "2024" [[bin]] name = "pf-api" diff --git a/api/src/bin/main.rs b/api/src/bin/main.rs index 89e82d2..1948e7c 100644 --- a/api/src/bin/main.rs +++ b/api/src/bin/main.rs @@ -5,7 +5,7 @@ use pf_api::{ configure::env::get_env_source, constant::ENV_PREFIX, error::result::ApiResult, - server::{worker::GarbageCollectorTask, ApiServer}, + server::{ApiServer, worker::GarbageCollectorTask}, util::{self, tracing::INIT_SUBSCRIBER}, }; diff --git a/api/src/configure/mod.rs b/api/src/configure/mod.rs index 384ea3f..92b489d 100644 --- a/api/src/configure/mod.rs +++ b/api/src/configure/mod.rs @@ -1,6 +1,6 @@ use crate::{ constant::ENV_PREFIX, - error::{result::ApiResult, ApiError}, + error::{ApiError, result::ApiResult}, }; use config::Environment; use once_cell::sync::Lazy; diff --git a/api/src/database/file_path.rs b/api/src/database/file_path.rs index 50b8940..cb1a323 100644 --- a/api/src/database/file_path.rs +++ b/api/src/database/file_path.rs @@ -1,4 +1,4 @@ -use crate::error::{result::ApiResult, ApiError}; +use crate::error::{ApiError, result::ApiResult}; use pf_sdk::dto::FileUrlPath; use serde::{Deserialize, Serialize}; use sled::IVec; diff --git a/api/src/database/meta_data_file.rs b/api/src/database/meta_data_file.rs index a86ad17..ce480d8 100644 --- a/api/src/database/meta_data_file.rs +++ b/api/src/database/meta_data_file.rs @@ -1,5 +1,5 @@ use crate::{ - error::{result::ApiResult, ApiError}, + error::{ApiError, result::ApiResult}, util::secret::SecretHash, }; use chrono::{DateTime, Utc}; diff --git a/api/src/database/mod.rs b/api/src/database/mod.rs index 4a69bb2..c74814f 100644 --- a/api/src/database/mod.rs +++ b/api/src/database/mod.rs @@ -1,6 +1,6 @@ use crate::{ configure::DatabaseConfig, - error::{result::ApiResult, ApiError}, + error::{ApiError, result::ApiResult}, util::path::get_fs_path, }; use chrono::{DateTime, Utc}; @@ -99,7 +99,7 @@ impl Database { let is_gc_notify = guard .iter() .next() - .map_or(true, |(first_expire, _)| *first_expire > expire_date_time); + .is_none_or(|(first_expire, _)| *first_expire > expire_date_time); guard.insert(expire.clone()); drop(guard); if is_gc_notify { diff --git a/api/src/error/response.rs b/api/src/error/response.rs index e17f338..2861faf 100644 --- a/api/src/error/response.rs +++ b/api/src/error/response.rs @@ -1,6 +1,6 @@ use axum::{ - response::{IntoResponse, Response}, Json, + response::{IntoResponse, Response}, }; use super::ApiError; diff --git a/api/src/handler/file.rs b/api/src/handler/file.rs index 09ce7e2..620b9f1 100644 --- a/api/src/handler/file.rs +++ b/api/src/handler/file.rs @@ -1,10 +1,10 @@ use anyhow::anyhow; use axum::{ + Json, body::Body, extract::{Multipart, Path, Query, State}, - http::{header::HeaderMap, Request}, + http::{Request, header::HeaderMap}, response::Response, - Json, }; use garde::Validate; use pf_sdk::{ @@ -25,7 +25,7 @@ pub async fn upload( headers: HeaderMap, multipart: Multipart, ) -> ApiResult> { - param.validate(&())?; + param.validate()?; let secret = crate::util::http::parse_basic_auth(&headers)?; let (file_path, expire_date_time) = service::file::store(&state, ¶m, secret, multipart).await?; diff --git a/api/src/router/mod.rs b/api/src/router/mod.rs index 5b213bf..2197f6f 100644 --- a/api/src/router/mod.rs +++ b/api/src/router/mod.rs @@ -1,8 +1,8 @@ use crate::{configure::cors::cors_layer, error::result::ApiResult, handler, server::ApiState}; use axum::{ + Router, extract::DefaultBodyLimit, routing::{delete, get, post}, - Router, }; pub fn get_router(state: ApiState) -> ApiResult { @@ -11,9 +11,9 @@ pub fn get_router(state: ApiState) -> ApiResult { .route("/upload", post(handler::file::upload)) .layer(DefaultBodyLimit::disable()) .route("/healthz", get(handler::health_check)) - .route("/info/:code/:file_name", get(handler::file::info)) - .route("/:code/:file_name", get(handler::file::download)) - .route("/:code/:file_name", delete(handler::file::delete)) + .route("/info/{code}/{file_name}", get(handler::file::info)) + .route("/{code}/{file_name}", get(handler::file::download)) + .route("/{code}/{file_name}", delete(handler::file::delete)) .route("/", get(handler::index::page)) .layer(cors_layer(&state.config.server)?) .with_state(state), diff --git a/api/src/server/axum_tls.rs b/api/src/server/axum_tls.rs index 41112ec..dccbe84 100644 --- a/api/src/server/axum_tls.rs +++ b/api/src/server/axum_tls.rs @@ -3,12 +3,12 @@ use std::sync::Arc; use axum::Router; use futures_util::pin_mut; -use hyper::body::Incoming; use hyper::Request; +use hyper::body::Incoming; use hyper_util::rt::{TokioExecutor, TokioIo}; use tokio::net::TcpListener; -use tokio_rustls::rustls::ServerConfig; use tokio_rustls::TlsAcceptor; +use tokio_rustls::rustls::ServerConfig; use tower_service::Service; // Async function to serve incoming connections over TLS diff --git a/api/src/service/file.rs b/api/src/service/file.rs index 774d6a6..2822542 100644 --- a/api/src/service/file.rs +++ b/api/src/service/file.rs @@ -3,14 +3,14 @@ use crate::database::file_path::FilePath; use crate::database::meta_data_file::MetaDataFile; use crate::error::invalid_input_error; use crate::error::{ - result::{ApiResult, ToApiResult}, ApiError, + result::{ApiResult, ToApiResult}, }; use crate::util::path::get_fs_path; use crate::util::secret::{Secret, SecretHash}; use anyhow::anyhow; -use axum::extract::multipart::Field; use axum::extract::Multipart; +use axum::extract::multipart::Field; use chrono::{DateTime, Utc}; use futures_util::TryStreamExt; use pf_sdk::dto::request::UploadQueryParam; diff --git a/api/src/util/hash.rs b/api/src/util/hash.rs index a9049ae..41d4a02 100644 --- a/api/src/util/hash.rs +++ b/api/src/util/hash.rs @@ -1,6 +1,6 @@ use argon2::{ - password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, Argon2, + password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng}, }; pub fn argon_hash(content: impl AsRef) -> Result { diff --git a/api/src/util/multipart.rs b/api/src/util/multipart.rs index e55cd8d..a54da4f 100644 --- a/api/src/util/multipart.rs +++ b/api/src/util/multipart.rs @@ -5,7 +5,9 @@ use axum::{ use hyper::header::CONTENT_TYPE; pub async fn create_multipart_request(file_name: &str, data: &str) -> anyhow::Result { - let data = format!("--X-BOUNDARY\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{file_name}\"\r\n\r\n{data}\r\n--X-BOUNDARY--\r\n"); + let data = format!( + "--X-BOUNDARY\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{file_name}\"\r\n\r\n{data}\r\n--X-BOUNDARY--\r\n" + ); let body = Body::from(Bytes::from(data)); let request = Request::builder() .header(CONTENT_TYPE, "multipart/form-data; boundary=X-BOUNDARY") diff --git a/api/src/util/secret.rs b/api/src/util/secret.rs index ee8fd3c..e293528 100644 --- a/api/src/util/secret.rs +++ b/api/src/util/secret.rs @@ -1,4 +1,4 @@ -use crate::error::{result::ApiResult, ApiError}; +use crate::error::{ApiError, result::ApiResult}; #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Secret(String); diff --git a/api/src/util/task.rs b/api/src/util/task.rs index cd04acc..b2d2f40 100644 --- a/api/src/util/task.rs +++ b/api/src/util/task.rs @@ -1,6 +1,6 @@ use tracing::error; -use crate::error::{result::ApiResult, ApiError}; +use crate::error::{ApiError, result::ApiResult}; /// If a task is fail fast after encounter an error node goes down. pub type IsFailFast = bool; diff --git a/api/src/util/test.rs b/api/src/util/test.rs index 69431d8..32aaf15 100644 --- a/api/src/util/test.rs +++ b/api/src/util/test.rs @@ -3,8 +3,8 @@ use std::path::PathBuf; use std::{collections::HashMap, hash::Hash}; use crate::error::result::ApiResult; -use crate::server::worker::GarbageCollectorTask; use crate::server::ApiState; +use crate::server::worker::GarbageCollectorTask; use crate::{configure::CONFIG, util::tracing::INIT_SUBSCRIBER}; use once_cell::sync::Lazy; use test_context::AsyncTestContext; diff --git a/api/tests/api/delete_api_test.rs b/api/tests/api/delete_api_test.rs index 383ad77..03f932d 100644 --- a/api/tests/api/delete_api_test.rs +++ b/api/tests/api/delete_api_test.rs @@ -1,7 +1,7 @@ use crate::helper::ApiTestContext; use crate::{assert_response_err, assert_response_ok}; use fake::{Fake, Faker}; -use pf_sdk::dto::{response::BodyResponseError, FileUrlPath}; +use pf_sdk::dto::{FileUrlPath, response::BodyResponseError}; use test_context::test_context; #[test_context(ApiTestContext)] diff --git a/api/tests/api/helper/mod.rs b/api/tests/api/helper/mod.rs index 805f768..f459315 100644 --- a/api/tests/api/helper/mod.rs +++ b/api/tests/api/helper/mod.rs @@ -10,8 +10,8 @@ use pf_api::server::worker::GarbageCollectorTask; use pf_api::server::{ApiServer, ApiState}; use pf_api::util::tracing::INIT_SUBSCRIBER; use pf_sdk::client::PasteFileClient; -use pf_sdk::dto::request::{QrCodeFormat, UploadQueryParam}; use pf_sdk::dto::FileUrlPath; +use pf_sdk::dto::request::{QrCodeFormat, UploadQueryParam}; use test_context::AsyncTestContext; pub mod assert; @@ -104,6 +104,7 @@ impl ApiTestContext { } } +#[allow(dead_code)] #[derive(Clone)] pub struct DummyFile { pub content: Vec, diff --git a/api/tests/api/info_api_test.rs b/api/tests/api/info_api_test.rs index beb7545..9a53780 100644 --- a/api/tests/api/info_api_test.rs +++ b/api/tests/api/info_api_test.rs @@ -1,7 +1,7 @@ use crate::helper::ApiTestContext; use crate::{assert_response_err, unwrap}; use fake::{Fake, Faker}; -use pf_sdk::dto::{response::BodyResponseError, FileUrlPath}; +use pf_sdk::dto::{FileUrlPath, response::BodyResponseError}; use test_context::test_context; #[test_context(ApiTestContext)] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2f399ef..589cb89 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pf-cli" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] pf-sdk = { path = "../sdk" } diff --git a/cli/src/args.rs b/cli/src/args.rs index 2ddceb2..e5be2e9 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -8,8 +8,8 @@ use crate::parse::{ parse_key_nonce, parse_source_file, }; -const HELP_ENCRYPT :&str = "The encrypt format should be `key:nonce`, with the key being 32 characters in length and the nonce being 19 characters."; -const HELP_DECRYPT :&str = "The decrypt format should be `key:nonce`, with the key being 32 characters in length and the nonce being 19 characters."; +const HELP_ENCRYPT: &str = "The encrypt format should be `key:nonce`, with the key being 32 characters in length and the nonce being 19 characters."; +const HELP_DECRYPT: &str = "The decrypt format should be `key:nonce`, with the key being 32 characters in length and the nonce being 19 characters."; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] diff --git a/cli/src/client.rs b/cli/src/client.rs index 5953b4c..c4fc3d9 100644 --- a/cli/src/client.rs +++ b/cli/src/client.rs @@ -6,9 +6,9 @@ use std::{ use pf_sdk::{ client::PasteFileClient, dto::{ + FileUrlPath, request::UploadQueryParam, response::{ApiResponseResult, BodyResponseError, UploadResponse}, - FileUrlPath, }, }; diff --git a/cli/src/command.rs b/cli/src/command.rs index c3e8de9..eebef1c 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -1,8 +1,8 @@ use pf_sdk::{ dto::{ + FileUrlPath, request::UploadQueryParam, response::{ApiResponseResult, BodyResponseError, UploadResponse}, - FileUrlPath, }, util::{ crypto::KeyNonce, diff --git a/cli/src/util/crypto.rs b/cli/src/util/crypto.rs index 77d187b..e5b0020 100644 --- a/cli/src/util/crypto.rs +++ b/cli/src/util/crypto.rs @@ -1,6 +1,6 @@ use super::progress::progress_bar; use pf_sdk::util::{ - crypto::{decrypt, decrypt_file, encrypt, encrypt_file, KeyNonce}, + crypto::{KeyNonce, decrypt, decrypt_file, encrypt, encrypt_file}, file::{add_extension, add_parent_dir, rm_extra_extension}, random::generate_random_string_with_prefix, }; diff --git a/cli/tests/cli/copy_and_paste_cli_test.rs b/cli/tests/cli/copy_and_paste_cli_test.rs index b8c2ae3..947f5a1 100644 --- a/cli/tests/cli/copy_and_paste_cli_test.rs +++ b/cli/tests/cli/copy_and_paste_cli_test.rs @@ -1,6 +1,6 @@ use assert_cmd::Command; -use crate::helper::{generate_random_key_nonce, CliTestContext}; +use crate::helper::{CliTestContext, generate_random_key_nonce}; #[test_context::test_context(CliTestContext)] #[tokio::test] diff --git a/cli/tests/cli/encrypt_and_decrypt_cli_test.rs b/cli/tests/cli/encrypt_and_decrypt_cli_test.rs index db75b58..aa9b0e8 100644 --- a/cli/tests/cli/encrypt_and_decrypt_cli_test.rs +++ b/cli/tests/cli/encrypt_and_decrypt_cli_test.rs @@ -1,4 +1,4 @@ -use crate::helper::{generate_random_key_nonce, CliTestContext}; +use crate::helper::{CliTestContext, generate_random_key_nonce}; use assert_cmd::Command; #[test_context::test_context(CliTestContext)] diff --git a/cli/tests/cli/helper/mod.rs b/cli/tests/cli/helper/mod.rs index 53e7ed6..89d1d8a 100644 --- a/cli/tests/cli/helper/mod.rs +++ b/cli/tests/cli/helper/mod.rs @@ -19,7 +19,7 @@ static SETUP: Lazy<()> = Lazy::new(|| { std::process::Command::new("cargo") .arg("build") .arg("-q") - .current_dir(&get_cargo_project_root().unwrap().unwrap()) + .current_dir(get_cargo_project_root().unwrap().unwrap()) .stdout(Stdio::piped()) .spawn() .unwrap() diff --git a/cli/tests/cli/upload_and_download_cli_test.rs b/cli/tests/cli/upload_and_download_cli_test.rs index aa8dcb7..be6e00c 100644 --- a/cli/tests/cli/upload_and_download_cli_test.rs +++ b/cli/tests/cli/upload_and_download_cli_test.rs @@ -1,7 +1,7 @@ use assert_cmd::Command; use pf_sdk::util::file::add_extension; -use crate::helper::{generate_random_key_nonce, CliTestContext}; +use crate::helper::{CliTestContext, generate_random_key_nonce}; #[test_context::test_context(CliTestContext)] #[tokio::test] diff --git a/rustfmt.toml b/rustfmt.toml index a4248b3..549ec94 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,3 @@ -edition = "2021" +edition = "2024" tab_spaces = 2 reorder_imports = true diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 71341c3..5e836eb 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pf-sdk" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] tokio = { workspace = true } diff --git a/sdk/src/client.rs b/sdk/src/client.rs index 452a69c..5f278eb 100644 --- a/sdk/src/client.rs +++ b/sdk/src/client.rs @@ -5,16 +5,16 @@ use std::{ use crate::{ dto::{ + FileUrlPath, request::UploadQueryParam, response::{ApiResponseResult, BodyResponseError, MetaDataFileResponse, UploadResponse}, - FileUrlPath, }, - util::crypto::{KeyNonce, DECRYPT_BUFFER_LEN, ENCRYPT_BUFFER_LEN}, + util::crypto::{DECRYPT_BUFFER_LEN, ENCRYPT_BUFFER_LEN, KeyNonce}, }; use anyhow::anyhow; use chacha20poly1305::{ - aead::stream::{DecryptorBE32, EncryptorBE32}, KeyInit, XChaCha20Poly1305, + aead::stream::{DecryptorBE32, EncryptorBE32}, }; use futures_util::{StreamExt, TryStreamExt}; diff --git a/sdk/src/util/crypto.rs b/sdk/src/util/crypto.rs index c3c8eac..091529e 100644 --- a/sdk/src/util/crypto.rs +++ b/sdk/src/util/crypto.rs @@ -1,12 +1,12 @@ use anyhow::anyhow; use chacha20poly1305::{ + XChaCha20Poly1305, aead::{ + KeyInit, generic_array::GenericArray, stream::{DecryptorBE32, EncryptorBE32}, - KeyInit, }, consts::U32, - XChaCha20Poly1305, }; use std::path::Path; diff --git a/sdk/src/util/qr_code.rs b/sdk/src/util/qr_code.rs index be90ba1..6591be8 100644 --- a/sdk/src/util/qr_code.rs +++ b/sdk/src/util/qr_code.rs @@ -1,6 +1,6 @@ use std::io::Cursor; -use base64::{engine::general_purpose::STANDARD, Engine}; +use base64::{Engine, engine::general_purpose::STANDARD}; use image::{ImageFormat, Luma}; use qrcode::QrCode; diff --git a/sdk/src/util/random.rs b/sdk/src/util/random.rs index 9cc5969..564c85d 100644 --- a/sdk/src/util/random.rs +++ b/sdk/src/util/random.rs @@ -1,7 +1,7 @@ -use rand::{distributions::Alphanumeric, Rng}; +use rand::{Rng, distr::Alphanumeric}; pub fn generate_random_string(len: usize) -> String { - rand::thread_rng() + rand::rng() .sample_iter(&Alphanumeric) .take(len) .map(char::from)