Feature #3109
openMake updating email / mobile / web3 xid more secure
0%
Description
Imagine you signed up with your email, but someone was able to get into your account (e.g. while you left your phone unlocked and went to the bathroom) changed your email address in the account, and logged out. Now you can't get into your account anymore!
Or, maybe they added a way to authenticate with your account while you weren't looking, such as mobile number or web3 wallet, etc. Now they can get into your account later, and even remove your way to log in!
We need to make this process more secure.
Current Code¶
Each user may already have a verified email address and mobile number. We should be sending them a notification whenever someone (who is logged in) uses setIdentifier to add or change their email / mobile number / web3 wallet. Before sending this notification, it should be verified (e.g. web3 signature, or send the usual email or mobile activation message with verification link, that is being sent now).
Don't change user row¶
Even though PHP will set state = verified for Users_Email, Users_Mobile or users_externalFrom/To tables, it should not be set yet inside the user account's "emailAddress", "mobileNumber" or "xids" fields.
(Well, only if xid is for web3 platform. For other platforms, you can indeed simply update the xid, because it might be more difficult to switch accounts and sign things in Facebook/Telegram than Web3).
When the user verifies the new email / mobile / xid, we already update users_email, users_mobile and users_external_from tables, and set the userId to the user. Now redirect user to a Users/identifiers action (page) where the user sees all user_email, users_mobile, and user_external_to by `userId`.
On this page, show the user's avatar and have a Users/identifiers tool that shows the identifiers and lets the user select the ones used for login. Group the identifiers by email, mobile, and (xid, platform, appId), with <optgroup> and radio buttons per group. Now match it to what's in the user
table now, under `emailAddress`, `mobileNumber` and `xids` and show radio buttons, with the selected radio button corresponding to what's in the user row.
While the user row doesn't match yet, on the me page, the user would have an orange clock icon instead of green checkmark. The setIdentifier dialog could have Users/identifiers tool also, but with "filter" option set to "email", "mobile" or "web3" (platform) with "appId" set to appId. That way it will show only that optgroup and not the others, allowing user to select from existing identifiers. The textbox and buttons would be below this tool.
Either way, the tool will allow the user to change radio buttons and click "Save Changes". This will do HTTP POST to Users/identifiers action and update users_user
row to the specified identifiers. The handler MUST double-check again, that the corresponding users_email, users_mobile and users_externalTo rows mention the userId, and don't just have identifiers verified by someone else.
Note that the user still needs to "approve" this change that was posted. Therefore it should send out a Users/email/changeIdentifiers template to email or mobile or both, if they are attached (so, 2 templates). The link in these templates would be clickable, to immediately approve this change. For example Users/identifiers/response but this time the querystring parameter ?Q.sig=... would approve it. You can use Q_Capability to sign the changes, and transmit just the signature. This Q.sig authorizes the changes to users_user table, which triggers hooks that send the notification (see section below).
Login¶
The login/post.php handler should now find the user row and should compare what's in that row vs the email/mobile/xid that was there. If user tries to log in using an identifier that isn't currently in the users_user table, it will throw a new Users_Exception_Identifier error similar to Users_Exception_AlreadyVerified but message would be 'This {{key}} is not the one you log in with'.
Send Notifications¶
There is a Streams hook after "Users/User/saveExecute" that works when user row has been successfully saved with changes, which updates Streams/user/emailAddress, Streams/user/mobileNumber, or Streams/user/xid/web3 and call ->changed() which generates Streams/changed message. The user would have been subscribed to this notification, and delivery happens as usual. This is to inform the user of these changes, if they have enabled any sort of ways to deliver notifications.