Skip to content

Commit 5c0c409

Browse files
Misc changes to the signups and pending accounts.
We are improving how signups and pending accounts are handled in BuddyPress. - activation emails resend are blocked for one hour, by default; - emails are checked if they are already in use in a signup; - `signup` endpoint (https://developer.buddypress.org/bp-rest-api/reference/signup/) returns a useful error when feature is disabled; - `Signup::resend`: Added the ability to resend to a single ID, instead of an array of IDs. Props niftythree and imath. Closes #396 See #9229 and #9145 Fixes #9137 git-svn-id: https://buddypress.svn.wordpress.org/trunk@14071 cdf35c40-ae34-48e0-9cc9-0c9da1808c22
1 parent f15348c commit 5c0c409

File tree

8 files changed

+323
-53
lines changed

8 files changed

+323
-53
lines changed

src/bp-core/bp-core-rest-api.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,41 @@ function bp_rest_api_v1_dispatch_error( $result, $server, $request ) {
392392
);
393393
}
394394
add_filter( 'rest_pre_dispatch', 'bp_rest_api_v1_dispatch_error', 10, 3 );
395+
396+
/**
397+
* Filter the WP REST API response to return a 403 if the signup feature is disabled.
398+
*
399+
* @since 15.0.0
400+
*
401+
* @param mixed $result Response to replace the requested version with. Can be anything
402+
* a normal endpoint can return, or null to not hijack the request.
403+
* @param WP_REST_Server $server Server instance.
404+
* @param WP_REST_Request $request Request used to generate the response.
405+
*
406+
* @return mixed
407+
*/
408+
function bp_rest_api_signup_disabled_feature_dispatch_error( $result, $server, $request ) {
409+
410+
// Bail early if the BP REST plugin is active.
411+
if ( bp_rest_is_plugin_active() ) {
412+
return $result;
413+
}
414+
415+
$route = $request->get_route();
416+
417+
if ( empty( $route ) || ! str_contains( $route, 'buddypress/v2/signup' ) ) {
418+
return $result;
419+
}
420+
421+
// Bail early if signups are allowed.
422+
if ( bp_get_signup_allowed() ) {
423+
return $result;
424+
}
425+
426+
return new WP_Error(
427+
'rest_no_route',
428+
__( 'BuddyPress: The user signup feature is currently disabled. Please activate this feature to proceed.', 'buddypress' ),
429+
array( 'status' => 403 )
430+
);
431+
}
432+
add_filter( 'rest_pre_dispatch', 'bp_rest_api_signup_disabled_feature_dispatch_error', 10, 3 );

src/bp-members/bp-members-functions.php

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,11 +1592,13 @@ function bp_core_get_illegal_names( $value = '' ) {
15921592
*
15931593
* Performs the following checks:
15941594
* - Is the email address well-formed?
1595-
* - Is the email address already used?
1595+
* - Is the email address already used in a user?
1596+
* - Is the email address already used in a signup?
15961597
* - If there are disallowed email domains, is the current domain among them?
1597-
* - If there's an email domain whitelist, is the current domain on it?
1598+
* - If there's an email domain allowlist, is the current domain on it?
15981599
*
15991600
* @since 1.6.2
1601+
* @since 15.0.0 Check if the email address is already used in a signup.
16001602
*
16011603
* @param string $user_email The email being checked.
16021604
* @return bool|array True if the address passes all checks; otherwise an array
@@ -1629,11 +1631,24 @@ function bp_core_validate_email_address( $user_email ) {
16291631
}
16301632
}
16311633

1632-
// Is the email already in use?
1634+
// Is the email already in use in a user?
16331635
if ( email_exists( $user_email ) ) {
16341636
$errors['in_use'] = 1;
16351637
}
16361638

1639+
// Is the email already in use in a signup?
1640+
if ( ! isset( $errors['in_use'] ) ) {
1641+
$signups = BP_Signup::get(
1642+
array( 'user_email' => $user_email )
1643+
);
1644+
1645+
$signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] );
1646+
1647+
if ( $signup ) {
1648+
$errors['in_use'] = 1;
1649+
}
1650+
}
1651+
16371652
return ! empty( $errors ) ? $errors : true;
16381653
}
16391654

@@ -1748,22 +1763,22 @@ function bp_core_validate_user_signup( $user_name, $user_email ) {
17481763

17491764
// Check into signups.
17501765
$signups = BP_Signup::get(
1751-
array(
1752-
'user_login' => $user_name,
1753-
)
1766+
array( 'user_login' => $user_name )
17541767
);
17551768

1756-
$signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] ) ? $signups['signups'][0] : false;
1769+
$signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] );
1770+
$user_name_exists = ( empty( $signup ) && username_exists( $user_name ) ) || ! empty( $signup );
17571771

17581772
// Check if the username has been used already.
1759-
if ( username_exists( $user_name ) || ! empty( $signup ) ) {
1773+
if ( true === $user_name_exists ) {
17601774
$errors->add( 'user_name', __( 'Sorry, that username already exists!', 'buddypress' ) );
17611775
}
17621776

1763-
// Validate the email address and process the validation results into
1764-
// error messages.
1765-
$validate_email = bp_core_validate_email_address( $user_email );
1766-
bp_core_add_validation_error_messages( $errors, $validate_email );
1777+
// Validate the email address.
1778+
bp_core_add_validation_error_messages(
1779+
$errors,
1780+
bp_core_validate_email_address( $user_email )
1781+
);
17671782

17681783
// Assemble the return array.
17691784
$result = array(
@@ -1772,7 +1787,7 @@ function bp_core_validate_user_signup( $user_name, $user_email ) {
17721787
'errors' => $errors,
17731788
);
17741789

1775-
// Apply WPMU legacy filter.
1790+
/** This filter is documented in wp-includes/ms-functions.php */
17761791
$result = apply_filters( 'wpmu_validate_user_signup', $result );
17771792
}
17781793

@@ -2486,6 +2501,7 @@ function bp_core_signup_disable_inactive( $user = null, $username = '', $passwor
24862501
* On the login screen, resends the activation email for a user.
24872502
*
24882503
* @since 2.0.0
2504+
* @since 15.0.0 Return an error when the activation email resend has been blocked temporarily.
24892505
*
24902506
* @global string $error The error message.
24912507
*
@@ -2499,22 +2515,40 @@ function bp_members_login_resend_activation_email() {
24992515
}
25002516

25012517
// Verify nonce.
2502-
if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'bp-resend-activation' ) ) {
2503-
die( 'Security check' );
2518+
if ( ! wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'bp-resend-activation' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2519+
wp_die( esc_html__( 'There was a problem performing this action. Please try again.', 'buddypress' ) );
25042520
}
25052521

2506-
$signup_id = (int) $_GET['id'];
2522+
$signups = BP_Signup::get(
2523+
array( 'include' => (int) $_GET['id'] )
2524+
);
2525+
2526+
// phpcs:disable WordPress.WP.GlobalVariablesOverride.Prohibited
2527+
2528+
if ( empty( $signups['signups'] ) || ! is_array( $signups['signups'] ) || empty( $signups['signups'][0] ) ) {
2529+
$error = __( '<strong>Error</strong>: Invalid signup id.', 'buddypress' );
2530+
return;
2531+
}
2532+
2533+
$signup = $signups['signups'][0];
2534+
2535+
if ( false === BP_Signup::allow_activation_resend( $signup ) ) {
2536+
$error = __( '<strong>Error</strong>: You\'ve reached the limit for resending your account activation email. Please wait a few minutes and try again. If you continue to experience issues, contact support for assistance.', 'buddypress' );
2537+
return;
2538+
}
25072539

25082540
// Resend the activation email.
25092541
// also updates the 'last sent' and '# of emails sent' values.
2510-
$resend = BP_Signup::resend( array( $signup_id ) );
2542+
$resend = BP_Signup::resend( $signup->id );
25112543

25122544
// Add feedback message.
25132545
if ( ! empty( $resend['errors'] ) ) {
25142546
$error = __( '<strong>Error</strong>: Your account has already been activated.', 'buddypress' );
25152547
} else {
25162548
$error = __( 'Activation email resent! Please check your inbox or spam folder.', 'buddypress' );
25172549
}
2550+
2551+
// phpcs:enable WordPress.WP.GlobalVariablesOverride.Prohibited
25182552
}
25192553
add_action( 'login_form_bp-resend-activation', 'bp_members_login_resend_activation_email' );
25202554

src/bp-members/bp-members-template.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3065,7 +3065,7 @@ function bp_signup_allowed() {
30653065
function bp_get_signup_allowed() {
30663066

30673067
/**
3068-
* Filters whether or not new signups are allowed.
3068+
* Filters whether new signups are allowed.
30693069
*
30703070
* @since 1.5.0
30713071
*

src/bp-members/classes/class-bp-members-signup-rest-controller.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -764,16 +764,22 @@ public function activate_item_permissions_check( $request ) {
764764
* @return WP_REST_Response|WP_Error
765765
*/
766766
public function signup_resend_activation_email( $request ) {
767-
$signup_id = $request->get_param( 'id' );
768-
$send = \BP_Signup::resend( array( $signup_id ) );
767+
$signup = $this->get_signup_object( $request->get_param( 'id' ) );
768+
$send = $signup::resend( $signup->id );
769+
770+
if ( empty( $send ) ) {
771+
return new WP_Error(
772+
'bp_rest_signup_resend_activation_email_fail',
773+
__( 'There was a problem performing this action. Please try again.', 'buddypress' ),
774+
array( 'status' => 500 )
775+
);
776+
}
769777

770778
if ( ! empty( $send['errors'] ) ) {
771779
return new WP_Error(
772780
'bp_rest_signup_resend_activation_email_fail',
773781
__( 'Your account has already been activated.', 'buddypress' ),
774-
array(
775-
'status' => 500,
776-
)
782+
array( 'status' => 500 )
777783
);
778784
}
779785

@@ -808,9 +814,15 @@ public function signup_resend_activation_email_permissions_check( $request ) {
808814
$retval = new WP_Error(
809815
'bp_rest_invalid_id',
810816
__( 'Invalid signup id.', 'buddypress' ),
811-
array(
812-
'status' => 404,
813-
)
817+
array( 'status' => 404 )
818+
);
819+
}
820+
821+
if ( true === $retval && false === BP_Signup::allow_activation_resend( $signup ) ) {
822+
$retval = new WP_Error(
823+
'bp_rest_signup_resend_activation_email_fail',
824+
__( 'You\'ve reached the limit for resending your account activation email. Please wait a few minutes and try again. If you continue to experience issues, contact support for assistance.', 'buddypress' ),
825+
array( 'status' => 500 )
814826
);
815827
}
816828

@@ -975,7 +987,7 @@ public function get_signup_object( $identifier ) {
975987
public function check_user_password( $value ) {
976988
$password = (string) $value;
977989

978-
if ( empty( $password ) || false !== strpos( $password, '\\' ) ) {
990+
if ( empty( $password ) || str_contains( $password, '\\' ) ) {
979991
return new WP_Error(
980992
'rest_user_invalid_password',
981993
__( 'Passwords cannot be empty or contain the "\\" character.', 'buddypress' ),

src/bp-members/classes/class-bp-signup.php

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Signups Management class.
44
*
55
* @package BuddyPress
6-
* @subpackage coreClasses
6+
* @subpackage Signup
77
* @since 2.0.0
88
*/
99

@@ -159,7 +159,7 @@ class BP_Signup {
159159
*
160160
* @since 2.0.0
161161
*
162-
* @param integer $signup_id The ID for the signup being queried.
162+
* @param int $signup_id The ID for the signup being queried.
163163
*/
164164
public function __construct( $signup_id = 0 ) {
165165
if ( ! empty( $signup_id ) ) {
@@ -248,8 +248,7 @@ public function populate() {
248248
* Set a boolean to track whether an activation link
249249
* was sent in the last day.
250250
*/
251-
$this->recently_sent = $this->count_sent && ( $diff < 1 * DAY_IN_SECONDS );
252-
251+
$this->recently_sent = $this->count_sent && ( $diff < DAY_IN_SECONDS );
253252
}
254253

255254
/** Static Methods *******************************************************/
@@ -826,23 +825,30 @@ public static function update( $args = array() ) {
826825
* Resend an activation email.
827826
*
828827
* @since 2.0.0
828+
* @since 15.0.0 Added the ability to resend to a single ID.
829829
*
830-
* @param array $signup_ids Single ID or list of IDs to resend.
830+
* @param array|int $signup_ids Single ID or list of IDs to resend.
831831
* @return array
832832
*/
833833
public static function resend( $signup_ids = array() ) {
834-
if ( empty( $signup_ids ) || ! is_array( $signup_ids ) ) {
835-
return false;
834+
if ( empty( $signup_ids ) ) {
835+
return array();
836+
}
837+
838+
if ( ! is_array( $signup_ids ) ) {
839+
$signup_ids = array( $signup_ids );
836840
}
837841

838842
$to_resend = self::get(
839843
array(
840-
'include' => $signup_ids,
844+
'include' => wp_parse_id_list( $signup_ids ),
841845
)
842846
);
843847

844-
if ( ! $signups = $to_resend['signups'] ) {
845-
return false;
848+
$signups = $to_resend['signups'];
849+
850+
if ( ! $signups ) {
851+
return array();
846852
}
847853

848854
$result = array();
@@ -875,7 +881,7 @@ public static function resend( $signup_ids = array() ) {
875881
// Check user status before sending email.
876882
$user_id = email_exists( $signup->user_email );
877883

878-
if ( ! empty( $user_id ) && 2 != self::check_user_status( $user_id ) ) {
884+
if ( ! empty( $user_id ) && 2 !== self::check_user_status( $user_id ) ) {
879885

880886
// Status is not 2, so user's account has been activated.
881887
$result['errors'][ $signup->signup_id ] = array( $signup->user_login, esc_html__( 'the sign-up has already been activated.', 'buddypress' ) );
@@ -885,7 +891,7 @@ public static function resend( $signup_ids = array() ) {
885891

886892
continue;
887893

888-
// Send the validation email.
894+
// Send the validation email.
889895
} else {
890896
$salutation = $signup->user_login;
891897
if ( bp_is_active( 'xprofile' ) && isset( $meta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) {
@@ -906,7 +912,7 @@ public static function resend( $signup_ids = array() ) {
906912
}
907913

908914
/**
909-
* Fires after activation emails are resent.
915+
* Fires after activation email(s) are/is resent.
910916
*
911917
* @since 2.0.0
912918
*
@@ -925,6 +931,44 @@ public static function resend( $signup_ids = array() ) {
925931
return apply_filters( 'bp_core_signup_resend', $result );
926932
}
927933

934+
/**
935+
* Check if an activation email can be resent.
936+
*
937+
* @since 15.0.0
938+
*
939+
* @param BP_Signup $signup The signup object.
940+
* @return bool
941+
*/
942+
public static function allow_activation_resend( $signup ) {
943+
944+
// Bail if the signup is not a BP_Signup object.
945+
if ( ! $signup instanceof BP_Signup ) {
946+
return false;
947+
}
948+
949+
// Allow the activation email to be sent if not already.
950+
if ( ! $signup->recently_sent || ! $signup->count_sent ) {
951+
return true;
952+
}
953+
954+
$sent_at = mysql2date( 'U', $signup->date_sent );
955+
$now = time();
956+
$diff = $now - $sent_at;
957+
958+
/**
959+
* Filters the lock time for the resend activation.
960+
*
961+
* @since 15.0.0
962+
*
963+
* @param float|int $lock_time The lock time for the resend activation. Default: 1 hour.
964+
* @param BP_Signup $signup The signup object.
965+
*/
966+
$lock_time = apply_filters( 'bp_core_signup_resend_activation_lock_time', HOUR_IN_SECONDS, $signup );
967+
968+
// If the activation email was sent less than the lock time ago.
969+
return false === ( $diff < $lock_time );
970+
}
971+
928972
/**
929973
* Activate a pending account.
930974
*

0 commit comments

Comments
 (0)