Files
archie/tests/servers/ftps_server.py
Mario Fetka 1e4baef047 Port Archie 3.5 to Linux/CMake, add Debian packaging and CI
- Replace autoconf/make build system with CMake (installs to /opt/archie)
- Add CPack DEB packaging for Debian Trixie (non-free/net, postinst creates
  archie user, extracts DB skeleton, sets setuid bits, enables systemd units)
- Add Gitea Actions workflow building .deb + binary/source tarballs on tag push
- Add portable archie_init.py for non-Debian post-install setup
- Port all scripts to Linux: getent passwd, systemctl, tail -n +N, gzip
- Add SFTP (libssh2) and FTPS (OpenSSL) scrapers alongside anonftp
- Add Flask web frontend (archie-web.service)
- Fix filter scripts (exec cat replaces broken sed s///g)
- Update all manpages: paths, contacts, add SFTP/FTPS section
- Update etc/: enable gzip, add webindex catalog, fix localhost refs
- Remove: AIX-2/SunOS-4.1.4/SunOS-5.4 dirs, tcl7.6/, tcl-dp/, tk4.2/,
  berkdb/, old Makefile.in/pre/post fragments, build.sh, unwrap scripts
- Add .gitignore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:05:12 +02:00

81 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""FTPS (FTP over TLS, explicit AUTH TLS) test server using pyftpdlib.
Usage:
python3 ftps_server.py [--host 127.0.0.1] [--port 2990] [--root /tmp/ftps-root]
A self-signed certificate is auto-generated at startup if --cert is not given.
Credentials: testuser / testpass
"""
import argparse
import logging
import os
import subprocess
import tempfile
from pyftpdlib.handlers import TLS_FTPHandler
from pyftpdlib.servers import FTPServer
from pyftpdlib.authorizers import DummyAuthorizer
def _generate_selfsigned(certfile, keyfile):
subprocess.run([
"openssl", "req", "-x509", "-newkey", "rsa:2048",
"-keyout", keyfile, "-out", certfile,
"-days", "3650", "-nodes",
"-subj", "/CN=archie-ftps-test"
], check=True, capture_output=True)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--host", default="127.0.0.1")
ap.add_argument("--port", type=int, default=2990)
ap.add_argument("--root", default="/tmp/ftps-root")
ap.add_argument("--cert", default="")
ap.add_argument("--key", default="")
ap.add_argument("--user", default="testuser")
ap.add_argument("--password", default="testpass")
ap.add_argument("--passive-ports", default="61000-61100")
args = ap.parse_args()
os.makedirs(args.root, exist_ok=True)
certfile = args.cert
keyfile = args.key
_tmpdir = None
if not certfile:
_tmpdir = tempfile.mkdtemp(prefix="ftps-certs-")
certfile = os.path.join(_tmpdir, "server.crt")
keyfile = os.path.join(_tmpdir, "server.key")
_generate_selfsigned(certfile, keyfile)
print(f"Generated self-signed cert: {certfile}", flush=True)
low, high = map(int, args.passive_ports.split("-"))
authorizer = DummyAuthorizer()
authorizer.add_user(args.user, args.password, args.root, perm="elradfmw")
authorizer.add_anonymous(args.root, perm="elr")
handler = TLS_FTPHandler
handler.authorizer = authorizer
handler.certfile = certfile
handler.keyfile = keyfile
handler.passive_ports = range(low, high + 1)
handler.tls_control_required = False # allow plain before AUTH TLS
handler.banner = "Archie test FTPS server (explicit TLS)"
logging.basicConfig(level=logging.INFO,
format="%(asctime)s [FTPS] %(message)s")
server = FTPServer((args.host, args.port), handler)
print(f"FTPS server listening on {args.host}:{args.port}, root={args.root}",
flush=True)
server.serve_forever()
if __name__ == "__main__":
main()