From 3aba6cc06e0a1bfda16fdab0ddad4b2b5ffd7ac7 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 9 Aug 2023 04:50:50 +0200 Subject: [PATCH] (Grav GitSync) Automatic Commit from dan --- plugins/admin/CHANGELOG.md | 6 ++ plugins/admin/blueprints.yaml | 4 +- plugins/admin/languages/en.yaml | 5 +- plugins/email/CHANGELOG.md | 22 ++++++ plugins/email/blueprints.yaml | 2 +- plugins/email/classes/Email.php | 48 ++++++----- plugins/email/classes/Message.php | 6 ++ plugins/email/email.php | 5 +- plugins/email/languages.yaml | 5 +- plugins/form/CHANGELOG.md | 14 ++++ plugins/form/blueprints.yaml | 13 ++- plugins/form/form.php | 114 ++++++++++++++++----------- plugins/form/form.yaml | 1 + plugins/login/CHANGELOG.md | 13 +++ plugins/login/blueprints.yaml | 2 +- plugins/login/classes/Controller.php | 92 +++++++++------------ plugins/login/languages/de.yaml | 3 - plugins/login/languages/en.yaml | 5 +- plugins/login/languages/es.yaml | 4 +- plugins/login/languages/fr.yaml | 2 - plugins/login/languages/lt.yaml | 7 +- plugins/login/languages/no.yaml | 2 - plugins/login/languages/pt-BR.yaml | 3 - plugins/login/languages/ru.yaml | 5 +- plugins/login/languages/uk.yaml | 5 +- plugins/login/languages/zh.yaml | 3 - 26 files changed, 230 insertions(+), 161 deletions(-) diff --git a/plugins/admin/CHANGELOG.md b/plugins/admin/CHANGELOG.md index 5183336..a7e2136 100644 --- a/plugins/admin/CHANGELOG.md +++ b/plugins/admin/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.10.42 +## 06/14/2023 + +1. [](#new) + * Added a couple of string translations + # v1.10.41.2 ## 05/11/2023 diff --git a/plugins/admin/blueprints.yaml b/plugins/admin/blueprints.yaml index ab6f115..41dae90 100644 --- a/plugins/admin/blueprints.yaml +++ b/plugins/admin/blueprints.yaml @@ -1,7 +1,7 @@ name: Admin Panel slug: admin type: plugin -version: 1.10.41.2 +version: 1.10.42 description: Adds an advanced administration panel to manage your site icon: empire author: @@ -15,7 +15,7 @@ docs: https://github.com/getgrav/grav-plugin-admin/blob/develop/README.md license: MIT dependencies: - - { name: grav, version: '>=1.7.41' } + - { name: grav, version: '>=1.7.42' } - { name: form, version: '>=6.0.1' } - { name: login, version: '>=3.7.0' } - { name: email, version: '>=3.1.6' } diff --git a/plugins/admin/languages/en.yaml b/plugins/admin/languages/en.yaml index 288c682..1235a11 100644 --- a/plugins/admin/languages/en.yaml +++ b/plugins/admin/languages/en.yaml @@ -107,7 +107,6 @@ PLUGIN_ADMIN: BACKUP_DELETED: "Backup Successfully Deleted" BACKUP_NOT_FOUND: "Backup Not Found" BACKUP_DATE: "Backup Date" - STATISTICS: "Statistics" VIEWS_STATISTICS: "Page View Statistics" TODAY: "Today" @@ -207,11 +206,13 @@ PLUGIN_ADMIN: PASSWORD: "Password" PASSWORD_CONFIRM: "Confirm Password" TITLE: "Title" - LANGUAGE: "Language" ACCOUNT: "Account" EMAIL_VALIDATION_MESSAGE: "Must be a valid email address" PASSWORD_VALIDATION_MESSAGE: "Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters" + LANGUAGE: "Language" LANGUAGE_HELP: "Set the favorite language" + LANGUAGE_DEBUG: "Debug language" + LANGUAGE_DEBUG_HELP: "Enable the debug of languages which are using the |t twig filter by adding a span around them that can be styled to help diagnose issues" MEDIA: "Media" DEFAULTS: "Defaults" SITE_TITLE: "Site Title" diff --git a/plugins/email/CHANGELOG.md b/plugins/email/CHANGELOG.md index f892ce1..78971ef 100644 --- a/plugins/email/CHANGELOG.md +++ b/plugins/email/CHANGELOG.md @@ -1,3 +1,25 @@ +# v4.0.4 +## 07/10/2023 + +1. [](#bugfix) + * Fix for email file attachments using stream + +# v4.0.3 +## 06/29/2023 + +1. [](#improved) + * Simplified the `Email::processRecipients()` logic for readability +1. [](#bugfix) + * Fix an issue with 2 email addresses provided with 'just' email and no name [#176](https://github.com/getgrav/grav-plugin-email/issues/176) + * Fix for blank subjectlines when using `Message::setSubject()` in Twig templates [getgrav/grav-plugin-login#299](https://github.com/getgrav/grav-plugin-login/issues/299) + +# v4.0.2 +## 06/27/2023 + +1. [](#bugfix) + * some recipient handling improvements. e.g. missing `bcc_name` throwing error + * Allow overriding of defaults with a form configuration. Use `null` to remove default email configuration + # v4.0.1 ## 05/20/2023 diff --git a/plugins/email/blueprints.yaml b/plugins/email/blueprints.yaml index 68c89de..d3a66a0 100644 --- a/plugins/email/blueprints.yaml +++ b/plugins/email/blueprints.yaml @@ -1,7 +1,7 @@ name: Email slug: email type: plugin -version: 4.0.1 +version: 4.0.4 testing: false description: Enables the emailing system for Grav icon: envelope diff --git a/plugins/email/classes/Email.php b/plugins/email/classes/Email.php index 617bbee..1bc7b1d 100644 --- a/plugins/email/classes/Email.php +++ b/plugins/email/classes/Email.php @@ -138,8 +138,9 @@ class Email $email = $message->getEmail(); // Extend parameters with defaults. - $params += [ + $defaults = [ 'bcc' => $config->get('plugins.email.bcc', []), + 'bcc_name' => $config->get('plugins.email.bcc_name'), 'body' => $config->get('plugins.email.body', '{% include "forms/data.html.twig" %}'), 'cc' => $config->get('plugins.email.cc', []), 'cc_name' => $config->get('plugins.email.cc_name'), @@ -157,6 +158,12 @@ class Email 'message' => $message ]; + foreach ($defaults as $key => $value) { + if (!key_exists($key, $params)) { + $params[$key] = $value; + } + } + if (!$params['to']) { throw new \RuntimeException($language->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_TO_ADDRESS')); } @@ -237,38 +244,39 @@ class Email */ protected function processRecipients(string $type, array $params): array { + if (array_key_exists($type, $params) && $params[$type] === null) { + return []; + } + $recipients = $params[$type] ?? Grav::instance()['config']->get('plugins.email.'.$type) ?? []; $list = []; if (!empty($recipients)) { - if (is_array($recipients) && Utils::isAssoc($recipients)) { - $list[] = $this->createAddress($recipients); + if (is_array($recipients)) { + if (Utils::isAssoc($recipients) || (count($recipients) ===2 && $this->isValidEmail($recipients[0]) && !$this->isValidEmail($recipients[1]))) { + $list[] = $this->createAddress($recipients); + } else { + foreach ($recipients as $recipient) { + $list[] = $this->createAddress($recipient); + } + } } else { - if (is_array($recipients)) { - if (count($recipients) ===2 && $this->isValidEmail($recipients[0]) && is_string($recipients[1])) { - $list[] = $this->createAddress($recipients); - } else { - foreach ($recipients as $recipient) { - $list[] = $this->createAddress($recipient); - } + if (is_string($recipients) && Utils::contains($recipients, ',')) { + $recipients = array_map('trim', explode(',', $recipients)); + foreach ($recipients as $recipient) { + $list[] = $this->createAddress($recipient); } } else { - if (is_string($recipients) && Utils::contains($recipients, ',')) { - $recipients = array_map('trim', explode(',', $recipients)); - foreach ($recipients as $recipient) { - $list[] = $this->createAddress($recipient); - } - } else { - if (!Utils::contains($recipients, ['<','>']) && ($params[$type."_name"])) { - $recipients = [$recipients, $params[$type."_name"]]; - } - $list[] = $this->createAddress($recipients); + if (!Utils::contains($recipients, ['<','>']) && (isset($params[$type."_name"]))) { + $recipients = [$recipients, $params[$type."_name"]]; } + $list[] = $this->createAddress($recipients); } } } + return $list; } diff --git a/plugins/email/classes/Message.php b/plugins/email/classes/Message.php index fb691f8..066a209 100644 --- a/plugins/email/classes/Message.php +++ b/plugins/email/classes/Message.php @@ -18,6 +18,12 @@ class Message return $this; } + public function setSubject($subject): self + { + $this->subject($subject); + return $this; + } + public function to($to): self { $this->email->to($to); diff --git a/plugins/email/email.php b/plugins/email/email.php index b96ff36..da59047 100644 --- a/plugins/email/email.php +++ b/plugins/email/email.php @@ -125,6 +125,7 @@ class EmailPlugin extends Plugin { // Build message $message = $this->email->buildMessage($params, $vars); + $locator = $this->grav['locator']; if (isset($params['attachments'])) { $filesToAttach = (array)$params['attachments']; @@ -135,9 +136,11 @@ class EmailPlugin extends Plugin if (isset($fileValues['file'])) { $filename = $fileValues['file']; } else { - $filename = ROOT_DIR . $fileValues['path']; + $filename = $fileValues['path']; } + $filename = $locator->findResource($filename, true, true); + try { $message->attachFromPath($filename); } catch (\Exception $e) { diff --git a/plugins/email/languages.yaml b/plugins/email/languages.yaml index 4cb044c..9f1fc7f 100644 --- a/plugins/email/languages.yaml +++ b/plugins/email/languages.yaml @@ -78,6 +78,7 @@ fr: PLUGIN_EMAIL: MAIL_ENGINE: "Moteur de messagerie" MAIL_ENGINE_DISABLED: "Désactivé" + MAIL_ENGINE_DESC: "NOTE : Si vous sélectionnez un moteur fourni par un autre plugin, vous devez configurer les options dans ce même plugin." CONTENT_TYPE: "Type de contenu" CONTENT_TYPE_PLAIN_TEXT: "Texte brut" CHARSET: "Jeu de caractères" @@ -130,7 +131,9 @@ fr: QUEUE_FLUSH_MSG_LIMIT: "Messages par Flush" QUEUE_FLUSH_MSG_LIMIT_APPEND: "Messages" QUEUE_FLUSH_TIME_LIMIT: "Délai de Flush" - QUEUE_FLUSH_TIME_LIMIT_APPEND: "Seconds" + QUEUE_FLUSH_TIME_LIMIT_APPEND: "Secondes" + EMAIL_FORMAT: "Utilisez le format `addr` : `email@adresse.org` ou le format `name-addr` : `Votre nom `. Séparer par des virgules pour plusieurs adresses." + hr: PLUGIN_EMAIL: diff --git a/plugins/form/CHANGELOG.md b/plugins/form/CHANGELOG.md index 1577d68..7c88629 100644 --- a/plugins/form/CHANGELOG.md +++ b/plugins/form/CHANGELOG.md @@ -1,3 +1,17 @@ +# v7.2.1 +## 06/27/2023 + +1. [](#improved) + * Added some optional debug output to help isolate form loading problems +1. [](#bugfix) + * More robust fix for multi-language form caching + +# v7.2.0 +## 06/21/2023 + +1. [](#bugfix) + * Fixed a long-standing bug with cached forms not working properly in multi-language scenarios + # v7.1.3 ## 05/09/2023 diff --git a/plugins/form/blueprints.yaml b/plugins/form/blueprints.yaml index 4552765..4a7ec33 100644 --- a/plugins/form/blueprints.yaml +++ b/plugins/form/blueprints.yaml @@ -1,7 +1,7 @@ name: Form slug: form type: plugin -version: 7.1.3 +version: 7.2.1 description: Enables forms handling and processing icon: check-square author: @@ -34,6 +34,17 @@ form: title: PLUGIN_FORM.GENERAL fields: + debug: + type: toggle + label: Debug + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + built_in_css: type: toggle label: PLUGIN_FORM.USE_BUILT_IN_CSS diff --git a/plugins/form/form.php b/plugins/form/form.php index bd96770..02eae7a 100644 --- a/plugins/form/form.php +++ b/plugins/form/form.php @@ -26,6 +26,7 @@ use Grav\Plugin\Form\Form; use Grav\Plugin\Form\Forms; use Grav\Plugin\Form\TwigExtension; use Grav\Common\HTTP\Client; +use Monolog\Logger; use ReCaptcha\ReCaptcha; use ReCaptcha\RequestMethod\CurlPost; use RecursiveArrayIterator; @@ -65,8 +66,7 @@ class FormPlugin extends Plugin protected $active_forms = []; /** @var array */ protected $json_response = []; - /** @var bool */ - protected $recache_forms = false; + /** * @return bool @@ -149,6 +149,8 @@ class FormPlugin extends Plugin 'onTwigSiteVariables' => ['onTwigVariables', 0], 'onFormValidationProcessed' => ['onFormValidationProcessed', 0], ]); + + } /** @@ -223,17 +225,11 @@ class FormPlugin extends Plugin $submitted = false; $this->json_response = []; - // Save cached forms. - if ($this->recache_forms) { - $this->saveCachedForms(); - } - /** @var PageInterface $page */ $page = $this->grav['page']; - // Force rebuild form when form has not been built and form cache expired. - // This happens when form cache expires before the page cache - // and then does not trigger 'onPageProcessed' event. + + // DEPRECATED: This should no longer ever happen if (!$this->forms) { $this->onPageProcessed(new Event(['page' => $page])); } @@ -318,9 +314,11 @@ class FormPlugin extends Plugin /** @var Forms $forms */ $forms = $this->grav['forms']; + $lang = $this->grav['language']->getLanguage(); + /** @var Route $route */ $route = $this->grav['route']; - $pageForms = $this->forms[$route->getRoute()] ?? []; + $pageForms = $this->forms[$lang][$route->getRoute()] ?? []; /** * @var string $name @@ -835,12 +833,12 @@ class FormPlugin extends Plugin public function addFormDefinition(PageInterface $page, string $name, array $form): void { $route = ($page->home() ? '/' : $page->route()) ?? '/'; + $lang = $this->grav['language']->getLanguage(); - if (!isset($this->forms[$route][$name])) { + if (!isset($this->forms[$lang][$route][$name])) { $form['_page_routable'] = !$page->isModule(); - - $this->forms[$route][$name] = $form; - $this->recache_forms = true; + $this->forms[$lang][$route][$name] = $form; + $this->saveCachedForms(); } } @@ -857,13 +855,14 @@ class FormPlugin extends Plugin return; } + $lang = $this->grav['language']->getLanguage(); $name = $form->getName(); - if (!isset($this->forms[$route][$name])) { + if (!isset($this->forms[$lang][$route][$name])) { $form['_page_routable'] = true; - $this->forms[$route][$name] = $form; - $this->recache_forms = true; + $this->forms[$lang][$route][$name] = $form; + $this->saveCachedForms(); } } @@ -877,6 +876,7 @@ class FormPlugin extends Plugin { /** @var Pages $pages */ $pages = $this->grav['pages']; + $lang = $this->grav['language']->getLanguage(); // Handle parameters. if (is_array($data)) { @@ -922,7 +922,7 @@ class FormPlugin extends Plugin // Attempt to find the form from the page. if ('' !== $route) { - $forms = $this->forms[$route] ?? []; + $forms = $this->forms[$lang][$route] ?? []; if (!$unnamed) { // Get form by the name. @@ -938,9 +938,7 @@ class FormPlugin extends Plugin if (null === $form) { // First check if we requested a specific form which didn't exist. if ($route_provided || $unnamed) { - /** @var Debugger $debugger */ - $debugger = $this->grav['debugger']; - $debugger->addMessage(sprintf('Form %s not found in page %s', $name ?? 'unnamed', $route), 'warning'); + $this->grav['debugger']->addMessage(sprintf('Form %s not found in page %s', $name ?? 'unnamed', $route), 'warning'); return null; } @@ -954,8 +952,7 @@ class FormPlugin extends Plugin // Check for naming conflicts. if (count($forms) > 1) { - $debugger = $this->grav['debugger']; - $debugger->addMessage(sprintf('Fetching form by its name, but there are multiple pages with the same form name %s', $name), 'warning'); + $this->grav['debugger']->addMessage(sprintf('Fetching form by its name, but there are multiple pages with the same form name %s', $name), 'warning'); } [$route, $name, $form] = $first; @@ -967,9 +964,7 @@ class FormPlugin extends Plugin if (is_array($form)) { // Form was cached as an array, try to create the object. if (null === $page) { - /** @var Debugger $debugger */ - $debugger = $this->grav['debugger']; - $debugger->addMessage(sprintf('Form %s cannot be created as page %s does not exist', $name, $route), 'warning'); + $this->grav['debugger']->addMessage(sprintf('Form %s cannot be created as page %s does not exist', $name, $route), 'warning'); return null; } @@ -1104,7 +1099,10 @@ class FormPlugin extends Plugin protected function findFormByName(string $name): array { $list = []; - foreach ($this->forms as $route => $forms) { + $lang = $this->grav['language']->getLanguage(); + $lang_forms = $this->forms[$lang] ?? []; + + foreach ($lang_forms as $route => $forms) { foreach ($forms as $key => $form) { if ($name === $key && !empty($form['_page_routable'])) { $list[] = [$route, $key, $form]; @@ -1241,12 +1239,9 @@ class FormPlugin extends Plugin /** @var Cache $cache */ $cache = $this->grav['cache']; - [$forms] = $cache->fetch($this->getFormCacheId()); + $forms = $cache->fetch($this->getFormCacheId()); } catch (Exception $e) { - /** @var Debugger $debugger */ - $debugger = Grav::instance()['debugger']; - $debugger->addMessage(sprintf('Unserializing cached forms failed: %s', $e->getMessage()), 'error'); - + $this->grav['debugger']->addMessage(sprintf('Unserializing cached forms failed: %s', $e->getMessage()), 'error'); $forms = null; } @@ -1256,7 +1251,11 @@ class FormPlugin extends Plugin // Only update the forms if it's not empty if ($forms) { - $this->forms = array_merge($this->forms, $forms); + $this->forms = Utils::arrayMergeRecursiveUnique($this->forms, $forms); + if ($this->config()['debug']) { + $this->grav['log']->addDebug(sprintf("<<<< Loaded cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); + } + } } @@ -1267,17 +1266,19 @@ class FormPlugin extends Plugin */ protected function saveCachedForms(): void { - // Save the current state of the forms to cache - if (!$this->recache_forms) { - return; - } - - $this->recache_forms = false; - /** @var Cache $cache */ $cache = $this->grav['cache']; + $cache_id = $this->getFormCacheId(); - $cache->save($this->getFormCacheId(), [$this->forms]); + $forms = $cache->fetch($cache_id); + if ($forms) { + $this->forms = Utils::arrayMergeRecursiveUnique($this->forms, $forms); + } + + $cache->save($cache_id, $this->forms); + if ($this->config()['debug']) { + $this->grav['log']->addDebug(sprintf(">>>> Saved cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); + } } /** @@ -1287,10 +1288,10 @@ class FormPlugin extends Plugin */ protected function getFormCacheId(): string { - /** @var Pages $pages */ - $pages = $this->grav['pages']; - - return $pages->getPagesCacheId() . '-form-plugin'; + /** @var \Grav\Common\Cache $cache */ + $cache = $this->grav['cache']; + $cache_id = $cache->getKey() . '-form-plugin'; + return $cache_id; } /** @@ -1323,4 +1324,25 @@ class FormPlugin extends Plugin exit; } } + + protected function arrayToString($array, $level = 2) { + $result = $this->limitArrayLevels($array, $level); + return json_encode($result, JSON_UNESCAPED_SLASHES); + } + + protected function limitArrayLevels($array, $levelsToKeep, $currentLevel = 0) { + if ($currentLevel >= $levelsToKeep) { + return '-'; + } + + $result = []; + foreach ($array as $key => $value) { + if (is_array($value)) { + $value = $this->limitArrayLevels($value, $levelsToKeep, $currentLevel + 1); + } + $result[$key] = $value; + } + + return $result; + } } diff --git a/plugins/form/form.yaml b/plugins/form/form.yaml index 29793ca..27124a0 100644 --- a/plugins/form/form.yaml +++ b/plugins/form/form.yaml @@ -3,6 +3,7 @@ built_in_css: true inline_css: true refresh_prevention: false client_side_validation: true +debug: false inline_errors: false files: multiple: false # To allow multiple files, default is single diff --git a/plugins/login/CHANGELOG.md b/plugins/login/CHANGELOG.md index 6bc6ad4..a360aac 100644 --- a/plugins/login/CHANGELOG.md +++ b/plugins/login/CHANGELOG.md @@ -1,3 +1,16 @@ +# v3.7.6 +## 06/29/2023 + +1. [](#bugfix) + * Don't save an empty user file on password reset of non-existing user + +# v3.7.5 +## 06/14/2023 + +1. [](#bugfix) + * Sanitized `email` during the "forgot password" process to protect against XSS attacks + * Fixed an account enumeration vulnerability in forgot password [#293](https://github.com/getgrav/grav-plugin-login/pull/293) + # v3.7.4 ## 05/09/2023 diff --git a/plugins/login/blueprints.yaml b/plugins/login/blueprints.yaml index e6b1b20..ce93d34 100644 --- a/plugins/login/blueprints.yaml +++ b/plugins/login/blueprints.yaml @@ -1,7 +1,7 @@ name: Login slug: login type: plugin -version: 3.7.4 +version: 3.7.6 testing: false description: Enables user authentication and login screen. icon: sign-in diff --git a/plugins/login/classes/Controller.php b/plugins/login/classes/Controller.php index e5cffda..ed006d7 100644 --- a/plugins/login/classes/Controller.php +++ b/plugins/login/classes/Controller.php @@ -347,80 +347,66 @@ class Controller $config = $this->grav['config']; $data = $this->post; - /** @var UserCollectionInterface $users */ - $users = $this->grav['accounts']; - - $email = $data['email'] ?? ''; - $user = !empty($email) ? $users->find($email, ['email']) : null; - /** @var Language $language */ $language = $this->grav['language']; $messages = $this->grav['messages']; - if (!isset($this->grav['Email'])) { - $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); - $this->setRedirect($this->login->getRoute('forgot') ?? '/'); + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + $email = $data['email'] ?? ''; - return true; - } + // Sanitize $email + $email = htmlspecialchars(strip_tags($email), ENT_QUOTES, 'UTF-8'); - if (!$user || !$user->exists()) { - $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_USERNAME_DOES_NOT_EXIST', $email]), 'error'); - $this->setRedirect($this->login->getRoute('forgot') ?? '/'); + // Find user if they exist + $user = $users->find($email, ['email']); - return true; - } + if ($user->exists()) { + if (!isset($this->grav['Email'])) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); + $this->setRedirect($this->login->getRoute('forgot') ?? '/'); - if (empty($user->email)) { - $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL', $email]), - 'error'); - $this->setRedirect($this->login->getRoute('forgot') ?? '/'); + return true; + } - return true; - } + $from = $config->get('plugins.email.from'); - if (empty($user->password) && empty($user->hashed_password)) { - $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD', $email]), - 'error'); - $this->setRedirect($this->login->getRoute('forgot') ?? '/'); + if (empty($from)) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); + $this->setRedirect($this->login->getRoute('forgot') ?? '/'); - return true; - } + return true; + } - $from = $config->get('plugins.email.from'); + $userKey = $user->username; + $rateLimiter = $this->login->getRateLimiter('pw_resets'); + $rateLimiter->registerRateLimitedAction($userKey); - if (empty($from)) { - $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); - $this->setRedirect($this->login->getRoute('forgot') ?? '/'); + if ($rateLimiter->isRateLimited($userKey)) { + $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_IT_IS_BLOCKED', $email, $rateLimiter->getInterval()]), 'error'); + $this->setRedirect($this->login->getRoute('login') ?? '/'); - return true; - } + return true; + } - $userKey = $user->username; - $rateLimiter = $this->login->getRateLimiter('pw_resets'); - $rateLimiter->registerRateLimitedAction($userKey); + $token = md5(uniqid((string)mt_rand(), true)); + $expire = time() + 604800; // next week - if ($rateLimiter->isRateLimited($userKey)) { - $messages->add($language->translate(['PLUGIN_LOGIN.FORGOT_CANNOT_RESET_IT_IS_BLOCKED', $email, $rateLimiter->getInterval()]), 'error'); - $this->setRedirect($this->login->getRoute('login') ?? '/'); + $user->reset = $token . '::' . $expire; + $user->save(); - return true; - } - - $token = md5(uniqid((string)mt_rand(), true)); - $expire = time() + 604800; // next week - - $user->reset = $token . '::' . $expire; - $user->save(); - - try { - Email::sendResetPasswordEmail($user); + try { + Email::sendResetPasswordEmail($user); + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL'), 'info'); + } catch (\Exception $e) { + $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_FAILED_TO_EMAIL'), 'error'); + } + } else { $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL'), 'info'); - } catch (\Exception $e) { - $messages->add($language->translate('PLUGIN_LOGIN.FORGOT_FAILED_TO_EMAIL'), 'error'); } + $this->setRedirect($this->login->getRoute('login') ?? '/'); return true; diff --git a/plugins/login/languages/de.yaml b/plugins/login/languages/de.yaml index 1af8a8b..c353d84 100644 --- a/plugins/login/languages/de.yaml +++ b/plugins/login/languages/de.yaml @@ -21,9 +21,6 @@ PLUGIN_LOGIN: RESET_INVALID_LINK: "Es wurde ein ungültiger Link zum Zurücksetzen verwendet. Bitte erneut versuchen." FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Die Anweisungen zum Zurücksetzen Ihres Passworts wurden per E-Mail gesendet." FORGOT_FAILED_TO_EMAIL: "Das Versenden der Anweisung per E-Mail ist fehlgeschlagen. Bitte später erneut versuchen." - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Das Passwort für %s kann nicht zurückgesetzt werden. Es ist keine E-Mail-Adresse hinterlegt." - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Das Passwort für %s kann nicht zurückgesetzt werden. Diese E-Mail ist mit einem Remote-Account verknüpft." - FORGOT_USERNAME_DOES_NOT_EXIST: "Der Benutzer mit dem Benutzername %s existiert nicht." FORGOT_EMAIL_NOT_CONFIGURED: "Das Passwort kann nicht zurückgesetzt werden, da die Website ist nicht zum Versenden von E-Mails konfiguriert." FORGOT_EMAIL_SUBJECT: "Passwort zurückzusetzen für %s" FORGOT_EMAIL_BODY: "

Passwort Zurücksetzen

Hallo %1$s,

Es wurde ein Anfrage auf %4$s gestellt, um Ihr Passwort zu ändern.


Klicken Sie hier, um Ihr Passwort zurückzusetzen

Alternativ kopieren Sie die folgende URL in die Adresszeile Ihres Browsers:

%2$s


Mit freundlichen Grüßen,

%3$s

" diff --git a/plugins/login/languages/en.yaml b/plugins/login/languages/en.yaml index 895ba26..c3eb1f1 100644 --- a/plugins/login/languages/en.yaml +++ b/plugins/login/languages/en.yaml @@ -18,11 +18,8 @@ PLUGIN_LOGIN: RESET_LINK_EXPIRED: "Reset link has expired, please try again" RESET_PASSWORD_RESET: "Password has been reset" RESET_INVALID_LINK: "Invalid reset link used, please try again" - FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instructions to reset your password have been sent via email" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "If an account exists, instructions on resetting your password have been sent via email" FORGOT_FAILED_TO_EMAIL: "Failed to email instructions, please try again later" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Cannot reset password for %s, no email address is set" - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Cannot reset password for %s, this email is associated with a remote account" - FORGOT_USERNAME_DOES_NOT_EXIST: "User with username %s does not exist" FORGOT_EMAIL_NOT_CONFIGURED: "Cannot reset password. This site is not configured to send emails" FORGOT_EMAIL_SUBJECT: "%s Password Reset Request" FORGOT_EMAIL_BODY: "

Password Reset

Dear %1$s,

A request was made on %4$s to reset your password.


Click this to reset your password

Alternatively, copy the following URL into your browser's address bar:

%2$s


Kind regards,

%3$s

" diff --git a/plugins/login/languages/es.yaml b/plugins/login/languages/es.yaml index eb9a27d..ed4aa95 100644 --- a/plugins/login/languages/es.yaml +++ b/plugins/login/languages/es.yaml @@ -19,10 +19,8 @@ PLUGIN_LOGIN: RESET_LINK_EXPIRED: "El enlace para la restauración ha caducado, inténtelo de nuevo." RESET_PASSWORD_RESET: "La contraseña ha sido restaurada" RESET_INVALID_LINK: "Ha utilizado un enlace de restauración inválido, inténtelo de nuevo." - FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instructions to reset your password have been sent via email" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "If an account exists, instructions on resetting your password have been sent via email" FORGOT_FAILED_TO_EMAIL: "No se ha podido enviar el email con instrucciones, inténtelo de nuevo." - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "No se puede restaurar la contraseña para %s, no hay dirección de email." - FORGOT_USERNAME_DOES_NOT_EXIST: "No existe ningún usuario con el nombre %s." FORGOT_EMAIL_NOT_CONFIGURED: "No se puede restaurar la contraseña. Este sitio no está configurado para enviar emails." FORGOT_EMAIL_SUBJECT: "%s solicitud de restauración de contraseña" FORGOT_EMAIL_BODY: "

Restauración de contraseña

Estimado/a %1$s,

Se ha realizado una petición de restauración de contraseña en %4$s.


Pulse aquí para restaurar su contraseña

Como alternativa puede copiar la siguiente URL en la barra de direcciones de su navegador:

%2$s


Saludos cordiales,

%3$s

" diff --git a/plugins/login/languages/fr.yaml b/plugins/login/languages/fr.yaml index f98c5ac..8ee745f 100644 --- a/plugins/login/languages/fr.yaml +++ b/plugins/login/languages/fr.yaml @@ -19,8 +19,6 @@ PLUGIN_LOGIN: RESET_INVALID_LINK: "Le lien de réinitialisation utilisé n’est pas valide, veuillez réessayer" FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Les instructions pour la réinitialisation de votre mot de passe ont été envoyées par e-mail" FORGOT_FAILED_TO_EMAIL: "Impossible d’envoyer les instructions, veuillez réessayer ultérieurement" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Impossible de réinitialiser le mot de passe pour %s, aucune adresse e-mail n’a été paramétrée" - FORGOT_USERNAME_DOES_NOT_EXIST: "L’utilisateur avec le nom d’utilisateur %s n’existe pas" FORGOT_EMAIL_NOT_CONFIGURED: "Impossible de réinitialiser le mot de passe. Ce site n’est pas configuré pour envoyer des e-mails" FORGOT_EMAIL_SUBJECT: "Demande de réinitialisation de mot de passe %s" FORGOT_EMAIL_BODY: "

Réinitialisation de mot de passe

%1$s,

Une demande a été faite sur %4$s pour la réinitialisation de votre mot de passe.


Cliquez ici pour réinitialiser votre mot de passe

Vous pouvez également copier l’URL suivante dans la barre d’adresse de votre navigateur :

%2$s


Cordialement,

%3$s

" diff --git a/plugins/login/languages/lt.yaml b/plugins/login/languages/lt.yaml index 12be54a..b29415e 100644 --- a/plugins/login/languages/lt.yaml +++ b/plugins/login/languages/lt.yaml @@ -18,12 +18,9 @@ PLUGIN_LOGIN: RESET_LINK_EXPIRED: "Atstatymo nuoroda nebegalioja, bandykite dar kartą" RESET_PASSWORD_RESET: "Slaptažodis atstatytas" RESET_INVALID_LINK: "Panaudota neteisinga atstatymo nuoroda, bandykite dar kartą" - FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Slaptažodžio atstatymo instrukcijos buvo išsiųstos el. paštu" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Jeigu vartotojo paskyra egzistuoja, slaptažodžio atstatymo instrukcijos buvo išsiųstos el. paštu" FORGOT_FAILED_TO_EMAIL: "Instrukcijų išsiuntimas nepavyko, bandykite dar kartą" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Negalima atstatyti %s slaptažodžio, nenurodytas el. paštas" - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Negalima atstatyti %s slaptažodžio, šis el. paštas susietas su nuotoline paskyra" - FORGOT_USERNAME_DOES_NOT_EXIST: "Vartotojas vardu %s neegzistuoja" - FORGOT_EMAIL_NOT_CONFIGURED: "Negalima tastatyti slaptažodžio. Ši svetainė nenustatyta siųsti el. laiškus" + FORGOT_EMAIL_NOT_CONFIGURED: "Negalima atstatyti slaptažodžio. Ši svetainė nenustatyta siųsti el. laiškus" FORGOT_EMAIL_SUBJECT: "%s slaptažodžio atstatymo užklausa" FORGOT_EMAIL_BODY: "

Slaptažodis atstatytas

Miela(s) %1$s,

%4$s buvo gauta užklausa jūsų slaptažodžio atstatymui.


Paspauskite čia norėdami atstatyti slaptažodį

Taip pat galite nukopijuoti sekančią nuorodą į savo naršyklės adreso juostą:

%2$s


Linkėjimai,

%3$s

" SESSION: "“Prisiminti mane”-sesija" diff --git a/plugins/login/languages/no.yaml b/plugins/login/languages/no.yaml index a8ca03a..098a361 100644 --- a/plugins/login/languages/no.yaml +++ b/plugins/login/languages/no.yaml @@ -21,8 +21,6 @@ PLUGIN_LOGIN: RESET_INVALID_LINK: "Ugyldig ilbakestillingslenke, vennligst prøv igjen" FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Instruksjoner for å tilbakestille passordet ditt er sendt via e-post" FORGOT_FAILED_TO_EMAIL: "Kunne ikke sende instruksjoner, prøv igjen senere" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Kan ikke tilbakestille passord for %s, ingen e-postadresse er angitt" - FORGOT_USERNAME_DOES_NOT_EXIST: "Bruker med brukernavn %s eksisterer ikke" FORGOT_EMAIL_NOT_CONFIGURED: "Kan ikke tilbakestille passord. Dette nettstedet er ikke konfigurert til å sende e-post" FORGOT_EMAIL_SUBJECT: "Forespørsel om tilbakestilling av passord for %s" FORGOT_EMAIL_BODY: "

Tilbekestilling av passord

%1$s,

En forespørsel om tilbakestilling av passord ble gjort på %4$s.


Klikk her for å tilbakestille passordet ditt

Du kan også kopiere følgende nettadresse til nettleserens adressefelt:

%2$s


Vennlig hilsen,

%3$s

" diff --git a/plugins/login/languages/pt-BR.yaml b/plugins/login/languages/pt-BR.yaml index c5ee63b..2aca491 100644 --- a/plugins/login/languages/pt-BR.yaml +++ b/plugins/login/languages/pt-BR.yaml @@ -17,9 +17,6 @@ PLUGIN_LOGIN: RESET_INVALID_LINK: "Link de recuperação de senha inválido, tente novamente!" FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "As instruções para recuperar sua senha foram enviadas para seu e-mail!" FORGOT_FAILED_TO_EMAIL: "Falha ao tentar recuperar a senha, tente novamente mais tarde!" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Não é possível recuperar a senha para %s, nenhum e-mail inserido!" - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Não é possível recuperar a senha para %s, este e-mail já está em uso!" - FORGOT_USERNAME_DOES_NOT_EXIST: "O usuário %s não existe!" FORGOT_EMAIL_NOT_CONFIGURED: "Não é possível recuperar a senha. Este site não está configurado para enviar e-mails!" FORGOT_EMAIL_SUBJECT: "%s requer recuperação da senha" FORGOT_EMAIL_BODY: "

Recuperação da Senha

Olá %1$s,

Foi feito um pedido no %4$s para recuperar sua senha.


Clique aqui para recuperar sua senha

Como alternativa, copie a seguinte URL na barra de endereços do navegador:

%2$s


Atenciosamente,

%3$s

" diff --git a/plugins/login/languages/ru.yaml b/plugins/login/languages/ru.yaml index 3ee8b61..528674c 100644 --- a/plugins/login/languages/ru.yaml +++ b/plugins/login/languages/ru.yaml @@ -19,11 +19,8 @@ PLUGIN_LOGIN: RESET_LINK_EXPIRED: "Время ссылки для сброса истекло, повторите попытку" RESET_PASSWORD_RESET: "Пароль был сброшен" RESET_INVALID_LINK: "Неверная ссылка сброса, повторите попытку" - FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Инструкции по сбросу пароля были отправлены по электронной почте" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Eсли имя пользователя существует, инструкции по сбросу пароля были отправлены по электронной почте" FORGOT_FAILED_TO_EMAIL: "Не удалось отправить инструкции по электронной почте, повторите попытку позже" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Не удается сбросить пароль для %s, адресс электронной почты не установлен" - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Невозможно сбросить пароль для %s, этот email связан с удаленной учетной записью" - FORGOT_USERNAME_DOES_NOT_EXIST: "Пользователь с именем %s не существует" FORGOT_EMAIL_NOT_CONFIGURED: "Невозможно сбросить пароль. Этот сайт не настроен для отправки писем" FORGOT_EMAIL_SUBJECT: "%s Запрос на сброс пароля" FORGOT_EMAIL_BODY: "

Восстановление пароля

Уважаемый %1$s,

Был сделан запрос для сброса пароля от %4$s.


Нажмите, чтобы сбросить пароль

Или скопируйте следующий URL-адрес в адресную строку браузера:

%2$s


С уважением,

%3$s

" diff --git a/plugins/login/languages/uk.yaml b/plugins/login/languages/uk.yaml index e0a0393..66be594 100644 --- a/plugins/login/languages/uk.yaml +++ b/plugins/login/languages/uk.yaml @@ -19,11 +19,8 @@ PLUGIN_LOGIN: RESET_LINK_EXPIRED: "Час посилання для скидання минув, спробуйте ще раз" RESET_PASSWORD_RESET: "Пароль був скинутий" RESET_INVALID_LINK: "Невірне посилання скидання, спробуйте ще раз" - FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Інструкції щодо скидання пароля були надіслані по електронній пошті" + FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Якщо ім'я користувача існує, iнструкції щодо скидання пароля були надіслані по електронній пошті" FORGOT_FAILED_TO_EMAIL: "Не вдалося надіслати інструкції електронною поштою, повторіть спробу пізніше" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Не вдається скинути пароль для %s, адреса електронної пошти не встановлена" - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "Неможливо скинути пароль для %s, цей email пов'язаний з віддаленим обліковим записом" - FORGOT_USERNAME_DOES_NOT_EXIST: "Користувач з ім'ям %s не існує" FORGOT_EMAIL_NOT_CONFIGURED: "Неможливо скинути пароль. Цей сайт не налаштований для надіслання листів" FORGOT_EMAIL_SUBJECT: "%s Запит на скидання пароля" FORGOT_EMAIL_BODY: "

Відновлення паролю

Шановний %1$s,

Був зроблений запит для скидання пароля від %4$s.


Нажмите, чтобы сбросить пароль

Или скопируйте следующий URL-адрес в адресную строку браузера:

%2$s


С уважением,

%3$s

" diff --git a/plugins/login/languages/zh.yaml b/plugins/login/languages/zh.yaml index bfca18f..e8f2691 100644 --- a/plugins/login/languages/zh.yaml +++ b/plugins/login/languages/zh.yaml @@ -17,9 +17,6 @@ PLUGIN_LOGIN: RESET_INVALID_LINK: "重置链接已经使用,请重试" FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "重置密码指引已经发送到您的邮箱。" FORGOT_FAILED_TO_EMAIL: "发送指引邮件失败,请稍后重试。" - FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "因尚未设置邮箱,无法为 %s 重置密码" - FORGOT_CANNOT_RESET_EMAIL_NO_PASSWORD: "因邮箱关联到一个外部帐号,无法为 %s 重置密码。" - FORGOT_USERNAME_DOES_NOT_EXIST: "用户 %s 不存在。" FORGOT_EMAIL_NOT_CONFIGURED: "无法重置密码,本站点尚未配置邮件系统。" FORGOT_EMAIL_SUBJECT: "%s 的密码重置请求" FORGOT_EMAIL_BODY: "

密码充值

尊敬的 %1$s,

我们收到一个重置您的 %4$s 密码的请求。


点击这里进行重置密码

另外,您也可以复制下面的链接到浏览器地址栏中访问:

%2$s


此致

%3$s

"