Skip to content

Instantly share code, notes, and snippets.

@one2blame
Last active September 29, 2023 17:14
Show Gist options
  • Save one2blame/09f149dd2c37ce4c2f3f23d8553456fa to your computer and use it in GitHub Desktop.
Save one2blame/09f149dd2c37ce4c2f3f23d8553456fa to your computer and use it in GitHub Desktop.
simple-https-server.py
#!/usr/bin/env python3
# Requires Python 3.7 or greater
import ssl
import subprocess
import time
from argparse import ArgumentParser, Namespace
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
SERVER_DIRECTORY = ""
class HTTPDirectoryHandler(SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=SERVER_DIRECTORY, **kwargs)
def get_parsed_args() -> Namespace:
parser = ArgumentParser(
prog="simple-https-server",
description="automates the creation of an HTTPS server, openssl certs and all",
)
parser.add_argument(
"--ip-address", "-i", default="0.0.0.0", help="Specify IP address to serve from"
)
parser.add_argument("--port", "-p", default=443, help="Specify port to serve from")
parser.add_argument(
"--server-version",
"-s",
default=f"{SimpleHTTPRequestHandler.server_version}",
help="Specify 'Server' string in HTTP response header",
)
parser.add_argument(
"--server-directory",
"-d",
default=f"{str(Path.cwd())}",
help="Specify directory to serve",
)
parser.add_argument(
"--cert", "-c", default=None, help="Specify certificate (*.pem)"
)
parser.add_argument(
"--cert-directory",
"-e",
default="/tmp",
help="Specify directory to store certificate",
)
parser.add_argument(
"--domain-name",
"-n",
default="example.com",
help="Specify domain name for certificate",
)
return parser.parse_args()
def create_cert(opts: Namespace) -> str:
try:
certificate_path = Path.joinpath(
Path(opts.cert_directory), f"simple-https-server-{int(time.time())}.pem"
).resolve()
process = subprocess.run(
args=[
"openssl",
"req",
"-x509",
"-newkey",
"rsa:4096",
"-sha256",
"-days",
"3650",
"-nodes",
"-keyout",
f"{str(certificate_path)}",
"-out",
f"{str(certificate_path)}",
"-subj",
f"/CN={opts.domain_name}",
"-addext",
f"subjectAltName=DNS:{opts.domain_name},DNS:www.{opts.domain_name},IP:{opts.ip_address}",
],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
process.check_returncode()
except subprocess.CalledProcessError:
raise (RuntimeError("[!] Failed to create certificate with openssl!"))
print(f"[+] Successfully created new certificate at: {str(certificate_path)}")
return str(certificate_path)
if __name__ == "__main__":
opts = get_parsed_args()
if not opts.cert:
opts.cert = create_cert(opts)
else:
opts.cert = Path(opts.cert).resolve()
if not opts.cert.exists():
raise (
FileNotFoundError(
f"[-] Certificate provided '{opts.cert}' does not exist!"
)
)
SERVER_DIRECTORY = opts.server_directory
request_handler = HTTPDirectoryHandler
request_handler.server_version = opts.server_version
request_handler.sys_version = ""
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.check_hostname = False
try:
httpd = HTTPServer((opts.ip_address, int(opts.port)), request_handler)
context.load_cert_chain(certfile=str(opts.cert))
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
print(
f"[*] Serving directory: '{opts.server_directory}' via HTTPS at port: '{opts.port}'..."
)
httpd.serve_forever()
except OverflowError:
raise (RuntimeError(f"[-] Port provided '{int(opts.port)}' too large!"))
except Exception as e:
raise (Exception(f"[-] Unhandled Exception: {e}"))
exit(0)
@one2blame
Copy link
Author

one2blame commented Feb 12, 2022

Useful for privately and quickly transferring things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment