First cleanup iteration
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 148 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB |
-143
@@ -1,143 +0,0 @@
|
|||||||
"""Development HTTPS server for testing production settings locally.
|
|
||||||
|
|
||||||
Generates a self-signed certificate (if not present) and runs the
|
|
||||||
application via Waitress wrapped in a TLS socket. This simulates the
|
|
||||||
production environment where Nginx handles TLS termination.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
python run_https.py
|
|
||||||
|
|
||||||
The server will listen on https://localhost:8443
|
|
||||||
Accept the self-signed certificate warning in your browser to proceed.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import ssl
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from waitress.server import create_server
|
|
||||||
|
|
||||||
from app.app import create_app
|
|
||||||
|
|
||||||
CERT_FILE = 'certs/localhost.pem'
|
|
||||||
KEY_FILE = 'certs/localhost-key.pem'
|
|
||||||
|
|
||||||
|
|
||||||
def generate_self_signed_cert():
|
|
||||||
"""Generate a self-signed certificate for local HTTPS testing.
|
|
||||||
|
|
||||||
Uses OpenSSL to create a key and certificate valid for 365 days.
|
|
||||||
Skips generation if certificate files already exist.
|
|
||||||
"""
|
|
||||||
if os.path.exists(CERT_FILE) and os.path.exists(KEY_FILE):
|
|
||||||
print('[OK] Self-signed certificate already exists.')
|
|
||||||
return
|
|
||||||
|
|
||||||
os.makedirs('certs', exist_ok=True)
|
|
||||||
|
|
||||||
print('[INFO] Generating self-signed certificate for localhost...')
|
|
||||||
try:
|
|
||||||
subprocess.run(
|
|
||||||
[
|
|
||||||
'openssl',
|
|
||||||
'req',
|
|
||||||
'-x509',
|
|
||||||
'-newkey',
|
|
||||||
'rsa:2048',
|
|
||||||
'-keyout',
|
|
||||||
KEY_FILE,
|
|
||||||
'-out',
|
|
||||||
CERT_FILE,
|
|
||||||
'-days',
|
|
||||||
'365',
|
|
||||||
'-nodes',
|
|
||||||
'-subj',
|
|
||||||
'/CN=localhost',
|
|
||||||
],
|
|
||||||
check=True,
|
|
||||||
capture_output=True,
|
|
||||||
)
|
|
||||||
print('[OK] Certificate generated: certs/localhost.pem')
|
|
||||||
except FileNotFoundError:
|
|
||||||
print('[ERROR] OpenSSL not found. Install OpenSSL or use:')
|
|
||||||
print(' winget install OpenSSL.OpenSSL')
|
|
||||||
print(' OR download from https://slproweb.com/products/Win32OpenSSL.html')
|
|
||||||
sys.exit(1)
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f'[ERROR] Certificate generation failed: {e}')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Start the HTTPS development server."""
|
|
||||||
port = int(os.getenv('HTTPS_PORT', 8443))
|
|
||||||
host = os.getenv('HOST', '127.0.0.1')
|
|
||||||
|
|
||||||
# Ensure certificate exists
|
|
||||||
generate_self_signed_cert()
|
|
||||||
|
|
||||||
# Create the Flask application
|
|
||||||
app = create_app()
|
|
||||||
|
|
||||||
# Create SSL context
|
|
||||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
|
||||||
context.load_cert_chain(CERT_FILE, KEY_FILE)
|
|
||||||
|
|
||||||
# Create a TCP socket, wrap it with TLS, then pass to Waitress
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
sock.bind((host, port))
|
|
||||||
sock.listen(5)
|
|
||||||
|
|
||||||
# Wrap the socket with TLS
|
|
||||||
ssl_sock = context.wrap_socket(sock, server_side=True)
|
|
||||||
|
|
||||||
# =====================================================================
|
|
||||||
# WSGI Middleware: Tell Flask the connection is HTTPS
|
|
||||||
#
|
|
||||||
# Waitress doesn't know the underlying socket is TLS, so Flask sees
|
|
||||||
# wsgi.url_scheme = "http". Without this middleware, force_https()
|
|
||||||
# would cause an infinite redirect loop (ERR_TOO_MANY_REDIRECTS).
|
|
||||||
# =====================================================================
|
|
||||||
class ForceHTTPSMiddleware:
|
|
||||||
"""WSGI middleware that sets url_scheme to 'https'.
|
|
||||||
|
|
||||||
Since we're wrapping the TCP socket with SSL before passing it
|
|
||||||
to Waitress, Flask's request.is_secure returns False because
|
|
||||||
Waitress reports wsgi.url_scheme='http'. This middleware fixes
|
|
||||||
that so Flask correctly identifies the connection as HTTPS.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, wsgi_app):
|
|
||||||
self.wsgi_app = wsgi_app
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
environ['wsgi.url_scheme'] = 'https'
|
|
||||||
environ['HTTPS'] = 'on'
|
|
||||||
return self.wsgi_app(environ, start_response)
|
|
||||||
|
|
||||||
# Wrap the Flask app with the HTTPS middleware
|
|
||||||
app.wsgi_app = ForceHTTPSMiddleware(app.wsgi_app)
|
|
||||||
|
|
||||||
print('\n╔══════════════════════════════════════════════════════╗')
|
|
||||||
print('║ TEAM TRYOUTS - Development HTTPS Server ║')
|
|
||||||
print('╠══════════════════════════════════════════════════════╣')
|
|
||||||
print(f'║ URL: https://{host}:{port} ║')
|
|
||||||
print('║ Cert: self-signed (accept browser warning) ║')
|
|
||||||
print('║ Press Ctrl+C to stop ║')
|
|
||||||
print('╚══════════════════════════════════════════════════════╝\n')
|
|
||||||
|
|
||||||
# Create Waitress server with the SSL-wrapped socket
|
|
||||||
server = create_server(
|
|
||||||
app,
|
|
||||||
sockets=[ssl_sock],
|
|
||||||
threads=4,
|
|
||||||
channel_timeout=30,
|
|
||||||
)
|
|
||||||
server.run()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
Reference in New Issue
Block a user