Changeset 3332295
- Timestamp:
- 07/22/2025 01:40:25 PM (9 months ago)
- Location:
- two-factor-login-telegram
- Files:
-
- 18 added
- 2 deleted
- 12 edited
- 1 copied
-
tags/3.5.0 (copied) (copied from two-factor-login-telegram/trunk)
-
tags/3.5.0/README.md (modified) (2 diffs)
-
tags/3.5.0/assets/css/wp-factor-telegram-plugin.css (modified) (1 diff)
-
tags/3.5.0/assets/js/wp-factor-telegram-plugin.js (modified) (8 diffs)
-
tags/3.5.0/includes/class-telegram-logs-list-table.php (added)
-
tags/3.5.0/includes/class-wp-factor-telegram-plugin.php (modified) (31 diffs)
-
tags/3.5.0/includes/class-wp-telegram.php (modified) (1 diff)
-
tags/3.5.0/sections (deleted)
-
tags/3.5.0/templates (added)
-
tags/3.5.0/templates/configuration.php (added)
-
tags/3.5.0/templates/error-expired-token.php (added)
-
tags/3.5.0/templates/error-invalid-token.php (added)
-
tags/3.5.0/templates/error-security-failed.php (added)
-
tags/3.5.0/templates/login-form.php (added)
-
tags/3.5.0/templates/logs-page.php (added)
-
tags/3.5.0/templates/user-2fa-form.php (added)
-
tags/3.5.0/two-factor-telegram.php (modified) (2 diffs)
-
trunk/README.md (modified) (2 diffs)
-
trunk/assets/css/wp-factor-telegram-plugin.css (modified) (1 diff)
-
trunk/assets/js/wp-factor-telegram-plugin.js (modified) (8 diffs)
-
trunk/includes/class-telegram-logs-list-table.php (added)
-
trunk/includes/class-wp-factor-telegram-plugin.php (modified) (31 diffs)
-
trunk/includes/class-wp-telegram.php (modified) (1 diff)
-
trunk/sections (deleted)
-
trunk/templates (added)
-
trunk/templates/configuration.php (added)
-
trunk/templates/error-expired-token.php (added)
-
trunk/templates/error-invalid-token.php (added)
-
trunk/templates/error-security-failed.php (added)
-
trunk/templates/login-form.php (added)
-
trunk/templates/logs-page.php (added)
-
trunk/templates/user-2fa-form.php (added)
-
trunk/two-factor-telegram.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
two-factor-login-telegram/tags/3.5.0/README.md
r3331421 r3332295 5 5 Requires PHP: 7.0 6 6 Tested up to: 6.8 7 Stable tag: 3. 47 Stable tag: 3.5.0 8 8 License: GPLv3 9 9 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 52 52 53 53 == Changelog == 54 55 = 3.5.0 = 56 * **Enhanced Logs System**: Replaced simple logs with professional WP_List_Table implementation featuring pagination (10 items per page), sorting, and bulk actions 57 * **Improved User Interface**: Complete UI overhaul with enhanced styling, better form layouts, and improved user experience 58 * **Advanced Database Management**: Migrated to MySQL tables for better performance and reliability instead of WordPress options 59 * **Better Chat ID Validation**: Enhanced Chat ID validation with proper format checking for both user and group chats 60 * **JavaScript Translations**: Implemented proper internationalization for all JavaScript messages using wp_localize_script 61 * **Enhanced User Feedback**: Added contextual status messages during 2FA configuration with clear visual indicators 62 * **Template System**: Introduced dedicated error templates for better error handling and user guidance 63 * **Timestamp Formatting**: Logs now respect WordPress date/time format settings for consistent display 64 * **Bug Fixes**: Fixed duplicate Chat ID input elements issue and improved form validation 65 * **Performance Improvements**: Optimized database queries and reduced memory usage 54 66 55 67 = 3.4 = -
two-factor-login-telegram/tags/3.5.0/assets/css/wp-factor-telegram-plugin.css
r2805641 r3332295 137 137 138 138 #wpft-howto .ui-accordion-header { 139 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 140 } 141 142 /* 2FA Configuration Improvements */ 143 #tg-2fa-configuration { 144 opacity: 0; 145 max-height: 0; 146 overflow: hidden; 147 transition: all 0.3s ease-in-out; 148 transform: translateY(-10px); 149 } 150 151 #tg-2fa-configuration.show { 152 opacity: 1; 153 max-height: 1000px; 154 transform: translateY(0); 155 } 156 157 #tg-2fa-configuration .form-table { 158 background: #f9f9f9; 159 border-radius: 8px; 160 padding: 20px; 161 margin-top: 15px; 162 border: 1px solid #e1e1e1; 163 } 164 165 /* Step indicator */ 166 .tg-setup-steps { 167 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 168 color: white; 169 padding: 20px; 170 border-radius: 8px; 171 margin-bottom: 20px; 172 } 173 174 .tg-setup-steps ol { 175 margin: 0; 176 padding-left: 20px; 177 } 178 179 .tg-setup-steps li { 180 margin-bottom: 10px; 181 line-height: 1.5; 182 } 183 184 .tg-setup-steps a { 185 color: #fff; 186 text-decoration: underline; 187 } 188 189 .tg-setup-steps strong { 190 font-weight: 600; 191 } 192 193 /* Input improvements */ 194 #tg_wp_factor_chat_id { 195 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; 196 font-size: 14px; 197 padding: 8px 12px; 198 border: 2px solid #ddd; 199 border-radius: 6px; 200 transition: all 0.2s ease; 201 } 202 203 #tg_wp_factor_chat_id:focus { 204 border-color: #667eea; 205 box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2); 206 outline: none; 207 } 208 209 #tg_wp_factor_chat_id.input-valid { 210 border-color: #46b450 !important; 211 box-shadow: 0 0 0 2px rgba(70, 180, 80, 0.2) !important; 212 } 213 214 /* Button improvements */ 215 .tg-action-button { 216 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 217 border: none; 218 color: white; 219 padding: 10px 20px; 220 border-radius: 6px; 221 cursor: pointer; 222 font-weight: 500; 223 transition: all 0.2s ease; 224 position: relative; 225 overflow: hidden; 226 } 227 228 .tg-action-button:hover { 229 transform: translateY(-1px); 230 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); 231 } 232 233 .tg-action-button:active { 234 transform: translateY(0); 235 } 236 237 .tg-action-button.disabled { 238 opacity: 0.6; 239 cursor: not-allowed; 240 transform: none !important; 241 box-shadow: none !important; 242 } 243 244 /* Loading spinner improvements */ 245 .load-spinner { 246 display: inline-block; 247 margin-left: 10px; 248 vertical-align: middle; 249 } 250 251 /* FAQ Section Styling */ 252 #wpft-howto { 253 margin: 20px 0; 254 } 255 256 #wpft-howto h3 { 139 257 background-color: #389abe; 140 } 258 color: white; 259 padding: 15px 20px; 260 margin: 20px 0 0 0; 261 font-size: 16px; 262 border-radius: 5px 5px 0 0; 263 } 264 265 #wpft-howto .faq-content { 266 background-color: #f9f9f9; 267 padding: 20px; 268 border: 1px solid #ddd; 269 border-top: none; 270 border-radius: 0 0 5px 5px; 271 margin-bottom: 20px; 272 } 273 274 #wpft-howto p { 275 margin: 10px 0; 276 line-height: 1.6; 277 } 278 279 #wpft-howto ol { 280 margin: 15px 0; 281 padding-left: 20px; 282 } 283 284 #wpft-howto li { 285 margin-bottom: 10px; 286 line-height: 1.5; 287 } 288 289 #wpft-howto .command { 290 background: #333; 291 color: #fff; 292 padding: 2px 6px; 293 border-radius: 3px; 294 font-family: monospace; 295 font-size: 13px; 296 } 297 298 #wpft-howto .screenshot-container { 299 margin: 15px 0; 300 text-align: center; 301 padding: 10px; 302 background: #fff; 303 border: 1px solid #ddd; 304 border-radius: 3px; 305 } 306 307 #wpft-howto .help-screenshot { 308 max-width: 100%; 309 height: auto; 310 border: 1px solid #ccc; 311 } 312 313 #wpft-howto .notice { 314 padding: 12px; 315 margin: 15px 0; 316 border-left: 4px solid #00a0d2; 317 background: #f7fcfe; 318 } 319 320 #wpft-howto .external-link { 321 color: #0073aa; 322 text-decoration: none; 323 } 324 325 #wpft-howto .external-link:hover { 326 text-decoration: underline; 327 } 328 329 .load-spinner img { 330 width: 20px; 331 height: 20px; 332 } 333 334 /* Progress indicator */ 335 .tg-progress { 336 background: #f0f0f0; 337 border-radius: 10px; 338 height: 6px; 339 overflow: hidden; 340 margin: 15px 0; 341 } 342 343 .tg-progress-bar { 344 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 345 height: 100%; 346 border-radius: 10px; 347 transition: width 0.3s ease; 348 width: 0%; 349 } 350 351 /* Status indicators */ 352 .tg-status { 353 display: inline-flex; 354 align-items: center; 355 padding: 8px 12px; 356 border-radius: 6px; 357 font-size: 12px; 358 font-weight: 500; 359 margin-top: 10px; 360 } 361 362 .tg-status.success { 363 background: #d4edda; 364 color: #155724; 365 border: 1px solid #c3e6cb; 366 } 367 368 .tg-status.error { 369 background: #f8d7da; 370 color: #721c24; 371 border: 1px solid #f5c6cb; 372 } 373 374 .tg-status.warning { 375 background: #fff3cd; 376 color: #856404; 377 border: 1px solid #ffeeba; 378 } 379 380 .tg-status::before { 381 content: ''; 382 width: 8px; 383 height: 8px; 384 border-radius: 50%; 385 margin-right: 8px; 386 } 387 388 .tg-status.success::before { 389 background: #28a745; 390 } 391 392 .tg-status.error::before { 393 background: #dc3545; 394 } 395 396 .tg-status.warning::before { 397 background: #ffc107; 398 } 399 400 /* Confirmation field improvements */ 401 #factor-chat-confirm { 402 background: #f8f9fa; 403 border-radius: 8px; 404 padding: 15px; 405 border: 1px solid #e9ecef; 406 margin-top: 15px; 407 } 408 409 #tg_wp_factor_chat_id_confirm { 410 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; 411 font-size: 14px; 412 padding: 8px 12px; 413 border: 2px solid #ddd; 414 border-radius: 6px; 415 transition: all 0.2s ease; 416 } 417 418 #tg_wp_factor_chat_id_confirm:focus { 419 border-color: #667eea; 420 box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2); 421 outline: none; 422 } 423 424 /* Responsive improvements */ 425 @media (max-width: 768px) { 426 #tg-2fa-configuration .form-table td { 427 display: block; 428 width: 100%; 429 padding-bottom: 10px; 430 } 431 432 .tg-action-button { 433 width: 100%; 434 margin-top: 10px; 435 } 436 } -
two-factor-login-telegram/tags/3.5.0/assets/js/wp-factor-telegram-plugin.js
r3168516 r3332295 9 9 var $twbtn = $("#tg_wp_factor_chat_id_send"); 10 10 var $twctrl = $("#tg_wp_factor_valid"); 11 var $twenabled = $("#tg_wp_factor_enabled"); 12 var $twconfig = $("#tg-2fa-configuration"); 13 var $tweditbtn = $("#tg-edit-chat-id"); 14 var $twconfigrow = $(".tg-configured-row"); 11 15 12 16 var $twfcr = $("#factor-chat-response"); … … 23 27 function init() { 24 28 29 // Handle checkbox toggle for 2FA configuration with smooth animation 30 $twenabled.on("change", function(evt){ 31 var isConfigured = $twconfigrow.length > 0; 32 33 if ($(this).is(":checked") && !isConfigured) { 34 $twconfig.addClass('show').show(); 35 updateProgress(25); 36 } else { 37 $twconfig.removeClass('show'); 38 setTimeout(function() { 39 $twconfig.hide(); 40 }, 300); 41 $twctrl.val(0); 42 updateProgress(0); 43 resetStatusIndicators(); 44 } 45 }); 46 47 // Handle edit button click (when 2FA is already configured) 48 $tweditbtn.on("click", function(evt){ 49 evt.preventDefault(); 50 51 // Hide configured row and show configuration form 52 $twconfigrow.hide(); 53 $twconfig.addClass('show').show(); 54 55 // Make the input editable and clear it 56 $twfci.prop('readonly', false).removeClass('input-valid').css('background', '').val(''); 57 58 // Reset validation state 59 $twctrl.val(0); 60 updateProgress(25); 61 resetStatusIndicators(); 62 63 // Show modifying status message 64 $('.tg-status.success').removeClass('success').addClass('warning').text(tlj.modifying_setup); 65 }); 66 67 // Watch for changes in Chat ID when in edit mode 68 $twfci.on("input", function(){ 69 var currentValue = $(this).val(); 70 var originalValue = $(this).data('original-value'); 71 72 // If value changed from original, require re-validation 73 if (currentValue !== originalValue) { 74 $twctrl.val(0); 75 $(this).removeClass('input-valid'); 76 } 77 }); 78 79 // Initialize visibility based on checkbox state and configuration 80 var isConfigured = $twconfigrow.length > 0; 81 if ($twenabled.is(":checked") && !isConfigured) { 82 $twconfig.addClass('show').show(); 83 updateProgress(25); 84 } else { 85 $twconfig.removeClass('show').hide(); 86 } 87 88 // Store original chat ID value for comparison 89 if ($twfci.length) { 90 $twfci.data('original-value', $twfci.val()); 91 } 92 25 93 $twfci.on("change", function(evt){ 26 94 $twctrl.val(0); 95 // Validate Chat ID format (basic validation) 96 validateChatId($(this).val()); 27 97 }); 28 98 29 99 $twbtn.on("click", function(evt){ 30 31 100 evt.preventDefault(); 32 101 var chat_id = $twfci.val(); 102 103 if (!validateChatId(chat_id)) { 104 showStatus('#chat-id-status', 'error', tlj.invalid_chat_id); 105 return; 106 } 107 33 108 send_tg_token(chat_id); 34 35 109 }); 36 110 37 111 $twfcheck.on("click", function(evt){ 38 39 112 evt.preventDefault(); 40 113 var token = $twfciconf.val(); 41 114 var chat_id = $twfci.val(); 115 116 if (!token.trim()) { 117 showStatus('#validation-status', 'error', tlj.enter_confirmation_code); 118 return; 119 } 120 42 121 check_tg_token(token, chat_id); 43 44 122 }); 45 123 … … 106 184 $twfcheck.addClass('disabled').after('<div class="load-spinner"><img src="'+tlj.spinner+'" /></div>'); 107 185 $twfcr.hide(); 186 hideStatus('#validation-status'); 108 187 }, 109 188 dataType: "json", … … 114 193 $twfci.addClass("input-valid"); 115 194 $twctrl.val(1); 195 updateProgress(100); 196 showStatus('#validation-status', 'success', tlj.setup_completed); 116 197 } 117 198 else { 118 $twfcr.find(".wpft-notice p").text(response.msg); 119 $twfcr.show(); 199 showStatus('#validation-status', 'error', response.msg); 120 200 $twfci.removeClass("input-valid"); 121 201 $twctrl.val(0); … … 124 204 }, 125 205 error: function(xhr, ajaxOptions, thrownError){ 126 $twfcr.find(".wpft-notice p").text(tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 127 $twfcr.show(); 206 showStatus('#validation-status', 'error', tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 128 207 $twfci.removeClass("input-valid"); 129 208 }, … … 152 231 $twfcr.hide(); 153 232 $twfconf.hide(); 233 hideStatus('#chat-id-status'); 154 234 }, 155 235 dataType: "json", … … 159 239 $twfconf.show(); 160 240 $twfci.removeClass("input-valid"); 241 updateProgress(75); 242 showStatus('#chat-id-status', 'success', tlj.code_sent); 161 243 } 162 244 else { 163 $twfcr.find(".wpft-notice p").text(response.msg); 164 $twfcr.show(); 245 showStatus('#chat-id-status', 'error', response.msg); 165 246 } 166 247 167 248 }, 168 249 error: function(xhr, ajaxOptions, thrownError){ 169 $twfcr.find(".wpft-notice p").text(tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 170 $twfcr.show(); 250 showStatus('#chat-id-status', 'error', tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 171 251 }, 172 252 complete: function() { … … 180 260 } 181 261 182 262 // Helper functions 263 function updateProgress(percentage) { 264 $('#tg-progress-bar').css('width', percentage + '%'); 265 } 266 267 function validateChatId(chatId) { 268 // Telegram Chat ID validation: must be numeric (positive for users, negative for groups) 269 if (!chatId || typeof chatId !== 'string') { 270 return false; 271 } 272 273 var trimmedId = chatId.trim(); 274 if (trimmedId === '') { 275 return false; 276 } 277 278 // Check if it's a valid number (can be negative for groups) 279 var numericId = parseInt(trimmedId, 10); 280 return !isNaN(numericId) && trimmedId === numericId.toString(); 281 } 282 283 function showStatus(selector, type, message) { 284 var $status = $(selector); 285 $status.removeClass('success error warning') 286 .addClass(type) 287 .text(message) 288 .fadeIn(300); 289 } 290 291 function hideStatus(selector) { 292 $(selector).fadeOut(300); 293 } 294 295 function resetStatusIndicators() { 296 hideStatus('#chat-id-status'); 297 hideStatus('#validation-status'); 298 } 183 299 184 300 }(jQuery); -
two-factor-login-telegram/tags/3.5.0/includes/class-wp-factor-telegram-plugin.php
r3331421 r3332295 56 56 require_once(dirname(WP_FACTOR_TG_FILE) 57 57 . "/includes/class-wp-telegram.php"); 58 require_once(dirname(WP_FACTOR_TG_FILE) 59 . "/includes/class-telegram-logs-list-table.php"); 58 60 } 59 61 … … 235 237 236 238 /** 237 * Authentication page238 *239 * @param $user240 */241 242 private function authentication_page($user)243 {244 require_once(ABSPATH . '/wp-admin/includes/template.php');245 ?>246 247 <p class="notice notice-warning">248 <?php249 _e("Enter the code sent to your Telegram account.",250 "two-factor-login-telegram");251 ?>252 </p>253 <p>254 <label for="authcode" style="padding-top:1em">255 <?php256 _e("Authentication code:", "two-factor-login-telegram");257 ?>258 </label>259 <input type="text" name="authcode" id="authcode" class="input"260 value="" size="5"/>261 </p>262 <?php263 submit_button(__('Login with Telegram',264 'two-factor-login-telegram'));265 }266 267 /**268 239 * Login HTML Page 269 240 * … … 280 251 } 281 252 282 login_header();283 284 if (!empty($error_msg)) {285 echo '<div id="login_error"><strong>' . esc_html($error_msg)286 . '</strong><br /></div>';287 }288 253 // Filter hook to add a custom logo to the 2FA login screen 289 254 $plugin_logo = apply_filters('two_factor_login_telegram_logo', 290 255 plugins_url('assets/img/plugin_logo.png', WP_FACTOR_TG_FILE)); 291 ?> 292 293 <style> 294 body.login div#login h1 a { 295 background-image: url("<?php echo esc_url($plugin_logo); ?>"); 296 } 297 </style> 298 299 <form name="validate_tg" id="loginform" action="<?php 300 echo esc_url(site_url('wp-login.php?action=validate_tg', 301 'login_post')); ?>" method="post" autocomplete="off"> 302 <input type="hidden" name="nonce" 303 value="<?php echo wp_create_nonce('wp2fa_telegram_auth_nonce_' . $user->ID); ?>"> 304 <input type="hidden" name="wp-auth-id" id="wp-auth-id" value="<?php 305 echo esc_attr($user->ID); ?>"/> 306 <input type="hidden" name="redirect_to" value="<?php 307 echo esc_attr($redirect_to); ?>"/> 308 <input type="hidden" name="rememberme" id="rememberme" value="<?php 309 echo esc_attr($rememberme); ?>"/> 310 311 <?php 312 $this->authentication_page($user); ?> 313 </form> 314 315 <p id="backtoblog"> 316 <a href="<?php 317 echo esc_url(home_url('/')); ?>" title="<?php 318 __("Are you lost?", "two-factor-login-telegram"); ?>"><?php 319 echo sprintf(__('← Back to %s', 320 'two-factor-login-telegram'), 321 get_bloginfo('title', 'display')); ?></a> 322 </p> 323 324 <?php 325 do_action('login_footer'); ?> 326 <div class="clear"></div> 327 </body> 328 329 </html> 330 <?php 256 257 require_once(ABSPATH . '/wp-admin/includes/template.php'); 258 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/login-form.php"); 331 259 } 332 260 … … 361 289 $hashed_auth_code = hash('sha256', $authcode); 362 290 $current_datetime = current_time('mysql'); 363 $query = $wpdb->prepare( 291 292 // Check if token exists for this user 293 $token_exists_query = $wpdb->prepare( 364 294 "SELECT COUNT(*) 365 FROM $table_name 366 WHERE auth_code = %s 367 AND user_id = %d 368 AND expiration_date > %s", 295 FROM $table_name 296 WHERE auth_code = %s 297 AND user_id = %d", 298 $hashed_auth_code, $user_id 299 ); 300 301 $token_exists = ($wpdb->get_var($token_exists_query) > 0); 302 303 if (!$token_exists) { 304 return 'invalid'; // Invalid token 305 } 306 307 // Check if token is not expired 308 $valid_token_query = $wpdb->prepare( 309 "SELECT COUNT(*) 310 FROM $table_name 311 WHERE auth_code = %s 312 AND user_id = %d 313 AND expiration_date > %s", 369 314 $hashed_auth_code, $user_id, $current_datetime 370 315 ); 371 316 372 return ($wpdb->get_var($query) > 0); 317 $is_valid = ($wpdb->get_var($valid_token_query) > 0); 318 319 if (!$is_valid) { 320 return 'expired'; // Token exists but expired 321 } 322 323 return 'valid'; // Valid token 373 324 } 374 325 … … 393 344 } 394 345 395 if (true !== $this->is_valid_authcode($_REQUEST['authcode'], $user->ID)) { 346 $authcode_validation = $this->is_valid_authcode($_REQUEST['authcode'], $user->ID); 347 348 if ('valid' !== $authcode_validation) { 396 349 do_action('wp_factor_telegram_failed', $user->user_login); 397 350 … … 400 353 $chat_id = $this->get_user_chatid($user->ID); 401 354 $result = $this->telegram->send_tg_token($auth_code, $chat_id, $user->ID); 355 356 // Determine error message based on validation result 357 $error_message = ''; 358 $log_reason = ''; 359 360 if ($authcode_validation === 'expired') { 361 $error_message = __('The verification code has expired. We just sent you a new code, please try again!', 362 'two-factor-login-telegram'); 363 $log_reason = 'expired_verification_code'; 364 } else { 365 $error_message = __('Wrong verification code, we just sent a new code, please try again!', 366 'two-factor-login-telegram'); 367 $log_reason = 'wrong_verification_code'; 368 } 402 369 403 370 $this->log_telegram_action('auth_code_resent', array( … … 406 373 'chat_id' => $chat_id, 407 374 'success' => $result !== false, 408 'reason' => 'wrong_verification_code'375 'reason' => $log_reason 409 376 )); 410 377 411 $this->login_html($user, $_REQUEST['redirect_to'], 412 __('Wrong verification code, we just sent a new code, please try again!', 413 'two-factor-login-telegram')); 378 $this->login_html($user, $_REQUEST['redirect_to'], $error_message); 414 379 exit; 415 380 } … … 431 396 public function configure_tg() 432 397 { 433 require (dirname(WP_FACTOR_TG_FILE) . "/sections/configure_tg.php");398 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/configuration.php"); 434 399 } 435 400 … … 439 404 public function show_telegram_logs() 440 405 { 441 $logs = get_option('telegram_bot_logs', array()); 442 443 // Handle clear logs action 444 if (isset($_POST['clear_logs']) && wp_verify_nonce($_POST['_wpnonce'], 'clear_telegram_logs')) { 445 delete_option('telegram_bot_logs'); 446 $logs = array(); 447 echo '<div class="notice notice-success is-dismissible"><p>' . __('Logs cleared successfully.', 'two-factor-login-telegram') . '</p></div>'; 448 } 449 450 ?> 451 <div class="wrap"> 452 <h1><?php _e('Telegram Bot Logs', 'two-factor-login-telegram'); ?></h1> 453 454 <form method="post"> 455 <?php wp_nonce_field('clear_telegram_logs'); ?> 456 <input type="submit" name="clear_logs" class="button button-secondary" value="<?php _e('Clear Logs', 'two-factor-login-telegram'); ?>" onclick="return confirm('<?php _e('Are you sure you want to clear all logs?', 'two-factor-login-telegram'); ?>')"> 457 </form> 458 459 <br> 460 461 <?php if (empty($logs)): ?> 462 <p><?php _e('No logs available.', 'two-factor-login-telegram'); ?></p> 463 <?php else: ?> 464 <table class="wp-list-table widefat fixed striped"> 465 <thead> 466 <tr> 467 <th style="width: 15%;"><?php _e('Timestamp', 'two-factor-login-telegram'); ?></th> 468 <th style="width: 15%;"><?php _e('Action', 'two-factor-login-telegram'); ?></th> 469 <th><?php _e('Data', 'two-factor-login-telegram'); ?></th> 470 </tr> 471 </thead> 472 <tbody> 473 <?php foreach ($logs as $log): ?> 474 <tr> 475 <td><?php echo esc_html($log['timestamp']); ?></td> 476 <td><?php echo esc_html($log['action']); ?></td> 477 <td> 478 <details> 479 <summary><?php _e('View details', 'two-factor-login-telegram'); ?></summary> 480 <pre style="background: #f1f1f1; padding: 10px; margin-top: 10px; overflow-x: auto;"><?php echo esc_html(print_r($log['data'], true)); ?></pre> 481 </details> 482 </td> 483 </tr> 484 <?php endforeach; ?> 485 </tbody> 486 </table> 487 <?php endif; ?> 488 </div> 489 <?php 406 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/logs-page.php"); 490 407 } 491 408 … … 502 419 } 503 420 504 function delete_transients($option_name, $old_value, $new_value) 505 { 506 if ($this->namespace === $option_name) { 507 delete_transient(WP_FACTOR_TG_GETME_TRANSIENT); 508 509 if (!empty($new_value['bot_token'])) { 510 $webhook_url = rest_url('telegram/v1/webhook'); 511 $this->telegram->set_bot_token($new_value['bot_token'])->set_webhook($webhook_url); 512 } 513 } 421 function sanitize_settings($input) 422 { 423 // Sanitize input values 424 $sanitized = array(); 425 426 if (isset($input['bot_token'])) { 427 $sanitized['bot_token'] = sanitize_text_field($input['bot_token']); 428 } 429 430 if (isset($input['chat_id'])) { 431 $sanitized['chat_id'] = sanitize_text_field($input['chat_id']); 432 } 433 434 if (isset($input['enabled'])) { 435 $sanitized['enabled'] = $input['enabled'] === '1' ? '1' : '0'; 436 } 437 438 if (isset($input['show_site_name'])) { 439 $sanitized['show_site_name'] = $input['show_site_name'] === '1' ? '1' : '0'; 440 } 441 442 if (isset($input['show_site_url'])) { 443 $sanitized['show_site_url'] = $input['show_site_url'] === '1' ? '1' : '0'; 444 } 445 446 if (isset($input['delete_data_on_deactivation'])) { 447 $sanitized['delete_data_on_deactivation'] = $input['delete_data_on_deactivation'] === '1' ? '1' : '0'; 448 } 449 450 // Delete transients when settings are updated 451 delete_transient(WP_FACTOR_TG_GETME_TRANSIENT); 452 453 // Set webhook if bot token is provided 454 if (!empty($sanitized['bot_token'])) { 455 $webhook_url = rest_url('telegram/v1/webhook'); 456 $this->telegram->set_bot_token($sanitized['bot_token'])->set_webhook($webhook_url); 457 } 458 459 return $sanitized; 514 460 } 515 461 516 462 function tg_register_settings() 517 463 { 518 register_setting($this->namespace, $this->namespace); 464 register_setting($this->namespace, $this->namespace, array( 465 'sanitize_callback' => array($this, 'sanitize_settings') 466 )); 519 467 520 468 add_settings_section($this->namespace . '_section', 521 469 __('Telegram Configuration', "two-factor-login-telegram"), '', 470 $this->namespace . '.php'); 471 472 add_settings_section($this->namespace . '_failed_login_section', 473 __('Failed Login Report', "two-factor-login-telegram"), array($this, 'failed_login_section_callback'), 474 $this->namespace . '.php'); 475 476 add_settings_section($this->namespace . '_data_management_section', 477 __('Data Management', "two-factor-login-telegram"), array($this, 'data_management_section_callback'), 522 478 $this->namespace . '.php'); 523 479 … … 539 495 $field_args); 540 496 497 // Move Chat ID to Failed Login Report section 541 498 $field_args = array( 542 499 'type' => 'text', 543 500 'id' => 'chat_id', 544 501 'name' => 'chat_id', 545 'desc' => __(' Chat ID (Telegram) for failed login report.',502 'desc' => __('Enter your Telegram Chat ID to receive notifications about failed login attempts.', 546 503 "two-factor-login-telegram"), 547 504 'std' => '', … … 551 508 552 509 add_settings_field('chat_id', 553 __('Chat ID ', "two-factor-login-telegram"), array(510 __('Chat ID for Reports', "two-factor-login-telegram"), array( 554 511 $this, 555 512 'tg_display_setting', 556 ), $this->namespace . '.php', $this->namespace . '_ section',513 ), $this->namespace . '.php', $this->namespace . '_failed_login_section', 557 514 $field_args); 558 515 … … 575 532 $field_args); 576 533 534 // Move Show site name to Failed Login Report section 577 535 $field_args = array( 578 536 'type' => 'checkbox', 579 537 'id' => 'show_site_name', 580 538 'name' => 'show_site_name', 581 'desc' => __(' Select this checkbox to show site name on failed login attempt message.<br>This option is useful when you use same bot in severalsites.',539 'desc' => __('Include site name in failed login notifications.<br>Useful when using the same bot for multiple sites.', 582 540 'two-factor-login-telegram'), 583 541 'std' => '', … … 587 545 588 546 add_settings_field('show_site_name', 589 __('Show site name?', 'two-factor-login-telegram'), array(547 __('Show Site Name', 'two-factor-login-telegram'), array( 590 548 $this, 591 549 'tg_display_setting', 592 ), $this->namespace . '.php', $this->namespace . '_ section',550 ), $this->namespace . '.php', $this->namespace . '_failed_login_section', 593 551 $field_args); 594 552 553 // Move Show site URL to Failed Login Report section 595 554 $field_args = array( 596 555 'type' => 'checkbox', 597 556 'id' => 'show_site_url', 598 557 'name' => 'show_site_url', 599 'desc' => __(' Select this checkbox to show site URL on failed login attempt message.<br>This option is useful when you use same bot in severalsites.',558 'desc' => __('Include site URL in failed login notifications.<br>Useful when using the same bot for multiple sites.', 600 559 'two-factor-login-telegram'), 601 560 'std' => '', … … 605 564 606 565 add_settings_field('show_site_url', 607 __('Show site URL?', 'two-factor-login-telegram'), array(566 __('Show Site URL', 'two-factor-login-telegram'), array( 608 567 $this, 609 568 'tg_display_setting', 610 ), $this->namespace . '.php', $this->namespace . '_section', 569 ), $this->namespace . '.php', $this->namespace . '_failed_login_section', 570 $field_args); 571 572 // Add data cleanup option to Data Management section 573 $field_args = array( 574 'type' => 'checkbox', 575 'id' => 'delete_data_on_deactivation', 576 'name' => 'delete_data_on_deactivation', 577 'desc' => __('Delete all plugin data when the plugin is deactivated.<br><strong>Warning:</strong> This will permanently remove all settings, user configurations, authentication codes, and logs.', 578 'two-factor-login-telegram'), 579 'std' => '', 580 'label_for' => 'delete_data_on_deactivation', 581 'class' => 'css_class', 582 ); 583 584 add_settings_field('delete_data_on_deactivation', 585 __('Delete Data on Deactivation', 'two-factor-login-telegram'), array( 586 $this, 587 'tg_display_setting', 588 ), $this->namespace . '.php', $this->namespace . '_data_management_section', 611 589 $field_args); 612 590 } … … 680 658 681 659 /** 660 * Failed login section callback 661 */ 662 public function failed_login_section_callback() 663 { 664 echo '<p>' . __('Configure how to receive notifications when someone fails to log in to your site.', 'two-factor-login-telegram') . '</p>'; 665 } 666 667 /** 668 * Data management section callback 669 */ 670 public function data_management_section_callback() 671 { 672 echo '<p>' . __('Manage plugin data and cleanup options.', 'two-factor-login-telegram') . '</p>'; 673 } 674 675 /** 682 676 * Action links 683 677 * … … 735 729 public function tg_add_two_factor_fields($user) 736 730 { 737 ?> 738 <h3 id="wptl"><?php 739 _e('2FA with Telegram', 740 'two-factor-login-telegram'); ?></h3> 741 742 <table class="form-table"> 743 744 <tr> 745 <th> 746 <label for="tg_wp_factor_enabled"><?php 747 _e('Enable 2FA', 748 'two-factor-login-telegram'); ?> 749 </label> 750 </th> 751 <td colspan="2"> 752 <input type="hidden" name="tg_wp_factor_valid" 753 id="tg_wp_factor_valid" value="<?php 754 echo (int)(esc_attr(get_the_author_meta('tg_wp_factor_enabled', 755 $user->ID)) === "1"); ?>"> 756 <input type="checkbox" name="tg_wp_factor_enabled" 757 id="tg_wp_factor_enabled" value="1" 758 class="regular-text" <?php 759 echo checked(esc_attr(get_the_author_meta('tg_wp_factor_enabled', 760 $user->ID)), 1); ?> /><br/> 761 </td> 762 </tr> 763 764 <tr> 765 766 <td colspan="3"> 767 768 <?php 769 $username = $this->telegram->get_me()->username; 770 ?> 771 772 <div> 773 774 <ol> 775 <li> 776 <?php 777 printf(__('Open a conversation with %s and press on <strong>Start</strong>', 778 'two-factor-login-telegram'), 779 '<a href="https://telegram.me/' . $username 780 . '" target="_blank">@' . $username . '</a>'); 781 ?> 782 </li> 783 784 <li> 785 <?php 786 printf(__('Type command %s to obtain your Chat ID.', 787 "two-factor-login-telegram"), 788 '<code>/get_id</code>'); 789 ?> 790 </li> 791 <li> 792 <?php 793 _e("The bot will reply with your <strong>Chat ID</strong> number", 794 'two-factor-login-telegram'); 795 ?> 796 </li> 797 798 <li><?php 799 _e('Copy your Chat ID and paste it below, then press <strong>Submit code</strong>', 800 'two-factor-login-telegram'); ?></li> 801 </ol> 802 </div> 803 </td> 804 805 </tr> 806 807 <tr> 808 <th> 809 <label for="tg_wp_factor_chat_id"><?php 810 _e('Telegram Chat ID', 811 'two-factor-login-telegram'); ?> 812 </label></th> 813 <td> 814 <input type="text" name="tg_wp_factor_chat_id" 815 id="tg_wp_factor_chat_id" value="<?php 816 echo esc_attr(get_the_author_meta('tg_wp_factor_chat_id', 817 $user->ID)); ?>" class="regular-text"/><br/> 818 <span class="description"><?php 819 _e('Put your Telegram Chat ID', 820 'two-factor-login-telegram'); ?></span> 821 </td> 822 <td> 823 <button class="button" id="tg_wp_factor_chat_id_send"><?php 824 _e("Submit code", 825 "two-factor-login-telegram"); ?></button> 826 </td> 827 </tr> 828 829 <tr id="factor-chat-confirm"> 830 <th> 831 <label for="tg_wp_factor_chat_id_confirm"><?php 832 _e('Confirmation code', 833 'two-factor-login-telegram'); ?> 834 </label></th> 835 <td> 836 <input type="text" name="tg_wp_factor_chat_id_confirm" 837 id="tg_wp_factor_chat_id_confirm" value="" 838 class="regular-text"/><br/> 839 <span class="description"><?php 840 _e('Please enter the confirmation code you received on Telegram', 841 'two-factor-login-telegram'); ?></span> 842 </td> 843 <td> 844 <button class="button" id="tg_wp_factor_chat_id_check"><?php 845 _e("Validate", 846 "two-factor-login-telegram"); ?></button> 847 </td> 848 </tr> 849 <tr id="factor-chat-response"> 850 <td colspan="3"> 851 <div class="wpft-notice wpft-notice-warning"> 852 <p></p> 853 </div> 854 </td> 855 </tr> 856 </table> 857 <?php 731 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/user-2fa-form.php"); 858 732 } 859 733 … … 878 752 "sendtoken_nonce" => wp_create_nonce('ajax-sendtoken-nonce'), 879 753 "tokencheck_nonce" => wp_create_nonce('ajax-tokencheck-nonce'), 880 "spinner" => admin_url("/images/spinner.gif") 754 "spinner" => admin_url("/images/spinner.gif"), 755 // Translated messages 756 "invalid_chat_id" => __('Please enter a valid Chat ID', 'two-factor-login-telegram'), 757 "enter_confirmation_code" => __('Please enter the confirmation code', 'two-factor-login-telegram'), 758 "setup_completed" => __('✅ 2FA setup completed successfully!', 'two-factor-login-telegram'), 759 "code_sent" => __('✅ Code sent! Check your Telegram', 'two-factor-login-telegram'), 760 "modifying_setup" => __('⚠️ Modifying 2FA configuration - validation required', 'two-factor-login-telegram') 881 761 )); 882 762 … … 954 834 __("Use this code to complete your 2FA setup in WordPress, or click the button below:", "two-factor-login-telegram") 955 835 ); 956 836 957 837 // Create inline keyboard with validation button 958 838 $reply_markup = null; 959 839 if ($current_user_id) { 960 840 $nonce = wp_create_nonce('telegram_validate_' . $current_user_id . '_' . $auth_code); 961 $validation_url = admin_url(' admin.php?page=tg-conf&action=telegram_validate&user_id=' . $current_user_id . '&token=' . $auth_code . '&nonce=' . $nonce);962 841 $validation_url = admin_url('options-general.php?page=tg-conf&action=telegram_validate&chat_id='.$_POST['chat_id'].'&user_id=' . $current_user_id . '&token=' . $auth_code . '&nonce=' . $nonce); 842 963 843 $reply_markup = array( 964 844 'inline_keyboard' => array( … … 972 852 ); 973 853 } 974 854 975 855 $send = $tg->send_with_keyboard($validation_message, $_POST['chat_id'], $reply_markup); 976 856 … … 1077 957 } 1078 958 1079 public function tg_save_custom_user_profile_fields($user_id) 959 /** 960 * Save user's 2FA settings 961 * 962 * @param int $user_id User ID 963 * @param string $chat_id Telegram Chat ID 964 * @param bool $enabled Whether 2FA is enabled 965 * @return bool Success status 966 */ 967 public function save_user_2fa_settings($user_id, $chat_id, $enabled = true) 1080 968 { 1081 969 if (!current_user_can('edit_user', $user_id)) { … … 1083 971 } 1084 972 973 if (empty($chat_id)) { 974 return false; 975 } 976 977 update_user_meta($user_id, 'tg_wp_factor_chat_id', sanitize_text_field($chat_id)); 978 update_user_meta($user_id, 'tg_wp_factor_enabled', $enabled ? '1' : '0'); 979 980 return true; 981 } 982 983 public function tg_save_custom_user_profile_fields($user_id) 984 { 1085 985 if ($_POST['tg_wp_factor_valid'] == 0 1086 986 || $_POST['tg_wp_factor_chat_id'] == "" … … 1089 989 } 1090 990 1091 update_user_meta($user_id, 'tg_wp_factor_chat_id', 1092 $_POST['tg_wp_factor_chat_id']); 1093 update_user_meta($user_id, 'tg_wp_factor_enabled', 1094 $_POST['tg_wp_factor_enabled']); 1095 1096 return true; 991 return $this->save_user_2fa_settings( 992 $user_id, 993 $_POST['tg_wp_factor_chat_id'], 994 isset($_POST['tg_wp_factor_enabled']) 995 ); 1097 996 } 1098 997 … … 1169 1068 } 1170 1069 1070 private function create_or_update_activities_table() 1071 { 1072 global $wpdb; 1073 1074 $table_name = $wpdb->prefix . 'wp2fat_activities'; 1075 1076 $charset_collate = $wpdb->get_charset_collate(); 1077 $sql = "CREATE TABLE IF NOT EXISTS $table_name ( 1078 id mediumint(9) NOT NULL AUTO_INCREMENT, 1079 timestamp datetime NOT NULL, 1080 action varchar(100) NOT NULL, 1081 data longtext, 1082 PRIMARY KEY (id), 1083 KEY timestamp (timestamp), 1084 KEY action (action) 1085 ) $charset_collate"; 1086 1087 require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); 1088 1089 // Esegue la query per creare/aggiornare la tabella 1090 dbDelta($sql); 1091 } 1092 1093 private function migrate_logs_to_activities_table() 1094 { 1095 global $wpdb; 1096 1097 // Check if old logs exist in option 1098 $old_logs = get_option('telegram_bot_logs', array()); 1099 1100 if (!empty($old_logs)) { 1101 $activities_table = $wpdb->prefix . 'wp2fat_activities'; 1102 1103 // Migrate each log entry 1104 foreach ($old_logs as $log) { 1105 $wpdb->insert( 1106 $activities_table, 1107 array( 1108 'timestamp' => $log['timestamp'], 1109 'action' => $log['action'], 1110 'data' => maybe_serialize($log['data']) 1111 ), 1112 array('%s', '%s', '%s') 1113 ); 1114 } 1115 1116 // Delete the old option after migration 1117 delete_option('telegram_bot_logs'); 1118 } 1119 } 1120 1171 1121 function plugin_activation() 1172 1122 { 1173 1123 $this->create_or_update_telegram_auth_codes_table(); 1124 $this->create_or_update_activities_table(); 1125 $this->migrate_logs_to_activities_table(); 1174 1126 update_option('wp_factor_plugin_version', WP_FACTOR_PLUGIN_VERSION); 1175 1127 1176 // Flush rewrite rules to add our webhook endpoint 1128 // Add rewrite rules before flushing 1129 $this->add_telegram_rewrite_rules(); 1130 1131 // Flush rewrite rules to add our new rules 1177 1132 flush_rewrite_rules(); 1133 } 1134 1135 function plugin_deactivation() 1136 { 1137 // Check if data cleanup is enabled 1138 $plugin_options = get_option($this->namespace, array()); 1139 1140 if (isset($plugin_options['delete_data_on_deactivation']) && $plugin_options['delete_data_on_deactivation'] === '1') { 1141 $this->cleanup_all_plugin_data(); 1142 } 1143 1144 // Always flush rewrite rules on deactivation 1145 flush_rewrite_rules(); 1146 } 1147 1148 private function cleanup_all_plugin_data() 1149 { 1150 global $wpdb; 1151 1152 // Delete plugin settings 1153 delete_option($this->namespace); 1154 delete_option('wp_factor_plugin_version'); 1155 delete_option('telegram_bot_logs'); // For backward compatibility 1156 1157 // Delete auth codes table 1158 $auth_codes_table = $wpdb->prefix . 'telegram_auth_codes'; 1159 $wpdb->query("DROP TABLE IF EXISTS $auth_codes_table"); 1160 1161 // Delete activities table 1162 $activities_table = $wpdb->prefix . 'wp2fat_activities'; 1163 $wpdb->query("DROP TABLE IF EXISTS $activities_table"); 1164 1165 // Delete user meta data for all users 1166 $wpdb->delete( 1167 $wpdb->usermeta, 1168 array( 1169 'meta_key' => 'tg_wp_factor_chat_id' 1170 ) 1171 ); 1172 1173 $wpdb->delete( 1174 $wpdb->usermeta, 1175 array( 1176 'meta_key' => 'tg_wp_factor_enabled' 1177 ) 1178 ); 1179 1180 // Delete all transients related to the plugin 1181 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_wp2fa_telegram_authcode_%'"); 1182 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_timeout_wp2fa_telegram_authcode_%'"); 1183 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_" . WP_FACTOR_TG_GETME_TRANSIENT . "%'"); 1184 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_timeout_" . WP_FACTOR_TG_GETME_TRANSIENT . "%'"); 1178 1185 } 1179 1186 … … 1184 1191 if ($installed_version !== WP_FACTOR_PLUGIN_VERSION) { 1185 1192 $this->create_or_update_telegram_auth_codes_table(); 1193 $this->create_or_update_activities_table(); 1194 $this->migrate_logs_to_activities_table(); 1186 1195 update_option('wp_factor_plugin_version', WP_FACTOR_PLUGIN_VERSION); 1187 1196 } … … 1201 1210 1202 1211 register_activation_hook(WP_FACTOR_TG_FILE, array($this, 'plugin_activation')); 1212 register_deactivation_hook(WP_FACTOR_TG_FILE, array($this, 'plugin_deactivation')); 1203 1213 add_action('plugins_loaded', array($this, 'check_plugin_update')); 1204 1214 … … 1209 1219 . plugin_basename(WP_FACTOR_TG_FILE), 1210 1220 array($this, 'action_links')); 1211 add_action('updated_option', array($this, 'delete_transients'),1212 10, 3);1213 1221 } 1214 1222 … … 1223 1231 } 1224 1232 1225 add_action('show_user_profile', 1226 array($this, 'tg_add_two_factor_fields')); 1227 add_action('edit_user_profile', 1228 array($this, 'tg_add_two_factor_fields')); 1233 if ($this->is_valid_bot()) { 1234 add_action('show_user_profile', 1235 array($this, 'tg_add_two_factor_fields')); 1236 add_action('edit_user_profile', 1237 array($this, 'tg_add_two_factor_fields')); 1238 } 1229 1239 1230 1240 add_action('personal_options_update', … … 1242 1252 // Add REST API endpoint for Telegram webhook 1243 1253 add_action('rest_api_init', array($this, 'register_telegram_webhook_route')); 1254 1255 // Add rewrite rules for Telegram confirmation URLs 1256 add_action('init', array($this, 'add_telegram_rewrite_rules')); 1257 add_action('parse_request', array($this, 'parse_telegram_request')); 1258 1244 1259 } 1245 1260 … … 1253 1268 'permission_callback' => '__return_true', 1254 1269 )); 1255 1256 register_rest_route('telegram/v1', '/confirm/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)', array( 1257 'methods' => 'GET', 1258 'callback' => array($this, 'handle_telegram_confirmation'), 1259 'permission_callback' => '__return_true', 1260 'args' => array( 1261 'user_id' => array( 1262 'validate_callback' => function($param, $request, $key) { 1263 return is_numeric($param); 1264 } 1265 ), 1266 'token' => array( 1267 'validate_callback' => function($param, $request, $key) { 1268 return preg_match('/^[a-zA-Z0-9]+$/', $param); 1269 } 1270 ), 1271 'nonce' => array( 1272 'required' => true, 1273 ) 1270 } 1271 1272 /** 1273 * Add rewrite rules for Telegram confirmation URLs 1274 */ 1275 public function add_telegram_rewrite_rules() { 1276 add_rewrite_rule( 1277 '^telegram-confirm/([0-9]+)/([a-zA-Z0-9]+)/?$', 1278 'index.php?telegram_confirm=1&user_id=$matches[1]&token=$matches[2]', 1279 'top' 1280 ); 1281 1282 // Add query vars 1283 add_filter('query_vars', function($vars) { 1284 $vars[] = 'telegram_confirm'; 1285 $vars[] = 'user_id'; 1286 $vars[] = 'token'; 1287 return $vars; 1288 }); 1289 } 1290 1291 /** 1292 * Parse Telegram confirmation requests 1293 */ 1294 public function parse_telegram_request() { 1295 global $wp; 1296 1297 if (isset($wp->query_vars['telegram_confirm']) && $wp->query_vars['telegram_confirm'] == 1) { 1298 $user_id = intval($wp->query_vars['user_id']); 1299 $token = sanitize_text_field($wp->query_vars['token']); 1300 $nonce = sanitize_text_field($_GET['nonce'] ?? ''); 1301 1302 $this->handle_telegram_confirmation_direct($user_id, $token, $nonce); 1303 } 1304 } 1305 1306 /** 1307 * Handle Telegram confirmation via direct URL (not REST API) 1308 */ 1309 public function handle_telegram_confirmation_direct($user_id, $token, $nonce) { 1310 // Verify nonce 1311 if (!wp_verify_nonce($nonce, 'telegram_confirm_' . $user_id . '_' . $token)) { 1312 $this->log_telegram_action('confirmation_failed', array( 1313 'user_id' => $user_id, 1314 'token' => $token, 1315 'reason' => 'invalid_nonce' 1316 )); 1317 1318 // Include error template 1319 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-security-failed.php"); 1320 } 1321 1322 // Validate the token 1323 $authcode_validation = $this->is_valid_authcode($token, $user_id); 1324 1325 if ('valid' !== $authcode_validation) { 1326 if ($authcode_validation === 'expired') { 1327 $log_reason = 'expired_token'; 1328 } else { 1329 $log_reason = 'invalid_token'; 1330 } 1331 1332 $this->log_telegram_action('confirmation_failed', array( 1333 'user_id' => $user_id, 1334 'token' => $token, 1335 'reason' => $log_reason 1336 )); 1337 1338 // Include appropriate error template 1339 if ($authcode_validation === 'expired') { 1340 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-expired-token.php"); 1341 } else { 1342 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-invalid-token.php"); 1343 } 1344 } 1345 1346 // Get user 1347 $user = get_userdata($user_id); 1348 if (!$user) { 1349 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-invalid-token.php"); 1350 } 1351 1352 // Log the user in 1353 wp_set_auth_cookie($user_id, false); 1354 1355 $this->log_telegram_action('confirmation_success', array( 1356 'user_id' => $user_id, 1357 'user_login' => $user->user_login, 1358 'token' => $token, 1359 'method' => 'direct_confirmation' 1360 )); 1361 1362 // Redirect to admin or specified location 1363 $redirect_url = apply_filters('telegram_confirmation_redirect_url', admin_url(), $user); 1364 1365 // Redirect directly 1366 wp_safe_redirect($redirect_url); 1367 exit; 1368 } 1369 1370 /** 1371 * Log Telegram bot actions 1372 */ 1373 public function log_telegram_action($action, $data = array()) { 1374 global $wpdb; 1375 1376 $activities_table = $wpdb->prefix . 'wp2fat_activities'; 1377 1378 // Insert new log entry 1379 $wpdb->insert( 1380 $activities_table, 1381 array( 1382 'timestamp' => current_time('mysql'), 1383 'action' => $action, 1384 'data' => maybe_serialize($data) 1274 1385 ), 1275 )); 1276 } 1277 1278 /** 1279 * Log Telegram bot actions 1280 */ 1281 private function log_telegram_action($action, $data = array()) { 1282 $log_entry = array( 1283 'timestamp' => current_time('mysql'), 1284 'action' => $action, 1285 'data' => $data 1286 ); 1287 1288 $logs = get_option('telegram_bot_logs', array()); 1289 array_unshift($logs, $log_entry); 1290 1291 // Keep only last 100 log entries 1292 $logs = array_slice($logs, 0, 100); 1293 1294 update_option('telegram_bot_logs', $logs); 1386 array('%s', '%s', '%s') 1387 ); 1388 1389 // Clean up old entries - keep only last 1000 entries 1390 $wpdb->query("DELETE FROM $activities_table WHERE id NOT IN (SELECT id FROM (SELECT id FROM $activities_table ORDER BY timestamp DESC LIMIT 1000) temp_table)"); 1295 1391 } 1296 1392 … … 1351 1447 } 1352 1448 1353 /** 1354 * Handle Telegram confirmation via link 1355 */ 1356 public function handle_telegram_confirmation($request) { 1357 $user_id = intval($request['user_id']); 1358 $token = sanitize_text_field($request['token']); 1359 $nonce = sanitize_text_field($request->get_param('nonce')); 1360 1361 // Verify nonce 1362 if (!wp_verify_nonce($nonce, 'telegram_confirm_' . $user_id . '_' . $token)) { 1363 $this->log_telegram_action('confirmation_failed', array( 1364 'user_id' => $user_id, 1365 'token' => $token, 1366 'reason' => 'invalid_nonce' 1367 )); 1368 return new WP_Error('invalid_nonce', __('Security check failed.', 'two-factor-login-telegram'), array('status' => 403)); 1369 } 1370 1371 // Validate the token 1372 if (!$this->is_valid_authcode($token, $user_id)) { 1373 $this->log_telegram_action('confirmation_failed', array( 1374 'user_id' => $user_id, 1375 'token' => $token, 1376 'reason' => 'invalid_token' 1377 )); 1378 return new WP_Error('invalid_token', __('Invalid or expired token.', 'two-factor-login-telegram'), array('status' => 400)); 1379 } 1380 1381 // Get user 1382 $user = get_userdata($user_id); 1383 if (!$user) { 1384 return new WP_Error('invalid_user', __('Invalid user.', 'two-factor-login-telegram'), array('status' => 400)); 1385 } 1386 1387 // Log the user in 1388 wp_set_auth_cookie($user_id, false); 1389 1390 $this->log_telegram_action('confirmation_success', array( 1391 'user_id' => $user_id, 1392 'user_login' => $user->user_login, 1393 'token' => $token, 1394 'method' => 'link_confirmation' 1395 )); 1396 1397 // Redirect to admin or specified location 1398 $redirect_url = apply_filters('telegram_confirmation_redirect_url', admin_url(), $user); 1399 1400 // Redirect directly instead of returning JSON 1401 wp_safe_redirect($redirect_url); 1402 exit; 1403 } 1449 1404 1450 1405 1451 } -
two-factor-login-telegram/tags/3.5.0/includes/class-wp-telegram.php
r3331421 r3332295 148 148 if ($user_id) { 149 149 $nonce = wp_create_nonce('telegram_confirm_' . $user_id . '_' . $token); 150 $confirmation_url = site_url('/wp-json/telegram/v1/confirm/' . $user_id . '/' . $token . '?nonce=' . $nonce);150 $confirmation_url = home_url('/telegram-confirm/' . $user_id . '/' . $token . '/?nonce=' . $nonce); 151 151 152 152 $reply_markup = array( -
two-factor-login-telegram/tags/3.5.0/two-factor-telegram.php
r3331421 r3332295 5 5 * Plugin URI: https://blog.dueclic.com/wordpress-autenticazione-due-fattori-telegram/ 6 6 * Description: This plugin enables two factor authentication with Telegram by increasing your website security and sends an alert every time a wrong login occurs. 7 * Version: 3. 47 * Version: 3.5.0 8 8 * Requires at least: 6.0 9 9 * Tested up to: 6.8 … … 22 22 } 23 23 24 define('WP_FACTOR_PLUGIN_VERSION', '3. 4');24 define('WP_FACTOR_PLUGIN_VERSION', '3.5.0'); 25 25 26 26 define('WP_FACTOR_AUTHCODE_EXPIRE_SECONDS', 60 * 20); -
two-factor-login-telegram/trunk/README.md
r3331421 r3332295 5 5 Requires PHP: 7.0 6 6 Tested up to: 6.8 7 Stable tag: 3. 47 Stable tag: 3.5.0 8 8 License: GPLv3 9 9 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 52 52 53 53 == Changelog == 54 55 = 3.5.0 = 56 * **Enhanced Logs System**: Replaced simple logs with professional WP_List_Table implementation featuring pagination (10 items per page), sorting, and bulk actions 57 * **Improved User Interface**: Complete UI overhaul with enhanced styling, better form layouts, and improved user experience 58 * **Advanced Database Management**: Migrated to MySQL tables for better performance and reliability instead of WordPress options 59 * **Better Chat ID Validation**: Enhanced Chat ID validation with proper format checking for both user and group chats 60 * **JavaScript Translations**: Implemented proper internationalization for all JavaScript messages using wp_localize_script 61 * **Enhanced User Feedback**: Added contextual status messages during 2FA configuration with clear visual indicators 62 * **Template System**: Introduced dedicated error templates for better error handling and user guidance 63 * **Timestamp Formatting**: Logs now respect WordPress date/time format settings for consistent display 64 * **Bug Fixes**: Fixed duplicate Chat ID input elements issue and improved form validation 65 * **Performance Improvements**: Optimized database queries and reduced memory usage 54 66 55 67 = 3.4 = -
two-factor-login-telegram/trunk/assets/css/wp-factor-telegram-plugin.css
r2805641 r3332295 137 137 138 138 #wpft-howto .ui-accordion-header { 139 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 140 } 141 142 /* 2FA Configuration Improvements */ 143 #tg-2fa-configuration { 144 opacity: 0; 145 max-height: 0; 146 overflow: hidden; 147 transition: all 0.3s ease-in-out; 148 transform: translateY(-10px); 149 } 150 151 #tg-2fa-configuration.show { 152 opacity: 1; 153 max-height: 1000px; 154 transform: translateY(0); 155 } 156 157 #tg-2fa-configuration .form-table { 158 background: #f9f9f9; 159 border-radius: 8px; 160 padding: 20px; 161 margin-top: 15px; 162 border: 1px solid #e1e1e1; 163 } 164 165 /* Step indicator */ 166 .tg-setup-steps { 167 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 168 color: white; 169 padding: 20px; 170 border-radius: 8px; 171 margin-bottom: 20px; 172 } 173 174 .tg-setup-steps ol { 175 margin: 0; 176 padding-left: 20px; 177 } 178 179 .tg-setup-steps li { 180 margin-bottom: 10px; 181 line-height: 1.5; 182 } 183 184 .tg-setup-steps a { 185 color: #fff; 186 text-decoration: underline; 187 } 188 189 .tg-setup-steps strong { 190 font-weight: 600; 191 } 192 193 /* Input improvements */ 194 #tg_wp_factor_chat_id { 195 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; 196 font-size: 14px; 197 padding: 8px 12px; 198 border: 2px solid #ddd; 199 border-radius: 6px; 200 transition: all 0.2s ease; 201 } 202 203 #tg_wp_factor_chat_id:focus { 204 border-color: #667eea; 205 box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2); 206 outline: none; 207 } 208 209 #tg_wp_factor_chat_id.input-valid { 210 border-color: #46b450 !important; 211 box-shadow: 0 0 0 2px rgba(70, 180, 80, 0.2) !important; 212 } 213 214 /* Button improvements */ 215 .tg-action-button { 216 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 217 border: none; 218 color: white; 219 padding: 10px 20px; 220 border-radius: 6px; 221 cursor: pointer; 222 font-weight: 500; 223 transition: all 0.2s ease; 224 position: relative; 225 overflow: hidden; 226 } 227 228 .tg-action-button:hover { 229 transform: translateY(-1px); 230 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); 231 } 232 233 .tg-action-button:active { 234 transform: translateY(0); 235 } 236 237 .tg-action-button.disabled { 238 opacity: 0.6; 239 cursor: not-allowed; 240 transform: none !important; 241 box-shadow: none !important; 242 } 243 244 /* Loading spinner improvements */ 245 .load-spinner { 246 display: inline-block; 247 margin-left: 10px; 248 vertical-align: middle; 249 } 250 251 /* FAQ Section Styling */ 252 #wpft-howto { 253 margin: 20px 0; 254 } 255 256 #wpft-howto h3 { 139 257 background-color: #389abe; 140 } 258 color: white; 259 padding: 15px 20px; 260 margin: 20px 0 0 0; 261 font-size: 16px; 262 border-radius: 5px 5px 0 0; 263 } 264 265 #wpft-howto .faq-content { 266 background-color: #f9f9f9; 267 padding: 20px; 268 border: 1px solid #ddd; 269 border-top: none; 270 border-radius: 0 0 5px 5px; 271 margin-bottom: 20px; 272 } 273 274 #wpft-howto p { 275 margin: 10px 0; 276 line-height: 1.6; 277 } 278 279 #wpft-howto ol { 280 margin: 15px 0; 281 padding-left: 20px; 282 } 283 284 #wpft-howto li { 285 margin-bottom: 10px; 286 line-height: 1.5; 287 } 288 289 #wpft-howto .command { 290 background: #333; 291 color: #fff; 292 padding: 2px 6px; 293 border-radius: 3px; 294 font-family: monospace; 295 font-size: 13px; 296 } 297 298 #wpft-howto .screenshot-container { 299 margin: 15px 0; 300 text-align: center; 301 padding: 10px; 302 background: #fff; 303 border: 1px solid #ddd; 304 border-radius: 3px; 305 } 306 307 #wpft-howto .help-screenshot { 308 max-width: 100%; 309 height: auto; 310 border: 1px solid #ccc; 311 } 312 313 #wpft-howto .notice { 314 padding: 12px; 315 margin: 15px 0; 316 border-left: 4px solid #00a0d2; 317 background: #f7fcfe; 318 } 319 320 #wpft-howto .external-link { 321 color: #0073aa; 322 text-decoration: none; 323 } 324 325 #wpft-howto .external-link:hover { 326 text-decoration: underline; 327 } 328 329 .load-spinner img { 330 width: 20px; 331 height: 20px; 332 } 333 334 /* Progress indicator */ 335 .tg-progress { 336 background: #f0f0f0; 337 border-radius: 10px; 338 height: 6px; 339 overflow: hidden; 340 margin: 15px 0; 341 } 342 343 .tg-progress-bar { 344 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 345 height: 100%; 346 border-radius: 10px; 347 transition: width 0.3s ease; 348 width: 0%; 349 } 350 351 /* Status indicators */ 352 .tg-status { 353 display: inline-flex; 354 align-items: center; 355 padding: 8px 12px; 356 border-radius: 6px; 357 font-size: 12px; 358 font-weight: 500; 359 margin-top: 10px; 360 } 361 362 .tg-status.success { 363 background: #d4edda; 364 color: #155724; 365 border: 1px solid #c3e6cb; 366 } 367 368 .tg-status.error { 369 background: #f8d7da; 370 color: #721c24; 371 border: 1px solid #f5c6cb; 372 } 373 374 .tg-status.warning { 375 background: #fff3cd; 376 color: #856404; 377 border: 1px solid #ffeeba; 378 } 379 380 .tg-status::before { 381 content: ''; 382 width: 8px; 383 height: 8px; 384 border-radius: 50%; 385 margin-right: 8px; 386 } 387 388 .tg-status.success::before { 389 background: #28a745; 390 } 391 392 .tg-status.error::before { 393 background: #dc3545; 394 } 395 396 .tg-status.warning::before { 397 background: #ffc107; 398 } 399 400 /* Confirmation field improvements */ 401 #factor-chat-confirm { 402 background: #f8f9fa; 403 border-radius: 8px; 404 padding: 15px; 405 border: 1px solid #e9ecef; 406 margin-top: 15px; 407 } 408 409 #tg_wp_factor_chat_id_confirm { 410 font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; 411 font-size: 14px; 412 padding: 8px 12px; 413 border: 2px solid #ddd; 414 border-radius: 6px; 415 transition: all 0.2s ease; 416 } 417 418 #tg_wp_factor_chat_id_confirm:focus { 419 border-color: #667eea; 420 box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2); 421 outline: none; 422 } 423 424 /* Responsive improvements */ 425 @media (max-width: 768px) { 426 #tg-2fa-configuration .form-table td { 427 display: block; 428 width: 100%; 429 padding-bottom: 10px; 430 } 431 432 .tg-action-button { 433 width: 100%; 434 margin-top: 10px; 435 } 436 } -
two-factor-login-telegram/trunk/assets/js/wp-factor-telegram-plugin.js
r3168516 r3332295 9 9 var $twbtn = $("#tg_wp_factor_chat_id_send"); 10 10 var $twctrl = $("#tg_wp_factor_valid"); 11 var $twenabled = $("#tg_wp_factor_enabled"); 12 var $twconfig = $("#tg-2fa-configuration"); 13 var $tweditbtn = $("#tg-edit-chat-id"); 14 var $twconfigrow = $(".tg-configured-row"); 11 15 12 16 var $twfcr = $("#factor-chat-response"); … … 23 27 function init() { 24 28 29 // Handle checkbox toggle for 2FA configuration with smooth animation 30 $twenabled.on("change", function(evt){ 31 var isConfigured = $twconfigrow.length > 0; 32 33 if ($(this).is(":checked") && !isConfigured) { 34 $twconfig.addClass('show').show(); 35 updateProgress(25); 36 } else { 37 $twconfig.removeClass('show'); 38 setTimeout(function() { 39 $twconfig.hide(); 40 }, 300); 41 $twctrl.val(0); 42 updateProgress(0); 43 resetStatusIndicators(); 44 } 45 }); 46 47 // Handle edit button click (when 2FA is already configured) 48 $tweditbtn.on("click", function(evt){ 49 evt.preventDefault(); 50 51 // Hide configured row and show configuration form 52 $twconfigrow.hide(); 53 $twconfig.addClass('show').show(); 54 55 // Make the input editable and clear it 56 $twfci.prop('readonly', false).removeClass('input-valid').css('background', '').val(''); 57 58 // Reset validation state 59 $twctrl.val(0); 60 updateProgress(25); 61 resetStatusIndicators(); 62 63 // Show modifying status message 64 $('.tg-status.success').removeClass('success').addClass('warning').text(tlj.modifying_setup); 65 }); 66 67 // Watch for changes in Chat ID when in edit mode 68 $twfci.on("input", function(){ 69 var currentValue = $(this).val(); 70 var originalValue = $(this).data('original-value'); 71 72 // If value changed from original, require re-validation 73 if (currentValue !== originalValue) { 74 $twctrl.val(0); 75 $(this).removeClass('input-valid'); 76 } 77 }); 78 79 // Initialize visibility based on checkbox state and configuration 80 var isConfigured = $twconfigrow.length > 0; 81 if ($twenabled.is(":checked") && !isConfigured) { 82 $twconfig.addClass('show').show(); 83 updateProgress(25); 84 } else { 85 $twconfig.removeClass('show').hide(); 86 } 87 88 // Store original chat ID value for comparison 89 if ($twfci.length) { 90 $twfci.data('original-value', $twfci.val()); 91 } 92 25 93 $twfci.on("change", function(evt){ 26 94 $twctrl.val(0); 95 // Validate Chat ID format (basic validation) 96 validateChatId($(this).val()); 27 97 }); 28 98 29 99 $twbtn.on("click", function(evt){ 30 31 100 evt.preventDefault(); 32 101 var chat_id = $twfci.val(); 102 103 if (!validateChatId(chat_id)) { 104 showStatus('#chat-id-status', 'error', tlj.invalid_chat_id); 105 return; 106 } 107 33 108 send_tg_token(chat_id); 34 35 109 }); 36 110 37 111 $twfcheck.on("click", function(evt){ 38 39 112 evt.preventDefault(); 40 113 var token = $twfciconf.val(); 41 114 var chat_id = $twfci.val(); 115 116 if (!token.trim()) { 117 showStatus('#validation-status', 'error', tlj.enter_confirmation_code); 118 return; 119 } 120 42 121 check_tg_token(token, chat_id); 43 44 122 }); 45 123 … … 106 184 $twfcheck.addClass('disabled').after('<div class="load-spinner"><img src="'+tlj.spinner+'" /></div>'); 107 185 $twfcr.hide(); 186 hideStatus('#validation-status'); 108 187 }, 109 188 dataType: "json", … … 114 193 $twfci.addClass("input-valid"); 115 194 $twctrl.val(1); 195 updateProgress(100); 196 showStatus('#validation-status', 'success', tlj.setup_completed); 116 197 } 117 198 else { 118 $twfcr.find(".wpft-notice p").text(response.msg); 119 $twfcr.show(); 199 showStatus('#validation-status', 'error', response.msg); 120 200 $twfci.removeClass("input-valid"); 121 201 $twctrl.val(0); … … 124 204 }, 125 205 error: function(xhr, ajaxOptions, thrownError){ 126 $twfcr.find(".wpft-notice p").text(tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 127 $twfcr.show(); 206 showStatus('#validation-status', 'error', tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 128 207 $twfci.removeClass("input-valid"); 129 208 }, … … 152 231 $twfcr.hide(); 153 232 $twfconf.hide(); 233 hideStatus('#chat-id-status'); 154 234 }, 155 235 dataType: "json", … … 159 239 $twfconf.show(); 160 240 $twfci.removeClass("input-valid"); 241 updateProgress(75); 242 showStatus('#chat-id-status', 'success', tlj.code_sent); 161 243 } 162 244 else { 163 $twfcr.find(".wpft-notice p").text(response.msg); 164 $twfcr.show(); 245 showStatus('#chat-id-status', 'error', response.msg); 165 246 } 166 247 167 248 }, 168 249 error: function(xhr, ajaxOptions, thrownError){ 169 $twfcr.find(".wpft-notice p").text(tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 170 $twfcr.show(); 250 showStatus('#chat-id-status', 'error', tlj.ajax_error+" "+thrownError+" ("+xhr.state+")"); 171 251 }, 172 252 complete: function() { … … 180 260 } 181 261 182 262 // Helper functions 263 function updateProgress(percentage) { 264 $('#tg-progress-bar').css('width', percentage + '%'); 265 } 266 267 function validateChatId(chatId) { 268 // Telegram Chat ID validation: must be numeric (positive for users, negative for groups) 269 if (!chatId || typeof chatId !== 'string') { 270 return false; 271 } 272 273 var trimmedId = chatId.trim(); 274 if (trimmedId === '') { 275 return false; 276 } 277 278 // Check if it's a valid number (can be negative for groups) 279 var numericId = parseInt(trimmedId, 10); 280 return !isNaN(numericId) && trimmedId === numericId.toString(); 281 } 282 283 function showStatus(selector, type, message) { 284 var $status = $(selector); 285 $status.removeClass('success error warning') 286 .addClass(type) 287 .text(message) 288 .fadeIn(300); 289 } 290 291 function hideStatus(selector) { 292 $(selector).fadeOut(300); 293 } 294 295 function resetStatusIndicators() { 296 hideStatus('#chat-id-status'); 297 hideStatus('#validation-status'); 298 } 183 299 184 300 }(jQuery); -
two-factor-login-telegram/trunk/includes/class-wp-factor-telegram-plugin.php
r3331421 r3332295 56 56 require_once(dirname(WP_FACTOR_TG_FILE) 57 57 . "/includes/class-wp-telegram.php"); 58 require_once(dirname(WP_FACTOR_TG_FILE) 59 . "/includes/class-telegram-logs-list-table.php"); 58 60 } 59 61 … … 235 237 236 238 /** 237 * Authentication page238 *239 * @param $user240 */241 242 private function authentication_page($user)243 {244 require_once(ABSPATH . '/wp-admin/includes/template.php');245 ?>246 247 <p class="notice notice-warning">248 <?php249 _e("Enter the code sent to your Telegram account.",250 "two-factor-login-telegram");251 ?>252 </p>253 <p>254 <label for="authcode" style="padding-top:1em">255 <?php256 _e("Authentication code:", "two-factor-login-telegram");257 ?>258 </label>259 <input type="text" name="authcode" id="authcode" class="input"260 value="" size="5"/>261 </p>262 <?php263 submit_button(__('Login with Telegram',264 'two-factor-login-telegram'));265 }266 267 /**268 239 * Login HTML Page 269 240 * … … 280 251 } 281 252 282 login_header();283 284 if (!empty($error_msg)) {285 echo '<div id="login_error"><strong>' . esc_html($error_msg)286 . '</strong><br /></div>';287 }288 253 // Filter hook to add a custom logo to the 2FA login screen 289 254 $plugin_logo = apply_filters('two_factor_login_telegram_logo', 290 255 plugins_url('assets/img/plugin_logo.png', WP_FACTOR_TG_FILE)); 291 ?> 292 293 <style> 294 body.login div#login h1 a { 295 background-image: url("<?php echo esc_url($plugin_logo); ?>"); 296 } 297 </style> 298 299 <form name="validate_tg" id="loginform" action="<?php 300 echo esc_url(site_url('wp-login.php?action=validate_tg', 301 'login_post')); ?>" method="post" autocomplete="off"> 302 <input type="hidden" name="nonce" 303 value="<?php echo wp_create_nonce('wp2fa_telegram_auth_nonce_' . $user->ID); ?>"> 304 <input type="hidden" name="wp-auth-id" id="wp-auth-id" value="<?php 305 echo esc_attr($user->ID); ?>"/> 306 <input type="hidden" name="redirect_to" value="<?php 307 echo esc_attr($redirect_to); ?>"/> 308 <input type="hidden" name="rememberme" id="rememberme" value="<?php 309 echo esc_attr($rememberme); ?>"/> 310 311 <?php 312 $this->authentication_page($user); ?> 313 </form> 314 315 <p id="backtoblog"> 316 <a href="<?php 317 echo esc_url(home_url('/')); ?>" title="<?php 318 __("Are you lost?", "two-factor-login-telegram"); ?>"><?php 319 echo sprintf(__('← Back to %s', 320 'two-factor-login-telegram'), 321 get_bloginfo('title', 'display')); ?></a> 322 </p> 323 324 <?php 325 do_action('login_footer'); ?> 326 <div class="clear"></div> 327 </body> 328 329 </html> 330 <?php 256 257 require_once(ABSPATH . '/wp-admin/includes/template.php'); 258 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/login-form.php"); 331 259 } 332 260 … … 361 289 $hashed_auth_code = hash('sha256', $authcode); 362 290 $current_datetime = current_time('mysql'); 363 $query = $wpdb->prepare( 291 292 // Check if token exists for this user 293 $token_exists_query = $wpdb->prepare( 364 294 "SELECT COUNT(*) 365 FROM $table_name 366 WHERE auth_code = %s 367 AND user_id = %d 368 AND expiration_date > %s", 295 FROM $table_name 296 WHERE auth_code = %s 297 AND user_id = %d", 298 $hashed_auth_code, $user_id 299 ); 300 301 $token_exists = ($wpdb->get_var($token_exists_query) > 0); 302 303 if (!$token_exists) { 304 return 'invalid'; // Invalid token 305 } 306 307 // Check if token is not expired 308 $valid_token_query = $wpdb->prepare( 309 "SELECT COUNT(*) 310 FROM $table_name 311 WHERE auth_code = %s 312 AND user_id = %d 313 AND expiration_date > %s", 369 314 $hashed_auth_code, $user_id, $current_datetime 370 315 ); 371 316 372 return ($wpdb->get_var($query) > 0); 317 $is_valid = ($wpdb->get_var($valid_token_query) > 0); 318 319 if (!$is_valid) { 320 return 'expired'; // Token exists but expired 321 } 322 323 return 'valid'; // Valid token 373 324 } 374 325 … … 393 344 } 394 345 395 if (true !== $this->is_valid_authcode($_REQUEST['authcode'], $user->ID)) { 346 $authcode_validation = $this->is_valid_authcode($_REQUEST['authcode'], $user->ID); 347 348 if ('valid' !== $authcode_validation) { 396 349 do_action('wp_factor_telegram_failed', $user->user_login); 397 350 … … 400 353 $chat_id = $this->get_user_chatid($user->ID); 401 354 $result = $this->telegram->send_tg_token($auth_code, $chat_id, $user->ID); 355 356 // Determine error message based on validation result 357 $error_message = ''; 358 $log_reason = ''; 359 360 if ($authcode_validation === 'expired') { 361 $error_message = __('The verification code has expired. We just sent you a new code, please try again!', 362 'two-factor-login-telegram'); 363 $log_reason = 'expired_verification_code'; 364 } else { 365 $error_message = __('Wrong verification code, we just sent a new code, please try again!', 366 'two-factor-login-telegram'); 367 $log_reason = 'wrong_verification_code'; 368 } 402 369 403 370 $this->log_telegram_action('auth_code_resent', array( … … 406 373 'chat_id' => $chat_id, 407 374 'success' => $result !== false, 408 'reason' => 'wrong_verification_code'375 'reason' => $log_reason 409 376 )); 410 377 411 $this->login_html($user, $_REQUEST['redirect_to'], 412 __('Wrong verification code, we just sent a new code, please try again!', 413 'two-factor-login-telegram')); 378 $this->login_html($user, $_REQUEST['redirect_to'], $error_message); 414 379 exit; 415 380 } … … 431 396 public function configure_tg() 432 397 { 433 require (dirname(WP_FACTOR_TG_FILE) . "/sections/configure_tg.php");398 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/configuration.php"); 434 399 } 435 400 … … 439 404 public function show_telegram_logs() 440 405 { 441 $logs = get_option('telegram_bot_logs', array()); 442 443 // Handle clear logs action 444 if (isset($_POST['clear_logs']) && wp_verify_nonce($_POST['_wpnonce'], 'clear_telegram_logs')) { 445 delete_option('telegram_bot_logs'); 446 $logs = array(); 447 echo '<div class="notice notice-success is-dismissible"><p>' . __('Logs cleared successfully.', 'two-factor-login-telegram') . '</p></div>'; 448 } 449 450 ?> 451 <div class="wrap"> 452 <h1><?php _e('Telegram Bot Logs', 'two-factor-login-telegram'); ?></h1> 453 454 <form method="post"> 455 <?php wp_nonce_field('clear_telegram_logs'); ?> 456 <input type="submit" name="clear_logs" class="button button-secondary" value="<?php _e('Clear Logs', 'two-factor-login-telegram'); ?>" onclick="return confirm('<?php _e('Are you sure you want to clear all logs?', 'two-factor-login-telegram'); ?>')"> 457 </form> 458 459 <br> 460 461 <?php if (empty($logs)): ?> 462 <p><?php _e('No logs available.', 'two-factor-login-telegram'); ?></p> 463 <?php else: ?> 464 <table class="wp-list-table widefat fixed striped"> 465 <thead> 466 <tr> 467 <th style="width: 15%;"><?php _e('Timestamp', 'two-factor-login-telegram'); ?></th> 468 <th style="width: 15%;"><?php _e('Action', 'two-factor-login-telegram'); ?></th> 469 <th><?php _e('Data', 'two-factor-login-telegram'); ?></th> 470 </tr> 471 </thead> 472 <tbody> 473 <?php foreach ($logs as $log): ?> 474 <tr> 475 <td><?php echo esc_html($log['timestamp']); ?></td> 476 <td><?php echo esc_html($log['action']); ?></td> 477 <td> 478 <details> 479 <summary><?php _e('View details', 'two-factor-login-telegram'); ?></summary> 480 <pre style="background: #f1f1f1; padding: 10px; margin-top: 10px; overflow-x: auto;"><?php echo esc_html(print_r($log['data'], true)); ?></pre> 481 </details> 482 </td> 483 </tr> 484 <?php endforeach; ?> 485 </tbody> 486 </table> 487 <?php endif; ?> 488 </div> 489 <?php 406 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/logs-page.php"); 490 407 } 491 408 … … 502 419 } 503 420 504 function delete_transients($option_name, $old_value, $new_value) 505 { 506 if ($this->namespace === $option_name) { 507 delete_transient(WP_FACTOR_TG_GETME_TRANSIENT); 508 509 if (!empty($new_value['bot_token'])) { 510 $webhook_url = rest_url('telegram/v1/webhook'); 511 $this->telegram->set_bot_token($new_value['bot_token'])->set_webhook($webhook_url); 512 } 513 } 421 function sanitize_settings($input) 422 { 423 // Sanitize input values 424 $sanitized = array(); 425 426 if (isset($input['bot_token'])) { 427 $sanitized['bot_token'] = sanitize_text_field($input['bot_token']); 428 } 429 430 if (isset($input['chat_id'])) { 431 $sanitized['chat_id'] = sanitize_text_field($input['chat_id']); 432 } 433 434 if (isset($input['enabled'])) { 435 $sanitized['enabled'] = $input['enabled'] === '1' ? '1' : '0'; 436 } 437 438 if (isset($input['show_site_name'])) { 439 $sanitized['show_site_name'] = $input['show_site_name'] === '1' ? '1' : '0'; 440 } 441 442 if (isset($input['show_site_url'])) { 443 $sanitized['show_site_url'] = $input['show_site_url'] === '1' ? '1' : '0'; 444 } 445 446 if (isset($input['delete_data_on_deactivation'])) { 447 $sanitized['delete_data_on_deactivation'] = $input['delete_data_on_deactivation'] === '1' ? '1' : '0'; 448 } 449 450 // Delete transients when settings are updated 451 delete_transient(WP_FACTOR_TG_GETME_TRANSIENT); 452 453 // Set webhook if bot token is provided 454 if (!empty($sanitized['bot_token'])) { 455 $webhook_url = rest_url('telegram/v1/webhook'); 456 $this->telegram->set_bot_token($sanitized['bot_token'])->set_webhook($webhook_url); 457 } 458 459 return $sanitized; 514 460 } 515 461 516 462 function tg_register_settings() 517 463 { 518 register_setting($this->namespace, $this->namespace); 464 register_setting($this->namespace, $this->namespace, array( 465 'sanitize_callback' => array($this, 'sanitize_settings') 466 )); 519 467 520 468 add_settings_section($this->namespace . '_section', 521 469 __('Telegram Configuration', "two-factor-login-telegram"), '', 470 $this->namespace . '.php'); 471 472 add_settings_section($this->namespace . '_failed_login_section', 473 __('Failed Login Report', "two-factor-login-telegram"), array($this, 'failed_login_section_callback'), 474 $this->namespace . '.php'); 475 476 add_settings_section($this->namespace . '_data_management_section', 477 __('Data Management', "two-factor-login-telegram"), array($this, 'data_management_section_callback'), 522 478 $this->namespace . '.php'); 523 479 … … 539 495 $field_args); 540 496 497 // Move Chat ID to Failed Login Report section 541 498 $field_args = array( 542 499 'type' => 'text', 543 500 'id' => 'chat_id', 544 501 'name' => 'chat_id', 545 'desc' => __(' Chat ID (Telegram) for failed login report.',502 'desc' => __('Enter your Telegram Chat ID to receive notifications about failed login attempts.', 546 503 "two-factor-login-telegram"), 547 504 'std' => '', … … 551 508 552 509 add_settings_field('chat_id', 553 __('Chat ID ', "two-factor-login-telegram"), array(510 __('Chat ID for Reports', "two-factor-login-telegram"), array( 554 511 $this, 555 512 'tg_display_setting', 556 ), $this->namespace . '.php', $this->namespace . '_ section',513 ), $this->namespace . '.php', $this->namespace . '_failed_login_section', 557 514 $field_args); 558 515 … … 575 532 $field_args); 576 533 534 // Move Show site name to Failed Login Report section 577 535 $field_args = array( 578 536 'type' => 'checkbox', 579 537 'id' => 'show_site_name', 580 538 'name' => 'show_site_name', 581 'desc' => __(' Select this checkbox to show site name on failed login attempt message.<br>This option is useful when you use same bot in severalsites.',539 'desc' => __('Include site name in failed login notifications.<br>Useful when using the same bot for multiple sites.', 582 540 'two-factor-login-telegram'), 583 541 'std' => '', … … 587 545 588 546 add_settings_field('show_site_name', 589 __('Show site name?', 'two-factor-login-telegram'), array(547 __('Show Site Name', 'two-factor-login-telegram'), array( 590 548 $this, 591 549 'tg_display_setting', 592 ), $this->namespace . '.php', $this->namespace . '_ section',550 ), $this->namespace . '.php', $this->namespace . '_failed_login_section', 593 551 $field_args); 594 552 553 // Move Show site URL to Failed Login Report section 595 554 $field_args = array( 596 555 'type' => 'checkbox', 597 556 'id' => 'show_site_url', 598 557 'name' => 'show_site_url', 599 'desc' => __(' Select this checkbox to show site URL on failed login attempt message.<br>This option is useful when you use same bot in severalsites.',558 'desc' => __('Include site URL in failed login notifications.<br>Useful when using the same bot for multiple sites.', 600 559 'two-factor-login-telegram'), 601 560 'std' => '', … … 605 564 606 565 add_settings_field('show_site_url', 607 __('Show site URL?', 'two-factor-login-telegram'), array(566 __('Show Site URL', 'two-factor-login-telegram'), array( 608 567 $this, 609 568 'tg_display_setting', 610 ), $this->namespace . '.php', $this->namespace . '_section', 569 ), $this->namespace . '.php', $this->namespace . '_failed_login_section', 570 $field_args); 571 572 // Add data cleanup option to Data Management section 573 $field_args = array( 574 'type' => 'checkbox', 575 'id' => 'delete_data_on_deactivation', 576 'name' => 'delete_data_on_deactivation', 577 'desc' => __('Delete all plugin data when the plugin is deactivated.<br><strong>Warning:</strong> This will permanently remove all settings, user configurations, authentication codes, and logs.', 578 'two-factor-login-telegram'), 579 'std' => '', 580 'label_for' => 'delete_data_on_deactivation', 581 'class' => 'css_class', 582 ); 583 584 add_settings_field('delete_data_on_deactivation', 585 __('Delete Data on Deactivation', 'two-factor-login-telegram'), array( 586 $this, 587 'tg_display_setting', 588 ), $this->namespace . '.php', $this->namespace . '_data_management_section', 611 589 $field_args); 612 590 } … … 680 658 681 659 /** 660 * Failed login section callback 661 */ 662 public function failed_login_section_callback() 663 { 664 echo '<p>' . __('Configure how to receive notifications when someone fails to log in to your site.', 'two-factor-login-telegram') . '</p>'; 665 } 666 667 /** 668 * Data management section callback 669 */ 670 public function data_management_section_callback() 671 { 672 echo '<p>' . __('Manage plugin data and cleanup options.', 'two-factor-login-telegram') . '</p>'; 673 } 674 675 /** 682 676 * Action links 683 677 * … … 735 729 public function tg_add_two_factor_fields($user) 736 730 { 737 ?> 738 <h3 id="wptl"><?php 739 _e('2FA with Telegram', 740 'two-factor-login-telegram'); ?></h3> 741 742 <table class="form-table"> 743 744 <tr> 745 <th> 746 <label for="tg_wp_factor_enabled"><?php 747 _e('Enable 2FA', 748 'two-factor-login-telegram'); ?> 749 </label> 750 </th> 751 <td colspan="2"> 752 <input type="hidden" name="tg_wp_factor_valid" 753 id="tg_wp_factor_valid" value="<?php 754 echo (int)(esc_attr(get_the_author_meta('tg_wp_factor_enabled', 755 $user->ID)) === "1"); ?>"> 756 <input type="checkbox" name="tg_wp_factor_enabled" 757 id="tg_wp_factor_enabled" value="1" 758 class="regular-text" <?php 759 echo checked(esc_attr(get_the_author_meta('tg_wp_factor_enabled', 760 $user->ID)), 1); ?> /><br/> 761 </td> 762 </tr> 763 764 <tr> 765 766 <td colspan="3"> 767 768 <?php 769 $username = $this->telegram->get_me()->username; 770 ?> 771 772 <div> 773 774 <ol> 775 <li> 776 <?php 777 printf(__('Open a conversation with %s and press on <strong>Start</strong>', 778 'two-factor-login-telegram'), 779 '<a href="https://telegram.me/' . $username 780 . '" target="_blank">@' . $username . '</a>'); 781 ?> 782 </li> 783 784 <li> 785 <?php 786 printf(__('Type command %s to obtain your Chat ID.', 787 "two-factor-login-telegram"), 788 '<code>/get_id</code>'); 789 ?> 790 </li> 791 <li> 792 <?php 793 _e("The bot will reply with your <strong>Chat ID</strong> number", 794 'two-factor-login-telegram'); 795 ?> 796 </li> 797 798 <li><?php 799 _e('Copy your Chat ID and paste it below, then press <strong>Submit code</strong>', 800 'two-factor-login-telegram'); ?></li> 801 </ol> 802 </div> 803 </td> 804 805 </tr> 806 807 <tr> 808 <th> 809 <label for="tg_wp_factor_chat_id"><?php 810 _e('Telegram Chat ID', 811 'two-factor-login-telegram'); ?> 812 </label></th> 813 <td> 814 <input type="text" name="tg_wp_factor_chat_id" 815 id="tg_wp_factor_chat_id" value="<?php 816 echo esc_attr(get_the_author_meta('tg_wp_factor_chat_id', 817 $user->ID)); ?>" class="regular-text"/><br/> 818 <span class="description"><?php 819 _e('Put your Telegram Chat ID', 820 'two-factor-login-telegram'); ?></span> 821 </td> 822 <td> 823 <button class="button" id="tg_wp_factor_chat_id_send"><?php 824 _e("Submit code", 825 "two-factor-login-telegram"); ?></button> 826 </td> 827 </tr> 828 829 <tr id="factor-chat-confirm"> 830 <th> 831 <label for="tg_wp_factor_chat_id_confirm"><?php 832 _e('Confirmation code', 833 'two-factor-login-telegram'); ?> 834 </label></th> 835 <td> 836 <input type="text" name="tg_wp_factor_chat_id_confirm" 837 id="tg_wp_factor_chat_id_confirm" value="" 838 class="regular-text"/><br/> 839 <span class="description"><?php 840 _e('Please enter the confirmation code you received on Telegram', 841 'two-factor-login-telegram'); ?></span> 842 </td> 843 <td> 844 <button class="button" id="tg_wp_factor_chat_id_check"><?php 845 _e("Validate", 846 "two-factor-login-telegram"); ?></button> 847 </td> 848 </tr> 849 <tr id="factor-chat-response"> 850 <td colspan="3"> 851 <div class="wpft-notice wpft-notice-warning"> 852 <p></p> 853 </div> 854 </td> 855 </tr> 856 </table> 857 <?php 731 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/user-2fa-form.php"); 858 732 } 859 733 … … 878 752 "sendtoken_nonce" => wp_create_nonce('ajax-sendtoken-nonce'), 879 753 "tokencheck_nonce" => wp_create_nonce('ajax-tokencheck-nonce'), 880 "spinner" => admin_url("/images/spinner.gif") 754 "spinner" => admin_url("/images/spinner.gif"), 755 // Translated messages 756 "invalid_chat_id" => __('Please enter a valid Chat ID', 'two-factor-login-telegram'), 757 "enter_confirmation_code" => __('Please enter the confirmation code', 'two-factor-login-telegram'), 758 "setup_completed" => __('✅ 2FA setup completed successfully!', 'two-factor-login-telegram'), 759 "code_sent" => __('✅ Code sent! Check your Telegram', 'two-factor-login-telegram'), 760 "modifying_setup" => __('⚠️ Modifying 2FA configuration - validation required', 'two-factor-login-telegram') 881 761 )); 882 762 … … 954 834 __("Use this code to complete your 2FA setup in WordPress, or click the button below:", "two-factor-login-telegram") 955 835 ); 956 836 957 837 // Create inline keyboard with validation button 958 838 $reply_markup = null; 959 839 if ($current_user_id) { 960 840 $nonce = wp_create_nonce('telegram_validate_' . $current_user_id . '_' . $auth_code); 961 $validation_url = admin_url(' admin.php?page=tg-conf&action=telegram_validate&user_id=' . $current_user_id . '&token=' . $auth_code . '&nonce=' . $nonce);962 841 $validation_url = admin_url('options-general.php?page=tg-conf&action=telegram_validate&chat_id='.$_POST['chat_id'].'&user_id=' . $current_user_id . '&token=' . $auth_code . '&nonce=' . $nonce); 842 963 843 $reply_markup = array( 964 844 'inline_keyboard' => array( … … 972 852 ); 973 853 } 974 854 975 855 $send = $tg->send_with_keyboard($validation_message, $_POST['chat_id'], $reply_markup); 976 856 … … 1077 957 } 1078 958 1079 public function tg_save_custom_user_profile_fields($user_id) 959 /** 960 * Save user's 2FA settings 961 * 962 * @param int $user_id User ID 963 * @param string $chat_id Telegram Chat ID 964 * @param bool $enabled Whether 2FA is enabled 965 * @return bool Success status 966 */ 967 public function save_user_2fa_settings($user_id, $chat_id, $enabled = true) 1080 968 { 1081 969 if (!current_user_can('edit_user', $user_id)) { … … 1083 971 } 1084 972 973 if (empty($chat_id)) { 974 return false; 975 } 976 977 update_user_meta($user_id, 'tg_wp_factor_chat_id', sanitize_text_field($chat_id)); 978 update_user_meta($user_id, 'tg_wp_factor_enabled', $enabled ? '1' : '0'); 979 980 return true; 981 } 982 983 public function tg_save_custom_user_profile_fields($user_id) 984 { 1085 985 if ($_POST['tg_wp_factor_valid'] == 0 1086 986 || $_POST['tg_wp_factor_chat_id'] == "" … … 1089 989 } 1090 990 1091 update_user_meta($user_id, 'tg_wp_factor_chat_id', 1092 $_POST['tg_wp_factor_chat_id']); 1093 update_user_meta($user_id, 'tg_wp_factor_enabled', 1094 $_POST['tg_wp_factor_enabled']); 1095 1096 return true; 991 return $this->save_user_2fa_settings( 992 $user_id, 993 $_POST['tg_wp_factor_chat_id'], 994 isset($_POST['tg_wp_factor_enabled']) 995 ); 1097 996 } 1098 997 … … 1169 1068 } 1170 1069 1070 private function create_or_update_activities_table() 1071 { 1072 global $wpdb; 1073 1074 $table_name = $wpdb->prefix . 'wp2fat_activities'; 1075 1076 $charset_collate = $wpdb->get_charset_collate(); 1077 $sql = "CREATE TABLE IF NOT EXISTS $table_name ( 1078 id mediumint(9) NOT NULL AUTO_INCREMENT, 1079 timestamp datetime NOT NULL, 1080 action varchar(100) NOT NULL, 1081 data longtext, 1082 PRIMARY KEY (id), 1083 KEY timestamp (timestamp), 1084 KEY action (action) 1085 ) $charset_collate"; 1086 1087 require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); 1088 1089 // Esegue la query per creare/aggiornare la tabella 1090 dbDelta($sql); 1091 } 1092 1093 private function migrate_logs_to_activities_table() 1094 { 1095 global $wpdb; 1096 1097 // Check if old logs exist in option 1098 $old_logs = get_option('telegram_bot_logs', array()); 1099 1100 if (!empty($old_logs)) { 1101 $activities_table = $wpdb->prefix . 'wp2fat_activities'; 1102 1103 // Migrate each log entry 1104 foreach ($old_logs as $log) { 1105 $wpdb->insert( 1106 $activities_table, 1107 array( 1108 'timestamp' => $log['timestamp'], 1109 'action' => $log['action'], 1110 'data' => maybe_serialize($log['data']) 1111 ), 1112 array('%s', '%s', '%s') 1113 ); 1114 } 1115 1116 // Delete the old option after migration 1117 delete_option('telegram_bot_logs'); 1118 } 1119 } 1120 1171 1121 function plugin_activation() 1172 1122 { 1173 1123 $this->create_or_update_telegram_auth_codes_table(); 1124 $this->create_or_update_activities_table(); 1125 $this->migrate_logs_to_activities_table(); 1174 1126 update_option('wp_factor_plugin_version', WP_FACTOR_PLUGIN_VERSION); 1175 1127 1176 // Flush rewrite rules to add our webhook endpoint 1128 // Add rewrite rules before flushing 1129 $this->add_telegram_rewrite_rules(); 1130 1131 // Flush rewrite rules to add our new rules 1177 1132 flush_rewrite_rules(); 1133 } 1134 1135 function plugin_deactivation() 1136 { 1137 // Check if data cleanup is enabled 1138 $plugin_options = get_option($this->namespace, array()); 1139 1140 if (isset($plugin_options['delete_data_on_deactivation']) && $plugin_options['delete_data_on_deactivation'] === '1') { 1141 $this->cleanup_all_plugin_data(); 1142 } 1143 1144 // Always flush rewrite rules on deactivation 1145 flush_rewrite_rules(); 1146 } 1147 1148 private function cleanup_all_plugin_data() 1149 { 1150 global $wpdb; 1151 1152 // Delete plugin settings 1153 delete_option($this->namespace); 1154 delete_option('wp_factor_plugin_version'); 1155 delete_option('telegram_bot_logs'); // For backward compatibility 1156 1157 // Delete auth codes table 1158 $auth_codes_table = $wpdb->prefix . 'telegram_auth_codes'; 1159 $wpdb->query("DROP TABLE IF EXISTS $auth_codes_table"); 1160 1161 // Delete activities table 1162 $activities_table = $wpdb->prefix . 'wp2fat_activities'; 1163 $wpdb->query("DROP TABLE IF EXISTS $activities_table"); 1164 1165 // Delete user meta data for all users 1166 $wpdb->delete( 1167 $wpdb->usermeta, 1168 array( 1169 'meta_key' => 'tg_wp_factor_chat_id' 1170 ) 1171 ); 1172 1173 $wpdb->delete( 1174 $wpdb->usermeta, 1175 array( 1176 'meta_key' => 'tg_wp_factor_enabled' 1177 ) 1178 ); 1179 1180 // Delete all transients related to the plugin 1181 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_wp2fa_telegram_authcode_%'"); 1182 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_timeout_wp2fa_telegram_authcode_%'"); 1183 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_" . WP_FACTOR_TG_GETME_TRANSIENT . "%'"); 1184 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_timeout_" . WP_FACTOR_TG_GETME_TRANSIENT . "%'"); 1178 1185 } 1179 1186 … … 1184 1191 if ($installed_version !== WP_FACTOR_PLUGIN_VERSION) { 1185 1192 $this->create_or_update_telegram_auth_codes_table(); 1193 $this->create_or_update_activities_table(); 1194 $this->migrate_logs_to_activities_table(); 1186 1195 update_option('wp_factor_plugin_version', WP_FACTOR_PLUGIN_VERSION); 1187 1196 } … … 1201 1210 1202 1211 register_activation_hook(WP_FACTOR_TG_FILE, array($this, 'plugin_activation')); 1212 register_deactivation_hook(WP_FACTOR_TG_FILE, array($this, 'plugin_deactivation')); 1203 1213 add_action('plugins_loaded', array($this, 'check_plugin_update')); 1204 1214 … … 1209 1219 . plugin_basename(WP_FACTOR_TG_FILE), 1210 1220 array($this, 'action_links')); 1211 add_action('updated_option', array($this, 'delete_transients'),1212 10, 3);1213 1221 } 1214 1222 … … 1223 1231 } 1224 1232 1225 add_action('show_user_profile', 1226 array($this, 'tg_add_two_factor_fields')); 1227 add_action('edit_user_profile', 1228 array($this, 'tg_add_two_factor_fields')); 1233 if ($this->is_valid_bot()) { 1234 add_action('show_user_profile', 1235 array($this, 'tg_add_two_factor_fields')); 1236 add_action('edit_user_profile', 1237 array($this, 'tg_add_two_factor_fields')); 1238 } 1229 1239 1230 1240 add_action('personal_options_update', … … 1242 1252 // Add REST API endpoint for Telegram webhook 1243 1253 add_action('rest_api_init', array($this, 'register_telegram_webhook_route')); 1254 1255 // Add rewrite rules for Telegram confirmation URLs 1256 add_action('init', array($this, 'add_telegram_rewrite_rules')); 1257 add_action('parse_request', array($this, 'parse_telegram_request')); 1258 1244 1259 } 1245 1260 … … 1253 1268 'permission_callback' => '__return_true', 1254 1269 )); 1255 1256 register_rest_route('telegram/v1', '/confirm/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)', array( 1257 'methods' => 'GET', 1258 'callback' => array($this, 'handle_telegram_confirmation'), 1259 'permission_callback' => '__return_true', 1260 'args' => array( 1261 'user_id' => array( 1262 'validate_callback' => function($param, $request, $key) { 1263 return is_numeric($param); 1264 } 1265 ), 1266 'token' => array( 1267 'validate_callback' => function($param, $request, $key) { 1268 return preg_match('/^[a-zA-Z0-9]+$/', $param); 1269 } 1270 ), 1271 'nonce' => array( 1272 'required' => true, 1273 ) 1270 } 1271 1272 /** 1273 * Add rewrite rules for Telegram confirmation URLs 1274 */ 1275 public function add_telegram_rewrite_rules() { 1276 add_rewrite_rule( 1277 '^telegram-confirm/([0-9]+)/([a-zA-Z0-9]+)/?$', 1278 'index.php?telegram_confirm=1&user_id=$matches[1]&token=$matches[2]', 1279 'top' 1280 ); 1281 1282 // Add query vars 1283 add_filter('query_vars', function($vars) { 1284 $vars[] = 'telegram_confirm'; 1285 $vars[] = 'user_id'; 1286 $vars[] = 'token'; 1287 return $vars; 1288 }); 1289 } 1290 1291 /** 1292 * Parse Telegram confirmation requests 1293 */ 1294 public function parse_telegram_request() { 1295 global $wp; 1296 1297 if (isset($wp->query_vars['telegram_confirm']) && $wp->query_vars['telegram_confirm'] == 1) { 1298 $user_id = intval($wp->query_vars['user_id']); 1299 $token = sanitize_text_field($wp->query_vars['token']); 1300 $nonce = sanitize_text_field($_GET['nonce'] ?? ''); 1301 1302 $this->handle_telegram_confirmation_direct($user_id, $token, $nonce); 1303 } 1304 } 1305 1306 /** 1307 * Handle Telegram confirmation via direct URL (not REST API) 1308 */ 1309 public function handle_telegram_confirmation_direct($user_id, $token, $nonce) { 1310 // Verify nonce 1311 if (!wp_verify_nonce($nonce, 'telegram_confirm_' . $user_id . '_' . $token)) { 1312 $this->log_telegram_action('confirmation_failed', array( 1313 'user_id' => $user_id, 1314 'token' => $token, 1315 'reason' => 'invalid_nonce' 1316 )); 1317 1318 // Include error template 1319 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-security-failed.php"); 1320 } 1321 1322 // Validate the token 1323 $authcode_validation = $this->is_valid_authcode($token, $user_id); 1324 1325 if ('valid' !== $authcode_validation) { 1326 if ($authcode_validation === 'expired') { 1327 $log_reason = 'expired_token'; 1328 } else { 1329 $log_reason = 'invalid_token'; 1330 } 1331 1332 $this->log_telegram_action('confirmation_failed', array( 1333 'user_id' => $user_id, 1334 'token' => $token, 1335 'reason' => $log_reason 1336 )); 1337 1338 // Include appropriate error template 1339 if ($authcode_validation === 'expired') { 1340 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-expired-token.php"); 1341 } else { 1342 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-invalid-token.php"); 1343 } 1344 } 1345 1346 // Get user 1347 $user = get_userdata($user_id); 1348 if (!$user) { 1349 require_once(dirname(WP_FACTOR_TG_FILE) . "/templates/error-invalid-token.php"); 1350 } 1351 1352 // Log the user in 1353 wp_set_auth_cookie($user_id, false); 1354 1355 $this->log_telegram_action('confirmation_success', array( 1356 'user_id' => $user_id, 1357 'user_login' => $user->user_login, 1358 'token' => $token, 1359 'method' => 'direct_confirmation' 1360 )); 1361 1362 // Redirect to admin or specified location 1363 $redirect_url = apply_filters('telegram_confirmation_redirect_url', admin_url(), $user); 1364 1365 // Redirect directly 1366 wp_safe_redirect($redirect_url); 1367 exit; 1368 } 1369 1370 /** 1371 * Log Telegram bot actions 1372 */ 1373 public function log_telegram_action($action, $data = array()) { 1374 global $wpdb; 1375 1376 $activities_table = $wpdb->prefix . 'wp2fat_activities'; 1377 1378 // Insert new log entry 1379 $wpdb->insert( 1380 $activities_table, 1381 array( 1382 'timestamp' => current_time('mysql'), 1383 'action' => $action, 1384 'data' => maybe_serialize($data) 1274 1385 ), 1275 )); 1276 } 1277 1278 /** 1279 * Log Telegram bot actions 1280 */ 1281 private function log_telegram_action($action, $data = array()) { 1282 $log_entry = array( 1283 'timestamp' => current_time('mysql'), 1284 'action' => $action, 1285 'data' => $data 1286 ); 1287 1288 $logs = get_option('telegram_bot_logs', array()); 1289 array_unshift($logs, $log_entry); 1290 1291 // Keep only last 100 log entries 1292 $logs = array_slice($logs, 0, 100); 1293 1294 update_option('telegram_bot_logs', $logs); 1386 array('%s', '%s', '%s') 1387 ); 1388 1389 // Clean up old entries - keep only last 1000 entries 1390 $wpdb->query("DELETE FROM $activities_table WHERE id NOT IN (SELECT id FROM (SELECT id FROM $activities_table ORDER BY timestamp DESC LIMIT 1000) temp_table)"); 1295 1391 } 1296 1392 … … 1351 1447 } 1352 1448 1353 /** 1354 * Handle Telegram confirmation via link 1355 */ 1356 public function handle_telegram_confirmation($request) { 1357 $user_id = intval($request['user_id']); 1358 $token = sanitize_text_field($request['token']); 1359 $nonce = sanitize_text_field($request->get_param('nonce')); 1360 1361 // Verify nonce 1362 if (!wp_verify_nonce($nonce, 'telegram_confirm_' . $user_id . '_' . $token)) { 1363 $this->log_telegram_action('confirmation_failed', array( 1364 'user_id' => $user_id, 1365 'token' => $token, 1366 'reason' => 'invalid_nonce' 1367 )); 1368 return new WP_Error('invalid_nonce', __('Security check failed.', 'two-factor-login-telegram'), array('status' => 403)); 1369 } 1370 1371 // Validate the token 1372 if (!$this->is_valid_authcode($token, $user_id)) { 1373 $this->log_telegram_action('confirmation_failed', array( 1374 'user_id' => $user_id, 1375 'token' => $token, 1376 'reason' => 'invalid_token' 1377 )); 1378 return new WP_Error('invalid_token', __('Invalid or expired token.', 'two-factor-login-telegram'), array('status' => 400)); 1379 } 1380 1381 // Get user 1382 $user = get_userdata($user_id); 1383 if (!$user) { 1384 return new WP_Error('invalid_user', __('Invalid user.', 'two-factor-login-telegram'), array('status' => 400)); 1385 } 1386 1387 // Log the user in 1388 wp_set_auth_cookie($user_id, false); 1389 1390 $this->log_telegram_action('confirmation_success', array( 1391 'user_id' => $user_id, 1392 'user_login' => $user->user_login, 1393 'token' => $token, 1394 'method' => 'link_confirmation' 1395 )); 1396 1397 // Redirect to admin or specified location 1398 $redirect_url = apply_filters('telegram_confirmation_redirect_url', admin_url(), $user); 1399 1400 // Redirect directly instead of returning JSON 1401 wp_safe_redirect($redirect_url); 1402 exit; 1403 } 1449 1404 1450 1405 1451 } -
two-factor-login-telegram/trunk/includes/class-wp-telegram.php
r3331421 r3332295 148 148 if ($user_id) { 149 149 $nonce = wp_create_nonce('telegram_confirm_' . $user_id . '_' . $token); 150 $confirmation_url = site_url('/wp-json/telegram/v1/confirm/' . $user_id . '/' . $token . '?nonce=' . $nonce);150 $confirmation_url = home_url('/telegram-confirm/' . $user_id . '/' . $token . '/?nonce=' . $nonce); 151 151 152 152 $reply_markup = array( -
two-factor-login-telegram/trunk/two-factor-telegram.php
r3331421 r3332295 5 5 * Plugin URI: https://blog.dueclic.com/wordpress-autenticazione-due-fattori-telegram/ 6 6 * Description: This plugin enables two factor authentication with Telegram by increasing your website security and sends an alert every time a wrong login occurs. 7 * Version: 3. 47 * Version: 3.5.0 8 8 * Requires at least: 6.0 9 9 * Tested up to: 6.8 … … 22 22 } 23 23 24 define('WP_FACTOR_PLUGIN_VERSION', '3. 4');24 define('WP_FACTOR_PLUGIN_VERSION', '3.5.0'); 25 25 26 26 define('WP_FACTOR_AUTHCODE_EXPIRE_SECONDS', 60 * 20);
Note: See TracChangeset
for help on using the changeset viewer.
