Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions src/js/_enqueues/admin/auth-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
context = {
userLogin: authApp.user_login,
successUrl: authApp.success,
successFormat: authApp.success_format,
rejectUrl: authApp.reject
};

Expand Down Expand Up @@ -48,8 +49,9 @@
* @param {Object} request The request data.
* @param {Object} context Context about the Application Password request.
* @param {string} context.userLogin The user's login username.
* @param {string} context.successUrl The URL the user will be redirected to after approving the request.
* @param {string} context.rejectUrl The URL the user will be redirected to after rejecting the request.
* @param {string} context.successUrl The URL the user will be redirected to after approving the request.
* @param {string} context.successFormat The transport used for the success payload.
* @param {string} context.rejectUrl The URL the user will be redirected to after rejecting the request.
*/
request = wp.hooks.applyFilters( 'wp_application_passwords_approve_app_request', request, context );

Expand All @@ -75,15 +77,27 @@
wp.hooks.doAction( 'wp_application_passwords_approve_app_request_success', response, textStatus, jqXHR );

var raw = authApp.success,
url, message, $notice;
url, message, $notice, $callbackForm;

if ( raw ) {
url = raw + ( -1 === raw.indexOf( '?' ) ? '?' : '&' ) +
'site_url=' + encodeURIComponent( authApp.site_url ) +
'&user_login=' + encodeURIComponent( authApp.user_login ) +
'&password=' + encodeURIComponent( response.password );

window.location = url;
if ( 'form_post' === authApp.success_format ) {
$callbackForm = $( '<form>' )
.attr( 'method', 'post' )
.attr( 'action', raw )
.hide()
.append( $( '<input>' ).attr( 'type', 'hidden' ).attr( 'name', 'site_url' ).val( authApp.site_url ) )
.append( $( '<input>' ).attr( 'type', 'hidden' ).attr( 'name', 'user_login' ).val( authApp.user_login ) )
.append( $( '<input>' ).attr( 'type', 'hidden' ).attr( 'name', 'password' ).val( response.password ) );
$( document.body ).append( $callbackForm );
$callbackForm[0].submit();
} else {
url = raw + ( -1 === raw.indexOf( '?' ) ? '?' : '&' ) +
'site_url=' + encodeURIComponent( authApp.site_url ) +
'&user_login=' + encodeURIComponent( authApp.user_login ) +
'&password=' + encodeURIComponent( response.password );

window.location = url;
}
} else {
message = wp.i18n.sprintf(
/* translators: %s: Application name. */
Expand Down Expand Up @@ -150,8 +164,9 @@
*
* @param {Object} context Context about the Application Password request.
* @param {string} context.userLogin The user's login username.
* @param {string} context.successUrl The URL the user will be redirected to after approving the request.
* @param {string} context.rejectUrl The URL the user will be redirected to after rejecting the request.
* @param {string} context.successUrl The URL the user will be redirected to after approving the request.
* @param {string} context.successFormat The transport used for the success payload.
* @param {string} context.rejectUrl The URL the user will be redirected to after rejecting the request.
*/
wp.hooks.doAction( 'wp_application_passwords_reject_app', context );

Expand Down
122 changes: 85 additions & 37 deletions src/wp-admin/authorize-application.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,27 @@

$error = null;
$new_password = '';
$user = wp_get_current_user();

// This is the no-js fallback script. Generally this will all be handled by `auth-app.js`.
if ( isset( $_POST['action'] ) && 'authorize_application_password' === $_POST['action'] ) {
check_admin_referer( 'authorize_application_password' );

$success_url = $_POST['success_url'];
$reject_url = $_POST['reject_url'];
$app_name = $_POST['app_name'];
$app_id = $_POST['app_id'];
$redirect = '';
$success_url = $_POST['success_url'];
$reject_url = $_POST['reject_url'];
$app_name = $_POST['app_name'];
$app_id = $_POST['app_id'];
$success_format = isset( $_POST['success_format'] ) ? $_POST['success_format'] : 'query';
$redirect = '';
$request = compact( 'app_name', 'app_id', 'success_url', 'reject_url', 'success_format' );
$is_valid = wp_is_authorize_application_password_request_valid( $request, $user );

if ( is_wp_error( $is_valid ) ) {
wp_die(
__( 'The Authorize Application request is not allowed.' ) . ' ' . implode( ' ', $is_valid->get_error_messages() ),
__( 'Cannot Authorize Application' )
);
}

if ( isset( $_POST['reject'] ) ) {
if ( $reject_url ) {
Expand All @@ -43,14 +54,42 @@
list( $new_password ) = $created;

if ( $success_url ) {
$redirect = add_query_arg(
array(
'site_url' => urlencode( site_url() ),
'user_login' => urlencode( wp_get_current_user()->user_login ),
'password' => urlencode( $new_password ),
),
$success_url
);
if ( 'form_post' === $success_format ) {
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
<title><?php esc_html_e( 'Authorizing Application' ); ?></title>
</head>
<body>
<form id="callback-form" action="<?php echo esc_url( $success_url, array( 'http', 'https' ) ); ?>" method="post">
<input type="hidden" name="site_url" value="<?php echo esc_attr( site_url() ); ?>" />
<input type="hidden" name="user_login" value="<?php echo esc_attr( $user->user_login ); ?>" />
<input type="hidden" name="password" value="<?php echo esc_attr( $new_password ); ?>" />
<noscript>
<p><?php esc_html_e( 'JavaScript is required to complete the authorization automatically.' ); ?></p>
<button type="submit"><?php esc_html_e( 'Complete Authorization' ); ?></button>
</noscript>
</form>
<script>
document.getElementById( 'callback-form' ).submit();
</script>
</body>
</html>
<?php
exit;
} else {
$redirect = add_query_arg(
array(
'site_url' => site_url(),
'user_login' => $user->user_login,
'password' => $new_password,
),
$success_url
);
}
}
}
}
Expand All @@ -65,9 +104,10 @@
// Used in the HTML title tag.
$title = __( 'Authorize Application' );

$app_name = ! empty( $_REQUEST['app_name'] ) ? $_REQUEST['app_name'] : '';
$app_id = ! empty( $_REQUEST['app_id'] ) ? $_REQUEST['app_id'] : '';
$success_url = ! empty( $_REQUEST['success_url'] ) ? $_REQUEST['success_url'] : null;
$app_name = ! empty( $_REQUEST['app_name'] ) ? $_REQUEST['app_name'] : '';
$app_id = ! empty( $_REQUEST['app_id'] ) ? $_REQUEST['app_id'] : '';
$success_url = ! empty( $_REQUEST['success_url'] ) ? $_REQUEST['success_url'] : null;
$success_format = ! empty( $_REQUEST['success_format'] ) ? $_REQUEST['success_format'] : 'query';

if ( ! empty( $_REQUEST['reject_url'] ) ) {
$reject_url = $_REQUEST['reject_url'];
Expand All @@ -77,9 +117,7 @@
$reject_url = null;
}

$user = wp_get_current_user();

$request = compact( 'app_name', 'app_id', 'success_url', 'reject_url' );
$request = compact( 'app_name', 'app_id', 'success_url', 'reject_url', 'success_format' );
$is_valid = wp_is_authorize_application_password_request_valid( $request, $user );

if ( is_wp_error( $is_valid ) ) {
Expand Down Expand Up @@ -124,10 +162,11 @@
'auth-app',
'authApp',
array(
'site_url' => site_url(),
'user_login' => $user->user_login,
'success' => $success_url,
'reject' => $reject_url ? $reject_url : admin_url(),
'site_url' => site_url(),
'user_login' => $user->user_login,
'success' => $success_url,
'success_format' => $success_format,
'reject' => $reject_url ? $reject_url : admin_url(),
)
);

Expand Down Expand Up @@ -241,6 +280,7 @@
<input type="hidden" name="action" value="authorize_application_password" />
<input type="hidden" name="app_id" value="<?php echo esc_attr( $app_id ); ?>" />
<input type="hidden" name="success_url" value="<?php echo esc_url( $success_url ); ?>" />
<input type="hidden" name="success_format" value="<?php echo esc_attr( $success_format ); ?>" />
<input type="hidden" name="reject_url" value="<?php echo esc_url( $reject_url ); ?>" />

<div class="form-field">
Expand Down Expand Up @@ -280,20 +320,28 @@
<p class="description" id="description-approve">
<?php
if ( $success_url ) {
printf(
/* translators: %s: The URL the user is being redirected to. */
__( 'You will be sent to %s' ),
'<strong><code>' . esc_html(
add_query_arg(
array(
'site_url' => site_url(),
'user_login' => $user->user_login,
'password' => '[------]',
),
$success_url
)
) . '</code></strong>'
);
if ( 'form_post' === $success_format ) {
printf(
/* translators: %s: The URL the user is being redirected to. */
__( 'Your connection details will be sent to %s.' ),
'<strong><code>' . esc_html( $success_url ) . '</code></strong>'
);
} else {
printf(
/* translators: %s: The URL the user is being redirected to. */
__( 'You will be sent to %s' ),
'<strong><code>' . esc_html(
add_query_arg(
array(
'site_url' => site_url(),
'user_login' => $user->user_login,
'password' => '[------]',
),
$success_url
)
) . '</code></strong>'
);
}
} else {
_e( 'You will be given a password to manually enter into the application in question.' );
}
Expand Down
30 changes: 26 additions & 4 deletions src/wp-admin/includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,11 @@ function admin_created_user_email( $text ) {
* @param array $request {
* The array of request data. All arguments are optional and may be empty.
*
* @type string $app_name The suggested name of the application.
* @type string $app_id A UUID provided by the application to uniquely identify it.
* @type string $success_url The URL the user will be redirected to after approving the application.
* @type string $reject_url The URL the user will be redirected to after rejecting the application.
* @type string $app_name The suggested name of the application.
* @type string $app_id A UUID provided by the application to uniquely identify it.
* @type string $success_url The URL the user will be redirected to after approving the application.
* @type string $success_format The transport to use for the success payload. Accepts 'query' or 'form_post'.
* @type string $reject_url The URL the user will be redirected to after rejecting the application.
* }
* @param WP_User $user The user authorizing the application.
* @return true|WP_Error True if the request is valid, a WP_Error object contains errors if not.
Expand Down Expand Up @@ -674,6 +675,27 @@ function wp_is_authorize_application_password_request_valid( $request, $user ) {
}
}

if ( isset( $request['success_format'] ) && ! in_array( $request['success_format'], array( 'query', 'form_post' ), true ) ) {
$error->add(
'invalid_success_format',
__( 'The success format must be "query" or "form_post".' )
);
}

$success_url_scheme = ! empty( $request['success_url'] ) ? wp_parse_url( $request['success_url'], PHP_URL_SCHEME ) : '';

if (
! empty( $request['success_url'] ) &&
isset( $request['success_format'] ) &&
'form_post' === $request['success_format'] &&
! in_array( strtolower( (string) $success_url_scheme ), array( 'http', 'https' ), true )
) {
$error->add(
'invalid_success_format',
__( 'The form_post success format requires an HTTP or HTTPS success URL.' )
);
}

if ( ! empty( $request['app_id'] ) && ! wp_is_uuid( $request['app_id'] ) ) {
$error->add(
'invalid_app_id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,36 @@ public function data_is_authorize_application_password_request_valid() {
'expected_error_code' => '',
'env' => $environment_type,
);

$datasets[ $environment_type . ' and a "query" success_format' ] = array(
'request' => array( 'success_format' => 'query' ),
'expected_error_code' => '',
'env' => $environment_type,
);

$datasets[ $environment_type . ' and a "form_post" success_format with an "https" scheme "success_url"' ] = array(
'request' => array(
'success_url' => 'https://example.org',
'success_format' => 'form_post',
),
'expected_error_code' => '',
'env' => $environment_type,
);

$datasets[ $environment_type . ' and an invalid success_format' ] = array(
'request' => array( 'success_format' => 'invalid' ),
'expected_error_code' => 'invalid_success_format',
'env' => $environment_type,
);

$datasets[ $environment_type . ' and a "form_post" success_format with an app scheme "success_url"' ] = array(
'request' => array(
'success_url' => 'wordpress://example',
'success_format' => 'form_post',
),
'expected_error_code' => 'invalid_success_format',
'env' => $environment_type,
);
}

return $datasets;
Expand Down
Loading