Skip to content

Commit

Permalink
Add max_publish_size setting
Browse files Browse the repository at this point in the history
  • Loading branch information
Palladinium committed Jan 8, 2024
1 parent 2d6353d commit 3cc500f
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 16 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2021"
axum = { version = "0.7.2", features = ["json"] }
axum-extra = { version = "0.9.0", features = ["typed-routing", "typed-header"] }
base64 = "0.21.5"
bytesize = { version = "1.3.0", features = ["serde"] }
config = "0.13.4"
futures = "0.3.29"
getrandom = "0.2.11"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Quartermaster is still very early in development, and these are features which a
- User/owner endpoints: Currently, tokens are global, and all crates are owned by nobody. The various `owner` endpoints are not implemented.
- More varied and robust auth methods (e.g. OpenID). I have no need for them yet.
- Cross-platform support: While in theory nothing stops Quartermaster from running on other platforms like Windows, MacOS or BSDs, I have only tested it on x86_64 Linux and the default values for the configuration reflect this.
- CLI management utility: Instead of a Web UI, I'm planning to add a CLI utility to perform registry maintenance tasks which cannot be performed through the Cargo API (e.g. fully removing crates, managing auth)

## Installation

Expand Down
7 changes: 6 additions & 1 deletion examples/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ root_url = "https://foo.bar"

#bind = ["10.1.1.1:80"]

[crates]

### The maximum size of a crate publish payload allowed by this registry. Defaults to 100 MiB.
## Supports human-readable prefixes (KB, MB, KiB, etc.)
#max_publish_size = "100 MiB"

[auth]

Expand All @@ -34,7 +39,7 @@ type = "none"

#type = "auto_token"

## The file to store the token in. Optional, defaults to `/var/lib/quartermaster/token`.
## The file to store the token in. Defaults to `/var/lib/quartermaster/token`.

#token_file = "/crate-token"

Expand Down
13 changes: 13 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ use std::{
path::PathBuf,
};

use bytesize::ByteSize;
use config::FileFormat;
use serde::Deserialize;

#[derive(Clone, Debug, Deserialize)]
pub struct Config {
pub server: Server,
pub crates: Crates,
pub auth: Auth,
pub storage: Storage,
}
Expand All @@ -33,6 +35,17 @@ fn default_bind() -> Vec<SocketAddr> {
]
}

#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Crates {
#[serde(default = "default_max_publish_size")]
pub max_publish_size: ByteSize,
}

fn default_max_publish_size() -> ByteSize {
ByteSize::mib(100)
}

#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum Auth {
Expand Down
30 changes: 15 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,6 @@ async fn get_download_crate(
Ok(body)
}

// TODO: Make configurable?
const MAX_BODY_SIZE: usize = 100 * 1024 * 1024;

#[derive(Deserialize)]
#[allow(dead_code)]
struct PublishRequest {
Expand Down Expand Up @@ -302,21 +299,24 @@ async fn put_publish_crate(
return Err(ErrorResponse::from_status(StatusCode::LENGTH_REQUIRED));
};

if body_size > u64::try_from(MAX_BODY_SIZE).unwrap() {
if body_size > state.config.crates.max_publish_size.as_u64() {
return Err(ErrorResponse::from_status(StatusCode::PAYLOAD_TOO_LARGE));
}

let body_data = Limited::new(body, MAX_BODY_SIZE)
.collect()
.await
.map_err(|e| {
if e.is::<LengthLimitError>() {
ErrorResponse::from_status(StatusCode::PAYLOAD_TOO_LARGE)
} else {
ErrorResponse::from_status(StatusCode::INTERNAL_SERVER_ERROR)
}
})?
.to_bytes();
let body_data = Limited::new(
body,
usize::try_from(state.config.crates.max_publish_size.as_u64()).unwrap(),
)
.collect()
.await
.map_err(|e| {
if e.is::<LengthLimitError>() {
ErrorResponse::from_status(StatusCode::PAYLOAD_TOO_LARGE)
} else {
ErrorResponse::from_status(StatusCode::INTERNAL_SERVER_ERROR)
}
})?
.to_bytes();

let json_length_bytes = body_data
.get(0..4)
Expand Down

0 comments on commit 3cc500f

Please sign in to comment.