ugh damn ssl shit

This commit is contained in:
C committed 2025-12-20 12:51:26 -08:00
1 parent 2da85c4d84
commit cca9d94b36
3 files changed
+235 -9

No files matched your search

+125
View File
@@ -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
+60
View File
@@ -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)
+50 -9
View File
@@ -1,6 +1,7 @@
import argparse import argparse
import asyncio import asyncio
import json import json
import ssl
from aiohttp import web from aiohttp import web
from base64 import b64decode from base64 import b64decode
from typing import Dict, Any from typing import Dict, Any
@@ -240,16 +241,48 @@ parser.add_argument(
default=8080, default=8080,
help="Optional separate port for webhook endpoint. 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() args = parser.parse_args()
if __name__ == "__main__": if __name__ == "__main__":
print(banner.generate("studspider v0.1")) print(banner.generate("studspider v0.1"))
print("Built for PLAY-WELL TEKNOLOGIES by contact@traps.moe\n\n") 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 hook-port is specified, run a separate server for webhooks
if args.hook_port: if args.hook_port:
print(f"Starting main server on {args.host}:{args.port}") protocol_main = "https" if (ssl_context and not args.hook_ssl_only) else "http"
print(f"Starting webhook server on {args.host}:{args.hook_port}") 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 # Create separate app for webhook
hook_app = web.Application() hook_app = web.Application()
@@ -259,23 +292,31 @@ if __name__ == "__main__":
async def run_servers(): async def run_servers():
runner1 = web.AppRunner(app) runner1 = web.AppRunner(app)
await runner1.setup() 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) runner2 = web.AppRunner(hook_app)
await runner2.setup() 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 site1.start()
await site2.start() await site2.start()
print(f"Main server running on http://{args.host}:{args.port}") print(f"Main server running on {protocol_main}://{args.host}:{args.port}")
print(f"Webhook server running on http://{args.host}:{args.hook_port}/hook") print(
f"Webhook server running on {protocol_hook}://{args.host}:{args.hook_port}/hook"
)
# Keep running # Keep running
await asyncio.Event().wait() await asyncio.Event().wait()
asyncio.run(run_servers()) asyncio.run(run_servers())
else: else:
print(f"Server running on {args.host}:{args.port}") protocol = "https" if ssl_context else "http"
print(f"Webhook endpoint: http://{args.host}:{args.port}/hook") print(f"Server running on {args.host}:{args.port} ({protocol})")
web.run_app(app, host=args.host, port=args.port) print(f"Webhook endpoint: {protocol}://{args.host}:{args.port}/hook")
web.run_app(app, host=args.host, port=args.port, ssl_context=ssl_context)