Merge branch '5.1' into 5

This commit is contained in:
Guy Sartorelli 2023-12-18 15:20:02 +13:00
commit c96f37ea93
No known key found for this signature in database
GPG Key ID: F313E3B9504D496A
10 changed files with 74 additions and 41 deletions

View File

@ -294,6 +294,7 @@ en:
CURRENT_PASSWORD: 'Current Password' CURRENT_PASSWORD: 'Current Password'
EDIT_PASSWORD: 'New Password' EDIT_PASSWORD: 'New Password'
EMAIL: Email EMAIL: Email
EMAIL_FAILED: 'There was an error when trying to email you a password reset link.'
EMPTYNEWPASSWORD: "The new password can't be empty, please try again" EMPTYNEWPASSWORD: "The new password can't be empty, please try again"
ENTEREMAIL: 'Please enter an email address to get a password reset link.' ENTEREMAIL: 'Please enter an email address to get a password reset link.'
ERRORLOCKEDOUT2: 'Your account has been temporarily disabled because of too many failed attempts at logging in. Please try again in {count} minutes.' ERRORLOCKEDOUT2: 'Your account has been temporarily disabled because of too many failed attempts at logging in. Please try again in {count} minutes.'

View File

@ -9,7 +9,6 @@ use SilverStripe\ORM\DatabaseAdmin;
/** /**
* Hook up static validation to the deb/build process * Hook up static validation to the deb/build process
* *
* @method DatabaseAdmin getOwner()
*/ */
class DatabaseAdminExtension extends Extension class DatabaseAdminExtension extends Extension
{ {

View File

@ -99,7 +99,6 @@ use stdClass;
* If any public method on this class is prefixed with an underscore, * If any public method on this class is prefixed with an underscore,
* the results are cached in memory through {@link cachedCall()}. * the results are cached in memory through {@link cachedCall()}.
* *
*
* @property int $ID ID of the DataObject, 0 if the DataObject doesn't exist in database. * @property int $ID ID of the DataObject, 0 if the DataObject doesn't exist in database.
* @property int $OldID ID of object, if deleted * @property int $OldID ID of object, if deleted
* @property string $Title * @property string $Title

View File

@ -47,11 +47,12 @@ use SilverStripe\ORM\UnsavedRelationList;
* *
* @property int $ParentID ID of parent group * @property int $ParentID ID of parent group
* *
* @method Group Parent() Return parent group
* @method HasManyList Permissions() List of group permissions
* @method HasManyList Groups() List of child groups
* @method ManyManyList Roles() List of PermissionRoles
* @mixin Hierarchy * @mixin Hierarchy
* @method HasManyList<Group> Groups()
* @method ManyManyList<Member> Members()
* @method Group Parent()
* @method HasManyList<Permission> Permissions()
* @method ManyManyList<PermissionRole> Roles()
*/ */
class Group extends DataObject class Group extends DataObject
{ {

View File

@ -10,10 +10,10 @@ use SilverStripe\ORM\ManyManyList;
* *
* @property string $CanViewType * @property string $CanViewType
* @property string $CanEditType * @property string $CanEditType
* @method ManyManyList ViewerGroups() * @method ManyManyList<Group> EditorGroups()
* @method ManyManyList EditorGroups() * @method ManyManyList<Member> EditorMembers()
* @method ManyManyList ViewerMembers() * @method ManyManyList<Group> ViewerGroups()
* @method ManyManyList EditorMembers() * @method ManyManyList<Member> ViewerMembers()
*/ */
class InheritedPermissionsExtension extends DataExtension class InheritedPermissionsExtension extends DataExtension
{ {

View File

@ -20,7 +20,7 @@ use SilverStripe\ORM\DataObject;
* @property string $IP IP address of user attempting to login * @property string $IP IP address of user attempting to login
* @property int $MemberID ID of the Member * @property int $MemberID ID of the Member
* *
* @method Member Member() Member object of the user trying to log in * @method Member Member()
*/ */
class LoginAttempt extends DataObject class LoginAttempt extends DataObject
{ {

View File

@ -4,6 +4,7 @@ namespace SilverStripe\Security;
use IntlDateFormatter; use IntlDateFormatter;
use InvalidArgumentException; use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use SilverStripe\Admin\LeftAndMain; use SilverStripe\Admin\LeftAndMain;
use SilverStripe\CMS\Controllers\CMSMain; use SilverStripe\CMS\Controllers\CMSMain;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
@ -34,15 +35,15 @@ use SilverStripe\ORM\SS_List;
use SilverStripe\ORM\UnsavedRelationList; use SilverStripe\ORM\UnsavedRelationList;
use SilverStripe\ORM\ValidationException; use SilverStripe\ORM\ValidationException;
use SilverStripe\ORM\ValidationResult; use SilverStripe\ORM\ValidationResult;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Exception\RfcComplianceException;
use Closure; use Closure;
use RuntimeException; use RuntimeException;
/** /**
* The member class which represents the users of the system * The member class which represents the users of the system
* *
* @method HasManyList LoggedPasswords()
* @method HasManyList RememberLoginHashes()
* @property string $FirstName * @property string $FirstName
* @property string $Surname * @property string $Surname
* @property string $Email * @property string $Email
@ -59,6 +60,9 @@ use RuntimeException;
* @property int $FailedLoginCount * @property int $FailedLoginCount
* @property string $DateFormat * @property string $DateFormat
* @property string $TimeFormat * @property string $TimeFormat
* @method ManyManyList<Group> Groups()
* @method HasManyList<MemberPassword> LoggedPasswords()
* @method HasManyList<RememberLoginHash> RememberLoginHashes()
*/ */
class Member extends DataObject class Member extends DataObject
{ {
@ -780,6 +784,7 @@ class Member extends DataObject
&& static::config()->get('notify_password_change') && static::config()->get('notify_password_change')
&& $this->isInDB() && $this->isInDB()
) { ) {
try {
$email = Email::create() $email = Email::create()
->setHTMLTemplate('SilverStripe\\Control\\Email\\ChangePasswordEmail') ->setHTMLTemplate('SilverStripe\\Control\\Email\\ChangePasswordEmail')
->setData($this) ->setData($this)
@ -792,6 +797,11 @@ class Member extends DataObject
$this->extend('updateChangedPasswordEmail', $email); $this->extend('updateChangedPasswordEmail', $email);
$email->send(); $email->send();
} catch (TransportExceptionInterface | RfcComplianceException $e) {
/** @var LoggerInterface $logger */
$logger = Injector::inst()->get(LoggerInterface::class . '.errorhandler');
$logger->error('Error sending email in ' . __FILE__ . ' line ' . __LINE__ . ": {$e->getMessage()}");
}
} }
// The test on $this->ID is used for when records are initially created. Note that this only works with // The test on $this->ID is used for when records are initially created. Note that this only works with

View File

@ -2,15 +2,19 @@
namespace SilverStripe\Security\MemberAuthenticator; namespace SilverStripe\Security\MemberAuthenticator;
use Psr\Log\LoggerInterface;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Control\Email\Email; use SilverStripe\Control\Email\Email;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\RequestHandler; use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\Form; use SilverStripe\Forms\Form;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Security\Member; use SilverStripe\Security\Member;
use SilverStripe\Security\Security; use SilverStripe\Security\Security;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mime\Exception\RfcComplianceException;
/** /**
* Handle login requests from MemberLoginForm * Handle login requests from MemberLoginForm
@ -173,7 +177,18 @@ class LostPasswordHandler extends RequestHandler
if ($member) { if ($member) {
$token = $member->generateAutologinTokenAndStoreHash(); $token = $member->generateAutologinTokenAndStoreHash();
$this->sendEmail($member, $token); $success = $this->sendEmail($member, $token);
if (!$success) {
$form->sessionMessage(
_t(
Member::class . '.EMAIL_FAILED',
'There was an error when trying to email you a password reset link.'
),
'bad'
);
return $this->redirectToLostPassword();
}
} }
return $this->redirectToSuccess($data); return $this->redirectToSuccess($data);
@ -225,6 +240,7 @@ class LostPasswordHandler extends RequestHandler
*/ */
protected function sendEmail($member, $token) protected function sendEmail($member, $token)
{ {
try {
/** @var Email $email */ /** @var Email $email */
$email = Email::create() $email = Email::create()
->setHTMLTemplate('SilverStripe\\Control\\Email\\ForgotPasswordEmail') ->setHTMLTemplate('SilverStripe\\Control\\Email\\ForgotPasswordEmail')
@ -238,7 +254,14 @@ class LostPasswordHandler extends RequestHandler
->setTo($member->Email); ->setTo($member->Email);
$member->extend('updateForgotPasswordEmail', $email); $member->extend('updateForgotPasswordEmail', $email);
return $email->send(); $email->send();
return true;
} catch (TransportExceptionInterface | RfcComplianceException $e) {
/** @var LoggerInterface $logger */
$logger = Injector::inst()->get(LoggerInterface::class . '.errorhandler');
$logger->error('Error sending email in ' . __FILE__ . ' line ' . __LINE__ . ": {$e->getMessage()}");
return false;
}
} }
/** /**

View File

@ -11,7 +11,7 @@ use SilverStripe\ORM\DataObject;
* @property string $Salt * @property string $Salt
* @property string $PasswordEncryption * @property string $PasswordEncryption
* @property int $MemberID ID of the Member * @property int $MemberID ID of the Member
* @method Member Member() Owner of the password * @method Member Member()
*/ */
class MemberPassword extends DataObject class MemberPassword extends DataObject
{ {

View File

@ -20,8 +20,8 @@ use SilverStripe\ORM\ManyManyList;
* @property string Title * @property string Title
* @property string OnlyAdminCanApply * @property string OnlyAdminCanApply
* *
* @method HasManyList Codes() List of PermissionRoleCode objects * @method HasManyList<PermissionRoleCode> Codes()
* @method ManyManyList Groups() List of Group objects * @method ManyManyList<Group> Groups()
*/ */
class PermissionRole extends DataObject class PermissionRole extends DataObject
{ {