Files
DECNET/decnet/services/registry.py
anti cf1e00af28 Add per-service customization, stealth hardening, and BYOS support
- HTTP: configurable server_header, response_code, fake_app presets
  (apache/nginx/wordpress/phpmyadmin/iis), extra_headers, custom_body,
  static files directory mount
- SSH/Cowrie: configurable kernel_version, hardware_platform, ssh_banner,
  and users/passwords via COWRIE_USERDB_ENTRIES; switched to build mode
  so cowrie.cfg.j2 persona fields and userdb.txt generation work
- SMTP: configurable banner and MTA hostname
- MySQL: configurable version string in protocol greeting
- Redis: configurable redis_version and os string in INFO response
- BYOS: [custom-*] INI sections define bring-your-own Docker services
- Stealth: rename all *_honeypot.py → server.py; replace HONEYPOT_NAME
  env var with NODE_NAME across all 22+ service templates and plugins;
  strip "honeypot" from all in-container file content
- Config: DeckyConfig.service_config dict; INI [decky-N.svc] subsections;
  composer passes service_cfg to compose_fragment
- 350 tests passing (100%)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 04:08:27 -03:00

50 lines
1.3 KiB
Python

"""
Service plugin registry.
Auto-discovers all BaseService subclasses by importing every module in the
services package. Adding a new service requires nothing beyond dropping a
new .py file here that subclasses BaseService.
"""
import importlib
import pkgutil
from pathlib import Path
from decnet.services.base import BaseService
_registry: dict[str, BaseService] = {}
_loaded = False
def _load_plugins() -> None:
global _loaded
if _loaded:
return
package_dir = Path(__file__).parent
for module_info in pkgutil.iter_modules([str(package_dir)]):
if module_info.name in ("base", "registry"):
continue
importlib.import_module(f"decnet.services.{module_info.name}")
for cls in BaseService.__subclasses__():
instance = cls()
_registry[instance.name] = instance
_loaded = True
def register_custom_service(instance: BaseService) -> None:
"""Register a dynamically created service (e.g. BYOS from INI)."""
_load_plugins()
_registry[instance.name] = instance
def get_service(name: str) -> BaseService:
_load_plugins()
if name not in _registry:
raise KeyError(f"Unknown service: '{name}'. Available: {list(_registry)}")
return _registry[name]
def all_services() -> dict[str, BaseService]:
_load_plugins()
return dict(_registry)