Skip to content
This repository was archived by the owner on Apr 9, 2025. It is now read-only.
/ api Public archive

Commit c9ae485

Browse files
committed
fix ip retrieval
1 parent a8717dd commit c9ae485

File tree

5 files changed

+63
-29
lines changed

5 files changed

+63
-29
lines changed

Cargo.lock

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "api"
3-
version = "3.2.2"
3+
version = "3.2.3"
44
edition = "2024"
55

66
[dependencies]

src/main.rs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use models::r#type::ServerType;
2020
use routes::{ApiError, GetState};
2121
use sentry_tower::SentryHttpLayer;
2222
use sha1::Digest;
23-
use std::{sync::Arc, time::Instant};
23+
use std::{net::IpAddr, sync::Arc, time::Instant};
2424
use tower_cookies::CookieManagerLayer;
2525
use tower_http::{catch_panic::CatchPanicLayer, cors::CorsLayer, trace::TraceLayer};
2626
use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme};
@@ -47,12 +47,9 @@ fn handle_panic(_err: Box<dyn std::any::Any + Send + 'static>) -> Response<Body>
4747
}
4848

4949
fn handle_request(req: &Request<Body>, _span: &tracing::Span) {
50-
let ip = req
51-
.headers()
52-
.get("x-real-ip")
53-
.or_else(|| req.headers().get("x-forwarded-for"))
54-
.map(|ip| ip.to_str().unwrap_or_default())
55-
.unwrap_or_default();
50+
let ip = extract_ip(req.headers())
51+
.map(|ip| ip.to_string())
52+
.unwrap_or_else(|| "unknown".to_string());
5653

5754
logger::log(
5855
logger::LoggerLevel::Info,
@@ -76,7 +73,7 @@ async fn handle_postprocessing(req: Request, next: Next) -> Result<Response, Sta
7673

7774
let mut response = next.run(req).await;
7875

79-
if let Some(content_type) = response.headers().get("Content-Type").cloned() {
76+
if let Some(content_type) = response.headers().get("Content-Type") {
8077
if content_type
8178
.to_str()
8279
.map(|c| c.starts_with("text/plain"))
@@ -131,6 +128,26 @@ async fn handle_postprocessing(req: Request, next: Next) -> Result<Response, Sta
131128
Ok(Response::from_parts(parts, Body::from(body_bytes)))
132129
}
133130

131+
pub fn extract_ip(headers: &HeaderMap) -> Option<IpAddr> {
132+
let ip = headers
133+
.get("x-real-ip")
134+
.or_else(|| headers.get("x-forwarded-for"))
135+
.map(|ip| ip.to_str().unwrap_or_default())
136+
.unwrap_or_default();
137+
138+
if ip.is_empty() {
139+
return None;
140+
}
141+
142+
let ip = if ip.contains(',') {
143+
ip.split(',').next().unwrap_or_default().trim().to_string()
144+
} else {
145+
ip.to_string()
146+
};
147+
148+
ip.parse().ok()
149+
}
150+
134151
#[tokio::main]
135152
async fn main() {
136153
let env = env::Env::parse();
@@ -230,8 +247,7 @@ async fn main() {
230247
)
231248
.as_str(),
232249
)
233-
.await
234-
.unwrap(),
250+
.await,
235251
"legacy-fabric" => reqwest::get(
236252
format!(
237253
"https://meta.legacyfabric.net/v2/versions/loader/{}/{}/{}/server/jar",
@@ -241,15 +257,25 @@ async fn main() {
241257
)
242258
.as_str(),
243259
)
244-
.await
245-
.unwrap(),
260+
.await,
246261
_ => return (
247262
StatusCode::NOT_FOUND,
248263
headers,
249264
Body::from(b"project not supported".to_vec()),
250265
),
251266
};
252267

268+
let response = match response {
269+
Ok(response) => response,
270+
Err(_) => {
271+
return (
272+
StatusCode::NOT_FOUND,
273+
headers,
274+
Body::from(b"error fetching build".to_vec()),
275+
);
276+
}
277+
};
278+
253279
if !response.status().is_success() {
254280
return (
255281
StatusCode::NOT_FOUND,

src/requests.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,12 @@ impl RequestLogger {
6868
request: Parts,
6969
organization: Option<&Organization>,
7070
) -> Result<(Option<String>, Option<RateLimitData>), Option<RateLimitData>> {
71-
let mut ratelimit: Option<RateLimitData> = None;
71+
let ip = match crate::extract_ip(&request.headers) {
72+
Some(ip) => ip,
73+
None => return Err(None),
74+
};
7275

73-
let ip = request
74-
.headers
75-
.get("x-real-ip")
76-
.or_else(|| request.headers.get("x-forwarded-for"))
77-
.map(|ip| ip.to_str().unwrap_or_default())
78-
.unwrap_or_default()
79-
.to_string();
76+
let mut ratelimit: Option<RateLimitData> = None;
8077

8178
if organization.is_none() || !organization.as_ref().unwrap().verified {
8279
let ratelimit_key = format!("mcjars_api::ratelimit::{}", ip);
@@ -136,7 +133,7 @@ impl RequestLogger {
136133
status: 0,
137134
body: None,
138135

139-
ip: ip.parse().unwrap(),
136+
ip: ip.into(),
140137
continent: None,
141138
country: None,
142139

src/routes/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ async fn handle_api_request(state: GetState, req: Request, next: Next) -> Respon
8686
ApiError::new(&["too many requests"]).to_value().to_string(),
8787
))
8888
.unwrap();
89+
} else if let Err(None) = request_id {
90+
return Response::builder()
91+
.status(StatusCode::BAD_REQUEST)
92+
.header("Content-Type", "application/json")
93+
.body(Body::from(
94+
ApiError::new(&["broken request, likely invalid IP"])
95+
.to_value()
96+
.to_string(),
97+
))
98+
.unwrap();
8999
}
90100

91101
let mut headers = HeaderMap::new();

0 commit comments

Comments
 (0)