diff --git a/database/setup_all.sql b/database/setup_all.sql new file mode 100644 index 0000000..089dd4f --- /dev/null +++ b/database/setup_all.sql @@ -0,0 +1,401 @@ +-- ============================================================ +-- MCLogger – Komplettes MariaDB Setup +-- Ausführen als root: mysql -u root -p < setup_all.sql +-- +-- Erstellt: +-- 1. mclogger_panel – Panel-Datenbank (User/Gruppen) +-- 2. mclogger_creds – Credentials-DB (verschl. MC-DB-Daten) +-- 3. mclog-1-sejru – MC Log-Datenbank (Netzwerk sejru) +-- +-- Bitte PASSWÖRTER vor dem Ausführen anpassen! +-- ============================================================ + +-- ============================================================ +-- DATENBANKEN ANLEGEN +-- ============================================================ + +CREATE DATABASE IF NOT EXISTS `mclogger_panel` + CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE DATABASE IF NOT EXISTS `mclogger_creds` + CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE DATABASE IF NOT EXISTS `mclog-1-sejru` + CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + + +-- ============================================================ +-- BENUTZER ANLEGEN (Passwörter UNBEDINGT ändern!) +-- ============================================================ + +-- Panel-App-Benutzer (Zugriff auf panel + creds DB) +CREATE USER IF NOT EXISTS 'mcl_panel'@'%' IDENTIFIED BY 'PASSWORT_PANEL_AENDERN'; +GRANT ALL PRIVILEGES ON `mclogger_panel`.* TO 'mcl_panel'@'%'; +GRANT ALL PRIVILEGES ON `mclogger_creds`.* TO 'mcl_panel'@'%'; + +-- MC-Plugin-Benutzer (schreibt Log-Daten für Netzwerk sejru) +CREATE USER IF NOT EXISTS 'mcl_sejru'@'%' IDENTIFIED BY 'PASSWORT_SEJRU_AENDERN'; +GRANT ALL PRIVILEGES ON `mclog-1-sejru`.* TO 'mcl_sejru'@'%'; + +FLUSH PRIVILEGES; + + +-- ============================================================ +-- DB 1: mclogger_panel +-- Tabellen: users, user_groups, group_members +-- ============================================================ + +USE `mclogger_panel`; + +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + salt VARCHAR(64) NOT NULL, + is_site_admin TINYINT(1) DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_login TIMESTAMP NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS user_groups ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) UNIQUE NOT NULL, + description TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS group_members ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + group_id INT NOT NULL, + role ENUM('admin','member') DEFAULT 'member', + permissions JSON, + joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY uq_user_group (user_id, group_id), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (group_id) REFERENCES user_groups(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +-- ============================================================ +-- DB 2: mclogger_creds +-- Tabelle: group_databases (verschlüsselte MC-DB-Zugangsdaten) +-- ============================================================ + +USE `mclogger_creds`; + +CREATE TABLE IF NOT EXISTS group_databases ( + id INT AUTO_INCREMENT PRIMARY KEY, + group_id INT UNIQUE NOT NULL, + enc_host TEXT NOT NULL, + enc_port TEXT NOT NULL, + enc_user TEXT NOT NULL, + enc_password TEXT NOT NULL, + enc_database TEXT NOT NULL, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +-- ============================================================ +-- DB 3: mclog-1-sejru +-- Alle MC-Log-Tabellen für das Netzwerk "sejru" +-- ============================================================ + +USE `mclog-1-sejru`; + +CREATE TABLE IF NOT EXISTS servers ( + id INT AUTO_INCREMENT PRIMARY KEY, + server_name VARCHAR(100) NOT NULL, + server_type ENUM('paper','velocity') NOT NULL DEFAULT 'paper', + ip_address VARCHAR(45), + mc_version VARCHAR(20), + first_seen TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + last_seen TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + UNIQUE KEY uq_server_name (server_name) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS players ( + uuid VARCHAR(36) PRIMARY KEY, + username VARCHAR(16) NOT NULL, + display_name VARCHAR(64), + ip_address VARCHAR(45), + locale VARCHAR(20), + first_seen TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + last_seen TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + total_playtime_sec BIGINT DEFAULT 0, + is_op TINYINT(1) DEFAULT 0, + INDEX idx_username (username) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS player_sessions ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + player_uuid VARCHAR(36) NOT NULL, + player_name VARCHAR(16) NOT NULL, + server_name VARCHAR(100), + login_time TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + logout_time TIMESTAMP(3) NULL, + duration_sec INT, + ip_address VARCHAR(45), + client_version VARCHAR(20), + INDEX idx_ps_uuid (player_uuid), + INDEX idx_ps_server (server_name), + INDEX idx_ps_login (login_time) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS player_chat ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + player_uuid VARCHAR(36), + player_name VARCHAR(16), + server_name VARCHAR(100), + world VARCHAR(100), + message TEXT NOT NULL, + channel VARCHAR(50) DEFAULT 'global', + INDEX idx_chat_uuid (player_uuid), + INDEX idx_chat_timestamp (timestamp), + INDEX idx_chat_server (server_name), + FULLTEXT INDEX ft_message (message) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS player_commands ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + player_uuid VARCHAR(36), + player_name VARCHAR(16), + server_name VARCHAR(100), + world VARCHAR(100), + command TEXT NOT NULL, + x DOUBLE, + y DOUBLE, + z DOUBLE, + INDEX idx_cmd_uuid (player_uuid), + INDEX idx_cmd_timestamp (timestamp), + INDEX idx_cmd_server (server_name) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS block_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type ENUM('break','place','ignite','burn','explode','fade','grow','dispense') NOT NULL, + player_uuid VARCHAR(36), + player_name VARCHAR(16), + server_name VARCHAR(100), + world VARCHAR(100) NOT NULL, + x INT NOT NULL, + y INT NOT NULL, + z INT NOT NULL, + block_type VARCHAR(100) NOT NULL, + block_data VARCHAR(255), + tool VARCHAR(100), + is_silk TINYINT(1) DEFAULT 0, + INDEX idx_be_player (player_uuid), + INDEX idx_be_timestamp (timestamp), + INDEX idx_be_world (world), + INDEX idx_be_type (event_type), + INDEX idx_be_server (server_name) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS player_deaths ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + player_uuid VARCHAR(36) NOT NULL, + player_name VARCHAR(16) NOT NULL, + server_name VARCHAR(100), + world VARCHAR(100), + x DOUBLE, + y DOUBLE, + z DOUBLE, + death_message TEXT, + cause VARCHAR(100), + killer_uuid VARCHAR(36), + killer_name VARCHAR(100), + killer_type VARCHAR(100), + exp_level INT, + items_lost JSON, + INDEX idx_deaths_uuid (player_uuid), + INDEX idx_deaths_timestamp (timestamp) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS entity_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type ENUM('spawn','death','damage','tame','breed','transform','explode') NOT NULL, + server_name VARCHAR(100), + world VARCHAR(100), + x DOUBLE, + y DOUBLE, + z DOUBLE, + entity_type VARCHAR(100) NOT NULL, + entity_uuid VARCHAR(36), + entity_name VARCHAR(100), + player_uuid VARCHAR(36), + player_name VARCHAR(16), + cause VARCHAR(100), + damage DOUBLE, + details JSON, + INDEX idx_ee_timestamp (timestamp), + INDEX idx_ee_type (event_type), + INDEX idx_ee_entity (entity_type), + INDEX idx_ee_player (player_uuid), + INDEX idx_ee_server (server_name) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS player_teleports ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + player_uuid VARCHAR(36) NOT NULL, + player_name VARCHAR(16) NOT NULL, + server_name VARCHAR(100), + from_world VARCHAR(100), + from_x DOUBLE, + from_y DOUBLE, + from_z DOUBLE, + to_world VARCHAR(100), + to_x DOUBLE, + to_y DOUBLE, + to_z DOUBLE, + cause VARCHAR(100), + INDEX idx_tp_uuid (player_uuid), + INDEX idx_tp_timestamp (timestamp) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS inventory_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type ENUM('pickup','drop','click','craft','enchant','anvil','trade') NOT NULL, + player_uuid VARCHAR(36) NOT NULL, + player_name VARCHAR(16) NOT NULL, + server_name VARCHAR(100), + world VARCHAR(100), + x DOUBLE, + y DOUBLE, + z DOUBLE, + item_type VARCHAR(100), + item_amount INT, + item_meta JSON, + slot INT, + inventory_type VARCHAR(100), + INDEX idx_inv_uuid (player_uuid), + INDEX idx_inv_timestamp (timestamp), + INDEX idx_inv_type (event_type) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS player_stats ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type VARCHAR(100) NOT NULL, + player_uuid VARCHAR(36) NOT NULL, + player_name VARCHAR(16) NOT NULL, + server_name VARCHAR(100), + old_value VARCHAR(255), + new_value VARCHAR(255), + details JSON, + INDEX idx_pst_uuid (player_uuid), + INDEX idx_pst_timestamp (timestamp), + INDEX idx_pst_type (event_type) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS world_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type VARCHAR(100) NOT NULL, + server_name VARCHAR(100), + world VARCHAR(100), + x DOUBLE, + y DOUBLE, + z DOUBLE, + details JSON, + INDEX idx_we_timestamp (timestamp), + INDEX idx_we_world (world), + INDEX idx_we_type (event_type) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS server_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type VARCHAR(100) NOT NULL, + server_name VARCHAR(100), + message TEXT, + details JSON, + INDEX idx_se_timestamp (timestamp), + INDEX idx_se_type (event_type), + INDEX idx_se_server (server_name) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS proxy_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type ENUM('login','disconnect','server_switch','command','chat','kick','proxy_start','proxy_stop') NOT NULL, + player_uuid VARCHAR(36), + player_name VARCHAR(16), + proxy_name VARCHAR(100), + from_server VARCHAR(100), + to_server VARCHAR(100), + ip_address VARCHAR(45), + details JSON, + INDEX idx_pe_uuid (player_uuid), + INDEX idx_pe_timestamp (timestamp), + INDEX idx_pe_type (event_type), + INDEX idx_pe_proxy (proxy_name) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS sign_edits ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + player_uuid VARCHAR(36), + player_name VARCHAR(16), + server_name VARCHAR(100), + world VARCHAR(100), + x INT, + y INT, + z INT, + line1 VARCHAR(255), + line2 VARCHAR(255), + line3 VARCHAR(255), + line4 VARCHAR(255), + INDEX idx_sign_uuid (player_uuid), + INDEX idx_sign_timestamp (timestamp) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS plugin_events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3), + event_type VARCHAR(100) NOT NULL, + plugin_name VARCHAR(100), + server_name VARCHAR(100), + player_uuid VARCHAR(36), + player_name VARCHAR(16), + actor_uuid VARCHAR(36), + actor_name VARCHAR(64), + target_type VARCHAR(50), + target_id VARCHAR(100), + action VARCHAR(255), + details JSON, + INDEX idx_plev_uuid (player_uuid), + INDEX idx_plev_timestamp (timestamp), + INDEX idx_plev_type (event_type), + INDEX idx_plev_plugin (plugin_name), + INDEX idx_plev_actor (actor_uuid) +) ENGINE=InnoDB; + +CREATE OR REPLACE VIEW v_recent_activity AS +SELECT 'chat' AS source, timestamp, player_name, server_name, message AS detail FROM player_chat WHERE timestamp >= NOW() - INTERVAL 24 HOUR +UNION ALL +SELECT 'command' AS source, timestamp, player_name, server_name, command AS detail FROM player_commands WHERE timestamp >= NOW() - INTERVAL 24 HOUR +UNION ALL +SELECT 'block' AS source, timestamp, player_name, server_name, CONCAT(event_type,' ',block_type,' @ ',world,' ',x,',',y,',',z) AS detail FROM block_events WHERE timestamp >= NOW() - INTERVAL 24 HOUR +UNION ALL +SELECT 'death' AS source, timestamp, player_name, server_name, death_message AS detail FROM player_deaths WHERE timestamp >= NOW() - INTERVAL 24 HOUR +ORDER BY timestamp DESC; + + +-- ============================================================ +-- FERTIG +-- ============================================================ + +SELECT '=== Setup abgeschlossen ===' AS Status; +SELECT TABLE_SCHEMA AS Datenbank, COUNT(*) AS Tabellen +FROM information_schema.TABLES +WHERE TABLE_SCHEMA IN ('mclogger_panel','mclogger_creds','mclog-1-sejru') +GROUP BY TABLE_SCHEMA; diff --git a/web/Dockerfile b/web/Dockerfile index 0aa46e0..92bdb1e 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -13,33 +13,10 @@ COPY . . EXPOSE 5000 -# ── Umgebungsvariablen (werden von Coolify gesetzt) ──────────────────────────── +# ── Statische Umgebungsvariablen (nur build-time defaults) ──────────────────── ENV PYTHONUNBUFFERED=1 ENV FLASK_APP=app.py - -# Flask -ENV SECRET_KEY=$SECRET_KEY -ENV HOST=$HOST -ENV PORT=$PORT -ENV DEBUG=$DEBUG - -# Panel-Datenbank (Benutzer / Gruppen) -ENV PANEL_DB_HOST=$PANEL_DB_HOST -ENV PANEL_DB_PORT=$PANEL_DB_PORT -ENV PANEL_DB_USER=$PANEL_DB_USER -ENV PANEL_DB_PASSWORD=$PANEL_DB_PASSWORD -ENV PANEL_DB_NAME=$PANEL_DB_NAME - -# Credentials-Datenbank (verschlüsselte MC-DB-Zugangsdaten) -ENV CREDS_DB_HOST=$CREDS_DB_HOST -ENV CREDS_DB_PORT=$CREDS_DB_PORT -ENV CREDS_DB_USER=$CREDS_DB_USER -ENV CREDS_DB_PASSWORD=$CREDS_DB_PASSWORD -ENV CREDS_DB_NAME=$CREDS_DB_NAME - -# Sicherheit -ENV FERNET_KEY=$FERNET_KEY -ENV PASSWORD_PEPPER=$PASSWORD_PEPPER +# Alle anderen ENV (DB, Passwörter, Keys) werden von Coolify zur Laufzeit gesetzt # Non-root user RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app diff --git a/web/config.py b/web/config.py index ea35334..a39a10b 100644 --- a/web/config.py +++ b/web/config.py @@ -8,23 +8,23 @@ import os class Config: # ── Flask ────────────────────────────────────────────────── SECRET_KEY = os.getenv("SECRET_KEY", "change-me-use-a-long-random-string-min-32-chars") - HOST = os.getenv("HOST", "0.0.0.0") - PORT = int(os.getenv("PORT", "5000")) - DEBUG = os.getenv("DEBUG", "false").lower() == "true" + HOST = os.getenv("HOST") or "0.0.0.0" + PORT = int(os.getenv("PORT") or "5000") + DEBUG = (os.getenv("DEBUG") or "false").lower() == "true" # ── Panel-Datenbank (Nutzer, Gruppen, Mitgliedschaften) ──── - PANEL_DB_HOST = os.getenv("PANEL_DB_HOST", "localhost") - PANEL_DB_PORT = int(os.getenv("PANEL_DB_PORT", "3306")) - PANEL_DB_USER = os.getenv("PANEL_DB_USER", "root") - PANEL_DB_PASSWORD = os.getenv("PANEL_DB_PASSWORD", "") - PANEL_DB_NAME = os.getenv("PANEL_DB_NAME", "mclogger_panel") + PANEL_DB_HOST = os.getenv("PANEL_DB_HOST") or "localhost" + PANEL_DB_PORT = int(os.getenv("PANEL_DB_PORT") or "3306") + PANEL_DB_USER = os.getenv("PANEL_DB_USER") or "root" + PANEL_DB_PASSWORD = os.getenv("PANEL_DB_PASSWORD") or "" + PANEL_DB_NAME = os.getenv("PANEL_DB_NAME") or "mclogger_panel" # ── Credentials-Datenbank (verschlüsselte MC-DB-Zugangsdaten) ── - CREDS_DB_HOST = os.getenv("CREDS_DB_HOST", os.getenv("PANEL_DB_HOST", "localhost")) - CREDS_DB_PORT = int(os.getenv("CREDS_DB_PORT", os.getenv("PANEL_DB_PORT", "3306"))) - CREDS_DB_USER = os.getenv("CREDS_DB_USER", os.getenv("PANEL_DB_USER", "root")) - CREDS_DB_PASSWORD = os.getenv("CREDS_DB_PASSWORD", os.getenv("PANEL_DB_PASSWORD", "")) - CREDS_DB_NAME = os.getenv("CREDS_DB_NAME", "mclogger_creds") + CREDS_DB_HOST = os.getenv("CREDS_DB_HOST") or os.getenv("PANEL_DB_HOST") or "localhost" + CREDS_DB_PORT = int(os.getenv("CREDS_DB_PORT") or os.getenv("PANEL_DB_PORT") or "3306") + CREDS_DB_USER = os.getenv("CREDS_DB_USER") or os.getenv("PANEL_DB_USER") or "root" + CREDS_DB_PASSWORD = os.getenv("CREDS_DB_PASSWORD") or os.getenv("PANEL_DB_PASSWORD") or "" + CREDS_DB_NAME = os.getenv("CREDS_DB_NAME") or "mclogger_creds" # ── Sicherheit ──────────────────────────────────────────── PASSWORD_PEPPER = os.getenv("PASSWORD_PEPPER", "change-me-global-pepper-secret-never-change")