WordPress/wp-admin/js/application-passwords.js
TimothyBlynJacobs ee710f2c16 App Passwords: Improve validation and sanitization of the application name.
Application names are now required to be unique and cannot contain solely whitespace characters. Additionally, invalid characters are now stripped from the application name using `sanitize_text_field()`.

Props Boniu91, hellofromTonya, engahmeds3ed, xkon, francina.
Fixes #51941.

Built from https://develop.svn.wordpress.org/trunk@50030


git-svn-id: http://core.svn.wordpress.org/trunk@49731 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-01-27 19:05:02 +00:00

213 lines
6.0 KiB
JavaScript

/**
* @output wp-admin/js/application-passwords.js
*/
( function( $ ) {
var $appPassSection = $( '#application-passwords-section' ),
$newAppPassForm = $appPassSection.find( '.create-application-password' ),
$newAppPassField = $newAppPassForm.find( '.input' ),
$newAppPassButton = $newAppPassForm.find( '.button' ),
$appPassTwrapper = $appPassSection.find( '.application-passwords-list-table-wrapper' ),
$appPassTbody = $appPassSection.find( 'tbody' ),
$appPassTrNoItems = $appPassTbody.find( '.no-items' ),
$removeAllBtn = $( '#revoke-all-application-passwords' ),
tmplNewAppPass = wp.template( 'new-application-password' ),
tmplAppPassRow = wp.template( 'application-password-row' ),
userId = $( '#user_id' ).val();
$newAppPassButton.on( 'click', function( e ) {
e.preventDefault();
if ( $newAppPassButton.prop( 'aria-disabled' ) ) {
return;
}
var name = $newAppPassField.val();
if ( 0 === name.length ) {
$newAppPassField.focus();
return;
}
clearNotices();
$newAppPassButton.prop( 'aria-disabled', true ).addClass( 'disabled' );
var request = {
name: name
};
/**
* Filters the request data used to create a new Application Password.
*
* @since 5.6.0
*
* @param {Object} request The request data.
* @param {number} userId The id of the user the password is added for.
*/
request = wp.hooks.applyFilters( 'wp_application_passwords_new_password_request', request, userId );
wp.apiRequest( {
path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user',
method: 'POST',
data: request
} ).always( function() {
$newAppPassButton.removeProp( 'aria-disabled' ).removeClass( 'disabled' );
} ).done( function( response ) {
$newAppPassField.val( '' );
$newAppPassButton.prop( 'disabled', false );
$newAppPassForm.after( tmplNewAppPass( {
name: response.name,
password: response.password
} ) );
$( '.new-application-password-notice' ).focus();
$appPassTbody.prepend( tmplAppPassRow( response ) );
$appPassTwrapper.show();
$appPassTrNoItems.remove();
/**
* Fires after an application password has been successfully created.
*
* @since 5.6.0
*
* @param {Object} response The response data from the REST API.
* @param {Object} request The request data used to create the password.
*/
wp.hooks.doAction( 'wp_application_passwords_created_password', response, request );
} ).fail( handleErrorResponse );
} );
$appPassTbody.on( 'click', '.delete', function( e ) {
e.preventDefault();
if ( ! window.confirm( wp.i18n.__( 'Are you sure you want to revoke this password? This action cannot be undone.' ) ) ) {
return;
}
var $submitButton = $( this ),
$tr = $submitButton.closest( 'tr' ),
uuid = $tr.data( 'uuid' );
clearNotices();
$submitButton.prop( 'disabled', true );
wp.apiRequest( {
path: '/wp/v2/users/' + userId + '/application-passwords/' + uuid + '?_locale=user',
method: 'DELETE'
} ).always( function() {
$submitButton.prop( 'disabled', false );
} ).done( function( response ) {
if ( response.deleted ) {
if ( 0 === $tr.siblings().length ) {
$appPassTwrapper.hide();
}
$tr.remove();
addNotice( wp.i18n.__( 'Application password revoked.' ), 'success' ).focus();
}
} ).fail( handleErrorResponse );
} );
$removeAllBtn.on( 'click', function( e ) {
e.preventDefault();
if ( ! window.confirm( wp.i18n.__( 'Are you sure you want to revoke all passwords? This action cannot be undone.' ) ) ) {
return;
}
var $submitButton = $( this );
clearNotices();
$submitButton.prop( 'disabled', true );
wp.apiRequest( {
path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user',
method: 'DELETE'
} ).always( function() {
$submitButton.prop( 'disabled', false );
} ).done( function( response ) {
if ( response.deleted ) {
$appPassTbody.children().remove();
$appPassSection.children( '.new-application-password' ).remove();
$appPassTwrapper.hide();
addNotice( wp.i18n.__( 'All application passwords revoked.' ), 'success' ).focus();
}
} ).fail( handleErrorResponse );
} );
$appPassSection.on( 'click', '.notice-dismiss', function( e ) {
e.preventDefault();
var $el = $( this ).parent();
$el.removeAttr( 'role' );
$el.fadeTo( 100, 0, function () {
$el.slideUp( 100, function () {
$el.remove();
$newAppPassField.focus();
} );
} );
} );
// If there are no items, don't display the table yet. If there are, show it.
if ( 0 === $appPassTbody.children( 'tr' ).not( $appPassTrNoItems ).length ) {
$appPassTwrapper.hide();
}
/**
* Handles an error response from the REST API.
*
* @since 5.6.0
*
* @param {jqXHR} xhr The XHR object from the ajax call.
* @param {string} textStatus The string categorizing the ajax request's status.
* @param {string} errorThrown The HTTP status error text.
*/
function handleErrorResponse( xhr, textStatus, errorThrown ) {
var errorMessage = errorThrown;
if ( xhr.responseJSON && xhr.responseJSON.message ) {
errorMessage = xhr.responseJSON.message;
}
addNotice( errorMessage, 'error' );
}
/**
* Displays a message in the Application Passwords section.
*
* @since 5.6.0
*
* @param {string} message The message to display.
* @param {string} type The notice type. Either 'success' or 'error'.
* @returns {jQuery} The notice element.
*/
function addNotice( message, type ) {
var $notice = $( '<div></div>' )
.attr( 'role', 'alert' )
.attr( 'tabindex', '-1' )
.addClass( 'is-dismissible notice notice-' + type )
.append( $( '<p></p>' ).text( message ) )
.append(
$( '<button></button>' )
.attr( 'type', 'button' )
.addClass( 'notice-dismiss' )
.append( $( '<span></span>' ).addClass( 'screen-reader-text' ).text( wp.i18n.__( 'Dismiss this notice.' ) ) )
);
$newAppPassForm.after( $notice );
return $notice;
}
/**
* Clears notice messages from the Application Passwords section.
*
* @since 5.6.0
*/
function clearNotices() {
$( '.notice', $appPassSection ).remove();
}
}( jQuery ) );