mirror of
git://develop.git.wordpress.org/
synced 2025-04-14 17:12:13 +02:00
Plugins: Move capability checks further up in wp_ajax_update_plugin()
and wp_ajax_delete_plugin()
.
Add tests for both Ajax handlers. Props Yorick Koster, swissspidy. Fixes #37490. git-svn-id: https://develop.svn.wordpress.org/trunk@38168 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
d097c1d916
commit
af6b1a5388
@ -3653,28 +3653,29 @@ function wp_ajax_update_plugin() {
|
||||
) );
|
||||
}
|
||||
|
||||
$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
|
||||
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
||||
$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
|
||||
|
||||
$status = array(
|
||||
'update' => 'plugin',
|
||||
'plugin' => $plugin,
|
||||
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
|
||||
'pluginName' => $plugin_data['Name'],
|
||||
'oldVersion' => '',
|
||||
'newVersion' => '',
|
||||
);
|
||||
|
||||
if ( ! current_user_can( 'update_plugins' ) || 0 !== validate_file( $plugin ) ) {
|
||||
$status['errorMessage'] = __( 'Sorry, you are not allowed to update plugins for this site.' );
|
||||
wp_send_json_error( $status );
|
||||
}
|
||||
|
||||
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
||||
$status['plugin'] = $plugin;
|
||||
$status['pluginName'] = $plugin_data['Name'];
|
||||
|
||||
if ( $plugin_data['Version'] ) {
|
||||
/* translators: %s: Plugin version */
|
||||
$status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'update_plugins' ) ) {
|
||||
$status['errorMessage'] = __( 'Sorry, you are not allowed to update plugins for this site.' );
|
||||
wp_send_json_error( $status );
|
||||
}
|
||||
|
||||
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
||||
|
||||
wp_update_plugins();
|
||||
@ -3748,24 +3749,29 @@ function wp_ajax_delete_plugin() {
|
||||
check_ajax_referer( 'updates' );
|
||||
|
||||
if ( empty( $_POST['slug'] ) || empty( $_POST['plugin'] ) ) {
|
||||
wp_send_json_error( array( 'errorCode' => 'no_plugin_specified' ) );
|
||||
wp_send_json_error( array(
|
||||
'slug' => '',
|
||||
'errorCode' => 'no_plugin_specified',
|
||||
'errorMessage' => __( 'No plugin specified.' ),
|
||||
) );
|
||||
}
|
||||
|
||||
$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
|
||||
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
||||
$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
|
||||
|
||||
$status = array(
|
||||
'delete' => 'plugin',
|
||||
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
|
||||
'plugin' => $plugin,
|
||||
'pluginName' => $plugin_data['Name'],
|
||||
'delete' => 'plugin',
|
||||
'slug' => sanitize_key( wp_unslash( $_POST['slug'] ) ),
|
||||
);
|
||||
|
||||
if ( ! current_user_can( 'delete_plugins' ) ) {
|
||||
if ( ! current_user_can( 'delete_plugins' ) || 0 !== validate_file( $plugin ) ) {
|
||||
$status['errorMessage'] = __( 'Sorry, you are not allowed to delete plugins for this site.' );
|
||||
wp_send_json_error( $status );
|
||||
}
|
||||
|
||||
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
||||
$status['plugin'] = $plugin;
|
||||
$status['pluginName'] = $plugin_data['Name'];
|
||||
|
||||
if ( is_plugin_active( $plugin ) ) {
|
||||
$status['errorMessage'] = __( 'You cannot delete a plugin while it is active on the main site.' );
|
||||
wp_send_json_error( $status );
|
||||
|
@ -447,7 +447,11 @@
|
||||
errorMessage = wp.updates.l10n.updateFailed.replace( '%s', response.errorMessage );
|
||||
|
||||
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
|
||||
$message = $( 'tr[data-plugin="' + response.plugin + '"]' ).find( '.update-message' );
|
||||
if ( response.plugin ) {
|
||||
$message = $( 'tr[data-plugin="' + response.plugin + '"]' ).find( '.update-message' );
|
||||
} else {
|
||||
$message = $( 'tr[data-slug="' + response.slug + '"]' ).find( '.update-message' );
|
||||
}
|
||||
$message.removeClass( 'updating-message notice-warning' ).addClass( 'notice-error' ).find( 'p' ).html( errorMessage );
|
||||
} else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
|
||||
$card = $( '.plugin-card-' + response.slug )
|
||||
@ -458,9 +462,13 @@
|
||||
} ) );
|
||||
|
||||
$card.find( '.update-now' )
|
||||
.attr( 'aria-label', wp.updates.l10n.updateFailedLabel.replace( '%s', response.pluginName ) )
|
||||
.text( wp.updates.l10n.updateFailedShort ).removeClass( 'updating-message' );
|
||||
|
||||
if ( response.pluginName ) {
|
||||
$card.find( '.update-now' )
|
||||
.attr( 'aria-label', wp.updates.l10n.updateFailedLabel.replace( '%s', response.pluginName ) );
|
||||
}
|
||||
|
||||
$card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() {
|
||||
|
||||
// Use same delay as the total duration of the notice fadeTo + slideUp animation.
|
||||
@ -814,14 +822,21 @@
|
||||
* @param {string} response.errorMessage The error that occurred.
|
||||
*/
|
||||
wp.updates.deletePluginError = function( response ) {
|
||||
var $plugin = $( 'tr.inactive[data-plugin="' + response.plugin + '"]' ),
|
||||
var $plugin, $pluginUpdateRow,
|
||||
pluginUpdateRow = wp.template( 'item-update-row' ),
|
||||
$pluginUpdateRow = $plugin.siblings( '[data-plugin="' + response.plugin + '"]' ),
|
||||
noticeContent = wp.updates.adminNotice( {
|
||||
className: 'update-message notice-error notice-alt',
|
||||
message: response.errorMessage
|
||||
} );
|
||||
|
||||
if ( response.plugin ) {
|
||||
$plugin = $( 'tr.inactive[data-plugin="' + response.plugin + '"]' );
|
||||
$pluginUpdateRow = $plugin.siblings( '[data-plugin="' + response.plugin + '"]' );
|
||||
} else {
|
||||
$plugin = $( 'tr.inactive[data-slug="' + response.slug + '"]' );
|
||||
$pluginUpdateRow = $plugin.siblings( '[data-slug="' + response.slug + '"]' );
|
||||
}
|
||||
|
||||
if ( ! wp.updates.isValidResponse( response, 'delete' ) ) {
|
||||
return;
|
||||
}
|
||||
@ -835,7 +850,7 @@
|
||||
$plugin.addClass( 'update' ).after(
|
||||
pluginUpdateRow( {
|
||||
slug: response.slug,
|
||||
plugin: response.plugin,
|
||||
plugin: response.plugin || response.slug,
|
||||
colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
|
||||
content: noticeContent
|
||||
} )
|
||||
|
@ -18,13 +18,13 @@ abstract class WP_Ajax_UnitTestCase extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Last AJAX response. This is set via echo -or- wp_die.
|
||||
* @var type
|
||||
* @var string
|
||||
*/
|
||||
protected $_last_response = '';
|
||||
|
||||
/**
|
||||
* List of ajax actions called via POST
|
||||
* @var type
|
||||
* @var array
|
||||
*/
|
||||
protected static $_core_actions_get = array(
|
||||
'fetch-list', 'ajax-tag-search', 'wp-compression-test', 'imgedit-preview', 'oembed-cache',
|
||||
@ -39,7 +39,7 @@ abstract class WP_Ajax_UnitTestCase extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* List of ajax actions called via GET
|
||||
* @var type
|
||||
* @var array
|
||||
*/
|
||||
protected static $_core_actions_post = array(
|
||||
'oembed_cache', 'image-editor', 'delete-comment', 'delete-tag', 'delete-link',
|
||||
@ -53,7 +53,9 @@ abstract class WP_Ajax_UnitTestCase extends WP_UnitTestCase {
|
||||
'wp-remove-post-lock', 'dismiss-wp-pointer', 'send-attachment-to-editor', 'heartbeat', 'nopriv_heartbeat', 'get-revision-diffs',
|
||||
'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail',
|
||||
'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post',
|
||||
'press-this-add-category', 'crop-image', 'generate-password',
|
||||
'press-this-add-category', 'crop-image', 'generate-password', 'save-wporg-username', 'delete-plugin',
|
||||
'search-plugins', 'search-install-plugins', 'activate-plugin', 'update-theme', 'delete-theme',
|
||||
'install-theme', 'get-post-thumbnail-html',
|
||||
);
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
|
158
tests/phpunit/tests/ajax/DeletePlugin.php
Normal file
158
tests/phpunit/tests/ajax/DeletePlugin.php
Normal file
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin ajax functions to be tested
|
||||
*/
|
||||
require_once( ABSPATH . 'wp-admin/includes/ajax-actions.php' );
|
||||
|
||||
/**
|
||||
* Testing Ajax handler for deleting a plugin.
|
||||
*
|
||||
* @group ajax
|
||||
*/
|
||||
class Tests_Ajax_Delete_Plugin extends WP_Ajax_UnitTestCase {
|
||||
/**
|
||||
* @expectedException WPAjaxDieStopException
|
||||
* @expectedExceptionMessage -1
|
||||
*/
|
||||
public function test_missing_nonce() {
|
||||
$this->_handleAjax( 'delete-plugin' );
|
||||
}
|
||||
|
||||
public function test_missing_plugin() {
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'delete-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'slug' => '',
|
||||
'errorCode' => 'no_plugin_specified',
|
||||
'errorMessage' => 'No plugin specified.',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_missing_slug() {
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = 'foo/bar.php';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'delete-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'slug' => '',
|
||||
'errorCode' => 'no_plugin_specified',
|
||||
'errorMessage' => 'No plugin specified.',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_missing_capability() {
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = 'foo/bar.php';
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'delete-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'delete' => 'plugin',
|
||||
'slug' => 'foo',
|
||||
'errorMessage' => 'Sorry, you are not allowed to delete plugins for this site.',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_invalid_file() {
|
||||
$this->_setRole( 'administrator' );
|
||||
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = '../foo/bar.php';
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'delete-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'delete' => 'plugin',
|
||||
'slug' => 'foo',
|
||||
'errorMessage' => 'Sorry, you are not allowed to delete plugins for this site.',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_delete_plugin() {
|
||||
$this->_setRole( 'administrator' );
|
||||
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = 'foo.php';
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'delete-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => true,
|
||||
'data' => array(
|
||||
'delete' => 'plugin',
|
||||
'slug' => 'foo',
|
||||
'plugin' => 'foo.php',
|
||||
'pluginName' => '',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
}
|
169
tests/phpunit/tests/ajax/UpdatePlugin.php
Normal file
169
tests/phpunit/tests/ajax/UpdatePlugin.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin ajax functions to be tested
|
||||
*/
|
||||
require_once( ABSPATH . 'wp-admin/includes/ajax-actions.php' );
|
||||
|
||||
/**
|
||||
* Testing Ajax handler for updating a plugin.
|
||||
*
|
||||
* @group ajax
|
||||
*/
|
||||
class Tests_Ajax_Update_Plugin extends WP_Ajax_UnitTestCase {
|
||||
/**
|
||||
* @expectedException WPAjaxDieStopException
|
||||
* @expectedExceptionMessage -1
|
||||
*/
|
||||
public function test_missing_nonce() {
|
||||
$this->_handleAjax( 'update-plugin' );
|
||||
}
|
||||
|
||||
public function test_missing_plugin() {
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'update-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'slug' => '',
|
||||
'errorCode' => 'no_plugin_specified',
|
||||
'errorMessage' => 'No plugin specified.',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_missing_slug() {
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = 'foo/bar.php';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'update-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'slug' => '',
|
||||
'errorCode' => 'no_plugin_specified',
|
||||
'errorMessage' => 'No plugin specified.',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_missing_capability() {
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = 'foo/bar.php';
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'update-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'update' => 'plugin',
|
||||
'slug' => 'foo',
|
||||
'errorMessage' => 'Sorry, you are not allowed to update plugins for this site.',
|
||||
'oldVersion' => '',
|
||||
'newVersion' => '',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_invalid_file() {
|
||||
$this->_setRole( 'administrator' );
|
||||
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = '../foo/bar.php';
|
||||
$_POST['slug'] = 'foo';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
$this->_handleAjax( 'update-plugin' );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'update' => 'plugin',
|
||||
'slug' => 'foo',
|
||||
'errorMessage' => 'Sorry, you are not allowed to update plugins for this site.',
|
||||
'oldVersion' => '',
|
||||
'newVersion' => '',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
|
||||
public function test_update_plugin() {
|
||||
$this->_setRole( 'administrator' );
|
||||
|
||||
$_POST['_ajax_nonce'] = wp_create_nonce( 'updates' );
|
||||
$_POST['plugin'] = 'hello.php';
|
||||
$_POST['slug'] = 'hello-dolly';
|
||||
|
||||
// Make the request
|
||||
try {
|
||||
// Prevent wp_update_plugins() from running
|
||||
wp_installing( true );
|
||||
$this->_handleAjax( 'update-plugin' );
|
||||
wp_installing( false );
|
||||
} catch ( WPAjaxDieContinueException $e ) {
|
||||
unset( $e );
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = json_decode( $this->_last_response, true );
|
||||
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
'data' => array(
|
||||
'update' => 'plugin',
|
||||
'slug' => 'hello-dolly',
|
||||
'plugin' => 'hello.php',
|
||||
'pluginName' => 'Hello Dolly',
|
||||
'errorMessage' => 'Plugin update failed.',
|
||||
'oldVersion' => 'Version 1.6',
|
||||
'newVersion' => '',
|
||||
'debug' => array( 'The plugin is at the latest version.' ),
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqualSets( $expected, $response );
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user