Plugin Directory

Changeset 3458129


Ignore:
Timestamp:
02/10/2026 02:47:49 PM (9 days ago)
Author:
skyminds
Message:

release SpamJam v1.1.0

Location:
spamjam/trunk
Files:
2 deleted
9 edited

Legend:

Unmodified
Added
Removed
  • spamjam/trunk/changelog.txt

    r3428403 r3458129  
     1= 1.1.0 - 2025-02-10 =
     2*   Security - Fixed SQL injection risk: all database queries now use $wpdb->prepare() with %i/%s placeholders
     3*   Security - Fixed email confirmation auth flaw: replaced expiring nonce with persistent hashed token
     4*   Security - Fixed premium plan bypass via HTTP Host header spoofing
     5*   Security - Sanitized all $_SERVER['REMOTE_ADDR'] usage via centralized get_client_ip() helper
     6*   Security - Added wp_unslash() to all raw $_POST accesses and nonce verifications
     7*   Security - Escaped all admin notice output with esc_html__() in multisite sync
     8*   WP VIP - Replaced file_get_contents(), rename(), unlink() with WP_Filesystem API in migration
     9*   WPCS - Replaced all _e() with esc_html_e() in admin templates
     10*   WPCS - Escaped $disabled output with esc_attr() in all form fields
     11*   WPCS - Replaced date() with gmdate() in advanced reporting
     12*   WPCS - Replaced deprecated current_time('timestamp') with time()
     13*   Enhancement - Added WooCommerce product_instance_caching compatibility
     14*   Enhancement - Added WooCommerce cart_checkout_blocks compatibility
     15
    116= 1.0.7 - 2025-12-27 =
    217*   Fixed - Field swap hook changed from pre_comment_on_post to init for better compatibility
  • spamjam/trunk/composer.lock

    r3427664 r3458129  
    699699    "platform": {},
    700700    "platform-dev": {},
    701     "plugin-api-version": "2.6.0"
     701    "plugin-api-version": "2.9.0"
    702702}
  • spamjam/trunk/includes/admin-tabs.php

    r3427664 r3458129  
    9999    $total      = 0;
    100100
    101     if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) === $table_name ) {
     101    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     102    if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) === $table_name ) {
    102103        // Optimized: Single query instead of 4 separate queries (75% faster).
     104        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    103105        $stats = $wpdb->get_row(
    104             "SELECT
    105                 COUNT(*) as total,
    106                 SUM(CASE WHEN DATE(created_at) = CURDATE() THEN 1 ELSE 0 END) as today,
    107                 SUM(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 1 ELSE 0 END) as week,
    108                 SUM(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1 ELSE 0 END) as month
    109             FROM $table_name"
     106            $wpdb->prepare(
     107                'SELECT
     108                    COUNT(*) as total,
     109                    SUM(CASE WHEN DATE(created_at) = CURDATE() THEN 1 ELSE 0 END) as today,
     110                    SUM(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 1 ELSE 0 END) as week,
     111                    SUM(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1 ELSE 0 END) as month
     112                FROM %i',
     113                $table_name
     114            )
    110115        );
    111116
     
    280285            <table class="form-table">
    281286                <tr>
    282                     <th scope="row"><?php _e( 'Comment Protection', 'spamjam' ); ?></th>
     287                    <th scope="row"><?php esc_html_e( 'Comment Protection', 'spamjam' ); ?></th>
    283288                    <td>
    284289                        <label class="switch">
     
    287292                            <span class="slider round"></span>
    288293                        </label>
    289                         <p class="description"><?php _e( 'Enable spam protection for comments (always enabled)', 'spamjam' ); ?></p>
     294                        <p class="description"><?php esc_html_e( 'Enable spam protection for comments (always enabled)', 'spamjam' ); ?></p>
    290295                    </td>
    291296                </tr>
     
    293298                <tr>
    294299                    <th scope="row">
    295                         <?php _e( 'Registration Protection', 'spamjam' ); ?>
     300                        <?php esc_html_e( 'Registration Protection', 'spamjam' ); ?>
    296301                        <span class="plan-badge pro">PRO</span>
    297302                    </th>
     
    300305                            <input type="checkbox" name="spamjam_enable_registration_protection" value="1"
    301306                                <?php checked( 1, get_option( 'spamjam_enable_registration_protection', 0 ) ); ?>
    302                                 <?php echo $disabled; ?>>
    303                             <span class="slider round"></span>
    304                         </label>
    305                         <p class="description"><?php _e( 'Protect registration forms from spam bots', 'spamjam' ); ?></p>
     307                                <?php echo esc_attr( $disabled ); ?>>
     308                            <span class="slider round"></span>
     309                        </label>
     310                        <p class="description"><?php esc_html_e( 'Protect registration forms from spam bots', 'spamjam' ); ?></p>
    306311                    </td>
    307312                </tr>
     
    309314                <tr>
    310315                    <th scope="row">
    311                         <?php _e( 'Contact Form Protection', 'spamjam' ); ?>
     316                        <?php esc_html_e( 'Contact Form Protection', 'spamjam' ); ?>
    312317                        <span class="plan-badge business">BUSINESS</span>
    313318                    </th>
     
    316321                            <input type="checkbox" name="spamjam_enable_contact_form_protection" value="1"
    317322                                <?php checked( 1, get_option( 'spamjam_enable_contact_form_protection', 0 ) ); ?>
    318                                 <?php echo $disabled; ?>>
    319                             <span class="slider round"></span>
    320                         </label>
    321                         <p class="description"><?php _e( 'Protect Contact Form 7, WPForms, and Gravity Forms', 'spamjam' ); ?></p>
     323                                <?php echo esc_attr( $disabled ); ?>>
     324                            <span class="slider round"></span>
     325                        </label>
     326                        <p class="description"><?php esc_html_e( 'Protect Contact Form 7, WPForms, and Gravity Forms', 'spamjam' ); ?></p>
    322327                    </td>
    323328                </tr>
     
    332337            <table class="form-table">
    333338                <tr>
    334                     <th scope="row"><?php _e( 'Honeypot Field Name', 'spamjam' ); ?></th>
     339                    <th scope="row"><?php esc_html_e( 'Honeypot Field Name', 'spamjam' ); ?></th>
    335340                    <td>
    336341                        <input type="text" name="spamjam_honeypot_field"
    337342                            value="<?php echo esc_attr( get_option( 'spamjam_honeypot_field', 'website_url' ) ); ?>"
    338343                            class="regular-text">
    339                         <p class="description"><?php _e( 'Custom name for the honeypot field (advanced users only)', 'spamjam' ); ?></p>
     344                        <p class="description"><?php esc_html_e( 'Custom name for the honeypot field (advanced users only)', 'spamjam' ); ?></p>
    340345                    </td>
    341346                </tr>
     
    365370            <table class="form-table">
    366371                <tr>
    367                     <th scope="row"><?php _e( 'Use Premium Blocklist', 'spamjam' ); ?></th>
     372                    <th scope="row"><?php esc_html_e( 'Use Premium Blocklist', 'spamjam' ); ?></th>
    368373                    <td>
    369374                        <label class="switch">
    370375                            <input type="checkbox" name="spamjam_use_premium_blocklist" value="1"
    371376                                <?php checked( 1, get_option( 'spamjam_use_premium_blocklist', 0 ) ); ?>
    372                                 <?php echo $disabled; ?>>
    373                             <span class="slider round"></span>
    374                         </label>
    375                         <p class="description"><?php _e( 'Enable the premium blocklist with 15,000+ spam terms from WordPress Comment Blocklist', 'spamjam' ); ?></p>
     377                                <?php echo esc_attr( $disabled ); ?>>
     378                            <span class="slider round"></span>
     379                        </label>
     380                        <p class="description"><?php esc_html_e( 'Enable the premium blocklist with 15,000+ spam terms from WordPress Comment Blocklist', 'spamjam' ); ?></p>
    376381                    </td>
    377382                </tr>
    378383                <tr class="dependent-field" data-depends="spamjam_use_premium_blocklist">
    379                     <th scope="row"><?php _e( 'Auto-Update Blocklist', 'spamjam' ); ?></th>
     384                    <th scope="row"><?php esc_html_e( 'Auto-Update Blocklist', 'spamjam' ); ?></th>
    380385                    <td>
    381386                        <label class="switch">
    382387                            <input type="checkbox" name="spamjam_update_blocklist_automatically" value="1"
    383388                                <?php checked( 1, get_option( 'spamjam_update_blocklist_automatically', 1 ) ); ?>
    384                                 <?php echo $disabled; ?>>
    385                             <span class="slider round"></span>
    386                         </label>
    387                         <p class="description"><?php _e( 'Automatically update the premium blocklist daily from GitHub', 'spamjam' ); ?></p>
     389                                <?php echo esc_attr( $disabled ); ?>>
     390                            <span class="slider round"></span>
     391                        </label>
     392                        <p class="description"><?php esc_html_e( 'Automatically update the premium blocklist daily from GitHub', 'spamjam' ); ?></p>
    388393                    </td>
    389394                </tr>
     
    400405            <table class="form-table">
    401406                <tr>
    402                     <th scope="row"><?php _e( 'Enable Custom Blocklist', 'spamjam' ); ?></th>
     407                    <th scope="row"><?php esc_html_e( 'Enable Custom Blocklist', 'spamjam' ); ?></th>
    403408                    <td>
    404409                        <label class="switch">
    405410                            <input type="checkbox" name="spamjam_enable_custom_blocklist" value="1"
    406411                                <?php checked( 1, get_option( 'spamjam_enable_custom_blocklist', 0 ) ); ?>
    407                                 <?php echo $disabled; ?>>
    408                             <span class="slider round"></span>
    409                         </label>
    410                         <p class="description"><?php _e( 'Add your own custom keywords to block', 'spamjam' ); ?></p>
     412                                <?php echo esc_attr( $disabled ); ?>>
     413                            <span class="slider round"></span>
     414                        </label>
     415                        <p class="description"><?php esc_html_e( 'Add your own custom keywords to block', 'spamjam' ); ?></p>
    411416                    </td>
    412417                </tr>
    413418                <tr class="dependent-field" data-depends="spamjam_enable_custom_blocklist">
    414                     <th scope="row"><?php _e( 'Blocked Keywords', 'spamjam' ); ?></th>
     419                    <th scope="row"><?php esc_html_e( 'Blocked Keywords', 'spamjam' ); ?></th>
    415420                    <td>
    416421                        <textarea name="spamjam_custom_blocklist" rows="8" class="large-text"
    417                             <?php echo $disabled; ?>
     422                            <?php echo esc_attr( $disabled ); ?>
    418423                            placeholder="viagra&#10;casino&#10;cheap-pills"><?php echo esc_textarea( get_option( 'spamjam_custom_blocklist', '' ) ); ?></textarea>
    419                         <p class="description"><?php _e( 'One keyword per line. Case-insensitive.', 'spamjam' ); ?></p>
     424                        <p class="description"><?php esc_html_e( 'One keyword per line. Case-insensitive.', 'spamjam' ); ?></p>
    420425                    </td>
    421426                </tr>
     
    432437            <table class="form-table">
    433438                <tr>
    434                     <th scope="row"><?php _e( 'Minimum Comment Length', 'spamjam' ); ?></th>
     439                    <th scope="row"><?php esc_html_e( 'Minimum Comment Length', 'spamjam' ); ?></th>
    435440                    <td>
    436441                        <input type="number" name="spamjam_min_comment_length"
    437442                            value="<?php echo esc_attr( get_option( 'spamjam_min_comment_length', 0 ) ); ?>"
    438                             min="0" max="1000" class="small-text" <?php echo $disabled; ?>>
    439                         <p class="description"><?php _e( 'Minimum characters required (0 = disabled)', 'spamjam' ); ?></p>
    440                     </td>
    441                 </tr>
    442                 <tr>
    443                     <th scope="row"><?php _e( 'Maximum Links Allowed', 'spamjam' ); ?></th>
     443                            min="0" max="1000" class="small-text" <?php echo esc_attr( $disabled ); ?>>
     444                        <p class="description"><?php esc_html_e( 'Minimum characters required (0 = disabled)', 'spamjam' ); ?></p>
     445                    </td>
     446                </tr>
     447                <tr>
     448                    <th scope="row"><?php esc_html_e( 'Maximum Links Allowed', 'spamjam' ); ?></th>
    444449                    <td>
    445450                        <input type="number" name="spamjam_max_links_allowed"
    446451                            value="<?php echo esc_attr( get_option( 'spamjam_max_links_allowed', 2 ) ); ?>"
    447                             min="0" max="20" class="small-text" <?php echo $disabled; ?>>
    448                         <p class="description"><?php _e( 'Maximum number of links allowed in comments', 'spamjam' ); ?></p>
     452                            min="0" max="20" class="small-text" <?php echo esc_attr( $disabled ); ?>>
     453                        <p class="description"><?php esc_html_e( 'Maximum number of links allowed in comments', 'spamjam' ); ?></p>
    449454                    </td>
    450455                </tr>
     
    461466            <table class="form-table">
    462467                <tr>
    463                     <th scope="row"><?php _e( 'Enable Geographic Blocking', 'spamjam' ); ?></th>
     468                    <th scope="row"><?php esc_html_e( 'Enable Geographic Blocking', 'spamjam' ); ?></th>
    464469                    <td>
    465470                        <label class="switch">
    466471                            <input type="checkbox" name="spamjam_enable_country_blocking" value="1"
    467472                                <?php checked( 1, get_option( 'spamjam_enable_country_blocking', 0 ) ); ?>
    468                                 <?php echo $disabled; ?>>
    469                             <span class="slider round"></span>
    470                         </label>
    471                         <p class="description"><?php _e( 'Block comments from specific countries', 'spamjam' ); ?></p>
     473                                <?php echo esc_attr( $disabled ); ?>>
     474                            <span class="slider round"></span>
     475                        </label>
     476                        <p class="description"><?php esc_html_e( 'Block comments from specific countries', 'spamjam' ); ?></p>
    472477                    </td>
    473478                </tr>
    474479                <tr class="dependent-field" data-depends="spamjam_enable_country_blocking">
    475                     <th scope="row"><?php _e( 'Blocked Countries', 'spamjam' ); ?></th>
     480                    <th scope="row"><?php esc_html_e( 'Blocked Countries', 'spamjam' ); ?></th>
    476481                    <td>
    477482                        <textarea name="spamjam_blocked_countries" rows="5" class="large-text"
    478                             <?php echo $disabled; ?>
     483                            <?php echo esc_attr( $disabled ); ?>
    479484                            placeholder="US&#10;GB&#10;CN"><?php echo esc_textarea( get_option( 'spamjam_blocked_countries', '' ) ); ?></textarea>
    480                         <p class="description"><?php _e( 'Two-letter country codes (ISO 3166-1 alpha-2), one per line', 'spamjam' ); ?></p>
     485                        <p class="description"><?php esc_html_e( 'Two-letter country codes (ISO 3166-1 alpha-2), one per line', 'spamjam' ); ?></p>
    481486                    </td>
    482487                </tr>
     
    493498            <table class="form-table">
    494499                <tr>
    495                     <th scope="row"><?php _e( 'Enable Email Blocking', 'spamjam' ); ?></th>
     500                    <th scope="row"><?php esc_html_e( 'Enable Email Blocking', 'spamjam' ); ?></th>
    496501                    <td>
    497502                        <label class="switch">
    498503                            <input type="checkbox" name="spamjam_enable_email_blocking" value="1"
    499504                                <?php checked( 1, get_option( 'spamjam_enable_email_blocking', 0 ) ); ?>
    500                                 <?php echo $disabled; ?>>
    501                             <span class="slider round"></span>
    502                         </label>
    503                         <p class="description"><?php _e( 'Block specific email addresses or domains from commenting and registering', 'spamjam' ); ?></p>
     505                                <?php echo esc_attr( $disabled ); ?>>
     506                            <span class="slider round"></span>
     507                        </label>
     508                        <p class="description"><?php esc_html_e( 'Block specific email addresses or domains from commenting and registering', 'spamjam' ); ?></p>
    504509                    </td>
    505510                </tr>
    506511                <tr class="dependent-field" data-depends="spamjam_enable_email_blocking">
    507                     <th scope="row"><?php _e( 'Blocked Emails', 'spamjam' ); ?></th>
     512                    <th scope="row"><?php esc_html_e( 'Blocked Emails', 'spamjam' ); ?></th>
    508513                    <td>
    509514                        <textarea name="spamjam_blocked_emails" rows="8" class="large-text"
    510                             <?php echo $disabled; ?>
     515                            <?php echo esc_attr( $disabled ); ?>
    511516                            placeholder="[email protected]&#10;@spam-domain.com&#10;spam-domain.com"><?php echo esc_textarea( get_option( 'spamjam_blocked_emails', '' ) ); ?></textarea>
    512                         <p class="description"><?php _e( 'One email or domain per line. Examples: [email protected], @example.com, or example.com', 'spamjam' ); ?></p>
     517                        <p class="description"><?php esc_html_e( 'One email or domain per line. Examples: [email protected], @example.com, or example.com', 'spamjam' ); ?></p>
    513518                    </td>
    514519                </tr>
     
    525530            <table class="form-table">
    526531                <tr>
    527                     <th scope="row"><?php _e( 'Enable IP Blocking', 'spamjam' ); ?></th>
     532                    <th scope="row"><?php esc_html_e( 'Enable IP Blocking', 'spamjam' ); ?></th>
    528533                    <td>
    529534                        <label class="switch">
    530535                            <input type="checkbox" name="spamjam_enable_ip_blocking" value="1"
    531536                                <?php checked( 1, get_option( 'spamjam_enable_ip_blocking', 0 ) ); ?>
    532                                 <?php echo $disabled; ?>>
    533                             <span class="slider round"></span>
    534                         </label>
    535                         <p class="description"><?php _e( 'Block comments from specific IP addresses or ranges', 'spamjam' ); ?></p>
     537                                <?php echo esc_attr( $disabled ); ?>>
     538                            <span class="slider round"></span>
     539                        </label>
     540                        <p class="description"><?php esc_html_e( 'Block comments from specific IP addresses or ranges', 'spamjam' ); ?></p>
    536541                    </td>
    537542                </tr>
    538543                <tr class="dependent-field" data-depends="spamjam_enable_ip_blocking">
    539                     <th scope="row"><?php _e( 'Blocked IPs', 'spamjam' ); ?></th>
     544                    <th scope="row"><?php esc_html_e( 'Blocked IPs', 'spamjam' ); ?></th>
    540545                    <td>
    541546                        <textarea name="spamjam_blocked_ips" rows="8" class="large-text"
    542                             <?php echo $disabled; ?>
     547                            <?php echo esc_attr( $disabled ); ?>
    543548                            placeholder="192.168.1.1&#10;10.0.0.0/8"><?php echo esc_textarea( get_option( 'spamjam_blocked_ips', '' ) ); ?></textarea>
    544                         <p class="description"><?php _e( 'One IP address or CIDR range per line', 'spamjam' ); ?></p>
     549                        <p class="description"><?php esc_html_e( 'One IP address or CIDR range per line', 'spamjam' ); ?></p>
    545550                    </td>
    546551                </tr>
     
    565570                <h3>📧 Trusted Emails</h3>
    566571                <span class="plan-badge business">BUSINESS</span>
    567                 <p class="section-description"><?php _e( 'Comments from these email addresses will always be approved and bypass all spam checks.', 'spamjam' ); ?></p>
    568             </div>
    569 
    570             <table class="form-table">
    571                 <tr>
    572                     <th scope="row"><?php _e( 'Enable Email Allowlist', 'spamjam' ); ?></th>
     572                <p class="section-description"><?php esc_html_e( 'Comments from these email addresses will always be approved and bypass all spam checks.', 'spamjam' ); ?></p>
     573            </div>
     574
     575            <table class="form-table">
     576                <tr>
     577                    <th scope="row"><?php esc_html_e( 'Enable Email Allowlist', 'spamjam' ); ?></th>
    573578                    <td>
    574579                        <label class="switch">
    575580                            <input type="checkbox" name="spamjam_enable_whitelist" value="1"
    576581                                <?php checked( 1, get_option( 'spamjam_enable_whitelist', 0 ) ); ?>
    577                                 <?php echo $disabled; ?>>
    578                             <span class="slider round"></span>
    579                         </label>
    580                         <p class="description"><?php _e( 'Always allow comments from trusted email addresses', 'spamjam' ); ?></p>
     582                                <?php echo esc_attr( $disabled ); ?>>
     583                            <span class="slider round"></span>
     584                        </label>
     585                        <p class="description"><?php esc_html_e( 'Always allow comments from trusted email addresses', 'spamjam' ); ?></p>
    581586                    </td>
    582587                </tr>
    583588                <tr class="dependent-field" data-depends="spamjam_enable_whitelist">
    584                     <th scope="row"><?php _e( 'Allowed Emails', 'spamjam' ); ?></th>
     589                    <th scope="row"><?php esc_html_e( 'Allowed Emails', 'spamjam' ); ?></th>
    585590                    <td>
    586591                        <textarea name="spamjam_whitelist_emails" rows="10" class="large-text"
    587                             <?php echo $disabled; ?>
     592                            <?php echo esc_attr( $disabled ); ?>
    588593                            placeholder="[email protected]&#10;[email protected]&#10;[email protected]"><?php echo esc_textarea( get_option( 'spamjam_whitelist_emails', '' ) ); ?></textarea>
    589                         <p class="description"><?php _e( 'One email address per line. These users will bypass all spam checks.', 'spamjam' ); ?></p>
     594                        <p class="description"><?php esc_html_e( 'One email address per line. These users will bypass all spam checks.', 'spamjam' ); ?></p>
    590595                    </td>
    591596                </tr>
     
    620625                <h3>⏱️ Rate Limiting</h3>
    621626                <span class="plan-badge pro">PRO</span>
    622                 <p class="section-description"><?php _e( 'Prevent spam floods by limiting how often users can comment.', 'spamjam' ); ?></p>
    623             </div>
    624 
    625             <table class="form-table">
    626                 <tr>
    627                     <th scope="row"><?php _e( 'Enable Rate Limiting', 'spamjam' ); ?></th>
     627                <p class="section-description"><?php esc_html_e( 'Prevent spam floods by limiting how often users can comment.', 'spamjam' ); ?></p>
     628            </div>
     629
     630            <table class="form-table">
     631                <tr>
     632                    <th scope="row"><?php esc_html_e( 'Enable Rate Limiting', 'spamjam' ); ?></th>
    628633                    <td>
    629634                        <label class="switch">
    630635                            <input type="checkbox" name="spamjam_enable_rate_limiting" value="1"
    631636                                <?php checked( 1, get_option( 'spamjam_enable_rate_limiting', 0 ) ); ?>
    632                                 <?php echo $disabled; ?>>
    633                             <span class="slider round"></span>
    634                         </label>
    635                         <p class="description"><?php _e( 'Limit comment frequency per IP address', 'spamjam' ); ?></p>
     637                                <?php echo esc_attr( $disabled ); ?>>
     638                            <span class="slider round"></span>
     639                        </label>
     640                        <p class="description"><?php esc_html_e( 'Limit comment frequency per IP address', 'spamjam' ); ?></p>
    636641                    </td>
    637642                </tr>
    638643                <tr class="dependent-field" data-depends="spamjam_enable_rate_limiting">
    639                     <th scope="row"><?php _e( 'Maximum Comments', 'spamjam' ); ?></th>
     644                    <th scope="row"><?php esc_html_e( 'Maximum Comments', 'spamjam' ); ?></th>
    640645                    <td>
    641646                        <input type="number" name="spamjam_rate_limit_count"
    642647                            value="<?php echo esc_attr( get_option( 'spamjam_rate_limit_count', 3 ) ); ?>"
    643                             min="1" max="100" class="small-text" <?php echo $disabled; ?>>
    644                         <p class="description"><?php _e( 'Maximum number of comments allowed per time period', 'spamjam' ); ?></p>
     648                            min="1" max="100" class="small-text" <?php echo esc_attr( $disabled ); ?>>
     649                        <p class="description"><?php esc_html_e( 'Maximum number of comments allowed per time period', 'spamjam' ); ?></p>
    645650                    </td>
    646651                </tr>
    647652                <tr class="dependent-field" data-depends="spamjam_enable_rate_limiting">
    648                     <th scope="row"><?php _e( 'Time Period (minutes)', 'spamjam' ); ?></th>
     653                    <th scope="row"><?php esc_html_e( 'Time Period (minutes)', 'spamjam' ); ?></th>
    649654                    <td>
    650655                        <input type="number" name="spamjam_rate_limit_period"
    651656                            value="<?php echo esc_attr( get_option( 'spamjam_rate_limit_period', 10 ) ); ?>"
    652                             min="1" max="1440" class="small-text" <?php echo $disabled; ?>>
    653                         <p class="description"><?php _e( 'Time window for rate limiting (1-1440 minutes)', 'spamjam' ); ?></p>
     657                            min="1" max="1440" class="small-text" <?php echo esc_attr( $disabled ); ?>>
     658                        <p class="description"><?php esc_html_e( 'Time window for rate limiting (1-1440 minutes)', 'spamjam' ); ?></p>
    654659                    </td>
    655660                </tr>
     
    681686                <h3>📝 Spam Logger</h3>
    682687                <span class="plan-badge business">BUSINESS</span>
    683                 <p class="section-description"><?php _e( 'Keep a detailed log of all blocked spam attempts.', 'spamjam' ); ?></p>
    684             </div>
    685 
    686             <table class="form-table">
    687                 <tr>
    688                     <th scope="row"><?php _e( 'Enable Spam Logging', 'spamjam' ); ?></th>
     688                <p class="section-description"><?php esc_html_e( 'Keep a detailed log of all blocked spam attempts.', 'spamjam' ); ?></p>
     689            </div>
     690
     691            <table class="form-table">
     692                <tr>
     693                    <th scope="row"><?php esc_html_e( 'Enable Spam Logging', 'spamjam' ); ?></th>
    689694                    <td>
    690695                        <label class="switch">
    691696                            <input type="checkbox" name="spamjam_enable_spam_logging" value="1"
    692697                                <?php checked( 1, get_option( 'spamjam_enable_spam_logging', 0 ) ); ?>
    693                                 <?php echo $disabled; ?>>
    694                             <span class="slider round"></span>
    695                         </label>
    696                         <p class="description"><?php _e( 'Log all blocked spam attempts to database', 'spamjam' ); ?></p>
     698                                <?php echo esc_attr( $disabled ); ?>>
     699                            <span class="slider round"></span>
     700                        </label>
     701                        <p class="description"><?php esc_html_e( 'Log all blocked spam attempts to database', 'spamjam' ); ?></p>
    697702                    </td>
    698703                </tr>
    699704                <tr class="dependent-field" data-depends="spamjam_enable_spam_logging">
    700                     <th scope="row"><?php _e( 'Log Retention (days)', 'spamjam' ); ?></th>
     705                    <th scope="row"><?php esc_html_e( 'Log Retention (days)', 'spamjam' ); ?></th>
    701706                    <td>
    702707                        <input type="number" name="spamjam_log_retention_days"
    703708                            value="<?php echo esc_attr( get_option( 'spamjam_log_retention_days', 30 ) ); ?>"
    704                             min="1" max="365" class="small-text" <?php echo $disabled; ?>>
    705                         <p class="description"><?php _e( 'How long to keep logs (1-365 days)', 'spamjam' ); ?></p>
     709                            min="1" max="365" class="small-text" <?php echo esc_attr( $disabled ); ?>>
     710                        <p class="description"><?php esc_html_e( 'How long to keep logs (1-365 days)', 'spamjam' ); ?></p>
    706711                    </td>
    707712                </tr>
     
    730735    $table_name = $wpdb->prefix . 'spamjam_log';
    731736
    732     if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) !== $table_name ) {
    733         echo '<p>' . __( 'Spam log table not found. Logs will be created when spam is blocked.', 'spamjam' ) . '</p>';
     737    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     738    if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) !== $table_name ) {
     739        echo '<p>' . esc_html__( 'Spam log table not found. Logs will be created when spam is blocked.', 'spamjam' ) . '</p>';
    734740        return;
    735741    }
     
    741747    if ( false === $logs ) {
    742748        // Cache miss - query database.
     749        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    743750        $logs = $wpdb->get_results(
    744             "SELECT id, ip_address, email, reason, content, blocked_at
    745             FROM $table_name
    746             ORDER BY blocked_at DESC
    747             LIMIT 50"
     751            $wpdb->prepare(
     752                'SELECT id, ip_address, email, reason, content, blocked_at
     753                FROM %i
     754                ORDER BY blocked_at DESC
     755                LIMIT 50',
     756                $table_name
     757            )
    748758        );
    749759        // Cache for 5 minutes.
     
    759769        <thead>
    760770            <tr>
    761                 <th><?php _e( 'Date', 'spamjam' ); ?></th>
    762                 <th><?php _e( 'IP Address', 'spamjam' ); ?></th>
    763                 <th><?php _e( 'Email', 'spamjam' ); ?></th>
    764                 <th><?php _e( 'Reason', 'spamjam' ); ?></th>
    765                 <th><?php _e( 'Content Preview', 'spamjam' ); ?></th>
     771                <th><?php esc_html_e( 'Date', 'spamjam' ); ?></th>
     772                <th><?php esc_html_e( 'IP Address', 'spamjam' ); ?></th>
     773                <th><?php esc_html_e( 'Email', 'spamjam' ); ?></th>
     774                <th><?php esc_html_e( 'Reason', 'spamjam' ); ?></th>
     775                <th><?php esc_html_e( 'Content Preview', 'spamjam' ); ?></th>
    766776            </tr>
    767777        </thead>
     
    802812                <h3>🔌 API Access</h3>
    803813                <span class="plan-badge agency">AGENCY</span>
    804                 <p class="section-description"><?php _e( 'Allow external applications to access spam statistics and logs via REST API.', 'spamjam' ); ?></p>
    805             </div>
    806 
    807             <table class="form-table">
    808                 <tr>
    809                     <th scope="row"><?php _e( 'Enable API Access', 'spamjam' ); ?></th>
     814                <p class="section-description"><?php esc_html_e( 'Allow external applications to access spam statistics and logs via REST API.', 'spamjam' ); ?></p>
     815            </div>
     816
     817            <table class="form-table">
     818                <tr>
     819                    <th scope="row"><?php esc_html_e( 'Enable API Access', 'spamjam' ); ?></th>
    810820                    <td>
    811821                        <label class="switch">
    812822                            <input type="checkbox" name="spamjam_enable_api_access" value="1"
    813823                                <?php checked( 1, get_option( 'spamjam_enable_api_access', 0 ) ); ?>
    814                                 <?php echo $disabled; ?>>
    815                             <span class="slider round"></span>
    816                         </label>
    817                         <p class="description"><?php _e( 'Enable REST API endpoints for external access', 'spamjam' ); ?></p>
     824                                <?php echo esc_attr( $disabled ); ?>>
     825                            <span class="slider round"></span>
     826                        </label>
     827                        <p class="description"><?php esc_html_e( 'Enable REST API endpoints for external access', 'spamjam' ); ?></p>
    818828                    </td>
    819829                </tr>
    820830                <tr class="dependent-field" data-depends="spamjam_enable_api_access">
    821                     <th scope="row"><?php _e( 'API Key', 'spamjam' ); ?></th>
     831                    <th scope="row"><?php esc_html_e( 'API Key', 'spamjam' ); ?></th>
    822832                    <td>
    823833                        <input type="text" name="spamjam_api_key" readonly
    824834                            value="<?php echo esc_attr( $api_key ); ?>"
    825835                            class="regular-text" style="font-family: monospace;">
    826                         <p class="description"><?php _e( 'Use this key in the Authorization header: Bearer YOUR_API_KEY', 'spamjam' ); ?></p>
     836                        <p class="description"><?php esc_html_e( 'Use this key in the Authorization header: Bearer YOUR_API_KEY', 'spamjam' ); ?></p>
    827837                    </td>
    828838                </tr>
     
    835845                <h3>🎨 White Label Mode</h3>
    836846                <span class="plan-badge agency">AGENCY</span>
    837                 <p class="section-description"><?php _e( 'Customize the plugin branding for your clients.', 'spamjam' ); ?></p>
    838             </div>
    839 
    840             <table class="form-table">
    841                 <tr>
    842                     <th scope="row"><?php _e( 'Enable White Label', 'spamjam' ); ?></th>
     847                <p class="section-description"><?php esc_html_e( 'Customize the plugin branding for your clients.', 'spamjam' ); ?></p>
     848            </div>
     849
     850            <table class="form-table">
     851                <tr>
     852                    <th scope="row"><?php esc_html_e( 'Enable White Label', 'spamjam' ); ?></th>
    843853                    <td>
    844854                        <label class="switch">
    845855                            <input type="checkbox" name="spamjam_enable_white_label" value="1"
    846856                                <?php checked( 1, get_option( 'spamjam_enable_white_label', 0 ) ); ?>
    847                                 <?php echo $disabled; ?>>
    848                             <span class="slider round"></span>
    849                         </label>
    850                         <p class="description"><?php _e( 'Remove SpamJam branding from admin interface', 'spamjam' ); ?></p>
     857                                <?php echo esc_attr( $disabled ); ?>>
     858                            <span class="slider round"></span>
     859                        </label>
     860                        <p class="description"><?php esc_html_e( 'Remove SpamJam branding from admin interface', 'spamjam' ); ?></p>
    851861                    </td>
    852862                </tr>
    853863                <tr class="dependent-field" data-depends="spamjam_enable_white_label">
    854                     <th scope="row"><?php _e( 'Custom Plugin Name', 'spamjam' ); ?></th>
     864                    <th scope="row"><?php esc_html_e( 'Custom Plugin Name', 'spamjam' ); ?></th>
    855865                    <td>
    856866                        <input type="text" name="spamjam_custom_plugin_name"
    857867                            value="<?php echo esc_attr( get_option( 'spamjam_custom_plugin_name', 'SpamJam' ) ); ?>"
    858                             class="regular-text" <?php echo $disabled; ?>>
    859                         <p class="description"><?php _e( 'Display name for the plugin (3-50 characters)', 'spamjam' ); ?></p>
     868                            class="regular-text" <?php echo esc_attr( $disabled ); ?>>
     869                        <p class="description"><?php esc_html_e( 'Display name for the plugin (3-50 characters)', 'spamjam' ); ?></p>
    860870                    </td>
    861871                </tr>
     
    868878                <h3>📊 Advanced Reporting</h3>
    869879                <span class="plan-badge agency">AGENCY</span>
    870                 <p class="section-description"><?php _e( 'Generate detailed reports and receive email summaries.', 'spamjam' ); ?></p>
    871             </div>
    872 
    873             <table class="form-table">
    874                 <tr>
    875                     <th scope="row"><?php _e( 'Enable Advanced Reporting', 'spamjam' ); ?></th>
     880                <p class="section-description"><?php esc_html_e( 'Generate detailed reports and receive email summaries.', 'spamjam' ); ?></p>
     881            </div>
     882
     883            <table class="form-table">
     884                <tr>
     885                    <th scope="row"><?php esc_html_e( 'Enable Advanced Reporting', 'spamjam' ); ?></th>
    876886                    <td>
    877887                        <label class="switch">
    878888                            <input type="checkbox" name="spamjam_enable_advanced_reporting" value="1"
    879889                                <?php checked( 1, get_option( 'spamjam_enable_advanced_reporting', 0 ) ); ?>
    880                                 <?php echo $disabled; ?>>
    881                             <span class="slider round"></span>
    882                         </label>
    883                         <p class="description"><?php _e( 'Generate PDF reports and email summaries', 'spamjam' ); ?></p>
     890                                <?php echo esc_attr( $disabled ); ?>>
     891                            <span class="slider round"></span>
     892                        </label>
     893                        <p class="description"><?php esc_html_e( 'Generate PDF reports and email summaries', 'spamjam' ); ?></p>
    884894                    </td>
    885895                </tr>
    886896                <tr class="dependent-field" data-depends="spamjam_enable_advanced_reporting">
    887                     <th scope="row"><?php _e( 'Report Email', 'spamjam' ); ?></th>
     897                    <th scope="row"><?php esc_html_e( 'Report Email', 'spamjam' ); ?></th>
    888898                    <td>
    889899                        <input type="email" name="spamjam_report_email"
    890900                            value="<?php echo esc_attr( get_option( 'spamjam_report_email', '' ) ); ?>"
    891                             class="regular-text" <?php echo $disabled; ?>
     901                            class="regular-text" <?php echo esc_attr( $disabled ); ?>
    892902                            placeholder="[email protected]">
    893                         <p class="description"><?php _e( 'Receive weekly spam reports at this email address', 'spamjam' ); ?></p>
     903                        <p class="description"><?php esc_html_e( 'Receive weekly spam reports at this email address', 'spamjam' ); ?></p>
    894904                    </td>
    895905                </tr>
     
    902912                <h3>🌐 Multisite Sync</h3>
    903913                <span class="plan-badge agency">AGENCY</span>
    904                 <p class="section-description"><?php _e( 'Synchronize settings across WordPress multisite network.', 'spamjam' ); ?></p>
    905             </div>
    906 
    907             <table class="form-table">
    908                 <tr>
    909                     <th scope="row"><?php _e( 'Enable Multisite Sync', 'spamjam' ); ?></th>
     914                <p class="section-description"><?php esc_html_e( 'Synchronize settings across WordPress multisite network.', 'spamjam' ); ?></p>
     915            </div>
     916
     917            <table class="form-table">
     918                <tr>
     919                    <th scope="row"><?php esc_html_e( 'Enable Multisite Sync', 'spamjam' ); ?></th>
    910920                    <td>
    911921                        <label class="switch">
    912922                            <input type="checkbox" name="spamjam_enable_multisite_sync" value="1"
    913923                                <?php checked( 1, get_option( 'spamjam_enable_multisite_sync', 0 ) ); ?>
    914                                 <?php echo $disabled; ?>>
    915                             <span class="slider round"></span>
    916                         </label>
    917                         <p class="description"><?php _e( 'Sync blocklists and settings across all sites in network', 'spamjam' ); ?></p>
     924                                <?php echo esc_attr( $disabled ); ?>>
     925                            <span class="slider round"></span>
     926                        </label>
     927                        <p class="description"><?php esc_html_e( 'Sync blocklists and settings across all sites in network', 'spamjam' ); ?></p>
    918928                    </td>
    919929                </tr>
  • spamjam/trunk/includes/admin.php

    r3427664 r3458129  
    115115    // Check if premium features are disabled.
    116116    $disabled = 'disabled';
    117     $is_local = in_array( $_SERVER['HTTP_HOST'] ?? '', [ 'localhost', '127.0.0.1', 'utopiqueplugins.local' ], true );
     117    $is_local = in_array( wp_parse_url( home_url(), PHP_URL_HOST ), [ 'localhost', '127.0.0.1', 'utopiqueplugins.local' ], true );
    118118
    119119    if ( $is_local || ( spamjam_fs()->is__premium_only() && spamjam_fs()->can_use_premium_code() && spamjam_fs()->is_plan__premium_only( 'pro' ) ) ) {
  • spamjam/trunk/includes/migration.php

    r3427664 r3458129  
    8686    }
    8787
     88    // Initialize WP_Filesystem.
     89    global $wp_filesystem;
     90    if ( ! function_exists( 'WP_Filesystem' ) ) {
     91        require_once ABSPATH . 'wp-admin/includes/file.php';
     92    }
     93    WP_Filesystem();
     94
     95    if ( ! $wp_filesystem ) {
     96        return;
     97    }
     98
    8899    // Read legacy file.
    89     $legacy_content = file_get_contents( $blocklist_file_path );
     100    $legacy_content = $wp_filesystem->get_contents( $blocklist_file_path );
    90101
    91102    if ( false === $legacy_content || empty( $legacy_content ) ) {
     
    95106    // Migrate to new option.
    96107    update_option( 'spamjam_premium_blocklist_data', $legacy_content );
    97     update_option( 'spamjam_premium_blocklist_last_updated', filemtime( $blocklist_file_path ) );
     108    $file_mtime = $wp_filesystem->mtime( $blocklist_file_path );
     109    update_option( 'spamjam_premium_blocklist_last_updated', $file_mtime );
    98110
    99111    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
     
    101113    }
    102114
    103     // Optionally rename the old file (don't delete in case of issues).
     115    // Optionally move the old file to a backup (don't delete in case of issues).
    104116    $backup_path = $blocklist_file_path . '.backup';
    105     if ( ! file_exists( $backup_path ) ) {
    106         rename( $blocklist_file_path, $backup_path );
     117    if ( ! $wp_filesystem->exists( $backup_path ) ) {
     118        $wp_filesystem->move( $blocklist_file_path, $backup_path );
    107119    }
    108120}
     
    118130
    119131    if ( file_exists( $backup_path ) ) {
    120         unlink( $backup_path );
     132        wp_delete_file( $backup_path );
    121133
    122134        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  • spamjam/trunk/includes/settings-schema.php

    r3427664 r3458129  
    435435    }
    436436    // Dev mode - always return agency for local development.
    437     $is_local = in_array( $_SERVER['HTTP_HOST'] ?? '', ['localhost', '127.0.0.1', 'utopiqueplugins.local'], true );
     437    $is_local = in_array( wp_parse_url( home_url(), PHP_URL_HOST ), ['localhost', '127.0.0.1', 'utopiqueplugins.local'], true );
    438438    if ( $is_local ) {
    439439        $plan = 'agency';
  • spamjam/trunk/readme.txt

    r3428403 r3458129  
    66Tested up to: 6.9
    77Requires PHP: 7.4
    8 Stable tag: 1.0.7
     8Stable tag: 1.1.0
     9WC requires at least: 5.3
     10WC tested up to: 10.5
     11WP requires at least: 6.2
     12WP tested up to: 6.9
    913License: GPLv3 or later
    1014
     
    167171== Changelog ==
    168172
     173= 1.1.0 - 2025-02-10 =
     174* Security - Fixed SQL injection risk: all queries now use $wpdb->prepare()
     175* Security - Fixed email confirmation auth flaw with persistent hashed token
     176* Security - Fixed premium plan bypass via HTTP Host header spoofing
     177* Security - Sanitized all $_SERVER['REMOTE_ADDR'] via centralized helper
     178* Security - Added wp_unslash() to all raw $_POST and nonce verifications
     179* Security - Escaped all admin notice output in multisite sync
     180* WP VIP - Replaced file_get_contents/rename/unlink with WP_Filesystem API
     181* WPCS - Replaced all _e() with esc_html_e() in admin templates
     182* WPCS - Escaped $disabled output with esc_attr()
     183* WPCS - Replaced date() with gmdate(), deprecated current_time('timestamp') with time()
     184* Enhancement - Added WooCommerce product_instance_caching and cart_checkout_blocks compatibility
     185
    169186= 1.0.7 - 2025-12-27 =
    170187* Fixed - Field swap hook changed from pre_comment_on_post to init for better compatibility
     
    188205== Upgrade Notice ==
    189206
    190 = 1.0.3 =
    191 Major milestone release! Performance improvements, PHP 7.4+ requirement, updated Freemius SDK, and proper cleanup on deactivation. Recommended update for all users.
     207= 1.1.0 =
     208Security hardening release. Fixes SQL injection vectors, email confirmation auth flaw, premium bypass vulnerability, and unsanitized input handling. All users should update immediately.
  • spamjam/trunk/spamjam.php

    r3428403 r3458129  
    55 * Plugin URI: https://utopique.net/products/spamjam/
    66 * Description: SpamJam silently kills spam in comments and registration.
    7  * Version: 1.0.7
     7 * Version: 1.1.0
    88 * Author: Utopique
    99 * Author URI: https://utopique.net/
    10  * Copyright: 2022-2025 Utopique
     10 * Copyright: 2022-2026 Utopique
    1111 * Text Domain: spamjam
    1212 * License: GPLv2 or later
     
    1515 * Requires PHP: 7.4
    1616 * WC requires at least: 5.3
    17  * WC tested up to: 10.4
     17 * WC tested up to: 10.5
     18 * WP requires at least: 6.2
     19 * WP tested up to: 6.9
    1820 * PHP version 7.4+
    1921 *
     
    8587    add_action( 'plugins_loaded', __NAMESPACE__ . '\\load_textdomain' );
    8688    /**
     89     * Get the sanitized and validated client IP address.
     90     *
     91     * @return string Validated IP address or empty string if invalid.
     92     */
     93    function get_client_ip() {
     94        $ip = ( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '' );
     95        if ( !empty( $ip ) && !filter_var( $ip, FILTER_VALIDATE_IP ) ) {
     96            return '';
     97        }
     98        return $ip;
     99    }
     100
     101    /**
    87102     * Block direct requests to wp-comments-post.php by checking the referrer URL.
    88103     *
     
    262277        */
    263278        // Honeypot technique: check if a hidden field has been filled out.
    264         if ( !empty( $_POST['email_confirm'] ) ) {
     279        if ( !empty( wp_unslash( $_POST['email_confirm'] ) ) ) {
     280            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- only checking emptiness
    265281            $error_messages[] = __( 'Honeypot field should be empty.', 'spamjam' );
    266282        }
     
    322338        // Only run on comment submission.
    323339        if ( !isset( $_POST['comment_post_ID'] ) ) {
     340            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- only checking existence
    324341            return;
    325342        }
    326343        // Debug: Log what we're receiving (only if WP_DEBUG is enabled).
    327344        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
    328             error_log( 'SpamJam Field Swap - POST comment: ' . (( isset( $_POST['comment'] ) ? $_POST['comment'] : 'NOT SET' )) );
    329             error_log( 'SpamJam Field Swap - POST sj-comment: ' . (( isset( $_POST['sj-comment'] ) ? $_POST['sj-comment'] : 'NOT SET' )) );
     345            error_log( 'SpamJam Field Swap - POST comment: ' . (( isset( $_POST['comment'] ) ? sanitize_text_field( wp_unslash( $_POST['comment'] ) ) : 'NOT SET' )) );
     346            error_log( 'SpamJam Field Swap - POST sj-comment: ' . (( isset( $_POST['sj-comment'] ) ? sanitize_text_field( wp_unslash( $_POST['sj-comment'] ) ) : 'NOT SET' )) );
    330347            error_log( 'SpamJam Field Swap - POST nonce: ' . (( isset( $_POST['spamjam_comment_nonce'] ) ? 'SET' : 'NOT SET' )) );
    331348        }
     
    360377        if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
    361378            \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
     379            \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'product_instance_caching', __FILE__, true );
     380            \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', __FILE__, true );
    362381        }
    363382    } );
  • spamjam/trunk/vendor/composer/installed.php

    r3427664 r3458129  
    44        'pretty_version' => 'dev-master',
    55        'version' => 'dev-master',
    6         'reference' => 'a307848b132e037ca2717f4ca7f613e434109820',
     6        'reference' => 'c5c12c0aeffacbb8305b8b6e546975f783150dd5',
    77        'type' => 'library',
    88        'install_path' => __DIR__ . '/../../',
     
    1414            'pretty_version' => 'dev-master',
    1515            'version' => 'dev-master',
    16             'reference' => 'a307848b132e037ca2717f4ca7f613e434109820',
     16            'reference' => 'c5c12c0aeffacbb8305b8b6e546975f783150dd5',
    1717            'type' => 'library',
    1818            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.