mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-12 04:42:16 +00:00
ip filter middleware (not rejecting yet)
This commit is contained in:
1 parent
b783fe5bcb
commit
8b95ea3abd
8 files changed
+103
-7
No files matched your search
Generated
+1
@@ -3168,6 +3168,7 @@ dependencies = [
|
||||
"actix-http",
|
||||
"actix-multipart",
|
||||
"actix-rt 2.2.0",
|
||||
"actix-service",
|
||||
"actix-utils 3.0.0",
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
|
||||
@@ -86,6 +86,7 @@ actix-files= "0.5"
|
||||
actix-http = "2.2.0"
|
||||
actix-multipart = "0.3.0" # TODO: Ready for 0.4 upgrade
|
||||
actix-rt = "2.2.0"
|
||||
actix-service = "1.0.6"
|
||||
actix-utils = "3.0.0"
|
||||
actix-web = "3.3.2"
|
||||
jwt = "0.13.0"
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_service::{Service, Transform};
|
||||
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
|
||||
use futures::future::{ok, Ready};
|
||||
use futures::Future;
|
||||
use crate::threads::ip_banlist_set::IpBanlistSet;
|
||||
use log::warn;
|
||||
use log::info;
|
||||
|
||||
// There are two steps in middleware processing.
|
||||
// 1. Middleware initialization, middleware factory gets called with
|
||||
// next service in chain as parameter.
|
||||
// 2. Middleware's call method gets called with normal request.
|
||||
#[derive(Clone)] // NB: Clone is safe because IpBanlist is clone-safe (internal Arc)
|
||||
pub struct IpFilter {
|
||||
ip_banlist: IpBanlistSet,
|
||||
}
|
||||
|
||||
impl IpFilter {
|
||||
pub fn new(ip_banlist: IpBanlistSet) -> Self {
|
||||
Self {
|
||||
ip_banlist,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware factory is `Transform` trait from actix-service crate
|
||||
// `S` - type of the next service
|
||||
// `B` - type of response's body
|
||||
impl<S, B> Transform<S> for IpFilter
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = IpFilterMiddleware<S>;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
// NB: IpBanlist is clone-safe due to internal Arc.
|
||||
ok(IpFilterMiddleware { service, ip_banlist: self.ip_banlist.clone() })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IpFilterMiddleware<S> {
|
||||
service: S,
|
||||
ip_banlist: IpBanlistSet,
|
||||
}
|
||||
|
||||
impl<S, B> Service for IpFilterMiddleware<S>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: ServiceRequest) -> Self::Future {
|
||||
println!("Hi from start. You requested: {}", req.path());
|
||||
info!("Checking IP. There are {} bans currently.", self.ip_banlist.num_bans().unwrap_or(0));
|
||||
|
||||
let fut = self.service.call(req);
|
||||
|
||||
Box::pin(async move {
|
||||
let res = fut.await?;
|
||||
|
||||
println!("Hi from response");
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod ip_filter_middleware;
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod endpoints;
|
||||
pub mod middleware;
|
||||
pub mod web_utils;
|
||||
@@ -97,6 +97,7 @@ use sqlx::MySqlPool;
|
||||
use sqlx::mysql::MySqlPoolOptions;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use crate::http_server::middleware::ip_filter_middleware::IpFilter;
|
||||
|
||||
// TODO TODO TODO TODO
|
||||
// TODO TODO TODO TODO
|
||||
@@ -270,6 +271,9 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
|
||||
let log_format = "[%{HOSTNAME}e] %a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T";
|
||||
|
||||
HttpServer::new(move || {
|
||||
// NB: Safe to clone due to internal arc
|
||||
let ip_banlist = server_state_arc.ip_banlist.clone();
|
||||
|
||||
App::new()
|
||||
.app_data(server_state_arc.clone())
|
||||
.wrap(Cors::default()
|
||||
@@ -310,6 +314,7 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
|
||||
.wrap(DefaultHeaders::new()
|
||||
.header("X-Backend-Hostname", &hostname)
|
||||
.header("X-Build-Sha", ""))
|
||||
.wrap(IpFilter::new(ip_banlist))
|
||||
// ==================== ACCOUNT CREATION / SESSION MANAGEMENT ====================
|
||||
.service(
|
||||
web::resource("/create_account")
|
||||
|
||||
@@ -36,4 +36,14 @@ impl IpBanlistSet {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_bans(&self) -> AnyhowResult<usize> {
|
||||
match self.ip_banlist.read() {
|
||||
Err(_) => Err(anyhow!("Can't read lock")),
|
||||
Ok(read) => {
|
||||
let result = read.len();
|
||||
Ok(result)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,8 @@ use log::info;
|
||||
use log::warn;
|
||||
use sqlx::MySqlPool;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tokio::signal::ctrl_c;
|
||||
use tokio::signal::unix::signal;
|
||||
use tokio::signal::unix::{SignalKind, Signal};
|
||||
use tokio::sync::oneshot::{Sender, Receiver};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
pub async fn poll_ip_bans(
|
||||
ip_banlist_set: IpBanlistSet,
|
||||
|
||||
Reference in new issue
Block a user