Skip to content

Commit 9a4929a

Browse files
committed
feat(su): su improvements
1 parent 6581c46 commit 9a4929a

File tree

4 files changed

+85
-3
lines changed

4 files changed

+85
-3
lines changed

servers/su/src/domain/config.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub struct AoConfig {
6060
pub max_size_owner_whitelist: Vec<String>,
6161
pub max_size_from_owner_whitelist: Vec<String>,
6262
pub max_size_from_whitelist: Vec<String>,
63+
64+
pub ip_whitelist_url: String,
6365
}
6466

6567
fn get_db_dirs() -> (String, String, String, String) {
@@ -249,6 +251,11 @@ impl AoConfig {
249251
Err(_e) => vec![],
250252
};
251253

254+
let ip_whitelist_url: String = match env::var("IP_WHITELIST_URL") {
255+
Ok(val) => val,
256+
Err(_e) => "".to_string(),
257+
};
258+
252259
Ok(AoConfig {
253260
database_url: env::var("DATABASE_URL")?,
254261
database_read_url,
@@ -285,7 +292,8 @@ impl AoConfig {
285292
max_message_size,
286293
max_size_owner_whitelist,
287294
max_size_from_owner_whitelist,
288-
max_size_from_whitelist
295+
max_size_from_whitelist,
296+
ip_whitelist_url
289297
})
290298
}
291299
}
@@ -342,4 +350,7 @@ impl Config for AoConfig {
342350
fn max_size_from_whitelist(&self) -> Vec<String> {
343351
self.max_size_from_whitelist.clone()
344352
}
353+
fn ip_whitelist_url(&self) -> String {
354+
self.ip_whitelist_url.clone()
355+
}
345356
}

servers/su/src/domain/core/dal.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub trait Config: Send + Sync {
8282
fn max_size_owner_whitelist(&self) -> Vec<String>;
8383
fn max_size_from_owner_whitelist(&self) -> Vec<String>;
8484
fn max_size_from_whitelist(&self) -> Vec<String>;
85+
fn ip_whitelist_url(&self) -> String;
8586
}
8687

8788
#[derive(Debug)]

servers/su/src/main.rs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::env;
22
use std::io::{self, Error, ErrorKind};
33
use std::sync::Arc;
4-
use std::time::{SystemTime, UNIX_EPOCH};
4+
use std::time::{SystemTime, UNIX_EPOCH, Duration};
5+
use std::collections::HashSet;
6+
use std::sync::RwLock;
57

68
use actix_cors::Cors;
79
use actix_web::{
@@ -11,9 +13,13 @@ use actix_web::{
1113

1214
use serde::Deserialize;
1315
use serde_json::json;
16+
use tokio::time::interval;
17+
use reqwest;
1418

1519
use su::domain::{flows, init_deps, router, Deps, PromMetrics};
1620

21+
type IpWhitelist = Arc<RwLock<HashSet<String>>>;
22+
1723
#[derive(Deserialize)]
1824
struct FromTo {
1925
from: Option<String>,
@@ -61,6 +67,40 @@ fn err_response(err: String) -> HttpResponse {
6167
.body(error_json.to_string())
6268
}
6369

70+
fn get_client_ip(req: &HttpRequest) -> Option<String> {
71+
req.connection_info()
72+
.realip_remote_addr()
73+
.map(|ip| ip.to_string())
74+
}
75+
76+
fn is_ip_allowed(ip: &str, whitelist: &IpWhitelist) -> bool {
77+
println!("Checking if IP {} is allowed", ip);
78+
match whitelist.read() {
79+
Ok(ips) => ips.contains(ip),
80+
Err(_) => false,
81+
}
82+
}
83+
84+
async fn fetch_ip_whitelist(url: String) -> Result<HashSet<String>, reqwest::Error> {
85+
let response = reqwest::get(url).await?;
86+
let ips: Vec<String> = response.json().await?;
87+
Ok(ips.into_iter().collect())
88+
}
89+
90+
async fn update_ip_whitelist_loop(ip_whitelist: IpWhitelist, whitelist_url: String) {
91+
let mut interval = interval(Duration::from_secs(30));
92+
93+
loop {
94+
interval.tick().await;
95+
96+
if let Ok(new_ips) = fetch_ip_whitelist(whitelist_url.clone()).await {
97+
if let Ok(mut ips) = ip_whitelist.write() {
98+
*ips = new_ips;
99+
}
100+
}
101+
}
102+
}
103+
64104
async fn base(
65105
data: web::Data<AppState>,
66106
query_params: web::Query<ProcessId>,
@@ -128,6 +168,16 @@ async fn main_post_route(
128168
return HttpResponse::ServiceUnavailable()
129169
.json(json!({"error": "Server is warming up. Please try again later."}));
130170
}
171+
172+
if let Some(client_ip) = get_client_ip(&req) {
173+
if !is_ip_allowed(&client_ip, &data.ip_whitelist) {
174+
return HttpResponse::Forbidden()
175+
.json(json!({"error": "Access denied"}));
176+
}
177+
} else {
178+
return HttpResponse::BadRequest()
179+
.json(json!({"error": "Access denied"}));
180+
}
131181
match router::redirect_data_item(
132182
data.deps.clone(),
133183
req_body.to_vec(),
@@ -281,6 +331,7 @@ struct AppState {
281331
deps: Arc<Deps>,
282332
metrics: Arc<PromMetrics>,
283333
startup_time: u64,
334+
ip_whitelist: IpWhitelist,
284335
}
285336

286337
#[actix_web::main]
@@ -311,13 +362,32 @@ async fn main() -> io::Result<()> {
311362
.as_secs();
312363

313364
let (deps, metrics) = init_deps(mode).await;
365+
366+
let run_deps = deps.clone();
367+
368+
let ip_whitelist: IpWhitelist = Arc::new(RwLock::new(HashSet::new()));
369+
370+
match fetch_ip_whitelist(run_deps.config.ip_whitelist_url()).await {
371+
Ok(initial_ips) => {
372+
if let Ok(mut ips) = ip_whitelist.write() {
373+
*ips = initial_ips;
374+
}
375+
}
376+
Err(_) => {}
377+
}
378+
314379
let app_state = web::Data::new(AppState {
315380
deps,
316381
metrics,
317382
startup_time,
383+
ip_whitelist: ip_whitelist.clone(),
318384
});
319385

320-
let run_deps = app_state.deps.clone();
386+
let whitelist_clone = ip_whitelist.clone();
387+
let whitelist_url = run_deps.config.ip_whitelist_url();
388+
tokio::spawn(async move {
389+
update_ip_whitelist_loop(whitelist_clone, whitelist_url).await;
390+
});
321391

322392
if run_deps.config.mode() == "router" {
323393
match router::init_schedulers(run_deps.clone()).await {

servers/su/su

91.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)