FactsDB/factsdb/ftp_server.py

111 lines
3.8 KiB
Python

"""
FTP Server module for FactsDB service
Provides secure FTP access to onboarded directories
"""
import os
import threading
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
from typing import Dict, List, Set
from .config import Config
from .database import DatabaseManager
class FTPServerManager:
"""Manages the FTP server for FactsDB service"""
def __init__(self, config):
self.config = config
# Fix: Remove database initialization from FTP server - it doesn't need database access for basic FTP
self.db_manager = None # Don't initialize database for FTP server
self.server = None
self.is_running = False
self.onboarded_directories: Set[str] = set()
def start(self):
"""Start the FTP server"""
if self.is_running:
print("FTP server is already running")
return
try:
# Create authorizer
authorizer = DummyAuthorizer()
# Add user with read/write permissions
authorizer.add_user(
self.config.ftp_server.username,
self.config.ftp_server.password,
homedir="/",
perm="elradfmw"
)
# Create handler
handler = FTPHandler
handler.authorizer = authorizer
# 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"""
if self.server:
self.server.serve_forever()
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")
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 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_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