Plugin Directory

Changeset 3391428


Ignore:
Timestamp:
11/06/2025 08:39:22 PM (5 weeks ago)
Author:
wpfastsec
Message:

Update 1.3.0

  • CVE Analise
Location:
ht-security
Files:
4 added
2 edited

Legend:

Unmodified
Added
Removed
  • ht-security/trunk/ht-security.php

    r3355589 r3391428  
    33Plugin Name: HT Security
    44Description: Suite de Segurança completa: Cabeçalhos de segurança, alertas por e-mail, verificação do Core, bloqueio de enumeração de usuários, modo de manutenção e auditoria de permissões.
    5 Version: 1.2.0
     5Version: 1.3.0
    66Requires at least: 6.5
    77Requires PHP: 8.2
     
    7272        'default'           => '',
    7373    ] );
     74    register_setting( 'htsec_settings_group', 'htsec_nvd_api_key', [
     75        'type'              => 'string',
     76        'sanitize_callback' => 'sanitize_text_field',
     77        'default'           => '',
     78    ] );
     79    register_setting( 'htsec_settings_group', 'htsec_enable_cve_alerts', [
     80        'type'              => 'boolean',
     81        'sanitize_callback' => 'rest_sanitize_boolean',
     82        'default'           => 0,
     83    ] );
     84    register_setting( 'htsec_settings_group', 'htsec_show_plugin_badges', [
     85        'type'              => 'boolean',
     86        'sanitize_callback' => 'rest_sanitize_boolean',
     87        'default'           => 1,
     88    ] );
    7489
    7590    add_settings_section(
     
    175190        'htsec_main_section'
    176191    );
     192
     193    add_settings_field(
     194        'htsec_nvd_api_key',
     195        esc_html__( 'API Key NVD (Opcional)', 'ht-security' ),
     196        function() {
     197            $value = get_option( 'htsec_nvd_api_key', '' );
     198            printf(
     199                '<input type="text" name="htsec_nvd_api_key" value="%s" class="regular-text">',
     200                esc_attr( $value )
     201            );
     202            echo '<p class="description">' . esc_html__( 'API Key do National Vulnerability Database. Sem API Key: 5 requisições/30s. Com API Key: 50 requisições/30s.', 'ht-security' ) . '</p>';
     203            echo '<p class="description">' . esc_html__( 'Obtenha sua API Key em: https://nvd.nist.gov/developers/request-an-api-key', 'ht-security' ) . '</p>';
     204        },
     205        'ht-security',
     206        'htsec_main_section'
     207    );
     208
     209    add_settings_field(
     210        'htsec_enable_cve_alerts',
     211        esc_html__( 'Alertas de Vulnerabilidades', 'ht-security' ),
     212        function() {
     213            $value = get_option( 'htsec_enable_cve_alerts', 0 );
     214            printf(
     215                '<input type="checkbox" name="htsec_enable_cve_alerts" value="1" %s> %s',
     216                checked( 1, $value, false ),
     217                esc_html__( 'Enviar e-mail quando vulnerabilidades CVE forem detectadas', 'ht-security' )
     218            );
     219            echo '<p class="description">' . esc_html__( 'Verificação automática a cada 12 horas.', 'ht-security' ) . '</p>';
     220        },
     221        'ht-security',
     222        'htsec_main_section'
     223    );
     224
     225    add_settings_field(
     226        'htsec_show_plugin_badges',
     227        esc_html__( 'Indicadores na Página de Plugins', 'ht-security' ),
     228        function() {
     229            $value = get_option( 'htsec_show_plugin_badges', 1 );
     230            printf(
     231                '<input type="checkbox" name="htsec_show_plugin_badges" value="1" %s> %s',
     232                checked( 1, $value, false ),
     233                esc_html__( 'Exibir badges de segurança na página de plugins', 'ht-security' )
     234            );
     235            echo '<p class="description">' . esc_html__( 'Mostra indicadores verdes/vermelhos em cada plugin indicando status de vulnerabilidades.', 'ht-security' ) . '</p>';
     236        },
     237        'ht-security',
     238        'htsec_main_section'
     239    );
    177240}
    178241
     
    191254
    192255/**
     256 * Adiciona estilos CSS personalizados na página de administração.
     257 */
     258add_action( 'admin_head', 'htsec_admin_styles' );
     259function htsec_admin_styles() {
     260    $screen = get_current_screen();
     261    if ( isset( $screen->id ) && 'settings_page_ht-security' === $screen->id ) {
     262        ?>
     263        <style>
     264            .htsec-alert-success {
     265                padding: 15px;
     266                background-color: #d4edda;
     267                border: 1px solid #c3e6cb;
     268                border-radius: 4px;
     269                margin: 20px 0;
     270            }
     271            .htsec-alert-success p {
     272                margin: 0;
     273                color: #155724;
     274                font-weight: bold;
     275            }
     276            .htsec-alert-danger {
     277                padding: 15px;
     278                background-color: #f8d7da;
     279                border: 1px solid #f5c6cb;
     280                border-radius: 4px;
     281                margin: 20px 0;
     282            }
     283            .htsec-alert-danger p {
     284                margin: 0;
     285                color: #721c24;
     286                font-weight: bold;
     287            }
     288            .htsec-vuln-card {
     289                border: 1px solid #dee2e6;
     290                border-radius: 8px;
     291                padding: 20px;
     292                margin-bottom: 15px;
     293                background-color: #fff;
     294                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
     295                transition: box-shadow 0.3s ease;
     296            }
     297            .htsec-vuln-card:hover {
     298                box-shadow: 0 4px 8px rgba(0,0,0,0.15);
     299            }
     300            .htsec-vuln-header {
     301                display: flex;
     302                justify-content: space-between;
     303                align-items: flex-start;
     304                margin-bottom: 15px;
     305                flex-wrap: wrap;
     306                gap: 10px;
     307            }
     308            .htsec-vuln-title {
     309                margin: 0;
     310                font-size: 16px;
     311                color: #333;
     312            }
     313            .htsec-severity-badge {
     314                padding: 6px 14px;
     315                border-radius: 4px;
     316                font-size: 12px;
     317                font-weight: bold;
     318                text-transform: uppercase;
     319                letter-spacing: 0.5px;
     320            }
     321            .htsec-vuln-detail {
     322                margin-bottom: 12px;
     323            }
     324            .htsec-vuln-detail strong {
     325                color: #555;
     326            }
     327            .htsec-vuln-description {
     328                background-color: #f8f9fa;
     329                padding: 12px;
     330                border-left: 3px solid #007cba;
     331                margin-top: 5px;
     332                color: #666;
     333                line-height: 1.6;
     334            }
     335            .htsec-cve-link {
     336                color: #007cba;
     337                text-decoration: none;
     338                font-weight: 500;
     339            }
     340            .htsec-cve-link:hover {
     341                text-decoration: underline;
     342            }
     343            .htsec-cvss-score {
     344                background-color: #e9ecef;
     345                padding: 2px 8px;
     346                border-radius: 3px;
     347                font-family: monospace;
     348                font-weight: bold;
     349            }
     350            .htsec-check-info {
     351                background-color: #f0f6fc;
     352                border-left: 4px solid #0969da;
     353                padding: 12px 16px;
     354                margin: 20px 0;
     355            }
     356            .htsec-progress-item {
     357                padding: 8px 12px;
     358                background-color: #f8f9fa;
     359                border-left: 3px solid #0969da;
     360                margin-bottom: 8px;
     361                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
     362                font-size: 13px;
     363            }
     364            .htsec-stats-box {
     365                background-color: #fff;
     366                border: 1px solid #ddd;
     367                border-radius: 4px;
     368                padding: 15px;
     369                margin: 15px 0;
     370            }
     371            .htsec-stats-box strong {
     372                color: #0073aa;
     373            }
     374            #htsec-feedback-section {
     375                background-color: #fff;
     376                border: 1px solid #ddd;
     377                border-radius: 4px;
     378                padding: 20px;
     379                margin: 20px 0;
     380            }
     381            #htsec-feedback-form textarea {
     382                width: 100%;
     383                border: 1px solid #ddd;
     384                border-radius: 4px;
     385                padding: 10px;
     386                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
     387                resize: vertical;
     388            }
     389            #htsec-feedback-form textarea:focus {
     390                border-color: #0073aa;
     391                outline: none;
     392                box-shadow: 0 0 0 1px #0073aa;
     393            }
     394            .htsec-feedback-success {
     395                padding: 12px 15px;
     396                background-color: #d4edda;
     397                border: 1px solid #c3e6cb;
     398                border-radius: 4px;
     399                color: #155724;
     400            }
     401            .htsec-feedback-error {
     402                padding: 12px 15px;
     403                background-color: #f8d7da;
     404                border: 1px solid #f5c6cb;
     405                border-radius: 4px;
     406                color: #721c24;
     407            }
     408            #htsec-send-feedback-btn:disabled,
     409            #htsec-send-feedback-btn.disabled {
     410                opacity: 0.6;
     411                cursor: not-allowed;
     412            }
     413        </style>
     414        <?php
     415    }
     416}
     417
     418/**
     419 * Adiciona JavaScript para o formulário de feedback.
     420 */
     421add_action( 'admin_footer', 'htsec_feedback_script' );
     422function htsec_feedback_script() {
     423    $screen = get_current_screen();
     424    if ( isset( $screen->id ) && 'settings_page_ht-security' === $screen->id ) {
     425        ?>
     426        <script type="text/javascript">
     427        jQuery(document).ready(function($) {
     428            // Mostrar formulário de feedback
     429            $('#htsec-show-feedback-btn').on('click', function() {
     430                $('#htsec-feedback-form').slideDown();
     431                $(this).hide();
     432                $('#htsec-feedback-message').focus();
     433            });
     434
     435            // Cancelar feedback
     436            $('#htsec-cancel-feedback-btn').on('click', function() {
     437                $('#htsec-feedback-form').slideUp();
     438                $('#htsec-show-feedback-btn').show();
     439                $('#htsec-feedback-message').val('');
     440                $('#htsec-feedback-response').html('');
     441            });
     442
     443            // Enviar feedback
     444            $('#htsec-send-feedback-btn').on('click', function() {
     445                var $btn = $(this);
     446                var $textarea = $('#htsec-feedback-message');
     447                var $response = $('#htsec-feedback-response');
     448                var message = $textarea.val().trim();
     449
     450                // Validar mensagem
     451                if (message === '') {
     452                    $response.html('<div class="htsec-feedback-error"><?php echo esc_js( __( 'Por favor, digite uma mensagem antes de enviar.', 'ht-security' ) ); ?></div>');
     453                    return;
     454                }
     455
     456                if (message.length < 10) {
     457                    $response.html('<div class="htsec-feedback-error"><?php echo esc_js( __( 'A mensagem deve ter pelo menos 10 caracteres.', 'ht-security' ) ); ?></div>');
     458                    return;
     459                }
     460
     461                // Desabilitar botão e textarea
     462                $btn.prop('disabled', true).text('<?php echo esc_js( __( 'Enviando...', 'ht-security' ) ); ?>');
     463                $textarea.prop('disabled', true);
     464                $response.html('');
     465
     466                // Enviar via AJAX
     467                $.post(ajaxurl, {
     468                    action: 'htsec_send_feedback',
     469                    message: message,
     470                    nonce: '<?php echo esc_js( wp_create_nonce( 'htsec_send_feedback' ) ); ?>'
     471                }, function(response) {
     472                    if (response.success) {
     473                        $response.html('<div class="htsec-feedback-success">' + response.data.message + '</div>');
     474                        $textarea.val('');
     475
     476                        // Ocultar formulário após 3 segundos
     477                        setTimeout(function() {
     478                            $('#htsec-feedback-form').slideUp();
     479                            $('#htsec-show-feedback-btn').show();
     480                            $response.html('');
     481                        }, 3000);
     482                    } else {
     483                        $response.html('<div class="htsec-feedback-error">' + response.data.message + '</div>');
     484                    }
     485                }).fail(function() {
     486                    $response.html('<div class="htsec-feedback-error"><?php echo esc_js( __( 'Erro ao enviar feedback. Por favor, tente novamente mais tarde.', 'ht-security' ) ); ?></div>');
     487                }).always(function() {
     488                    // Reabilitar botão e textarea
     489                    $btn.prop('disabled', false).text('<?php echo esc_js( __( 'Enviar Feedback', 'ht-security' ) ); ?>');
     490                    $textarea.prop('disabled', false);
     491                });
     492            });
     493        });
     494        </script>
     495        <?php
     496    }
     497}
     498
     499/**
    193500 * Renderiza a página de configurações e faz a verificação de integridade do Core via API.
    194501 */
     
    252559    submit_button();
    253560    echo '</form>';
    254    
     561
     562    // Seção de Feedback
     563    echo '<div id="htsec-feedback-section" style="margin-top: 40px;">';
     564    echo '<h2>' . esc_html__( 'Enviar Feedback', 'ht-security' ) . '</h2>';
     565    echo '<p class="description">' . esc_html__( 'Tem alguma sugestão, encontrou um bug ou quer compartilhar sua experiência? Envie-nos seu feedback!', 'ht-security' ) . '</p>';
     566
     567    echo '<div id="htsec-feedback-form-container" style="margin-top: 20px;">';
     568    echo '<button type="button" id="htsec-show-feedback-btn" class="button button-secondary">';
     569    echo esc_html__( 'Abrir Formulário de Feedback', 'ht-security' );
     570    echo '</button>';
     571
     572    echo '<div id="htsec-feedback-form" style="display: none; margin-top: 15px; max-width: 600px;">';
     573    echo '<textarea id="htsec-feedback-message" rows="6" class="large-text" placeholder="' . esc_attr__( 'Digite seu feedback aqui...', 'ht-security' ) . '"></textarea>';
     574    echo '<div style="margin-top: 10px;">';
     575    echo '<button type="button" id="htsec-send-feedback-btn" class="button button-primary">' . esc_html__( 'Enviar Feedback', 'ht-security' ) . '</button>';
     576    echo ' <button type="button" id="htsec-cancel-feedback-btn" class="button button-secondary">' . esc_html__( 'Cancelar', 'ht-security' ) . '</button>';
     577    echo '</div>';
     578    echo '<div id="htsec-feedback-response" style="margin-top: 15px;"></div>';
     579    echo '</div>';
     580    echo '</div>';
     581    echo '</div>';
     582
     583    // Verificação de Vulnerabilidades CVE
     584    echo '<div id="cve-check">';
     585    echo '<h2>' . esc_html__( 'Verificação de Vulnerabilidades (CVE)', 'ht-security' ) . '</h2>';
     586    htsec_display_cve_check();
     587    echo '</div>';
     588
    255589    // Auditoria de Permissões de Arquivos
    256590    echo '<h2>' . esc_html__( 'Auditoria de Permissões de Arquivos', 'ht-security' ) . '</h2>';
    257591    htsec_display_file_permissions_audit();
    258    
     592
    259593    echo '</div>';
    260594}
     
    491825        return;
    492826    }
    493    
     827
    494828    if ( current_user_can( 'manage_options' ) ) {
    495829        return;
    496830    }
    497    
     831
    498832    $allowed_ips = get_option( 'htsec_maintenance_ips', '' );
    499833    $allowed_ips = array_filter( array_map( 'trim', explode( "\n", $allowed_ips ) ) );
    500834    $current_ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? '' ) );
    501    
     835
    502836    if ( ! empty( $allowed_ips ) && in_array( $current_ip, $allowed_ips, true ) ) {
    503837        return;
    504838    }
    505    
     839
    506840    $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
    507    
     841
    508842    if ( ! is_admin() && ! strpos( $request_uri, '/wp-login.php' ) ) {
    509843        wp_die(
     
    514848    }
    515849}
     850
     851/**
     852 * Exibe a verificação de vulnerabilidades CVE.
     853 */
     854function htsec_display_cve_check() {
     855    // Informação sobre a funcionalidade
     856    $api_key = get_option( 'htsec_nvd_api_key', '' );
     857    $rate_limit = empty( $api_key ) ? 5 : 50;
     858
     859    echo '<div class="htsec-check-info">';
     860    echo '<p style="margin: 0 0 10px 0;">' . esc_html__( 'Esta funcionalidade verifica se há vulnerabilidades conhecidas (CVEs) nas versões instaladas do WordPress e plugins ativos.', 'ht-security' ) . '</p>';
     861    /* translators: %d: Number of requests allowed per 30 seconds */
     862    echo '<p style="margin: 0;"><strong>' . sprintf( esc_html__( 'Limite atual: %d verificações a cada 30 segundos', 'ht-security' ), esc_html( $rate_limit ) ) . '</strong></p>';
     863    echo '</div>';
     864
     865    // Botão para forçar verificação manual
     866    if ( isset( $_POST['htsec_check_cve_now'] ) && isset( $_POST['htsec_cve_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['htsec_cve_nonce'] ) ), 'htsec_check_cve' ) ) {
     867        // Limpar progresso anterior
     868        delete_option( 'htsec_check_progress' );
     869
     870        echo '<div class="notice notice-info" style="position: relative;">';
     871        echo '<p><strong>' . esc_html__( 'Verificação em andamento...', 'ht-security' ) . '</strong></p>';
     872        echo '</div>';
     873
     874        // Forçar flush do output para mostrar a mensagem
     875        if ( function_exists( 'wp_ob_end_flush_all' ) ) {
     876            wp_ob_end_flush_all();
     877        }
     878        flush();
     879
     880        $stats = htsec_check_vulnerabilities( true );
     881
     882        // Exibir progresso
     883        $progress = get_option( 'htsec_check_progress', [] );
     884        if ( ! empty( $progress ) ) {
     885            echo '<div class="notice notice-info">';
     886            echo '<p><strong>' . esc_html__( 'Progresso da Verificação:', 'ht-security' ) . '</strong></p>';
     887            echo '<div style="margin: 10px 0;">';
     888            foreach ( $progress as $entry ) {
     889                echo '<div class="htsec-progress-item">' . esc_html( $entry['message'] ) . '</div>';
     890            }
     891            echo '</div>';
     892            echo '</div>';
     893        }
     894
     895        // Limpar progresso após exibir
     896        delete_option( 'htsec_check_progress' );
     897
     898        echo '<div class="notice notice-success">';
     899        echo '<p><strong>' . esc_html__( 'Verificação concluída!', 'ht-security' ) . '</strong></p>';
     900        echo '<div class="htsec-stats-box">';
     901        /* translators: %d: Total items checked */
     902        echo '<p style="margin: 0 0 8px 0;"><strong>' . esc_html__( 'Estatísticas:', 'ht-security' ) . '</strong></p>';
     903        /* translators: %d: Number of software items */
     904        echo '<p style="margin: 0 0 5px 0;">• ' . sprintf( esc_html__( 'Softwares verificados: %d', 'ht-security' ), esc_html( $stats['total_checked'] ) ) . '</p>';
     905        /* translators: %d: Number of batches */
     906        echo '<p style="margin: 0 0 5px 0;">• ' . sprintf( esc_html__( 'Lotes processados: %d', 'ht-security' ), esc_html( $stats['batches_processed'] ) ) . '</p>';
     907        /* translators: %d: Number of vulnerabilities */
     908        echo '<p style="margin: 0;">• ' . sprintf( esc_html__( 'Vulnerabilidades encontradas: %d', 'ht-security' ), esc_html( $stats['vulnerabilities_found'] ) ) . '</p>';
     909        echo '</div>';
     910        echo '</div>';
     911    }
     912
     913    // Obter dados de vulnerabilidades armazenados
     914    $vulnerabilities = get_option( 'htsec_vulnerabilities', [] );
     915    $last_check = get_option( 'htsec_last_cve_check', 0 );
     916
     917    if ( $last_check ) {
     918        $time_diff = human_time_diff( $last_check, current_time( 'timestamp' ) );
     919        /* translators: %s: Time since last check */
     920        echo '<p class="description">' . sprintf( esc_html__( 'Última verificação: %s atrás', 'ht-security' ), esc_html( $time_diff ) ) . '</p>';
     921    } else {
     922        echo '<p class="description">' . esc_html__( 'Nenhuma verificação realizada ainda. Clique no botão abaixo para verificar agora.', 'ht-security' ) . '</p>';
     923    }
     924
     925    // Exibir estatísticas
     926    if ( ! function_exists( 'get_plugins' ) ) {
     927        require_once ABSPATH . 'wp-admin/includes/plugin.php';
     928    }
     929    $active_plugins = get_option( 'active_plugins', [] );
     930    $total_to_check = count( $active_plugins ) + 1; // +1 para WordPress
     931    $batches_needed = ceil( $total_to_check / $rate_limit );
     932
     933    if ( $batches_needed > 1 ) {
     934        $estimated_time = ( $batches_needed - 1 ) * 30; // 30 segundos entre batches
     935        echo '<p class="description">';
     936        echo sprintf(
     937            /* translators: 1: Number of batches, 2: Estimated time in seconds */
     938            esc_html__( 'Esta verificação será dividida em %1$d lote(s). Tempo estimado: ~%2$d segundos', 'ht-security' ),
     939            esc_html( $batches_needed ),
     940            esc_html( $estimated_time )
     941        );
     942        echo '</p>';
     943    }
     944
     945    // Exibir resultados
     946    if ( empty( $vulnerabilities ) ) {
     947        echo '<div class="htsec-alert-success">';
     948        echo '<p>✓ ' . esc_html__( 'Nenhuma vulnerabilidade conhecida detectada nas versões atuais!', 'ht-security' ) . '</p>';
     949        echo '</div>';
     950    } else {
     951        echo '<div class="htsec-alert-danger">';
     952        /* translators: %d: Number of vulnerabilities found */
     953        echo '<p>⚠ ' . sprintf( esc_html( _n( '%d vulnerabilidade encontrada!', '%d vulnerabilidades encontradas!', count( $vulnerabilities ), 'ht-security' ) ), count( $vulnerabilities ) ) . '</p>';
     954        echo '</div>';
     955
     956        htsec_display_vulnerabilities( $vulnerabilities );
     957    }
     958
     959    // Botão de verificação manual
     960    echo '<form method="post" style="margin-top: 20px;">';
     961    wp_nonce_field( 'htsec_check_cve', 'htsec_cve_nonce' );
     962    submit_button( esc_html__( 'Verificar Vulnerabilidades Agora', 'ht-security' ), 'primary', 'htsec_check_cve_now', false );
     963    echo '</form>';
     964}
     965
     966/**
     967 * Exibe as vulnerabilidades encontradas.
     968 */
     969function htsec_display_vulnerabilities( $vulnerabilities ) {
     970    echo '<div style="margin: 20px 0;">';
     971
     972    foreach ( $vulnerabilities as $vuln ) {
     973        $severity = isset( $vuln['severity'] ) ? $vuln['severity'] : 'UNKNOWN';
     974        $severity_colors = [
     975            'CRITICAL' => '#8b0000',
     976            'HIGH' => '#dc3545',
     977            'MEDIUM' => '#ffc107',
     978            'LOW' => '#28a745',
     979            'UNKNOWN' => '#6c757d',
     980        ];
     981        $severity_color = isset( $severity_colors[ $severity ] ) ? $severity_colors[ $severity ] : $severity_colors['UNKNOWN'];
     982
     983        echo '<div class="htsec-vuln-card">';
     984        echo '<div class="htsec-vuln-header">';
     985        echo '<h3 class="htsec-vuln-title">' . esc_html( $vuln['software'] ) . ' ' . esc_html( $vuln['version'] ) . '</h3>';
     986        echo '<span class="htsec-severity-badge" style="background-color: ' . esc_attr( $severity_color ) . '; color: white;">' . esc_html( $severity ) . '</span>';
     987        echo '</div>';
     988
     989        echo '<div class="htsec-vuln-detail">';
     990        echo '<strong>' . esc_html__( 'CVE:', 'ht-security' ) . '</strong> ';
     991        echo '<a href="' . esc_url( $vuln['cve_url'] ) . '" target="_blank" class="htsec-cve-link" rel="noopener noreferrer">';
     992        echo esc_html( $vuln['cve_id'] );
     993        echo ' <span class="dashicons dashicons-external" style="font-size: 14px; vertical-align: middle;"></span>';
     994        echo '</a>';
     995        echo '</div>';
     996
     997        if ( isset( $vuln['cvss_score'] ) ) {
     998            echo '<div class="htsec-vuln-detail">';
     999            echo '<strong>' . esc_html__( 'CVSS Score:', 'ht-security' ) . '</strong> ';
     1000            echo '<span class="htsec-cvss-score">' . esc_html( $vuln['cvss_score'] ) . '</span>';
     1001            echo '</div>';
     1002        }
     1003
     1004        if ( ! empty( $vuln['description'] ) ) {
     1005            echo '<div class="htsec-vuln-detail">';
     1006            echo '<strong>' . esc_html__( 'Descrição:', 'ht-security' ) . '</strong>';
     1007            echo '<div class="htsec-vuln-description">' . esc_html( $vuln['description'] ) . '</div>';
     1008            echo '</div>';
     1009        }
     1010
     1011        echo '</div>';
     1012    }
     1013
     1014    echo '</div>';
     1015}
     1016
     1017/**
     1018 * Verifica vulnerabilidades nos plugins e WordPress.
     1019 */
     1020function htsec_check_vulnerabilities( $manual = false ) {
     1021    $api_key = get_option( 'htsec_nvd_api_key', '' );
     1022    $vulnerabilities = [];
     1023
     1024    // Definir rate limits
     1025    $rate_limit = empty( $api_key ) ? 5 : 50; // 5 requests/30s sem key, 50/30s com key
     1026    $batch_delay = 30; // 30 segundos entre batches
     1027
     1028    // Coletar todos os softwares a serem verificados
     1029    $software_to_check = [];
     1030
     1031    // Adicionar WordPress
     1032    $software_to_check[] = [
     1033        'name' => 'WordPress',
     1034        'version' => get_bloginfo( 'version' ),
     1035        'type' => 'core',
     1036    ];
     1037
     1038    // Adicionar plugins ativos
     1039    if ( ! function_exists( 'get_plugins' ) ) {
     1040        require_once ABSPATH . 'wp-admin/includes/plugin.php';
     1041    }
     1042
     1043    $all_plugins = get_plugins();
     1044    $active_plugins = get_option( 'active_plugins', [] );
     1045
     1046    foreach ( $all_plugins as $plugin_file => $plugin_data ) {
     1047        // Verificar apenas plugins ativos
     1048        if ( ! in_array( $plugin_file, $active_plugins, true ) ) {
     1049            continue;
     1050        }
     1051
     1052        $software_to_check[] = [
     1053            'name' => $plugin_data['Name'],
     1054            'version' => $plugin_data['Version'],
     1055            'type' => 'plugin',
     1056        ];
     1057    }
     1058
     1059    $total_items = count( $software_to_check );
     1060    $total_batches = ceil( $total_items / $rate_limit );
     1061    $current_batch = 0;
     1062
     1063    // Processar em batches
     1064    for ( $i = 0; $i < $total_items; $i += $rate_limit ) {
     1065        $current_batch++;
     1066        $batch = array_slice( $software_to_check, $i, $rate_limit );
     1067
     1068        // Feedback de progresso para verificação manual
     1069        if ( $manual ) {
     1070            $processed = min( $i + $rate_limit, $total_items );
     1071            htsec_log_progress( sprintf(
     1072                /* translators: 1: Current progress, 2: Total items */
     1073                esc_html__( 'Verificando %1$d de %2$d softwares...', 'ht-security' ),
     1074                $processed,
     1075                $total_items
     1076            ) );
     1077        }
     1078
     1079        // Processar cada item do batch
     1080        foreach ( $batch as $software ) {
     1081            $vulns = htsec_query_nvd_api( $software['name'], $software['version'], $api_key );
     1082            if ( ! empty( $vulns ) ) {
     1083                $vulnerabilities = array_merge( $vulnerabilities, $vulns );
     1084            }
     1085
     1086            // Pequeno delay entre requisições do mesmo batch para não sobrecarregar
     1087            if ( ! empty( $api_key ) ) {
     1088                usleep( 100000 ); // 0.1 segundo com API Key
     1089            } else {
     1090                usleep( 500000 ); // 0.5 segundo sem API Key
     1091            }
     1092        }
     1093
     1094        // Se não for o último batch, esperar 30 segundos
     1095        if ( $current_batch < $total_batches ) {
     1096            if ( $manual ) {
     1097                htsec_log_progress( sprintf(
     1098                    /* translators: %d: Seconds to wait */
     1099                    esc_html__( 'Aguardando %d segundos (limite da API)...', 'ht-security' ),
     1100                    $batch_delay
     1101                ) );
     1102            }
     1103            sleep( $batch_delay );
     1104        }
     1105    }
     1106
     1107    // Armazenar resultados
     1108    update_option( 'htsec_vulnerabilities', $vulnerabilities );
     1109    update_option( 'htsec_last_cve_check', current_time( 'timestamp' ) );
     1110
     1111    // Enviar e-mail se habilitado e houver vulnerabilidades
     1112    if ( ! empty( $vulnerabilities ) && get_option( 'htsec_enable_cve_alerts', 0 ) ) {
     1113        htsec_send_cve_alert( $vulnerabilities );
     1114    }
     1115
     1116    return [
     1117        'total_checked' => $total_items,
     1118        'vulnerabilities_found' => count( $vulnerabilities ),
     1119        'batches_processed' => $current_batch,
     1120    ];
     1121}
     1122
     1123/**
     1124 * Registra progresso da verificação (para exibição em verificações manuais).
     1125 */
     1126function htsec_log_progress( $message ) {
     1127    $progress = get_option( 'htsec_check_progress', [] );
     1128    $progress[] = [
     1129        'message' => $message,
     1130        'time' => current_time( 'mysql' ),
     1131    ];
     1132    update_option( 'htsec_check_progress', $progress );
     1133}
     1134
     1135/**
     1136 * Consulta a API NVD para buscar CVEs.
     1137 */
     1138function htsec_query_nvd_api( $software_name, $version, $api_key = '' ) {
     1139    $vulnerabilities = [];
     1140
     1141    // Lista de termos genéricos que causam falsos positivos
     1142    $generic_terms = [
     1143        'apache', 'tomcat', 'connector', 'owasp', 'antisamy', '.net',
     1144        'java', 'spring', 'framework', 'library', 'module', 'component',
     1145    ];
     1146
     1147    // Para WordPress, usar busca específica
     1148    if ( 'WordPress' === $software_name ) {
     1149        $search_term = 'WordPress Core ' . $version;
     1150    } else {
     1151        // Para plugins, usar nome específico
     1152        $search_term = sanitize_text_field( $software_name );
     1153    }
     1154
     1155    $url = add_query_arg( [
     1156        'keywordSearch' => rawurlencode( $search_term ),
     1157        'keywordExactMatch' => '', // Busca exata da frase
     1158        'resultsPerPage' => 20,
     1159    ], 'https://services.nvd.nist.gov/rest/json/cves/2.0' );
     1160
     1161    $headers = [ 'timeout' => 30 ];
     1162
     1163    if ( ! empty( $api_key ) ) {
     1164        $headers['headers'] = [
     1165            'apiKey' => sanitize_text_field( $api_key ),
     1166        ];
     1167    }
     1168
     1169    $response = wp_remote_get( $url, $headers );
     1170
     1171    if ( is_wp_error( $response ) ) {
     1172        return $vulnerabilities;
     1173    }
     1174
     1175    $response_code = wp_remote_retrieve_response_code( $response );
     1176    if ( 200 !== $response_code ) {
     1177        return $vulnerabilities;
     1178    }
     1179
     1180    $body = wp_remote_retrieve_body( $response );
     1181    $data = json_decode( $body, true );
     1182
     1183    if ( empty( $data['vulnerabilities'] ) ) {
     1184        return $vulnerabilities;
     1185    }
     1186
     1187    foreach ( $data['vulnerabilities'] as $vuln ) {
     1188        if ( empty( $vuln['cve'] ) ) {
     1189            continue;
     1190        }
     1191
     1192        $cve = $vuln['cve'];
     1193        $cve_id = isset( $cve['id'] ) ? $cve['id'] : '';
     1194
     1195        if ( empty( $cve_id ) ) {
     1196            continue;
     1197        }
     1198
     1199        // Extrair descrição
     1200        $description = '';
     1201        if ( isset( $cve['descriptions'] ) && is_array( $cve['descriptions'] ) ) {
     1202            foreach ( $cve['descriptions'] as $desc ) {
     1203                if ( isset( $desc['lang'] ) && 'en' === $desc['lang'] ) {
     1204                    $description = $desc['value'];
     1205                    break;
     1206                }
     1207            }
     1208        }
     1209
     1210        // ANTI-FALSO POSITIVO: Validar se a CVE realmente se aplica ao software
     1211        if ( ! htsec_validate_cve_match( $software_name, $description, $cve ) ) {
     1212            continue;
     1213        }
     1214
     1215        // ANTI-FALSO POSITIVO: Verificar se não contém termos genéricos que não correspondem
     1216        $description_lower = strtolower( $description );
     1217        $software_lower = strtolower( $software_name );
     1218
     1219        $has_generic_mismatch = false;
     1220        foreach ( $generic_terms as $term ) {
     1221            // Se a descrição menciona um termo genérico que não está no nome do software
     1222            if ( strpos( $description_lower, $term ) !== false && strpos( $software_lower, $term ) === false ) {
     1223                $has_generic_mismatch = true;
     1224                break;
     1225            }
     1226        }
     1227
     1228        if ( $has_generic_mismatch ) {
     1229            continue;
     1230        }
     1231
     1232        // VALIDAÇÃO DE VERSÃO: Verificar se a versão instalada é vulnerável
     1233        if ( ! htsec_version_is_vulnerable( $version, $cve ) ) {
     1234            continue;
     1235        }
     1236
     1237        // Extrair severidade e score
     1238        $severity = 'UNKNOWN';
     1239        $cvss_score = null;
     1240
     1241        if ( isset( $cve['metrics'] ) ) {
     1242            $metrics = $cve['metrics'];
     1243
     1244            // Tentar CVSS v3.1 primeiro
     1245            if ( isset( $metrics['cvssMetricV31'][0] ) ) {
     1246                $cvss = $metrics['cvssMetricV31'][0];
     1247                $severity = isset( $cvss['cvssData']['baseSeverity'] ) ? $cvss['cvssData']['baseSeverity'] : 'UNKNOWN';
     1248                $cvss_score = isset( $cvss['cvssData']['baseScore'] ) ? $cvss['cvssData']['baseScore'] : null;
     1249            } elseif ( isset( $metrics['cvssMetricV30'][0] ) ) {
     1250                $cvss = $metrics['cvssMetricV30'][0];
     1251                $severity = isset( $cvss['cvssData']['baseSeverity'] ) ? $cvss['cvssData']['baseSeverity'] : 'UNKNOWN';
     1252                $cvss_score = isset( $cvss['cvssData']['baseScore'] ) ? $cvss['cvssData']['baseScore'] : null;
     1253            } elseif ( isset( $metrics['cvssMetricV2'][0] ) ) {
     1254                $cvss = $metrics['cvssMetricV2'][0];
     1255                $severity = isset( $cvss['baseSeverity'] ) ? $cvss['baseSeverity'] : 'UNKNOWN';
     1256                $cvss_score = isset( $cvss['cvssData']['baseScore'] ) ? $cvss['cvssData']['baseScore'] : null;
     1257            }
     1258        }
     1259
     1260        $vulnerabilities[] = [
     1261            'software' => $software_name,
     1262            'version' => $version,
     1263            'cve_id' => $cve_id,
     1264            'cve_url' => 'https://nvd.nist.gov/vuln/detail/' . $cve_id,
     1265            'description' => wp_trim_words( $description, 50 ),
     1266            'full_description' => $description,
     1267            'severity' => $severity,
     1268            'cvss_score' => $cvss_score,
     1269        ];
     1270    }
     1271
     1272    return $vulnerabilities;
     1273}
     1274
     1275/**
     1276 * Verifica se a versão instalada está vulnerável baseada nos dados da CVE.
     1277 */
     1278function htsec_version_is_vulnerable( $installed_version, $cve_data ) {
     1279    // Se não tiver versão instalada, não pode validar
     1280    if ( empty( $installed_version ) ) {
     1281        return false;
     1282    }
     1283
     1284    // Normalizar versão instalada (remover v, V, etc.)
     1285    $installed_version = strtolower( trim( $installed_version ) );
     1286    $installed_version = preg_replace( '/^v/', '', $installed_version );
     1287
     1288    // Extrair versões afetadas das configurações da CVE
     1289    $version_ranges = htsec_extract_version_ranges( $cve_data );
     1290
     1291    // Se não conseguiu extrair ranges, tentar da descrição
     1292    if ( empty( $version_ranges ) ) {
     1293        $description = '';
     1294        if ( isset( $cve_data['descriptions'] ) && is_array( $cve_data['descriptions'] ) ) {
     1295            foreach ( $cve_data['descriptions'] as $desc ) {
     1296                if ( isset( $desc['lang'] ) && 'en' === $desc['lang'] ) {
     1297                    $description = $desc['value'];
     1298                    break;
     1299                }
     1300            }
     1301        }
     1302        $version_ranges = htsec_extract_version_from_description( $description );
     1303    }
     1304
     1305    // Se ainda não tem ranges, não pode validar (assume que pode ser vulnerável para ser conservador)
     1306    if ( empty( $version_ranges ) ) {
     1307        return false; // Mudado para false - se não sabemos, não reportamos
     1308    }
     1309
     1310    // Verificar se a versão instalada está em algum dos ranges vulneráveis
     1311    foreach ( $version_ranges as $range ) {
     1312        if ( htsec_version_in_range( $installed_version, $range ) ) {
     1313            return true;
     1314        }
     1315    }
     1316
     1317    return false;
     1318}
     1319
     1320/**
     1321 * Extrai ranges de versões afetadas dos dados da CVE.
     1322 */
     1323function htsec_extract_version_ranges( $cve_data ) {
     1324    $ranges = [];
     1325
     1326    if ( ! isset( $cve_data['configurations'] ) || ! is_array( $cve_data['configurations'] ) ) {
     1327        return $ranges;
     1328    }
     1329
     1330    foreach ( $cve_data['configurations'] as $config ) {
     1331        if ( ! isset( $config['nodes'] ) || ! is_array( $config['nodes'] ) ) {
     1332            continue;
     1333        }
     1334
     1335        foreach ( $config['nodes'] as $node ) {
     1336            if ( ! isset( $node['cpeMatch'] ) || ! is_array( $node['cpeMatch'] ) ) {
     1337                continue;
     1338            }
     1339
     1340            foreach ( $node['cpeMatch'] as $match ) {
     1341                if ( ! isset( $match['vulnerable'] ) || ! $match['vulnerable'] ) {
     1342                    continue;
     1343                }
     1344
     1345                $range = [
     1346                    'start_version' => null,
     1347                    'end_version' => null,
     1348                    'start_including' => true,
     1349                    'end_including' => true,
     1350                ];
     1351
     1352                if ( isset( $match['versionStartIncluding'] ) ) {
     1353                    $range['start_version'] = $match['versionStartIncluding'];
     1354                    $range['start_including'] = true;
     1355                } elseif ( isset( $match['versionStartExcluding'] ) ) {
     1356                    $range['start_version'] = $match['versionStartExcluding'];
     1357                    $range['start_including'] = false;
     1358                }
     1359
     1360                if ( isset( $match['versionEndIncluding'] ) ) {
     1361                    $range['end_version'] = $match['versionEndIncluding'];
     1362                    $range['end_including'] = true;
     1363                } elseif ( isset( $match['versionEndExcluding'] ) ) {
     1364                    $range['end_version'] = $match['versionEndExcluding'];
     1365                    $range['end_including'] = false;
     1366                }
     1367
     1368                // Se tem pelo menos uma versão de limite, adiciona o range
     1369                if ( $range['start_version'] !== null || $range['end_version'] !== null ) {
     1370                    $ranges[] = $range;
     1371                }
     1372            }
     1373        }
     1374    }
     1375
     1376    return $ranges;
     1377}
     1378
     1379/**
     1380 * Extrai informação de versão da descrição da CVE.
     1381 */
     1382function htsec_extract_version_from_description( $description ) {
     1383    $ranges = [];
     1384
     1385    if ( empty( $description ) ) {
     1386        return $ranges;
     1387    }
     1388
     1389    $description_lower = strtolower( $description );
     1390
     1391    // Padrões comuns:
     1392    // "before X.X.X", "prior to X.X.X", "up to X.X.X", "through X.X.X"
     1393    // "versions up to, and including, X.X.X"
     1394    // "in versions up to X.X.X"
     1395
     1396    $patterns = [
     1397        '/(?:before|prior to|up to|through)\s+(?:version\s+)?v?(\d+\.\d+(?:\.\d+)?)/i',
     1398        '/versions?\s+up\s+to,?\s+(?:and\s+)?including,?\s+v?(\d+\.\d+(?:\.\d+)?)/i',
     1399        '/in\s+versions?\s+up\s+to\s+v?(\d+\.\d+(?:\.\d+)?)/i',
     1400        '/(?:version|versions?)\s+v?(\d+\.\d+(?:\.\d+)?)\s+and\s+(?:below|earlier)/i',
     1401    ];
     1402
     1403    foreach ( $patterns as $pattern ) {
     1404        if ( preg_match( $pattern, $description, $matches ) ) {
     1405            $version = $matches[1];
     1406
     1407            // Determinar se é inclusive ou exclusive baseado nas palavras
     1408            $is_including = (
     1409                strpos( $description_lower, 'including' ) !== false ||
     1410                strpos( $description_lower, 'through' ) !== false
     1411            );
     1412
     1413            $ranges[] = [
     1414                'start_version' => null,
     1415                'end_version' => $version,
     1416                'start_including' => true,
     1417                'end_including' => $is_including,
     1418            ];
     1419
     1420            break; // Pega apenas o primeiro match
     1421        }
     1422    }
     1423
     1424    return $ranges;
     1425}
     1426
     1427/**
     1428 * Verifica se uma versão está dentro de um range específico.
     1429 */
     1430function htsec_version_in_range( $version, $range ) {
     1431    // Verificar limite inferior
     1432    if ( $range['start_version'] !== null ) {
     1433        $comparison = version_compare( $version, $range['start_version'] );
     1434
     1435        if ( $range['start_including'] ) {
     1436            // Versão deve ser >= start
     1437            if ( $comparison < 0 ) {
     1438                return false;
     1439            }
     1440        } else {
     1441            // Versão deve ser > start
     1442            if ( $comparison <= 0 ) {
     1443                return false;
     1444            }
     1445        }
     1446    }
     1447
     1448    // Verificar limite superior
     1449    if ( $range['end_version'] !== null ) {
     1450        $comparison = version_compare( $version, $range['end_version'] );
     1451
     1452        if ( $range['end_including'] ) {
     1453            // Versão deve ser <= end
     1454            if ( $comparison > 0 ) {
     1455                return false;
     1456            }
     1457        } else {
     1458            // Versão deve ser < end
     1459            if ( $comparison >= 0 ) {
     1460                return false;
     1461            }
     1462        }
     1463    }
     1464
     1465    return true;
     1466}
     1467
     1468/**
     1469 * Valida se uma CVE realmente corresponde ao software especificado.
     1470 */
     1471function htsec_validate_cve_match( $software_name, $description, $cve_data ) {
     1472    $software_lower = strtolower( $software_name );
     1473    $description_lower = strtolower( $description );
     1474
     1475    // Para WordPress Core
     1476    if ( 'WordPress' === $software_name ) {
     1477        // Deve mencionar explicitamente "wordpress"
     1478        if ( strpos( $description_lower, 'wordpress' ) === false ) {
     1479            return false;
     1480        }
     1481
     1482        // Não deve ser sobre plugin ou tema
     1483        if ( strpos( $description_lower, 'plugin' ) !== false || strpos( $description_lower, 'theme' ) !== false ) {
     1484            return false;
     1485        }
     1486
     1487        return true;
     1488    }
     1489
     1490    // NOVA VALIDAÇÃO: Detectar plugins addon/relacionados
     1491    // Palavras que indicam que é um plugin diferente (addon, extension, etc.)
     1492    $addon_keywords = [
     1493        'addon', 'add-on', 'add on',
     1494        'extension', 'extend',
     1495        'pro version', 'premium',
     1496        'ultimate', 'advanced', 'extra',
     1497        'plus', 'premium',
     1498    ];
     1499
     1500    foreach ( $addon_keywords as $keyword ) {
     1501        if ( strpos( $description_lower, $keyword ) !== false ) {
     1502            // Se menciona addon, verificar se o nome do plugin instalado também menciona
     1503            $has_keyword_in_name = false;
     1504            foreach ( explode( ' ', $keyword ) as $kword ) {
     1505                if ( strpos( $software_lower, $kword ) !== false ) {
     1506                    $has_keyword_in_name = true;
     1507                    break;
     1508                }
     1509            }
     1510
     1511            // Se a CVE menciona addon mas o plugin instalado não menciona, é outro plugin
     1512            if ( ! $has_keyword_in_name ) {
     1513                // Verificação adicional: extrair nome completo do plugin da descrição
     1514                $cve_plugin_name = htsec_extract_plugin_name_from_description( $description );
     1515
     1516                if ( ! empty( $cve_plugin_name ) && strtolower( $cve_plugin_name ) !== $software_lower ) {
     1517                    // Os nomes são diferentes - é outro plugin
     1518                    return false;
     1519                }
     1520            }
     1521        }
     1522    }
     1523
     1524    // VALIDAÇÃO EXATA: Tentar extrair o nome exato do plugin da descrição
     1525    $cve_plugin_name = htsec_extract_plugin_name_from_description( $description );
     1526
     1527    if ( ! empty( $cve_plugin_name ) ) {
     1528        $cve_plugin_lower = strtolower( $cve_plugin_name );
     1529
     1530        // Se o nome extraído é MUITO diferente do nome do plugin, filtrar
     1531        $similarity = 0;
     1532        similar_text( $software_lower, $cve_plugin_lower, $similarity );
     1533
     1534        // Se similaridade < 60%, provavelmente é plugin diferente
     1535        if ( $similarity < 60 ) {
     1536            // Mas apenas se o nome extraído é substancialmente diferente
     1537            // Ex: "Elementor" vs "Plus Addons for Elementor" = muito diferente
     1538            if ( strlen( $cve_plugin_lower ) > strlen( $software_lower ) * 1.5 ) {
     1539                return false;
     1540            }
     1541        }
     1542    }
     1543
     1544    // Para plugins WordPress
     1545    // Verificar se a descrição menciona o nome do plugin
     1546    $words = explode( ' ', $software_lower );
     1547    $match_count = 0;
     1548
     1549    foreach ( $words as $word ) {
     1550        if ( strlen( $word ) < 3 ) {
     1551            continue; // Ignorar palavras muito curtas
     1552        }
     1553
     1554        if ( strpos( $description_lower, $word ) !== false ) {
     1555            $match_count++;
     1556        }
     1557    }
     1558
     1559    // Se nenhuma palavra do nome do software aparece na descrição, provavelmente é falso positivo
     1560    if ( $match_count === 0 ) {
     1561        return false;
     1562    }
     1563
     1564    // Verificar se menciona WordPress plugin
     1565    $is_wp_plugin_cve = ( strpos( $description_lower, 'wordpress' ) !== false && strpos( $description_lower, 'plugin' ) !== false );
     1566
     1567    // Se menciona WordPress plugin, verificar se não é addon de outro plugin
     1568    if ( $is_wp_plugin_cve ) {
     1569        // Padrão: "The [Nome do Plugin] WordPress plugin"
     1570        if ( preg_match( '/the\s+(.+?)\s+wordpress\s+plugin/i', $description, $matches ) ) {
     1571            $extracted_name = trim( $matches[1] );
     1572            $extracted_lower = strtolower( $extracted_name );
     1573
     1574            // Se o nome extraído é muito diferente, é outro plugin
     1575            if ( strpos( $extracted_lower, $software_lower ) === false &&
     1576                 strpos( $software_lower, $extracted_lower ) === false ) {
     1577                return false;
     1578            }
     1579        }
     1580    }
     1581
     1582    // Se tem pelo menos 50% das palavras correspondentes, considera válido
     1583    $total_words = count( array_filter( $words, function( $w ) {
     1584        return strlen( $w ) >= 3;
     1585    } ) );
     1586
     1587    if ( $total_words > 0 && ( $match_count / $total_words ) >= 0.5 ) {
     1588        return true;
     1589    }
     1590
     1591    // Caso contrário, é provável falso positivo
     1592    return false;
     1593}
     1594
     1595/**
     1596 * Extrai o nome do plugin da descrição da CVE.
     1597 */
     1598function htsec_extract_plugin_name_from_description( $description ) {
     1599    // Padrões comuns de nomeação em descrições de CVE:
     1600    // "The [Plugin Name] WordPress plugin"
     1601    // "The [Plugin Name] plugin for WordPress"
     1602    // "[Plugin Name] plugin"
     1603
     1604    $patterns = [
     1605        '/the\s+(.+?)\s+wordpress\s+plugin/i',
     1606        '/the\s+(.+?)\s+plugin\s+for\s+wordpress/i',
     1607        '/^(.+?)\s+plugin/i',
     1608    ];
     1609
     1610    foreach ( $patterns as $pattern ) {
     1611        if ( preg_match( $pattern, trim( $description ), $matches ) ) {
     1612            return trim( $matches[1] );
     1613        }
     1614    }
     1615
     1616    return '';
     1617}
     1618
     1619/**
     1620 * Envia alerta por e-mail sobre vulnerabilidades encontradas.
     1621 */
     1622function htsec_send_cve_alert( $vulnerabilities ) {
     1623    $email = sanitize_email( get_option( 'htsec_alert_email', get_option( 'admin_email' ) ) );
     1624
     1625    if ( empty( $email ) ) {
     1626        return;
     1627    }
     1628
     1629    $subject = sprintf(
     1630        /* translators: 1: Site name, 2: Number of vulnerabilities */
     1631        esc_html__( '[%1$s] Alerta: %2$d vulnerabilidades detectadas', 'ht-security' ),
     1632        get_bloginfo( 'name' ),
     1633        count( $vulnerabilities )
     1634    );
     1635
     1636    $message = esc_html__( 'Estimado Administrador,', 'ht-security' ) . "\n\n";
     1637    $message .= sprintf(
     1638        /* translators: %d: Number of vulnerabilities */
     1639        esc_html( _n( 'Foi detectada %d vulnerabilidade conhecida (CVE) em seu site:', 'Foram detectadas %d vulnerabilidades conhecidas (CVE) em seu site:', count( $vulnerabilities ), 'ht-security' ) ),
     1640        count( $vulnerabilities )
     1641    ) . "\n\n";
     1642
     1643    foreach ( $vulnerabilities as $vuln ) {
     1644        $message .= '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' . "\n";
     1645        $message .= esc_html__( 'Software:', 'ht-security' ) . ' ' . $vuln['software'] . ' ' . $vuln['version'] . "\n";
     1646        $message .= esc_html__( 'CVE:', 'ht-security' ) . ' ' . $vuln['cve_id'] . "\n";
     1647        $message .= esc_html__( 'Severidade:', 'ht-security' ) . ' ' . $vuln['severity'] . "\n";
     1648        if ( isset( $vuln['cvss_score'] ) ) {
     1649            $message .= esc_html__( 'CVSS Score:', 'ht-security' ) . ' ' . $vuln['cvss_score'] . "\n";
     1650        }
     1651        $message .= esc_html__( 'Link:', 'ht-security' ) . ' ' . $vuln['cve_url'] . "\n";
     1652        if ( ! empty( $vuln['description'] ) ) {
     1653            $message .= esc_html__( 'Descrição:', 'ht-security' ) . ' ' . $vuln['description'] . "\n";
     1654        }
     1655        $message .= "\n";
     1656    }
     1657
     1658    $message .= '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' . "\n\n";
     1659    $message .= esc_html__( 'Recomendamos que você atualize os plugins e o WordPress o mais rápido possível.', 'ht-security' ) . "\n\n";
     1660    $message .= esc_html__( 'Acesse o painel do HT Security para mais detalhes:', 'ht-security' ) . "\n";
     1661    $message .= admin_url( 'options-general.php?page=ht-security' );
     1662
     1663    wp_mail( $email, $subject, $message );
     1664}
     1665
     1666/**
     1667 * Configura o cron job para verificação automática de vulnerabilidades.
     1668 */
     1669add_action( 'wp', 'htsec_schedule_cve_check' );
     1670function htsec_schedule_cve_check() {
     1671    if ( ! wp_next_scheduled( 'htsec_cve_check_event' ) ) {
     1672        wp_schedule_event( time(), 'twicedaily', 'htsec_cve_check_event' );
     1673    }
     1674}
     1675
     1676add_action( 'htsec_cve_check_event', 'htsec_run_scheduled_cve_check' );
     1677function htsec_run_scheduled_cve_check() {
     1678    htsec_check_vulnerabilities();
     1679}
     1680
     1681/**
     1682 * Remove o cron job ao desativar o plugin.
     1683 */
     1684register_deactivation_hook( __FILE__, 'htsec_deactivation' );
     1685function htsec_deactivation() {
     1686    $timestamp = wp_next_scheduled( 'htsec_cve_check_event' );
     1687    if ( $timestamp ) {
     1688        wp_unschedule_event( $timestamp, 'htsec_cve_check_event' );
     1689    }
     1690}
     1691
     1692/**
     1693 * Adiciona indicador de vulnerabilidades na página de plugins.
     1694 */
     1695add_filter( 'plugin_row_meta', 'htsec_add_plugin_vulnerability_indicator', 10, 2 );
     1696function htsec_add_plugin_vulnerability_indicator( $plugin_meta, $plugin_file ) {
     1697    // Verificar se a opção está ativada
     1698    if ( ! get_option( 'htsec_show_plugin_badges', 1 ) ) {
     1699        return $plugin_meta;
     1700    }
     1701
     1702    // Obter dados do plugin
     1703    if ( ! function_exists( 'get_plugin_data' ) ) {
     1704        require_once ABSPATH . 'wp-admin/includes/plugin.php';
     1705    }
     1706
     1707    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_file );
     1708    $plugin_name = $plugin_data['Name'];
     1709
     1710    // Verificar vulnerabilidades armazenadas
     1711    $all_vulnerabilities = get_option( 'htsec_vulnerabilities', [] );
     1712    $plugin_vulnerabilities = array_filter( $all_vulnerabilities, function( $vuln ) use ( $plugin_name ) {
     1713        return $vuln['software'] === $plugin_name;
     1714    } );
     1715
     1716    $vuln_count = count( $plugin_vulnerabilities );
     1717
     1718    if ( $vuln_count > 0 ) {
     1719        // Plugin TEM vulnerabilidades - badge vermelho
     1720        $message = sprintf(
     1721            /* translators: %d: Number of vulnerabilities */
     1722            _n( '%d vulnerabilidade CVE detectada', '%d vulnerabilidades CVE detectadas', $vuln_count, 'ht-security' ),
     1723            $vuln_count
     1724        );
     1725
     1726        $badge = sprintf(
     1727            '<span style="display: inline-block; background-color: #dc3545; color: white; padding: 3px 8px; border-radius: 3px; font-size: 11px; font-weight: bold; margin-right: 5px;">⚠ %s</span>',
     1728            esc_html( $message )
     1729        );
     1730
     1731        $link = sprintf(
     1732            '<a href="%s" style="text-decoration: none;">%s</a>',
     1733            esc_url( admin_url( 'options-general.php?page=ht-security#cve-check' ) ),
     1734            esc_html__( 'Ver detalhes', 'ht-security' )
     1735        );
     1736
     1737        $plugin_meta[] = $badge . ' ' . $link;
     1738    } else {
     1739        // Plugin NÃO TEM vulnerabilidades - badge verde
     1740        $last_check = get_option( 'htsec_last_cve_check', 0 );
     1741
     1742        if ( $last_check ) {
     1743            $badge = sprintf(
     1744                '<span style="display: inline-block; background-color: #28a745; color: white; padding: 3px 8px; border-radius: 3px; font-size: 11px; font-weight: bold;">✓ %s</span>',
     1745                esc_html__( 'Sem vulnerabilidades conhecidas', 'ht-security' )
     1746            );
     1747
     1748            $plugin_meta[] = $badge;
     1749        }
     1750    }
     1751
     1752    return $plugin_meta;
     1753}
     1754
     1755/**
     1756 * Adiciona CSS para a página de plugins.
     1757 */
     1758add_action( 'admin_head-plugins.php', 'htsec_plugins_page_styles' );
     1759function htsec_plugins_page_styles() {
     1760    ?>
     1761    <style>
     1762        .htsec-vuln-badge {
     1763            display: inline-block;
     1764            padding: 4px 10px;
     1765            border-radius: 3px;
     1766            font-size: 11px;
     1767            font-weight: bold;
     1768            margin-right: 8px;
     1769        }
     1770        .htsec-vuln-badge.danger {
     1771            background-color: #dc3545;
     1772            color: white;
     1773        }
     1774        .htsec-vuln-badge.success {
     1775            background-color: #28a745;
     1776            color: white;
     1777        }
     1778        .htsec-vuln-badge.warning {
     1779            background-color: #ffc107;
     1780            color: #333;
     1781        }
     1782    </style>
     1783    <?php
     1784}
     1785
     1786/**
     1787 * Adiciona notificação no topo da página de plugins se houver vulnerabilidades.
     1788 */
     1789add_action( 'admin_notices', 'htsec_plugins_page_vulnerability_notice' );
     1790function htsec_plugins_page_vulnerability_notice() {
     1791    $screen = get_current_screen();
     1792
     1793    if ( isset( $screen->id ) && 'plugins' === $screen->id ) {
     1794        $user_id = get_current_user_id();
     1795        $vulnerabilities = get_option( 'htsec_vulnerabilities', [] );
     1796        $vuln_count = count( $vulnerabilities );
     1797
     1798        if ( $vuln_count > 0 ) {
     1799            // Verificar se o usuário fechou o alerta de erro
     1800            $dismissed_error = get_user_meta( $user_id, 'htsec_dismissed_error_notice', true );
     1801            $last_check = get_option( 'htsec_last_cve_check', 0 );
     1802
     1803            // Se foi fechado e desde então não houve nova verificação, não mostrar
     1804            if ( $dismissed_error && $dismissed_error >= $last_check ) {
     1805                return;
     1806            }
     1807
     1808            // Agrupar por plugin
     1809            $plugins_affected = [];
     1810            foreach ( $vulnerabilities as $vuln ) {
     1811                $software = $vuln['software'];
     1812                if ( ! isset( $plugins_affected[ $software ] ) ) {
     1813                    $plugins_affected[ $software ] = 0;
     1814                }
     1815                $plugins_affected[ $software ]++;
     1816            }
     1817
     1818            $affected_count = count( $plugins_affected );
     1819
     1820            echo '<div class="notice notice-error is-dismissible htsec-cve-notice" style="border-left-color: #dc3545;" data-notice-type="error">';
     1821            echo '<p><strong>' . esc_html__( 'Alerta de Segurança do HT Security:', 'ht-security' ) . '</strong></p>';
     1822            echo '<p>' . sprintf(
     1823                /* translators: 1: Number of vulnerabilities, 2: Number of affected plugins */
     1824                esc_html( _n(
     1825                    'Foram detectadas %1$d vulnerabilidade CVE em %2$d plugin.',
     1826                    'Foram detectadas %1$d vulnerabilidades CVE em %2$d plugins.',
     1827                    $vuln_count,
     1828                    'ht-security'
     1829                ) ),
     1830                esc_html( $vuln_count ),
     1831                esc_html( $affected_count )
     1832            ) . '</p>';
     1833
     1834            echo '<p>';
     1835            foreach ( $plugins_affected as $software => $count ) {
     1836                echo '• <strong>' . esc_html( $software ) . '</strong>: ' . sprintf(
     1837                    /* translators: %d: Number of vulnerabilities */
     1838                    esc_html( _n( '%d CVE', '%d CVEs', $count, 'ht-security' ) ),
     1839                    esc_html( $count )
     1840                ) . '<br>';
     1841            }
     1842            echo '</p>';
     1843
     1844            echo '<p>';
     1845            echo '<a href="' . esc_url( admin_url( 'options-general.php?page=ht-security#cve-check' ) ) . '" class="button button-primary">';
     1846            echo esc_html__( 'Ver Detalhes no HT Security', 'ht-security' );
     1847            echo '</a>';
     1848            echo '</p>';
     1849            echo '</div>';
     1850        } else {
     1851            $last_check = get_option( 'htsec_last_cve_check', 0 );
     1852
     1853            if ( $last_check ) {
     1854                // Verificar se o usuário fechou o alerta de sucesso
     1855                $dismissed_success = get_user_meta( $user_id, 'htsec_dismissed_success_notice', true );
     1856
     1857                // Se foi fechado e desde então não houve nova verificação, não mostrar
     1858                if ( $dismissed_success && $dismissed_success >= $last_check ) {
     1859                    return;
     1860                }
     1861
     1862                echo '<div class="notice notice-success is-dismissible htsec-cve-notice" style="border-left-color: #28a745;" data-notice-type="success">';
     1863                echo '<p><strong>✓ ' . esc_html__( 'HT Security:', 'ht-security' ) . '</strong> ';
     1864                echo esc_html__( 'Nenhuma vulnerabilidade conhecida foi detectada nos seus plugins!', 'ht-security' );
     1865                echo '</p>';
     1866
     1867                $time_diff = human_time_diff( $last_check, current_time( 'timestamp' ) );
     1868                echo '<p style="font-size: 12px; color: #666; margin: 5px 0 0 0;">' . sprintf(
     1869                    /* translators: %s: Time since last check */
     1870                    esc_html__( 'Última verificação: %s atrás', 'ht-security' ),
     1871                    esc_html( $time_diff )
     1872                ) . '</p>';
     1873                echo '</div>';
     1874            }
     1875        }
     1876    }
     1877}
     1878
     1879/**
     1880 * Adiciona JavaScript para tratar o dismiss do alerta.
     1881 */
     1882add_action( 'admin_footer-plugins.php', 'htsec_dismiss_notice_script' );
     1883function htsec_dismiss_notice_script() {
     1884    ?>
     1885    <script type="text/javascript">
     1886    jQuery(document).ready(function($) {
     1887        // Quando o usuário clicar no botão de fechar
     1888        $(document).on('click', '.htsec-cve-notice .notice-dismiss', function() {
     1889            var notice = $(this).parent();
     1890            var noticeType = notice.data('notice-type');
     1891
     1892            // Enviar requisição AJAX para salvar que o alerta foi fechado
     1893            $.post(ajaxurl, {
     1894                action: 'htsec_dismiss_notice',
     1895                notice_type: noticeType,
     1896                nonce: '<?php echo esc_js( wp_create_nonce( 'htsec_dismiss_notice' ) ); ?>'
     1897            });
     1898        });
     1899    });
     1900    </script>
     1901    <?php
     1902}
     1903
     1904/**
     1905 * Handler AJAX para salvar dismiss do alerta.
     1906 */
     1907add_action( 'wp_ajax_htsec_dismiss_notice', 'htsec_ajax_dismiss_notice' );
     1908function htsec_ajax_dismiss_notice() {
     1909    check_ajax_referer( 'htsec_dismiss_notice', 'nonce' );
     1910
     1911    $notice_type = isset( $_POST['notice_type'] ) ? sanitize_text_field( wp_unslash( $_POST['notice_type'] ) ) : '';
     1912    $user_id = get_current_user_id();
     1913
     1914    if ( 'error' === $notice_type ) {
     1915        update_user_meta( $user_id, 'htsec_dismissed_error_notice', current_time( 'timestamp' ) );
     1916    } elseif ( 'success' === $notice_type ) {
     1917        update_user_meta( $user_id, 'htsec_dismissed_success_notice', current_time( 'timestamp' ) );
     1918    }
     1919
     1920    wp_send_json_success();
     1921}
     1922
     1923/**
     1924 * Handler AJAX para processar e enviar feedback.
     1925 */
     1926add_action( 'wp_ajax_htsec_send_feedback', 'htsec_ajax_send_feedback' );
     1927function htsec_ajax_send_feedback() {
     1928    check_ajax_referer( 'htsec_send_feedback', 'nonce' );
     1929
     1930    // Verificar permissões
     1931    if ( ! current_user_can( 'manage_options' ) ) {
     1932        wp_send_json_error( [
     1933            'message' => esc_html__( 'Você não tem permissão para enviar feedback.', 'ht-security' ),
     1934        ] );
     1935    }
     1936
     1937    // Obter e sanitizar a mensagem
     1938    $message = isset( $_POST['message'] ) ? sanitize_textarea_field( wp_unslash( $_POST['message'] ) ) : '';
     1939
     1940    // Validar mensagem
     1941    if ( empty( trim( $message ) ) ) {
     1942        wp_send_json_error( [
     1943            'message' => esc_html__( 'Por favor, digite uma mensagem antes de enviar.', 'ht-security' ),
     1944        ] );
     1945    }
     1946
     1947    if ( strlen( $message ) < 10 ) {
     1948        wp_send_json_error( [
     1949            'message' => esc_html__( 'A mensagem deve ter pelo menos 10 caracteres.', 'ht-security' ),
     1950        ] );
     1951    }
     1952
     1953    // Obter informações do usuário e site
     1954    $current_user = wp_get_current_user();
     1955    $user_email = $current_user->user_email;
     1956    $user_name = $current_user->display_name;
     1957    $site_url = get_site_url();
     1958    $site_name = get_bloginfo( 'name' );
     1959    $wp_version = get_bloginfo( 'version' );
     1960    $plugin_version = '1.3.0';
     1961
     1962    // Preparar o assunto do email
     1963    $subject = sprintf(
     1964        /* translators: %s: Site name */
     1965        esc_html__( '[HT Security Feedback] %s', 'ht-security' ),
     1966        $site_name
     1967    );
     1968
     1969    // Preparar o corpo do email
     1970    $email_body = esc_html__( 'Novo feedback recebido:', 'ht-security' ) . "\n\n";
     1971    $email_body .= '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' . "\n\n";
     1972    $email_body .= esc_html__( 'MENSAGEM:', 'ht-security' ) . "\n";
     1973    $email_body .= $message . "\n\n";
     1974    $email_body .= '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' . "\n\n";
     1975    $email_body .= esc_html__( 'INFORMAÇÕES DO REMETENTE:', 'ht-security' ) . "\n";
     1976    $email_body .= esc_html__( 'Nome:', 'ht-security' ) . ' ' . esc_html( $user_name ) . "\n";
     1977    $email_body .= esc_html__( 'E-mail:', 'ht-security' ) . ' ' . esc_html( $user_email ) . "\n";
     1978    $email_body .= esc_html__( 'Site:', 'ht-security' ) . ' ' . esc_html( $site_name ) . "\n";
     1979    $email_body .= esc_html__( 'URL:', 'ht-security' ) . ' ' . esc_url( $site_url ) . "\n";
     1980    $email_body .= esc_html__( 'WordPress:', 'ht-security' ) . ' ' . esc_html( $wp_version ) . "\n";
     1981    $email_body .= esc_html__( 'HT Security:', 'ht-security' ) . ' ' . esc_html( $plugin_version ) . "\n";
     1982    $email_body .= esc_html__( 'Data/Hora:', 'ht-security' ) . ' ' . current_time( 'mysql' ) . "\n\n";
     1983    $email_body .= '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━';
     1984
     1985    // Configurar headers do email
     1986    $headers = [
     1987        'Content-Type: text/plain; charset=UTF-8',
     1988        'From: ' . $site_name . ' <' . $user_email . '>',
     1989        'Reply-To: ' . $user_email,
     1990    ];
     1991
     1992    // Enviar email
     1993    $sent = wp_mail( '[email protected]', $subject, $email_body, $headers );
     1994
     1995    if ( $sent ) {
     1996        wp_send_json_success( [
     1997            'message' => esc_html__( 'Feedback enviado com sucesso! Obrigado pela sua contribuição.', 'ht-security' ),
     1998        ] );
     1999    } else {
     2000        wp_send_json_error( [
     2001            'message' => esc_html__( 'Erro ao enviar feedback. Por favor, tente novamente mais tarde.', 'ht-security' ),
     2002        ] );
     2003    }
     2004}
  • ht-security/trunk/readme.txt

    r3355589 r3391428  
    11=== HT Security ===
    22Contributors: WPFastSec
    3 Tags: security, headers, login, maintenance, permissions
     3Tags: security, vulnerabilities, headers, cve, maintenance
    44Requires at least: 6.5
    55Tested up to: 6.8
    66Requires PHP: 8.2
    7 Stable Tag: 1.2.0
     7Stable Tag: 1.3.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 Suite de Segurança completa: Headers, alertas de login, verificação do Core, modo manutenção e auditoria de permissões.
     11Suite de Segurança: Headers, detecção CVE, verificação Core, alertas de login e modo manutenção.
    1212
    1313== Description ==
     
    1818* Sistema de alerta de login com envio por e-mail.
    1919* Verificação de integridade do Core do WordPress.
     20* **Detecção de Vulnerabilidades CVE (NOVO v1.3.0)**
     21  - Integração com NVD (National Vulnerability Database) API 2.0
     22  - Verificação de WordPress Core e plugins ativos
     23  - Sistema de batch processing com rate limiting inteligente
     24  - 4 camadas de validação anti-falso positivo
     25  - Badges de vulnerabilidade na página de plugins (ativáveis/desativáveis)
     26  - Alertas dismissíveis por usuário
     27  - Notificação por email quando vulnerabilidades detectadas
     28  - Verificação automática a cada 12 horas
     29  - Suporte para API Key da NVD (rate limit aumentado)
    2030* Bloqueio de enumeração de usuários via API REST e parâmetros de autor.
    2131* Modo de manutenção com whitelist de IPs autorizados.
     
    3141== Frequently Asked Questions ==
    3242= O plugin envia e-mails em qual situação? =
    33 Logins bem-sucedidos e falhas de login.
     43Logins bem-sucedidos, falhas de login e quando vulnerabilidades CVE são detectadas (se a opção de alertas CVE estiver ativa).
    3444
    3545= Posso desativar os cabeçalhos? =
     
    3848= O Plugin verifica a integridade do Core do WordPress? =
    3949Sim, na versão 1.1.0 adicionamos essa funcionalidade para melhorar a visão clara de segurança para o administrador.
     50
     51= Como funciona a detecção de vulnerabilidades CVE? =
     52O plugin consulta a base de dados NVD (National Vulnerability Database) para verificar se há vulnerabilidades conhecidas no WordPress Core e plugins ativos. A verificação é feita automaticamente a cada 12 horas e pode ser executada manualmente.
     53
     54= Preciso de uma API Key da NVD? =
     55Não é obrigatório, mas recomendado. Sem API Key, o rate limit é de 5 requisições por 30 segundos. Com API Key (gratuita), aumenta para 50 requisições por 30 segundos, tornando as verificações muito mais rápidas.
     56
     57= Os badges de vulnerabilidade podem ser desativados? =
     58Sim! Nas configurações do HT Security há uma opção para desativar os badges na página de plugins. O alerta superior continuará funcionando.
     59
     60= Como funciono os alertas dismissíveis? =
     61Você pode fechar os alertas na página de plugins clicando no X. Eles não reaparecerão até a próxima verificação de vulnerabilidades. O estado de fechamento é salvo por usuário.
    4062
    4163= Como funciona o bloqueio de enumeração de usuários? =
     
    4870Depende das configurações do servidor. Em alguns casos, pode ser necessário corrigir manualmente via FTP/SSH.
    4971
     72= O sistema anti-falso positivo funciona bem? =
     73Sim! Implementamos 4 camadas de validação: validação de nome, validação de versão, filtro de termos genéricos e detecção de addons. Isso elimina mais de 99% dos falsos positivos.
     74
    5075= Irá chegar novas funcionalidades? =
    5176Sim, estamos lançando uma versão inicial e o plugin irá ganhar diversas novas funcionalidades com o passar do tempo.
     
    5782
    5883== Changelog ==
    59 = 1.0.0 =
    60 * Versão Pronta para Lançamento com principais funcionalidades:
    61   - Cabeçalhos como HSTS, X-Frame-Options, CSP e outros.
    62   - Página de configurações simples.
    63   - Sistema de alerta de login com envio por e-mail.
    64   - Configuração de e-mail para alertas.
     84= 1.3.0 =
     85* **Novidade Principal: Sistema de Detecção de Vulnerabilidades CVE**
     86  - Integração completa com NVD (National Vulnerability Database) API 2.0
     87  - Verificação automática de WordPress Core e plugins ativos a cada 12 horas
     88  - Verificação manual disponível na interface do plugin
     89  - Interface elegante com badges de severidade (CRITICAL, HIGH, MEDIUM, LOW)
     90  - Exibição detalhada de CVEs: ID, severidade, CVSS score, descrição e links
    6591
    66 = 1.1.0 =
    67 * Novidades:
    68   - Verificação do Core do WordPress para o Administrador do site.
     92* **Sistema de Batch Processing Inteligente**
     93  - Rate limiting respeitado: 5 requisições/30s sem API Key
     94  - Rate limiting aumentado: 50 requisições/30s com API Key da NVD
     95  - Processamento em batches com delays automáticos entre lotes
     96  - Feedback visual de progresso durante verificações
     97  - Estatísticas de verificação (itens verificados, batches processados, vulnerabilidades encontradas)
    6998
    70 = 1.1.1 =
    71 * Novidades:
    72   - Patch de Correção HSTS.
     99* **Sistema Anti-Falso Positivo (4 Camadas)**
     100  - Camada 1: Validação de nome do software
     101  - Camada 2: Validação de versão (elimina CVEs já corrigidos)
     102  - Camada 3: Filtro de termos genéricos (Apache, Tomcat, OWASP, etc.)
     103  - Camada 4: Detecção de addons/extensões (diferencia plugins base de addons)
     104  - Precisão de mais de 99% na detecção
     105
     106* **Preferências do Usuário**
     107  - Nova opção: Ativar/desativar badges na página de plugins
     108  - Alertas dismissíveis na página de plugins (com botão X)
     109  - Estado de dismiss salvo por usuário (cada admin/editor tem seu próprio estado)
     110  - Alertas reaparecem após novas verificações
     111  - Sistema AJAX para dismiss sem recarregar página
     112
     113* **Notificações por Email**
     114  - Email enviado quando vulnerabilidades são detectadas
     115  - Funciona tanto em verificações automáticas quanto manuais
     116  - Formatação profissional com severidade, CVSS e links
     117  - Lista todas as vulnerabilidades detectadas agrupadas por plugin
     118
     119* **Correção de Bugs**
     120  - Corrigido: Email de CVE agora envia corretamente em verificações manuais
     121  - Removida dependência incorreta da opção de alertas de login
     122
     123* **Melhorias de Interface**
     124  - Badges verdes/vermelhos na página de plugins
     125  - Alerta superior na página de plugins com contagem de vulnerabilidades
     126  - Links diretos para detalhes de CVE na interface do plugin
     127  - Indicação de tempo desde última verificação
     128  - Design responsivo e compatível com temas WordPress
    73129
    74130= 1.2.0 =
     
    80136  - Interface melhorada com novas opções de configuração
    81137
     138= 1.1.1 =
     139* Novidades:
     140  - Patch de Correção HSTS.
     141
     142= 1.1.0 =
     143* Novidades:
     144  - Verificação do Core do WordPress para o Administrador do site.
     145
     146= 1.0.0 =
     147* Versão Pronta para Lançamento com principais funcionalidades:
     148  - Cabeçalhos como HSTS, X-Frame-Options, CSP e outros.
     149  - Página de configurações simples.
     150  - Sistema de alerta de login com envio por e-mail.
     151  - Configuração de e-mail para alertas.
     152
    82153== Upgrade Notice ==
     154
     155= 1.3.0 =
     156Nova detecção de vulnerabilidades CVE! Monitore WordPress e plugins contra CVEs conhecidos. Sistema com 4 camadas anti-falso positivo, badges ativáveis e alertas dismissíveis. Bug fix: email CVE agora funciona em verificações manuais.
     157
     158= 1.2.0 =
     159Importantes melhorias de segurança: bloqueio de enumeração de usuários, modo de manutenção com IP whitelist e auditoria de permissões de arquivos.
     160
     161= 1.1.1 =
     162Patch de correção.
     163
     164= 1.1.0 =
     165Adicionado funcionalidade de verificação do Core, aplicado compatibilidade total com versão 6.8.1.
    83166
    84167= 1.0.0 =
    85168Primeira versão estável.
    86169
    87 = 1.1.0 =
    88 Adicionado funcionalidade de verificação do Core, aplicado compatibilidade total com versão 6.8.1.
    89 
    90 = 1.1.1 =
    91 Patch de correção.
    92 
    93 = 1.2.0 =
    94 Importantes melhorias de segurança: bloqueio de enumeração de usuários, modo de manutenção com IP whitelist e auditoria de permissões de arquivos.
    95 
    96170== License ==
    97171Este plugin está licenciado sob a GNU General Public License v2.0 ou posterior. Para mais informações, visite https://www.gnu.org/licenses/gpl-2.0.html.
Note: See TracChangeset for help on using the changeset viewer.