mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat(registry): ✨ add ratelimits
This commit is contained in:
parent
d6dcad739f
commit
21d841fcee
7 changed files with 173 additions and 3234 deletions
116
Cargo.lock
generated
116
Cargo.lock
generated
|
@ -34,6 +34,18 @@ dependencies = [
|
|||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-governor"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2e7b88f3804e01bd4191fdb08650430bbfcb43d3d9b2890064df3551ec7d25b"
|
||||
dependencies = [
|
||||
"actix-http",
|
||||
"actix-web",
|
||||
"futures",
|
||||
"governor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-http"
|
||||
version = "3.6.0"
|
||||
|
@ -1116,6 +1128,19 @@ dependencies = [
|
|||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown 0.14.3",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.5.0"
|
||||
|
@ -1541,6 +1566,21 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
|
@ -1548,6 +1588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1624,12 +1665,19 @@ version = "0.3.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
|
@ -1732,6 +1780,26 @@ dependencies = [
|
|||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "governor"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dashmap",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"no-std-compat",
|
||||
"nonzero_ext",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
"quanta",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"spinning_top",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.24"
|
||||
|
@ -2628,6 +2696,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no-std-compat"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
|
@ -2638,6 +2712,12 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nonzero_ext"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
@ -2973,9 +3053,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pesde-registry"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"actix-cors",
|
||||
"actix-governor",
|
||||
"actix-multipart",
|
||||
"actix-multipart-derive",
|
||||
"actix-web",
|
||||
|
@ -3174,6 +3255,21 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quanta"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ca0b7bac0b97248c40bb77288fc52029cf1459c0461ea1b05ee32ccf011de2c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"raw-cpuid",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.30.0"
|
||||
|
@ -3242,6 +3338,15 @@ dependencies = [
|
|||
"getrandom 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "11.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.9.0"
|
||||
|
@ -4146,6 +4251,15 @@ version = "0.9.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
|
3201
registry/Cargo.lock
generated
3201
registry/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pesde-registry"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -9,6 +9,7 @@ actix-cors = "0.7.0"
|
|||
actix-web-httpauth = "0.8.1"
|
||||
actix-multipart = "0.6.1"
|
||||
actix-multipart-derive = "0.6.1"
|
||||
actix-governor = "0.5.0"
|
||||
dotenvy = "0.15.7"
|
||||
reqwest = { version = "0.11.24", features = ["json", "blocking"] }
|
||||
rusty-s3 = "0.5.0"
|
||||
|
|
|
@ -1,8 +1,2 @@
|
|||
use actix_web::web;
|
||||
|
||||
pub mod packages;
|
||||
pub mod search;
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.configure(packages::configure);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use actix_multipart::form::{bytes::Bytes, MultipartForm};
|
||||
use actix_web::{get, post, web, HttpResponse, Responder};
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use flate2::read::GzDecoder;
|
||||
use reqwest::StatusCode;
|
||||
use rusty_s3::S3Action;
|
||||
|
@ -14,13 +14,12 @@ use pesde::{
|
|||
use crate::{commit_signature, errors, AppState, UserId, S3_EXPIRY};
|
||||
|
||||
#[derive(MultipartForm)]
|
||||
struct CreateForm {
|
||||
pub struct CreateForm {
|
||||
#[multipart(limit = "4 MiB")]
|
||||
tarball: Bytes,
|
||||
}
|
||||
|
||||
#[post("/packages")]
|
||||
async fn create(
|
||||
pub async fn create_package(
|
||||
form: MultipartForm<CreateForm>,
|
||||
app_state: web::Data<AppState>,
|
||||
user_id: web::ReqData<UserId>,
|
||||
|
@ -156,8 +155,7 @@ async fn create(
|
|||
)))
|
||||
}
|
||||
|
||||
#[get("/packages/{author_name}/{package_name}/{version}")]
|
||||
async fn get(
|
||||
pub async fn get_package_version(
|
||||
app_state: web::Data<AppState>,
|
||||
path: web::Path<(String, String, String)>,
|
||||
) -> Result<impl Responder, errors::Errors> {
|
||||
|
@ -202,7 +200,3 @@ async fn get(
|
|||
|
||||
Ok(HttpResponse::Ok().body(response.bytes().await?))
|
||||
}
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(create).service(get);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
use actix_web::{get, web, Responder};
|
||||
use actix_web::{web, Responder};
|
||||
use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{errors, AppState};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Query {
|
||||
pub struct Query {
|
||||
query: String,
|
||||
}
|
||||
|
||||
#[get("/search")]
|
||||
async fn search(
|
||||
pub async fn search_packages(
|
||||
app_state: web::Data<AppState>,
|
||||
query: web::Query<Query>,
|
||||
) -> Result<impl Responder, errors::Errors> {
|
||||
|
@ -50,7 +49,3 @@ async fn search(
|
|||
.collect::<Vec<Value>>(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(search);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use std::{fs::read_dir, sync::Mutex, time::Duration};
|
||||
|
||||
use actix_cors::Cors;
|
||||
use actix_governor::{Governor, GovernorConfigBuilder, KeyExtractor, SimpleKeyExtractionError};
|
||||
use actix_web::{
|
||||
dev::ServiceRequest,
|
||||
error::ErrorUnauthorized,
|
||||
middleware::{Compress, Condition},
|
||||
middleware::{Compress, Condition, Logger},
|
||||
rt::System,
|
||||
web, App, Error, HttpMessage, HttpServer,
|
||||
};
|
||||
|
@ -73,7 +74,7 @@ pub fn commit_signature<'a>() -> Signature<'a> {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
pub struct UserId(pub u64);
|
||||
|
||||
async fn validator(
|
||||
|
@ -107,6 +108,18 @@ async fn validator(
|
|||
Ok(req)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct UserIdKey;
|
||||
|
||||
impl KeyExtractor for UserIdKey {
|
||||
type Key = UserId;
|
||||
type KeyExtractionError = SimpleKeyExtractionError<&'static str>;
|
||||
|
||||
fn extract(&self, req: &ServiceRequest) -> Result<Self::Key, Self::KeyExtractionError> {
|
||||
Ok(*req.extensions().get::<UserId>().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fn search_index(index: &GitIndex) -> (IndexReader, IndexWriter) {
|
||||
let mut schema_builder = tantivy::schema::SchemaBuilder::new();
|
||||
let name =
|
||||
|
@ -245,23 +258,52 @@ fn main() -> std::io::Result<()> {
|
|||
search_writer: Mutex::new(search_writer),
|
||||
});
|
||||
|
||||
let upload_governor_config = GovernorConfigBuilder::default()
|
||||
.burst_size(10)
|
||||
.per_second(600)
|
||||
.key_extractor(UserIdKey)
|
||||
.use_headers()
|
||||
.finish()
|
||||
.unwrap();
|
||||
|
||||
let generic_governor_config = GovernorConfigBuilder::default()
|
||||
.burst_size(10)
|
||||
.per_second(10)
|
||||
.use_headers()
|
||||
.finish()
|
||||
.unwrap();
|
||||
|
||||
info!("listening on {address}:{port}");
|
||||
|
||||
System::new().block_on(async move {
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(Condition::new(with_sentry, sentry_actix::Sentry::new()))
|
||||
.wrap(Logger::default())
|
||||
.wrap(Cors::permissive())
|
||||
.wrap(Compress::default())
|
||||
.app_data(app_data.clone())
|
||||
.route("/", web::get().to(|| async { env!("CARGO_PKG_VERSION") }))
|
||||
.service(
|
||||
web::scope("/v0")
|
||||
.configure(endpoints::search::configure)
|
||||
.service(
|
||||
web::scope("")
|
||||
.wrap(HttpAuthentication::with_fn(validator))
|
||||
.configure(endpoints::configure),
|
||||
.route(
|
||||
"/search",
|
||||
web::get()
|
||||
.to(endpoints::search::search_packages)
|
||||
.wrap(Governor::new(&generic_governor_config)),
|
||||
)
|
||||
.route(
|
||||
"/packages/{scope}/{name}/{version}",
|
||||
web::get()
|
||||
.to(endpoints::packages::get_package_version)
|
||||
.wrap(Governor::new(&generic_governor_config)),
|
||||
)
|
||||
.route(
|
||||
"/packages",
|
||||
web::post()
|
||||
.to(endpoints::packages::create_package)
|
||||
.wrap(Governor::new(&upload_governor_config))
|
||||
.wrap(HttpAuthentication::bearer(validator)),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue