';
+
+ echo '
';
+
+ echo '
';
+ echo '
Status';
+ echo '
' . esc_html($live_status['label']) . '
';
+ echo '
' . esc_html($live_status['meta']) . '
';
+ echo '
';
+
+ echo '
';
+ echo '
Letzte Meldung';
if ($last_message !== null) {
$msg_title = isset($last_message['title']) ? (string) $last_message['title'] : 'Meldung';
$msg_text = isset($last_message['message']) ? (string) $last_message['message'] : '';
- $msg_ts = isset($last_message['ts']) ? (int) $last_message['ts'] : 0;
- echo '
' . esc_html($msg_title) . '
';
- echo '
' . esc_html($msg_text) . '
';
- echo '
' . esc_html(self::format_timestamp($msg_ts)) . '
';
+ echo '
' . esc_html($msg_title) . '
';
+ echo '
' . esc_html(substr($msg_text, 0, 50)) . '
';
} else {
- echo '
Noch keine Meldungen vorhanden.
';
+ echo '
Keine Meldungen
';
}
echo '
';
+
echo '
';
- echo '
';
- echo '
';
- echo '
HTTP
';
- echo '
' . esc_html($live_status['http_code'] > 0 ? (string) $live_status['http_code'] : 'n/a') . '
';
+ echo '
';
+ echo '
HTTP
' . esc_html($live_status['http_code'] > 0 ? (string) $live_status['http_code'] : '—') . '
';
+ echo '
Spieler
' . esc_html($live_status['metrics']['online_players']) . '
';
+ echo '
RAM
' . esc_html($live_status['metrics']['memory']) . '
';
+ echo '
Check
' . esc_html(self::format_timestamp($state['last_check_at'])) . '
';
echo '
';
- echo '
';
- echo '
Spieler online
';
- echo '
' . esc_html($live_status['metrics']['online_players']) . '
';
+ echo '';
- echo '
';
- echo '
RAM
';
- echo '
' . esc_html($live_status['metrics']['memory']) . '
';
echo '
';
-
- echo '
';
- echo '
Zuletzt geprüft
';
- echo '
' . esc_html(self::format_timestamp($state['last_check_at'])) . '
';
- echo '
';
- echo '
';
-
- echo '
';
- echo 'StatusPulse öffnen ';
- echo 'Meldungen öffnen';
- echo '
';
echo '
';
}
@@ -123,6 +242,15 @@ if (!class_exists('StatusAPI_Backend_Helper')) {
self::MESSAGES_SLUG,
array(__CLASS__, 'render_messages_page')
);
+
+ add_submenu_page(
+ self::MENU_SLUG,
+ 'Angriffsversuche',
+ 'Angriffsversuche',
+ 'manage_options',
+ self::LIST_SLUG,
+ array(__CLASS__, 'render_list_page')
+ );
}
public static function register_settings() {
@@ -200,6 +328,33 @@ if (!class_exists('StatusAPI_Backend_Helper')) {
if (count($state['messages']) > 60) {
$state['messages'] = array_slice($state['messages'], 0, 60);
}
+
+ self::push_history_entry($level, $title, $message);
+ }
+
+ private static function get_history() {
+ $stored = get_option(self::HISTORY_OPTION_KEY, array());
+ return is_array($stored) ? $stored : array();
+ }
+
+ private static function save_history($history) {
+ update_option(self::HISTORY_OPTION_KEY, is_array($history) ? $history : array(), false);
+ }
+
+ private static function push_history_entry($level, $title, $message) {
+ $history = self::get_history();
+ array_unshift($history, array(
+ 'ts' => time(),
+ 'level' => (string) $level,
+ 'title' => (string) $title,
+ 'message' => (string) $message,
+ ));
+
+ if (count($history) > 1000) {
+ $history = array_slice($history, 0, 1000);
+ }
+
+ self::save_history($history);
}
private static function build_messages_markup($state) {
@@ -375,6 +530,64 @@ if (!class_exists('StatusAPI_Backend_Helper')) {
echo '
';
}
+ public static function render_list_page() {
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
+ $options = self::get_options();
+ $notice = self::build_notice();
+ $attacker_data = self::fetch_attacker_entries($options['statusapi_base_url']);
+ $rows = isset($attacker_data['entries']) && is_array($attacker_data['entries']) ? $attacker_data['entries'] : array();
+ $list_error = isset($attacker_data['error']) ? (string) $attacker_data['error'] : '';
+
+ echo '
';
+ self::render_styles();
+
+ echo '
StatusPulse Angriffsversuche
';
+ echo '
Zeigt nur Spielername und UUID von erkannten Angriffsversuchen (inkl. Datum/Uhrzeit).
';
+
+ if ($notice !== null) {
+ printf(
+ '
',
+ esc_attr($notice['type']),
+ esc_html($notice['message'])
+ );
+ }
+
+ echo '
';
+ echo '
Angriffs-Ereignisse
Neueste Einträge oben.
';
+
+ if ($list_error !== '') {
+ echo '
' . esc_html($list_error) . '
';
+ }
+
+ if (empty($rows)) {
+ echo '
Keine Angriffs-Einträge mit Spielername/UUID vorhanden.
';
+ } else {
+ echo '
';
+ echo '| Datum / Uhrzeit | Spielername | IP | UUID |
';
+ echo '';
+ foreach ($rows as $row) {
+ $date = isset($row['datetime']) ? (string) $row['datetime'] : '';
+ $player = isset($row['player']) ? (string) $row['player'] : '-';
+ $ip = isset($row['ip']) ? (string) $row['ip'] : '-';
+ $uuid = isset($row['uuid']) ? (string) $row['uuid'] : '-';
+
+ echo '';
+ echo '| ' . esc_html($date) . ' | ';
+ echo '' . esc_html($player) . ' | ';
+ echo '' . esc_html($ip) . ' | ';
+ echo '' . esc_html($uuid) . ' | ';
+ echo '
';
+ }
+ echo '
';
+ }
+
+ echo '
';
+ echo '
';
+ }
+
private static function render_messages_center($messages_markup, $redirect_page) {
echo '
';
echo '
Meldungs-Center
Hier siehst du laufend erkannte Status-, Attack- und Warnmeldungen aus deinem Proxy.
';
@@ -765,12 +978,19 @@ if (!class_exists('StatusAPI_Backend_Helper')) {
check_admin_referer('statusapi_backend_helper_clear_messages');
$state = self::get_state();
- $state['messages'] = array();
+ $redirect_page = isset($_POST['redirect_page']) ? sanitize_text_field(wp_unslash($_POST['redirect_page'])) : self::MENU_SLUG;
+
+ if ($redirect_page === self::LIST_SLUG) {
+ self::save_history(array());
+ } else {
+ $state['messages'] = array();
+ }
self::save_state($state);
- $redirect_page = isset($_POST['redirect_page']) ? sanitize_text_field(wp_unslash($_POST['redirect_page'])) : self::MENU_SLUG;
if ($redirect_page !== self::MESSAGES_SLUG) {
- $redirect_page = self::MENU_SLUG;
+ if ($redirect_page !== self::LIST_SLUG) {
+ $redirect_page = self::MENU_SLUG;
+ }
}
self::redirect_with_notice('messages_cleared', $redirect_page);
@@ -843,8 +1063,53 @@ if (!class_exists('StatusAPI_Backend_Helper')) {
return $code >= 200 && $code < 300;
}
+ private static function fetch_attacker_entries($base_url) {
+ if ($base_url === '') {
+ return array(
+ 'entries' => array(),
+ 'error' => 'StatusAPI Basis-URL ist nicht konfiguriert.',
+ );
+ }
+
+ $endpoint = untrailingslashit($base_url) . '/antibot/security-log';
+ $response = wp_remote_get($endpoint, array('timeout' => 8));
+ if (is_wp_error($response)) {
+ return array(
+ 'entries' => array(),
+ 'error' => 'Konnte Angriffsdaten nicht laden: ' . $response->get_error_message(),
+ );
+ }
+
+ $code = (int) wp_remote_retrieve_response_code($response);
+ if ($code < 200 || $code >= 300) {
+ return array(
+ 'entries' => array(),
+ 'error' => 'StatusAPI lieferte HTTP ' . $code . ' für /antibot/security-log.',
+ );
+ }
+
+ $body = wp_remote_retrieve_body($response);
+ $decoded = json_decode($body, true);
+ if (!is_array($decoded) || !isset($decoded['events']) || !is_array($decoded['events'])) {
+ return array(
+ 'entries' => array(),
+ 'error' => 'Antwort von /antibot/security-log ist ungültig.',
+ );
+ }
+
+ return array(
+ 'entries' => $decoded['events'],
+ 'error' => '',
+ );
+ }
+
private static function redirect_with_notice($code, $page = self::MENU_SLUG) {
- $target_page = ($page === self::MESSAGES_SLUG) ? self::MESSAGES_SLUG : self::MENU_SLUG;
+ $target_page = self::MENU_SLUG;
+ if ($page === self::MESSAGES_SLUG) {
+ $target_page = self::MESSAGES_SLUG;
+ } elseif ($page === self::LIST_SLUG) {
+ $target_page = self::LIST_SLUG;
+ }
$url = add_query_arg(
array(
'page' => $target_page,
@@ -1217,6 +1482,30 @@ if (!class_exists('StatusAPI_Backend_Helper')) {
.statusapi-message-empty {
border-left-color: #2563eb;
}
+ .statusapi-level-pill {
+ display: inline-block;
+ padding: 4px 8px;
+ border-radius: 999px;
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: .04em;
+ }
+ .statusapi-level-pill.statusapi-level-success {
+ background: #dcfce7;
+ color: #166534;
+ }
+ .statusapi-level-pill.statusapi-level-warning {
+ background: #fef3c7;
+ color: #92400e;
+ }
+ .statusapi-level-pill.statusapi-level-error {
+ background: #fee2e2;
+ color: #991b1b;
+ }
+ .statusapi-level-pill.statusapi-level-info {
+ background: #dbeafe;
+ color: #1e40af;
+ }
@media (max-width: 1100px) {
.statusapi-metric-grid,
.statusapi-status-grid {