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",
|
"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]]
|
[[package]]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.6.0"
|
version = "3.6.0"
|
||||||
|
@ -1116,6 +1128,19 @@ dependencies = [
|
||||||
"syn 2.0.52",
|
"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]]
|
[[package]]
|
||||||
name = "data-encoding"
|
name = "data-encoding"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -1541,6 +1566,21 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"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]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -1548,6 +1588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1624,12 +1665,19 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-timer"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
|
@ -1732,6 +1780,26 @@ dependencies = [
|
||||||
"regex-syntax 0.8.2",
|
"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]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.24"
|
version = "0.3.24"
|
||||||
|
@ -2628,6 +2696,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "no-std-compat"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
|
@ -2638,6 +2712,12 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonzero_ext"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
@ -2973,9 +3053,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pesde-registry"
|
name = "pesde-registry"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-cors",
|
"actix-cors",
|
||||||
|
"actix-governor",
|
||||||
"actix-multipart",
|
"actix-multipart",
|
||||||
"actix-multipart-derive",
|
"actix-multipart-derive",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
@ -3174,6 +3255,21 @@ dependencies = [
|
||||||
"cc",
|
"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]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.30.0"
|
version = "0.30.0"
|
||||||
|
@ -3242,6 +3338,15 @@ dependencies = [
|
||||||
"getrandom 0.2.12",
|
"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]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
@ -4146,6 +4251,15 @@ version = "0.9.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
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]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
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]
|
[package]
|
||||||
name = "pesde-registry"
|
name = "pesde-registry"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -9,6 +9,7 @@ actix-cors = "0.7.0"
|
||||||
actix-web-httpauth = "0.8.1"
|
actix-web-httpauth = "0.8.1"
|
||||||
actix-multipart = "0.6.1"
|
actix-multipart = "0.6.1"
|
||||||
actix-multipart-derive = "0.6.1"
|
actix-multipart-derive = "0.6.1"
|
||||||
|
actix-governor = "0.5.0"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
reqwest = { version = "0.11.24", features = ["json", "blocking"] }
|
reqwest = { version = "0.11.24", features = ["json", "blocking"] }
|
||||||
rusty-s3 = "0.5.0"
|
rusty-s3 = "0.5.0"
|
||||||
|
|
|
@ -1,8 +1,2 @@
|
||||||
use actix_web::web;
|
|
||||||
|
|
||||||
pub mod packages;
|
pub mod packages;
|
||||||
pub mod search;
|
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_multipart::form::{bytes::Bytes, MultipartForm};
|
||||||
use actix_web::{get, post, web, HttpResponse, Responder};
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use rusty_s3::S3Action;
|
use rusty_s3::S3Action;
|
||||||
|
@ -14,13 +14,12 @@ use pesde::{
|
||||||
use crate::{commit_signature, errors, AppState, UserId, S3_EXPIRY};
|
use crate::{commit_signature, errors, AppState, UserId, S3_EXPIRY};
|
||||||
|
|
||||||
#[derive(MultipartForm)]
|
#[derive(MultipartForm)]
|
||||||
struct CreateForm {
|
pub struct CreateForm {
|
||||||
#[multipart(limit = "4 MiB")]
|
#[multipart(limit = "4 MiB")]
|
||||||
tarball: Bytes,
|
tarball: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/packages")]
|
pub async fn create_package(
|
||||||
async fn create(
|
|
||||||
form: MultipartForm<CreateForm>,
|
form: MultipartForm<CreateForm>,
|
||||||
app_state: web::Data<AppState>,
|
app_state: web::Data<AppState>,
|
||||||
user_id: web::ReqData<UserId>,
|
user_id: web::ReqData<UserId>,
|
||||||
|
@ -156,8 +155,7 @@ async fn create(
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/packages/{author_name}/{package_name}/{version}")]
|
pub async fn get_package_version(
|
||||||
async fn get(
|
|
||||||
app_state: web::Data<AppState>,
|
app_state: web::Data<AppState>,
|
||||||
path: web::Path<(String, String, String)>,
|
path: web::Path<(String, String, String)>,
|
||||||
) -> Result<impl Responder, errors::Errors> {
|
) -> Result<impl Responder, errors::Errors> {
|
||||||
|
@ -202,7 +200,3 @@ async fn get(
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().body(response.bytes().await?))
|
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::Deserialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::{errors, AppState};
|
use crate::{errors, AppState};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Query {
|
pub struct Query {
|
||||||
query: String,
|
query: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/search")]
|
pub async fn search_packages(
|
||||||
async fn search(
|
|
||||||
app_state: web::Data<AppState>,
|
app_state: web::Data<AppState>,
|
||||||
query: web::Query<Query>,
|
query: web::Query<Query>,
|
||||||
) -> Result<impl Responder, errors::Errors> {
|
) -> Result<impl Responder, errors::Errors> {
|
||||||
|
@ -50,7 +49,3 @@ async fn search(
|
||||||
.collect::<Vec<Value>>(),
|
.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 std::{fs::read_dir, sync::Mutex, time::Duration};
|
||||||
|
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
|
use actix_governor::{Governor, GovernorConfigBuilder, KeyExtractor, SimpleKeyExtractionError};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::ServiceRequest,
|
dev::ServiceRequest,
|
||||||
error::ErrorUnauthorized,
|
error::ErrorUnauthorized,
|
||||||
middleware::{Compress, Condition},
|
middleware::{Compress, Condition, Logger},
|
||||||
rt::System,
|
rt::System,
|
||||||
web, App, Error, HttpMessage, HttpServer,
|
web, App, Error, HttpMessage, HttpServer,
|
||||||
};
|
};
|
||||||
|
@ -73,7 +74,7 @@ pub fn commit_signature<'a>() -> Signature<'a> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub struct UserId(pub u64);
|
pub struct UserId(pub u64);
|
||||||
|
|
||||||
async fn validator(
|
async fn validator(
|
||||||
|
@ -107,6 +108,18 @@ async fn validator(
|
||||||
Ok(req)
|
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) {
|
fn search_index(index: &GitIndex) -> (IndexReader, IndexWriter) {
|
||||||
let mut schema_builder = tantivy::schema::SchemaBuilder::new();
|
let mut schema_builder = tantivy::schema::SchemaBuilder::new();
|
||||||
let name =
|
let name =
|
||||||
|
@ -245,23 +258,52 @@ fn main() -> std::io::Result<()> {
|
||||||
search_writer: Mutex::new(search_writer),
|
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}");
|
info!("listening on {address}:{port}");
|
||||||
|
|
||||||
System::new().block_on(async move {
|
System::new().block_on(async move {
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(Condition::new(with_sentry, sentry_actix::Sentry::new()))
|
.wrap(Condition::new(with_sentry, sentry_actix::Sentry::new()))
|
||||||
|
.wrap(Logger::default())
|
||||||
.wrap(Cors::permissive())
|
.wrap(Cors::permissive())
|
||||||
.wrap(Compress::default())
|
.wrap(Compress::default())
|
||||||
.app_data(app_data.clone())
|
.app_data(app_data.clone())
|
||||||
.route("/", web::get().to(|| async { env!("CARGO_PKG_VERSION") }))
|
.route("/", web::get().to(|| async { env!("CARGO_PKG_VERSION") }))
|
||||||
.service(
|
.service(
|
||||||
web::scope("/v0")
|
web::scope("/v0")
|
||||||
.configure(endpoints::search::configure)
|
.route(
|
||||||
.service(
|
"/search",
|
||||||
web::scope("")
|
web::get()
|
||||||
.wrap(HttpAuthentication::with_fn(validator))
|
.to(endpoints::search::search_packages)
|
||||||
.configure(endpoints::configure),
|
.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