Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New password generation method: send user email # 15461 #16519

Merged
merged 1 commit into from
Aug 30, 2024
Merged
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
6 changes: 3 additions & 3 deletions core/lexicon/en/user.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
$_lang['password_gen_specify'] = 'Let me specify the password:';
$_lang['password_method'] = 'Password notification method';
$_lang['password_method_screen'] = 'Show the new password on screen.';
$_lang['password_gen_user_email_specify'] = 'Let the user choose their own password via email';
$_lang['notify_new_user'] = 'Email this user about their new login for this website.';
$_lang['password_new'] = 'New Password';
$_lang['password_notification'] = 'Password Notification';
Expand Down Expand Up @@ -197,6 +198,5 @@
$_lang['users'] = 'Users';
$_lang['user_createdon'] = 'Created On';
$_lang['user_createdon_desc'] = 'The date the user was created.';

// Renamed and/or deprecated as of 3.0.4; remove in 3.1.0
$_lang['ugc_mutate'] = 'User Group Access to Context'; // now in access.inc.php, access_context_create
$_lang['user_password_email_subject'] = 'Set up your password';
$_lang['user_password_email'] = '<h2>Set up your password</h2><p>We received a request to set up your MODX Revolution password. You can set up your password by clicking the button below and following the instructions on screen.</p><p class="center"><a href="[[+url_scheme]][[+http_host]][[+manager_url]]?modhash=[[+hash]]" class="btn">Set up my password</a></p><p class="small">If you did not send this request, please ignore this email.</p>';
51 changes: 51 additions & 0 deletions core/src/Revolution/Processors/Security/User/Create.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@


use Exception;
use MODX\Revolution\Hashing\modHashing;
use MODX\Revolution\Processors\Model\CreateProcessor;
use MODX\Revolution\Processors\Processor;
use MODX\Revolution\modUser;
use MODX\Revolution\modUserGroup;
use MODX\Revolution\modUserGroupMember;
use MODX\Revolution\modUserProfile;
use MODX\Revolution\modX;
use MODX\Revolution\Registry\modRegister;
use MODX\Revolution\Registry\modRegistry;
use MODX\Revolution\Smarty\modSmarty;

/**
Expand Down Expand Up @@ -232,6 +235,54 @@ public function sendNotificationEmail() {
'html' => true,
]);
}

if (
$this->getProperty('passwordgenmethod') === 'user_email_specify'
) {
$activationHash = bin2hex(random_bytes(32));

/** @var modRegistry $registry */
$registry = $this->modx->getService('registry', 'registry.modRegistry');
/** @var modRegister $register */
$register = $registry->getRegister('user', 'registry.modDbRegister');
$register->connect();
$register->subscribe('/pwd/change/');
$register->send('/pwd/change/', [$activationHash => $this->object->get('username')], ['ttl' => 86400]);

// Send activation email
$message = $this->modx->lexicon('user_password_email');
$placeholders = array_merge($this->modx->config, $this->object->toArray());
$placeholders['hash'] = $activationHash;

// Store previous placeholders
$ph = $this->modx->placeholders;
// now set those useful for modParser
$this->modx->setPlaceholders($placeholders);
$this->modx->getParser()->processElementTags('', $message, true, false, '[[', ']]', [], 10);
$this->modx->getParser()->processElementTags('', $message, true, true, '[[', ']]', [], 10);
// Then restore previous placeholders to prevent any breakage
$this->modx->placeholders = $ph;

$this->modx->getService('smarty', 'smarty.modSmarty', '', ['template_dir' => $this->modx->getOption('manager_path') . 'templates/default/']);

$this->modx->smarty->assign('_config', $this->modx->config);
$this->modx->smarty->assign('content', $message, true);

$sent = $this->object->sendEmail(
$this->modx->smarty->fetch('email/default.tpl'),
[
'from' => $this->modx->getOption('emailsender'),
'fromName' => $this->modx->getOption('site_name'),
'sender' => $this->modx->getOption('emailsender'),
'subject' => $this->modx->lexicon('user_password_email_subject'),
'html' => true,
]
);

if (!$sent) {
return $this->failure($this->modx->lexicon('error_sending_email_to') . $this->object->get('email'));
}
}
}

/**
Expand Down
80 changes: 71 additions & 9 deletions core/src/Revolution/Processors/Security/User/Update.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use MODX\Revolution\modUserGroupMember;
use MODX\Revolution\modUserProfile;
use MODX\Revolution\modX;
use MODX\Revolution\Registry\modRegister;
use MODX\Revolution\Registry\modRegistry;

/**
* Update a user.
Expand Down Expand Up @@ -285,6 +287,7 @@ public function setUserGroups() {
*/
public function afterSave() {
$this->setUserGroups();
$this->sendNotificationEmail();
if ($this->activeStatusChanged) {
$this->fireAfterActiveStatusChange();
}
Expand All @@ -305,6 +308,62 @@ public function fireAfterActiveStatusChange() {
);
}

/**
* Send the password notification email, if specified
*
* @return void
* @throws \Exception
*/
public function sendNotificationEmail() {
if ($this->getProperty('passwordgenmethod') === 'user_email_specify') {
$activationHash = bin2hex(random_bytes(32));

/** @var modRegistry $registry */
$registry = $this->modx->getService('registry', 'registry.modRegistry');
/** @var modRegister $register */
$register = $registry->getRegister('user', 'registry.modDbRegister');
$register->connect();
$register->subscribe('/pwd/change/');
$register->send('/pwd/change/', [$activationHash => $this->object->get('username')], ['ttl' => 86400]);

$this->modx->lexicon->load('core:login');

// Send activation email
$message = $this->modx->lexicon('user_password_email');
$placeholders = array_merge($this->modx->config, $this->object->toArray());
$placeholders['hash'] = $activationHash;

// Store previous placeholders
$ph = $this->modx->placeholders;
// now set those useful for modParser
$this->modx->setPlaceholders($placeholders);
$this->modx->getParser()->processElementTags('', $message, true, false, '[[', ']]', [], 10);
$this->modx->getParser()->processElementTags('', $message, true, true, '[[', ']]', [], 10);
// Then restore previous placeholders to prevent any breakage
$this->modx->placeholders = $ph;

$this->modx->getService('smarty', 'smarty.modSmarty', '', ['template_dir' => $this->modx->getOption('manager_path') . 'templates/default/']);

$this->modx->smarty->assign('_config', $this->modx->config);
$this->modx->smarty->assign('content', $message, true);

$sent = $this->object->sendEmail(
$this->modx->smarty->fetch('email/default.tpl'),
[
'from' => $this->modx->getOption('emailsender'),
'fromName' => $this->modx->getOption('site_name'),
'sender' => $this->modx->getOption('emailsender'),
'subject' => $this->modx->lexicon('user_password_email_subject'),
'html' => true,
]
);

if (!$sent) {
return $this->failure($this->modx->lexicon('error_sending_email_to') . $this->object->get('email'));
}
}
}

/**
* {@inheritDoc}
* @return array|string
Expand All @@ -314,20 +373,23 @@ public function cleanup()
$userArray = $this->object->toArray();
$profile = $this->object->getOne('Profile');
if ($profile) {
$userArray = array_merge($profile->toArray(),$userArray);
$userArray = array_merge($profile->toArray(), $userArray);
}
unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']);

$passwordNotifyMethod = $this->getProperty('passwordnotifymethod');
if (!empty($passwordNotifyMethod) && !empty($this->newPassword) && $passwordNotifyMethod == 's') {
return $this->success($this->modx->lexicon('user_updated_password_message',
[
'username' => $this->object->get('username'),
'password' => $this->newPassword,
]
), $this->object);
} else {
return $this->success('',$this->object);
return $this->success(
$this->modx->lexicon(
'user_updated_password_message',
[
'username' => $this->object->get('username'),
'password' => $this->newPassword,
]
),
$this->object
);
}
return $this->success('', $this->object);
}
}
6 changes: 4 additions & 2 deletions core/src/Revolution/Processors/Security/User/Validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@ public function alreadyExists($name) {
public function checkPassword() {
$newPassword = $this->processor->getProperty('newpassword',null);
$id = $this->processor->getProperty('id');
if ($newPassword !== null && $newPassword != 'false' || empty($id)) {

$passwordGenerationMethod = $this->processor->getProperty('passwordgenmethod','g');
if ($passwordGenerationMethod !== 'user_email_specify' && ($newPassword !== null && $newPassword != 'false' || empty($id))) {
$passwordNotifyMethod = $this->processor->getProperty('passwordnotifymethod',null);
if (empty($passwordNotifyMethod)) {
$this->processor->addFieldError('password_notify_method',$this->modx->lexicon('user_err_not_specified_notification_method'));
}
$passwordGenerationMethod = $this->processor->getProperty('passwordgenmethod','g');

if ($passwordGenerationMethod == 'g') {
$autoPassword = $this->user->generatePassword();
$this->user->set('password', $autoPassword);
Expand Down
7 changes: 7 additions & 0 deletions manager/assets/modext/widgets/security/modx.panel.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,13 @@ Ext.extend(MODx.panel.User,MODx.FormPanel,{
,xtype: 'radio'
,inputValue: 'spec'
,value: 'spec'
},{
id: 'modx-user-password-genmethod-user-email-specify'
,name: 'passwordgenmethod'
,boxLabel: _('password_gen_user_email_specify')
,xtype: 'radio'
,inputValue: 'user_email_specify'
,value: 'user_email_specify'
}]
},{
id: 'modx-user-panel-newpassword'
Expand Down
Loading