Enforce network IP restriction
This commit is contained in:
		@@ -1,9 +1,11 @@
 | 
			
		||||
use crate::user::{APIClient, APIClientID, UserConfig, UserID};
 | 
			
		||||
use crate::utils::curr_time;
 | 
			
		||||
use actix_remote_ip::RemoteIP;
 | 
			
		||||
use actix_web::dev::Payload;
 | 
			
		||||
use actix_web::{FromRequest, HttpRequest};
 | 
			
		||||
use jwt_simple::common::VerificationOptions;
 | 
			
		||||
use jwt_simple::prelude::{Duration, HS256Key, MACLike};
 | 
			
		||||
use std::net::IpAddr;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
 | 
			
		||||
pub struct APIClientAuth {
 | 
			
		||||
@@ -19,7 +21,7 @@ pub struct TokenClaims {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl APIClientAuth {
 | 
			
		||||
    async fn extract_auth(req: &HttpRequest) -> Result<Self, actix_web::Error> {
 | 
			
		||||
    async fn extract_auth(req: &HttpRequest, remote_ip: IpAddr) -> Result<Self, actix_web::Error> {
 | 
			
		||||
        let Some(token) = req.headers().get("x-client-auth") else {
 | 
			
		||||
            return Err(actix_web::error::ErrorBadRequest(
 | 
			
		||||
                "Missing authentication header!",
 | 
			
		||||
@@ -99,6 +101,19 @@ impl APIClientAuth {
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check IP restriction
 | 
			
		||||
        if let Some(net) = client.network {
 | 
			
		||||
            if !net.contains(&remote_ip) {
 | 
			
		||||
                log::error!(
 | 
			
		||||
                    "Trying to use client {} from unauthorized IP address: {remote_ip}",
 | 
			
		||||
                    client.id.0
 | 
			
		||||
                );
 | 
			
		||||
                return Err(actix_web::error::ErrorForbidden(
 | 
			
		||||
                    "This client cannot be used from this IP address!",
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check URI & verb
 | 
			
		||||
        if claims.custom.uri != req.uri().to_string() {
 | 
			
		||||
            return Err(actix_web::error::ErrorBadRequest("URI mismatch!"));
 | 
			
		||||
@@ -115,7 +130,6 @@ impl APIClientAuth {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO : handle payload
 | 
			
		||||
        // TODO : check for IP restriction
 | 
			
		||||
 | 
			
		||||
        // Update last use (if needed)
 | 
			
		||||
        if client.need_update_last_used() {
 | 
			
		||||
@@ -143,6 +157,12 @@ impl FromRequest for APIClientAuth {
 | 
			
		||||
 | 
			
		||||
    fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
 | 
			
		||||
        let req = req.clone();
 | 
			
		||||
        Box::pin(async move { Self::extract_auth(&req).await })
 | 
			
		||||
 | 
			
		||||
        let remote_ip = match RemoteIP::from_request(&req, &mut Payload::None).into_inner() {
 | 
			
		||||
            Ok(ip) => ip,
 | 
			
		||||
            Err(e) => return Box::pin(async { Err(e) }),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Box::pin(async move { Self::extract_auth(&req, remote_ip.0).await })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
use actix_remote_ip::RemoteIPConfig;
 | 
			
		||||
use actix_session::config::SessionLifecycle;
 | 
			
		||||
use actix_session::{storage::RedisSessionStore, SessionMiddleware};
 | 
			
		||||
use actix_web::cookie::Key;
 | 
			
		||||
@@ -35,6 +36,9 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                    .session_lifecycle(SessionLifecycle::BrowserSession(Default::default()))
 | 
			
		||||
                    .build(),
 | 
			
		||||
            )
 | 
			
		||||
            .app_data(web::Data::new(RemoteIPConfig {
 | 
			
		||||
                proxy: AppConfig::get().proxy_ip.clone(),
 | 
			
		||||
            }))
 | 
			
		||||
            // Web configuration routes
 | 
			
		||||
            .route("/assets/{tail:.*}", web::get().to(web_ui::static_file))
 | 
			
		||||
            .route("/", web::get().to(web_ui::home))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user