[wp-trac] [WordPress Trac] #55659: User without post lock can overwrite changes of user with lock via autosave
WordPress Trac
noreply at wordpress.org
Mon Jul 18 22:22:46 UTC 2022
#55659: User without post lock can overwrite changes of user with lock via autosave
--------------------------------------+------------------------------
Reporter: jhart35 | Owner: adamsilverstein
Type: defect (bug) | Status: assigned
Priority: normal | Milestone: 6.1
Component: Autosave | Version: 5.9.3
Severity: normal | Resolution:
Keywords: has-patch has-unit-tests | Focuses: rest-api
--------------------------------------+------------------------------
Comment (by primetimejas):
I was able to replicate the issue and verify that the fix works. The PR
was created to add onto what @sathyapulse contributed. I the meantime we
are using a fix like this:
{{{#!php
<?php
/**
* Fix autosave updates issue.
*
* @see https://core.trac.wordpress.org/ticket/55659
*
*
* @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response
Result to send to the client.
*
Usually a WP_REST_Response or WP_Error.
* @param array $handler Route
handler used for the request.
* @param WP_REST_Request $request
Request used to generate the response.
*
* @return mixed|\WP_Error
*/
function fix_autosave_post_updates( $response, $handler, $request ) {
// Check for the response ID.
if ( empty( $request['id'] ) ) {
return $response;
}
// Ensure we have a valid post.
$post = get_post( $request['id'] );
if ( is_wp_error( $post ) ) {
return $response;
}
// Check that we are in the correct context.
if ( 'POST' !== $request->get_method() ) {
return $response;
}
// Ensure this request is coming from the autosaves route.
$autosave_route = '/wp/v2/' . get_post_type( $post ) . '/' .
$post->ID . '/autosaves';
if ( $autosave_route !== $request->get_route() ) {
return $response;
}
// The wp_check_post_lock function does not exist until we include
it.
if ( ! function_exists( 'wp_check_post_lock' ) ) {
require_once( ABSPATH . 'wp-
admin/includes/post.php' );
}
$user_id = get_current_user_id();
/**
* If this is draft, the post author is the current user and the
post is locked then return an error, stopping autosave.
* Note: Only the original author can autosave, this is defined in
class-wp-rest-autosaves.controller.php
*
* wp_check_post_lock() will return false if the post is locked to
the current user, so if it is locked to the current user we can continue
with autosaving.
*
* So in a scenario where the post has been taken over by another
user "User B" but the original author left their browser tab open:
* wp_check_post_lock() would return false for "User B" that
has taken over the post since the post is not locked for them.
* wp_check_post_lock() would return the user ID of "User B"
for the original author since the post is locked to "User B".
*
* Our issue happens because core does not check post lock and the
original author's browser tab initiates an autosave, overwriting changes
from "User B".
*/
if ( ( 'draft' === $post->post_status || 'auto-draft' ===
$post->post_status ) && (int) $post->post_author === (int) $user_id &&
false !== wp_check_post_lock( $post->ID ) ) {
return new WP_Error(
'rest_forbidden',
'Sorry, you are not allowed to
update the post with autosave since it is locked by another user.',
array( 'status' => 400 )
);
}
return $response;
}
add_filter( 'rest_request_before_callbacks', 'fix_autosave_post_updates',
10, 3 );
}}}
--
Ticket URL: <https://core.trac.wordpress.org/ticket/55659#comment:6>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list