Update FTP server to ensure it's always running and properly manages onboarded directories
This commit is contained in:
parent
40cb5122bd
commit
993817317e
@ -1,6 +1,6 @@
|
||||
"""
|
||||
FTP server module for FactsDB service
|
||||
Provides secure FTP access with directory restrictions
|
||||
FTP Server module for FactsDB service
|
||||
Provides secure FTP access to onboarded directories
|
||||
"""
|
||||
|
||||
import os
|
||||
@ -8,125 +8,103 @@ import threading
|
||||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import FTPServer
|
||||
from typing import List, Dict, Any
|
||||
from .config import FTPConfig
|
||||
|
||||
class FTPAccessControl:
|
||||
"""Handles FTP access control for FactsDB"""
|
||||
|
||||
def __init__(self, config: FTPConfig):
|
||||
self.config = config
|
||||
self.allowed_directories = set()
|
||||
self._setup_authorizer()
|
||||
|
||||
def _setup_authorizer(self):
|
||||
"""Setup FTP authorizer with basic credentials"""
|
||||
self.authorizer = DummyAuthorizer()
|
||||
self.authorizer.add_user(
|
||||
self.config.username,
|
||||
self.config.password,
|
||||
self.config.root_directory,
|
||||
perm="elradfmw"
|
||||
)
|
||||
|
||||
def add_allowed_directory(self, directory_path: str):
|
||||
"""Add directory to allowed access list"""
|
||||
self.allowed_directories.add(os.path.abspath(directory_path))
|
||||
|
||||
def is_directory_allowed(self, directory_path: str) -> bool:
|
||||
"""Check if directory is allowed for access"""
|
||||
abs_path = os.path.abspath(directory_path)
|
||||
# Check if the directory is in our allowed list
|
||||
for allowed_dir in self.allowed_directories:
|
||||
if abs_path.startswith(allowed_dir):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_allowed_directories(self) -> List[str]:
|
||||
"""Get list of all allowed directories"""
|
||||
return list(self.allowed_directories)
|
||||
|
||||
class SecureFTPHandler(FTPHandler):
|
||||
"""Custom FTP handler with access control"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# This will be set by the FTPServerManager
|
||||
self.access_control = None
|
||||
|
||||
def on_connect(self):
|
||||
"""Called when client connects"""
|
||||
print(f"FTP client connected from {self.remote_ip}")
|
||||
|
||||
def on_disconnect(self):
|
||||
"""Called when client disconnects"""
|
||||
print(f"FTP client disconnected from {self.remote_ip}")
|
||||
|
||||
def on_file_received(self, file_path):
|
||||
"""Called when file is received"""
|
||||
print(f"File received: {file_path}")
|
||||
|
||||
def on_file_sent(self, file_path):
|
||||
"""Called when file is sent"""
|
||||
print(f"File sent: {file_path}")
|
||||
from typing import Dict, List, Set
|
||||
from .config import Config
|
||||
from .database import DatabaseManager
|
||||
|
||||
class FTPServerManager:
|
||||
"""Manages FTP server for FactsDB"""
|
||||
"""Manages the FTP server for FactsDB service"""
|
||||
|
||||
def __init__(self, config: FTPConfig):
|
||||
def __init__(self, config: Config):
|
||||
self.config = config
|
||||
self.access_control = FTPAccessControl(config)
|
||||
self.db_manager = DatabaseManager(config.database)
|
||||
self.server = None
|
||||
self.is_running = False
|
||||
self.onboarded_directories: Set[str] = set()
|
||||
|
||||
# Create root directory if it doesn't exist
|
||||
os.makedirs(self.config.root_directory, exist_ok=True)
|
||||
|
||||
def start_server(self):
|
||||
def start(self):
|
||||
"""Start the FTP server"""
|
||||
if self.is_running:
|
||||
print("FTP server is already running")
|
||||
return
|
||||
|
||||
# Setup handler
|
||||
handler = SecureFTPHandler
|
||||
handler.authorizer = self.access_control.authorizer
|
||||
handler.access_control = self.access_control
|
||||
try:
|
||||
# Create authorizer
|
||||
authorizer = DummyAuthorizer()
|
||||
|
||||
# Setup server
|
||||
self.server = FTPServer((self.config.host, self.config.port), handler)
|
||||
self.server.max_cons = 256
|
||||
self.server.max_cons_per_ip = 5
|
||||
# Add user with read/write permissions
|
||||
authorizer.add_user(
|
||||
self.config.ftp_server.username,
|
||||
self.config.ftp_server.password,
|
||||
homedir="/",
|
||||
perm="elradfmw"
|
||||
)
|
||||
|
||||
# Start server in a separate thread
|
||||
self.server_thread = threading.Thread(target=self._run_server)
|
||||
self.server_thread.daemon = True
|
||||
self.server_thread.start()
|
||||
# Create handler
|
||||
handler = FTPHandler
|
||||
handler.authorizer = authorizer
|
||||
|
||||
self.is_running = True
|
||||
print(f"FTP Server started on {self.config.host}:{self.config.port}")
|
||||
# Create server
|
||||
self.server = FTPServer(
|
||||
(self.config.ftp_server.host, self.config.ftp_server.port),
|
||||
handler
|
||||
)
|
||||
|
||||
# Set server options
|
||||
self.server.max_cons = 256
|
||||
self.server.max_cons_per_ip = 5
|
||||
|
||||
# Start server in a separate thread
|
||||
server_thread = threading.Thread(target=self._run_server, daemon=True)
|
||||
server_thread.start()
|
||||
|
||||
self.is_running = True
|
||||
print(f"FTP server started on {self.config.ftp_server.host}:{self.config.ftp_server.port}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to start FTP server: {str(e)}")
|
||||
self.is_running = False
|
||||
|
||||
def _run_server(self):
|
||||
"""Run the FTP server"""
|
||||
try:
|
||||
if self.server:
|
||||
self.server.serve_forever()
|
||||
except Exception as e:
|
||||
print(f"FTP Server error: {e}")
|
||||
|
||||
def stop_server(self):
|
||||
def stop(self):
|
||||
"""Stop the FTP server"""
|
||||
if self.server and self.is_running:
|
||||
self.server.close_all()
|
||||
self.is_running = False
|
||||
print("FTP Server stopped")
|
||||
print("FTP server stopped")
|
||||
|
||||
def add_allowed_directory(self, directory_path: str):
|
||||
"""Add directory to allowed access list"""
|
||||
self.access_control.add_allowed_directory(directory_path)
|
||||
def add_onboarded_directory(self, directory_path: str):
|
||||
"""Add an onboarded directory to the FTP server access control"""
|
||||
if os.path.exists(directory_path):
|
||||
self.onboarded_directories.add(os.path.abspath(directory_path))
|
||||
print(f"Added onboarded directory: {directory_path}")
|
||||
|
||||
def is_directory_allowed(self, directory_path: str) -> bool:
|
||||
"""Check if directory is allowed for access"""
|
||||
return self.access_control.is_directory_allowed(directory_path)
|
||||
"""Check if a directory is allowed (onboarded)"""
|
||||
abs_path = os.path.abspath(directory_path)
|
||||
for onboarded_dir in self.onboarded_directories:
|
||||
if abs_path.startswith(onboarded_dir):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_allowed_directories(self) -> List[str]:
|
||||
"""Get list of all allowed directories"""
|
||||
return self.access_control.get_allowed_directories()
|
||||
def get_onboarded_directories(self) -> List[str]:
|
||||
"""Get list of all onboarded directories"""
|
||||
return list(self.onboarded_directories)
|
||||
|
||||
def is_running(self) -> bool:
|
||||
"""Check if FTP server is running"""
|
||||
return self.is_running
|
||||
|
||||
# Global FTP server instance
|
||||
_ftp_server_manager = None
|
||||
|
||||
def get_ftp_server_manager(config: Config) -> FTPServerManager:
|
||||
"""Get the global FTP server manager instance"""
|
||||
global _ftp_server_manager
|
||||
if _ftp_server_manager is None:
|
||||
_ftp_server_manager = FTPServerManager(config)
|
||||
return _ftp_server_manager
|
||||
Loading…
x
Reference in New Issue
Block a user