sensitive-changed.diff (22,979 bytes)
diff --git a/lang/EN/cns.ini b/lang/EN/cns.ini
index 77b9741..0ae8b30 100644
--- a/lang/EN/cns.ini
+++ b/lang/EN/cns.ini
@@ -528,8 +528,6 @@ PASSWORD_TOO_SHORT=The password must be at least {1} {1|character|characters}
PASSWORD_TOO_LONG=The password must be at most {1} {1|character|characters}
USERNAME_NUMERIC=Numeric usernames are not permitted
USERNAME_PASSWORD_WHITESPACE=You must not use whitespace (e.g. spaces or tabs) in your username or password
-USERNAME_CHANGED_MAIL_SUBJECT=Your username has been changed
-USERNAME_CHANGED_MAIL=Your username on {1} has been changed to '{2}'.\nYou will need to use this username for future logins.
STAFF_USERNAME_CHANGED_MAIL_SUBJECT={1} is now {2}
STAFF_USERNAME_CHANGED_MAIL=The username on {1} has been changed to '{2}'.
BAN_MEMBER=Ban member
@@ -690,9 +688,6 @@ DOC_DELETE_LURKERS=Lurkers are members that have registered but do not contribut
SECRET_GROUP=(Secret usergroup #{1})
HIDDEN_USERGROUP=Hidden usergroup
DESCRIPTION_GROUP_HIDDEN=Whether the name and membership-list of this usergroup is hidden (from those who do not have the “See hidden usergroups and their membership” privilege). If you put members in this as a primary usergroup then the member's presence in a usergroup named “unknown” will be revealed along with the rank image.
-PASSWORD_CHANGED_MAIL_SUBJECT=Your password has been changed
-PASSWORD_CHANGED_MAIL_BODY=Your [b]{1}[/b] password has been changed.\n\nThis is a courtesy notice: no response is needed.\n\nIf you did not make this change and you have not requested it, you may wish to get in contact with the staff (in case your account has been hijacked).{2}
-PASSWORD_CHANGED_MAIL_BODY_2=\n\nThe Password Change request was made from:\nIP address: {1}
RANK_IMAGE_PRI_ONLY=Rank image for primary members only
RANK_IMAGE_PRI_ONLY_DESCRIPTION=Whether the rank image will only be shown for members who have this usergroup as their primary usergroup.
FORUMS_AND_MEMBERS=Members, usergroups and forums
@@ -808,8 +803,6 @@ NOTIFICATION_TYPE_cns_new_pt=New Private Topic/Post with you
NOTIFICATION_TYPE_cns_topic=Forum topic activity
NOTIFICATION_TYPE_cns_group_join_request=Application to join your usergroup
NOTIFICATION_TYPE_cns_group_declined=Your usergroup join request was declined
-NOTIFICATION_TYPE_cns_username_changed=Your username changed
-NOTIFICATION_TYPE_cns_password_changed=Your password changed
NOTIFICATION_TYPE_cns_friend_birthday=Your friend's birthday is today
NOTIFICATION_TYPE_cns_birthday=A member's birthday today
NOTIFICATION_TYPE_cns_club=New club added
@@ -884,3 +877,13 @@ DESCRIPTION_ENABLE_AUTO_MARK_READ=Whether to mark topics as read automatically o
AVATARS_CARTOONS=Cartoons
AVATARS_THEMATIC=Hobbies
AVATARS_MISC=Miscellaneous
+
+SECURITY_ASPECT_CHANGED_SUBJECT=Changes to sensitive areas of your account
+SECURITY_ASPECT_CHANGED_BODY=Hello {1},\n\nThis is an automatic courtesy e-mail to inform you that sensitive area(s) of your account on {3} have just been changed.\n\n{4}\n\nThe change(s) were made by {{{2}}}.\n\nIf you think these changes were not made legitimately, reply to this e-mail (just in case your account has been hijacked).{5}
+SECURITY_ASPECT_CHANGED_BODY_2=\n\nThe changes were made from:\nIP address: {1}
+SECURITY_ASPECT_CHANGED__USERNAME= - Your username from “{1}” to “{2}”.
+SECURITY_ASPECT_CHANGED__EMAIL_ADDRESS= - Your e-mail address from “{1}” to “{2}”.
+SECURITY_ASPECT_CHANGED__PASSWORD= - Your password.
+SECURITY_ASPECT_CHANGED__PHONE_NUMBER= - Your phone number from “{1}” to “{2}”.
+SENSITIVE_CHANGE_ALERT=Sensitive change alert
+DESCRIPTION_SENSITIVE_CHANGE_ALERT=Send an alert to the account owner if any sensitive account details are changed in this edit, with your username referenced.
diff --git a/sources/cns_members.php b/sources/cns_members.php
index 5e34af3..978c744 100644
--- a/sources/cns_members.php
+++ b/sources/cns_members.php
@@ -389,7 +389,7 @@ function find_cpf_field_id($title)
/**
* Get the ID for a special CPF if we only know the title. Warning: Only use this with custom code, never core code! It assumes a single language and that fields aren't renamed.
*
- * @param SHORT_TEXT $title The title.
+ * @param SHORT_TEXT $title The title, including cms_ prefix.
* @return ?AUTO_LINK The ID (null: could not find).
*/
function find_cms_cpf_field_id($title)
diff --git a/sources/cns_members_action2.php b/sources/cns_members_action2.php
index a270236..dc9ea13 100644
--- a/sources/cns_members_action2.php
+++ b/sources/cns_members_action2.php
@@ -713,9 +713,14 @@ function cns_get_member_fields_settings($mini_mode = true, $member_id = null, $g
if (get_option('enable_highlight_name') == '1') {
$fields->attach(form_input_tick(do_lang_tempcode('HIGHLIGHTED_NAME'), do_lang_tempcode(addon_installed('pointstore') ? 'DESCRIPTION_HIGHLIGHTED_NAME_P' : 'DESCRIPTION_HIGHLIGHTED_NAME'), 'highlighted_name', $highlighted_name == 1));
}
- if ((!is_null($member_id)) && ($member_id != get_member())) {// Can't ban someone new, and can't ban yourself
+ if ((!is_null($member_id)) && ($member_id != get_member())) { // Can't ban someone new, and can't ban yourself
$fields->attach(form_input_tick(do_lang_tempcode('BANNED'), do_lang_tempcode('DESCRIPTION_MEMBER_BANNED'), 'is_perm_banned', $is_perm_banned == 1));
}
+
+ if (($member_id !== null) && ($member_id != get_member())) {
+ $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '03452238c372edd0b11c11a05feb6267', 'TITLE' => do_lang_tempcode('ACTIONS'))));
+ $fields->attach(form_input_tick(do_lang_tempcode('SENSITIVE_CHANGE_ALERT'), do_lang_tempcode('DESCRIPTION_SENSITIVE_CHANGE_ALERT'), 'sensitive_change_alert', true));
+ }
}
if (addon_installed('content_reviews')) {
@@ -876,16 +881,21 @@ function cns_get_member_fields_profile($mini_mode = true, $member_id = null, $gr
* @param ?ID_TEXT $password_compatibility_scheme Password compatibility scheme (null: don't change)
* @param boolean $skip_checks Whether to skip security checks and most of the change-triggered emails
*/
-function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $dob_month, $dob_year, $timezone, $primary_group, $custom_fields, $theme, $reveal_age, $views_signatures, $auto_monitor_contrib_content, $language, $allow_emails, $allow_emails_from_staff, $validated = null, $username = null, $password = null, $highlighted_name = null, $pt_allow = '*', $pt_rules_text = '', $on_probation_until = null, $auto_mark_read = null, $join_time = null, $avatar_url = null, $signature = null, $is_perm_banned = null, $photo_url = null, $photo_thumb_url = null, $salt = null, $password_compatibility_scheme = null, $skip_checks = false)
+function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $dob_month, $dob_year, $timezone, $primary_group, $custom_fields, $theme, $reveal_age, $views_signatures, $auto_monitor_contrib_content, $language, $allow_emails, $allow_emails_from_staff, $validated = null, $username = null, $password = null, $highlighted_name = null, $pt_allow = '*', $pt_rules_text = '', $on_probation_until = null, $auto_mark_read = null, $join_time = null, $avatar_url = null, $signature = null, $is_perm_banned = null, $photo_url = null, $photo_thumb_url = null, $salt = null, $password_compatibility_scheme = null, $skip_checks = false, $sensitive_change_alert = null)
{
+ if ($sensitive_change_alert === null) {
+ $sensitive_change_alert = !$skip_checks;
+ }
+
require_code('type_sanitisation');
require_code('cns_members_action');
$update = array();
- if (!$skip_checks) {
- $old_email_address = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_email_address');
+ $old_email_address = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_email_address');
+ $old_username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
+ if (!$skip_checks) {
$email_address_required = member_field_is_required($member_id, 'email_address');
if ((!is_null($email_address)) && ($email_address != '') && ($email_address != STRING_MAGIC_NULL) && (!is_email_address($email_address))) {
@@ -960,11 +970,21 @@ function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $
// Set custom profile field values
$all_fields_types = collapse_2d_complexity('id', 'cf_type', $all_fields);
$changes = array();
+ $phone_number_field = find_cms_cpf_field_id('cms_mobile_phone_number');
+ if ($phone_number_field !== null) {
+ $phone_number = null;
+ $old_values = $GLOBALS['FORUM_DRIVER']->get_custom_fields($member_id);
+ $old_phone_number = $old_values['mobile_phone_number'];
+ }
foreach ($custom_fields as $field_id => $value) {
if (!array_key_exists($field_id, $all_fields_types)) {
continue; // Trying to set a field we're not allowed to (doesn't apply to our group)
}
+ if ($field_id === $phone_number_field) {
+ $phone_number = $value;
+ }
+
$change = cns_set_custom_field($member_id, $field_id, $value, $all_fields_types[$field_id], true);
if (!is_null($change)) {
$changes = array_merge($changes, $change);
@@ -1051,7 +1071,6 @@ function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $
$update['m_photo_thumb_url'] = $photo_thumb_url;
}
- $old_username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
if ((!is_null($username)) && (!is_null($old_username)) && ($username != $old_username) && (($skip_checks) || (has_actual_page_access(get_member(), 'admin_cns_members')) || (has_privilege($member_id, 'rename_self')))) { // Username change
$update['m_username'] = $username;
@@ -1070,10 +1089,6 @@ function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $
require_code('notifications');
- $subject = do_lang('USERNAME_CHANGED_MAIL_SUBJECT', $username, $old_username, null, get_lang($member_id));
- $mail = do_notification_lang('USERNAME_CHANGED_MAIL', comcode_escape(get_site_name()), comcode_escape($username), comcode_escape($old_username), get_lang($member_id));
- dispatch_notification('cns_username_changed', null, $subject, $mail, array($member_id));
-
$subject = do_lang('STAFF_USERNAME_CHANGED_MAIL_SUBJECT', $username, $old_username, null, get_site_default_lang());
$mail = do_notification_lang('STAFF_USERNAME_CHANGED_MAIL', comcode_escape(get_site_name()), comcode_escape($username), comcode_escape($old_username), get_site_default_lang());
dispatch_notification('cns_username_changed_staff', null, $subject, $mail, null, get_member(), 3, false, false, null, null, '', '', '', '', null, true);
@@ -1087,22 +1102,6 @@ function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $
if (!is_null($password)) { // Password change
// Security, clear out sessions from other people on this user - just in case the reset is due to suspicious activity
$GLOBALS['SITE_DB']->query('DELETE FROM ' . get_table_prefix() . 'sessions WHERE member_id=' . strval($member_id) . ' AND ' . db_string_not_equal_to('the_session', get_session_id()));
-
- if (!$skip_checks) {
- if (($member_id == get_member()) || (get_value('disable_password_change_notifications_for_staff') !== '1')) {
- if (get_page_name() != 'admin_cns_members') {
- require_code('notifications');
-
- $part_b = '';
- if (!has_actual_page_access(get_member(), 'admin_cns_members')) {
- $part_b = do_lang('PASSWORD_CHANGED_MAIL_BODY_2', get_ip_address());
- }
- $mail = do_notification_lang('PASSWORD_CHANGED_MAIL_BODY', get_site_name(), $part_b, null, get_lang($member_id));
-
- dispatch_notification('cns_password_changed', null, do_lang('PASSWORD_CHANGED_MAIL_SUBJECT', null, null, null, get_lang($member_id)), $mail, array($member_id), null, 2);
- }
- }
- }
}
if (!is_null($validated)) {
$update['m_validated_email_confirm_code'] = '';
@@ -1144,19 +1143,49 @@ function cns_edit_member($member_id, $email_address, $preview_posts, $dob_day, $
require_code('mail');
$_login_url = build_url(array('page' => 'login'), get_module_zone('login'), null, false, false, true);
$login_url = $_login_url->evaluate();
- $_username = $GLOBALS['CNS_DRIVER']->get_member_row_field($member_id, 'm_username');
// NB: Same mail also sent in settings.php (quick-validate feature)
$vm_subject = do_lang('VALIDATED_MEMBER_SUBJECT', get_site_name(), null, get_lang($member_id));
- $vm_body = do_lang('MEMBER_VALIDATED', get_site_name(), $_username, $login_url, get_lang($member_id));
- mail_wrap($vm_subject, $vm_body, array($email_address), $_username, $login_url, '', 3, null, false, null, false, false, false, 'MAIL', false, null, null, $join_time);
+ $vm_body = do_lang('MEMBER_VALIDATED', get_site_name(), $old_username, $login_url, get_lang($member_id));
+ mail_wrap($vm_subject, $vm_body, array($email_address), $old_username, '', '', 2, null, false, null, false, false, false, 'MAIL', false, null, null, $join_time);
}
- $old_email_address = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_email_address');
- if ($old_email_address != $email_address) {
- $GLOBALS['FORUM_DB']->query_update('f_invites', array('i_email_address' => $old_email_address), array('i_email_address' => $email_address));
+ // E-mail OLD e-mail address to inform of sensitive changes
+ $username_changed = ($username !== null) && ($username !== $old_username);
+ $email_address_changed = ($email_address !== null) && ($email_address !== $old_email_address);
+ $password_changed = ($password !== null);
+ $phone_number_changed = ($phone_number_field !== null) && ($phone_number !== null) && ($old_phone_number !== $phone_number);
+ if (($username_changed || $email_address_changed || $password_changed || $phone_number_changed) && ($sensitive_change_alert)) {
+ $current_username = $GLOBALS['FORUM_DRIVER']->get_username(get_member());
+
+ $_sensitive_changes = array();
+ if ($username_changed) {
+ $_sensitive_changes[] = do_lang('SECURITY_ASPECT_CHANGED__USERNAME', $old_username, $username);
+ }
+ if ($email_address_changed) {
+ $_sensitive_changes[] = do_lang('SECURITY_ASPECT_CHANGED__EMAIL_ADDRESS', $old_email_address, $email_address);
+ }
+ if ($password_changed) {
+ $_sensitive_changes[] = do_lang('SECURITY_ASPECT_CHANGED__PASSWORD');
+ }
+ if ($phone_number_changed) {
+ $_sensitive_changes[] = do_lang('SECURITY_ASPECT_CHANGED__PHONE_NUMBER', $old_phone_number, $phone_number);
+ }
+ $sensitive_changes = implode("\n", $_sensitive_changes);
+
+ $part_b = '';
+ if (!has_actual_page_access(get_member(), 'admin_cns_members')) { // If change not by an admin
+ $part_b = do_lang('SECURITY_ASPECT_CHANGED_BODY_2', get_ip_address());
+ }
+
+ $cm_subject = do_lang('SECURITY_ASPECT_CHANGED_SUBJECT', $old_username, $current_username, array(get_site_name()));
+ $cm_body = do_lang('SECURITY_ASPECT_CHANGED_BODY', $old_username, $current_username, array(get_site_name(), $sensitive_changes, $part_b));
+
+ if ($old_email_address != '') {
+ require_code('mail');
+ mail_wrap($cm_subject, $cm_body, array($old_email_address), $old_username, '', '', 1, null, false, null, false, false, false, 'MAIL', true, null, null, $join_time);
+ }
}
- $old_email_address = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_email_address');
if ($old_email_address != $email_address) {
$GLOBALS['FORUM_DB']->query_update('f_invites', array('i_email_address' => $old_email_address), array('i_email_address' => $email_address));
}
diff --git a/sources/hooks/systems/addon_registry/core_cns.php b/sources/hooks/systems/addon_registry/core_cns.php
index 6b4ad15..501d414 100644
--- a/sources/hooks/systems/addon_registry/core_cns.php
+++ b/sources/hooks/systems/addon_registry/core_cns.php
@@ -154,7 +154,6 @@ class Hook_addon_registry_core_cns
'sources/hooks/systems/content_meta_aware/topic.php',
'sources/hooks/systems/content_meta_aware/post.php',
'sources/hooks/modules/admin_import/emoticons.php',
- 'sources/hooks/systems/notifications/cns_password_changed.php',
'sources/hooks/systems/snippets/member_tooltip.php',
'sources/hooks/systems/notifications/cns_rank_promoted.php',
'sources/hooks/systems/snippets/exists_email.php',
@@ -191,7 +190,6 @@ class Hook_addon_registry_core_cns
'sources/hooks/systems/config/require_new_member_validation.php',
'sources/hooks/systems/config/restricted_usernames.php',
'sources/hooks/systems/config/show_first_join_page.php',
- 'sources/hooks/systems/notifications/cns_username_changed.php',
'sources/hooks/systems/notifications/cns_group_join_request.php',
'sources/hooks/systems/notifications/cns_group_declined.php',
'sources/hooks/systems/notifications/cns_birthday.php',
diff --git a/sources/hooks/systems/notifications/cns_password_changed.php b/sources/hooks/systems/notifications/cns_password_changed.php
deleted file mode 100644
index f4dad7e..0000000
--- a/sources/hooks/systems/notifications/cns_password_changed.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php /*
-
- Composr
- Copyright (c) ocProducts, 2004-2016
-
- See text/EN/licence.txt for full licencing information.
-
-
- NOTE TO PROGRAMMERS:
- Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
- **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****
-
-*/
-
-/**
- * @license http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
- * @copyright ocProducts Ltd
- * @package core_cns
- */
-
-/**
- * Hook class.
- */
-class Hook_notification_cns_password_changed extends Hook_Notification
-{
- /**
- * Get a list of all the notification codes this hook can handle.
- * (Addons can define hooks that handle whole sets of codes, so hooks are written so they can take wide authority)
- *
- * @return array List of codes (mapping between code names, and a pair: section and labelling for those codes)
- */
- public function list_handled_codes()
- {
- $list = array();
- $list['cns_password_changed'] = array(do_lang('MEMBERS'), do_lang('cns:NOTIFICATION_TYPE_cns_password_changed'));
- return $list;
- }
-}
diff --git a/sources/hooks/systems/notifications/cns_username_changed.php b/sources/hooks/systems/notifications/cns_username_changed.php
deleted file mode 100644
index 13dc39d..0000000
--- a/sources/hooks/systems/notifications/cns_username_changed.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php /*
-
- Composr
- Copyright (c) ocProducts, 2004-2016
-
- See text/EN/licence.txt for full licencing information.
-
-
- NOTE TO PROGRAMMERS:
- Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
- **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****
-
-*/
-
-/**
- * @license http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
- * @copyright ocProducts Ltd
- * @package core_cns
- */
-
-/**
- * Hook class.
- */
-class Hook_notification_cns_username_changed extends Hook_Notification
-{
- /**
- * Get a list of all the notification codes this hook can handle.
- * (Addons can define hooks that handle whole sets of codes, so hooks are written so they can take wide authority)
- *
- * @return array List of codes (mapping between code names, and a pair: section and labelling for those codes)
- */
- public function list_handled_codes()
- {
- $list = array();
- $list['cns_username_changed'] = array(do_lang('MEMBERS'), do_lang('cns:NOTIFICATION_TYPE_cns_username_changed'));
- return $list;
- }
-}
diff --git a/sources/hooks/systems/profiles_tabs_edit/settings.php b/sources/hooks/systems/profiles_tabs_edit/settings.php
index 121cdbd..c42ad25 100644
--- a/sources/hooks/systems/profiles_tabs_edit/settings.php
+++ b/sources/hooks/systems/profiles_tabs_edit/settings.php
@@ -193,7 +193,12 @@ class Hook_profiles_tabs_edit_settings
}
}
- cns_edit_member($member_id_of, $email_address, $preview_posts, $dob_day, $dob_month, $dob_year, $timezone, $primary_group, $actual_custom_fields, $theme, post_param_integer('reveal_age', fractional_edit() ? INTEGER_MAGIC_NULL : 0), $views_signatures, $auto_monitor_contrib_content, post_param_string('language', fractional_edit() ? STRING_MAGIC_NULL : null), post_param_integer('allow_emails', fractional_edit() ? INTEGER_MAGIC_NULL : 0), post_param_integer('allow_emails_from_staff', fractional_edit() ? INTEGER_MAGIC_NULL : 0), $validated, $username, $password, $highlighted_name, $pt_allow, $pt_rules_text, $on_probation_until, $auto_mark_read);
+ $sensitive_change_alert = true;
+ if ((has_privilege($member_id_viewing, 'member_maintenance')) && ($member_id_viewing != $member_id_of) && (post_param_integer('sensitive_change_alert', 0) == 0)) {
+ $sensitive_change_alert = false;
+ }
+
+ cns_edit_member($member_id_of, $email_address, $preview_posts, $dob_day, $dob_month, $dob_year, $timezone, $primary_group, $actual_custom_fields, $theme, post_param_integer('reveal_age', fractional_edit() ? INTEGER_MAGIC_NULL : 0), $views_signatures, $auto_monitor_contrib_content, post_param_string('language', fractional_edit() ? STRING_MAGIC_NULL : null), post_param_integer('allow_emails', fractional_edit() ? INTEGER_MAGIC_NULL : 0), post_param_integer('allow_emails_from_staff', fractional_edit() ? INTEGER_MAGIC_NULL : 0), $validated, $username, $password, $highlighted_name, $pt_allow, $pt_rules_text, $on_probation_until, $auto_mark_read, null, null, null, null, null, null, null, null, false, $sensitive_change_alert);
if (addon_installed('content_reviews')) {
require_code('content_reviews2');