HTTPS/CORS improvements: Enable CORS for player connections, secure session cookies, add certificate endpoint, nginx CORS headers
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
# Kiwy-Signage Self-Signed Certificate Support - Code Patches
|
||||
|
||||
This file contains exact code patches ready to apply to enable self-signed certificate support.
|
||||
|
||||
## PATCH 1: Create ssl_config.py
|
||||
|
||||
**File:** `Kiwy-Signage/src/ssl_config.py` (NEW FILE)
|
||||
|
||||
```python
|
||||
"""
|
||||
SSL Configuration Module for Kiwy-Signage
|
||||
Handles certificate verification for self-signed and custom CA certificates
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SSLConfig:
|
||||
"""Manage SSL certificate verification settings"""
|
||||
|
||||
# Default to True (use system CA certificates)
|
||||
_custom_ca_path = None
|
||||
_verify_ssl = True
|
||||
|
||||
@classmethod
|
||||
def get_ca_bundle(cls):
|
||||
"""Get path to CA certificate bundle for verification
|
||||
|
||||
Priority order:
|
||||
1. Custom CA bundle path specified via set_ca_bundle()
|
||||
2. CA bundle path from REQUESTS_CA_BUNDLE environment variable
|
||||
3. CA bundle in config/ca_bundle.crt
|
||||
4. System default CA bundle (True = use system certs)
|
||||
|
||||
Returns:
|
||||
str or bool: Path to CA bundle file or True for system default
|
||||
"""
|
||||
# Check if custom CA was explicitly set
|
||||
if cls._custom_ca_path:
|
||||
if os.path.exists(cls._custom_ca_path):
|
||||
logger.info(f"Using custom CA bundle: {cls._custom_ca_path}")
|
||||
return cls._custom_ca_path
|
||||
else:
|
||||
logger.warning(f"Custom CA bundle not found: {cls._custom_ca_path}, falling back to system")
|
||||
|
||||
# Check environment variable
|
||||
env_ca = os.environ.get('REQUESTS_CA_BUNDLE')
|
||||
if env_ca and os.path.exists(env_ca):
|
||||
logger.info(f"Using CA bundle from REQUESTS_CA_BUNDLE: {env_ca}")
|
||||
return env_ca
|
||||
|
||||
# Check config directory
|
||||
config_ca = 'config/ca_bundle.crt'
|
||||
if os.path.exists(config_ca):
|
||||
logger.info(f"Using CA bundle from config: {config_ca}")
|
||||
return config_ca
|
||||
|
||||
# Use system default
|
||||
logger.debug("Using system default CA certificates")
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def get_verify_setting(cls):
|
||||
"""Get the 'verify' parameter for requests calls
|
||||
|
||||
Returns:
|
||||
bool or str: Value to pass as 'verify=' parameter to requests
|
||||
"""
|
||||
if not cls._verify_ssl:
|
||||
logger.warning("SSL verification is DISABLED - this is insecure!")
|
||||
return False
|
||||
|
||||
return cls.get_ca_bundle()
|
||||
|
||||
@classmethod
|
||||
def set_ca_bundle(cls, ca_path):
|
||||
"""Manually set custom CA bundle path
|
||||
|
||||
Args:
|
||||
ca_path (str): Path to CA certificate file
|
||||
"""
|
||||
if os.path.exists(ca_path):
|
||||
cls._custom_ca_path = ca_path
|
||||
logger.info(f"CA bundle set to: {ca_path}")
|
||||
else:
|
||||
logger.error(f"CA bundle file not found: {ca_path}")
|
||||
|
||||
@classmethod
|
||||
def disable_verification(cls):
|
||||
"""DANGER: Disable SSL certificate verification
|
||||
|
||||
⚠️ WARNING: Only use for development/testing!
|
||||
This makes the application vulnerable to MITM attacks.
|
||||
"""
|
||||
cls._verify_ssl = False
|
||||
logger.critical("⚠️ SSL VERIFICATION DISABLED - This is insecure!")
|
||||
|
||||
@classmethod
|
||||
def enable_verification(cls):
|
||||
"""Enable SSL certificate verification (default)"""
|
||||
cls._verify_ssl = True
|
||||
logger.info("SSL verification enabled")
|
||||
|
||||
@classmethod
|
||||
def is_verification_enabled(cls):
|
||||
"""Check if SSL verification is enabled
|
||||
|
||||
Returns:
|
||||
bool: True if verification is enabled, False if disabled
|
||||
"""
|
||||
return cls._verify_ssl
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PATCH 2: Modify src/player_auth.py
|
||||
|
||||
**Location:** `Kiwy-Signage/src/player_auth.py`
|
||||
|
||||
### Change 2a: Add import at top of file
|
||||
|
||||
```python
|
||||
# AFTER line 10 (after existing imports), ADD:
|
||||
|
||||
from ssl_config import SSLConfig
|
||||
```
|
||||
|
||||
### Change 2b: Modify __init__ method (lines 20-30)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
def __init__(self, config_file: str = 'player_auth.json'):
|
||||
"""Initialize player authentication.
|
||||
|
||||
Args:
|
||||
config_file: Path to authentication config file
|
||||
"""
|
||||
self.config_file = config_file
|
||||
self.auth_data = self._load_auth_data()
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
def __init__(self, config_file: str = 'player_auth.json'):
|
||||
"""Initialize player authentication.
|
||||
|
||||
Args:
|
||||
config_file: Path to authentication config file
|
||||
"""
|
||||
self.config_file = config_file
|
||||
self.auth_data = self._load_auth_data()
|
||||
self.verify_ssl = SSLConfig.get_verify_setting()
|
||||
```
|
||||
|
||||
### Change 2c: Modify authenticate() method (line 95)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
response = requests.post(auth_url, json=payload, timeout=timeout)
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
response = requests.post(auth_url, json=payload, timeout=timeout, verify=self.verify_ssl)
|
||||
```
|
||||
|
||||
### Change 2d: Modify verify_auth() method (line 157)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
response = requests.post(verify_url, json=payload, timeout=timeout)
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
response = requests.post(verify_url, json=payload, timeout=timeout, verify=self.verify_ssl)
|
||||
```
|
||||
|
||||
### Change 2e: Modify get_playlist() method (line 178)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
response = requests.get(playlist_url, headers=headers, timeout=timeout)
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
response = requests.get(playlist_url, headers=headers, timeout=timeout, verify=self.verify_ssl)
|
||||
```
|
||||
|
||||
### Change 2f: Modify send_heartbeat() method (line 227-228)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
response = requests.post(heartbeat_url, headers=headers,
|
||||
json=payload, timeout=timeout)
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
response = requests.post(heartbeat_url, headers=headers,
|
||||
json=payload, timeout=timeout, verify=self.verify_ssl)
|
||||
```
|
||||
|
||||
### Change 2g: Modify send_feedback() method (line 254-255)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
response = requests.post(feedback_url, headers=headers,
|
||||
json=payload, timeout=timeout)
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
response = requests.post(feedback_url, headers=headers,
|
||||
json=payload, timeout=timeout, verify=self.verify_ssl)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PATCH 3: Modify src/get_playlists_v2.py
|
||||
|
||||
**Location:** `Kiwy-Signage/src/get_playlists_v2.py`
|
||||
|
||||
### Change 3a: Add import (after line 6)
|
||||
|
||||
```python
|
||||
# AFTER line 6 (after "from player_auth import PlayerAuth"), ADD:
|
||||
|
||||
from ssl_config import SSLConfig
|
||||
```
|
||||
|
||||
### Change 3b: Modify download_media_files() function (line 159)
|
||||
|
||||
**BEFORE:**
|
||||
```python
|
||||
response = requests.get(file_url, timeout=30)
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```python
|
||||
verify_ssl = SSLConfig.get_verify_setting()
|
||||
response = requests.get(file_url, timeout=30, verify=verify_ssl)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PATCH 4: Extract Server Certificate
|
||||
|
||||
**Steps to follow on the DigiServer:**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Run this on the DigiServer with self-signed certificate
|
||||
|
||||
# Export the certificate
|
||||
openssl s_client -connect localhost:443 -showcerts < /dev/null | \
|
||||
openssl x509 -outform PEM > /tmp/server_cert.crt
|
||||
|
||||
# Copy to player configuration directory
|
||||
# (transfer via SSH, USB, or other secure method)
|
||||
cp /tmp/server_cert.crt /path/to/Kiwy-Signage/config/ca_bundle.crt
|
||||
|
||||
# Verify it was copied correctly
|
||||
ls -la /path/to/Kiwy-Signage/config/ca_bundle.crt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PATCH 5: Alternative - Use Environment Variable
|
||||
|
||||
Instead of placing cert in config directory, you can use environment variable:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Before running the player:
|
||||
|
||||
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/custom-ca.crt
|
||||
cd /path/to/Kiwy-Signage
|
||||
./start.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing After Patches
|
||||
|
||||
### Test 1: Verify patches applied correctly
|
||||
|
||||
```bash
|
||||
cd /tmp/Kiwy-Signage/src
|
||||
|
||||
# Check imports added
|
||||
grep "from ssl_config import SSLConfig" player_auth.py
|
||||
grep "from ssl_config import SSLConfig" get_playlists_v2.py
|
||||
|
||||
# Check verify parameter added
|
||||
grep "verify=self.verify_ssl" player_auth.py | wc -l
|
||||
# Should output: 5
|
||||
|
||||
# Check new file exists
|
||||
test -f ssl_config.py && echo "ssl_config.py exists" || echo "MISSING"
|
||||
```
|
||||
|
||||
### Test 2: Test with self-signed server
|
||||
|
||||
```bash
|
||||
cd /tmp/Kiwy-Signage
|
||||
|
||||
# 1. Export server cert (run on server)
|
||||
openssl s_client -connect server.local:443 -showcerts < /dev/null | \
|
||||
openssl x509 -outform PEM > config/ca_bundle.crt
|
||||
|
||||
# 2. Test player connection
|
||||
python3 -c "
|
||||
import sys
|
||||
sys.path.insert(0, 'src')
|
||||
from player_auth import PlayerAuth
|
||||
from ssl_config import SSLConfig
|
||||
|
||||
# Check what certificate will be used
|
||||
cert_path = SSLConfig.get_ca_bundle()
|
||||
print(f'Using certificate: {cert_path}')
|
||||
|
||||
# Try authentication
|
||||
auth = PlayerAuth()
|
||||
success, error = auth.authenticate(
|
||||
server_url='https://server.local:443',
|
||||
hostname='test-player',
|
||||
quickconnect_code='TEST123'
|
||||
)
|
||||
print(f'Connection result: {\"SUCCESS\" if success else \"FAILED\"}')
|
||||
if error:
|
||||
print(f'Error: {error}')
|
||||
"
|
||||
```
|
||||
|
||||
### Test 3: Verify backward compatibility
|
||||
|
||||
```bash
|
||||
cd /tmp/Kiwy-Signage
|
||||
|
||||
# Test connection to production server (valid CA cert)
|
||||
python3 -c "
|
||||
import sys
|
||||
sys.path.insert(0, 'src')
|
||||
from player_auth import PlayerAuth
|
||||
|
||||
auth = PlayerAuth()
|
||||
success, error = auth.authenticate(
|
||||
server_url='https://digi-signage.moto-adv.com',
|
||||
hostname='test-player',
|
||||
quickconnect_code='TEST123'
|
||||
)
|
||||
print(f'Production server: {\"OK\" if success else \"FAILED\"}')
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary of Changes
|
||||
|
||||
| File | Type | Changes | Complexity |
|
||||
|------|------|---------|------------|
|
||||
| `src/ssl_config.py` | NEW | Full file (~60 lines) | Low |
|
||||
| `src/player_auth.py` | MODIFY | 7 small changes | Low |
|
||||
| `src/get_playlists_v2.py` | MODIFY | 2 small changes | Low |
|
||||
| `config/ca_bundle.crt` | NEW | Certificate file | N/A |
|
||||
|
||||
**Total lines of code modified:** ~8 lines
|
||||
**New code added:** ~60 lines
|
||||
**Breaking changes:** None
|
||||
**Backward compatible:** Yes
|
||||
|
||||
---
|
||||
|
||||
## Rollback Instructions
|
||||
|
||||
If you need to revert the changes:
|
||||
|
||||
```bash
|
||||
cd /tmp/Kiwy-Signage
|
||||
|
||||
# Restore original files from git
|
||||
git checkout src/player_auth.py
|
||||
git checkout src/get_playlists_v2.py
|
||||
|
||||
# Remove new file
|
||||
rm src/ssl_config.py
|
||||
|
||||
# Remove certificate file (optional)
|
||||
rm config/ca_bundle.crt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
- [ ] Read the full analysis (KIWY_PLAYER_HTTPS_ANALYSIS.md)
|
||||
- [ ] Review this patch file
|
||||
- [ ] Create `src/ssl_config.py` (PATCH 1)
|
||||
- [ ] Apply changes to `src/player_auth.py` (PATCH 2)
|
||||
- [ ] Apply changes to `src/get_playlists_v2.py` (PATCH 3)
|
||||
- [ ] Export server certificate (PATCH 4)
|
||||
- [ ] Place certificate in `config/ca_bundle.crt`
|
||||
- [ ] Run Test 1: Verify patches applied
|
||||
- [ ] Run Test 2: Test with self-signed server
|
||||
- [ ] Run Test 3: Test with production server
|
||||
- [ ] Update player documentation
|
||||
- [ ] Deploy to test player
|
||||
- [ ] Monitor player logs for SSL errors
|
||||
|
||||
Reference in New Issue
Block a user