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) {
+ ?>
+
+ 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
+
+ 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
+
+
+
+
+
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);
+ ?>
+ />
+
+