From cca9d94b36febf90120f92de4866c2e41b632bfa Mon Sep 17 00:00:00 2001 From: C <0xicl33n@gmail.com> Date: Sat, 20 Dec 2025 12:51:26 -0800 Subject: [PATCH] ugh damn ssl shit --- HTTPS_SETUP.md | 125 +++++++++++++++++++++++++++++++++++++++++++++ generate_cert.py | 60 ++++++++++++++++++++++ src/test_server.py | 59 +++++++++++++++++---- 3 files changed, 235 insertions(+), 9 deletions(-) create mode 100644 HTTPS_SETUP.md create mode 100644 generate_cert.py diff --git a/HTTPS_SETUP.md b/HTTPS_SETUP.md new file mode 100644 index 0000000..8ac5027 --- /dev/null +++ b/HTTPS_SETUP.md @@ -0,0 +1,125 @@ +# HTTPS Webhook Setup Guide + +## Quick Start (Self-Signed Certificate for Testing) + +### 1. Generate Certificate +```powershell +python generate_cert.py +``` + +This creates `cert.pem` and `key.pem` files. + +### 2. Run Server with HTTPS + +#### Option A: HTTPS for webhook only (recommended for development) +```powershell +python src/test_server.py --ssl-cert cert.pem --ssl-key key.pem --hook-port 8443 --hook-ssl-only +``` +- Main server: `http://localhost:7432/` (HTTP) +- Webhook: `https://localhost:8443/hook` (HTTPS) + +#### Option B: HTTPS for everything +```powershell +python src/test_server.py --ssl-cert cert.pem --ssl-key key.pem --hook-port 8443 +``` +- Main server: `https://localhost:7432/` (HTTPS) +- Webhook: `https://localhost:8443/hook` (HTTPS) + +#### Option C: Single port with HTTPS +```powershell +python src/test_server.py --ssl-cert cert.pem --ssl-key key.pem +``` +- Everything on: `https://localhost:7432/` + +### 3. Test the Webhook + +Update `src/test_webhook.py` to use HTTPS: +```python +url = "https://localhost:8443/hook" +``` + +Then run: +```powershell +python src/test_webhook.py +``` + +## Production Setup (with Real Certificate) + +### Option 1: Let's Encrypt (Free, Recommended) + +On Linux/WSL: +```bash +# Install certbot +sudo apt-get install certbot + +# Generate certificate (replace yourdomain.com) +sudo certbot certonly --standalone -d yourdomain.com + +# Certificates will be at: +# /etc/letsencrypt/live/yourdomain.com/fullchain.pem +# /etc/letsencrypt/live/yourdomain.com/privkey.pem + +# Run server +python src/test_server.py \ + --ssl-cert /etc/letsencrypt/live/yourdomain.com/fullchain.pem \ + --ssl-key /etc/letsencrypt/live/yourdomain.com/privkey.pem \ + --host 0.0.0.0 \ + --hook-port 443 \ + --hook-ssl-only +``` + +### Option 2: Reverse Proxy (nginx/Caddy) + +Run studspider on HTTP internally, use nginx/Caddy for HTTPS: + +```nginx +# nginx config +server { + listen 443 ssl; + server_name yourdomain.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + location /hook { + proxy_pass http://localhost:7432/hook; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +``` + +Then run studspider normally: +```powershell +python src/test_server.py +``` + +## Troubleshooting + +### "OpenSSL not found" Error +- **Windows**: Install from https://slproweb.com/products/Win32OpenSSL.html +- **Alternative**: Use Git Bash or WSL which include OpenSSL + +### Self-Signed Certificate Warnings +- Normal for development +- Use `--insecure` flag with curl/tools for testing +- For production, get a proper certificate from Let's Encrypt + +### Port 443 Already in Use +- Use a different port like 8443 +- Or stop the service using port 443 + +### Certificate File Not Found +- Use absolute paths: `--ssl-cert C:\path\to\cert.pem` +- Or run from the directory containing the certificates + +## Square Webhook Configuration + +When setting up webhooks in Square Dashboard: +1. Use your HTTPS URL: `https://yourdomain.com:8443/hook` +2. Square requires valid SSL (not self-signed) +3. Consider using ngrok for local testing: + ```powershell + ngrok http 8443 + ``` + Then use the ngrok HTTPS URL in Square Dashboard diff --git a/generate_cert.py b/generate_cert.py new file mode 100644 index 0000000..78e1e13 --- /dev/null +++ b/generate_cert.py @@ -0,0 +1,60 @@ +""" +Generate self-signed SSL certificate for testing HTTPS webhooks +Run this script to create cert.pem and key.pem files +""" + +import subprocess +import sys +import os + +def generate_certificate(): + """Generate self-signed certificate using OpenSSL""" + + cert_file = "cert.pem" + key_file = "key.pem" + + # Check if OpenSSL is available + try: + subprocess.run(["openssl", "version"], + capture_output=True, check=True) + except (subprocess.CalledProcessError, FileNotFoundError): + print("ERROR: OpenSSL not found!") + print("\nFor Windows, you can:") + print("1. Install OpenSSL from: https://slproweb.com/products/Win32OpenSSL.html") + print("2. Or use Git Bash which includes OpenSSL") + print("3. Or use WSL (Windows Subsystem for Linux)") + return False + + print("Generating self-signed certificate...") + print("This will create cert.pem and key.pem files") + print() + + # Generate certificate valid for 365 days + cmd = [ + "openssl", "req", "-x509", + "-newkey", "rsa:4096", + "-keyout", key_file, + "-out", cert_file, + "-days", "365", + "-nodes", # No passphrase + "-subj", "/C=US/ST=State/L=City/O=Organization/CN=localhost" + ] + + try: + subprocess.run(cmd, check=True) + print(f"\nāœ“ Certificate created: {os.path.abspath(cert_file)}") + print(f"āœ“ Private key created: {os.path.abspath(key_file)}") + print("\nYou can now run the server with HTTPS:") + print(f" python src/test_server.py --ssl-cert {cert_file} --ssl-key {key_file} --hook-port 8443") + print("\nOr webhook-only HTTPS:") + print(f" python src/test_server.py --ssl-cert {cert_file} --ssl-key {key_file} --hook-port 8443 --hook-ssl-only") + print("\nNote: Self-signed certificates will show security warnings in browsers.") + print("For production, use certificates from a trusted CA like Let's Encrypt.") + return True + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to generate certificate: {e}") + return False + +if __name__ == "__main__": + if not generate_certificate(): + sys.exit(1) diff --git a/src/test_server.py b/src/test_server.py index f12087b..94942c7 100644 --- a/src/test_server.py +++ b/src/test_server.py @@ -1,6 +1,7 @@ import argparse import asyncio import json +import ssl from aiohttp import web from base64 import b64decode from typing import Dict, Any @@ -240,16 +241,48 @@ parser.add_argument( default=8080, help="Optional separate port for webhook endpoint. default: 8080", ) +parser.add_argument( + "--ssl-cert", + type=str, + default=None, + help="Path to SSL certificate file for HTTPS (PEM format)", +) +parser.add_argument( + "--ssl-key", + type=str, + default=None, + help="Path to SSL private key file for HTTPS (PEM format)", +) +parser.add_argument( + "--hook-ssl-only", + action="store_true", + help="Enable HTTPS only for webhook endpoint (main server stays HTTP)", +) args = parser.parse_args() if __name__ == "__main__": print(banner.generate("studspider v0.1")) print("Built for PLAY-WELL TEKNOLOGIES by contact@traps.moe\n\n") + # Setup SSL context if certificates provided + ssl_context = None + if args.ssl_cert and args.ssl_key: + ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_context.load_cert_chain(args.ssl_cert, args.ssl_key) + print(f"SSL enabled with cert: {args.ssl_cert}") + elif args.ssl_cert or args.ssl_key: + print("ERROR: Both --ssl-cert and --ssl-key must be provided together") + exit(1) + # If hook-port is specified, run a separate server for webhooks if args.hook_port: - print(f"Starting main server on {args.host}:{args.port}") - print(f"Starting webhook server on {args.host}:{args.hook_port}") + protocol_main = "https" if (ssl_context and not args.hook_ssl_only) else "http" + protocol_hook = "https" if ssl_context else "http" + + print(f"Starting main server on {args.host}:{args.port} ({protocol_main})") + print( + f"Starting webhook server on {args.host}:{args.hook_port} ({protocol_hook})" + ) # Create separate app for webhook hook_app = web.Application() @@ -259,23 +292,31 @@ if __name__ == "__main__": async def run_servers(): runner1 = web.AppRunner(app) await runner1.setup() - site1 = web.TCPSite(runner1, args.host, args.port) + # Main server uses SSL only if not hook-ssl-only mode + main_ssl = None if args.hook_ssl_only else ssl_context + site1 = web.TCPSite(runner1, args.host, args.port, ssl_context=main_ssl) runner2 = web.AppRunner(hook_app) await runner2.setup() - site2 = web.TCPSite(runner2, args.host, args.hook_port) + # Webhook server always uses SSL if certificates provided + site2 = web.TCPSite( + runner2, args.host, args.hook_port, ssl_context=ssl_context + ) await site1.start() await site2.start() - print(f"Main server running on http://{args.host}:{args.port}") - print(f"Webhook server running on http://{args.host}:{args.hook_port}/hook") + print(f"Main server running on {protocol_main}://{args.host}:{args.port}") + print( + f"Webhook server running on {protocol_hook}://{args.host}:{args.hook_port}/hook" + ) # Keep running await asyncio.Event().wait() asyncio.run(run_servers()) else: - print(f"Server running on {args.host}:{args.port}") - print(f"Webhook endpoint: http://{args.host}:{args.port}/hook") - web.run_app(app, host=args.host, port=args.port) + protocol = "https" if ssl_context else "http" + print(f"Server running on {args.host}:{args.port} ({protocol})") + print(f"Webhook endpoint: {protocol}://{args.host}:{args.port}/hook") + web.run_app(app, host=args.host, port=args.port, ssl_context=ssl_context)