|
19 | 19 | from synapse.types import UserID |
20 | 20 | from synapse.http.server import finish_request |
21 | 21 | from synapse.http.servlet import parse_json_object_from_request |
| 22 | +from synapse.util.msisdn import phone_number_to_msisdn |
22 | 23 |
|
23 | 24 | from .base import ClientV1RestServlet, client_path_patterns |
24 | 25 |
|
|
37 | 38 | logger = logging.getLogger(__name__) |
38 | 39 |
|
39 | 40 |
|
| 41 | +def login_submission_legacy_convert(submission): |
| 42 | + """ |
| 43 | + If the input login submission is an old style object |
| 44 | + (ie. with top-level user / medium / address) convert it |
| 45 | + to a typed object. |
| 46 | + """ |
| 47 | + if "user" in submission: |
| 48 | + submission["identifier"] = { |
| 49 | + "type": "m.id.user", |
| 50 | + "user": submission["user"], |
| 51 | + } |
| 52 | + del submission["user"] |
| 53 | + |
| 54 | + if "medium" in submission and "address" in submission: |
| 55 | + submission["identifier"] = { |
| 56 | + "type": "m.id.thirdparty", |
| 57 | + "medium": submission["medium"], |
| 58 | + "address": submission["address"], |
| 59 | + } |
| 60 | + del submission["medium"] |
| 61 | + del submission["address"] |
| 62 | + |
| 63 | + |
| 64 | +def login_id_thirdparty_from_phone(identifier): |
| 65 | + """ |
| 66 | + Convert a phone login identifier type to a generic threepid identifier |
| 67 | + Args: |
| 68 | + identifier(dict): Login identifier dict of type 'm.id.phone' |
| 69 | +
|
| 70 | + Returns: Login identifier dict of type 'm.id.threepid' |
| 71 | + """ |
| 72 | + if "country" not in identifier or "number" not in identifier: |
| 73 | + raise SynapseError(400, "Invalid phone-type identifier") |
| 74 | + |
| 75 | + msisdn = phone_number_to_msisdn(identifier["country"], identifier["number"]) |
| 76 | + |
| 77 | + return { |
| 78 | + "type": "m.id.thirdparty", |
| 79 | + "medium": "msisdn", |
| 80 | + "address": msisdn, |
| 81 | + } |
| 82 | + |
| 83 | + |
40 | 84 | class LoginRestServlet(ClientV1RestServlet): |
41 | 85 | PATTERNS = client_path_patterns("/login$") |
42 | 86 | PASS_TYPE = "m.login.password" |
@@ -117,20 +161,52 @@ def on_POST(self, request): |
117 | 161 |
|
118 | 162 | @defer.inlineCallbacks |
119 | 163 | def do_password_login(self, login_submission): |
120 | | - if 'medium' in login_submission and 'address' in login_submission: |
121 | | - address = login_submission['address'] |
122 | | - if login_submission['medium'] == 'email': |
| 164 | + if "password" not in login_submission: |
| 165 | + raise SynapseError(400, "Missing parameter: password") |
| 166 | + |
| 167 | + login_submission_legacy_convert(login_submission) |
| 168 | + |
| 169 | + if "identifier" not in login_submission: |
| 170 | + raise SynapseError(400, "Missing param: identifier") |
| 171 | + |
| 172 | + identifier = login_submission["identifier"] |
| 173 | + if "type" not in identifier: |
| 174 | + raise SynapseError(400, "Login identifier has no type") |
| 175 | + |
| 176 | + # convert phone type identifiers to generic threepids |
| 177 | + if identifier["type"] == "m.id.phone": |
| 178 | + identifier = login_id_thirdparty_from_phone(identifier) |
| 179 | + |
| 180 | + # convert threepid identifiers to user IDs |
| 181 | + if identifier["type"] == "m.id.thirdparty": |
| 182 | + if 'medium' not in identifier or 'address' not in identifier: |
| 183 | + raise SynapseError(400, "Invalid thirdparty identifier") |
| 184 | + |
| 185 | + address = identifier['address'] |
| 186 | + if identifier['medium'] == 'email': |
123 | 187 | # For emails, transform the address to lowercase. |
124 | 188 | # We store all email addreses as lowercase in the DB. |
125 | 189 | # (See add_threepid in synapse/handlers/auth.py) |
126 | 190 | address = address.lower() |
127 | 191 | user_id = yield self.hs.get_datastore().get_user_id_by_threepid( |
128 | | - login_submission['medium'], address |
| 192 | + identifier['medium'], address |
129 | 193 | ) |
130 | 194 | if not user_id: |
131 | 195 | raise LoginError(403, "", errcode=Codes.FORBIDDEN) |
132 | | - else: |
133 | | - user_id = login_submission['user'] |
| 196 | + |
| 197 | + identifier = { |
| 198 | + "type": "m.id.user", |
| 199 | + "user": user_id, |
| 200 | + } |
| 201 | + |
| 202 | + # by this point, the identifier should be an m.id.user: if it's anything |
| 203 | + # else, we haven't understood it. |
| 204 | + if identifier["type"] != "m.id.user": |
| 205 | + raise SynapseError(400, "Unknown login identifier type") |
| 206 | + if "user" not in identifier: |
| 207 | + raise SynapseError(400, "User identifier is missing 'user' key") |
| 208 | + |
| 209 | + user_id = identifier["user"] |
134 | 210 |
|
135 | 211 | if not user_id.startswith('@'): |
136 | 212 | user_id = UserID.create( |
|
0 commit comments