Index: /trunk/wp-admin/includes/ajax-actions.php =================================================================== --- /trunk/wp-admin/includes/ajax-actions.php (revision 23031) +++ /trunk/wp-admin/includes/ajax-actions.php (revision 23032) @@ -1813,5 +1813,11 @@ wp_send_json_error(); - if ( ! current_user_can( 'read_post', $id ) ) + if ( ! $post = get_post( $id ) ) + wp_send_json_error(); + + if ( 'attachment' != $post->post_type ) + wp_send_json_error(); + + if ( ! current_user_can( 'upload_files' ) ) wp_send_json_error(); @@ -1828,4 +1834,7 @@ */ function wp_ajax_query_attachments() { + if ( ! current_user_can( 'upload_files' ) ) + wp_send_json_error(); + $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array(); $query = array_intersect_key( $query, array_flip( array( @@ -1989,13 +1998,12 @@ wp_send_json_error(); - if ( ! current_user_can( 'edit_post', $id ) ) - wp_send_json_error(); - if ( 'attachment' != $post->post_type ) wp_send_json_error(); - // If this attachment is unattached, attach it. Primarily a back compat thing. - if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) { - wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) ); + if ( current_user_can( 'edit_post', $id ) ) { + // If this attachment is unattached, attach it. Primarily a back compat thing. + if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) { + wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) ); + } } Index: /trunk/wp-includes/css/media-views.css =================================================================== --- /trunk/wp-includes/css/media-views.css (revision 23031) +++ /trunk/wp-includes/css/media-views.css (revision 23032) @@ -62,4 +62,11 @@ } +.media-frame input:disabled, +.media-frame textarea:disabled, +.media-frame input[readonly], +.media-frame textarea[readonly] { + background-color: #eee; +} + .media-frame input[type="search"] { -webkit-appearance: textfield; Index: /trunk/wp-includes/js/media-models.js =================================================================== --- /trunk/wp-includes/js/media-models.js (revision 23031) +++ /trunk/wp-includes/js/media-models.js (revision 23032) @@ -220,5 +220,5 @@ // rejected promise. Otherwise, all of our requests will fail. if ( _.isUndefined( this.id ) ) - return $.Deferred().reject().promise(); + return $.Deferred().rejectWith( this ).promise(); // Overload the `read` request so Attachment.fetch() functions correctly. @@ -234,6 +234,7 @@ // Overload the `update` request so properties can be saved. } else if ( 'update' === method ) { - if ( ! this.get('nonces') ) - return $.Deferred().resolveWith( this ).promise(); + // If we do not have the necessary nonce, fail immeditately. + if ( ! this.get('nonces') || ! this.get('nonces').update ) + return $.Deferred().rejectWith( this ).promise(); options = options || {}; @@ -286,4 +287,8 @@ saveCompat: function( data, options ) { var model = this; + + // If we do not have the necessary nonce, fail immeditately. + if ( ! this.get('nonces') || ! this.get('nonces').update ) + return $.Deferred().rejectWith( this ).promise(); return media.post( 'save-attachment-compat', _.defaults({ Index: /trunk/wp-includes/js/media-views.js =================================================================== --- /trunk/wp-includes/js/media-views.js (revision 23031) +++ /trunk/wp-includes/js/media-views.js (revision 23032) @@ -2757,6 +2757,5 @@ render: function() { - var attachment = this.model.toJSON(), - options = _.defaults( this.model.toJSON(), { + var options = _.defaults( this.model.toJSON(), { orientation: 'landscape', uploading: false, @@ -2780,4 +2779,10 @@ options.size = this.imageSize(); + options.can = {}; + if ( options.nonces ) { + options.can.remove = !! options.nonces['delete']; + options.can.save = !! options.nonces.update; + } + this.views.detach(); this.$el.html( this.template( options ) ); @@ -2968,10 +2973,10 @@ this.updateSave('waiting'); save.requests = requests; - requests.done( function() { + requests.always( function() { // If we've performed another request since this one, bail. if ( save.requests !== requests ) return; - view.updateSave('complete'); + view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' ); save.savedTimer = setTimeout( function() { view.updateSave('ready'); Index: /trunk/wp-includes/media.php =================================================================== --- /trunk/wp-includes/media.php (revision 23031) +++ /trunk/wp-includes/media.php (revision 23032) @@ -1335,8 +1335,14 @@ 'dateFormatted' => mysql2date( get_option('date_format'), $attachment->post_date ), 'nonces' => array( - 'update' => wp_create_nonce( 'update-post_' . $attachment->ID ), - 'delete' => wp_create_nonce( 'delete-post_' . $attachment->ID ), + 'update' => false, + 'delete' => false, ), ); + + if ( current_user_can( 'edit_post', $attachment->ID ) ) + $response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID ); + + if ( current_user_can( 'delete_post', $attachment->ID ) ) + $response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID ); if ( $meta && 'image' === $type ) { @@ -1691,5 +1697,5 @@