Send link to set new password in SendNewPasswordWorker
authorTim Düsterhus <duesterhus@woltlab.com>
Fri, 29 Jul 2016 21:20:46 +0000 (23:20 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Fri, 29 Jul 2016 21:20:46 +0000 (23:20 +0200)
com.woltlab.wcf/templates/email_sendNewPassword.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/system/worker/SendNewPasswordWorker.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

diff --git a/com.woltlab.wcf/templates/email_sendNewPassword.tpl b/com.woltlab.wcf/templates/email_sendNewPassword.tpl
new file mode 100644 (file)
index 0000000..5a3a139
--- /dev/null
@@ -0,0 +1,19 @@
+{if $mimeType === 'text/plain'}
+{capture assign='content'}{lang}wcf.acp.user.sendNewPassword.mail.plaintext{/lang}{/capture}
+{include file='email_plaintext'}
+{else}
+       {capture assign='content'}
+       <h1>{lang}wcf.acp.user.sendNewPassword.mail.html.headline{/lang}</h1>
+       {lang}wcf.acp.user.sendNewPassword.mail.html.intro{/lang}
+
+       {capture assign=button}
+       <a href="{link controller='NewPassword' object=$mailbox->getUser() isEmail=true}k={@$mailbox->getUser()->lostPasswordKey}{/link}">
+               {lang}wcf.acp.user.sendNewPassword.mail.html.reset{/lang}
+       </a>
+       {/capture}
+       {include file='email_paddingHelper' class='button' content=$button sandbox=true}
+
+       {lang}wcf.acp.user.sendNewPassword.mail.html.outro{/lang}
+       {/capture}
+       {include file='email_html'}
+{/if}
index 7e53f2e2d93b794bba8a5b20e42be104a32eea6c..b455fe730e0a0cacc13fb6a1cd961067ff42a4e2 100644 (file)
@@ -1,14 +1,19 @@
 <?php
 namespace wcf\system\worker;
+use wcf\data\user\User;
 use wcf\data\user\UserAction;
 use wcf\data\user\UserEditor;
 use wcf\data\user\UserList;
 use wcf\system\clipboard\ClipboardHandler;
 use wcf\system\exception\SystemException;
-use wcf\system\mail\Mail;
+use wcf\system\email\mime\MimePartFacade;
+use wcf\system\email\mime\RecipientAwareTextMimePart;
+use wcf\system\email\Email;
+use wcf\system\email\UserMailbox;
 use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
-use wcf\util\PasswordUtil;
+use wcf\util\exception\CryptoException;
+use wcf\util\CryptoUtil;
 
 /**
  * Worker implementation for sending new passwords.
@@ -22,7 +27,7 @@ class SendNewPasswordWorker extends AbstractWorker {
        /**
         * @inheritDoc
         */
-       protected $limit = 50;
+       protected $limit = 20;
        
        /**
         * @inheritDoc
@@ -47,7 +52,18 @@ class SendNewPasswordWorker extends AbstractWorker {
                
                /** @var UserEditor $userEditor */
                foreach ($userList as $userEditor) {
-                       $this->sendNewPassword($userEditor);
+                       $this->resetPassword($userEditor);
+               }
+               
+               $userList = new UserList();
+               $userList->getConditionBuilder()->add('user_table.userID IN (?)', [$this->parameters['userIDs']]);
+               $userList->sqlLimit = $this->limit;
+               $userList->sqlOffset = $this->limit * $this->loopCount;
+               $userList->readObjects();
+               
+               /** @var User $user */
+               foreach ($userList as $user) {
+                       $this->sendLink($user);
                }
        }
        
@@ -73,25 +89,43 @@ class SendNewPasswordWorker extends AbstractWorker {
        }
        
        /**
-        * Sends a new password to the given user.
+        * Resets the password of the given user.
         * 
-        * @param       \wcf\data\user\UserEditor       $userEditor
+        * @param       UserEditor      $userEditor
         */
-       protected function sendNewPassword(UserEditor $userEditor) {
+       protected function resetPassword(UserEditor $userEditor) {
+               try {
+                       $lostPasswordKey = bin2hex(CryptoUtil::randomBytes(20));
+                       $lastLostPasswordRequestTime = TIME_NOW;
+               }
+               catch (CryptoException $e) {
+                       $lostPasswordKey = null;
+                       $lastLostPasswordRequestTime = 0;
+               }
                $userAction = new UserAction([$userEditor], 'update', [
                        'data' => [
-                               'password' => null
+                               'password' => null,
+                               'lostPasswordKey' => $lostPasswordKey,
+                               'lastLostPasswordRequestTime' => $lastLostPasswordRequestTime
                        ]
                ]);
                $userAction->executeAction();
-               
-               // send mail
-               // TODO: Send link
-               $mail = new Mail([$userEditor->username => $userEditor->email], $userEditor->getLanguage()->getDynamicVariable('wcf.acp.user.sendNewPassword.mail.subject'), $userEditor->getLanguage()->getDynamicVariable('wcf.acp.user.sendNewPassword.mail', [
-                       'password' => $newPassword,
-                       'username' => $userEditor->username
+       }
+       
+       /**
+        * Send links.
+        * 
+        * @param       User    $user
+        */
+       protected function sendLink(User $user) {
+               $email = new Email();
+               $email->addRecipient(new UserMailbox($user));
+               $email->setSubject($user->getLanguage()->getDynamicVariable('wcf.acp.user.sendNewPassword.mail.subject'));
+               $email->setBody(new MimePartFacade([
+                       new RecipientAwareTextMimePart('text/html', 'email_sendNewPassword'),
+                       new RecipientAwareTextMimePart('text/plain', 'email_sendNewPassword')
                ]));
-               $mail->send();
+               $email->send();
        }
        
        /**
index 22f1496b895bea00c2b182606b2e98609a1c2a6b..9dc3b5e3c59d74f8ded99249723e17488608f5e5 100644 (file)
@@ -1795,6 +1795,27 @@ Wenn {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} unter <em>System -&gt; O
 
 {if LANGUAGE_USE_INFORMAL_VARIANT}Klicke hier, um dich mit deinem{else}Klicken Sie hier, um sich mit Ihrem{/if} neuen Kennwort anzumelden: {link controller='Login' isEmail=true}{/link}]]></item>
                <item name="wcf.acp.user.sendNewPassword.mail.subject"><![CDATA[Neues Kennwort für {if LANGUAGE_USE_INFORMAL_VARIANT}dein{else}Ihr{/if} Benutzerkonto auf der Website: {@PAGE_TITLE|language}]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.plaintext"><![CDATA[Hallo {@$mailbox->getUser()->username},
+
+ein Administrator hat {if LANGUAGE_USE_INFORMAL_VARIANT}dein{else}Ihr{/if} Kennwort zurück gesetzt. Es ist nun
+erforderlich, dass {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} nun ein neues Kennwort setzen, damit {if LANGUAGE_USE_INFORMAL_VARIANT}du dein {else}Sie ihr {/if}
+Benutzerkonto {@$mailbox->getUser()->username} auf der Seite {@PAGE_TITLE|language} [URL:{link isEmail=true}{/link}]
+weiterhin verwenden {if LANGUAGE_USE_INFORMAL_VARIANT}kannst{else}können{/if}:
+
+    {link controller='NewPassword' object=$mailbox->getUser() isEmail=true}k={@$mailbox->getUser()->lostPasswordKey}{/link} {* this line ends with a space *}
+
+{if LANGUAGE_USE_INFORMAL_VARIANT}Solltest du{else}Sollten Sie{/if} diese Nachricht erst nach dem {$mailbox->getUser()->lastLostPasswordRequestTime+86400|plainTime} lesen, ist es
+aus Sicherheitsgründen erforderlich, dass Sie die Kennwort vergessen-Funktion [URL:{link controller='LostPassword' isEmail=true}{/link}] nutzen.]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.headline"><![CDATA[Hallo {@$mailbox->getUser()->username},]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.intro"><![CDATA[
+<p>ein Administrator hat {if LANGUAGE_USE_INFORMAL_VARIANT}dein{else}Ihr{/if} Kennwort zurück gesetzt. Es ist nun
+erforderlich, dass {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} nun ein neues Kennwort setzen, damit {if LANGUAGE_USE_INFORMAL_VARIANT}du dein{else}Sie ihr{/if}
+Benutzerkonto {@$mailbox->getUser()->username} auf der Seite <a href="{link isEmail=true}{/link}">{@PAGE_TITLE|language}</a>
+weiterhin verwenden {if LANGUAGE_USE_INFORMAL_VARIANT}kannst{else}können{/if}:</p>]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.reset"><![CDATA[Neues Kennwort setzen]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.outro"><![CDATA[
+<p>{if LANGUAGE_USE_INFORMAL_VARIANT}Solltest du{else}Sollten Sie{/if} diese Nachricht erst nach dem {$mailbox->getUser()->lastLostPasswordRequestTime+86400|plainTime} lesen, ist es
+aus Sicherheitsgründen erforderlich, dass Sie die <a href="{link controller='LostPassword' isEmail=true}{/link}">Kennwort vergessen-Funktion</a> nutzen.</p>]]></item>
                <item name="wcf.acp.user.sendNewPassword.workerTitle"><![CDATA[Neue Passwörter zusenden]]></item>
                <item name="wcf.acp.user.authentication.failure.list"><![CDATA[Fehlgeschlagene Anmeldungen]]></item>
                <item name="wcf.acp.user.authentication.failure.environment"><![CDATA[Umgebung]]></item>
index 6ed03af0cbbfe4587d7398352da572a17557363f..80ac2a37bf65ff54d794752454b5060e640b2729 100644 (file)
@@ -1761,13 +1761,24 @@ You can define the default sender in <em>System -&gt; Options -&gt; General -&gt
                <item name="wcf.acp.user.usersAwaitingApprovalInfo"><![CDATA[<a href="{link controller='UserQuickSearch'}mode=disabled{/link}">{#$usersAwaitingApproval} User{if $usersAwaitingApproval != 1}s{/if}</a> {if $usersAwaitingApproval == 1}is{else}are{/if} awaiting your approval.]]></item>
                <item name="wcf.acp.user.search.conditions.state.enabled"><![CDATA[Approved]]></item>
                <item name="wcf.acp.user.search.conditions.state.disabled"><![CDATA[Awaiting approval]]></item>
-               <item name="wcf.acp.user.sendNewPassword.mail"><![CDATA[Dear {@$username},
+               <item name="wcf.acp.user.sendNewPassword.mail.subject"><![CDATA[New Password for your Account for Website: {@PAGE_TITLE|language}]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.plaintext"><![CDATA[Dear {@$mailbox->getUser()->username},
 
-Your password has been changed by an administrator.
-Your new password is: {$password}
+an administrator resetted your password. You are now required to set a new password to be able to use your
+user account {@$mailbox->getUser()->username} on the website {@PAGE_TITLE|language} [URL:{link isEmail=true}{/link}] again:
 
-Login with your new password: {link controller='Login' isEmail=true}{/link}]]></item>
-               <item name="wcf.acp.user.sendNewPassword.mail.subject"><![CDATA[New Password for your Account for Website: {@PAGE_TITLE|language}]]></item>
+    {link controller='NewPassword' object=$mailbox->getUser() isEmail=true}k={@$mailbox->getUser()->lostPasswordKey}{/link} {* this line ends with a space *}
+
+If you read this message after {$mailbox->getUser()->lastLostPasswordRequestTime+86400|plainTime} you’ll have to use
+the lost password form [URL:{link controller='LostPassword' isEmail=true}{/link}] for security reasons.]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.headline"><![CDATA[Dear {@$mailbox->getUser()->username},]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.intro"><![CDATA[
+<p>an administrator resetted your password. You are now required to set a new password to be able to use your
+user account {@$mailbox->getUser()->username} on the website <a href="{link isEmail=true}{/link}">{@PAGE_TITLE|language}</a> again:</p>]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.reset"><![CDATA[Choose new password]]></item>
+               <item name="wcf.acp.user.sendNewPassword.mail.html.outro"><![CDATA[
+<p>If you read this message after {$mailbox->getUser()->lastLostPasswordRequestTime+86400|plainTime} you’ll have to use
+the lost password form <a href="{link controller='LostPassword' isEmail=true}{/link}">lost password form</a> for security reasons.</p>]]></item>
                <item name="wcf.acp.user.sendNewPassword.workerTitle"><![CDATA[Sending New Passwords]]></item>
                <item name="wcf.acp.user.authentication.failure.list"><![CDATA[Failed Login Attempts]]></item>
                <item name="wcf.acp.user.authentication.failure.environment"><![CDATA[Environment]]></item>