Update from Git Manager GUI

This commit is contained in:
2026-03-29 13:41:26 +02:00
parent 3ea89e9841
commit 3b7fd16301
7 changed files with 369 additions and 106 deletions

View File

@@ -43,23 +43,46 @@ class WBF_Ajax {
// ── Auth ──────────────────────────────────────────────────────────────────
public static function handle_login() {
// Brute-Force-Schutz: max. 10 Versuche pro IP in 15 Minuten
$ip_key = 'wbf_login_fail_' . md5( $_SERVER['REMOTE_ADDR'] ?? 'unknown' );
$fails = (int) get_transient( $ip_key );
if ( $fails >= 10 ) {
wp_send_json_error([
'message' => 'Zu viele fehlgeschlagene Loginversuche. Bitte warte 15 Minuten.',
'locked' => true,
]);
}
// Login braucht keinen Nonce — Credentials sind die Authentifizierung
$result = WBF_Auth::login(
sanitize_text_field($_POST['username'] ?? ''),
$_POST['password'] ?? ''
);
if ($result['success']) {
// Erfolgreicher Login: Fehlzähler löschen
delete_transient( $ip_key );
$u = $result['user'];
if ( ! empty($_POST['remember_me']) ) {
WBF_Auth::set_remember_cookie($u->id);
}
wp_send_json_success(['display_name'=>$u->display_name,'avatar_url'=>$u->avatar_url,'user_id'=>$u->id]);
} else {
// Fehlversuch zählen — außer bei gesperrten Konten (kein Passwortfehler)
if ( empty($result['banned']) ) {
set_transient( $ip_key, $fails + 1, 15 * MINUTE_IN_SECONDS );
}
wp_send_json_error($result);
}
}
public static function handle_register() {
// Brute-Force/Spam-Schutz: max. 5 Registrierungen pro IP pro Stunde
$reg_ip_key = 'wbf_reg_ip_' . md5( $_SERVER['REMOTE_ADDR'] ?? 'unknown' );
$reg_fails = (int) get_transient( $reg_ip_key );
if ( $reg_fails >= 5 ) {
wp_send_json_error(['message' => 'Zu viele Registrierungsversuche von dieser IP. Bitte warte eine Stunde.']);
}
// Spam-Schutz: Honeypot + Zeitlimit
if ( ! empty($_POST['wbf_website']) ) {
wp_send_json_error(['message' => 'Spam erkannt.']);
@@ -98,6 +121,8 @@ class WBF_Ajax {
sanitize_text_field($_POST['display_name'] ?? '')
);
if ($result['success']) {
// Registrierungs-Zähler für IP erhöhen
set_transient( $reg_ip_key, $reg_fails + 1, HOUR_IN_SECONDS );
$u = $result['user'];
// Einladungscode einlösen
$reg_mode2 = wbf_get_settings()['registration_mode'] ?? 'open';
@@ -226,9 +251,11 @@ class WBF_Ajax {
}
// Thread-Abonnenten benachrichtigen
$subscribers = WBF_DB::get_thread_subscribers($thread_id);
// $notif_users is a flat array of IDs (from get_col) — cast to int for comparison
$notif_ids = array_map('intval', $notif_users);
foreach ($subscribers as $sub) {
if ((int)$sub->id === (int)$user->id) continue; // nicht sich selbst
if (in_array($sub->id, array_column($notif_users, 'id') ?: [])) continue; // schon benachrichtigt
if (in_array((int)$sub->id, $notif_ids, true)) continue; // schon benachrichtigt
self::send_notification_email($sub, 'reply', $user->display_name, [
'thread_id' => $thread_id,
'thread_title' => $thread->title,
@@ -372,6 +399,19 @@ class WBF_Ajax {
if (!empty($_POST['new_password'])) {
if (strlen($_POST['new_password']) < 6) wp_send_json_error(['message'=>'Passwort mindestens 6 Zeichen.']);
// Sicherheit: aktuelles Passwort muss zur Bestätigung angegeben werden
$current_pw = $_POST['current_password'] ?? '';
if ( empty($current_pw) ) {
wp_send_json_error(['message'=>'Bitte aktuelles Passwort zur Bestätigung eingeben.']);
}
if ( ! password_verify($current_pw, $user->password) ) {
wp_send_json_error(['message'=>'Aktuelles Passwort ist falsch.']);
}
// Bestätigungsfeld server-seitig prüfen
$new_pw2 = $_POST['new_password2'] ?? '';
if ( ! empty($new_pw2) && $new_pw2 !== $_POST['new_password'] ) {
wp_send_json_error(['message'=>'Die Passwörter stimmen nicht überein.']);
}
$update['password'] = password_hash($_POST['new_password'], PASSWORD_DEFAULT);
}
@@ -397,6 +437,15 @@ class WBF_Ajax {
$value = sanitize_textarea_field( $raw );
} elseif ( $def['type'] === 'number' ) {
$value = is_numeric($raw) ? (string)(float)$raw : '';
} elseif ( $def['type'] === 'date' ) {
// Datum validieren — nur YYYY-MM-DD, nicht in der Zukunft
$raw_date = sanitize_text_field( trim($raw) );
if ( preg_match('/^\d{4}-\d{2}-\d{2}$/', $raw_date) ) {
$ts = strtotime($raw_date);
$value = ($ts && $ts <= time()) ? $raw_date : '';
} else {
$value = '';
}
} else {
$value = sanitize_text_field( $raw );
}
@@ -594,7 +643,8 @@ class WBF_Ajax {
self::verify();
$query = sanitize_text_field( $_POST['query'] ?? '' );
if ( mb_strlen( $query ) < 2 ) wp_send_json_error(['message' => 'Suchbegriff zu kurz.']);
$results = WBF_DB::search( $query, 40 );
$current_search = WBF_Auth::get_current_user();
$results = WBF_DB::search( $query, 40, $current_search );
wp_send_json_success(['results' => $results, 'query' => $query]);
}
@@ -1141,6 +1191,12 @@ class WBF_Ajax {
self::verify();
$user = WBF_Auth::get_current_user();
if (!$user) wp_send_json_error(['message'=>'Nicht eingeloggt.']);
// Sicherstellen dass Spalte existiert (Schutz für bestehende Installs)
global $wpdb;
$cols = $wpdb->get_col( "DESCRIBE {$wpdb->prefix}forum_users" );
if ( ! in_array( 'profile_public', $cols ) ) {
$wpdb->query( "ALTER TABLE {$wpdb->prefix}forum_users ADD COLUMN profile_public TINYINT(1) NOT NULL DEFAULT 1" );
}
$current = (int)($user->profile_public ?? 1);
$new = $current ? 0 : 1;
WBF_DB::update_user($user->id, ['profile_public'=>$new]);