Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Allow password providers to bind emails #4947

Merged
merged 4 commits into from
Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/4947.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ability for password provider modules to bind email addresses to users upon registration.
32 changes: 32 additions & 0 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def register(
user_type=None,
default_display_name=None,
address=None,
bind_emails=[],
):
"""Registers a new client on the server.

Expand All @@ -172,6 +173,7 @@ def register(
default_display_name (unicode|None): if set, the new user's displayname
will be set to this. Defaults to 'localpart'.
address (str|None): the IP address used to perform the registration.
bind_emails (List[str]): list of emails to bind to this account.
Returns:
A tuple of (user_id, access_token).
Raises:
Expand Down Expand Up @@ -261,6 +263,10 @@ def register(
if not self.hs.config.user_consent_at_registration:
yield self._auto_join_rooms(user_id)

# Bind any specified emails to this account
for email in bind_emails:
yield self.bind_email_to_account(user_id, email)

defer.returnValue((user_id, token))

@defer.inlineCallbacks
Expand Down Expand Up @@ -406,6 +412,32 @@ def register_email(self, threepidCreds):
403, "Third party identifier is not allowed"
)

@defer.inlineCallbacks
def bind_email_to_account(self, user_id, email, validated_at=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless you have a reason for factoring this out, i feel like it may as well be inlined.

"""Binds an email address with the registered identity service.

Args:
user_id (str): The user id of the user to bind the email to.
email (str): The email to bind.
validated_at (int|None): Time to mark emails validated at. If
`None`, the current time is used.

Returns:
Deferred
"""

# generate threepid dict
threepid_dict = {
"medium": "email",
"address": email,
"validated_at": self.hs.get_clock().time_msec(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are ignoring the validated_at param

}

# Bind email to new account
yield self._register_email_threepid(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the record: where you have a function which just does some synchronous things and ends up calling an asynchronous function, you can skip @inlineCallbacks and just return the deferred from the other function:

def bind_email_to_account():
    do_synchronous_stuff()
    return self._register_email_threepid(...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know, thanks!

user_id, threepid_dict, None, False,
)

@defer.inlineCallbacks
def bind_emails(self, user_id, threepidCreds):
"""Links emails with a user ID and informs an identity server.
Expand Down
9 changes: 5 additions & 4 deletions synapse/module_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ def check_user_exists(self, user_id):
return self._auth_handler.check_user_exists(user_id)

@defer.inlineCallbacks
def register(self, localpart, displayname=None):
def register(self, localpart, displayname=None, emails=[]):
"""Registers a new user with given localpart and optional
displayname.
displayname, emails.

Args:
localpart (str): The localpart of the new user.
displayname (str|None): The displayname of the new user. If None,
the user's displayname will default to `localpart`.
displayname (str|None): The displayname of the new user.
emails (List[str]): Emails to bind to the new user.

Returns:
Deferred: a 2-tuple of (user_id, access_token)
Expand All @@ -90,6 +90,7 @@ def register(self, localpart, displayname=None):
reg = self.hs.get_registration_handler()
user_id, access_token = yield reg.register(
localpart=localpart, default_display_name=displayname,
bind_emails=emails,
)

defer.returnValue((user_id, access_token))
Expand Down