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

Support registration & login with phone number #1971

Merged
merged 19 commits into from
Mar 9, 2017
Merged

Conversation

dbkr
Copy link
Member

@dbkr dbkr commented Mar 7, 2017

  • Adds the msisdn form of the proxy requestToken APIs
  • Changes the call to the ID servers to use JSON rather than x-www-form-urlencoded
  • Adds support for binding msisdns at registration time
  • Adds support for m.login.msisdn UI auth type and offers flows that use it in the registration API

@richvdh
Copy link
Member

richvdh commented Mar 8, 2017

defer.returnValue(True)

@defer.inlineCallbacks
def _check_threepid(self, medium, authdict, ):
Copy link
Member

Choose a reason for hiding this comment

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

random trailing ,?

Copy link
Member Author

Choose a reason for hiding this comment

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

done

del submission["medium"]
del submission["address"]

return submission
Copy link
Member

Choose a reason for hiding this comment

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

since you're modifying the input, I'd suggest not returning it, to make that clear.

Copy link
Member Author

Choose a reason for hiding this comment

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

done

if "type" not in identifier:
raise SynapseError(400, "Login identifier has no type")

# convert phone type identifiers to geberic threepids
Copy link
Member

Choose a reason for hiding this comment

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

geberic

Copy link
Member Author

Choose a reason for hiding this comment

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

done

raise SynapseError(400, "Unable to parse phone number")
msisdn = phonenumbers.format_number(
phoneNumber, phonenumbers.PhoneNumberFormat.E164
)[1:]
Copy link
Member

Choose a reason for hiding this comment

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

let's factor out the (phone_number, country) -> msisdn_or_throw_400 conversion to a utility, since it appears in several places.

Copy link
Member Author

Choose a reason for hiding this comment

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

done

if existingUid is None:
raise SynapseError(400, "MSISDN not found", Codes.THREEPID_NOT_FOUND)

ret = yield self.identity_handler.requestEmailToken(**body)
Copy link
Member

Choose a reason for hiding this comment

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

should be requestMsisdnToken?

Copy link
Member Author

Choose a reason for hiding this comment

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

done

absent.append(k)

if len(absent) > 0:
raise SynapseError(400, "Missing params: %r" % absent, Codes.MISSING_PARAM)
Copy link
Member

Choose a reason for hiding this comment

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

could we not have an assert_params_in_request(body, required) utility rather than copying this pattern twenty times?

suggest sticking it alongside parse_json_object_from_request in servlet.py

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@@ -226,6 +281,7 @@ def on_POST(self, request):
)
# don't re-register the email address
Copy link
Member

Choose a reason for hiding this comment

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

s/email address/threepids/

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@@ -372,6 +436,44 @@ def _register_email_threepid(self, user_id, threepid, token, bind_email):
logger.info("bind_email not specified: not binding email")

@defer.inlineCallbacks
def _register_msisdn_threepid(self, user_id, threepid, token, bind_msisdn):
"""Add aphone number as a 3pid identifier
Copy link
Member

Choose a reason for hiding this comment

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

aphone

Copy link
Member Author

Choose a reason for hiding this comment

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

done

"""
reqd = ('medium', 'address', 'validated_at')
if any(x not in threepid for x in reqd):
logger.info("Can't add incomplete 3pid")
Copy link
Member

Choose a reason for hiding this comment

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

when would this happen?

Copy link
Member Author

Choose a reason for hiding this comment

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

This would have to be the ID server giving an invalid response

Copy link
Member

Choose a reason for hiding this comment

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

comment would help, then

@richvdh richvdh assigned dbkr and unassigned richvdh Mar 8, 2017
Copy link
Member

@erikjohnston erikjohnston left a comment

Choose a reason for hiding this comment

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

I've only looked at the synapse/python part of it, not the functionality. Looks mostly good, other than factoring a few bits out to reduce code duplication

@defer.inlineCallbacks
def _check_dummy_auth(self, authdict, _):
yield run_on_reactor()
defer.returnValue(True)
Copy link
Member

Choose a reason for hiding this comment

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

Why do we do wait a reactor tick?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because these functions are all specified to return a deferred, so we need to yield somewhere in the function for it to actually return a deferred.

Copy link
Member

Choose a reason for hiding this comment

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

you could do that with return success(True).

A better answer might be: because it did before we got here, and changing it is scary.

yield run_on_reactor()

if 'threepid_creds' not in authdict:
raise LoginError(400, "Missing threepid_creds", Codes.MISSING_PARAM)

threepid_creds = authdict['threepid_creds']

identity_handler = self.hs.get_handlers().identity_handler

logger.info("Getting validated threepid. threepidcreds: %r" % (threepid_creds,))
Copy link
Member

Choose a reason for hiding this comment

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

I know this isn't you, but this should be logger.info("..", threepid_creds)

Copy link
Member Author

Choose a reason for hiding this comment

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

It probably was me in a former life

"""
Convert a phone login identifier type to a generic threepid identifier
Args:
identifier: Login identifier dict of type 'm.id.phone'
Copy link
Member

Choose a reason for hiding this comment

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

If you're listing args please add type, e.g. identifier(str): ...

Copy link
Member Author

Choose a reason for hiding this comment

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

done

absent.append(k)

if absent:
raise SynapseError(400, "Missing params: %r" % absent, Codes.MISSING_PARAM)
Copy link
Member

Choose a reason for hiding this comment

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

This checking of required keys should probably be factored out as its shared between at least this and the email one

Copy link
Member Author

Choose a reason for hiding this comment

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

done

raise SynapseError(400, "Unable to parse phone number")
msisdn = phonenumbers.format_number(
phoneNumber, phonenumbers.PhoneNumberFormat.E164
)[1:]
Copy link
Member

Choose a reason for hiding this comment

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

Is this the same block of code as in login_id_thirdparty_from_phone? Its probably worth factoring out as a) DRY and b) it'll probably be easier to see whats going on in this function

Copy link
Member Author

Choose a reason for hiding this comment

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

done

phoneNumber, phonenumbers.PhoneNumberFormat.E164
)[1:]

existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
Copy link
Member

Choose a reason for hiding this comment

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

We should be avoiding using self.hs.get_*() outside of initialisers and instead pull out all the dependencies from the HS we need in the initialiser

Copy link
Member Author

Choose a reason for hiding this comment

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

done

reqd = ('medium', 'address', 'validated_at')
if any(x not in threepid for x in reqd):
logger.info("Can't add incomplete 3pid")
defer.returnValue()
Copy link
Member

Choose a reason for hiding this comment

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

This will likely fail as it doesn't have a parameter? If you just want to return None you can actually just do return

Copy link
Member Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

can you? really? I thought it was naughty to have yield and return in the same function.

Copy link
Member

Choose a reason for hiding this comment

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

ah, you can return without a value.

logger.info("bind_msisdn specified: binding")
logger.debug("Binding msisdn %s to %s" % (
threepid, user_id
))
Copy link
Member

Choose a reason for hiding this comment

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

What's the reasoning for not just having this as one info log line?

Copy link
Member Author

Choose a reason for hiding this comment

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

hmm, it probably used to be longer. fixed.

Copy link
Member

Choose a reason for hiding this comment

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

I assumed it was something to do with not wanting to put the email/msisdn in the log.

raise SynapseError(400, "Unable to parse phone number")
msisdn = phonenumbers.format_number(
phoneNumber, phonenumbers.PhoneNumberFormat.E164
)[1:]
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, this would be much nicer to read if factored out a bit:

def on_POST(self, request):
    body = parse_json_object_from_request(request)
    check_required_keys(request, ('id_server', 'client_secret', ..))

    msisdn = format_msisdn(body['phone_number'], body['country'])

    existingUid = yield self.store.get_user_id_by_threepid('msisdn', msisdn)
    if existingUid:
        raise

    ret = yield self.identity_handler.requestEmailToken(**body)
    defer.returnValue((200, ret))

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@dbkr
Copy link
Member Author

dbkr commented Mar 8, 2017

@erikjohnston @richvdh ptal

@dbkr dbkr assigned richvdh and erikjohnston and unassigned dbkr Mar 8, 2017
If the input login submission is an old style object
(ie. with top-level user / medium / address) convert it
to a typed object.
Returns: Typed-object style login identifier
Copy link
Member

Choose a reason for hiding this comment

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

LIES!

Copy link
Member Author

Choose a reason for hiding this comment

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

ah yes

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd
Copy link
Member

Choose a reason for hiding this comment

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

technically not

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

from synapse.api.errors import SynapseError


def phone_number_to_msisdn(country, number):
Copy link
Member

Choose a reason for hiding this comment

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

can haz doc pls kthxbye

Copy link
Member Author

Choose a reason for hiding this comment

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

u haz doc

"""
reqd = ('medium', 'address', 'validated_at')
if any(x not in threepid for x in reqd):
logger.info("Can't add incomplete 3pid")
Copy link
Member

Choose a reason for hiding this comment

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

comment would help, then

@richvdh richvdh assigned dbkr and erikjohnston and unassigned richvdh Mar 8, 2017
@dbkr dbkr assigned richvdh and unassigned dbkr Mar 8, 2017
Copy link
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

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

lgtm

@dbkr dbkr merged commit 663396e into develop Mar 9, 2017
dbkr added a commit that referenced this pull request Mar 13, 2017
@dbkr dbkr deleted the dbkr/msisdn_signin branch October 17, 2017 12:48
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants