diff --git a/wp-admin/js/application-passwords.js b/wp-admin/js/application-passwords.js index 7901ac901b..cab592519b 100644 --- a/wp-admin/js/application-passwords.js +++ b/wp-admin/js/application-passwords.js @@ -57,7 +57,7 @@ $newAppPassButton.prop( 'disabled', false ); $newAppPassForm.after( tmplNewAppPass( { - name: name, + name: response.name, password: response.password } ) ); $( '.new-application-password-notice' ).focus(); diff --git a/wp-admin/js/application-passwords.min.js b/wp-admin/js/application-passwords.min.js index 90b6dcb131..5d9fa5010e 100644 --- a/wp-admin/js/application-passwords.min.js +++ b/wp-admin/js/application-passwords.min.js @@ -1,2 +1,2 @@ /*! This file is auto-generated */ -!function(o){var a=o("#application-passwords-section"),i=a.find(".create-application-password"),n=i.find(".input"),t=i.find(".button"),p=a.find(".application-passwords-list-table-wrapper"),r=a.find("tbody"),d=r.find(".no-items"),e=o("#revoke-all-application-passwords"),l=wp.template("new-application-password"),c=wp.template("application-password-row"),u=o("#user_id").val();function w(e,s,a){f(e.responseJSON&&e.responseJSON.message?e.responseJSON.message:a,"error")}function f(e,s){e=o("
").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(o("

").text(e)).append(o("").attr("type","button").addClass("notice-dismiss").append(o("").addClass("screen-reader-text").text(wp.i18n.__("Dismiss this notice."))));return i.after(e),e}function v(){o(".notice",a).remove()}t.on("click",function(e){var s,a;e.preventDefault(),t.prop("aria-disabled")||(0!==(s=n.val()).length?(v(),t.prop("aria-disabled",!0).addClass("disabled"),a={name:s},a=wp.hooks.applyFilters("wp_application_passwords_new_password_request",a,u),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"POST",data:a}).always(function(){t.removeProp("aria-disabled").removeClass("disabled")}).done(function(e){n.val(""),t.prop("disabled",!1),i.after(l({name:s,password:e.password})),o(".new-application-password-notice").focus(),r.prepend(c(e)),p.show(),d.remove(),wp.hooks.doAction("wp_application_passwords_created_password",e,a)}).fail(w)):n.focus())}),r.on("click",".delete",function(e){var s,a;e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke this password? This action cannot be undone."))&&(s=o(this),e=(a=s.closest("tr")).data("uuid"),v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords/"+e+"?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(0===a.siblings().length&&p.hide(),a.remove(),f(wp.i18n.__("Application password revoked."),"success").focus())}).fail(w))}),e.on("click",function(e){var s;e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke all passwords? This action cannot be undone."))&&(s=o(this),v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(r.children().remove(),a.children(".new-application-password").remove(),p.hide(),f(wp.i18n.__("All application passwords revoked."),"success").focus())}).fail(w))}),a.on("click",".notice-dismiss",function(e){e.preventDefault();var s=o(this).parent();s.removeAttr("role"),s.fadeTo(100,0,function(){s.slideUp(100,function(){s.remove(),n.focus()})})}),0===r.children("tr").not(d).length&&p.hide()}(jQuery); \ No newline at end of file +!function(o){var a=o("#application-passwords-section"),i=a.find(".create-application-password"),n=i.find(".input"),t=i.find(".button"),p=a.find(".application-passwords-list-table-wrapper"),r=a.find("tbody"),d=r.find(".no-items"),e=o("#revoke-all-application-passwords"),l=wp.template("new-application-password"),c=wp.template("application-password-row"),u=o("#user_id").val();function w(e,s,a){f(e.responseJSON&&e.responseJSON.message?e.responseJSON.message:a,"error")}function f(e,s){e=o("
").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(o("

").text(e)).append(o("").attr("type","button").addClass("notice-dismiss").append(o("").addClass("screen-reader-text").text(wp.i18n.__("Dismiss this notice."))));return i.after(e),e}function v(){o(".notice",a).remove()}t.on("click",function(e){var s;e.preventDefault(),t.prop("aria-disabled")||(0!==(e=n.val()).length?(v(),t.prop("aria-disabled",!0).addClass("disabled"),s={name:e},s=wp.hooks.applyFilters("wp_application_passwords_new_password_request",s,u),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"POST",data:s}).always(function(){t.removeProp("aria-disabled").removeClass("disabled")}).done(function(e){n.val(""),t.prop("disabled",!1),i.after(l({name:e.name,password:e.password})),o(".new-application-password-notice").focus(),r.prepend(c(e)),p.show(),d.remove(),wp.hooks.doAction("wp_application_passwords_created_password",e,s)}).fail(w)):n.focus())}),r.on("click",".delete",function(e){var s,a;e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke this password? This action cannot be undone."))&&(s=o(this),e=(a=s.closest("tr")).data("uuid"),v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords/"+e+"?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(0===a.siblings().length&&p.hide(),a.remove(),f(wp.i18n.__("Application password revoked."),"success").focus())}).fail(w))}),e.on("click",function(e){var s;e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke all passwords? This action cannot be undone."))&&(s=o(this),v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(r.children().remove(),a.children(".new-application-password").remove(),p.hide(),f(wp.i18n.__("All application passwords revoked."),"success").focus())}).fail(w))}),a.on("click",".notice-dismiss",function(e){e.preventDefault();var s=o(this).parent();s.removeAttr("role"),s.fadeTo(100,0,function(){s.slideUp(100,function(){s.remove(),n.focus()})})}),0===r.children("tr").not(d).length&&p.hide()}(jQuery); \ No newline at end of file diff --git a/wp-admin/js/auth-app.js b/wp-admin/js/auth-app.js index b4b8ddbda5..f358dd7e64 100644 --- a/wp-admin/js/auth-app.js +++ b/wp-admin/js/auth-app.js @@ -98,7 +98,7 @@ .append( '

' + wp.i18n.__( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ) + '

' ); // We're using .text() to write the variables to avoid any chance of XSS. - $( 'strong', $notice ).text( name ); + $( 'strong', $notice ).text( response.name ); $( 'input', $notice ).val( response.password ); $form.replaceWith( $notice ); diff --git a/wp-admin/js/auth-app.min.js b/wp-admin/js/auth-app.min.js index daacbeb0ed..062f3b31a5 100644 --- a/wp-admin/js/auth-app.min.js +++ b/wp-admin/js/auth-app.min.js @@ -1,2 +1,2 @@ /*! This file is auto-generated */ -!function(t,n){var s=t("#app_name"),r=t("#approve"),e=t("#reject"),i=s.closest("form"),o={userLogin:n.user_login,successUrl:n.success,rejectUrl:n.reject};r.click(function(e){var p=s.val(),a=t('input[name="app_id"]',i).val();e.preventDefault(),r.prop("aria-disabled")||(0!==p.length?(r.prop("aria-disabled",!0).addClass("disabled"),e={name:p},0'+wp.i18n.__("Your new password for %s is:")+"","")+' ',o=t("
").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(t("

").addClass("application-password-display").html(o)).append("

"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"

"),t("strong",o).text(p),t("input",o).val(e.password),i.replaceWith(o),o.focus())}).fail(function(e,a,s){var o=s,p=null;e.responseJSON&&(p=e.responseJSON).message&&(o=p.message);o=t("
").attr("role","alert").addClass("notice notice-error").append(t("

").text(o));t("h1").after(o),r.removeProp("aria-disabled",!1).removeClass("disabled"),wp.hooks.doAction("wp_application_passwords_approve_app_request_error",p,a,s,e)})):s.focus())}),e.click(function(e){e.preventDefault(),wp.hooks.doAction("wp_application_passwords_reject_app",o),window.location=n.reject}),i.on("submit",function(e){e.preventDefault()})}(jQuery,authApp); \ No newline at end of file +!function(t,p){var o=t("#app_name"),n=t("#approve"),e=t("#reject"),r=o.closest("form"),i={userLogin:p.user_login,successUrl:p.success,rejectUrl:p.reject};n.click(function(e){var a=o.val(),s=t('input[name="app_id"]',r).val();e.preventDefault(),n.prop("aria-disabled")||(0!==a.length?(n.prop("aria-disabled",!0).addClass("disabled"),a={name:a},0'+wp.i18n.__("Your new password for %s is:")+"","")+' ',o=t("
").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(t("

").addClass("application-password-display").html(o)).append("

"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"

"),t("strong",o).text(e.name),t("input",o).val(e.password),r.replaceWith(o),o.focus())}).fail(function(e,a,s){var o=s,p=null;e.responseJSON&&(p=e.responseJSON).message&&(o=p.message);o=t("
").attr("role","alert").addClass("notice notice-error").append(t("

").text(o));t("h1").after(o),n.removeProp("aria-disabled",!1).removeClass("disabled"),wp.hooks.doAction("wp_application_passwords_approve_app_request_error",p,a,s,e)})):o.focus())}),e.click(function(e){e.preventDefault(),wp.hooks.doAction("wp_application_passwords_reject_app",i),window.location=p.reject}),r.on("submit",function(e){e.preventDefault()})}(jQuery,authApp); \ No newline at end of file diff --git a/wp-includes/class-wp-application-passwords.php b/wp-includes/class-wp-application-passwords.php index 22ad1c72c8..0fd5d8b40a 100644 --- a/wp-includes/class-wp-application-passwords.php +++ b/wp-includes/class-wp-application-passwords.php @@ -58,6 +58,7 @@ class WP_Application_Passwords { * Creates a new application password. * * @since 5.6.0 + * @since 5.7.0 Returns WP_Error if application name already exists. * * @param int $user_id User ID. * @param array $args Information about the application password. @@ -65,8 +66,16 @@ class WP_Application_Passwords { * A WP_Error instance is returned on error. */ public static function create_new_application_password( $user_id, $args = array() ) { + if ( ! empty( $args['name'] ) ) { + $args['name'] = sanitize_text_field( $args['name'] ); + } + if ( empty( $args['name'] ) ) { - return new WP_Error( 'application_password_empty_name', __( 'An application name is required to create an application password.' ) ); + return new WP_Error( 'application_password_empty_name', __( 'An application name is required to create an application password.' ), array( 'status' => 400 ) ); + } + + if ( self::application_name_exists_for_user( $user_id, $args['name'] ) ) { + return new WP_Error( 'application_password_duplicate_name', __( 'Each application name should be unique.' ), array( 'status' => 409 ) ); } $new_password = wp_generate_password( static::PW_LENGTH, false ); @@ -162,6 +171,28 @@ class WP_Application_Passwords { return null; } + /** + * Check if application name exists before for this user. + * + * @since 5.7.0 + * + * @param int $user_id User ID. + * @param string $name Application name. + * + * @return bool Provided application name exists or not. + */ + public static function application_name_exists_for_user( $user_id, $name ) { + $passwords = static::get_user_application_passwords( $user_id ); + + foreach ( $passwords as $password ) { + if ( strtolower( $password['name'] ) === strtolower( $name ) ) { + return true; + } + } + + return false; + } + /** * Updates an application password. * @@ -180,6 +211,10 @@ class WP_Application_Passwords { continue; } + if ( ! empty( $update['name'] ) ) { + $update['name'] = sanitize_text_field( $update['name'] ); + } + $save = false; if ( ! empty( $update['name'] ) && $item['name'] !== $update['name'] ) { diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php index dc94348022..622d3617c2 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php @@ -631,6 +631,8 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { 'type' => 'string', 'required' => true, 'context' => array( 'view', 'edit', 'embed' ), + 'minLength' => 1, + 'pattern' => '.*\S.*', ), 'password' => array( 'description' => __( 'The generated password. Only available after adding an application.' ), diff --git a/wp-includes/version.php b/wp-includes/version.php index 1ff22af295..88c23aa67a 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.7-alpha-50029'; +$wp_version = '5.7-alpha-50030'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.