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
21 changes: 16 additions & 5 deletions src/wp-activate.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
list( $activate_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
$activate_cookie = 'wp-activate-' . COOKIEHASH;

$key = '';
$result = null;
$key = '';
$signup_id = 0;
$result = null;

if ( isset( $_GET['key'] ) && isset( $_POST['key'] ) && $_GET['key'] !== $_POST['key'] ) {
wp_die( __( 'A key value mismatch has been detected. Please follow the link provided in your activation email.' ), __( 'An error occurred during the activation' ), 400 );
Expand All @@ -34,6 +35,12 @@
$key = sanitize_text_field( $_POST['key'] );
}

if ( ! empty( $_GET['signup_id'] ) ) {
$signup_id = absint( $_GET['signup_id'] );
} elseif ( ! empty( $_POST['signup_id'] ) ) {
$signup_id = absint( $_POST['signup_id'] );
}

if ( $key ) {
$redirect_url = remove_query_arg( 'key' );

Expand All @@ -42,17 +49,17 @@
wp_safe_redirect( $redirect_url );
exit;
} else {
$result = wpmu_activate_signup( $key );
$result = wpmu_activate_signup( $key, $signup_id );
}
}

if ( null === $result && isset( $_COOKIE[ $activate_cookie ] ) ) {
$key = $_COOKIE[ $activate_cookie ];
$result = wpmu_activate_signup( $key );
$result = wpmu_activate_signup( $key, $signup_id );
setcookie( $activate_cookie, ' ', time() - YEAR_IN_SECONDS, $activate_path, COOKIE_DOMAIN, is_ssl(), true );
}

if ( null === $result || ( is_wp_error( $result ) && 'invalid_key' === $result->get_error_code() ) ) {
if ( null === $result || ( is_wp_error( $result ) && in_array( $result->get_error_code(), array( 'invalid_key', 'invalid_id', 'expired_key' ), true ) ) ) {
status_header( 404 );
} elseif ( is_wp_error( $result ) ) {
$error_code = $result->get_error_code();
Expand Down Expand Up @@ -130,6 +137,10 @@ function wpmu_activate_stylesheet() {
<label for="key"><?php _e( 'Activation Key:' ); ?></label>
<br /><input type="text" name="key" id="key" value="" size="50" autofocus="autofocus" />
</p>
<p>
<label for="signup_id"><?php _e( 'Signup ID:' ); ?></label>
<br /><input type="number" name="signup_id" id="signup_id" value="" size="50" />
</p>
<p class="submit">
<input id="submit" type="submit" name="Submit" class="submit" value="<?php esc_attr_e( 'Activate' ); ?>" />
</p>
Expand Down
4 changes: 2 additions & 2 deletions src/wp-admin/user-new.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@
);

if ( isset( $_POST['noconfirmation'] ) && current_user_can( 'manage_network_users' ) ) {
$key = $wpdb->get_var( $wpdb->prepare( "SELECT activation_key FROM {$wpdb->signups} WHERE user_login = %s AND user_email = %s", $new_user_login, $new_user_email ) );
$new_user = wpmu_activate_signup( $key );
$row = $wpdb->get_row( $wpdb->prepare( "SELECT activation_key, signup_id FROM {$wpdb->signups} WHERE user_login = %s AND user_email = %s", $new_user_login, $new_user_email ) );
$new_user = wpmu_activate_signup( $row->activation_key, $row->signup_id );
if ( is_wp_error( $new_user ) ) {
$redirect = add_query_arg( array( 'update' => 'addnoconfirmation' ), 'user-new.php' );
} elseif ( ! is_user_member_of_blog( $new_user['user_id'] ) ) {
Expand Down
4 changes: 2 additions & 2 deletions src/wp-includes/ms-default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
add_action( 'wpmu_new_user', 'newuser_notify_siteadmin' );
add_action( 'wpmu_activate_user', 'add_new_user_to_blog', 10, 3 );
add_action( 'wpmu_activate_user', 'wpmu_welcome_user_notification', 10, 3 );
add_action( 'after_signup_user', 'wpmu_signup_user_notification', 10, 4 );
add_action( 'after_signup_user', 'wpmu_signup_user_notification', 10, 5 );
add_action( 'network_site_new_created_user', 'wp_send_new_user_notifications' );
add_action( 'network_site_users_created_user', 'wp_send_new_user_notifications' );
add_action( 'network_user_new_created_user', 'wp_send_new_user_notifications' );
Expand All @@ -39,7 +39,7 @@
// Blogs.
add_filter( 'wpmu_validate_blog_signup', 'signup_nonce_check' );
add_action( 'wpmu_activate_blog', 'wpmu_welcome_notification', 10, 5 );
add_action( 'after_signup_site', 'wpmu_signup_blog_notification', 10, 7 );
add_action( 'after_signup_site', 'wpmu_signup_blog_notification', 10, 8 );
add_filter( 'wp_normalize_site_data', 'wp_normalize_site_data', 10, 1 );
add_action( 'wp_validate_site_data', 'wp_validate_site_data', 10, 3 );
add_action( 'wp_insert_site', 'wp_maybe_update_network_site_counts_on_update', 10, 1 );
Expand Down
99 changes: 79 additions & 20 deletions src/wp-includes/ms-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -800,10 +800,17 @@ function wpmu_validate_blog_signup( $blogname, $blog_title, $user = '' ) {
* @param array $meta Optional. Signup meta data. By default, contains the requested privacy setting and lang_id.
*/
function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = array() ) {
global $wpdb;
global $wpdb, $wp_hasher;

$key = substr( md5( time() . wp_rand() . $domain ), 0, 16 );

if ( empty( $wp_hasher ) ) {
require_once ABSPATH . WPINC . '/class-phpass.php';
$wp_hasher = new PasswordHash( 8, true );
}

$hashed = time() . ':' . $wp_hasher->HashPassword( $key );

/**
* Filters the metadata for a site signup.
*
Expand All @@ -818,8 +825,9 @@ function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = a
* @param string $user The user's requested login name.
* @param string $user_email The user's email address.
* @param string $key The user's activation key.
* @param string $hashed The user's hashed activation key.
*/
$meta = apply_filters( 'signup_site_meta', $meta, $domain, $path, $title, $user, $user_email, $key );
$meta = apply_filters( 'signup_site_meta', $meta, $domain, $path, $title, $user, $user_email, $key, $hashed );

$wpdb->insert(
$wpdb->signups,
Expand All @@ -830,7 +838,7 @@ function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = a
'user_login' => $user,
'user_email' => $user_email,
'registered' => current_time( 'mysql', true ),
'activation_key' => $key,
'activation_key' => $hashed,
'meta' => serialize( $meta ),
)
);
Expand All @@ -847,8 +855,10 @@ function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = a
* @param string $user_email The user's email address.
* @param string $key The user's activation key.
* @param array $meta Signup meta data. By default, contains the requested privacy setting and lang_id.
* @param int $signup_id Signup ID.
* @param string $hashed The user's hashed activation key.
*/
do_action( 'after_signup_site', $domain, $path, $title, $user, $user_email, $key, $meta );
do_action( 'after_signup_site', $domain, $path, $title, $user, $user_email, $key, $meta, $wpdb->insert_id, $hashed );
}

/**
Expand All @@ -866,13 +876,20 @@ function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = a
* @param array $meta Optional. Signup meta data. Default empty array.
*/
function wpmu_signup_user( $user, $user_email, $meta = array() ) {
global $wpdb;
global $wpdb, $wp_hasher;

// Format data.
$user = preg_replace( '/\s+/', '', sanitize_user( $user, true ) );
$user_email = sanitize_email( $user_email );
$key = substr( md5( time() . wp_rand() . $user_email ), 0, 16 );

if ( empty( $wp_hasher ) ) {
require_once ABSPATH . WPINC . '/class-phpass.php';
$wp_hasher = new PasswordHash( 8, true );
}

$hashed = time() . ':' . $wp_hasher->HashPassword( $key );

/**
* Filters the metadata for a user signup.
*
Expand All @@ -884,8 +901,9 @@ function wpmu_signup_user( $user, $user_email, $meta = array() ) {
* @param string $user The user's requested login name.
* @param string $user_email The user's email address.
* @param string $key The user's activation key.
* @param string $hashed The user's hashed activation key.
*/
$meta = apply_filters( 'signup_user_meta', $meta, $user, $user_email, $key );
$meta = apply_filters( 'signup_user_meta', $meta, $user, $user_email, $key, $hashed );

$wpdb->insert(
$wpdb->signups,
Expand All @@ -896,7 +914,7 @@ function wpmu_signup_user( $user, $user_email, $meta = array() ) {
'user_login' => $user,
'user_email' => $user_email,
'registered' => current_time( 'mysql', true ),
'activation_key' => $key,
'activation_key' => $hashed,
'meta' => serialize( $meta ),
)
);
Expand All @@ -910,8 +928,10 @@ function wpmu_signup_user( $user, $user_email, $meta = array() ) {
* @param string $user_email The user's email address.
* @param string $key The user's activation key.
* @param array $meta Signup meta data. Default empty array.
* @param int $signup_id Signup ID.
* @param string $hashed The user's hashed activation key.
*/
do_action( 'after_signup_user', $user, $user_email, $key, $meta );
do_action( 'after_signup_user', $user, $user_email, $key, $meta, $wpdb->insert_id, $hashed );
}

/**
Expand Down Expand Up @@ -947,7 +967,8 @@ function wpmu_signup_blog_notification(
$user_email,
#[\SensitiveParameter]
$key,
$meta = array()
$meta = array(),
$signup_id = 0
) {
/**
* Filters whether to bypass the new site email notification.
Expand All @@ -968,9 +989,9 @@ function wpmu_signup_blog_notification(

// Send email with activation link.
if ( ! is_subdomain_install() || get_current_network_id() !== 1 ) {
$activate_url = network_site_url( "wp-activate.php?key=$key" );
$activate_url = network_site_url( "wp-activate.php?key=$key&signup_id=$signup_id" );
} else {
$activate_url = "http://{$domain}{$path}wp-activate.php?key=$key"; // @todo Use *_url() API.
$activate_url = "http://{$domain}{$path}wp-activate.php?key=$key&signup_id=$signup_id"; // @todo Use *_url() API.
}

$activate_url = esc_url( $activate_url );
Expand Down Expand Up @@ -1088,7 +1109,8 @@ function wpmu_signup_user_notification(
$user_email,
#[\SensitiveParameter]
$key,
$meta = array()
$meta = array(),
$signup_id = 0
) {
/**
* Filters whether to bypass the email notification for new user sign-up.
Expand Down Expand Up @@ -1139,7 +1161,7 @@ function wpmu_signup_user_notification(
$key,
$meta
),
site_url( "wp-activate.php?key=$key" )
site_url( "wp-activate.php?key=$key&signup_id=$signup_id" )
);

$subject = sprintf(
Expand Down Expand Up @@ -1188,21 +1210,58 @@ function wpmu_signup_user_notification(
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $key The activation key provided to the user.
* @param string $key The activation key provided to the user.
* @param int $signup_id The signup ID.
* @return array|WP_Error An array containing information about the activated user and/or blog.
*/
function wpmu_activate_signup(
#[\SensitiveParameter]
$key
$key,
$signup_id = 0
) {
global $wpdb;
global $wpdb, $wp_hasher;

$signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s", $key ) );
$signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = %s OR signup_id = %d", $key, $signup_id ) );

if ( empty( $signup ) ) {
return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
}

// The format of new keys is <timestamp>:<hashed_key>. If the stored key has no colon,
// it is a legacy plain-text key from before this hashing was introduced.
if ( false === strpos( $signup->activation_key, ':' ) ) {
// Legacy key: compare directly and allow activation for backwards compatibility.
// Pre-upgrade pending activations must continue to work after the site upgrades.
if ( $key !== $signup->activation_key ) {
return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
}
} else {
if ( empty( $wp_hasher ) ) {
require_once ABSPATH . WPINC . '/class-phpass.php';
$wp_hasher = new PasswordHash( 8, true );
}

list( $pass_request_time, $signup_key ) = explode( ':', $signup->activation_key, 2 );

if ( ! $wp_hasher->CheckPassword( $key, $signup_key ) ) {
return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
}

/**
* Filters the expiration time of signup activation keys.
*
* @since 6.9.0
*
* @param int $expiration_duration The expiration time in seconds.
*/
$expiration_duration = apply_filters( 'activate_signup_expiration', DAY_IN_SECONDS );
$expiration_time = $pass_request_time + $expiration_duration;

if ( time() > $expiration_time ) {
return new WP_Error( 'expired_key', __( 'Invalid key' ) );
}
}

if ( $signup->active ) {
if ( empty( $signup->domain ) ) {
return new WP_Error( 'already_active', __( 'The user is already active.' ), $signup );
Expand Down Expand Up @@ -1235,7 +1294,7 @@ function wpmu_activate_signup(
'active' => 1,
'activated' => $now,
),
array( 'activation_key' => $key )
array( 'signup_id' => $signup->signup_id )
);

if ( isset( $user_already_exists ) ) {
Expand Down Expand Up @@ -1277,7 +1336,7 @@ function wpmu_activate_signup(
'active' => 1,
'activated' => $now,
),
array( 'activation_key' => $key )
array( 'signup_id' => $signup->signup_id )
);
}
return $blog_id;
Expand All @@ -1289,7 +1348,7 @@ function wpmu_activate_signup(
'active' => 1,
'activated' => $now,
),
array( 'activation_key' => $key )
array( 'signup_id' => $signup->signup_id )
);

/**
Expand Down
Loading
Loading