addressRegistry = $addressRegistry; $this->getByToken = $getByToken; $this->customerRegistry = $customerRegistry; $this->credentialsValidator = $credentialsValidator; $this->customerRepository = $customerRepository; $this->sessionCleaner = $sessionCleaner; } /** * Disable Customer Address Validation * * @param CustomerInterface $customer * @throws NoSuchEntityException */ protected function disableAddressValidation($customer) { foreach ($customer->getAddresses() as $address) { $addressModel = $this->addressRegistry->retrieve($address->getId()); $addressModel->setShouldIgnoreValidation(true); } } /** * Set ignore_validation_flag for reset password flow to skip unnecessary address and customer validation * * @param Customer $customer * @return void */ protected function setIgnoreValidationFlag($customer) { $customer->setData('ignore_validation_flag', true); } /** * Validate the Reset Password Token for a customer. * * @param int $customerId * @param string $resetPasswordLinkToken * * @return bool * @throws ExpiredException If token is expired * @throws InputException If token or customer id is invalid * @throws InputMismatchException If token is mismatched * @throws LocalizedException * @throws NoSuchEntityException If customer doesn't exist * @SuppressWarnings(PHPMD.LongVariable) */ protected function validateResetPasswordToken($customerId, $resetPasswordLinkToken) { if ($customerId !== null && $customerId <= 0) { throw new InputException( __( 'Invalid value of "%value" provided for the %fieldName field.', ['value' => $customerId, 'fieldName' => 'customerId'] ) ); } if ($customerId === null) { //Looking for the customer. $customerId = $this->getByToken ->execute($resetPasswordLinkToken) ->getId(); } if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) { $params = ['fieldName' => 'resetPasswordLinkToken']; throw new InputException(__('"%fieldName" is required. Enter and try again.', $params)); } $customerSecureData = $this->customerRegistry->retrieveSecureData($customerId); $rpToken = $customerSecureData->getRpToken(); $rpTokenCreatedAt = $customerSecureData->getRpTokenCreatedAt(); if (!Security::compareStrings($rpToken, $resetPasswordLinkToken)) { throw new InputMismatchException(__('The password token is mismatched. Reset and try again.')); } elseif ($this->isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)) { throw new ExpiredException(__('The password token is expired. Reset and try again.')); } return true; } public function resetPassword($email, $resetToken, $newPassword) { if (!$email && $resetToken) { $customer = $this->getByToken->execute($resetToken); $email = $customer->getEmail(); } else { $customer = $this->customerRepository->get($email); } // No need to validate customer and customer address while saving customer reset password token $this->disableAddressValidation($customer); $this->setIgnoreValidationFlag($customer); //Validate Token and new password strength if ($resetToken) { $this->validateResetPasswordToken($customer->getId(), $resetToken); } $this->credentialsValidator->checkPasswordDifferentFromEmail( $email, $newPassword ); $this->checkPasswordStrength($newPassword); //Update secure data $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId()); $customerSecure->setRpToken(null); $customerSecure->setRpTokenCreatedAt(null); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); $this->sessionCleaner->clearFor((int)$customer->getId()); $this->customerRepository->save($customer); return true; } }