diff --git a/build/build.xml b/build/build.xml index aa35381650..65b99b14c2 100644 --- a/build/build.xml +++ b/build/build.xml @@ -3,7 +3,7 @@ - + diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index 37fe4a2cb5..8b20e374b1 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -50,6 +50,7 @@
  1. Changelog
      +
    • Changes since 3.3.12-RC1
    • Changes since 3.3.11
    • Changes since 3.3.10
    • Changes since 3.3.10-RC1
    • @@ -168,6 +169,21 @@
      +

      Changes since 3.3.12-RC1

      +

      Bug

      +
        +
      • [PHPBB3-17312] - User last visit gets updated too often
      • +
      +

      Improvement

      +
        +
      • [PHPBB3-17324] - Add template event to notification_dropdown.html
      • +
      +

      Hardening

      +
        +
      • [SECURITY-276] - Prevent resending activation email too often
      • +
      • [SECURITY-278] - Always release cron lock, even invalid task is passed
      • +
      +

      Changes since 3.3.11

      Bug

        diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php index 02412aa526..0301a53c2b 100644 --- a/phpBB/includes/acp/acp_inactive.php +++ b/phpBB/includes/acp/acp_inactive.php @@ -238,10 +238,11 @@ class acp_inactive $messenger->save_queue(); - // Add the remind state to the database + // Add the remind state to the database and increase activation expiration by one day $sql = 'UPDATE ' . USERS_TABLE . ' SET user_reminded = user_reminded + 1, - user_reminded_time = ' . time() . ' + user_reminded_time = ' . time() . ', + user_actkey_expiration = ' . (int) $user::get_token_expiration() . ' WHERE ' . $db->sql_in_set('user_id', $user_ids); $db->sql_query($sql); diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 7a5036f931..21f6542410 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -391,14 +391,18 @@ class acp_users $user_actkey = empty($user_activation_key) ? $user_actkey : $user_activation_key; } - if ($user_row['user_type'] == USER_NORMAL || empty($user_activation_key)) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_actkey = '" . $db->sql_escape($user_actkey) . "' - WHERE user_id = $user_id"; - $db->sql_query($sql); - } + // Always update actkey even if same and also update actkey expiration to 24 hours from now + $sql_ary = [ + 'user_actkey' => $user_actkey, + 'user_actkey_expiration' => $user::get_token_expiration(), + ]; + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . (int) $user_id; + $db->sql_query($sql); + + // Start sending email $messenger = new messenger(false); $messenger->template($email_template, $user_row['user_lang']); diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index ef35ac553a..c41e54098e 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -210,24 +210,23 @@ function user_add($user_row, $cp_data = false, $notifications_data = null) // These are the additional vars able to be specified $additional_vars = array( - 'user_permissions' => '', - 'user_timezone' => $config['board_timezone'], - 'user_dateformat' => $config['default_dateformat'], - 'user_lang' => $config['default_lang'], - 'user_style' => (int) $config['default_style'], - 'user_actkey' => '', - 'user_ip' => '', - 'user_regdate' => time(), - 'user_passchg' => time(), - 'user_options' => 230271, + 'user_permissions' => '', + 'user_timezone' => $config['board_timezone'], + 'user_dateformat' => $config['default_dateformat'], + 'user_lang' => $config['default_lang'], + 'user_style' => (int) $config['default_style'], + 'user_actkey' => '', + 'user_ip' => '', + 'user_regdate' => time(), + 'user_passchg' => time(), + 'user_options' => 230271, // We do not set the new flag here - registration scripts need to specify it - 'user_new' => 0, + 'user_new' => 0, 'user_inactive_reason' => 0, 'user_inactive_time' => 0, 'user_lastmark' => time(), 'user_lastvisit' => 0, - 'user_last_active' => 0, 'user_lastpost_time' => 0, 'user_lastpage' => '', 'user_posts' => 0, diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 87175889ba..36ccd76156 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -196,9 +196,10 @@ class ucp_profile { $notifications_manager = $phpbb_container->get('notification_manager'); $notifications_manager->add_notifications('notification.type.admin_activate_user', array( - 'user_id' => $user->data['user_id'], - 'user_actkey' => $user_actkey, - 'user_regdate' => time(), // Notification time + 'user_id' => $user->data['user_id'], + 'user_actkey' => $user_actkey, + 'user_actkey_expiration' => $user::get_token_expiration(), + 'user_regdate' => time(), // Notification time )); } diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 3f9a74744a..40b14a9b54 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -380,18 +380,19 @@ class ucp_register $passwords_manager = $phpbb_container->get('passwords.manager'); $user_row = array( - 'username' => $data['username'], - 'user_password' => $passwords_manager->hash($data['new_password']), - 'user_email' => $data['email'], - 'group_id' => (int) $group_id, - 'user_timezone' => $data['tz'], - 'user_lang' => $data['lang'], - 'user_type' => $user_type, - 'user_actkey' => $user_actkey, - 'user_ip' => $user->ip, - 'user_regdate' => time(), - 'user_inactive_reason' => $user_inactive_reason, - 'user_inactive_time' => $user_inactive_time, + 'username' => $data['username'], + 'user_password' => $passwords_manager->hash($data['new_password']), + 'user_email' => $data['email'], + 'group_id' => (int) $group_id, + 'user_timezone' => $data['tz'], + 'user_lang' => $data['lang'], + 'user_type' => $user_type, + 'user_actkey' => $user_actkey, + 'user_actkey_expiration' => $user::get_token_expiration(), + 'user_ip' => $user->ip, + 'user_regdate' => time(), + 'user_inactive_reason' => $user_inactive_reason, + 'user_inactive_time' => $user_inactive_time, ); if ($config['new_member_post_limit']) diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php index 7f952af6c3..31e0878663 100644 --- a/phpBB/includes/ucp/ucp_resend.php +++ b/phpBB/includes/ucp/ucp_resend.php @@ -45,7 +45,7 @@ class ucp_resend trigger_error('FORM_INVALID'); } - $sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_inactive_reason + $sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_actkey_expiration, user_inactive_reason FROM ' . USERS_TABLE . " WHERE user_email = '" . $db->sql_escape($email) . "' AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; @@ -73,6 +73,12 @@ class ucp_resend trigger_error('ACCOUNT_DEACTIVATED'); } + // Do not resend activation email if valid one still exists + if (!empty($user_row['user_actkey']) && (int) $user_row['user_actkey_expiration'] >= time()) + { + trigger_error('ACTIVATION_ALREADY_SENT'); + } + // Determine coppa status on group (REGISTERED(_COPPA)) $sql = 'SELECT group_name, group_type FROM ' . GROUPS_TABLE . ' @@ -144,6 +150,8 @@ class ucp_resend $db->sql_freeresult($result); } + $this->update_activation_expiration(); + meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); $message = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? $user->lang['ACTIVATION_EMAIL_SENT_ADMIN'] : $user->lang['ACTIVATION_EMAIL_SENT']; @@ -160,4 +168,23 @@ class ucp_resend $this->tpl_name = 'ucp_resend'; $this->page_title = 'UCP_RESEND'; } + + /** + * Update activation expiration to 1 day from now + * + * @return void + */ + protected function update_activation_expiration(): void + { + global $db, $user; + + $sql_ary = [ + 'user_actkey_expiration' => $user::get_token_expiration(), + ]; + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . (int) $user->id(); + $db->sql_query($sql); + } } diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 7eaecfb874..68a97decb7 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -538,10 +538,10 @@ INSERT INTO phpbb_forums (forum_name, forum_desc, left_id, right_id, parent_id, INSERT INTO phpbb_forums (forum_name, forum_desc, left_id, right_id, parent_id, forum_type, forum_posts_approved, forum_posts_unapproved, forum_posts_softdeleted, forum_topics_approved, forum_topics_unapproved, forum_topics_softdeleted, forum_last_post_id, forum_last_poster_id, forum_last_poster_name, forum_last_poster_colour, forum_last_post_subject, forum_last_post_time, forum_link, forum_password, forum_image, forum_rules, forum_rules_link, forum_rules_uid, forum_desc_uid, prune_freq, prune_days, prune_viewed, forum_parents, forum_flags) VALUES ('{L_FORUMS_TEST_FORUM_TITLE}', '{L_FORUMS_TEST_FORUM_DESC}', 2, 3, 1, 1, 1, 0, 0, 1, 0, 0, 1, 2, 'Admin', 'AA0000', '{L_TOPICS_TOPIC_TITLE}', 972086460, '', '', '', '', '', '', '', 1, 7, 7, '', 48); # -- Users / Anonymous user -INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_jabber, user_actkey, user_newpasswd, user_allow_massemail) VALUES (2, 1, 'Anonymous', 'anonymous', 0, '', '', 'en', 1, 0, '', 0, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', 0); +INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_jabber, user_actkey, user_actkey_expiration, user_newpasswd, user_allow_massemail) VALUES (2, 1, 'Anonymous', 'anonymous', 0, '', '', 'en', 1, 0, '', 0, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', 0, '', 0); # -- username: Admin password: admin (change this or remove it once everything is working!) -INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_jabber, user_actkey, user_newpasswd) VALUES (3, 5, 'Admin', 'admin', 0, '21232f297a57a5a743894a0e4a801fc3', 'admin@yourdomain.com', 'en', 1, 1, 'AA0000', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', ''); +INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_jabber, user_actkey, user_actkey_expiration, user_newpasswd) VALUES (3, 5, 'Admin', 'admin', 0, '21232f297a57a5a743894a0e4a801fc3', 'admin@yourdomain.com', 'en', 1, 1, 'AA0000', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', 0, ''); # -- Groups INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GUESTS', 3, 0, '', 0, '', '', '', 5); diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 25851d738e..71790e499b 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -57,6 +57,7 @@ $lang = array_merge($lang, array( 'ACCOUNT_DEACTIVATED' => 'Your account has been manually deactivated and is only able to be reactivated by an administrator.', 'ACP' => 'Administration Control Panel', 'ACP_SHORT' => 'ACP', + 'ACTIVATION_ALREADY_SENT' => 'The activation email has already been sent to your email address. You can try again after 24 hours. If you continue to have problems activating your account, please contact a board administrator.', 'ACTIVE' => 'active', 'ACTIVE_ERROR' => 'The specified username is currently inactive. If you have problems activating your account, please contact a board administrator.', 'ADMINISTRATOR' => 'Administrator', diff --git a/phpBB/phpbb/console/command/user/add.php b/phpBB/phpbb/console/command/user/add.php index 30ce1ff1d3..f0ad089508 100644 --- a/phpBB/phpbb/console/command/user/add.php +++ b/phpBB/phpbb/console/command/user/add.php @@ -296,18 +296,17 @@ class add extends command { case USER_ACTIVATION_SELF: $email_template = 'user_welcome_inactive'; - $user_actkey = gen_rand_string(mt_rand(6, 10)); break; case USER_ACTIVATION_ADMIN: $email_template = 'admin_welcome_inactive'; - $user_actkey = gen_rand_string(mt_rand(6, 10)); break; default: $email_template = 'user_welcome'; - $user_actkey = ''; break; } + $user_actkey = $this->get_activation_key($user_id); + if (!class_exists('messenger')) { require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); @@ -327,6 +326,35 @@ class add extends command $messenger->send(NOTIFY_EMAIL); } + /** + * Get user activation key + * + * @param int $user_id User ID + * + * @return string User activation key for user + */ + protected function get_activation_key(int $user_id): string + { + $user_actkey = ''; + + if ($this->config['require_activation'] == USER_ACTIVATION_SELF || $this->config['require_activation'] == USER_ACTIVATION_ADMIN) + { + $user_actkey = gen_rand_string(mt_rand(6, 10)); + + $sql_ary = [ + 'user_actkey' => $user_actkey, + 'user_actkey_expiration' => \phpbb\user::get_token_expiration(), + ]; + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . (int) $user_id; + $this->db->sql_query($sql); + } + + return $user_actkey; + } + /** * Helper to translate questions to the user * diff --git a/phpBB/phpbb/cron/event/cron_runner_listener.php b/phpBB/phpbb/cron/event/cron_runner_listener.php index 0c5c6555e6..b4a8e3538f 100644 --- a/phpBB/phpbb/cron/event/cron_runner_listener.php +++ b/phpBB/phpbb/cron/event/cron_runner_listener.php @@ -85,9 +85,8 @@ class cron_runner_listener implements EventSubscriberInterface { $task->run(); } - - $this->cron_lock->release(); } + $this->cron_lock->release(); } } diff --git a/phpBB/phpbb/db/migration/data/v33x/add_resend_activation_expiration.php b/phpBB/phpbb/db/migration/data/v33x/add_resend_activation_expiration.php new file mode 100644 index 0000000000..9ebbe9811a --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v33x/add_resend_activation_expiration.php @@ -0,0 +1,48 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v33x; + +use phpbb\db\migration\migration; + +class add_resend_activation_expiration extends migration +{ + public static function depends_on(): array + { + return [ + '\phpbb\db\migration\data\v33x\v3311', + ]; + } + + public function update_schema(): array + { + return [ + 'add_columns' => [ + $this->table_prefix . 'users' => [ + 'user_actkey_expiration' => ['TIMESTAMP', 0, 'after' => 'user_actkey'], + ], + ], + ]; + } + + public function revert_schema(): array + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'users' => [ + 'user_actkey_expiration', + ], + ], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v33x/v3312.php b/phpBB/phpbb/db/migration/data/v33x/v3312.php new file mode 100644 index 0000000000..36e78b95ef --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v33x/v3312.php @@ -0,0 +1,38 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v33x; + +class v3312 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.12', '>='); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v33x\add_resend_activation_expiration', + '\phpbb\db\migration\data\v33x\add_user_last_active', + '\phpbb\db\migration\data\v33x\v3312rc1', + ]; + } + + public function update_data() + { + return [ + ['config.update', ['version', '3.3.12']], + ]; + } +} diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index feafc3762e..64c43a5d00 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -242,7 +242,7 @@ class reset_password $sql_ary = [ 'reset_token' => $reset_token, - 'reset_token_expiration' => strtotime('+1 day'), + 'reset_token_expiration' => $this->user::get_token_expiration(), ]; $sql = 'UPDATE ' . $this->users_table . ' diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php index 20a54fe9e4..c486161a05 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -59,7 +59,7 @@ class user extends \phpbb\session * @param \phpbb\language\language $lang phpBB's Language loader * @param string $datetime_class Class name of datetime class */ - function __construct(\phpbb\language\language $lang, $datetime_class) + public function __construct(\phpbb\language\language $lang, $datetime_class) { global $phpbb_root_path; @@ -80,6 +80,16 @@ class user extends \phpbb\session return $this->is_setup_flag; } + /** + * Get expiration time for user tokens, e.g. activation or reset password tokens + * + * @return int Expiration for user tokens + */ + public static function get_token_expiration(): int + { + return strtotime('+1 day') ?: 0; + } + /** * Magic getter for BC compatibility * diff --git a/tests/auth/provider_apache_test.php b/tests/auth/provider_apache_test.php index cd9040ca28..cdccd2a358 100644 --- a/tests/auth/provider_apache_test.php +++ b/tests/auth/provider_apache_test.php @@ -167,6 +167,7 @@ class phpbb_auth_provider_apache_test extends phpbb_database_test_case 'user_sig_bbcode_bitfield' => '', 'user_jabber' => '', 'user_actkey' => '', + 'user_actkey_expiration' => 0, 'user_newpasswd' => '', 'user_form_salt' => '', 'user_new' => 1, diff --git a/tests/functional/user_password_reset_test.php b/tests/functional/user_password_reset_test.php index eb6631bf28..7e15aca56f 100644 --- a/tests/functional/user_password_reset_test.php +++ b/tests/functional/user_password_reset_test.php @@ -18,10 +18,14 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca { protected $user_data; + protected const TEST_USER = 'reset-password-test-user'; + + protected const TEST_EMAIL = 'reset-password-test-user@test.com'; + public function test_password_reset() { $this->add_lang('ucp'); - $user_id = $this->create_user('reset-password-test-user', 'reset-password-test-user@test.com'); + $user_id = $this->create_user(self::TEST_USER, self::TEST_EMAIL); // test without email $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}"); @@ -41,13 +45,13 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca // test with correct email $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); $form = $crawler->selectButton('submit')->form(array( - 'email' => 'reset-password-test-user@test.com', + 'email' => self::TEST_EMAIL, )); $crawler = self::submit($form); $this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text()); // Check if columns in database were updated for password reset - $this->get_user_data('reset-password-test-user'); + $this->get_user_data(self::TEST_USER); $this->assertNotEmpty($this->user_data['reset_token']); $this->assertNotEmpty($this->user_data['reset_token_expiration']); $reset_token = $this->user_data['reset_token']; @@ -56,31 +60,31 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca // Check that reset token is only created once per day $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); $form = $crawler->selectButton('submit')->form(array( - 'email' => 'reset-password-test-user@test.com', + 'email' => self::TEST_EMAIL, )); $crawler = self::submit($form); $this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text()); - $this->get_user_data('reset-password-test-user'); + $this->get_user_data(self::TEST_USER); $this->assertNotEmpty($this->user_data['reset_token']); $this->assertNotEmpty($this->user_data['reset_token_expiration']); $this->assertEquals($reset_token, $this->user_data['reset_token']); $this->assertEquals($reset_token_expiration, $this->user_data['reset_token_expiration']); // Create another user with the same email - $this->create_user('reset-password-test-user1', 'reset-password-test-user@test.com'); + $this->create_user('reset-password-test-user1', self::TEST_EMAIL); // Test that username is now also required $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); $form = $crawler->selectButton('submit')->form(array( - 'email' => 'reset-password-test-user@test.com', + 'email' => self::TEST_EMAIL, )); $crawler = self::submit($form); $this->assertContainsLang('EMAIL_NOT_UNIQUE', $crawler->text()); // Provide both username and email $form = $crawler->selectButton('submit')->form(array( - 'email' => 'reset-password-test-user@test.com', + 'email' => self::TEST_EMAIL, 'username' => 'reset-password-test-user1', )); $crawler = self::submit($form); @@ -95,7 +99,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca public function test_login_after_reset() { - $this->login('reset-password-test-user'); + $this->login(self::TEST_USER); } public function data_reset_user_password() @@ -117,7 +121,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca public function test_reset_user_password($expected, $user_id, $token) { $this->add_lang('ucp'); - $this->get_user_data('reset-password-test-user'); + $this->get_user_data(self::TEST_USER); $user_id = !$user_id ? $this->user_data['user_id'] : $user_id; $token = !$token ? $this->user_data['reset_token'] : $token; @@ -131,8 +135,8 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca { $form = $crawler->filter('input[type=submit]')->form(); $values = array_merge($form->getValues(), [ - 'new_password' => 'reset-password-test-user', - 'new_password_confirm' => 'reset-password-test-user', + 'new_password' => self::TEST_USER, + 'new_password_confirm' => self::TEST_USER, ]); $crawler = self::submit($form, $values); $this->assertContainsLang('PASSWORD_RESET', $crawler->text()); @@ -146,7 +150,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca $this->assertStringContainsString($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text()); $form = $crawler->selectButton($this->lang('LOGIN'))->form(); - $crawler = self::submit($form, array('username' => 'reset-password-test-user', 'password' => 'reset-password-test-user')); + $crawler = self::submit($form, array('username' => self::TEST_USER, 'password' => self::TEST_USER)); $this->assertStringNotContainsString($this->lang('LOGIN'), $crawler->filter('.navbar')->text()); $cookies = self::$cookieJar->all(); @@ -167,17 +171,17 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca $form = $crawler->selectButton($this->lang('LOGIN'))->form(); // Try logging in with the old password - $crawler = self::submit($form, array('username' => 'reset-password-test-user', 'password' => 'reset-password-test-userreset-password-test-user')); + $crawler = self::submit($form, array('username' => self::TEST_USER, 'password' => 'reset-password-test-userreset-password-test-user')); $this->assertStringContainsString($this->lang('LOGIN_ERROR_PASSWORD', '', ''), $crawler->filter('html')->text()); } /** * @depends test_login */ - public function test_acivateAfterDeactivate() + public function test_activateAfterDeactivate() { // User is active, actkey should not exist - $this->get_user_data('reset-password-test-user'); + $this->get_user_data(self::TEST_USER); $this->assertEmpty($this->user_data['user_actkey']); $this->login(); @@ -189,7 +193,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca $this->assertContainsLang('FIND_USERNAME', $crawler->filter('html')->text()); $form = $crawler->selectButton('Submit')->form(); - $crawler = self::submit($form, array('username' => 'reset-password-test-user')); + $crawler = self::submit($form, array('username' => self::TEST_USER)); // Deactivate account and go back to overview of current user $this->assertContainsLang('USER_TOOLS', $crawler->filter('html')->text()); @@ -201,7 +205,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca $crawler = self::request('GET', preg_replace('#(.+)(adm/index.php.+)#', '$2', $link->getUri())); // Ensure again that actkey is empty after deactivation - $this->get_user_data('reset-password-test-user'); + $this->get_user_data(self::TEST_USER); $this->assertEmpty($this->user_data['user_actkey']); // Force reactivation of account and check that act key is not empty anymore @@ -210,8 +214,50 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca $crawler = self::submit($form, array('action' => 'reactivate')); $this->assertContainsLang('FORCE_REACTIVATION_SUCCESS', $crawler->filter('html')->text()); - $this->get_user_data('reset-password-test-user'); + $this->get_user_data(self::TEST_USER); $this->assertNotEmpty($this->user_data['user_actkey']); + + // Logout and try resending activation email, account is deactivated though + $this->logout(); + $this->add_lang('ucp'); + + $crawler = self::request('GET', 'ucp.php?mode=resend_act'); + $this->assertContainsLang('UCP_RESEND', $crawler->filter('html')->text()); + $form = $crawler->filter('input[name=submit]')->selectButton('Submit')->form(); + $crawler = self::submit($form, [ + 'username' => self::TEST_USER, + 'email' => self::TEST_EMAIL, + ]); + $this->assertContainsLang('ACCOUNT_DEACTIVATED', $crawler->filter('html')->text()); + } + + /** + * @depends test_activateAfterDeactivate + */ + public function test_resendActivation() + { + // User is deactivated and should have actkey, actkey should not exist + $this->get_user_data(self::TEST_USER); + $this->assertNotEmpty($this->user_data['user_actkey']); + + // Change reason for inactivity + $db = $this->get_db(); + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_inactive_reason = ' . INACTIVE_REMIND . ' + WHERE user_id = ' . (int) $this->user_data['user_id']; + $db->sql_query($sql); + + $this->add_lang('ucp'); + + $crawler = self::request('GET', 'ucp.php?mode=resend_act'); + $this->assertContainsLang('UCP_RESEND', $crawler->filter('html')->text()); + $form = $crawler->filter('input[name=submit]')->selectButton('Submit')->form(); + $crawler = self::submit($form, [ + 'username' => self::TEST_USER, + 'email' => self::TEST_EMAIL, + ]); + $this->assertContainsLang('ACTIVATION_ALREADY_SENT', $crawler->filter('html')->text()); } protected function get_user_data($username)