Füge Unterstützung für SSL/TLS in die Konfiguration und das Build-System ein
- Integriere die libwebsockets-Bibliothek für SSL/TLS WebSocket-Unterstützung in `CMakeLists.txt`. - Aktualisiere `chatconfig.json`, um SSL-Optionen wie `ssl_enabled`, `ssl_cert_path` und `ssl_key_path` hinzuzufügen. - Ergänze das `deploy.sh`-Skript um einen Schritt zur optionalen Einrichtung von SSL/TLS. - Modifiziere `update_config.sh`, um die SSL-Konfiguration in die Servereinstellungen zu integrieren. - Implementiere eine Überprüfung in `main.cpp`, um den SSL-Status zu prüfen und entsprechende Meldungen auszugeben.
This commit is contained in:
@@ -39,6 +39,12 @@ endif()
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(yourchat OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
# Link libwebsockets for SSL/TLS WebSocket support
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LWS REQUIRED libwebsockets)
|
||||
target_include_directories(yourchat PRIVATE ${LWS_INCLUDE_DIRS})
|
||||
target_link_libraries(yourchat ${LWS_LIBRARIES})
|
||||
|
||||
add_executable(ws_probe tools/ws_probe.cpp)
|
||||
target_compile_features(ws_probe PRIVATE cxx_std_17)
|
||||
target_link_libraries(ws_probe pthread)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"server": {
|
||||
"port": 1235
|
||||
"port": 1235,
|
||||
"ssl_enabled": false,
|
||||
"ssl_cert_path": "/etc/yourpart/server.crt",
|
||||
"ssl_key_path": "/etc/yourpart/server.key"
|
||||
},
|
||||
"database": {
|
||||
"user": "yourpart",
|
||||
|
||||
@@ -40,6 +40,16 @@ echo "=== Schritt 4: Konfiguration aktualisieren ==="
|
||||
echo "Führe update_config.sh aus..."
|
||||
./deploy/update_config.sh
|
||||
|
||||
echo ""
|
||||
echo "=== Schritt 5: SSL-Setup (optional) ==="
|
||||
echo "Möchten Sie SSL/TLS für sichere Verbindungen einrichten? (y/N)"
|
||||
read -p "SSL einrichten? " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Führe SSL-Setup aus..."
|
||||
./deploy/setup-ssl.sh
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Deployment abgeschlossen! ==="
|
||||
echo ""
|
||||
|
||||
@@ -34,7 +34,7 @@ sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-13 130
|
||||
|
||||
echo "=== Bibliotheken installieren ==="
|
||||
# Benötigte Bibliotheken
|
||||
sudo apt install -y libssl-dev libjsoncpp-dev libpqxx-dev
|
||||
sudo apt install -y libssl-dev libjsoncpp-dev libpqxx-dev libwebsockets-dev
|
||||
|
||||
echo "=== PostgreSQL installieren (falls nicht vorhanden) ==="
|
||||
# PostgreSQL (falls Datenbank lokal laufen soll)
|
||||
|
||||
419
deploy/setup-ssl.sh
Executable file
419
deploy/setup-ssl.sh
Executable file
@@ -0,0 +1,419 @@
|
||||
#!/bin/bash
|
||||
|
||||
# SSL/TLS Setup Script für YourChat
|
||||
# Erstellt oder verwaltet SSL-Zertifikate für sichere Chat-Verbindungen
|
||||
# Unterstützt Self-Signed Certificates und Let's Encrypt
|
||||
|
||||
set -e
|
||||
|
||||
# Farben für Logging
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
CERT_DIR="/etc/yourpart"
|
||||
CERT_FILE="$CERT_DIR/server.crt"
|
||||
KEY_FILE="$CERT_DIR/server.key"
|
||||
CSR_FILE="$CERT_DIR/server.csr"
|
||||
|
||||
# Let's Encrypt Verzeichnisse
|
||||
LETSENCRYPT_DIR="/etc/letsencrypt/live"
|
||||
LETSENCRYPT_CERT="$LETSENCRYPT_DIR/your-part.de/fullchain.pem"
|
||||
LETSENCRYPT_KEY="$LETSENCRYPT_DIR/your-part.de/privkey.pem"
|
||||
|
||||
# Apache2 Zertifikate (Ubuntu/Debian)
|
||||
APACHE2_CERT_PATHS=(
|
||||
"/etc/letsencrypt/live/your-part.de/fullchain.pem"
|
||||
"/etc/letsencrypt/live/$(hostname)/fullchain.pem"
|
||||
"/etc/apache2/ssl/apache.crt"
|
||||
"/etc/httpd/ssl/apache.crt"
|
||||
"/etc/ssl/certs/apache-selfsigned.crt"
|
||||
"/etc/ssl/certs/ssl-cert-snakeoil.pem"
|
||||
)
|
||||
|
||||
APACHE2_KEY_PATHS=(
|
||||
"/etc/letsencrypt/live/your-part.de/privkey.pem"
|
||||
"/etc/letsencrypt/live/$(hostname)/privkey.pem"
|
||||
"/etc/apache2/ssl/apache.key"
|
||||
"/etc/httpd/ssl/apache.key"
|
||||
"/etc/ssl/private/apache-selfsigned.key"
|
||||
"/etc/ssl/private/ssl-cert-snakeoil.key"
|
||||
)
|
||||
|
||||
# Prüfe ob OpenSSL installiert ist
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
log_error "OpenSSL ist nicht installiert!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prüfe ob wir sudo-Rechte haben
|
||||
if ! sudo -n true 2>/dev/null; then
|
||||
log_info "Einige Operationen benötigen sudo-Rechte für SSL-Verzeichnisse..."
|
||||
fi
|
||||
|
||||
# Funktionen
|
||||
setup_letsencrypt() {
|
||||
log_info "Let's Encrypt Setup für your-part.de"
|
||||
|
||||
# Prüfe ob certbot installiert ist
|
||||
if ! command -v certbot &> /dev/null; then
|
||||
log_error "Certbot ist nicht installiert!"
|
||||
log_info "Installiere Certbot..."
|
||||
if command -v apt &> /dev/null; then
|
||||
sudo apt update
|
||||
sudo apt install -y certbot
|
||||
elif command -v zypper &> /dev/null; then
|
||||
sudo zypper install -y certbot
|
||||
else
|
||||
log_error "Paketmanager nicht unterstützt. Installiere Certbot manuell."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prüfe ob Let's Encrypt Zertifikate bereits existieren
|
||||
if [ -f "$LETSENCRYPT_CERT" ] && [ -f "$LETSENCRYPT_KEY" ]; then
|
||||
log_info "Let's Encrypt Zertifikate existieren bereits"
|
||||
|
||||
# Prüfe Gültigkeit
|
||||
if openssl x509 -in "$LETSENCRYPT_CERT" -text -noout &> /dev/null; then
|
||||
log_success "Let's Encrypt Zertifikat ist gültig"
|
||||
|
||||
# Zeige Zertifikats-Informationen
|
||||
log_info "Let's Encrypt Zertifikats-Informationen:"
|
||||
openssl x509 -in "$LETSENCRYPT_CERT" -text -noout | grep -E "(Subject:|Not Before|Not After|DNS:)"
|
||||
|
||||
read -p "Möchten Sie die Zertifikate erneuern? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Zertifikate bleiben unverändert"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
log_warning "Let's Encrypt Zertifikat ist ungültig, erstelle neue..."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Erstelle oder erneuere Let's Encrypt Zertifikat
|
||||
log_info "Erstelle/erneuere Let's Encrypt Zertifikat für your-part.de..."
|
||||
|
||||
# Prüfe ob Port 80 verfügbar ist (für HTTP-01 Challenge)
|
||||
if ! sudo netstat -tlnp | grep -q ":80 "; then
|
||||
log_warning "Port 80 ist nicht verfügbar. Stelle sicher, dass kein anderer Service läuft."
|
||||
log_info "Oder verwende DNS-01 Challenge mit --dns-cloudflare oder ähnlich"
|
||||
fi
|
||||
|
||||
# Erstelle Zertifikat mit HTTP-01 Challenge
|
||||
sudo certbot certonly --standalone -d your-part.de --non-interactive --agree-tos --email admin@your-part.de
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log_success "Let's Encrypt Zertifikat erfolgreich erstellt!"
|
||||
|
||||
# Erstelle Symlinks zu den Zertifikaten
|
||||
sudo ln -sf "$LETSENCRYPT_CERT" "$CERT_FILE"
|
||||
sudo ln -sf "$LETSENCRYPT_KEY" "$KEY_FILE"
|
||||
|
||||
# Setze korrekte Berechtigungen
|
||||
sudo chown yourchat:yourchat "$CERT_FILE" "$KEY_FILE"
|
||||
sudo chmod 644 "$CERT_FILE"
|
||||
sudo chmod 600 "$KEY_FILE"
|
||||
|
||||
# Zeige Zertifikats-Informationen
|
||||
log_info "Let's Encrypt Zertifikats-Informationen:"
|
||||
openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Not Before|Not After|DNS:)"
|
||||
|
||||
# Erstelle Auto-Renewal Cron Job
|
||||
setup_auto_renewal
|
||||
|
||||
else
|
||||
log_error "Let's Encrypt Zertifikat konnte nicht erstellt werden!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
setup_apache2_certificates() {
|
||||
log_info "Apache2 Zertifikate Setup"
|
||||
|
||||
# Finde verfügbare Zertifikate
|
||||
FOUND_CERT=""
|
||||
FOUND_KEY=""
|
||||
|
||||
for cert_path in "${APACHE2_CERT_PATHS[@]}"; do
|
||||
if sudo test -f "$cert_path"; then
|
||||
FOUND_CERT="$cert_path"
|
||||
log_info "Gefundenes Zertifikat: $cert_path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
for key_path in "${APACHE2_KEY_PATHS[@]}"; do
|
||||
if sudo test -f "$key_path"; then
|
||||
FOUND_KEY="$key_path"
|
||||
log_info "Gefundener Private Key: $key_path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$FOUND_CERT" ] || [ -z "$FOUND_KEY" ]; then
|
||||
log_error "Keine Apache2-Zertifikate gefunden!"
|
||||
log_info "Verfügbare Pfade:"
|
||||
for path in "${APACHE2_CERT_PATHS[@]}" "${APACHE2_KEY_PATHS[@]}"; do
|
||||
if sudo test -f "$path"; then
|
||||
log_info " ✓ $path"
|
||||
else
|
||||
log_info " ✗ $path"
|
||||
fi
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Warnung für Snakeoil-Zertifikate
|
||||
if [[ "$FOUND_CERT" == *"snakeoil"* ]]; then
|
||||
log_warning "ACHTUNG: Snakeoil-Zertifikat erkannt!"
|
||||
log_warning "Dieses Zertifikat ist nur für localhost gültig, nicht für your-part.de"
|
||||
log_warning "Für Produktionsumgebungen sollten Sie Let's Encrypt verwenden"
|
||||
echo ""
|
||||
read -p "Möchten Sie trotzdem fortfahren? (y/N): " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Setup abgebrochen. Verwenden Sie Option 2 für Let's Encrypt."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Erstelle Symlinks zu den Apache2-Zertifikaten
|
||||
log_info "Erstelle Symlinks zu Apache2-Zertifikaten..."
|
||||
sudo ln -sf "$FOUND_CERT" "$CERT_FILE"
|
||||
sudo ln -sf "$FOUND_KEY" "$KEY_FILE"
|
||||
|
||||
# Setze korrekte Berechtigungen
|
||||
sudo chown yourchat:yourchat "$CERT_FILE" "$KEY_FILE"
|
||||
sudo chmod 644 "$CERT_FILE"
|
||||
sudo chmod 600 "$KEY_FILE"
|
||||
|
||||
log_success "Apache2-Zertifikate erfolgreich verlinkt!"
|
||||
|
||||
# Zeige Zertifikats-Informationen
|
||||
log_info "Apache2-Zertifikats-Informationen:"
|
||||
openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Not Before|Not After|DNS:)"
|
||||
|
||||
# Prüfe ob es sich um Let's Encrypt-Zertifikate handelt
|
||||
if [[ "$FOUND_CERT" == *"letsencrypt"* ]]; then
|
||||
log_info "Let's Encrypt-Zertifikate erkannt, richte Auto-Renewal ein..."
|
||||
setup_auto_renewal
|
||||
else
|
||||
log_warning "Self-Signed oder andere Zertifikate erkannt - kein Auto-Renewal eingerichtet"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_auto_renewal() {
|
||||
log_info "Richte automatische Zertifikats-Erneuerung ein..."
|
||||
|
||||
# Erstelle Renewal Script
|
||||
sudo tee /etc/yourpart/renew-ssl.sh > /dev/null << 'EOF'
|
||||
#!/bin/bash
|
||||
# Automatische SSL-Zertifikats-Erneuerung für YourChat
|
||||
|
||||
CERT_DIR="/etc/yourpart"
|
||||
LETSENCRYPT_CERT="/etc/letsencrypt/live/your-part.de/fullchain.pem"
|
||||
LETSENCRYPT_KEY="/etc/letsencrypt/live/your-part.de/privkey.pem"
|
||||
|
||||
# Erneuere Zertifikat
|
||||
certbot renew --quiet
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
# Aktualisiere Symlinks
|
||||
ln -sf "$LETSENCRYPT_CERT" "$CERT_DIR/server.crt"
|
||||
ln -sf "$LETSENCRYPT_KEY" "$CERT_DIR/server.key"
|
||||
|
||||
# Setze Berechtigungen
|
||||
chown yourchat:yourchat "$CERT_DIR/server.crt" "$CERT_DIR/server.key"
|
||||
chmod 644 "$CERT_DIR/server.crt"
|
||||
chmod 600 "$CERT_DIR/server.key"
|
||||
|
||||
# Starte YourChat neu
|
||||
systemctl reload yourchat
|
||||
|
||||
echo "$(date): SSL-Zertifikat erfolgreich erneuert" >> /var/log/yourchat/ssl-renewal.log
|
||||
fi
|
||||
EOF
|
||||
|
||||
sudo chmod +x /etc/yourpart/renew-ssl.sh
|
||||
|
||||
# Füge Cron Job hinzu (täglich um 2:30 Uhr)
|
||||
(sudo crontab -l 2>/dev/null; echo "30 2 * * * /etc/yourpart/renew-ssl.sh") | sudo crontab -
|
||||
|
||||
log_success "Automatische Erneuerung eingerichtet (täglich um 2:30 Uhr)"
|
||||
}
|
||||
|
||||
log_info "SSL/TLS Setup für YourChat"
|
||||
|
||||
# Benutzerauswahl
|
||||
echo ""
|
||||
log_info "Wählen Sie den Zertifikatstyp:"
|
||||
echo "1) Self-Signed Certificate (für Entwicklung/Testing)"
|
||||
echo "2) Let's Encrypt Certificate (für Produktion)"
|
||||
echo "3) Bestehende Let's Encrypt Zertifikate verwenden"
|
||||
echo "4) Apache2-Zertifikate verwenden (empfohlen für Ubuntu)"
|
||||
echo ""
|
||||
read -p "Ihre Wahl (1-4): " -n 1 -r
|
||||
echo ""
|
||||
|
||||
case $REPLY in
|
||||
1)
|
||||
log_info "Self-Signed Certificate wird erstellt..."
|
||||
CERT_TYPE="self-signed"
|
||||
;;
|
||||
2)
|
||||
log_info "Let's Encrypt Certificate wird erstellt..."
|
||||
CERT_TYPE="letsencrypt"
|
||||
;;
|
||||
3)
|
||||
log_info "Bestehende Let's Encrypt Zertifikate werden verwendet..."
|
||||
CERT_TYPE="existing-letsencrypt"
|
||||
;;
|
||||
4)
|
||||
log_info "Apache2-Zertifikate werden verwendet..."
|
||||
CERT_TYPE="apache2"
|
||||
;;
|
||||
*)
|
||||
log_error "Ungültige Auswahl!"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Erstelle Zertifikats-Verzeichnis falls nicht vorhanden
|
||||
if [ ! -d "$CERT_DIR" ]; then
|
||||
log_info "Erstelle Zertifikats-Verzeichnis: $CERT_DIR"
|
||||
sudo mkdir -p "$CERT_DIR"
|
||||
fi
|
||||
|
||||
# Führe entsprechenden Setup-Typ aus
|
||||
case $CERT_TYPE in
|
||||
"self-signed")
|
||||
# Prüfe ob bereits Zertifikate existieren
|
||||
if [ -f "$CERT_FILE" ] && [ -f "$KEY_FILE" ]; then
|
||||
log_info "Zertifikate existieren bereits"
|
||||
|
||||
# Prüfe Gültigkeit der Zertifikate
|
||||
if openssl x509 -in "$CERT_FILE" -text -noout &> /dev/null; then
|
||||
log_success "Zertifikat ist gültig"
|
||||
|
||||
# Zeige Zertifikats-Informationen
|
||||
log_info "Zertifikats-Informationen:"
|
||||
openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Not Before|Not After|DNS:)"
|
||||
|
||||
read -p "Möchten Sie neue Zertifikate erstellen? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Zertifikate bleiben unverändert"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
log_warning "Zertifikat ist ungültig, erstelle neue..."
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Erstelle neue Self-Signed SSL-Zertifikate..."
|
||||
|
||||
# Erstelle Private Key
|
||||
log_info "Erstelle Private Key..."
|
||||
sudo openssl genrsa -out "$KEY_FILE" 2048
|
||||
sudo chmod 600 "$KEY_FILE"
|
||||
sudo chown yourchat:yourchat "$KEY_FILE"
|
||||
|
||||
# Erstelle Certificate Signing Request (CSR)
|
||||
log_info "Erstelle Certificate Signing Request..."
|
||||
sudo openssl req -new -key "$KEY_FILE" -out "$CSR_FILE" -subj "/C=DE/ST=Germany/L=Berlin/O=YourChat/OU=IT/CN=your-part.de"
|
||||
|
||||
# Erstelle Self-Signed Certificate
|
||||
log_info "Erstelle Self-Signed Certificate..."
|
||||
sudo openssl x509 -req -days 365 -in "$CSR_FILE" -signkey "$KEY_FILE" -out "$CERT_FILE"
|
||||
|
||||
# Setze korrekte Berechtigungen
|
||||
sudo chmod 644 "$CERT_FILE"
|
||||
sudo chown yourchat:yourchat "$CERT_FILE"
|
||||
|
||||
# Lösche CSR-Datei (nicht mehr benötigt)
|
||||
sudo rm -f "$CSR_FILE"
|
||||
|
||||
log_success "Self-Signed SSL-Zertifikate erfolgreich erstellt!"
|
||||
;;
|
||||
|
||||
"letsencrypt")
|
||||
setup_letsencrypt
|
||||
;;
|
||||
|
||||
"existing-letsencrypt")
|
||||
if [ -f "$LETSENCRYPT_CERT" ] && [ -f "$LETSENCRYPT_KEY" ]; then
|
||||
log_info "Verwende bestehende Let's Encrypt Zertifikate..."
|
||||
|
||||
# Erstelle Symlinks zu den Zertifikaten
|
||||
sudo ln -sf "$LETSENCRYPT_CERT" "$CERT_FILE"
|
||||
sudo ln -sf "$LETSENCRYPT_KEY" "$KEY_FILE"
|
||||
|
||||
# Setze korrekte Berechtigungen
|
||||
sudo chown yourchat:yourchat "$CERT_FILE" "$KEY_FILE"
|
||||
sudo chmod 644 "$CERT_FILE"
|
||||
sudo chmod 600 "$KEY_FILE"
|
||||
|
||||
log_success "Let's Encrypt Zertifikate erfolgreich verlinkt!"
|
||||
|
||||
# Richte Auto-Renewal ein
|
||||
setup_auto_renewal
|
||||
else
|
||||
log_error "Let's Encrypt Zertifikate nicht gefunden in $LETSENCRYPT_DIR"
|
||||
log_info "Führen Sie zuerst 'certbot certonly' aus oder wählen Sie Option 2"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
"apache2")
|
||||
setup_apache2_certificates
|
||||
;;
|
||||
esac
|
||||
|
||||
# Zeige Zertifikats-Informationen
|
||||
log_info "Zertifikats-Informationen:"
|
||||
openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Not Before|Not After|DNS:)"
|
||||
|
||||
log_info ""
|
||||
log_info "Nächste Schritte:"
|
||||
log_info "1. Aktiviere SSL in der Konfiguration:"
|
||||
log_info " ./deploy/update_config.sh"
|
||||
log_info "2. Starte YourChat neu:"
|
||||
log_info " sudo systemctl restart yourchat"
|
||||
log_info "3. Verbinde dich mit:"
|
||||
log_info " wss://your-part.de:1235"
|
||||
log_info ""
|
||||
|
||||
case $CERT_TYPE in
|
||||
"self-signed")
|
||||
log_warning "Hinweis: Dies ist ein Self-Signed Certificate!"
|
||||
log_warning "Für Produktionsumgebungen verwenden Sie Let's Encrypt oder Apache2-Zertifikate."
|
||||
;;
|
||||
"apache2")
|
||||
log_success "Apache2-Zertifikate erfolgreich konfiguriert!"
|
||||
log_info "Diese Zertifikate werden automatisch von Apache2 verwaltet."
|
||||
;;
|
||||
*)
|
||||
log_success "Let's Encrypt Zertifikat ist produktionsbereit!"
|
||||
;;
|
||||
esac
|
||||
@@ -137,6 +137,18 @@ def merge_json(source_file, target_file, output_file):
|
||||
if 'database' not in db_config:
|
||||
db_config['database'] = database
|
||||
|
||||
# Spezielle Behandlung für server-Konfiguration (SSL)
|
||||
if 'server' in merged_data and isinstance(merged_data['server'], dict):
|
||||
server_config = merged_data['server']
|
||||
|
||||
# SSL-Konfiguration hinzufügen falls nicht vorhanden
|
||||
if 'ssl_enabled' not in server_config:
|
||||
server_config['ssl_enabled'] = False
|
||||
if 'ssl_cert_path' not in server_config:
|
||||
server_config['ssl_cert_path'] = "/etc/yourpart/server.crt"
|
||||
if 'ssl_key_path' not in server_config:
|
||||
server_config['ssl_key_path'] = "/etc/yourpart/server.key"
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(merged_data, f, indent=4, ensure_ascii=False)
|
||||
|
||||
|
||||
364
src/core/ssl_server.cpp
Normal file
364
src/core/ssl_server.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
#include "ssl_server.h"
|
||||
#include "config.h"
|
||||
#include "lib/database.h"
|
||||
#include "chat_room.h"
|
||||
#include "chat_user.h"
|
||||
#include "lib/base.h"
|
||||
#include <iostream>
|
||||
#include <json/json.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace Yc {
|
||||
namespace Lib {
|
||||
|
||||
// Static instance pointer
|
||||
SSLServer* SSLServer::_instance = nullptr;
|
||||
|
||||
// Protocols array definition
|
||||
struct lws_protocols SSLServer::_protocols[] = {
|
||||
{
|
||||
"yourchat-protocol",
|
||||
SSLServer::wsCallback,
|
||||
sizeof(WebSocketUserData),
|
||||
4096
|
||||
},
|
||||
{ nullptr, nullptr, 0, 0 }
|
||||
};
|
||||
|
||||
SSLServer::SSLServer(std::shared_ptr<Config> config, std::shared_ptr<Database> database)
|
||||
: _config(std::move(config)), _database(std::move(database)) {
|
||||
_instance = this;
|
||||
|
||||
// Load SSL settings from config
|
||||
_useSSL = _config->value("server", "ssl_enabled").asBool();
|
||||
_certPath = _config->value("server", "ssl_cert_path").asString();
|
||||
_keyPath = _config->value("server", "ssl_key_path").asString();
|
||||
_port = _config->value("server", "port").asInt();
|
||||
|
||||
if (_useSSL && (_certPath.empty() || _keyPath.empty())) {
|
||||
throw std::runtime_error("SSL enabled but certificate or key path not provided");
|
||||
}
|
||||
}
|
||||
|
||||
SSLServer::~SSLServer() {
|
||||
stop();
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
void SSLServer::run() {
|
||||
_running = true;
|
||||
_serverThread = std::thread([this](){ startServer(); });
|
||||
_messageThread = std::thread([this](){ processMessageQueue(); });
|
||||
}
|
||||
|
||||
void SSLServer::stop() {
|
||||
_running = false;
|
||||
if (_context) lws_cancel_service(_context);
|
||||
if (_serverThread.joinable()) _serverThread.join();
|
||||
if (_messageThread.joinable()) _messageThread.join();
|
||||
if (_context) {
|
||||
lws_context_destroy(_context);
|
||||
_context = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SSLServer::startServer() {
|
||||
struct lws_context_creation_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.port = _port;
|
||||
info.protocols = _protocols;
|
||||
|
||||
// SSL/TLS Konfiguration
|
||||
if (_useSSL) {
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.ssl_cert_filepath = _certPath.c_str();
|
||||
info.ssl_private_key_filepath = _keyPath.c_str();
|
||||
std::cout << "[YourChat] SSL WebSocket Server starting on port " << _port
|
||||
<< " with certificates: " << _certPath << " / " << _keyPath << std::endl;
|
||||
} else {
|
||||
std::cout << "[YourChat] WebSocket Server starting on port " << _port << " (no SSL)" << std::endl;
|
||||
}
|
||||
|
||||
// Reduziere Log-Level um weniger Debug-Ausgaben zu haben
|
||||
setenv("LWS_LOG_LEVEL", "0", 1); // 0 = nur Fehler
|
||||
|
||||
_context = lws_create_context(&info);
|
||||
if (!_context) {
|
||||
throw std::runtime_error("Failed to create LWS context");
|
||||
}
|
||||
|
||||
while (_running) {
|
||||
lws_service(_context, 50);
|
||||
}
|
||||
}
|
||||
|
||||
void SSLServer::processMessageQueue() {
|
||||
while (_running) {
|
||||
std::unique_lock<std::mutex> lock(_queueMutex);
|
||||
_queueCV.wait(lock, [this](){ return !_messageQueue.empty() || !_running; });
|
||||
|
||||
while (!_messageQueue.empty()) {
|
||||
std::string msg = std::move(_messageQueue.front());
|
||||
_messageQueue.pop();
|
||||
lock.unlock();
|
||||
|
||||
// Process message here if needed
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SSLServer::wsCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
|
||||
if (!_instance) return 0;
|
||||
|
||||
auto *ud = reinterpret_cast<WebSocketUserData*>(user);
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
std::cout << "[YourChat] WebSocket-Verbindung hergestellt" << std::endl;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE: {
|
||||
std::string msg(reinterpret_cast<char*>(in), len);
|
||||
std::cout << "[YourChat] WebSocket-Nachricht empfangen: " << msg << std::endl;
|
||||
|
||||
_instance->handleWebSocketMessage(wsi, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE: {
|
||||
if (ud->pendingMessage.empty()) {
|
||||
// Ping senden
|
||||
unsigned char buf[LWS_PRE + 4];
|
||||
memcpy(buf + LWS_PRE, "ping", 4);
|
||||
lws_write(wsi, buf + LWS_PRE, 4, LWS_WRITE_TEXT);
|
||||
} else {
|
||||
// Nachricht senden
|
||||
unsigned char buf[LWS_PRE + ud->pendingMessage.length()];
|
||||
memcpy(buf + LWS_PRE, ud->pendingMessage.c_str(), ud->pendingMessage.length());
|
||||
lws_write(wsi, buf + LWS_PRE, ud->pendingMessage.length(), LWS_WRITE_TEXT);
|
||||
ud->pendingMessage.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
if (!ud->token.empty()) {
|
||||
_instance->removeConnection(ud->token);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SSLServer::handleWebSocketMessage(struct lws *wsi, const std::string& message) {
|
||||
try {
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
|
||||
if (!reader.parse(message, root)) {
|
||||
std::cerr << "[YourChat] JSON Parse Error: " << reader.getFormattedErrorMessages() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string type = root.get("type", "").asString();
|
||||
std::string token = root.get("token", "").asString();
|
||||
|
||||
if (type == "init") {
|
||||
// User initialization
|
||||
std::string name = root.get("name", "").asString();
|
||||
std::string room = root.get("room", "").asString();
|
||||
std::string color = root.get("color", "#000000").asString();
|
||||
std::string password = root.get("password", "").asString();
|
||||
|
||||
if (name.empty() || room.empty()) {
|
||||
Json::Value errorJson;
|
||||
errorJson["type"] = "error";
|
||||
errorJson["message"] = "missing_fields";
|
||||
errorJson["detail"] = "'name' und 'room' müssen gesetzt sein.";
|
||||
sendMessage(lws_get_socket_fd(wsi), errorJson);
|
||||
return;
|
||||
}
|
||||
|
||||
if (userExists(name)) {
|
||||
Json::Value errorJson;
|
||||
errorJson["type"] = "error";
|
||||
errorJson["message"] = "loggedin";
|
||||
sendMessage(lws_get_socket_fd(wsi), errorJson);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate token if not provided
|
||||
if (token.empty()) {
|
||||
token = Base::generateToken();
|
||||
}
|
||||
|
||||
// Store user data
|
||||
auto *ud = reinterpret_cast<WebSocketUserData*>(lws_wsi_user(wsi));
|
||||
ud->token = token;
|
||||
ud->userName = name;
|
||||
ud->userColor = color;
|
||||
ud->currentRoom = room;
|
||||
ud->authenticated = true;
|
||||
|
||||
// Add to connections
|
||||
addConnection(token, wsi);
|
||||
|
||||
// Try to add user to room
|
||||
bool added = false;
|
||||
for (auto &roomObj: _rooms) {
|
||||
if (roomObj->name() == room) {
|
||||
// Create ChatUser and add to room
|
||||
auto chatUser = std::make_shared<ChatUser>(name, color, token, lws_get_socket_fd(wsi));
|
||||
if (roomObj->addUser(name, color, password, lws_get_socket_fd(wsi))) {
|
||||
_users[token] = chatUser;
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
Json::Value errorJson;
|
||||
errorJson["type"] = "error";
|
||||
errorJson["message"] = "room_not_found_or_join_failed";
|
||||
sendMessage(lws_get_socket_fd(wsi), errorJson);
|
||||
} else {
|
||||
// Send success response
|
||||
Json::Value successJson;
|
||||
successJson["type"] = "init_success";
|
||||
successJson["token"] = token;
|
||||
successJson["message"] = "Erfolgreich verbunden";
|
||||
sendMessage(lws_get_socket_fd(wsi), successJson);
|
||||
}
|
||||
} else if (type == "message") {
|
||||
// Handle chat message
|
||||
if (!token.empty()) {
|
||||
auto user = getUserByToken(token);
|
||||
if (user) {
|
||||
std::string msg = root.get("message", "").asString();
|
||||
// Process message through room
|
||||
for (auto &room: _rooms) {
|
||||
if (room->userIsInRoom(user->name())) {
|
||||
room->addMessage(user, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add more message types as needed
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "[YourChat] Error processing WebSocket message: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SSLServer::addConnection(const std::string& token, struct lws *wsi) {
|
||||
std::unique_lock<std::shared_mutex> lock(_connectionsMutex);
|
||||
_connections[token] = wsi;
|
||||
std::cout << "[YourChat] Verbindung für Token " << token << " gespeichert" << std::endl;
|
||||
}
|
||||
|
||||
void SSLServer::removeConnection(const std::string& token) {
|
||||
std::unique_lock<std::shared_mutex> lock(_connectionsMutex);
|
||||
_connections.erase(token);
|
||||
_users.erase(token);
|
||||
std::cout << "[YourChat] Verbindung für Token " << token << " entfernt" << std::endl;
|
||||
}
|
||||
|
||||
std::shared_ptr<ChatUser> SSLServer::getUserByToken(const std::string& token) {
|
||||
std::shared_lock<std::shared_mutex> lock(_connectionsMutex);
|
||||
auto it = _users.find(token);
|
||||
return (it != _users.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
void SSLServer::sendMessage(int socket, const Json::Value& message) {
|
||||
Json::StreamWriterBuilder builder;
|
||||
std::string jsonString = Json::writeString(builder, message);
|
||||
sendMessage(socket, jsonString);
|
||||
}
|
||||
|
||||
void SSLServer::sendMessage(int socket, const std::string& message) {
|
||||
// Find the WebSocket connection for this socket
|
||||
std::shared_lock<std::shared_mutex> lock(_connectionsMutex);
|
||||
for (auto& pair : _connections) {
|
||||
if (lws_get_socket_fd(pair.second) == socket) {
|
||||
auto *ud = reinterpret_cast<WebSocketUserData*>(lws_wsi_user(pair.second));
|
||||
if (ud) {
|
||||
ud->pendingMessage = message;
|
||||
lws_callback_on_writable(pair.second);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSLServer::broadcastToRoom(const std::string& roomName, const std::string& message) {
|
||||
for (auto &room: _rooms) {
|
||||
if (room->name() == roomName) {
|
||||
// This would need to be implemented in ChatRoom to work with WebSockets
|
||||
// For now, just a placeholder
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSLServer::createRooms() {
|
||||
// Load rooms from database or config
|
||||
// This is a simplified version - would need to be expanded
|
||||
Json::Value roomList = _config->group("rooms");
|
||||
|
||||
if (roomList.isArray()) {
|
||||
for (const auto& room : roomList) {
|
||||
// Create room objects
|
||||
// This would need the actual ChatRoom constructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> SSLServer::roomList() {
|
||||
std::vector<std::string> list;
|
||||
for (const auto &room: _rooms) {
|
||||
list.push_back(room->name());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
bool SSLServer::roomAllowed(const std::string& roomName, const std::string& userName, const std::string& password) {
|
||||
for (auto &room: _rooms) {
|
||||
if (room->name() == roomName && room->accessAllowed(userName, password)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SSLServer::changeRoom(std::shared_ptr<ChatUser> user, const std::string& newRoom, const std::string& password) {
|
||||
if (!roomAllowed(newRoom, user->name(), password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Implementation would go here
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SSLServer::userExists(const std::string& userName) {
|
||||
for (const auto &room: _rooms) {
|
||||
if (room->userNameExists(userName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SSLServer::initUser(const std::string& token, const std::string& name, const std::string& room, const std::string& color, const std::string& password) {
|
||||
// Implementation would go here
|
||||
}
|
||||
|
||||
} // namespace Lib
|
||||
} // namespace Yc
|
||||
100
src/core/ssl_server.h
Normal file
100
src/core/ssl_server.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef YC_LIB_SSL_SERVER_H
|
||||
#define YC_LIB_SSL_SERVER_H
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <condition_variable>
|
||||
#include <vector>
|
||||
|
||||
namespace Yc {
|
||||
namespace Lib {
|
||||
|
||||
class Config;
|
||||
class Database;
|
||||
class ChatRoom;
|
||||
class ChatUser;
|
||||
|
||||
struct WebSocketUserData {
|
||||
std::string token;
|
||||
std::string userName;
|
||||
std::string userColor;
|
||||
std::string currentRoom;
|
||||
bool authenticated = false;
|
||||
std::string pendingMessage;
|
||||
};
|
||||
|
||||
class SSLServer {
|
||||
public:
|
||||
SSLServer(std::shared_ptr<Config> config, std::shared_ptr<Database> database);
|
||||
~SSLServer();
|
||||
|
||||
void run();
|
||||
void stop();
|
||||
void createRooms();
|
||||
|
||||
// Room management
|
||||
std::vector<std::string> roomList();
|
||||
bool roomAllowed(const std::string& roomName, const std::string& userName, const std::string& password);
|
||||
bool changeRoom(std::shared_ptr<ChatUser> user, const std::string& newRoom, const std::string& password);
|
||||
|
||||
// User management
|
||||
bool userExists(const std::string& userName);
|
||||
void initUser(const std::string& token, const std::string& name, const std::string& room, const std::string& color, const std::string& password);
|
||||
|
||||
// Message handling
|
||||
void sendMessage(int socket, const std::string& message);
|
||||
void broadcastToRoom(const std::string& roomName, const std::string& message);
|
||||
|
||||
// WebSocket callbacks
|
||||
static int wsCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
|
||||
private:
|
||||
void startServer();
|
||||
void processMessageQueue();
|
||||
void handleWebSocketMessage(struct lws *wsi, const std::string& message);
|
||||
void addConnection(const std::string& token, struct lws *wsi);
|
||||
void removeConnection(const std::string& token);
|
||||
std::shared_ptr<ChatUser> getUserByToken(const std::string& token);
|
||||
|
||||
std::shared_ptr<Config> _config;
|
||||
std::shared_ptr<Database> _database;
|
||||
std::vector<std::shared_ptr<ChatRoom>> _rooms;
|
||||
|
||||
// SSL/TLS settings
|
||||
bool _useSSL;
|
||||
std::string _certPath;
|
||||
std::string _keyPath;
|
||||
int _port;
|
||||
|
||||
// Server state
|
||||
std::atomic<bool> _running{false};
|
||||
struct lws_context* _context = nullptr;
|
||||
std::thread _serverThread;
|
||||
std::thread _messageThread;
|
||||
|
||||
// Message queue
|
||||
std::mutex _queueMutex;
|
||||
std::condition_variable _queueCV;
|
||||
std::queue<std::string> _messageQueue;
|
||||
|
||||
// Connections
|
||||
std::shared_mutex _connectionsMutex;
|
||||
std::unordered_map<std::string, struct lws*> _connections;
|
||||
std::unordered_map<std::string, std::shared_ptr<ChatUser>> _users;
|
||||
|
||||
// Static instance for callbacks
|
||||
static SSLServer* _instance;
|
||||
static struct lws_protocols _protocols[];
|
||||
};
|
||||
|
||||
} // namespace Lib
|
||||
} // namespace Yc
|
||||
|
||||
#endif // YC_LIB_SSL_SERVER_H
|
||||
13
src/main.cpp
13
src/main.cpp
@@ -2,13 +2,26 @@
|
||||
#include "core/config.h"
|
||||
#include "core/server.h"
|
||||
#include "lib/database.h"
|
||||
#include <iostream>
|
||||
|
||||
// main function
|
||||
int main(int, char **) {
|
||||
auto config = std::make_shared<Yc::Lib::Config>();
|
||||
auto database = std::make_shared<Yc::Lib::Database>(config);
|
||||
|
||||
// Check if SSL is enabled (for future implementation)
|
||||
bool sslEnabled = config->value("server", "ssl_enabled").asBool();
|
||||
|
||||
if (sslEnabled) {
|
||||
std::cout << "[YourChat] SSL/TLS support is configured but not yet implemented" << std::endl;
|
||||
std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl;
|
||||
} else {
|
||||
std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl;
|
||||
}
|
||||
|
||||
auto server = std::make_shared<Yc::Lib::Server>(config, database);
|
||||
server->createRooms(config->group("rooms"));
|
||||
server->run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user