From bb7b039a326e2f5eb8514a8c80488faa8895ff75 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Mon, 30 Jun 2025 03:57:31 +0000 Subject: [PATCH] Dateien nach "/" hochladen --- WP Multi 2FA.php | 419 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 419 insertions(+) create mode 100644 WP Multi 2FA.php diff --git a/WP Multi 2FA.php b/WP Multi 2FA.php new file mode 100644 index 0000000..97694f2 --- /dev/null +++ b/WP Multi 2FA.php @@ -0,0 +1,419 @@ +🔴 Neue Updates auf Gitea'; + $links[] = $update_link; + } + return $links; +} + +// === 2. Admin-Dashboard-Hinweis bei neuer Version === +add_action('admin_init', 'wp_multi_2fa_check_update_notice'); +function wp_multi_2fa_check_update_notice() { + if (!current_user_can('update_plugins')) return; + + $transient = get_transient('wp_multi_2fa_gitea_version'); + + if ($transient === false) { + $response = wp_remote_get('https://git.viper.ipv64.net/api/v1/repos/M_Viper/WP-Multi-2FA/releases/latest'); + if (is_wp_error($response)) return; + + $data = json_decode(wp_remote_retrieve_body($response)); + if (isset($data->tag_name)) { + $latest = ltrim($data->tag_name, 'v'); // Entfernt evtl. "v" vor der Versionsnummer + set_transient('wp_multi_2fa_gitea_version', $latest, 12 * HOUR_IN_SECONDS); + } else { + return; + } + } else { + $latest = $transient; + } + + if (!function_exists('get_plugin_data')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + $plugin_data = get_plugin_data(__FILE__); + $current_version = $plugin_data['Version']; + + if (version_compare($latest, $current_version, '>')) { + add_action('admin_notices', function () use ($latest) { + ?> +
+

WP Multi 2FA: Eine neue Version () ist verfügbar. + Jetzt ansehen auf Gitea.

+
+ Allgemein + add_action('admin_init', [$this, 'register_settings_field']); + + // Session für 2FA-Code speichern + if (!session_id()) { + session_start(); + } + } + + private function get_user_2fa_data($user_id) { + $all = get_option($this->option_name, []); + return $all[$user_id] ?? null; + } + + private function set_user_2fa_data($user_id, $data) { + $all = get_option($this->option_name, []); + $all[$user_id] = $data; + update_option($this->option_name, $all); + } + + public function show_2fa_settings($user) { + if (!current_user_can('edit_user', $user->ID)) return; + + $data = $this->get_user_2fa_data($user->ID); + $enabled = $data['enabled'] ?? false; + $secret = $data['secret'] ?? null; + $backup_codes = $data['backup_codes'] ?? []; + + if (!$secret && $enabled) { + $secret = $this->generate_secret(); + $data['secret'] = $secret; + $backup_codes = $this->generate_backup_codes(); + $data['backup_codes'] = $backup_codes; + $this->set_user_2fa_data($user->ID, $data); + } + + ?> +

2-Faktor-Authentifizierung

+ + + + + + + + + + + + + + + +
+ > +

Aktiviere die Zwei-Faktor-Authentifizierung für dein Konto.

+
QR-Code (für Authenticator-App) + QR Code +

Scanne diesen QR-Code mit einer App wie Google Authenticator oder Authy.

+
Backup-Codes +
+ + +

Bewahre diese Codes sicher auf. Jeder Code kann einmal zur Anmeldung verwendet werden.

+
+ get_user_2fa_data($user_id) ?? []; + + $enabled = isset($_POST['wp2fa_enabled']) && $_POST['wp2fa_enabled'] == '1'; + + if ($enabled && empty($data['secret'])) { + $data['secret'] = $this->generate_secret(); + $data['backup_codes'] = $this->generate_backup_codes(); + } + + if (!$enabled) { + // Deaktivieren: löschen + $data = []; + } else { + $data['enabled'] = true; + } + + $this->set_user_2fa_data($user_id, $data); + } + + private function generate_secret() { + $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; + $secret = ''; + for ($i=0; $i < 16; $i++) { + $secret .= $chars[random_int(0, 31)]; + } + return $secret; + } + + private function generate_backup_codes() { + $codes = []; + for ($i = 0; $i < 10; $i++) { + $codes[] = strtoupper(bin2hex(random_bytes(4))); + } + return $codes; + } + + private function get_qr_code_url($email, $secret) { + $issuer = rawurlencode(get_bloginfo('name')); + $label = rawurlencode(get_bloginfo('name') . ':' . $email); + $otpauth = "otpauth://totp/{$label}?secret={$secret}&issuer={$issuer}"; + $chl = urlencode($otpauth); + return "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data={$chl}"; + } + + // Nach Login prüfen, ob 2FA nötig + public function after_login($user_login, $user) { + if (!$this->needs_2fa($user->ID)) return; + + $_SESSION['wp2fa_user'] = $user->ID; + wp_logout(); + wp_redirect(site_url('/wp-login.php?action=wp2fa')); + exit; + } + + private function needs_2fa($user_id) { + $data = $this->get_user_2fa_data($user_id); + $admin_forced = get_option('wp2fa_admin_forced', false); + return ($data['enabled'] ?? false) || $admin_forced; + } + + // 2FA Handler: Formular verarbeiten und ggf. anzeigen (Popup) + public function handle_2fa() { + if (!isset($_GET['action']) || $_GET['action'] !== 'wp2fa') return; + + $user_id = $_SESSION['wp2fa_user'] ?? 0; + if (!$user_id) { + wp_redirect(wp_login_url()); + exit; + } + + $error = ''; + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $code = strtoupper(trim($_POST['wp2fa_code'] ?? '')); + + $data = $this->get_user_2fa_data($user_id); + if (!$data) { + wp_redirect(wp_login_url()); + exit; + } + + $secret = $data['secret'] ?? ''; + $backup_codes = $data['backup_codes'] ?? []; + + if ($this->verify_code($secret, $code)) { + // Erfolgreicher Authenticator-Code + wp_set_auth_cookie($user_id); + unset($_SESSION['wp2fa_user']); + wp_redirect(admin_url()); + exit; + } elseif (in_array($code, $backup_codes, true)) { + // Backup-Code erfolgreich, diesen Code löschen + $backup_codes = array_diff($backup_codes, [$code]); + $data['backup_codes'] = $backup_codes; + $this->set_user_2fa_data($user_id, $data); + + wp_set_auth_cookie($user_id); + unset($_SESSION['wp2fa_user']); + wp_redirect(admin_url()); + exit; + } else { + $error = 'Falscher Code!'; + } + } + + $this->show_2fa_form($error); + exit; + } + + private function show_2fa_form($error = '') { + ?> + + + + 2-Faktor-Authentifizierung + + + + + + + get_totp_code($secret, $timeSlice + $i); + if ($calc === $code) return true; + } + return false; + } + + private function get_totp_code($secret, $timeSlice) { + $secretkey = $this->base32_decode($secret); + + $time = pack('N*', 0) . pack('N*', $timeSlice); + $hash = hash_hmac('sha1', $time, $secretkey, true); + $offset = ord(substr($hash, -1)) & 0x0F; + $truncatedHash = substr($hash, $offset, 4); + + $code = unpack('N', $truncatedHash)[1] & 0x7FFFFFFF; + $code = $code % 1000000; + + return str_pad($code, 6, '0', STR_PAD_LEFT); + } + + private function base32_decode($b32) { + $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; + $b32 = strtoupper($b32); + $l = strlen($b32); + $n = 0; + $j = 0; + $binary = ''; + + for ($i = 0; $i < $l; $i++) { + $n = $n << 5; // 5 bits per char + $n = $n + strpos($alphabet, $b32[$i]); + $j += 5; + if ($j >= 8) { + $j -= 8; + $binary .= chr(($n & (0xFF << $j)) >> $j); + } + } + return $binary; + } + + // Registrierung des Admin-Feldes in Einstellungen > Allgemein + public function register_settings_field() { + register_setting('general', 'wp2fa_admin_forced', [ + 'type' => 'boolean', + 'description' => '2FA für alle Benutzer erzwingen', + 'sanitize_callback' => [$this, 'sanitize_bool'], + 'default' => false, + ]); + + add_settings_field( + 'wp2fa_admin_forced', + '2FA für alle Benutzer erzwingen', + [$this, 'render_admin_forced_field'], + 'general' + ); + } + + public function render_admin_forced_field() { + $forced = get_option('wp2fa_admin_forced', false); + ?> + /> + +