- 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>
81 lines
2.5 KiB
Python
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()
|