Email confirmation for changing email in Settings#27277
Email confirmation for changing email in Settings#27277PVince81 merged 11 commits intoowncloud:masterfrom imujjwal96:master
Conversation
|
@imujjwal96, thanks for your PR! By analyzing the history of the files in this pull request, we identified @DeepDiver1975, @phisch and @mmattel to be potential reviewers. |
.htaccess
Outdated
| <IfModule pagespeed_module> | ||
| ModPagespeed Off | ||
| </IfModule> | ||
| #### DO NOT CHANGE ANYTHING ABOVE THIS LINE #### |
There was a problem hiding this comment.
Oh! Didn't intend to add them. Guess they were added automatically. Will delete them in the next push.
| if ($splittedToken[0] < ($this->timeFactory->getTime() - 60*60*12) || | ||
| $user->getLastLogin() > $splittedToken[0]) { | ||
| $this->config->deleteUserValue($userId, 'owncloud', 'changemail'); | ||
| throw new \Exception($this->l10n->t('Couldn\'t change the email address because the token is expired')); |
There was a problem hiding this comment.
I suggest to always say "invalid", so an attacker cannot guess whether a token used to be valid.
There was a problem hiding this comment.
This piece of code is inspired from the Reset password feature (tbh a copy+paste). Guess we'll have to correct it there too.
| * @throws \Exception | ||
| */ | ||
| public function sendEmail($user, $mailAddress) { | ||
| $token = $this->secureRandom->generate(21, |
| <input type="email" name="email" id="email" value="<?php p($_['email']); ?>" | ||
| placeholder="<?php p($l->t('Your email address'));?>" | ||
| autocomplete="on" autocapitalize="off" autocorrect="off" /> | ||
| <input id="emailbutton" type="button" value="<?php if(isset($_['email'][0])) { echo $l->t('Change email'); } else { echo $l->t('Set email'); }?>" /> |
There was a problem hiding this comment.
would it be possible to display an indicator that tells whether the email address has been confirmed already or whether it's still pending ?
There was a problem hiding this comment.
I will look into that.
| [ | ||
| 'status' => 'success', | ||
| 'data' => [ | ||
| 'message' => (string)$this->l10n->t('Email Sent.') |
There was a problem hiding this comment.
Also display a text like "An email has been sent to this address for confirmation".
Since the text is long, it might fit better in an orange temporary notification: OC.Notification.showTemporary(...) instead of inline.
There was a problem hiding this comment.
@PVince81 All notifications in the settings/personal route work similar to what i implemented. In fact the reason I did it was to maintain consistency. Changing the approach in one would require change in all of the forms in that page
|
@imujjwal96 it seems you linked to the wrong issue ? #6633 is about limiting password reset. I think there was another ticket about sending a confirmation email. |
|
@PVince81 A request for this feature was made in one of the comments of this issue so I referred it. I will search for the issue (if it is raised) and refer that instead. |
|
@PVince81 All checks have passed. I guess this PR is ready for a merge. Please have a look. |
PVince81
left a comment
There was a problem hiding this comment.
Overall this is a great addition!
Please see my comments for several minor issues in the code.
I'm going to test this now.
| * @throws \Exception | ||
| */ | ||
| public function sendEmail($user, $mailAddress, $action='change') { | ||
| $token = $this->secureRandom->generate(21, |
| $userObject = $this->userManager->get($user); | ||
| $email = $userObject->getEMailAddress(); | ||
|
|
||
| if ($action == 'change' || $action == 'add') { |
There was a problem hiding this comment.
use strict equality ===, see https://doc.owncloud.org/server/10.0/developer_manual/general/codingguidelines.html#operators
| * @param string $userId | ||
| * @param string $mailAddress | ||
| */ | ||
| public function setEmailAddress($userId, $mailAddress) { |
| * @param $mailAddress | ||
| * @return TemplateResponse | ||
| */ | ||
| public function changemail($token, $userId, $mailAddress) { |
settings/js/personal.js
Outdated
| * @param allowEmptyValue if this is set to true the callback is also called when the value is empty | ||
| */ | ||
|
|
||
| jQuery.fn.Enter = function (callback, allowEmptyValue) { |
settings/templates/error.php
Outdated
| <p class='hint'><?php print_unescaped($error['hint']) ?></p> | ||
| <?php endif;?> | ||
| </li> | ||
| <?php endforeach ?> |
There was a problem hiding this comment.
this could also be in a generic status template but only displayed if errors exist
There was a problem hiding this comment.
If showing status on the notification bar in the settings url is to be implemented, then i guess this will also be shown as a notification
There was a problem hiding this comment.
Good point. Yes, it could make it easier as it would be the same code path than the success message.
.htaccess
Outdated
| <IfModule pagespeed_module> | ||
| ModPagespeed Off | ||
| </IfModule> | ||
| </IfModule> No newline at end of file |
There was a problem hiding this comment.
no idea how this is messed.
| * @param string $userId | ||
| * @throws \Exception | ||
| */ | ||
| private function checkEmailChangeToken($token, $userId) { |
There was a problem hiding this comment.
You might need to check if $user is null and show an error/exception message. If the user was deleted in-between it could cause trouble.
| ); | ||
| } | ||
| $action = 'change'; | ||
| $message = 'An email has been sent to the old address for confirmation'; |
There was a problem hiding this comment.
please use the t() translation function here directly instead of below.
the reason is because there's a bot that parses the code to find the texts to submit for translation and it can only find the texts if they are directly wrapped in t()
|
|
||
| // delete user value if email address is empty | ||
| $user->setEMailAddress($mailAddress); | ||
| if ($mailAddress == '') { |
There was a problem hiding this comment.
use strict equality === (also check other places)
Comments/tasks
Test plan:
@imujjwal96 it's a great start but there are still many cases to handle. Let me know if you need any assistance 😄 |
|
Bug1: the action was supposed to perform whenever a user presses Enter or when "Set email" is clicked. if it is happening otherwise, i will try to fix it |
Yes, it is allowed. But an email is still sent out. When emptying the field no email should be sent. |
@PVince81 The email is always sent to the previous email address (one that was set before). This would prevent spamming mails to some extent |
But emptying should not send any email, there is no confirmation needed. I think that the purpose of the email itself is to confirm the email address itself, not to confirm the change. (even if the change leads to an empty value) Another issue if you send to the old email address is that the old email might not be valid / accessible any more. For example let's say a user has lost their email account / password (or left a university and was revoked access). Then they want to put their new email address in OC. They won't be able to because this PR sends to the old email address instead of the new one. I think we should always send to the new email address. Your concern about spamming is valid, not sure how other projects deal with that ? Maybe there needs to be a delay before sending email. For example don't let a user change their email more than once an hour or so. |
I think confirmation mails are always desirable and can't imagine why an admin would want to disable this. A config.php switch should not be necessary therefore.
Yes, good behavior would be to require the user password first and then send a confirmation link to the new address to confirm the change. Additionally it would be nice to send an email to the old address to inform about the change (this is how Dropbox handles it): "Your Dropbox account's email address was recently changed. Old email address: a@b.com If you didn't make this change, please let us know "
Yep, a short delay would make sense, maybe around 5 minutes. |
|
@pmaier1 I've now made the change. It sends confirmation only to the new mail address.
Can work on it. |
@PVince81 : Is this applicable to admin changing his own email address?
in apps/provisioning_api/lib/Users.php, the email address is changed by directly calling the function setEMailAddress on a User object. I guess it shouldn't send any confirmation email |
I'd say let's do it based on where it is changed. If the email address is changed in the settings page of the user (personal section), then always send a confirmation regardless. |
|
@PVince81 For Notifications, I was thinking to set the response message in the session and the get the message in the JS file and then use OC.Notif...... |
This won't work. Please don't store anything in the session. Also the JS code has no access to the session. One way to pass the notification type is to pass an additional argument in the URL: "#email_saved_status=value" where value could be "success", "error", etc... Then you can read the URL hash from the JS code and decide what message to display based on it. Then you can also remove the hash part after processing. |
|
@PVince81 There are some test files in the project which have in their setUp function whereas other files have Does one need to be refactored to other? |
No need to refactor right now, thanks |
In both cases I didn't have any email address set initially. |
|
@PVince81 What should be expected when a logged out user changes his email address? |
If by "changes his email address" you mean "open the link from the email", then the following should happen:
Now normally this should already work because the redirect logic already exists, but for some reason maybe some parameters are lost. I seem to remember advising you to use the hash part of the URL ? ("#something"). I think such parts might be lost on redirect, so maybe try using a real URL parameter instead like "&something" |
it was because there was some error in checking the validity of the email change token. This bug does not occur after correcting that. |
Test plan:
@PVince81 : Will again test all these before pushing |
@imujjwal96 otherwise the other test cases look good. @imujjwal96 side note: it seems there are conflicts that you'll need to resolve. Let me know if you need guidance for doing that as it can be tricky especially when working on your own fork. |
|
I've tested all the cases and they're working fine on my server.
What should I do? @PVince81 |
|
@imujjwal96 first make a backup of your branch: @imujjwal96 I see github has a button "Resolve conflicts" with a web editor, maybe you could first try with that ? |
|
Should I push the changes i made recently? |
sounds good |
|
@PVince81 I have made some changes through Github in order to resolve the conflicts. Can you review them now or do I have to first commit them? |
|
It seems the conflits still appear so maybe you need to commit them |
| @@ -0,0 +1,2 @@ | |||
| <?php | |||
| echo str_replace('{mailAddress}', $_['mailAddress'], $l->t('Email address changed to {mailAddress} successfully.')); | |||
There was a problem hiding this comment.
please delete this file it is not needed any more
There was a problem hiding this comment.
never mind, this is for the email contents
|
Code looks good otherwise, great job ! I'll redo a quick test and then I think this is good to go. |
|
👍 |
|
@imujjwal96 congrats! Merged. I think this PR doesn't fix the password reset limitation, right ? #6633 |
|
@PVince81 No it does not. Forgot to remove the reference to that issue. |
|
Regression found for group admins (aka subadmins) who cannot change a group member's email any more: #28035 |
| return new RedirectResponse($this->urlGenerator->linkToRoute('settings.SettingsPage.getPersonal', ['changestatus' => 'success'])); | ||
| } | ||
|
|
||
| /* |
There was a problem hiding this comment.
Accident here (missing 2nd asterisk for docblock) that causes regression #31280 "subadmin cannot disable member of his group"
There was a problem hiding this comment.
Can you check if there are other locations where there might be a docblock issue like that?
For reference, fix is in owncloud-archive/user_management#30
|
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Can be tested at: http://163.172.11.243:8080/core
Username: owncloud
Password: password
Description
When a user sets his/her email address for the first time, a confirmation mail is sent to the inputted address. From then onwards, every time a user tries to change/remove the email address, a confirmation mail is sent to the previous mail.
It also uses token validation (similar to reset password.)
Set Email / Change Email button added in front of the email input. Instead of changing email at every key delay, confirmation mail is sent when the user clicks on the button or when an Enter is pressed. Proper tests have been done.
Related Issue
Issue: #7326
Screenshots (if appropriate):
Types of changes
Checklist: