Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
<exclude name="Generic.Commenting" />
<exclude name="Squiz.PHP.CommentedOutCode.Found" />

<!-- Fix security issues -->
<exclude name="WordPress.Security.NonceVerification" />

<!-- Fix AlternativeFunctons-->
<exclude name="WordPress.WP.AlternativeFunctions" />
<exclude name="WordPress.WP.GlobalVariablesOverride.Prohibited" />
Expand Down
30 changes: 0 additions & 30 deletions src/class-tiny-helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,36 +111,6 @@ public static function get_mimetype( $input ) {
}


/**
* Checks wether a user is viewing from a page builder
*
* @since 3.6.5
*/
public static function is_pagebuilder_request() {
$pagebuilder_keys = array(
'fl_builder', // Beaver Builder
'et_fb', // Divi Builder
'bricks', // Bricks Builder
'breakdance', // Breakdance Builder
'breakdance_browser', // Breakdance Builder
'ct_builder', // Oxygen Builder
'fb-edit', // Avada Live Builder
'builder', // Avada Live Builder
'spio_no_cdn', // Site Origin
'tatsu', // Tatsu Builder
'tve', // Thrive Architect
'tcbf', // Thrive Architect
);

foreach ( $pagebuilder_keys as $key ) {
if ( isset( $_GET[ $key ] ) ) {
return true;
}
}

return false;
}

/**
* Gets or initializes the WordPress filesystem instance.
*
Expand Down
2 changes: 1 addition & 1 deletion src/class-tiny-notices.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public function remove( $name ) {
}

public function dismiss() {
if ( empty( $_POST['name'] ) || ! $this->check_ajax_referer() ) {
if ( ! check_ajax_referer( 'tiny-compress', '_nonce', false ) || empty( $_POST['name'] ) ) {
echo json_encode( false );
exit();
}
Expand Down
51 changes: 50 additions & 1 deletion src/class-tiny-picture.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,62 @@ public function __construct( $settings, $base_dir = ABSPATH, $domains = array()
return;
}

if ( Tiny_Helpers::is_pagebuilder_request() ) {
if ( static::is_pagebuilder_request() ) {
return;
}

add_action( 'template_redirect', array( $this, 'on_template_redirect' ) );
}

/**
* Checks whether the current request originates from a page builder.
*
* Detects known page builder query parameters to prevent picture-element
* injection from interfering with builder previews.
*
* @since 3.6.5
*
* @return bool True if a page builder query parameter is present.
*/
protected static function is_pagebuilder_request() {
$pagebuilder_keys = array(
'fl_builder', // Beaver Builder
'et_fb', // Divi Builder
'bricks', // Bricks Builder
'breakdance', // Breakdance Builder
'breakdance_browser', // Breakdance Builder
'ct_builder', // Oxygen Builder
'fb-edit', // Avada Live Builder
'builder', // Avada Live Builder
'spio_no_cdn', // Site Origin
'tatsu', // Tatsu Builder
'tve', // Thrive Architect
'tcbf', // Thrive Architect
);

foreach ( $pagebuilder_keys as $key ) {
if ( static::has_get_var( $key ) ) {
return true;
}
}

return false;
}

/**
* Checks whether a GET variable exists in the original request.
*
* Wraps filter_has_var() to allow overriding in tests via late static binding.
*
* @since 3.6.5
*
* @param string $key The query string key to check.
* @return bool True if the key exists in the original GET request.
*/
protected static function has_get_var( $key ) {
return filter_has_var( INPUT_GET, $key );
}

public function on_template_redirect() {
$conversion_enabled = $this->settings->get_conversion_enabled();
if ( apply_filters( 'tiny_replace_with_picture', $conversion_enabled ) ) {
Expand Down
33 changes: 27 additions & 6 deletions src/class-tiny-plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -517,9 +517,8 @@ public function compress_on_upload() {
* or success array ['data' => [$id, $metadata]]
*/
private function validate_ajax_attachment_request() {
if ( ! $this->check_ajax_referer() ) {
exit();
}
check_ajax_referer( 'tiny-compress', '_nonce' );

if ( ! current_user_can( 'upload_files' ) ) {
return array(
'error' => esc_html__(
Expand Down Expand Up @@ -614,11 +613,14 @@ public function compress_image_for_bulk() {
);
wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() );

// Nonce verified in validate_ajax_attachment_request().
// phpcs:disable WordPress.Security.NonceVerification.Missing
$current_library_size = isset( $_POST['current_size'] ) ?
intval( wp_unslash( $_POST['current_size'] ) )
: 0;
$size_after = $image_statistics['compressed_total_size'];
$new_library_size = $current_library_size + $size_after - $size_before;
// phpcs:enable WordPress.Security.NonceVerification.Missing
$size_after = $image_statistics['compressed_total_size'];
$new_library_size = $current_library_size + $size_after - $size_before;

$result['message'] = $tiny_image->get_latest_error();
$result['image_sizes_compressed'] = $image_statistics['image_sizes_compressed'];
Expand Down Expand Up @@ -655,7 +657,8 @@ public function compress_image_for_bulk() {
}

public function ajax_optimization_statistics() {
if ( $this->check_ajax_referer() && current_user_can( 'upload_files' ) ) {
if ( check_ajax_referer( 'tiny-compress', '_nonce', false ) &&
current_user_can( 'upload_files' ) ) {
$stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings );
echo json_encode( $stats );
}
Expand Down Expand Up @@ -703,6 +706,7 @@ public function media_library_bulk_action() {
$location = 'upload.php?mode=list&ids=' . $ids;

$location = add_query_arg( 'action', $action, $location );
$location = add_query_arg( '_tiny_nonce', wp_create_nonce( 'tiny-bulk-ids' ), $location );

if ( ! empty( $_REQUEST['paged'] ) ) {
$location = add_query_arg( 'paged', absint( $_REQUEST['paged'] ), $location );
Expand Down Expand Up @@ -758,6 +762,23 @@ public function show_media_info() {
}

private function render_compress_details( $tiny_image ) {
$images_to_compress = array();

if ( ! empty( $_REQUEST['ids'] ) ) {
if (
! isset( $_REQUEST['_tiny_nonce'] ) ||
! wp_verify_nonce(
sanitize_key( wp_unslash( $_REQUEST['_tiny_nonce'] ) ),
'tiny-bulk-ids'
)
) {
return;
}

$request_ids = sanitize_text_field( wp_unslash( $_REQUEST['ids'] ) );
$images_to_compress = array_map( 'intval', explode( '-', $request_ids ) );
}

$in_progress = $tiny_image->filter_image_sizes( 'in_progress' );
if ( count( $in_progress ) > 0 ) {
include __DIR__ . '/views/compress-details-processing.php';
Expand Down
11 changes: 5 additions & 6 deletions src/class-tiny-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ public function add_options_to_page() {
}

public function image_sizes_notice() {
check_ajax_referer( 'tiny-compress' );

if ( current_user_can( 'manage_options' ) ) {
$selected_sizes = isset( $_GET['image_sizes_selected'] ) ?
intval( $_GET['image_sizes_selected'] ) : 0;
Expand Down Expand Up @@ -827,9 +829,8 @@ public function render_pending_status() {
}

public function create_api_key() {
if ( ! $this->check_ajax_referer() ) {
exit;
}
check_ajax_referer( 'tiny-compress', '_nonce' );

$compressor = $this->get_compressor();
if ( ! current_user_can( 'manage_options' ) ) {
$status = (object) array(
Expand Down Expand Up @@ -905,9 +906,7 @@ public function create_api_key() {
}

public function update_api_key() {
if ( ! $this->check_ajax_referer() ) {
exit;
}
check_ajax_referer( 'tiny-compress', '_nonce' );

$key = null;
if ( ! current_user_can( 'manage_options' ) ) {
Expand Down
4 changes: 0 additions & 4 deletions src/class-tiny-wp-base.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ protected function get_user_id() {
return get_current_user_id();
}

protected function check_ajax_referer() {
return check_ajax_referer( 'tiny-compress', '_nonce', false );
}

public function init() {
}

Expand Down
41 changes: 22 additions & 19 deletions src/js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@
eventOn('click', 'button.tiny-mark-as-compressed', onClickButtonMarkAsCompressed);

setPropOf('button.tiny-compress', 'disabled', null);

compressImageSelection();
watchCompressingImages();

Expand Down Expand Up @@ -329,29 +328,33 @@
});
}

eventOn('click', 'input[name*=tinypng_sizes], #tinypng_resize_original_enabled', function() {
/* Unfortunately, we need some additional information to display
the correct notice. */
var totalSelectedSizes = jQuery('input[name*=tinypng_sizes]:checked').length;
var compressWr2x = propOf('#tinypng_sizes_wr2x', 'checked');
if (compressWr2x) {
totalSelectedSizes--;
}
async function refreshSizeDescriptionNotice() {
const totalSelectedSizes = document.querySelectorAll('input[name*=tinypng_sizes]:checked').length;
const compressWr2x = document.querySelector('#tinypng_sizes_wr2x')?.checked ?? false;
const selectedCount = compressWr2x ? totalSelectedSizes - 1 : totalSelectedSizes;

var image_count_url = ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_image_sizes_notice&image_sizes_selected=' + totalSelectedSizes;
if (propOf('#tinypng_resize_original_enabled', 'checked') && propOf('#tinypng_sizes_0', 'checked')) {
image_count_url += '&resize_original=true';
const separator = ajaxurl.includes('?') ? '&' : '?';
let imageCountUrl = `${ajaxurl}${separator}action=tiny_image_sizes_notice&image_sizes_selected=${selectedCount}&_ajax_nonce=${tinyCompress.nonce}`;

const resizeOriginalChecked = document.querySelector('#tinypng_resize_original_enabled')?.checked;
const compressOriginalChecked = document.querySelector('#tinypng_sizes_0')?.checked;
if (resizeOriginalChecked && compressOriginalChecked) {
imageCountUrl += '&resize_original=true';
}
if (compressWr2x) {
image_count_url += '&compress_wr2x=true';
imageCountUrl += '&compress_wr2x=true';
}
jQuery('#tiny-image-sizes-notice').load(image_count_url);
});

eventOn('click', '#tinypng_auto_compress_enabled', function() {
updateSettings();
});
try {
const sizeDescriptionHtml = await fetch(imageCountUrl).then(r => r.text());
document.querySelector('#tiny-image-sizes-notice').innerHTML = sizeDescriptionHtml;
} catch (err) {
document.querySelector('#tiny-image-sizes-notice').innerHTML = '';
console.error(err);
}
}

eventOn('click', 'input[name*=tinypng_sizes], #tinypng_resize_original_enabled', refreshSizeDescriptionNotice);
eventOn('click', '#tinypng_auto_compress_enabled', updateSettings);
jQuery('#tinypng_sizes_0, #tinypng_resize_original_enabled').click(updateSettings);
updateSettings();
}
Expand Down
10 changes: 3 additions & 7 deletions src/views/compress-details.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
/**
* Compression details on media overview page.
*
* @var Tiny_Plugin $this The plugin instance.
* @var Tiny_Image $tiny_image The image being compressed.
* @var Tiny_Plugin $this The plugin instance.
* @var Tiny_Image $tiny_image The image being compressed.
* @var int[] $images_to_compress The IDs that are being compressed
*/

$available_sizes = array_keys( $this->settings->get_sizes() );
Expand All @@ -22,11 +23,6 @@
$size_exists = array_fill_keys( $available_sizes, true );
ksort( $size_exists );

$images_to_compress = array();
if ( ! empty( $_REQUEST['ids'] ) ) {
$request_ids = sanitize_text_field( wp_unslash( $_REQUEST['ids'] ) );
$images_to_compress = array_map( 'intval', explode( '-', $request_ids ) );
}
?>
<div class="details-container">
<div class="details">
Expand Down
20 changes: 0 additions & 20 deletions test/unit/TinyHelpersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,26 +111,6 @@ public function test_uppercase_extension_and_mimetype_case_insensitive()
$this->assertEquals($expected, Tiny_Helpers::replace_file_extension('image/avif', $input));
}

public function test_is_pagebuilder_request_returns_false_when_no_pagebuilder_keys()
{
$_GET = array();
$this->assertFalse(Tiny_Helpers::is_pagebuilder_request());
}

public function test_is_pagebuilder_request_returns_true_for_beaver_builder()
{
$_GET = array('fl_builder' => '1');
$this->assertTrue(Tiny_Helpers::is_pagebuilder_request());
$_GET = array();
}

public function test_is_pagebuilder_request_returns_false_for_non_pagebuilder_keys()
{
$_GET = array('page' => 'settings', 'post_id' => '123');
$this->assertFalse(Tiny_Helpers::is_pagebuilder_request());
$_GET = array();
}

public function test_str_starts_with_returns_true_when_haystack_starts_with_needle()
{
$this->assertTrue(Tiny_Helpers::str_starts_with('hello world', 'hello'));
Expand Down
15 changes: 14 additions & 1 deletion test/unit/TinyPictureTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

require_once dirname(__FILE__) . '/TinyTestCase.php';

class Tiny_Picture_Overrides extends Tiny_Picture {
/**
* filter_has_var looks for immutable $_GET
* so unit tests cannot set the $_GET.
*
* isset( $_GET ) is similar to filter_has_var
* but allows us to mutate.
*/
protected static function has_get_var( $key ) {
return isset( $_GET[ $key ] );
}
}

class Tiny_Picture_Test extends Tiny_TestCase
{

Expand Down Expand Up @@ -337,7 +350,7 @@ public function test_does_not_register_hooks_when_pagebuilder_request()
});

$settings = new Tiny_Settings();
$tiny_picture = new Tiny_Picture($settings, $this->vfs->url(), array('https://www.tinifytest.com'));
$tiny_picture = new Tiny_Picture_Overrides($settings, $this->vfs->url(), array('https://www.tinifytest.com'));

$template_redirect_registered = false;
foreach ($this->wp->getCalls('add_action') as $call) {
Expand Down
Loading