Compare commits

...

458 Commits

Author SHA1 Message Date
Andrew Morgan
cafeb5e0e7 Fix resetting password via a phone number (#21) 2020-01-24 15:23:31 +00:00
Andrew Morgan
0cc2594966 Validate client_secret parameter according to spec (#20) 2020-01-22 15:52:46 +00:00
Andrew Morgan
f4d1ab0027 Add the ability to restrict max avatar filesize and content-type (#19) 2019-12-12 13:51:25 +00:00
Andrew Morgan
c7e206b69b Add some flaky sytests to a sytest-blacklist (#17) 2019-12-09 15:17:07 +00:00
Andrew Morgan
d49933470d Add limit_profile_requests_to_known_users option (#18) 2019-12-05 11:55:12 +00:00
Andrew Morgan
32b7e20d41 Fix scripts/generate_signing_key.py import statement (#15) 2019-12-03 10:49:29 +00:00
Andrew Morgan
b69732705d Capatilise letters after a - in new user displaynames (#14) 2019-12-02 15:10:23 +00:00
Brendan Abolivier
c3a2c8c768 Merge pull request #16 from matrix-org/babolivier/dinsic-state-retrieval
Discard retention policies when retrieving state
2019-11-29 14:25:52 +00:00
Brendan Abolivier
9cd241d070 Changelog 2019-11-29 11:37:11 +00:00
Brendan Abolivier
f7b12c955b Discard retention policies when retrieving state
Purge jobs don't delete the latest event in a room in order to keep the forward extremity and not break the room. On the other hand, get_state_events, when given an at_token argument calls filter_events_for_client to know if the user can see the event that matches that (sync) token. That function uses the retention policies of the events it's given to filter out those that are too old from a client's view.

Some clients, such as Riot, when loading a room, request the list of members for the latest sync token it knows about, and get confused to the point of refusing to send any message if the server tells it that it can't get that information. This can happen very easily with the message retention feature turned on and a room with low activity so that the last event sent becomes too old according to the room's retention policy.

An easy and clean fix for that issue is to discard the room's retention policies when retrieving state.
2019-11-29 11:35:09 +00:00
Andrew Morgan
c446f59047 Hide expired users from user directory, optionally show on renewal (#13) 2019-11-14 18:42:55 +00:00
Andrew Morgan
28578e7568 Add a /user/:user_id/info servlet to give user deactivated/expired information (#12) 2019-11-14 14:22:58 +00:00
Andrew Morgan
d6b7606e07 Create configurable ratelimiter for 3pid invites (#11) 2019-11-12 11:38:35 +00:00
Brendan Abolivier
b77369079c Merge pull request #10 from matrix-org/babolivier/dinsic-retention-visibility
Don't apply retention policy based filtering on state events
2019-11-11 13:44:01 +00:00
Brendan Abolivier
f93e4b6a39 Changelog 2019-11-06 15:53:31 +00:00
Brendan Abolivier
dfa60504af Don't apply retention policy based filtering on state events
As per MSC1763, 'Retention is only considered for non-state events.', so don't filter out state events based on the room's retention policy.
2019-11-06 15:47:40 +00:00
Richard van der Hoff
85f15ac592 Support for routing outbound HTTP requests via a proxy (#6239)
The `http_proxy` and `HTTPS_PROXY` env vars can be set to a `host[:port]` value which should point to a proxy.

The address of the proxy should be excluded from IP blacklists such as the `url_preview_ip_range_blacklist`.

The proxy will then be used for
 * push
 * url previews
 * phone-home stats
 * recaptcha validation
 * CAS auth validation

It will *not* be used for:
 * Application Services
 * Identity servers
 * Outbound federation
 * In worker configurations, connections from workers to masters

Fixes #4198.
2019-11-01 14:22:46 +00:00
Brendan Abolivier
3e4527d796 Merge pull request #9 from matrix-org/babolivier/ci
Add SyTest to the BuildKite CI
2019-10-31 23:09:23 +00:00
Brendan Abolivier
e6f0536de1 Remove python TAP script 2019-10-31 16:16:25 +00:00
Brendan Abolivier
0559c87007 Don't use test image 2019-10-31 15:49:15 +00:00
Brendan Abolivier
7467a8090c Remove CircleCI configuration 2019-10-23 17:37:50 +01:00
Brendan Abolivier
0263c044ff Move sytest jobs to the right location 2019-10-23 17:37:28 +01:00
Brendan Abolivier
a4e4a9c93b Try running the workers job on bigger agents 2019-10-21 17:35:16 +01:00
Brendan Abolivier
73147f44fc Add py3 jobs on BuildKite 2019-10-18 15:25:45 +01:00
Brendan Abolivier
c3c1add9f3 Add TAP formatting script 2019-10-18 14:52:57 +01:00
Brendan Abolivier
7a50b07bb4 Add workers to buildkite 2019-10-09 11:34:20 +01:00
Brendan Abolivier
1a58f6196f Try to run stuff on buildkite 2019-10-09 11:17:36 +01:00
Brendan Abolivier
d6371916cc Actually use the right image 2019-10-09 11:08:30 +01:00
Brendan Abolivier
c29182ce8a Add python3 jobs 2019-10-09 11:06:29 +01:00
Brendan Abolivier
7123f50c44 fix 2019-10-08 18:15:47 +01:00
Brendan Abolivier
9398f55982 Try to fix CircleCI 2019-10-08 17:38:03 +01:00
Brendan Abolivier
4d52ccf41f peek 2019-10-08 17:09:14 +01:00
Brendan Abolivier
b77d92514e peek 2019-10-08 17:07:58 +01:00
Brendan Abolivier
60b4585403 peek 2019-10-08 16:51:18 +01:00
Brendan Abolivier
6bf5dbc5f2 peek 2019-10-08 16:47:18 +01:00
Brendan Abolivier
4150508759 peek 2019-10-08 16:45:04 +01:00
Brendan Abolivier
a093ac6d86 peek 2019-10-08 16:40:15 +01:00
Brendan Abolivier
9ec8072a87 Temporarily move the sytest job before the wait 2019-10-08 16:35:08 +01:00
Brendan Abolivier
078c0638e3 peek 2019-10-08 16:33:17 +01:00
Brendan Abolivier
c5eb8342b2 Try adding workers to CircleCI instead 2019-10-07 15:35:49 +01:00
Brendan Abolivier
f38ad87384 Use mainline's merge_base_branch.sh 2019-10-07 13:03:08 +01:00
Brendan Abolivier
90f1eb3ee5 Changelog 2019-10-07 12:54:20 +01:00
Brendan Abolivier
9e1e5f8ed5 First attempt at running SyTest in buildkite 2019-10-07 12:52:02 +01:00
Brendan Abolivier
6b59493dfa Merge pull request #8 from matrix-org/babolivier/3pid-invite-revoked
Don't 500 when trying to exchange a revoked 3PID invite
2019-10-04 13:12:01 +01:00
Brendan Abolivier
c49ba3677c Fixup tests 2019-10-04 12:21:33 +01:00
Brendan Abolivier
04d4fff806 Typo 2019-10-04 12:10:20 +01:00
Brendan Abolivier
b0a350ef48 Lint 2019-10-04 12:10:20 +01:00
Brendan Abolivier
eaec1d4ce7 Incorporate review 2019-10-04 12:10:20 +01:00
Brendan Abolivier
d694546453 Lint (again) 2019-10-04 12:10:19 +01:00
Brendan Abolivier
06159a0ee7 Lint 2019-10-04 12:10:19 +01:00
Brendan Abolivier
a6a55039a4 Add test case 2019-10-04 12:10:19 +01:00
Brendan Abolivier
1a01ca0774 Changelog 2019-10-04 12:10:19 +01:00
Brendan Abolivier
78d9b4a6e6 Lint 2019-10-04 12:10:19 +01:00
Brendan Abolivier
dfcf4ba406 Don't 500 code when trying to exchange a revoked 3PID invite
While this is not documented in the spec (but should be), Riot (and other clients) revoke 3PID invites by sending a m.room.third_party_invite event with an empty ({}) content to the room's state.
When the invited 3PID gets associated with a MXID, the identity server (which doesn't know about revocations) sends down to the MXID's homeserver all of the undelivered invites it has for this 3PID. The homeserver then tries to talk to the inviting homeserver in order to exchange these invite for m.room.member events.
When one of the invite is revoked, the inviting homeserver responds with a 500 error because it tries to extract a 'display_name' property from the content, which is empty. This might cause the invited server to consider that the server is down and not try to exchange other, valid invites (or at least delay it).

This fix handles the case of revoked invites by avoiding trying to fetch a 'display_name' from the original invite's content, and letting the m.room.member event fail the auth rules (because, since the original invite's content is empty, it doesn't have public keys), which results in sending a 403 with the correct error message to the invited server.
2019-10-04 12:10:14 +01:00
Brendan Abolivier
cd858afea6 Merge pull request #7 from matrix-org/babolivier/deactivation-invite
Reject pending invites on deactivation
2019-09-27 17:52:41 +01:00
Brendan Abolivier
ce2448efbe Fix git messing up 2019-09-27 17:18:10 +01:00
Brendan Abolivier
04b779a6ac s/return/defer.returnValue/ 2019-09-27 17:06:12 +01:00
Brendan Abolivier
42409b3022 Incorporate review 2019-09-27 17:03:34 +01:00
Brendan Abolivier
5a207c1113 Update synapse/handlers/deactivate_account.py
Co-Authored-By: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2019-09-27 17:03:34 +01:00
Brendan Abolivier
0ae6c8efc1 Update synapse/handlers/deactivate_account.py
Co-Authored-By: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2019-09-27 17:03:34 +01:00
Brendan Abolivier
318fed18da Update changelog.d/6125.feature
Co-Authored-By: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2019-09-27 17:03:10 +01:00
Brendan Abolivier
97672c03e2 ok 2019-09-27 16:57:19 +01:00
Brendan Abolivier
acf6b2388e Lint 2019-09-27 16:57:19 +01:00
Brendan Abolivier
4c6d9408d3 Merge pull request #6 from matrix-org/babolivier/access-rules-membership
Allow membership events which membership isn't join or invite in restricted rooms
2019-09-26 12:07:54 +01:00
Brendan Abolivier
0d069e4407 Changelog 2019-09-26 11:15:49 +01:00
Brendan Abolivier
e6a7f8964f Allow membership events which membership isn't join or invite in restricted rooms 2019-09-26 11:12:21 +01:00
Michael Kaye
efaf8038e2 Merge pull request #5 from matrix-org/babolivier/get-retention-worker
Fix room retention policy management in worker mode
2019-09-25 12:43:46 +01:00
Brendan Abolivier
f3dfbc82d5 Typo 2019-09-24 17:25:13 +01:00
Brendan Abolivier
25815841b1 Consider every room as having no retention policy if the feature is disabled 2019-09-24 17:24:28 +01:00
Brendan Abolivier
32bc69d0f5 Changelog 2019-09-24 17:19:59 +01:00
Brendan Abolivier
af597b1eb6 Move get_retention_policy_for_room to RoomWorkerStore 2019-09-24 17:19:59 +01:00
Brendan Abolivier
07eb311b11 Merge pull request #4 from matrix-org/babolivier/strip_invalid_mxid_characters
Fix handling of filtered strings in Python 3 when processing MXIDs
2019-09-20 10:57:07 +01:00
Brendan Abolivier
736394d46b Remove unnecessary cast to list 2019-09-20 10:07:55 +01:00
Brendan Abolivier
6f364634ee Changelog 2019-09-19 13:02:23 +01:00
Brendan Abolivier
8bc39401fe Lint 2019-09-19 13:01:05 +01:00
Brendan Abolivier
30c085fbc3 Use six.moves.filter when filtering out from MXID
Python 2's filter() function and Python 3's don't return the same type when processing a string (respectively str and filter), therefore use six's compatibility mapping (which resolves to itertools.ifilter() if using Python2), then generate a string from the filtered list, in order to ensure consistent behaviour between Python 2 and Python 3.
2019-09-19 12:03:10 +01:00
Brendan Abolivier
ae036ed636 Add unit tests for strip_invalid_mxid_characters 2019-09-19 11:58:06 +01:00
Brendan Abolivier
27b982269e Merge pull request #2 from matrix-org/babolivier/dinsic-3pid-invite
Don't treat 3PID revocation as a new 3PID invite
2019-09-10 11:32:31 +01:00
Brendan Abolivier
0b993427e1 Update changelog.d/2.bugfix
Co-Authored-By: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2019-09-10 10:18:37 +01:00
Brendan Abolivier
66be293c79 Process revocations in _on_membership_or_invite_direct 2019-09-09 17:52:41 +01:00
Brendan Abolivier
43c1a10e91 Merge pull request #3 from matrix-org/babolivier/password-reset-template-unicode
Ensure the password reset template is correctly converted to binary
2019-09-09 17:52:05 +01:00
Brendan Abolivier
c8f03a8fb0 Rename io.open import to limite side-effects 2019-09-09 17:13:37 +01:00
Brendan Abolivier
b0eec085bd Lint 2019-09-09 16:41:46 +01:00
Brendan Abolivier
76f70779f1 Revert "Merge pull request #5932 from matrix-org/babolivier/account_validity_template_encode"
This reverts commit 84e695f506, reversing
changes made to 99eec6d2d5.
2019-09-09 16:36:00 +01:00
Brendan Abolivier
21a6f0b12c Read all files as UTF-8 2019-09-09 16:34:47 +01:00
Brendan Abolivier
6ceaf90e13 Revert "Ensure the password reset template is correctly converted to binary"
This reverts commit 665dd9f7f8.
2019-09-09 16:33:09 +01:00
Brendan Abolivier
a8c7c26e7d Changelog 2019-09-09 11:49:42 +01:00
Brendan Abolivier
665dd9f7f8 Ensure the password reset template is correctly converted to binary
Regardless of the Python version
2019-09-09 11:35:56 +01:00
Brendan Abolivier
5076c2ebf6 Typo 2019-09-06 17:48:42 +01:00
Brendan Abolivier
6a78a0ce9b Lint 2019-09-06 15:51:52 +01:00
Brendan Abolivier
160a0c767d Changelog 2019-09-06 15:51:30 +01:00
Brendan Abolivier
e1c4d2c8ba Only filter on 3PID invite tokens 2019-09-06 15:48:02 +01:00
Brendan Abolivier
e35c30ed4b Fix bogus conflict resolution 2019-09-06 15:44:48 +01:00
Brendan Abolivier
e163df4c20 Merge branch 'dinsic' into babolivier/dinsic-3pid-invite 2019-09-06 15:41:37 +01:00
Brendan Abolivier
b2ec4467c9 Don't process revoked/redacted events as part of the room's membership info 2019-09-06 15:36:43 +01:00
Brendan Abolivier
b15557cd46 Don't treat 3PID revokation as a new 3PID invite 2019-09-06 15:32:11 +01:00
Brendan Abolivier
e9f2925292 Merge pull request #1 from matrix-org/babolivier/direct-avatar-name
Forbid changing the name, avatar or topic of a direct room
2019-09-06 11:46:17 +01:00
Brendan Abolivier
6cf60da6e9 Fix CI 2019-09-05 16:40:55 +01:00
Brendan Abolivier
d1d464388a Lint 2019-09-05 16:35:13 +01:00
Brendan Abolivier
9ef4e90be7 Changelog 2019-09-05 16:35:00 +01:00
Brendan Abolivier
2477f1f7aa Add tests 2019-09-05 16:25:37 +01:00
Brendan Abolivier
eddc6d8855 Forbid changing the name, avatar or topic of a direct room 2019-09-05 16:25:22 +01:00
Brendan Abolivier
84e695f506 Merge pull request #5932 from matrix-org/babolivier/account_validity_template_encode
Fix encoding for account validity HTML files on Python 2
2019-08-29 16:50:10 +01:00
Brendan Abolivier
91694227b6 Bump requirement for six to 1.12 2019-08-29 16:20:21 +01:00
Brendan Abolivier
7a95d8fff9 Fix encoding for account validity HTML files on Python 2 2019-08-29 16:03:59 +01:00
Brendan Abolivier
99eec6d2d5 Merge pull request #5815 from matrix-org/babolivier/dinsic-message-retention
Message retention policies at the room and server levels
2019-08-28 18:49:13 +01:00
Brendan Abolivier
e5df12ad16 Merge branch 'dinsic' into babolivier/dinsic-message-retention 2019-08-28 18:17:26 +01:00
Brendan Abolivier
70714595bc Implement per-room message retention policies 2019-08-28 18:16:17 +01:00
Michael Kaye
62f5e3bc4c Merge pull request #5812 from matrix-org/babolivier/account-validity-messages
Account validity: allow defining HTML templates to serve the user on account renewal attempt
2019-08-12 13:26:49 +01:00
Michael Kaye
63d0d21a28 Merge pull request #5781 from matrix-org/baboliver/loopingcall-args
Add ability to pass arguments to looping calls
2019-08-08 12:10:36 +01:00
Michael Kaye
8551b4f336 Merge pull request #5760 from matrix-org/babolivier/access-rules-public-restricted
Force the access rule to be "restricted" if the join rule is "public"
2019-08-08 12:10:22 +01:00
Brendan Abolivier
359aed4168 Lint 2019-08-01 16:08:39 +02:00
Brendan Abolivier
cd47482257 Sample config 2019-08-01 16:08:39 +02:00
Brendan Abolivier
a9567ee1a6 Changelog 2019-08-01 16:08:38 +02:00
Brendan Abolivier
9502bd8d78 Add tests 2019-08-01 16:08:38 +02:00
Brendan Abolivier
235271be4f Allow defining HTML templates to serve the user on account renewal 2019-08-01 16:08:38 +02:00
Brendan Abolivier
0c6500a08b Explain rationale 2019-08-01 10:19:04 +02:00
Brendan Abolivier
c862d5baf6 Check room ID and type of redacted event (#5784)
Check room ID and type of redacted event
2019-07-31 16:44:19 +02:00
Brendan Abolivier
35ec13baab Ignore redactions of redactions in get_events_as_list 2019-07-31 15:48:57 +02:00
Brendan Abolivier
c4e56a8ee9 Ignore invalid redactions in _get_event_from_row 2019-07-31 15:11:27 +02:00
Brendan Abolivier
d2bb51080e Incorporate review 2019-07-30 16:15:01 +02:00
Brendan Abolivier
0fda4e2e50 Should now work, unless we can't find the redaction event which happens for some reason (need to investigate) 2019-07-30 15:56:02 +02:00
Brendan Abolivier
8ced9a2f58 Don't make the checks depend on recheck_redaction 2019-07-30 15:55:18 +02:00
Brendan Abolivier
bbd6208b3e Do checks sooner 2019-07-29 17:22:42 +02:00
Brendan Abolivier
36c61df659 Check room ID and type of redacted event 2019-07-29 16:07:12 +02:00
Brendan Abolivier
132887db8c Changelog 2019-07-29 11:06:43 +02:00
Brendan Abolivier
bec6d9e090 Add kwargs and doc 2019-07-29 11:06:43 +02:00
Brendan Abolivier
8a47155763 Add ability to pass arguments to looping calls 2019-07-29 11:06:43 +02:00
Brendan Abolivier
ffa30b507f Fix changelog 2019-07-25 10:19:13 +02:00
Brendan Abolivier
00b47fdfc7 Changelog 2019-07-25 10:17:07 +02:00
Brendan Abolivier
2526b79ce6 Merge ifs 2019-07-25 10:15:44 +02:00
Brendan Abolivier
aea03c9d73 Doc 2019-07-25 10:14:41 +02:00
Brendan Abolivier
ddf256c77f Fix status code for forbidden events 2019-07-25 10:03:59 +02:00
Brendan Abolivier
dd92685179 Only check the join rule on room creation if an access rule is also provided 2019-07-25 10:03:36 +02:00
Brendan Abolivier
0bb375c124 Turns out the default preset is public_chat 2019-07-24 17:29:17 +02:00
Brendan Abolivier
ea5f86304e Implement restrictions on new events 2019-07-24 17:27:07 +02:00
Brendan Abolivier
d1a78ba2a3 Implement restriction on public room creation 2019-07-24 17:06:23 +02:00
Brendan Abolivier
dcdfdb3f17 Add test case 2019-07-24 16:38:49 +02:00
Brendan Abolivier
4dc2eda1d3 Merge pull request #5702 from matrix-org/babolivier/3pid-invite
Fix check of the association between a 3PID invite and the subsequent m.room.member event in the 3rd party rules
2019-07-18 13:38:05 +02:00
Brendan Abolivier
13ad3f5ab1 Fix changelog 2019-07-17 15:10:16 +02:00
Brendan Abolivier
28803ad56a Merge branch 'dinsic' into babolivier/3pid-invite 2019-07-17 15:06:41 +02:00
Brendan Abolivier
446fb64d50 Changelog 2019-07-17 15:05:35 +02:00
Brendan Abolivier
34dd738e4b There's no third_party_signed property in an invite's content 2019-07-17 15:03:23 +02:00
Brendan Abolivier
048f86ef5d Fix check of the association between a 3PID invite and the subsequent m.room.member event in the 3rd party rules 2019-07-17 14:54:58 +02:00
Brendan Abolivier
3bc4ea841d Merge pull request #5646 from matrix-org/babolivier/profile-allow-self
Port #5644 to dinsic
2019-07-09 13:19:57 +01:00
Amber H. Brown
4e954f4bbd make the base branch dinsic for dinsic 2019-07-09 20:53:38 +10:00
Amber H. Brown
f10b6f7385 cut down circleci config to just what dinsic needs 2019-07-09 20:38:24 +10:00
Brendan Abolivier
9fc40f7b3f Lint 2019-07-09 10:30:43 +01:00
Brendan Abolivier
cf22aae355 Add test case 2019-07-09 10:27:53 +01:00
Brendan Abolivier
6b9d27d793 Changelog 2019-07-09 10:27:53 +01:00
Brendan Abolivier
25fff95448 Allow newly-registered users to lookup their own profiles
When a user creates an account and the 'require_auth_for_profile_requests' config flag is set, and a client that performed the registration wants to lookup the newly-created profile, the request will be denied because the user doesn't share a room with themselves yet.
2019-07-09 10:27:53 +01:00
Brendan Abolivier
5fe0cea37e Merge pull request #5610 from matrix-org/babolivier/power-levels
Implement new restrictions on power levels
2019-07-04 11:12:47 +01:00
Brendan Abolivier
95b5d4ad54 Merge branch 'babolivier/power-levels' of github.com:matrix-org/synapse into babolivier/power-levels 2019-07-03 18:30:13 +01:00
Brendan Abolivier
4dd7de17b7 Incorporate review 2019-07-03 18:26:48 +01:00
Brendan Abolivier
8b44097771 Update synapse/third_party_rules/access_rules.py
Co-Authored-By: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2019-07-03 18:21:42 +01:00
Brendan Abolivier
6b83a1826c Incorporate review 2019-07-03 17:32:52 +01:00
Brendan Abolivier
aeda7fde78 Changelog 2019-07-03 15:47:58 +01:00
Brendan Abolivier
d085e0df2a Change the rule for applying PL restrictions 2019-07-03 15:44:22 +01:00
Brendan Abolivier
8d28817eac Add tests 2019-07-03 15:43:52 +01:00
Brendan Abolivier
aa3ba41933 Default return value for events we're not interested in 2019-07-03 12:05:56 +01:00
Brendan Abolivier
724ddaddb3 Refactor part of the access rules module
Since we're not processing only membership events and 3PID invites anymore, it's nice to know which function is supposed to process what.
2019-07-03 12:03:22 +01:00
Brendan Abolivier
8636ec042b Implement restrictions for power levels 2019-07-03 11:45:07 +01:00
Brendan Abolivier
78b737ff71 Merge pull request #5577 from matrix-org/babolivier/3pid-invite-ratelimit
Port #5576 to dinsic
2019-06-28 18:23:53 +01:00
Brendan Abolivier
a7a8bbf502 Only ratelimit when sending the email
If we do the opposite, an event can arrive after or while sending the email and the 3PID invite event will get ratelimited.
2019-06-28 17:47:38 +01:00
Brendan Abolivier
f304996c61 Changelog 2019-06-28 17:44:28 +01:00
Brendan Abolivier
7c644198c8 Don't update the ratelimiter before sending a 3PID invite
This would cause emails being sent, but Synapse responding with a 429 when creating the event. The client would then retry, and with bad timing the same scenario would happen again. Some testing I did ended up sending me 10 emails for one single invite because of this.
2019-06-28 17:44:28 +01:00
Brendan Abolivier
ee0ee97447 Add test case for #5574
There's no test that makes sure #5574 didn't break things or works correctly (my bad), so this PR adds a test case that makes sure of it.
2019-06-28 10:29:02 +01:00
Brendan Abolivier
f370fd01ec Merge pull request #5574 from matrix-org/babolivier/fix-3pid-bind
Fix new 3PID bindings being associated with rewritten IS's server names instead of the original one
2019-06-27 15:17:15 +01:00
Brendan Abolivier
1ef3627b05 Fix new 3PID bindings being associated with rewritten IS's server names instead of the original one
This would make unbind requests fail because Synapse is using the server name it has in DB as destination_is to generate signature, and Sydent uses its own server name there when verifying it, so if a mismatch happens, which is the case if the name gets rewritten for routing purposes, the unbind requests fail on the signature verification.
2019-06-27 14:53:10 +01:00
Brendan Abolivier
fbc5b58d21 Merge pull request #5542 from matrix-org/babolivier/federation-publicrooms
Port "Split public rooms directory auth config in two" to dinsic
2019-06-24 16:42:21 +01:00
Brendan Abolivier
84875301b6 Split public rooms directory auth config in two 2019-06-24 16:41:48 +01:00
Brendan Abolivier
18f0b69c49 Merge pull request #5495 from matrix-org/babolivier/deactivate_bg_job_typo
Port "Fix typo in deactivation background job" to dinsic
2019-06-19 11:58:52 +01:00
Brendan Abolivier
4875746d82 Fix typo in deactivation background job 2019-06-19 11:39:18 +01:00
Brendan Abolivier
fa4efb5967 Merge pull request #5484 from matrix-org/babolivier/dinsic_access_rules
Implement custom access rules
2019-06-19 10:41:37 +01:00
Brendan Abolivier
c1bc48f9d4 Add tests for constraints on changing the rule for a room 2019-06-18 18:07:05 +01:00
Brendan Abolivier
9b3c69f661 Add tests for 3PID invites 2019-06-18 17:59:07 +01:00
Brendan Abolivier
7157276124 Don't process 3PIDs in _apply_restricted 2019-06-18 17:43:34 +01:00
Brendan Abolivier
1532369dcd Remove unused import 2019-06-18 16:46:57 +01:00
Brendan Abolivier
145291108d Add tests for inviting with access rules 2019-06-18 16:32:54 +01:00
Brendan Abolivier
cefc5542fb Lint 2019-06-18 14:59:05 +01:00
Brendan Abolivier
2a1f35193b Remove unused imports 2019-06-18 14:57:04 +01:00
Brendan Abolivier
a09767d57d Lint 2019-06-18 14:55:24 +01:00
Brendan Abolivier
bc0fd8f170 Add tests for room creation hook 2019-06-18 14:54:19 +01:00
Brendan Abolivier
d36a876d2d Incorporate review 2019-06-18 14:53:33 +01:00
Brendan Abolivier
f7339d42ee Fixes 2019-06-18 11:28:33 +01:00
Brendan Abolivier
8aea2c3be1 Docstrings 2019-06-17 20:24:36 +01:00
Brendan Abolivier
1cd0ecc1f2 Rename into RoomAccessRules 2019-06-17 20:24:30 +01:00
Brendan Abolivier
19a4298a51 Fix function call 2019-06-17 20:24:26 +01:00
Brendan Abolivier
073dd7778e Implement rules change 2019-06-17 20:24:22 +01:00
Brendan Abolivier
00736c8935 Improve doc 2019-06-17 20:24:16 +01:00
Brendan Abolivier
112a48a5aa Implement 3PID invite hook 2019-06-17 20:24:07 +01:00
Brendan Abolivier
53aff08ebe Implement restricted rules and room creation hook 2019-06-17 20:22:53 +01:00
Brendan Abolivier
8b2f655589 Implement rules for direct 2019-06-17 20:22:27 +01:00
Brendan Abolivier
bd8448ccb2 Backbone 2019-06-17 20:19:12 +01:00
Brendan Abolivier
110608d1d6 Base 2019-06-17 20:19:08 +01:00
Brendan Abolivier
5a28504c08 Merge pull request #5481 from matrix-org/babolivier/third_party_rules_3pid
Port "Add third party rules hook for 3PID invites" to dinsic
2019-06-17 18:35:54 +01:00
Brendan Abolivier
9bb7cec90f Make check_threepid_can_be_invited async 2019-06-17 18:10:00 +01:00
Brendan Abolivier
8a8644045f Changelog 2019-06-17 18:10:00 +01:00
Brendan Abolivier
08d4534771 Add third party rules hook for 3PID invites 2019-06-17 18:10:00 +01:00
Erik Johnston
c8349787b7 Merge pull request #5474 from matrix-org/erikj/add_create_room_hook
Add third party rules hook into create room
2019-06-17 17:30:08 +01:00
Erik Johnston
e5e690041d Newsfile 2019-06-17 15:52:15 +01:00
Erik Johnston
fb1b76ff4c Add third party rules hook into create room 2019-06-17 15:48:57 +01:00
Brendan Abolivier
40ea934de0 Merge pull request #5471 from matrix-org/erikj/3pid_remote_invite_state
Port "Fix 3PID invite room state over federation" to dinsic
2019-06-17 11:43:02 +01:00
Brendan Abolivier
5c4296b47a Merge branch 'babolivier/third_party_event_rules' into dinsic 2019-06-14 19:38:44 +01:00
Brendan Abolivier
8b2543c0ec Merge pull request #5466 from matrix-org/babolivier/fix_deactivation_bg_job
Port "Fix background job for deactivated flag" to dinsic
2019-06-14 19:22:56 +01:00
Brendan Abolivier
bd59e154c1 Fix changelog 2019-06-14 18:29:13 +01:00
Brendan Abolivier
66378d13ce Changelog 2019-06-14 18:29:13 +01:00
Brendan Abolivier
65d3652cb7 Fix background job for deactivated flag 2019-06-14 18:29:13 +01:00
Brendan Abolivier
c644755123 Merge pull request #5463 from matrix-org/babolivier/account_validity_deactivated_accounts_2
Port "Don't send renewal emails to deactivated users" to dinsic
2019-06-14 17:19:57 +01:00
Brendan Abolivier
c7964e7430 Fix test 2019-06-14 16:25:18 +01:00
Erik Johnston
3c9bb86fde Newsfile 2019-06-14 16:19:11 +01:00
Erik Johnston
304a1376c2 Fix 3PID invite room state over federation.
Fixes that when a user exchanges a 3PID invite for a proper invite over
federation it does not include the `invite_room_state` key.

This was due to synapse incorrectly sending out two invite requests.
2019-06-14 16:19:11 +01:00
Brendan Abolivier
aded5cfb72 Don't send renewal emails to deactivated users 2019-06-14 15:39:18 +01:00
Brendan Abolivier
57bd5cfc9a Track deactivated accounts in the database (#5378) 2019-06-14 13:45:36 +01:00
Brendan Abolivier
ad566df746 Merge pull request #5420 from matrix-org/babolivier/userdir_hide_users
Add configuration option to hide new users from the user directory
2019-06-14 10:59:45 +01:00
Brendan Abolivier
c4759cd041 Merge branch 'dinsic' into babolivier/userdir_hide_users 2019-06-14 10:37:43 +01:00
Brendan Abolivier
4dda68da9a Make index unique 2019-06-14 10:37:12 +01:00
Brendan Abolivier
adf3eee668 Merge branch 'babolivier/fix_profile_replication' into babolivier/userdir_hide_users 2019-06-13 18:11:11 +01:00
Brendan Abolivier
a6cf1e079e Merge pull request #5416 from matrix-org/babolivier/fix_profile_replication
Add unique index to the profile_replication_status table.
2019-06-13 18:10:14 +01:00
Brendan Abolivier
996cf15d42 Lint 2019-06-13 17:41:13 +01:00
Brendan Abolivier
27cd0b3037 Fix snafu 2019-06-13 17:40:14 +01:00
Neil Johnson
4f68188d0b Change to absolute path for contrib/docker
because this file is reproduced on dockerhub and relative paths don't work
2019-06-13 16:42:36 +01:00
Brendan Abolivier
26a27e06b9 Create the index in a background update 2019-06-13 15:57:55 +01:00
Brendan Abolivier
5283f65316 Fix bogus changelog 2019-06-12 16:49:10 +01:00
Brendan Abolivier
4a1b749582 Lint 2019-06-12 16:48:51 +01:00
Brendan Abolivier
e0c56d6527 Merge branch 'dinsic' into babolivier/fix_profile_replication 2019-06-12 16:41:08 +01:00
Brendan Abolivier
7c2d936802 Fix bogus changelog 2019-06-12 16:38:00 +01:00
Brendan Abolivier
1c7628eb3a Lint 2019-06-12 16:36:28 +01:00
Brendan Abolivier
8400e5f624 Merge branch 'dinsic' into babolivier/userdir_hide_users 2019-06-12 16:29:56 +01:00
Brendan Abolivier
02a659ae30 Regenerate full schemas 2019-06-12 15:51:59 +01:00
Brendan Abolivier
a55b2efca1 Fix path for password policy endpoints 2019-06-12 15:51:42 +01:00
Brendan Abolivier
d907e8f599 Merge branch 'master' into dinsic 2019-06-12 14:36:44 +01:00
Erik Johnston
97174780ce 1.0.0 2019-06-11 17:10:01 +01:00
Erik Johnston
9532eb55ec Merge pull request #5424 from matrix-org/erikj/change_password_reset_links
Change password reset links to /_matrix.
2019-06-11 13:29:42 +01:00
Erik Johnston
a766c41d25 Bump bleach version so that tests can run on old deps. 2019-06-11 12:34:18 +01:00
Neil Johnson
426218323b Neilj/improve federation docs (#5419)
Add FAQ questions to federate.md. Add a health warning making it clear that the 1711 upgrade FAQ is now out of date.
2019-06-11 12:17:43 +01:00
Erik Johnston
453aaaadc0 Newsfile 2019-06-11 11:34:38 +01:00
Erik Johnston
10383e6e6f Change password reset links to /_matrix. 2019-06-11 11:34:33 +01:00
Brendan Abolivier
3c8262b181 Merge branch 'master' into dinsic 2019-06-11 10:55:53 +01:00
Brendan Abolivier
389aa20170 Generate sample config 2019-06-10 17:31:45 +01:00
Brendan Abolivier
c10226581a Lint 2019-06-10 17:25:42 +01:00
Brendan Abolivier
10510f1e7e Lint 2019-06-10 17:23:11 +01:00
Brendan Abolivier
9ece96f5c8 Changelog 2019-06-10 17:17:18 +01:00
Brendan Abolivier
1924848dfa Add test case 2019-06-10 17:16:17 +01:00
Brendan Abolivier
deee82aebc Fix variable definition 2019-06-10 17:16:03 +01:00
Brendan Abolivier
0e63dd89a4 Fix condition 2019-06-10 16:56:53 +01:00
Brendan Abolivier
d331119758 Hide new users from the user directory if enabled in the server config. 2019-06-10 16:56:53 +01:00
Brendan Abolivier
9cce175bf0 Move schema update to 54 and add a warning comment 2019-06-10 15:34:41 +01:00
Brendan Abolivier
4f0e9a3f01 New line 2019-06-10 15:22:55 +01:00
Brendan Abolivier
35eea39c8c Add unique index to the profile_replication_status table. 2019-06-10 15:18:22 +01:00
Brendan Abolivier
8d16321edc Merge branch 'babolivier/account_validity_send_mail_auth' into dinsic 2019-06-10 11:59:20 +01:00
Brendan Abolivier
028f674cd3 Better wording 2019-06-10 11:35:54 +01:00
Brendan Abolivier
4914a88829 Doc 2019-06-10 11:34:45 +01:00
Brendan Abolivier
ccbc9e5e17 Gah towncrier 2019-06-05 16:41:26 +01:00
Brendan Abolivier
d51ca9d9b3 Changelog 2019-06-05 16:38:51 +01:00
Brendan Abolivier
fe13bd52ac Don't check whether the user's account is expired on /send_mail requests 2019-06-05 16:35:05 +01:00
Brendan Abolivier
116f7778f4 Merge branch 'babolivier/email_config' into dinsic 2019-06-04 14:49:55 +01:00
Erik Johnston
d8fdba7bfb Merge branch 'babolivier/account_validity_job_delta' of github.com:matrix-org/synapse into dinsic 2019-05-31 12:12:24 +01:00
Brendan Abolivier
dde07c6859 Merge branch 'babolivier/account_validity_fix_schema' into dinsic 2019-05-28 11:36:11 +01:00
Brendan Abolivier
64365fcbdd Merge pull request #5214 from matrix-org/babolivier/password-policy
Allow server admins to define and enforce a password policy (MSC2000)
2019-05-22 11:09:42 +01:00
Brendan Abolivier
4a9eba9576 Test whole dict instead of individual fields 2019-05-22 10:43:23 +01:00
Brendan Abolivier
50cd07a836 Merge branch 'babolivier/account_validity_expiration_date' into dinsic 2019-05-21 14:56:05 +01:00
Brendan Abolivier
7dfc3c327c Improve documentation on generated configuration 2019-05-21 10:49:44 +01:00
Brendan Abolivier
42cea6b437 Make error messages more explicit 2019-05-21 10:21:27 +01:00
Brendan Abolivier
d9105b5ed8 Also test the /password client route 2019-05-21 09:55:32 +01:00
Brendan Abolivier
6fbf2ae9a8 Remove unused import 2019-05-20 19:49:19 +01:00
Brendan Abolivier
ed2b5b77f2 Config and changelog 2019-05-20 19:44:37 +01:00
Brendan Abolivier
6d54f1534a First implementation of MSC2000 2019-05-20 19:42:39 +01:00
Brendan Abolivier
d6e2f9f9da Merge branch 'babolivier/per_room_profiles' into dinsic 2019-05-17 15:07:41 +01:00
Brendan Abolivier
f608ddbe5c Merge branch 'release-v0.99.4' into dinsic 2019-05-14 11:43:03 +01:00
Brendan Abolivier
38e3d9ed67 Merge pull request #5115 from matrix-org/babolivier/lookup_path
[DINSIC] Move 3PID lookup endpoint to CS API and proxy bulk lookups
2019-05-09 15:02:21 +01:00
Brendan Abolivier
aa5c42f5bc Fix failing test 2019-05-09 13:59:57 +01:00
Brendan Abolivier
8bcb78891e Merge branch 'babolivier/lookup_path' of github.com:matrix-org/synapse into babolivier/lookup_path 2019-05-09 13:09:19 +01:00
Brendan Abolivier
f304f1a574 Incorporate review 2019-05-09 13:07:43 +01:00
Brendan Abolivier
532ba44add Fix test 2019-05-09 13:01:40 +01:00
Brendan Abolivier
10e3ed83e9 Check if Synapse should check given ISs 2019-05-09 12:53:24 +01:00
Richard van der Hoff
622ecec24b Merge remote-tracking branch 'origin/dinsic' into babolivier/lookup_path 2019-05-09 11:06:02 +01:00
Richard van der Hoff
09ea63ae7a Merge pull request #5098 from matrix-org/rav/fix_pep_517
Workarounds for pep-517 errors
2019-05-08 18:13:15 +01:00
Brendan Abolivier
f059a91085 /bulk_lookup doesn't return a signature 2019-05-07 14:16:26 +01:00
Brendan Abolivier
66f7588f87 Fix expected key in bulk lookup response 2019-05-07 12:06:24 +01:00
Brendan Abolivier
b4f3d70b21 Incorporate review 2019-05-07 11:47:37 +01:00
Brendan Abolivier
3d031c211d Fix error message 2019-05-01 10:10:38 +01:00
Andrew Morgan
371296443f Update synapse/handlers/identity.py
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-05-01 10:03:46 +01:00
Andrew Morgan
1973eb11d2 Update synapse/rest/client/v2_alpha/account.py
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-05-01 10:02:18 +01:00
Andrew Morgan
26c004129f Update synapse/rest/client/v2_alpha/account.py
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-05-01 10:01:57 +01:00
Richard van der Hoff
0cc91efd6a Merge pull request #5098 from matrix-org/rav/fix_pep_517
Workarounds for pep-517 errors
2019-04-30 18:33:19 +01:00
Brendan Abolivier
fe6ac9c5d7 Fixed return value 2019-04-30 18:28:01 +01:00
Brendan Abolivier
96bd70f6d0 Bunch of tests 2019-04-30 18:22:52 +01:00
Brendan Abolivier
3a9c405a0f Fix url and method 2019-04-30 18:22:42 +01:00
Brendan Abolivier
909ceecc28 Tests 2019-04-30 17:27:58 +01:00
Brendan Abolivier
70da5202ba Fixes 2019-04-30 17:27:47 +01:00
Brendan Abolivier
34bbbe81a6 Fix method 2019-04-30 16:59:46 +01:00
Brendan Abolivier
2d979e639d Register servlets 2019-04-30 16:51:50 +01:00
Brendan Abolivier
d296cdc9dd Add bulk lookup 2019-04-30 15:15:02 +01:00
Brendan Abolivier
8df16a8aee Move lookup endpoint to CS API (and s/is_server/id_server/) 2019-04-30 15:11:21 +01:00
Matthew Hodgson
15b7a84aa8 changelog 2019-04-21 01:01:40 +01:00
Andrew Morgan
2f61dd058d [DINSIC] Add ability to proxy identity lookups (#5048) 2019-04-16 17:41:01 +01:00
Andrew Morgan
e6218e4880 [DINSIC] Block internal users from inviting external users to a public room (#5061)
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-04-16 16:41:01 +01:00
Andrew Morgan
7d71975e6a Merge branch 'develop' into dinsic 2019-04-15 15:22:14 +01:00
Brendan Abolivier
0fcf7e5c57 Add config option to block users from looking up 3PIDs (#5010) 2019-04-05 14:25:27 +01:00
Erik Johnston
9bf49abc07 Merge branch 'master' of github.com:matrix-org/synapse into dinsic 2019-04-05 14:10:16 +01:00
Michael Kaye
dd747ba045 Prevent exception when hs or shadow_hs missing (#5012)
* Prevent exception when hs or shadow_hs missing
2019-04-04 17:45:12 +01:00
Erik Johnston
b00a8d870c Fix registration with register_mxid_from_3pid enabled (#5011) 2019-04-04 16:45:15 +01:00
Michael Kaye
8fa09c7479 Rewrite more internal IS urls. (#5006)
* Rewrite more internal IS urls.
2019-04-04 15:28:37 +01:00
Erik Johnston
d94873d525 Merge pull request #4997 from matrix-org/erikj/dinsic_email_display_name
Add config option to use email as display name for new users
2019-04-03 10:57:20 +01:00
Erik Johnston
f2fa172375 Sample config 2019-04-03 10:40:40 +01:00
Erik Johnston
8c0ebe3026 Add config option to use email as display name for new users 2019-04-03 10:26:56 +01:00
Erik Johnston
53dd358c83 Merge pull request #4910 from matrix-org/erikj/third_party_invite_create_spam
Add third party invite support to spam checker
2019-03-21 16:07:27 +00:00
Erik Johnston
f5c944c7f2 Fix comments 2019-03-21 15:31:34 +00:00
Erik Johnston
aefb7a1146 Update sample config 2019-03-21 12:52:22 +00:00
Erik Johnston
479b7b1eff Add another test 2019-03-21 12:48:37 +00:00
Erik Johnston
f04ee0b351 Run black on tests/rulecheck/ 2019-03-21 12:48:37 +00:00
Erik Johnston
164798ec32 Add 3PID invite support to spam checker 2019-03-21 12:48:37 +00:00
Erik Johnston
b7d7d20a38 Correctly handle 3PID invites in create room spam check
We also add an option to outright deny third party invites
2019-03-21 12:48:37 +00:00
Erik Johnston
2bb6d85736 Turn off newsfile check 2019-03-21 12:48:25 +00:00
Erik Johnston
0f0671e5e0 Merge branch 'develop' of github.com:matrix-org/synapse into erikj/dinsic-merged 2019-03-21 12:41:42 +00:00
Erik Johnston
8eb9f37a01 Merge pull request #4875 from matrix-org/erikj/spam_checker
Extend spam checking rules
2019-03-18 16:28:46 +00:00
Erik Johnston
ea89e73ebf Add unit tests 2019-03-18 15:56:08 +00:00
Erik Johnston
68a9d1fc34 Add rules to DomainRuleChecker 2019-03-18 15:56:04 +00:00
Erik Johnston
feae387576 Don't spam check actions by admins 2019-03-18 15:51:00 +00:00
Erik Johnston
e64f7c0188 Run black on tests/rulecheck/test_domainrulecheck.py 2019-03-18 15:51:00 +00:00
Erik Johnston
b85ff4b894 Add user_may_join_room spam check 2019-03-18 15:51:00 +00:00
Erik Johnston
4eca8d3fb3 Add invite_list and cloning param to create room rule 2019-03-18 15:50:55 +00:00
Michael Kaye
aa3dc78f65 Merge pull request #4862 from matrix-org/erikj/dinsic-merged-master
Merge master into dinsic
2019-03-15 17:21:22 +01:00
Erik Johnston
de874364e7 Fixup config 2019-03-15 14:41:27 +00:00
Erik Johnston
7e94e2ad94 Disable changelog CI checks 2019-03-15 14:40:28 +00:00
Erik Johnston
e7ec6f78ca Manifest 2019-03-15 14:39:25 +00:00
Erik Johnston
7a9aa4b81b Isort 2019-03-15 14:39:25 +00:00
Erik Johnston
5827e976fe Fixups 2019-03-15 14:39:25 +00:00
Erik Johnston
44c0661d97 Merge branch 'master' of github.com:matrix-org/synapse into erikj/dinsic-merged-master 2019-03-15 14:36:44 +00:00
Erik Johnston
85db96cc81 Add some debug logging for device list handling 2019-03-08 12:31:41 +00:00
Andrew Morgan
3271742905 Merge pull request #4681 from matrix-org/dinsic_anoa/info_split
[DINSIC] Use internal-info for identity server
2019-02-28 11:28:55 +00:00
Andrew Morgan
0a23bf442f Merge branch 'dinsic_anoa/info_split' of github.com:matrix-org/synapse into dinsic_anoa/info_split 2019-02-27 15:23:19 +00:00
Andrew Morgan
9b13038d05 Check shadow_hs as well as hs during 3pid reg 2019-02-27 15:22:41 +00:00
Andrew Morgan
dfe09ec313 Merge pull request #4747 from matrix-org/anoa/public_rooms_federate
[DINSIC] Prevent showing non-fed rooms in fed /publicRooms
2019-02-26 14:40:45 +00:00
Richard van der Hoff
13bc1e5307 Update synapse/util/threepids.py
Co-Authored-By: anoadragon453 <1342360+anoadragon453@users.noreply.github.com>
2019-02-25 16:08:58 +00:00
Andrew Morgan
70e039c7ae Use internal-info for identity server. Block reg on fields 2019-02-19 15:29:49 +00:00
Michael Kaye
2712a9ef8f Fix to keep the signature valid for the request. (#4480) 2019-01-28 14:24:28 +00:00
Michael Kaye
da757b7759 Rewrite identity server URLs as required. (#4393)
This takes a mapping of <old> -> <new> and looks up and replaces as
required.
2019-01-21 15:48:15 +00:00
Michael Kaye
59bc7debf0 When performing shadow registration, don't inhibit login. (#4385) 2019-01-14 18:01:34 +00:00
Matthew Hodgson
cf68593544 Synchronise account metadata onto another server. (#4145)
* implement shadow registration via AS (untested)
* shadow support for 3pid binding/unbinding (untested)
2019-01-11 15:50:28 +00:00
Michael Kaye
9cc95fd0a5 Merge pull request #4148 from matrix-org/matthew/red_list
add im.vector.hide_profile to user account_data
2018-12-19 15:42:19 +00:00
Matthew Hodgson
82886e4c8f hide_profile: false should mean not to hide the profile :/ 2018-12-12 00:57:39 +00:00
Matthew Hodgson
08919847c1 fix sense of 'hide' 2018-11-04 23:49:57 +00:00
Matthew Hodgson
c3acc45a87 pull in profile_handler correctly 2018-11-04 23:49:19 +00:00
Matthew Hodgson
ae5bb32ad0 add im.vector.hide_profile to user account_data 2018-11-04 23:46:11 +00:00
Matthew Hodgson
7ed3232b08 fix tests 2018-11-03 12:58:25 +00:00
Matthew Hodgson
6e7488ce11 merge master into dinsic, again... 2018-11-03 12:14:24 +00:00
Michael Kaye
41585e1340 Merge pull request #4047 from matrix-org/michaelkaye/dinsic_allow_user_directory_url
user_directory.defer_to_id_server should be an URL, not a hostname
2018-11-02 12:00:18 +00:00
Matthew Hodgson
9498cd3e7b fix conflict and reinstate 6372dff771 2018-10-22 20:27:25 +02:00
Matthew Hodgson
c7503f8f33 merge in master 2018-10-22 20:19:40 +02:00
Michael Kaye
9d8baa1595 Allow us to configure http vs https for user_directory 2018-10-17 11:38:48 +01:00
Matthew Hodgson
4ff8486f0f fix missing import and run isort 2018-07-20 11:29:18 +01:00
David Baker
2669e494e0 Merge remote-tracking branch 'origin/master' into dinsic 2018-07-19 18:25:25 +01:00
David Baker
b6d8a808a4 Merge pull request #3557 from matrix-org/dbkr/delete_profiles
Remove deactivated users from profile search
2018-07-19 15:58:40 +01:00
David Baker
0cb5d34756 Hopefully fix postgres 2018-07-19 15:12:48 +01:00
David Baker
650761666d More run_on_reactor 2018-07-19 14:52:35 +01:00
David Baker
aa2a4b4b42 run_on_reactor is dead 2018-07-19 14:48:24 +01:00
David Baker
022469d819 Change column def so it works on pgsql & sqlite
Now I remember discovering previously there was no way to make boolean
columns work
2018-07-19 10:28:26 +01:00
David Baker
45d06c754a Add hopefully enlightening comment 2018-07-18 20:52:21 +01:00
David Baker
dbd0821c43 Oops, didn't mean to commit that 2018-07-18 20:50:20 +01:00
David Baker
0476852fc6 Remove deactivated users from profile search 2018-07-18 18:05:29 +01:00
David Baker
1d11d9323d Merge remote-tracking branch 'origin/master' into dinsic 2018-07-17 15:43:33 +01:00
Michael Kaye
261e4f2542 Merge pull request #3502 from matrix-org/matthew/dinsic-tweak-display-names
tweak dinsic display names
2018-07-10 15:59:26 +01:00
Matthew Hodgson
11728561f3 improve domain matches 2018-07-10 15:21:14 +01:00
Matthew Hodgson
9d57abcadd fix bounds error 2018-07-10 13:58:01 +01:00
Matthew Hodgson
cb0bbde981 tweak dinsic display names 2018-07-10 13:56:32 +01:00
Matthew Hodgson
abc97bd1de Merge pull request #3487 from matrix-org/matthew/dinsic-encrypt-for-invited-users
Query the device lists of users when they are invited to a room.
2018-07-10 12:21:57 +01:00
Matthew Hodgson
ee238254a0 Query the device lists of users when they are invited to a room.
Previously we only queried the device list when the user joined the room; now we
do it when they are invited too.  This means that new messages can be encrypted
for the devices of the invited user as of the point they were invited.

WARNING: This commit has two major problems however:
 1. If the invited user adds devices after being invited but before joining, the
    device-list will not be updated to the other servers in the room (as we don't
    know who those servers are).
 2. This introduces a regression, as previously the device-list would be correctly
    updated when when user joined the room.  However, this resync doesn't happen
    now, so devices which joined after the invite and before the join may never
    be added to the device-list.

This is being merged for DINSIC given the edge case of adding devices between
invite & join is pretty rare in their use case, but before it can be merged to
synapse in general we need to at least re-sync the devicelist when the user joins
or to implement some kind of pubsub mechanism to let interested servers subscribe
to devicelist updates on other servers irrespective of user join/invite membership.

This was originally https://github.com/matrix-org/synapse/pull/3484
2018-07-06 16:29:08 +02:00
Matthew Hodgson
0125b5d002 typos 2018-06-25 17:37:00 +01:00
Michael Kaye
fe265fe990 Merge tag 'v0.31.2' into dinsic 2018-06-22 17:04:50 +01:00
David Baker
7735eee41d Merge pull request #3426 from matrix-org/dbkr/e2e_by_default
Server-enforced e2e for private rooms
2018-06-22 16:49:42 +01:00
David Baker
3d0faa39fb Add m.encryption to event types 2018-06-22 16:47:49 +01:00
David Baker
fd28d13e19 Server-enforced e2e for private rooms 2018-06-22 13:54:17 +01:00
Michael Kaye
d18731e252 Merge pull request #3202 from matrix-org/michaelkaye/domain_based_rule_checker
DomainRuleChecker
2018-05-21 09:32:47 +01:00
Michael Kaye
81beae30b8 Update with documentation suggestions 2018-05-18 16:12:22 +01:00
Michael Kaye
11f1bace3c Address PR feedback
- add code and test to handle configuration of an empty array
- move docstrings around and update class level documentation
2018-05-11 12:51:03 +01:00
Michael Kaye
1e8cfc9e77 pep8 style fixes 2018-05-09 15:11:19 +01:00
Michael Kaye
488ed3e444 Generic "are users in domain X allowed to invite users in domain Y" logic 2018-05-09 14:50:48 +01:00
Matthew Hodgson
c3ec84dbcd Merge pull request #3096 from matrix-org/matthew/derive-mxid-from-3pid
add the register_mxid_from_3pid setting (untested)
2018-05-04 02:26:46 +01:00
Matthew Hodgson
0783801659 unbreak tests 2018-05-04 02:18:01 +01:00
Matthew Hodgson
9f2fd29c14 fix double negative 2018-05-04 02:11:22 +01:00
Matthew Hodgson
6372dff771 remove create_profile from tests 2018-05-04 01:58:45 +01:00
Matthew Hodgson
b3e346f40c don't pass a requester if we don't have one to set_displayname 2018-05-04 01:56:01 +01:00
Matthew Hodgson
fb47ce3e6a make set_profile_* an upsert rather than update, now create_profile is gone 2018-05-04 01:46:26 +01:00
Matthew Hodgson
debf04556b fix user in user regexp 2018-05-04 01:15:33 +01:00
Matrix
907a62df28 fix strip_invalid_mxid_characters 2018-05-03 23:54:36 +00:00
Matrix
41b987cbc5 unbreak 3pid deletion 2018-05-03 23:54:36 +00:00
Matthew Hodgson
5c74ab4064 fix user_id / user confusion 2018-05-04 00:53:56 +01:00
Matrix
06820250c9 unbreak 3pid deletion 2018-05-03 23:27:34 +00:00
Matthew Hodgson
383c4ae59c Merge branch 'dinsic' into matthew/derive-mxid-from-3pid 2018-05-03 23:39:08 +01:00
Matthew Hodgson
f639ac143d Merge pull request #3180 from matrix-org/matthew/disable-3pid-changes
add option to disable changes to the 3PIDs for an account.
2018-05-03 18:19:58 +01:00
Matthew Hodgson
ad0424bab0 Merge pull request #3179 from matrix-org/matthew/disable-set-profile
options to disable setting profile info
2018-05-03 18:19:48 +01:00
Matthew Hodgson
2992125561 special case msisdns when deriving mxids from 3pids 2018-05-03 17:52:46 +01:00
David Baker
ef56b6e27c Merge pull request #3185 from matrix-org/dbkr/change_profile_replication_uri
Change profile replication URI
2018-05-03 15:17:51 +01:00
David Baker
53d6245529 Change profile replication URI 2018-05-03 14:55:40 +01:00
Matthew Hodgson
25e471dac3 fix defaults in config example 2018-05-03 11:46:56 +01:00
Matthew Hodgson
76fca1730e fix defaults in example config 2018-05-03 11:46:11 +01:00
Matthew Hodgson
32e4420a66 improve mxid & displayname selection for register_mxid_from_3pid
* [x] strip invalid characters from generated mxid
* [x] append numbers to disambiguate clashing mxids
* [x] generate displayanames from 3pids using a dodgy heuristic
* [x] get rid of the create_profile_with_localpart and instead
      explicitly set displaynames so they propagate correctly
2018-05-03 04:21:20 +01:00
Matthew Hodgson
79b2583f1b Merge branch 'dinsic' into matthew/derive-mxid-from-3pid 2018-05-03 02:51:49 +01:00
Matthew Hodgson
8a24c4eee5 add option to disable changes to the 3PIDs for an account.
This only considers the /account/3pid API, which should be sufficient
as currently we can't change emails associated with push notifs
(which are provisioned at registration), and we can't directly create
mappings for accounts in an IS other than by answering an invite
2018-05-03 02:47:55 +01:00
Matthew Hodgson
f93cb7410d options to disable setting profile info 2018-05-03 01:29:12 +01:00
Matthew Hodgson
50d5a97c1b Merge branch 'master' into dinsic 2018-05-03 00:26:33 +01:00
David Baker
c06932a029 Merge pull request #3166 from matrix-org/dbkr/postgres_doesnt_have_ifnull
Use COALESCE rather than IFNULL
2018-05-01 18:15:28 +01:00
David Baker
3a62cacfb0 Use COALESCE rather than IFNULL
as this works on sqlite and postgres (postgres doesn't have IFNULL)
2018-05-01 17:54:03 +01:00
David Baker
4d55b16faa Fix python synatx 2018-05-01 14:32:30 +01:00
David Baker
105709bf32 Fix profile repl 2018-05-01 14:27:14 +01:00
David Baker
d7fad867fa Merge pull request #3123 from matrix-org/dbkr/user_directory_defer_to_is
Option to defer user_directory search to an ID server
2018-04-27 17:18:13 +01:00
David Baker
8fddcf703e Merge remote-tracking branch 'origin/dinsic' into dbkr/user_directory_defer_to_is 2018-04-26 10:23:12 +01:00
David Baker
e2adb360eb Merge pull request #3112 from matrix-org/dbkr/profile_replication
Option to replicate user profiles to another server
2018-04-26 10:22:28 +01:00
David Baker
47ed4a4aa7 PR feedback
Unnecessary inlineCallbacks, missing yield, SQL comments & trailing
commas.
2018-04-25 13:58:37 +01:00
David Baker
7fafa838ae Comment why the looping call loops 2018-04-25 11:59:22 +01:00
David Baker
de341bec1b Add 'ex[erimental API' comment 2018-04-25 11:51:57 +01:00
David Baker
643c89d497 Fix spelling & add experimental API comment 2018-04-25 11:40:37 +01:00
David Baker
6554253f48 Option to defer to an ID server for user_directory 2018-04-19 19:28:12 +01:00
David Baker
3add16df49 pep8 again 2018-04-17 13:23:16 +01:00
David Baker
dde01efbcb Don't do profile repl if no repl targets 2018-04-17 12:26:45 +01:00
David Baker
22e416b726 Update profile cache only on master
and same for the profile replication
2018-04-17 12:17:16 +01:00
David Baker
b4b7c80181 Fix other tests 2018-04-17 11:03:10 +01:00
David Baker
5fc3477fd3 Fix tests 2018-04-17 10:46:49 +01:00
David Baker
8743f42b49 pep8 2018-04-17 10:34:04 +01:00
David Baker
7285afa4be Handle current batch number being null 2018-04-17 10:28:00 +01:00
Matthew Hodgson
b22a53e357 turn @'s to -'s rather than .'s 2018-04-17 09:32:42 +01:00
David Baker
3c446d0a81 Merge remote-tracking branch 'origin/dinsic' into dbkr/profile_replication 2018-04-16 18:35:25 +01:00
Matthew Hodgson
240e940c3f handle medium checks correctly 2018-04-12 18:30:32 +01:00
Matthew Hodgson
969ed2e49d add the register_mxid_from_3pid setting (untested) 2018-04-12 18:20:51 +01:00
David Baker
1147ce7e18 Include origin_server in the sig!
Also be consistent with underscores
2018-04-12 17:59:37 +01:00
Matthew Hodgson
0d2b7fdcec Merge branch 'develop' into dinsic 2018-04-12 13:29:57 +01:00
David Baker
4e12b10c7c Trigger profile replication on profile change 2018-04-11 10:17:07 +01:00
David Baker
e654230a51 Written but untested profile replication 2018-04-10 17:41:58 +01:00
Matthew Hodgson
ef5193e0cb Merge pull request #2973 from matrix-org/matthew/dinsic_3pid_check
Delegate 3PID registration determination to experimental IS API
2018-03-14 22:35:58 +00:00
Matthew Hodgson
7b3959c7f3 Merge branch 'develop' into dinsic 2018-03-14 22:31:34 +00:00
Matthew Hodgson
2e4a6c5aab incorporate PR feedback and rename URL 2018-03-14 22:09:08 +00:00
Matthew Hodgson
e3eb2cfe8b Merge branch 'develop' into matthew/dinsic_3pid_check 2018-03-14 21:56:58 +00:00
Matthew Hodgson
5c341c99f6 add 'allow_invited_3pids' option to invited 3PIDs to register 2018-03-13 21:15:14 +00:00
Matthew Hodgson
739d3500fe pep8 2018-03-13 01:50:32 +00:00
Matthew Hodgson
0e2d70e101 typos 2018-03-13 01:41:20 +00:00
Matthew Hodgson
82c4fd7226 add yields 2018-03-13 01:38:02 +00:00
Matthew Hodgson
e446077478 delegate to the IS to check 3PID signup eligibility 2018-03-13 01:34:20 +00:00
Matthew Hodgson
d82c89ac22 fix thinko on 3pid whitelisting 2018-01-24 11:07:24 +01:00
Matthew Hodgson
75b25b3f1f Merge branch 'develop' into dinsic 2018-01-23 10:00:53 +01:00
AmandineLP
1df10d8814 Fixed translation 2018-01-22 21:18:44 +01:00
AmandineLP
8f9340d248 Fixed translation 2018-01-22 21:17:36 +01:00
AmandineLP
c5034cd4b0 More translation 2018-01-22 21:16:46 +01:00
AmandineLP
f7f937d051 Translate to FR 2018-01-22 21:14:13 +01:00
AmandineLP
e52b5d94a9 Translate to FR 2018-01-22 21:13:03 +01:00
AmandineLP
d90f27a21f Translate to FR 2018-01-22 21:12:06 +01:00
AmandineLP
03cf9710e3 Translate to FR 2018-01-22 21:10:00 +01:00
AmandineLP
1dcdd8d568 Translate to FR 2018-01-22 20:02:47 +01:00
AmandineLP
4344fb1faf translate to FR 2018-01-22 20:01:00 +01:00
Matthew Hodgson
846577ebde fork notif templates 2018-01-22 19:55:27 +01:00
Matthew Hodgson
3869981227 remove unreachable except block 2018-01-22 18:43:41 +01:00
Matthew Hodgson
fa80b492a5 fix thinko 2018-01-22 18:43:41 +01:00
Richard van der Hoff
c776c52eed Back out unrelated changes 2018-01-22 16:44:39 +00:00
Matthew Hodgson
b424c16f50 fix tests 2018-01-22 15:25:25 +01:00
Matthew Hodgson
313a489fc9 incorporate PR feedback 2018-01-22 14:54:46 +01:00
Matthew Hodgson
4b090cb273 add federation_domain_whitelist
gives a way to restrict which domains your HS is allowed to federate with.
useful mainly for gracefully preventing a private but internet-connected HS from trying to federate to the wider public Matrix network
2018-01-22 12:13:41 +01:00
Matthew Hodgson
3f79378d4b make replication tests pass on OSX 2018-01-20 17:23:27 +00:00
170 changed files with 8324 additions and 578 deletions

34
.buildkite/merge_base_branch.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -ex
if [[ "$BUILDKITE_BRANCH" == "dinsic" ]]; then
echo "Not merging forward, as this is a release branch"
exit 0
fi
if [[ -z $BUILDKITE_PULL_REQUEST_BASE_BRANCH ]]; then
echo "Can't figure out what the PR number is! Assuming merge target is dinsic."
# It probably hasn't had a PR opened yet. Since all PRs for dinsic land on
# dinsic, we can probably assume it's based on it and will be merged into
# it.
GITBASE="dinsic"
else
# Get the reference, using the GitHub API
GITBASE=$BUILDKITE_PULL_REQUEST_BASE_BRANCH
fi
# Show what we are before
git --no-pager show -s
# Set up username so it can do a merge
git config --global user.email bot@matrix.org
git config --global user.name "A robot"
# Fetch and merge. If it doesn't work, it will raise due to set -e.
git fetch -u origin $GITBASE
git merge --no-edit --no-commit origin/$GITBASE
# Show what we are after.
git --no-pager show -s

View File

@@ -232,3 +232,106 @@ steps:
limit: 2
- exit_status: 2
limit: 2
- label: "SyTest - :python: 2.7 / :postgres: 9.6 / Monolith"
agents:
queue: "medium"
env:
POSTGRES: "1"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash /synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:dinsic"
propagate-environment: true
always-pull: true
workdir: "/src"
entrypoint: "/bin/sh"
init: false
shell: ["-x", "-c"]
mount-buildkite-agent: false
volumes: ["./logs:/logs"]
- artifacts#v1.2.0:
upload: [ "logs/**/*.log", "logs/**/*.log.*", "logs/results.tap" ]
- matrix-org/annotate:
path: "logs/annotate.md"
style: "error"
- label: "SyTest - :python: 2.7 / :postgres: 9.6 / Workers"
agents:
queue: "xlarge"
env:
POSTGRES: "1"
WORKERS: "1"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash /synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:dinsic"
propagate-environment: true
always-pull: true
workdir: "/src"
entrypoint: "/bin/sh"
init: false
shell: ["-x", "-c"]
mount-buildkite-agent: false
volumes: ["./logs:/logs"]
- artifacts#v1.2.0:
upload: [ "logs/**/*.log", "logs/**/*.log.*", "logs/results.tap" ]
- matrix-org/annotate:
path: "logs/annotate.md"
style: "error"
- label: "SyTest - :python: 3 / :postgres: 9.6 / Monolith"
agents:
queue: "medium"
env:
POSTGRES: "1"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash /synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:dinsic-py3"
propagate-environment: true
always-pull: true
workdir: "/src"
entrypoint: "/bin/sh"
init: false
shell: ["-x", "-c"]
mount-buildkite-agent: false
volumes: ["./logs:/logs"]
- artifacts#v1.2.0:
upload: [ "logs/**/*.log", "logs/**/*.log.*", "logs/results.tap" ]
- matrix-org/annotate:
path: "logs/annotate.md"
style: "error"
- label: "SyTest - :python: 3 / :postgres: 9.6 / Workers"
agents:
queue: "xlarge"
env:
POSTGRES: "1"
WORKERS: "1"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash /synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:dinsic-py3"
propagate-environment: true
always-pull: true
workdir: "/src"
entrypoint: "/bin/sh"
init: false
shell: ["-x", "-c"]
mount-buildkite-agent: false
volumes: ["./logs:/logs"]
- artifacts#v1.2.0:
upload: [ "logs/**/*.log", "logs/**/*.log.*", "logs/results.tap" ]
- matrix-org/annotate:
path: "logs/annotate.md"
style: "error"

View File

@@ -1,170 +0,0 @@
version: 2
jobs:
dockerhubuploadrelease:
machine: true
steps:
- checkout
- run: docker build -f docker/Dockerfile --label gitsha1=${CIRCLE_SHA1} -t matrixdotorg/synapse:${CIRCLE_TAG}-py2 .
- run: docker build -f docker/Dockerfile --label gitsha1=${CIRCLE_SHA1} -t matrixdotorg/synapse:${CIRCLE_TAG} -t matrixdotorg/synapse:${CIRCLE_TAG}-py3 --build-arg PYTHON_VERSION=3.6 .
- run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_PASSWORD
- run: docker push matrixdotorg/synapse:${CIRCLE_TAG}
- run: docker push matrixdotorg/synapse:${CIRCLE_TAG}-py2
- run: docker push matrixdotorg/synapse:${CIRCLE_TAG}-py3
dockerhubuploadlatest:
machine: true
steps:
- checkout
- run: docker build -f docker/Dockerfile --label gitsha1=${CIRCLE_SHA1} -t matrixdotorg/synapse:latest-py2 .
- run: docker build -f docker/Dockerfile --label gitsha1=${CIRCLE_SHA1} -t matrixdotorg/synapse:latest -t matrixdotorg/synapse:latest-py3 --build-arg PYTHON_VERSION=3.6 .
- run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_PASSWORD
- run: docker push matrixdotorg/synapse:latest
- run: docker push matrixdotorg/synapse:latest-py2
- run: docker push matrixdotorg/synapse:latest-py3
sytestpy2:
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy2postgres:
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy2merged:
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy2postgresmerged:
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy3:
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy3postgres:
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy3merged:
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
sytestpy3postgresmerged:
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: /logs
destination: logs
- store_test_results:
path: /logs
workflows:
version: 2
build:
jobs:
- sytestpy2:
filters:
branches:
only: /develop|master|release-.*/
- sytestpy2postgres:
filters:
branches:
only: /develop|master|release-.*/
- sytestpy3:
filters:
branches:
only: /develop|master|release-.*/
- sytestpy3postgres:
filters:
branches:
only: /develop|master|release-.*/
- sytestpy2merged:
filters:
branches:
ignore: /develop|master|release-.*/
- sytestpy2postgresmerged:
filters:
branches:
ignore: /develop|master|release-.*/
- sytestpy3merged:
filters:
branches:
ignore: /develop|master|release-.*/
- sytestpy3postgresmerged:
filters:
branches:
ignore: /develop|master|release-.*/
- dockerhubuploadrelease:
filters:
tags:
only: /v[0-9].[0-9]+.[0-9]+.*/
branches:
ignore: /.*/
- dockerhubuploadlatest:
filters:
branches:
only: master

View File

@@ -1,34 +0,0 @@
#!/usr/bin/env bash
set -e
# CircleCI doesn't give CIRCLE_PR_NUMBER in the environment for non-forked PRs. Wonderful.
# In this case, we just need to do some ~shell magic~ to strip it out of the PULL_REQUEST URL.
echo 'export CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}"' >> $BASH_ENV
source $BASH_ENV
if [[ -z "${CIRCLE_PR_NUMBER}" ]]
then
echo "Can't figure out what the PR number is! Assuming merge target is develop."
# It probably hasn't had a PR opened yet. Since all PRs land on develop, we
# can probably assume it's based on it and will be merged into it.
GITBASE="develop"
else
# Get the reference, using the GitHub API
GITBASE=`wget -O- https://api.github.com/repos/matrix-org/synapse/pulls/${CIRCLE_PR_NUMBER} | jq -r '.base.ref'`
fi
# Show what we are before
git --no-pager show -s
# Set up username so it can do a merge
git config --global user.email bot@matrix.org
git config --global user.name "A robot"
# Fetch and merge. If it doesn't work, it will raise due to set -e.
git fetch -u origin $GITBASE
git merge --no-edit origin/$GITBASE
# Show what we are after.
git --no-pager show -s

View File

@@ -1,3 +1,24 @@
Synapse 1.0.0 (2019-06-11)
==========================
Bugfixes
--------
- Fix bug where attempting to send transactions with large number of EDUs can fail. ([\#5418](https://github.com/matrix-org/synapse/issues/5418))
Improved Documentation
----------------------
- Expand the federation guide to include relevant content from the MSC1711 FAQ ([\#5419](https://github.com/matrix-org/synapse/issues/5419))
Internal Changes
----------------
- Move password reset links to /_matrix/client/unstable namespace. ([\#5424](https://github.com/matrix-org/synapse/issues/5424))
Synapse 1.0.0rc3 (2019-06-10)
=============================

View File

@@ -1,14 +1,14 @@
* [Installing Synapse](#installing-synapse)
* [Installing from source](#installing-from-source)
* [Platform-Specific Instructions](#platform-specific-instructions)
* [Troubleshooting Installation](#troubleshooting-installation)
* [Prebuilt packages](#prebuilt-packages)
* [Setting up Synapse](#setting-up-synapse)
* [TLS certificates](#tls-certificates)
* [Email](#email)
* [Registering a user](#registering-a-user)
* [Setting up a TURN server](#setting-up-a-turn-server)
* [URL previews](#url-previews)
- [Installing Synapse](#installing-synapse)
- [Installing from source](#installing-from-source)
- [Platform-Specific Instructions](#platform-specific-instructions)
- [Troubleshooting Installation](#troubleshooting-installation)
- [Prebuilt packages](#prebuilt-packages)
- [Setting up Synapse](#setting-up-synapse)
- [TLS certificates](#tls-certificates)
- [Email](#email)
- [Registering a user](#registering-a-user)
- [Setting up a TURN server](#setting-up-a-turn-server)
- [URL previews](#url-previews)
# Installing Synapse
@@ -395,8 +395,9 @@ To configure Synapse to expose an HTTPS port, you will need to edit
instance, if using certbot, use `fullchain.pem` as your certificate, not
`cert.pem`).
For those of you upgrading your TLS certificate for Synapse 1.0 compliance,
please take a look at [our guide](docs/MSC1711_certificates_FAQ.md#configuring-certificates-for-compatibility-with-synapse-100).
For a more detailed guide to configuring your server for federation, see
[federate.md](docs/federate.md)
## Email

View File

@@ -1,4 +1,5 @@
include synctl
include sytest-blacklist
include LICENSE
include VERSION
include *.rst
@@ -48,3 +49,8 @@ prune .buildkite
exclude jenkins*
recursive-exclude jenkins *.sh
# FIXME: we shouldn't have these templates here
recursive-include res/templates-dinsic *.css
recursive-include res/templates-dinsic *.html
recursive-include res/templates-dinsic *.txt

1
changelog.d/1.feature Normal file
View File

@@ -0,0 +1 @@
Forbid changing the name, avatar or topic of a direct room.

1
changelog.d/10.bugfix Normal file
View File

@@ -0,0 +1 @@
Don't apply retention policy based filtering on state events.

1
changelog.d/11.feature Normal file
View File

@@ -0,0 +1 @@
Allow server admins to configure a custom global rate-limiting for third party invites.

1
changelog.d/12.feature Normal file
View File

@@ -0,0 +1 @@
Add `/user/:user_id/info` CS servlet and to give user deactivated/expired information.

1
changelog.d/13.feature Normal file
View File

@@ -0,0 +1 @@
Hide expired users from the user directory, and optionally re-add them on renewal.

1
changelog.d/14.feature Normal file
View File

@@ -0,0 +1 @@
User displaynames now have capitalised letters after - symbols.

1
changelog.d/15.misc Normal file
View File

@@ -0,0 +1 @@
Fix the ordering on `scripts/generate_signing_key.py`'s import statement.

1
changelog.d/17.misc Normal file
View File

@@ -0,0 +1 @@
Blacklist some flaky sytests until they're fixed.

1
changelog.d/18.feature Normal file
View File

@@ -0,0 +1 @@
Add option `limit_profile_requests_to_known_users` to prevent requirement of a user sharing a room with another user to query their profile information.

1
changelog.d/19.feature Normal file
View File

@@ -0,0 +1 @@
Add `max_avatar_size` and `allowed_avatar_mimetypes` to restrict the size of user avatars and their file type respectively.

1
changelog.d/2.bugfix Normal file
View File

@@ -0,0 +1 @@
Don't treat 3PID revocation as a new 3PID invite.

1
changelog.d/20.bugfix Normal file
View File

@@ -0,0 +1 @@
Validate `client_secret` parameter against the regex provided by the C-S spec.

1
changelog.d/21.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix resetting user passwords via a phone number.

1
changelog.d/3.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix encoding on password reset HTML responses in Python 2.

1
changelog.d/4.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix handling of filtered strings in Python 3.

1
changelog.d/5.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix room retention policy management in worker mode.

1
changelog.d/5083.feature Normal file
View File

@@ -0,0 +1 @@
Adds auth_profile_reqs option to require access_token to GET /profile endpoints on CS API.

1
changelog.d/5098.misc Normal file
View File

@@ -0,0 +1 @@
Add workarounds for pep-517 install errors.

1
changelog.d/5214.feature Normal file
View File

@@ -0,0 +1 @@
Allow server admins to define and enforce a password policy (MSC2000).

1
changelog.d/5363.feature Normal file
View File

@@ -0,0 +1 @@
Allow expired user to trigger renewal email sending manually.

1
changelog.d/5378.misc Normal file
View File

@@ -0,0 +1 @@
Track deactivated accounts in the database.

1
changelog.d/5394.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix a bug where deactivated users could receive renewal emails if the account validity feature is on.

1
changelog.d/5416.misc Normal file
View File

@@ -0,0 +1 @@
Add unique index to the profile_replication_status table.

View File

@@ -1 +0,0 @@
Fix bug where attempting to send transactions with large number of EDUs can fail.

1
changelog.d/5420.feature Normal file
View File

@@ -0,0 +1 @@
Add configuration option to hide new users from the user directory.

1
changelog.d/5464.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix missing invite state after exchanging 3PID invites over federaton.

2
changelog.d/5465.misc Normal file
View File

@@ -0,0 +1,2 @@
Track deactivated accounts in the database.

1
changelog.d/5474.feature Normal file
View File

@@ -0,0 +1 @@
Allow server admins to define implementations of extra rules for allowing or denying incoming events.

1
changelog.d/5477.feature Normal file
View File

@@ -0,0 +1 @@
Allow server admins to define implementations of extra rules for allowing or denying incoming events.

1
changelog.d/5493.misc Normal file
View File

@@ -0,0 +1 @@
Track deactivated accounts in the database.

1
changelog.d/5534.feature Normal file
View File

@@ -0,0 +1 @@
Split public rooms directory auth config in two settings, in order to manage client auth independently from the federation part of it. Obsoletes the "restrict_public_rooms_to_local_users" configuration setting. If "restrict_public_rooms_to_local_users" is set in the config, Synapse will act as if both new options are enabled, i.e. require authentication through the client API and deny federation requests.

1
changelog.d/5576.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix a bug that would cause invited users to receive several emails for a single 3PID invite in case the inviter is rate limited.

1
changelog.d/5610.feature Normal file
View File

@@ -0,0 +1 @@
Implement new custom event rules for power levels.

1
changelog.d/5644.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix newly-registered users not being able to lookup their own profile without joining a room.

1
changelog.d/5702.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix 3PID invite to invite association detection in the Tchap room access rules.

1
changelog.d/5760.feature Normal file
View File

@@ -0,0 +1 @@
Force the access rule to be "restricted" if the join rule is "public".

1
changelog.d/5780.misc Normal file
View File

@@ -0,0 +1 @@
Allow looping calls to be given arguments.

1
changelog.d/5807.feature Normal file
View File

@@ -0,0 +1 @@
Allow defining HTML templates to serve the user on account renewal attempt when using the account validity feature.

1
changelog.d/5815.feature Normal file
View File

@@ -0,0 +1 @@
Implement per-room message retention policies.

1
changelog.d/6.bugfix Normal file
View File

@@ -0,0 +1 @@
Don't forbid membership events which membership isn't 'join' or 'invite' in restricted rooms, so that users who got into these rooms before the access rules started to be enforced can leave them.

1
changelog.d/6125.feature Normal file
View File

@@ -0,0 +1 @@
Reject all pending invites for a user during deactivation.

1
changelog.d/6147.bugfix Normal file
View File

@@ -0,0 +1 @@
Don't 500 when trying to exchange a revoked 3PID invite.

1
changelog.d/6238.feature Normal file
View File

@@ -0,0 +1 @@
Add support for outbound http proxying via http_proxy/HTTPS_PROXY env vars.

1
changelog.d/6436.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix a bug where a room could become unusable with a low retention policy and a low activity.

1
changelog.d/9.misc Normal file
View File

@@ -0,0 +1 @@
Add SyTest to the BuildKite CI.

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
matrix-synapse-py3 (1.0.0) stable; urgency=medium
* New synapse release 1.0.0.
-- Synapse Packaging team <packages@matrix.org> Tue, 11 Jun 2019 17:09:53 +0100
matrix-synapse-py3 (0.99.5.2) stable; urgency=medium
* New synapse release 0.99.5.2.

View File

@@ -14,7 +14,7 @@ This image is designed to run either with an automatically generated
configuration file or with a custom configuration that requires manual editing.
An easy way to make use of this image is via docker-compose. See the
[contrib/docker](../contrib/docker) section of the synapse project for
[contrib/docker](https://github.com/matrix-org/synapse/tree/master/contrib/docker) section of the synapse project for
examples.
### Without Compose (harder)

View File

@@ -1,5 +1,22 @@
# MSC1711 Certificates FAQ
## Historical Note
This document was originally written to guide server admins through the upgrade
path towards Synapse 1.0. Specifically,
[MSC1711](https://github.com/matrix-org/matrix-doc/blob/master/proposals/1711-x509-for-federation.md)
required that all servers present valid TLS certificates on their federation
API. Admins were encouraged to achieve compliance from version 0.99.0 (released
in February 2019) ahead of version 1.0 (released June 2019) enforcing the
certificate checks.
Much of what follows is now outdated since most admins will have already
upgraded, however it may be of use to those with old installs returning to the
project.
If you are setting up a server from scratch you almost certainly should look at
the [installation guide](INSTALL.md) instead.
## Introduction
The goal of Synapse 0.99.0 is to act as a stepping stone to Synapse 1.0.0. It
supports the r0.1 release of the server to server specification, but is
compatible with both the legacy Matrix federation behaviour (pre-r0.1) as well

View File

@@ -14,9 +14,9 @@ up and will work provided you set the ``server_name`` to match your
machine's public DNS hostname, and provide Synapse with a TLS certificate
which is valid for your ``server_name``.
Once you have completed the steps necessary to federate, you should be able to
join a room via federation. (A good place to start is ``#synapse:matrix.org`` - a
room for Synapse admins.)
Once federation has been configured, you should be able to join a room over
federation. A good place to start is ``#synapse:matrix.org`` - a room for
Synapse admins.
## Delegation
@@ -98,6 +98,77 @@ _matrix._tcp.<server_name>``. In our example, we would expect this:
Note that the target of a SRV record cannot be an alias (CNAME record): it has to point
directly to the server hosting the synapse instance.
### Delegation FAQ
#### When do I need a SRV record or .well-known URI?
If your homeserver listens on the default federation port (8448), and your
`server_name` points to the host that your homeserver runs on, you do not need an SRV
record or `.well-known/matrix/server` URI.
For instance, if you registered `example.com` and pointed its DNS A record at a
fresh server, you could install Synapse on that host,
giving it a `server_name` of `example.com`, and once [ACME](acme.md) support is enabled,
it would automatically generate a valid TLS certificate for you via Let's Encrypt
and no SRV record or .well-known URI would be needed.
This is the common case, although you can add an SRV record or
`.well-known/matrix/server` URI for completeness if you wish.
**However**, if your server does not listen on port 8448, or if your `server_name`
does not point to the host that your homeserver runs on, you will need to let
other servers know how to find it. The way to do this is via .well-known or an
SRV record.
#### I have created a .well-known URI. Do I still need an SRV record?
As of Synapse 0.99, Synapse will first check for the existence of a .well-known
URI and follow any delegation it suggests. It will only then check for the
existence of an SRV record.
That means that the SRV record will often be redundant. However, you should
remember that there may still be older versions of Synapse in the federation
which do not understand .well-known URIs, so if you removed your SRV record
you would no longer be able to federate with them.
It is therefore best to leave the SRV record in place for now. Synapse 0.34 and
earlier will follow the SRV record (and not care about the invalid
certificate). Synapse 0.99 and later will follow the .well-known URI, with the
correct certificate chain.
#### Can I manage my own certificates rather than having Synapse renew certificates itself?
Yes, you are welcome to manage your certificates yourself. Synapse will only
attempt to obtain certificates from Let's Encrypt if you configure it to do
so.The only requirement is that there is a valid TLS cert present for
federation end points.
#### Do you still recommend against using a reverse proxy on the federation port?
We no longer actively recommend against using a reverse proxy. Many admins will
find it easier to direct federation traffic to a reverse proxy and manage their
own TLS certificates, and this is a supported configuration.
See [reverse_proxy.rst](reverse_proxy.rst) for information on setting up a
reverse proxy.
#### Do I still need to give my TLS certificates to Synapse if I am using a reverse proxy?
Practically speaking, this is no longer necessary.
If you are using a reverse proxy for all of your TLS traffic, then you can set
`no_tls: True` in the Synapse config. In that case, the only reason Synapse
needs the certificate is to populate a legacy `tls_fingerprints` field in the
federation API. This is ignored by Synapse 0.99.0 and later, and the only time
pre-0.99 Synapses will check it is when attempting to fetch the server keys -
and generally this is delegated via `matrix.org`, which will be running a modern
version of Synapse.
#### Do I need the same certificate for the client and federation port?
No. There is nothing stopping you from using different certificates,
particularly if you are using a reverse proxy. However, Synapse will use the
same certificate on any ports where TLS is configured.
## Troubleshooting
You can use the [federation tester](

View File

@@ -77,11 +77,22 @@ pid_file: DATADIR/homeserver.pid
#
#require_auth_for_profile_requests: true
# If set to 'true', requires authentication to access the server's
# public rooms directory through the client API, and forbids any other
# homeserver to fetch it via federation. Defaults to 'false'.
# Whether to require a user to share a room with another user in order
# to retrieve their profile information. Only checked on Client-Server
# requests. Profile requests from other servers should be checked by the
# requesting server. Defaults to 'false'.
#
#restrict_public_rooms_to_local_users: true
# limit_profile_requests_to_known_users: true
# If set to 'false', requires authentication to access the server's public rooms
# directory through the client API. Defaults to 'true'.
#
#allow_public_rooms_without_auth: false
# If set to 'false', forbids any other homeserver to fetch the server's public
# rooms directory via federation. Defaults to 'true'.
#
#allow_public_rooms_over_federation: false
# The default room version for newly created rooms.
#
@@ -308,6 +319,74 @@ listeners:
#
#allow_per_room_profiles: false
# Whether to show the users on this homeserver in the user directory. Defaults to
# 'true'.
#
#show_users_in_user_directory: false
# Message retention policy at the server level.
#
# Room admins and mods can define a retention period for their rooms using the
# 'm.room.retention' state event, and server admins can cap this period by setting
# the 'allowed_lifetime_min' and 'allowed_lifetime_max' config options.
#
# If this feature is enabled, Synapse will regularly look for and purge events
# which are older than the room's maximum retention period. Synapse will also
# filter events received over federation so that events that should have been
# purged are ignored and not stored again.
#
retention:
# The message retention policies feature is disabled by default. Uncomment the
# following line to enable it.
#
#enabled: true
# Default retention policy. If set, Synapse will apply it to rooms that lack the
# 'm.room.retention' state event. Currently, the value of 'min_lifetime' doesn't
# matter much because Synapse doesn't take it into account yet.
#
#default_policy:
# min_lifetime: 1d
# max_lifetime: 1y
# Retention policy limits. If set, a user won't be able to send a
# 'm.room.retention' event which features a 'min_lifetime' or a 'max_lifetime'
# that's not within this range. This is especially useful in closed federations,
# in which server admins can make sure every federating server applies the same
# rules.
#
#allowed_lifetime_min: 1d
#allowed_lifetime_max: 1y
# Server admins can define the settings of the background jobs purging the
# events which lifetime has expired under the 'purge_jobs' section.
#
# If no configuration is provided, a single job will be set up to delete expired
# events in every room daily.
#
# Each job's configuration defines which range of message lifetimes the job
# takes care of. For example, if 'shortest_max_lifetime' is '2d' and
# 'longest_max_lifetime' is '3d', the job will handle purging expired events in
# rooms whose state defines a 'max_lifetime' that's both higher than 2 days, and
# lower than or equal to 3 days. Both the minimum and the maximum value of a
# range are optional, e.g. a job with no 'shortest_max_lifetime' and a
# 'longest_max_lifetime' of '3d' will handle every room with a retention policy
# which 'max_lifetime' is lower than or equal to three days.
#
# The rationale for this per-job configuration is that some rooms might have a
# retention policy with a low 'max_lifetime', where history needs to be purged
# of outdated messages on a very frequent basis (e.g. every 5min), but not want
# that purge to be performed by a job that's iterating over every room it knows,
# which would be quite heavy on the server.
#
#purge_jobs:
# - shortest_max_lifetime: 1d
# longest_max_lifetime: 3d
# interval: 5m:
# - shortest_max_lifetime: 3d
# longest_max_lifetime: 1y
# interval: 24h
## TLS ##
@@ -496,6 +575,8 @@ log_config: "CONFDIR/SERVERNAME.log.config"
# - one for login that ratelimits login requests based on the account the
# client is attempting to log into, based on the amount of failed login
# attempts for this account.
# - one that ratelimits third-party invites requests based on the account
# that's making the requests.
#
# The defaults are as shown below.
#
@@ -517,6 +598,10 @@ log_config: "CONFDIR/SERVERNAME.log.config"
# failed_attempts:
# per_second: 0.17
# burst_count: 3
#
#rc_third_party_invite:
# per_second: 0.2
# burst_count: 10
# Ratelimiting settings for incoming federation
@@ -578,6 +663,30 @@ uploads_path: "DATADIR/uploads"
#
#max_upload_size: 10M
# The largest allowed size for a user avatar. If not defined, no
# restriction will be imposed.
#
# Note that this only applies when an avatar is changed globally.
# Per-room avatar changes are not affected. See allow_per_room_profiles
# for disabling that functionality.
#
# Note that user avatar changes will not work if this is set without
# using Synapse's local media repo.
#
#max_avatar_size: 10M
# Allow mimetypes for a user avatar. If not defined, no restriction will
# be imposed.
#
# Note that this only applies when an avatar is changed globally.
# Per-room avatar changes are not affected. See allow_per_room_profiles
# for disabling that functionality.
#
# Note that user avatar changes will not work if this is set without
# using Synapse's local media repo.
#
#allowed_avatar_mimetypes: ["image/png", "image/jpeg", "image/gif"]
# Maximum number of pixels that will be thumbnailed
#
#max_image_pixels: 32M
@@ -788,6 +897,16 @@ uploads_path: "DATADIR/uploads"
# period: 6w
# renew_at: 1w
# renew_email_subject: "Renew your %(app)s account"
# # Directory in which Synapse will try to find the HTML files to serve to the
# # user when trying to renew an account. Optional, defaults to
# # synapse/res/templates.
# template_dir: "res/templates"
# # HTML to be displayed to the user after they successfully renewed their
# # account. Optional.
# account_renewed_html_path: "account_renewed.html"
# # HTML to be displayed when the user tries to renew an account with an invalid
# # renewal token. Optional.
# invalid_token_html_path: "invalid_token.html"
# The user must provide all of the below types of 3PID when registering.
#
@@ -800,9 +919,32 @@ uploads_path: "DATADIR/uploads"
#
#disable_msisdn_registration: true
# Derive the user's matrix ID from a type of 3PID used when registering.
# This overrides any matrix ID the user proposes when calling /register
# The 3PID type should be present in registrations_require_3pid to avoid
# users failing to register if they don't specify the right kind of 3pid.
#
#register_mxid_from_3pid: email
# Uncomment to set the display name of new users to their email address,
# rather than using the default heuristic.
#
#register_just_use_email_for_display_name: true
# Mandate that users are only allowed to associate certain formats of
# 3PIDs with accounts on this server.
#
# Use an Identity Server to establish which 3PIDs are allowed to register?
# Overrides allowed_local_3pids below.
#
#check_is_for_allowed_local_3pids: matrix.org
#
# If you are using an IS you can also check whether that IS registers
# pending invites for the given 3PID (and then allow it to sign up on
# the platform):
#
#allow_invited_3pids: False
#
#allowed_local_3pids:
# - medium: email
# pattern: '.*@matrix\.org'
@@ -811,6 +953,11 @@ uploads_path: "DATADIR/uploads"
# - medium: msisdn
# pattern: '\+44'
# If true, stop users from trying to change the 3PIDs associated with
# their accounts.
#
#disable_3pid_changes: False
# Enable 3PIDs lookup requests to identity servers from this server.
#
#enable_3pid_lookup: true
@@ -852,6 +999,30 @@ uploads_path: "DATADIR/uploads"
# - matrix.org
# - vector.im
# If enabled, user IDs, display names and avatar URLs will be replicated
# to this server whenever they change.
# This is an experimental API currently implemented by sydent to support
# cross-homeserver user directories.
#
#replicate_user_profiles_to: example.com
# If specified, attempt to replay registrations, profile changes & 3pid
# bindings on the given target homeserver via the AS API. The HS is authed
# via a given AS token.
#
#shadow_server:
# hs_url: https://shadow.example.com
# hs: shadow.example.com
# as_token: 12u394refgbdhivsia
# If enabled, don't let users set their own display names/avatars
# other than for the very first time (unless they are a server admin).
# Useful when provisioning users based on the contents of a 3rd party
# directory and to avoid ambiguities.
#
#disable_set_displayname: False
#disable_set_avatar_url: False
# Users who register on this homeserver will automatically be joined
# to these rooms
#
@@ -1063,6 +1234,36 @@ password_config:
#
#pepper: "EVEN_MORE_SECRET"
# Define and enforce a password policy. Each parameter is optional, boolean
# parameters default to 'false' and integer parameters default to 0.
# This is an early implementation of MSC2000.
#
#policy:
# Whether to enforce the password policy.
#
#enabled: true
# Minimum accepted length for a password.
#
#minimum_length: 15
# Whether a password must contain at least one digit.
#
#require_digit: true
# Whether a password must contain at least one symbol.
# A symbol is any character that's not a number or a letter.
#
#require_symbol: true
# Whether a password must contain at least one lowercase letter.
#
#require_lowercase: true
# Whether a password must contain at least one lowercase letter.
#
#require_uppercase: true
# Enable sending emails for password resets, notification events or
@@ -1199,6 +1400,11 @@ password_config:
#user_directory:
# enabled: true
# search_all_users: false
#
# # If this is set, user search will be delegated to this ID server instead
# # of synapse performing the search itself.
# # This is an experimental API.
# defer_to_id_server: https://id.example.com
# User Consent configuration

View File

@@ -0,0 +1,7 @@
.header {
border-bottom: 4px solid #e4f7ed ! important;
}
.notif_link a, .footer a {
color: #76CFA6 ! important;
}

View File

@@ -0,0 +1,156 @@
body {
margin: 0px;
}
pre, code {
word-break: break-word;
white-space: pre-wrap;
}
#page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-color: #454545;
font-size: 12pt;
width: 100%;
padding: 20px;
}
#inner {
width: 640px;
}
.header {
width: 100%;
height: 87px;
color: #454545;
border-bottom: 4px solid #e5e5e5;
}
.logo {
text-align: right;
margin-left: 20px;
}
.salutation {
padding-top: 10px;
font-weight: bold;
}
.summarytext {
}
.room {
width: 100%;
color: #454545;
border-bottom: 1px solid #e5e5e5;
}
.room_header td {
padding-top: 38px;
padding-bottom: 10px;
border-bottom: 1px solid #e5e5e5;
}
.room_name {
vertical-align: middle;
font-size: 18px;
font-weight: bold;
}
.room_header h2 {
margin-top: 0px;
margin-left: 75px;
font-size: 20px;
}
.room_avatar {
width: 56px;
line-height: 0px;
text-align: center;
vertical-align: middle;
}
.room_avatar img {
width: 48px;
height: 48px;
object-fit: cover;
border-radius: 24px;
}
.notif {
border-bottom: 1px solid #e5e5e5;
margin-top: 16px;
padding-bottom: 16px;
}
.historical_message .sender_avatar {
opacity: 0.3;
}
/* spell out opacity and historical_message class names for Outlook aka Word */
.historical_message .sender_name {
color: #e3e3e3;
}
.historical_message .message_time {
color: #e3e3e3;
}
.historical_message .message_body {
color: #c7c7c7;
}
.historical_message td,
.message td {
padding-top: 10px;
}
.sender_avatar {
width: 56px;
text-align: center;
vertical-align: top;
}
.sender_avatar img {
margin-top: -2px;
width: 32px;
height: 32px;
border-radius: 16px;
}
.sender_name {
display: inline;
font-size: 13px;
color: #a2a2a2;
}
.message_time {
text-align: right;
width: 100px;
font-size: 11px;
color: #a2a2a2;
}
.message_body {
}
.notif_link td {
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
}
.notif_link a, .footer a {
color: #454545;
text-decoration: none;
}
.debug {
font-size: 10px;
color: #888;
}
.footer {
margin-top: 20px;
text-align: center;
}

View File

@@ -0,0 +1,45 @@
{% for message in notif.messages %}
<tr class="{{ "historical_message" if message.is_historical else "message" }}">
<td class="sender_avatar">
{% if loop.index0 == 0 or notif.messages[loop.index0 - 1].sender_name != notif.messages[loop.index0].sender_name %}
{% if message.sender_avatar_url %}
<img alt="" class="sender_avatar" src="{{ message.sender_avatar_url|mxc_to_http(32,32) }}" />
{% else %}
{% if message.sender_hash % 3 == 0 %}
<img class="sender_avatar" src="https://vector.im/beta/img/76cfa6.png" />
{% elif message.sender_hash % 3 == 1 %}
<img class="sender_avatar" src="https://vector.im/beta/img/50e2c2.png" />
{% else %}
<img class="sender_avatar" src="https://vector.im/beta/img/f4c371.png" />
{% endif %}
{% endif %}
{% endif %}
</td>
<td class="message_contents">
{% if loop.index0 == 0 or notif.messages[loop.index0 - 1].sender_name != notif.messages[loop.index0].sender_name %}
<div class="sender_name">{% if message.msgtype == "m.emote" %}*{% endif %} {{ message.sender_name }}</div>
{% endif %}
<div class="message_body">
{% if message.msgtype == "m.text" %}
{{ message.body_text_html }}
{% elif message.msgtype == "m.emote" %}
{{ message.body_text_html }}
{% elif message.msgtype == "m.notice" %}
{{ message.body_text_html }}
{% elif message.msgtype == "m.image" %}
<img src="{{ message.image_url|mxc_to_http(640, 480, scale) }}" />
{% elif message.msgtype == "m.file" %}
<span class="filename">{{ message.body_text_plain }}</span>
{% endif %}
</div>
</td>
<td class="message_time">{{ message.ts|format_ts("%H:%M") }}</td>
</tr>
{% endfor %}
<tr class="notif_link">
<td></td>
<td>
<a href="{{ notif.link }}">Voir {{ room.title }}</a>
</td>
<td></td>
</tr>

View File

@@ -0,0 +1,16 @@
{% for message in notif.messages %}
{% if message.msgtype == "m.emote" %}* {% endif %}{{ message.sender_name }} ({{ message.ts|format_ts("%H:%M") }})
{% if message.msgtype == "m.text" %}
{{ message.body_text_plain }}
{% elif message.msgtype == "m.emote" %}
{{ message.body_text_plain }}
{% elif message.msgtype == "m.notice" %}
{{ message.body_text_plain }}
{% elif message.msgtype == "m.image" %}
{{ message.body_text_plain }}
{% elif message.msgtype == "m.file" %}
{{ message.body_text_plain }}
{% endif %}
{% endfor %}
Voir {{ room.title }} à {{ notif.link }}

View File

@@ -0,0 +1,55 @@
<!doctype html>
<html lang="en">
<head>
<style type="text/css">
{% include 'mail.css' without context %}
{% include "mail-%s.css" % app_name ignore missing without context %}
</style>
</head>
<body>
<table id="page">
<tr>
<td> </td>
<td id="inner">
<table class="header">
<tr>
<td>
<div class="salutation">Bonjour {{ user_display_name }},</div>
<div class="summarytext">{{ summary_text }}</div>
</td>
<td class="logo">
{% if app_name == "Riot" %}
<img src="http://matrix.org/img/riot-logo-email.png" width="83" height="83" alt="[Riot]"/>
{% elif app_name == "Vector" %}
<img src="http://matrix.org/img/vector-logo-email.png" width="64" height="83" alt="[Vector]"/>
{% else %}
<img src="http://matrix.org/img/matrix-120x51.png" width="120" height="51" alt="[matrix]"/>
{% endif %}
</td>
</tr>
</table>
{% for room in rooms %}
{% include 'room.html' with context %}
{% endfor %}
<div class="footer">
<a href="{{ unsubscribe_link }}">Se désinscrire</a>
<br/>
<br/>
<div class="debug">
Sending email at {{ reason.now|format_ts("%c") }} due to activity in room {{ reason.room_name }} because
an event was received at {{ reason.received_at|format_ts("%c") }}
which is more than {{ "%.1f"|format(reason.delay_before_mail_ms / (60*1000)) }} ({{ reason.delay_before_mail_ms }}) mins ago,
{% if reason.last_sent_ts %}
and the last time we sent a mail for this room was {{ reason.last_sent_ts|format_ts("%c") }},
which is more than {{ "%.1f"|format(reason.throttle_ms / (60*1000)) }} (current throttle_ms) mins ago.
{% else %}
and we don't have a last time we sent a mail for this room.
{% endif %}
</div>
</div>
</td>
<td> </td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,10 @@
Bonjour {{ user_display_name }},
{{ summary_text }}
{% for room in rooms %}
{% include 'room.txt' with context %}
{% endfor %}
Vous pouvez désactiver ces notifications en cliquant ici {{ unsubscribe_link }}

View File

@@ -0,0 +1,33 @@
<table class="room">
<tr class="room_header">
<td class="room_avatar">
{% if room.avatar_url %}
<img alt="" src="{{ room.avatar_url|mxc_to_http(48,48) }}" />
{% else %}
{% if room.hash % 3 == 0 %}
<img alt="" src="https://vector.im/beta/img/76cfa6.png" />
{% elif room.hash % 3 == 1 %}
<img alt="" src="https://vector.im/beta/img/50e2c2.png" />
{% else %}
<img alt="" src="https://vector.im/beta/img/f4c371.png" />
{% endif %}
{% endif %}
</td>
<td class="room_name" colspan="2">
{{ room.title }}
</td>
</tr>
{% if room.invite %}
<tr>
<td></td>
<td>
<a href="{{ room.link }}">Rejoindre la conversation.</a>
</td>
<td></td>
</tr>
{% else %}
{% for notif in room.notifs %}
{% include 'notif.html' with context %}
{% endfor %}
{% endif %}
</table>

View File

@@ -0,0 +1,9 @@
{{ room.title }}
{% if room.invite %}
  Vous avez été invité, rejoignez la conversation en cliquant sur le lien suivant {{ room.link }}
{% else %}
{% for notif in room.notifs %}
{% include 'notif.txt' with context %}
{% endfor %}
{% endif %}

View File

@@ -5,9 +5,9 @@
set -e
# make sure that origin/develop is up to date
git remote set-branches --add origin develop
git fetch origin develop
# make sure that origin/dinsic is up to date
git remote set-branches --add origin dinsic
git fetch origin dinsic
# if there are changes in the debian directory, check that the debian changelog
# has been updated

View File

@@ -16,7 +16,7 @@
import argparse
import sys
from signedjson.key import write_signing_keys, generate_signing_key
from signedjson.key import generate_signing_key, write_signing_keys
from synapse.util.stringutils import random_string

View File

@@ -27,4 +27,4 @@ try:
except ImportError:
pass
__version__ = "1.0.0rc3"
__version__ = "1.0.0"

View File

@@ -184,11 +184,22 @@ class Auth(object):
return event_auth.get_public_keys(invite_event)
@defer.inlineCallbacks
def get_user_by_req(self, request, allow_guest=False, rights="access"):
def get_user_by_req(
self,
request,
allow_guest=False,
rights="access",
allow_expired=False,
):
""" Get a registered user's ID.
Args:
request - An HTTP request with an access_token query parameter.
allow_expired - Whether to allow the request through even if the account is
expired. If true, Synapse will still require an access token to be
provided but won't check if the account it belongs to has expired. This
works thanks to /login delivering access tokens regardless of accounts'
expiration.
Returns:
defer.Deferred: resolves to a ``synapse.types.Requester`` object
Raises:
@@ -207,6 +218,7 @@ class Auth(object):
)
user_id, app_service = yield self._get_appservice_user_id(request)
if user_id:
request.authenticated_entity = user_id
@@ -229,7 +241,7 @@ class Auth(object):
is_guest = user_info["is_guest"]
# Deny the request if the user account has expired.
if self._account_validity.enabled:
if self._account_validity.enabled and not allow_expired:
user_id = user.to_string()
expiration_ts = yield self.store.get_expiration_ts_for_user(user_id)
if expiration_ts is not None and self.clock.time_msec() >= expiration_ts:
@@ -268,39 +280,40 @@ class Auth(object):
errcode=Codes.MISSING_TOKEN
)
@defer.inlineCallbacks
def _get_appservice_user_id(self, request):
app_service = self.store.get_app_service_by_token(
self.get_access_token_from_request(
request, self.TOKEN_NOT_FOUND_HTTP_STATUS
)
)
if app_service is None:
defer.returnValue((None, None))
return(None, None)
if app_service.ip_range_whitelist:
ip_address = IPAddress(self.hs.get_ip_from_request(request))
if ip_address not in app_service.ip_range_whitelist:
defer.returnValue((None, None))
return(None, None)
if b"user_id" not in request.args:
defer.returnValue((app_service.sender, app_service))
return(app_service.sender, app_service)
user_id = request.args[b"user_id"][0].decode('utf8')
if app_service.sender == user_id:
defer.returnValue((app_service.sender, app_service))
return(app_service.sender, app_service)
if not app_service.is_interested_in_user(user_id):
raise AuthError(
403,
"Application service cannot masquerade as this user."
)
if not (yield self.store.get_user_by_id(user_id)):
raise AuthError(
403,
"Application service has not registered this user"
)
defer.returnValue((user_id, app_service))
# Let ASes manipulate nonexistent users (e.g. to shadow-register them)
# if not (yield self.store.get_user_by_id(user_id)):
# raise AuthError(
# 403,
# "Application service has not registered this user"
# )
return(user_id, app_service)
@defer.inlineCallbacks
def get_user_by_access_token(self, token, rights="access"):
@@ -533,24 +546,15 @@ class Auth(object):
defer.returnValue(user_info)
def get_appservice_by_req(self, request):
try:
token = self.get_access_token_from_request(
request, self.TOKEN_NOT_FOUND_HTTP_STATUS
)
service = self.store.get_app_service_by_token(token)
if not service:
logger.warn("Unrecognised appservice access token.")
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS,
"Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN
)
request.authenticated_entity = service.sender
return defer.succeed(service)
except KeyError:
(user_id, app_service) = self._get_appservice_user_id(request)
if not app_service:
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Missing access token."
self.TOKEN_NOT_FOUND_HTTP_STATUS,
"Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN,
)
request.authenticated_entity = app_service.sender
return app_service
def is_server_admin(self, user):
""" Check if the given user is a local server admin.

View File

@@ -83,6 +83,7 @@ class EventTypes(object):
RoomAvatar = "m.room.avatar"
RoomEncryption = "m.room.encryption"
GuestAccess = "m.room.guest_access"
Encryption = "m.room.encryption"
# These are used for validation
Message = "m.room.message"
@@ -92,6 +93,8 @@ class EventTypes(object):
ServerACL = "m.room.server_acl"
Pinned = "m.room.pinned_events"
Retention = "m.room.retention"
class RejectedReason(object):
AUTH_ERROR = "auth_error"

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2018 New Vector Ltd
# Copyright 2017-2018 New Vector Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -61,6 +62,13 @@ class Codes(object):
INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION"
WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
EXPIRED_ACCOUNT = "ORG_MATRIX_EXPIRED_ACCOUNT"
PASSWORD_TOO_SHORT = "M_PASSWORD_TOO_SHORT"
PASSWORD_NO_DIGIT = "M_PASSWORD_NO_DIGIT"
PASSWORD_NO_UPPERCASE = "M_PASSWORD_NO_UPPERCASE"
PASSWORD_NO_LOWERCASE = "M_PASSWORD_NO_LOWERCASE"
PASSWORD_NO_SYMBOL = "M_PASSWORD_NO_SYMBOL"
PASSWORD_IN_DICTIONARY = "M_PASSWORD_IN_DICTIONARY"
WEAK_PASSWORD = "M_WEAK_PASSWORD"
class CodeMessageException(RuntimeError):
@@ -372,6 +380,22 @@ class IncompatibleRoomVersionError(SynapseError):
)
class PasswordRefusedError(SynapseError):
"""A password has been refused, either during password reset/change or registration.
"""
def __init__(
self,
msg="This password doesn't comply with the server's policy",
errcode=Codes.WEAK_PASSWORD,
):
super(PasswordRefusedError, self).__init__(
code=400,
msg=msg,
errcode=errcode,
)
class RequestSendFailed(RuntimeError):
"""Sending a HTTP request over federation failed due to not being able to
talk to the remote server for some reason.

View File

@@ -176,7 +176,6 @@ class SynapseHomeServer(HomeServer):
resources.update({
"/_matrix/client/api/v1": client_resource,
"/_synapse/password_reset": client_resource,
"/_matrix/client/r0": client_resource,
"/_matrix/client/unstable": client_resource,
"/_matrix/client/v2_alpha": client_resource,
@@ -564,9 +563,8 @@ def run(hs):
stats["database_server_version"] = hs.get_datastore().get_server_version()
logger.info("Reporting stats to matrix.org: %s" % (stats,))
try:
yield hs.get_simple_http_client().put_json(
"https://matrix.org/report-usage-stats/push",
stats
yield hs.get_proxied_http_client().put_json(
"https://matrix.org/report-usage-stats/push", stats
)
except Exception as e:
logger.warn("Error reporting stats: %s", e)

View File

@@ -265,7 +265,7 @@ class ApplicationService(object):
def is_exclusive_room(self, room_id):
return self._is_exclusive(ApplicationService.NS_ROOMS, room_id)
def get_exlusive_user_regexes(self):
def get_exclusive_user_regexes(self):
"""Get the list of regexes used to determine if a user is exclusively
registered by the AS
"""

View File

@@ -16,6 +16,7 @@
import argparse
import errno
import os
from io import open as io_open
from textwrap import dedent
from six import integer_types
@@ -131,7 +132,7 @@ class Config(object):
@classmethod
def read_file(cls, file_path, config_name):
cls.check_file(file_path, config_name)
with open(file_path) as file_stream:
with io_open(file_path, encoding="utf-8") as file_stream:
return file_stream.read()
@staticmethod

View File

@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd
# Copyright 2015-2016 OpenMarket Ltd
# Copyright 2017-2018 New Vector Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -28,6 +30,10 @@ class PasswordConfig(Config):
self.password_enabled = password_config.get("enabled", True)
self.password_pepper = password_config.get("pepper", "")
# Password policy
self.password_policy = password_config.get("policy", {})
self.password_policy_enabled = self.password_policy.pop("enabled", False)
def default_config(self, config_dir_path, server_name, **kwargs):
return """\
password_config:
@@ -39,4 +45,34 @@ class PasswordConfig(Config):
# DO NOT CHANGE THIS AFTER INITIAL SETUP!
#
#pepper: "EVEN_MORE_SECRET"
# Define and enforce a password policy. Each parameter is optional, boolean
# parameters default to 'false' and integer parameters default to 0.
# This is an early implementation of MSC2000.
#
#policy:
# Whether to enforce the password policy.
#
#enabled: true
# Minimum accepted length for a password.
#
#minimum_length: 15
# Whether a password must contain at least one digit.
#
#require_digit: true
# Whether a password must contain at least one symbol.
# A symbol is any character that's not a number or a letter.
#
#require_symbol: true
# Whether a password must contain at least one lowercase letter.
#
#require_lowercase: true
# Whether a password must contain at least one lowercase letter.
#
#require_uppercase: true
"""

View File

@@ -68,6 +68,9 @@ class RatelimitConfig(Config):
)
self.rc_registration = RateLimitConfig(config.get("rc_registration", {}))
self.rc_third_party_invite = RateLimitConfig(
config.get("rc_third_party_invite", {})
)
rc_login_config = config.get("rc_login", {})
self.rc_login_address = RateLimitConfig(rc_login_config.get("address", {}))
@@ -102,6 +105,8 @@ class RatelimitConfig(Config):
# - one for login that ratelimits login requests based on the account the
# client is attempting to log into, based on the amount of failed login
# attempts for this account.
# - one that ratelimits third-party invites requests based on the account
# that's making the requests.
#
# The defaults are as shown below.
#
@@ -123,6 +128,10 @@ class RatelimitConfig(Config):
# failed_attempts:
# per_second: 0.17
# burst_count: 3
#
#rc_third_party_invite:
# per_second: 0.2
# burst_count: 10
# Ratelimiting settings for incoming federation

View File

@@ -13,8 +13,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from distutils.util import strtobool
import pkg_resources
from synapse.config._base import Config, ConfigError
from synapse.types import RoomAlias
from synapse.util.stringutils import random_string_with_symbols
@@ -41,8 +44,36 @@ class AccountValidityConfig(Config):
self.startup_job_max_delta = self.period * 10. / 100.
if self.renew_by_email_enabled and "public_baseurl" not in synapse_config:
raise ConfigError("Can't send renewal emails without 'public_baseurl'")
if self.renew_by_email_enabled:
if "public_baseurl" not in synapse_config:
raise ConfigError("Can't send renewal emails without 'public_baseurl'")
template_dir = config.get("template_dir")
if not template_dir:
template_dir = pkg_resources.resource_filename("synapse", "res/templates")
if "account_renewed_html_path" in config:
file_path = os.path.join(template_dir, config["account_renewed_html_path"])
self.account_renewed_html_content = self.read_file(
file_path, "account_validity.account_renewed_html_path"
)
else:
self.account_renewed_html_content = (
"<html><body>Your account has been successfully renewed.</body><html>"
)
if "invalid_token_html_path" in config:
file_path = os.path.join(template_dir, config["invalid_token_html_path"])
self.invalid_token_html_content = self.read_file(
file_path, "account_validity.invalid_token_html_path"
)
else:
self.invalid_token_html_content = (
"<html><body>Invalid renewal token.</body><html>"
)
class RegistrationConfig(Config):
@@ -62,8 +93,19 @@ class RegistrationConfig(Config):
self.registrations_require_3pid = config.get("registrations_require_3pid", [])
self.allowed_local_3pids = config.get("allowed_local_3pids", [])
self.check_is_for_allowed_local_3pids = config.get(
"check_is_for_allowed_local_3pids", None
)
self.allow_invited_3pids = config.get("allow_invited_3pids", False)
self.disable_3pid_changes = config.get("disable_3pid_changes", False)
self.enable_3pid_lookup = config.get("enable_3pid_lookup", True)
self.registration_shared_secret = config.get("registration_shared_secret")
self.register_mxid_from_3pid = config.get("register_mxid_from_3pid")
self.register_just_use_email_for_display_name = config.get(
"register_just_use_email_for_display_name", False,
)
self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
self.trusted_third_party_id_servers = config.get(
@@ -83,6 +125,16 @@ class RegistrationConfig(Config):
raise ConfigError('Invalid auto_join_rooms entry %s' % (room_alias,))
self.autocreate_auto_join_rooms = config.get("autocreate_auto_join_rooms", True)
self.disable_set_displayname = config.get("disable_set_displayname", False)
self.disable_set_avatar_url = config.get("disable_set_avatar_url", False)
self.replicate_user_profiles_to = config.get("replicate_user_profiles_to", [])
if not isinstance(self.replicate_user_profiles_to, list):
self.replicate_user_profiles_to = [self.replicate_user_profiles_to, ]
self.shadow_server = config.get("shadow_server", None)
self.rewrite_identity_server_urls = config.get("rewrite_identity_server_urls", {})
self.disable_msisdn_registration = (
config.get("disable_msisdn_registration", False)
)
@@ -140,6 +192,16 @@ class RegistrationConfig(Config):
# period: 6w
# renew_at: 1w
# renew_email_subject: "Renew your %%(app)s account"
# # Directory in which Synapse will try to find the HTML files to serve to the
# # user when trying to renew an account. Optional, defaults to
# # synapse/res/templates.
# template_dir: "res/templates"
# # HTML to be displayed to the user after they successfully renewed their
# # account. Optional.
# account_renewed_html_path: "account_renewed.html"
# # HTML to be displayed when the user tries to renew an account with an invalid
# # renewal token. Optional.
# invalid_token_html_path: "invalid_token.html"
# The user must provide all of the below types of 3PID when registering.
#
@@ -152,9 +214,32 @@ class RegistrationConfig(Config):
#
#disable_msisdn_registration: true
# Derive the user's matrix ID from a type of 3PID used when registering.
# This overrides any matrix ID the user proposes when calling /register
# The 3PID type should be present in registrations_require_3pid to avoid
# users failing to register if they don't specify the right kind of 3pid.
#
#register_mxid_from_3pid: email
# Uncomment to set the display name of new users to their email address,
# rather than using the default heuristic.
#
#register_just_use_email_for_display_name: true
# Mandate that users are only allowed to associate certain formats of
# 3PIDs with accounts on this server.
#
# Use an Identity Server to establish which 3PIDs are allowed to register?
# Overrides allowed_local_3pids below.
#
#check_is_for_allowed_local_3pids: matrix.org
#
# If you are using an IS you can also check whether that IS registers
# pending invites for the given 3PID (and then allow it to sign up on
# the platform):
#
#allow_invited_3pids: False
#
#allowed_local_3pids:
# - medium: email
# pattern: '.*@matrix\\.org'
@@ -163,6 +248,11 @@ class RegistrationConfig(Config):
# - medium: msisdn
# pattern: '\\+44'
# If true, stop users from trying to change the 3PIDs associated with
# their accounts.
#
#disable_3pid_changes: False
# Enable 3PIDs lookup requests to identity servers from this server.
#
#enable_3pid_lookup: true
@@ -204,6 +294,30 @@ class RegistrationConfig(Config):
# - matrix.org
# - vector.im
# If enabled, user IDs, display names and avatar URLs will be replicated
# to this server whenever they change.
# This is an experimental API currently implemented by sydent to support
# cross-homeserver user directories.
#
#replicate_user_profiles_to: example.com
# If specified, attempt to replay registrations, profile changes & 3pid
# bindings on the given target homeserver via the AS API. The HS is authed
# via a given AS token.
#
#shadow_server:
# hs_url: https://shadow.example.com
# hs: shadow.example.com
# as_token: 12u394refgbdhivsia
# If enabled, don't let users set their own display names/avatars
# other than for the very first time (unless they are a server admin).
# Useful when provisioning users based on the contents of a 3rd party
# directory and to avoid ambiguities.
#
#disable_set_displayname: False
#disable_set_avatar_url: False
# Users who register on this homeserver will automatically be joined
# to these rooms
#

View File

@@ -111,6 +111,12 @@ class ContentRepositoryConfig(Config):
self.max_image_pixels = self.parse_size(config.get("max_image_pixels", "32M"))
self.max_spider_size = self.parse_size(config.get("max_spider_size", "10M"))
self.max_avatar_size = config.get("max_avatar_size")
if self.max_avatar_size:
self.max_avatar_size = self.parse_size(self.max_avatar_size)
self.allowed_avatar_mimetypes = config.get("allowed_avatar_mimetypes", [])
self.media_store_path = self.ensure_directory(config["media_store_path"])
backup_media_store_path = config.get("backup_media_store_path")
@@ -247,6 +253,30 @@ class ContentRepositoryConfig(Config):
#
#max_upload_size: 10M
# The largest allowed size for a user avatar. If not defined, no
# restriction will be imposed.
#
# Note that this only applies when an avatar is changed globally.
# Per-room avatar changes are not affected. See allow_per_room_profiles
# for disabling that functionality.
#
# Note that user avatar changes will not work if this is set without
# using Synapse's local media repo.
#
#max_avatar_size: 10M
# Allow mimetypes for a user avatar. If not defined, no restriction will
# be imposed.
#
# Note that this only applies when an avatar is changed globally.
# Per-room avatar changes are not affected. See allow_per_room_profiles
# for disabling that functionality.
#
# Note that user avatar changes will not work if this is set without
# using Synapse's local media repo.
#
#allowed_avatar_mimetypes: ["image/png", "image/jpeg", "image/gif"]
# Maximum number of pixels that will be thumbnailed
#
#max_image_pixels: 32M

View File

@@ -84,13 +84,39 @@ class ServerConfig(Config):
"require_auth_for_profile_requests", False,
)
# If set to 'True', requires authentication to access the server's
# public rooms directory through the client API, and forbids any other
# homeserver to fetch it via federation.
self.restrict_public_rooms_to_local_users = config.get(
"restrict_public_rooms_to_local_users", False,
# Whether to require sharing a room with a user to retrieve their
# profile data
self.limit_profile_requests_to_known_users = config.get(
"limit_profile_requests_to_known_users", False,
)
if "restrict_public_rooms_to_local_users" in config and (
"allow_public_rooms_without_auth" in config
or "allow_public_rooms_over_federation" in config
):
raise ConfigError(
"Can't use 'restrict_public_rooms_to_local_users' if"
" 'allow_public_rooms_without_auth' and/or"
" 'allow_public_rooms_over_federation' is set."
)
# Check if the legacy "restrict_public_rooms_to_local_users" flag is set. This
# flag is now obsolete but we need to check it for backward-compatibility.
if config.get("restrict_public_rooms_to_local_users", False):
self.allow_public_rooms_without_auth = False
self.allow_public_rooms_over_federation = False
else:
# If set to 'False', requires authentication to access the server's public
# rooms directory through the client API. Defaults to 'True'.
self.allow_public_rooms_without_auth = config.get(
"allow_public_rooms_without_auth", True
)
# If set to 'False', forbids any other homeserver to fetch the server's public
# rooms directory via federation. Defaults to 'True'.
self.allow_public_rooms_over_federation = config.get(
"allow_public_rooms_over_federation", True
)
default_room_version = config.get(
"default_room_version", DEFAULT_ROOM_VERSION,
)
@@ -202,6 +228,121 @@ class ServerConfig(Config):
# events with profile information that differ from the target's global profile.
self.allow_per_room_profiles = config.get("allow_per_room_profiles", True)
# Whether to show the users on this homeserver in the user directory. Defaults to
# True.
self.show_users_in_user_directory = config.get(
"show_users_in_user_directory", True,
)
retention_config = config.get("retention")
if retention_config is None:
retention_config = {}
self.retention_enabled = retention_config.get("enabled", False)
retention_default_policy = retention_config.get("default_policy")
if retention_default_policy is not None:
self.retention_default_min_lifetime = retention_default_policy.get(
"min_lifetime"
)
if self.retention_default_min_lifetime is not None:
self.retention_default_min_lifetime = self.parse_duration(
self.retention_default_min_lifetime
)
self.retention_default_max_lifetime = retention_default_policy.get(
"max_lifetime"
)
if self.retention_default_max_lifetime is not None:
self.retention_default_max_lifetime = self.parse_duration(
self.retention_default_max_lifetime
)
if (
self.retention_default_min_lifetime is not None
and self.retention_default_max_lifetime is not None
and (
self.retention_default_min_lifetime
> self.retention_default_max_lifetime
)
):
raise ConfigError(
"The default retention policy's 'min_lifetime' can not be greater"
" than its 'max_lifetime'"
)
else:
self.retention_default_min_lifetime = None
self.retention_default_max_lifetime = None
self.retention_allowed_lifetime_min = retention_config.get("allowed_lifetime_min")
if self.retention_allowed_lifetime_min is not None:
self.retention_allowed_lifetime_min = self.parse_duration(
self.retention_allowed_lifetime_min
)
self.retention_allowed_lifetime_max = retention_config.get("allowed_lifetime_max")
if self.retention_allowed_lifetime_max is not None:
self.retention_allowed_lifetime_max = self.parse_duration(
self.retention_allowed_lifetime_max
)
if (
self.retention_allowed_lifetime_min is not None
and self.retention_allowed_lifetime_max is not None
and self.retention_allowed_lifetime_min > self.retention_allowed_lifetime_max
):
raise ConfigError(
"Invalid retention policy limits: 'allowed_lifetime_min' can not be"
" greater than 'allowed_lifetime_max'"
)
self.retention_purge_jobs = []
for purge_job_config in retention_config.get("purge_jobs", []):
interval_config = purge_job_config.get("interval")
if interval_config is None:
raise ConfigError(
"A retention policy's purge jobs configuration must have the"
" 'interval' key set."
)
interval = self.parse_duration(interval_config)
shortest_max_lifetime = purge_job_config.get("shortest_max_lifetime")
if shortest_max_lifetime is not None:
shortest_max_lifetime = self.parse_duration(shortest_max_lifetime)
longest_max_lifetime = purge_job_config.get("longest_max_lifetime")
if longest_max_lifetime is not None:
longest_max_lifetime = self.parse_duration(longest_max_lifetime)
if (
shortest_max_lifetime is not None
and longest_max_lifetime is not None
and shortest_max_lifetime > longest_max_lifetime
):
raise ConfigError(
"A retention policy's purge jobs configuration's"
" 'shortest_max_lifetime' value can not be greater than its"
" 'longest_max_lifetime' value."
)
self.retention_purge_jobs.append({
"interval": interval,
"shortest_max_lifetime": shortest_max_lifetime,
"longest_max_lifetime": longest_max_lifetime,
})
if not self.retention_purge_jobs:
self.retention_purge_jobs = [{
"interval": self.parse_duration("1d"),
"shortest_max_lifetime": None,
"longest_max_lifetime": None,
}]
self.listeners = []
for listener in config.get("listeners", []):
if not isinstance(listener.get("port", None), int):
@@ -401,11 +542,22 @@ class ServerConfig(Config):
#
#require_auth_for_profile_requests: true
# If set to 'true', requires authentication to access the server's
# public rooms directory through the client API, and forbids any other
# homeserver to fetch it via federation. Defaults to 'false'.
# Whether to require a user to share a room with another user in order
# to retrieve their profile information. Only checked on Client-Server
# requests. Profile requests from other servers should be checked by the
# requesting server. Defaults to 'false'.
#
#restrict_public_rooms_to_local_users: true
# limit_profile_requests_to_known_users: true
# If set to 'false', requires authentication to access the server's public rooms
# directory through the client API. Defaults to 'true'.
#
#allow_public_rooms_without_auth: false
# If set to 'false', forbids any other homeserver to fetch the server's public
# rooms directory via federation. Defaults to 'true'.
#
#allow_public_rooms_over_federation: false
# The default room version for newly created rooms.
#
@@ -631,6 +783,74 @@ class ServerConfig(Config):
# Defaults to 'true'.
#
#allow_per_room_profiles: false
# Whether to show the users on this homeserver in the user directory. Defaults to
# 'true'.
#
#show_users_in_user_directory: false
# Message retention policy at the server level.
#
# Room admins and mods can define a retention period for their rooms using the
# 'm.room.retention' state event, and server admins can cap this period by setting
# the 'allowed_lifetime_min' and 'allowed_lifetime_max' config options.
#
# If this feature is enabled, Synapse will regularly look for and purge events
# which are older than the room's maximum retention period. Synapse will also
# filter events received over federation so that events that should have been
# purged are ignored and not stored again.
#
retention:
# The message retention policies feature is disabled by default. Uncomment the
# following line to enable it.
#
#enabled: true
# Default retention policy. If set, Synapse will apply it to rooms that lack the
# 'm.room.retention' state event. Currently, the value of 'min_lifetime' doesn't
# matter much because Synapse doesn't take it into account yet.
#
#default_policy:
# min_lifetime: 1d
# max_lifetime: 1y
# Retention policy limits. If set, a user won't be able to send a
# 'm.room.retention' event which features a 'min_lifetime' or a 'max_lifetime'
# that's not within this range. This is especially useful in closed federations,
# in which server admins can make sure every federating server applies the same
# rules.
#
#allowed_lifetime_min: 1d
#allowed_lifetime_max: 1y
# Server admins can define the settings of the background jobs purging the
# events which lifetime has expired under the 'purge_jobs' section.
#
# If no configuration is provided, a single job will be set up to delete expired
# events in every room daily.
#
# Each job's configuration defines which range of message lifetimes the job
# takes care of. For example, if 'shortest_max_lifetime' is '2d' and
# 'longest_max_lifetime' is '3d', the job will handle purging expired events in
# rooms whose state defines a 'max_lifetime' that's both higher than 2 days, and
# lower than or equal to 3 days. Both the minimum and the maximum value of a
# range are optional, e.g. a job with no 'shortest_max_lifetime' and a
# 'longest_max_lifetime' of '3d' will handle every room with a retention policy
# which 'max_lifetime' is lower than or equal to three days.
#
# The rationale for this per-job configuration is that some rooms might have a
# retention policy with a low 'max_lifetime', where history needs to be purged
# of outdated messages on a very frequent basis (e.g. every 5min), but not want
# that purge to be performed by a job that's iterating over every room it knows,
# which would be quite heavy on the server.
#
#purge_jobs:
# - shortest_max_lifetime: 1d
# longest_max_lifetime: 3d
# interval: 5m:
# - shortest_max_lifetime: 3d
# longest_max_lifetime: 1y
# interval: 24h
""" % locals()
def read_arguments(self, args):

View File

@@ -24,6 +24,7 @@ class UserDirectoryConfig(Config):
def read_config(self, config):
self.user_directory_search_enabled = True
self.user_directory_search_all_users = False
self.user_directory_defer_to_id_server = None
user_directory_config = config.get("user_directory", None)
if user_directory_config:
self.user_directory_search_enabled = (
@@ -32,6 +33,9 @@ class UserDirectoryConfig(Config):
self.user_directory_search_all_users = (
user_directory_config.get("search_all_users", False)
)
self.user_directory_defer_to_id_server = (
user_directory_config.get("defer_to_id_server", None)
)
def default_config(self, config_dir_path, server_name, **kwargs):
return """
@@ -50,4 +54,9 @@ class UserDirectoryConfig(Config):
#user_directory:
# enabled: true
# search_all_users: false
#
# # If this is set, user search will be delegated to this ID server instead
# # of synapse performing the search itself.
# # This is an experimental API.
# defer_to_id_server: https://id.example.com
"""

View File

@@ -46,13 +46,26 @@ class SpamChecker(object):
return self.spam_checker.check_event_for_spam(event)
def user_may_invite(self, inviter_userid, invitee_userid, room_id):
def user_may_invite(self, inviter_userid, invitee_userid, third_party_invite,
room_id, new_room, published_room):
"""Checks if a given user may send an invite
If this method returns false, the invite will be rejected.
Args:
userid (string): The sender's user ID
inviter_userid (str)
invitee_userid (str|None): The user ID of the invitee. Is None
if this is a third party invite and the 3PID is not bound to a
user ID.
third_party_invite (dict|None): If a third party invite then is a
dict containing the medium and address of the invitee.
room_id (str)
new_room (bool): Whether the user is being invited to the room as
part of a room creation, if so the invitee would have been
included in the call to `user_may_create_room`.
published_room (bool): Whether the room the user is being invited
to has been published in the local homeserver's public room
directory.
Returns:
bool: True if the user may send an invite, otherwise False
@@ -60,15 +73,25 @@ class SpamChecker(object):
if self.spam_checker is None:
return True
return self.spam_checker.user_may_invite(inviter_userid, invitee_userid, room_id)
return self.spam_checker.user_may_invite(
inviter_userid, invitee_userid, third_party_invite, room_id, new_room,
published_room,
)
def user_may_create_room(self, userid):
def user_may_create_room(self, userid, invite_list, third_party_invite_list,
cloning):
"""Checks if a given user may create a room
If this method returns false, the creation request will be rejected.
Args:
userid (string): The sender's user ID
invite_list (list[str]): List of user IDs that would be invited to
the new room.
third_party_invite_list (list[dict]): List of third party invites
for the new room.
cloning (bool): Whether the user is cloning an existing room, e.g.
upgrading a room.
Returns:
bool: True if the user may create a room, otherwise False
@@ -76,7 +99,9 @@ class SpamChecker(object):
if self.spam_checker is None:
return True
return self.spam_checker.user_may_create_room(userid)
return self.spam_checker.user_may_create_room(
userid, invite_list, third_party_invite_list, cloning,
)
def user_may_create_room_alias(self, userid, room_alias):
"""Checks if a given user may create a room alias
@@ -111,3 +136,21 @@ class SpamChecker(object):
return True
return self.spam_checker.user_may_publish_room(userid, room_id)
def user_may_join_room(self, userid, room_id, is_invited):
"""Checks if a given users is allowed to join a room.
Is not called when the user creates a room.
Args:
userid (str)
room_id (str)
is_invited (bool): Whether the user is invited into the room
Returns:
bool: Whether the user may join the room
"""
if self.spam_checker is None:
return True
return self.spam_checker.user_may_join_room(userid, room_id, is_invited)

View File

@@ -17,8 +17,8 @@ from twisted.internet import defer
class ThirdPartyEventRules(object):
"""Allows server admins to provide a Python module implementing an extra set of rules
to apply when processing events.
"""Allows server admins to provide a Python module implementing an extra
set of rules to apply when processing events.
This is designed to help admins of closed federations with enforcing custom
behaviours.
@@ -35,7 +35,10 @@ class ThirdPartyEventRules(object):
module, config = hs.config.third_party_event_rules
if module is not None:
self.third_party_rules = module(config=config)
self.third_party_rules = module(
config=config,
http_client=hs.get_simple_http_client(),
)
@defer.inlineCallbacks
def check_event_allowed(self, event, context):
@@ -46,7 +49,7 @@ class ThirdPartyEventRules(object):
context (synapse.events.snapshot.EventContext): The context of the event.
Returns:
defer.Deferred(bool), True if the event should be allowed, False if not.
defer.Deferred[bool]: True if the event should be allowed, False if not.
"""
if self.third_party_rules is None:
defer.returnValue(True)
@@ -60,3 +63,52 @@ class ThirdPartyEventRules(object):
ret = yield self.third_party_rules.check_event_allowed(event, state_events)
defer.returnValue(ret)
@defer.inlineCallbacks
def on_create_room(self, requester, config, is_requester_admin):
"""Intercept requests to create room to allow, deny or update the
request config.
Args:
requester (Requester)
config (dict): The creation config from the client.
is_requester_admin (bool): If the requester is an admin
Returns:
defer.Deferred
"""
if self.third_party_rules is None:
return
yield self.third_party_rules.on_create_room(
requester, config, is_requester_admin
)
@defer.inlineCallbacks
def check_threepid_can_be_invited(self, medium, address, room_id):
"""Check if a provided 3PID can be invited in the given room.
Args:
medium (str): The 3PID's medium.
address (str): The 3PID's address.
room_id (str): The room we want to invite the threepid to.
Returns:
defer.Deferred[bool], True if the 3PID can be invited, False if not.
"""
if self.third_party_rules is None:
defer.returnValue(True)
state_ids = yield self.store.get_filtered_current_state_ids(room_id)
room_state_events = yield self.store.get_events(state_ids.values())
state_events = {}
for key, event_id in state_ids.items():
state_events[key] = room_state_events[event_id]
ret = yield self.third_party_rules.check_threepid_can_be_invited(
medium, address, state_events,
)
defer.returnValue(ret)

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from six import string_types
from six import integer_types, string_types
from synapse.api.constants import MAX_ALIAS_LENGTH, EventTypes, Membership
from synapse.api.errors import Codes, SynapseError
@@ -22,11 +22,12 @@ from synapse.types import EventID, RoomID, UserID
class EventValidator(object):
def validate_new(self, event):
def validate_new(self, event, config):
"""Validates the event has roughly the right format
Args:
event (FrozenEvent)
event (FrozenEvent): The event to validate.
config (Config): The homeserver's configuration.
"""
self.validate_builder(event)
@@ -67,6 +68,99 @@ class EventValidator(object):
Codes.INVALID_PARAM,
)
if event.type == EventTypes.Retention:
self._validate_retention(event, config)
def _validate_retention(self, event, config):
"""Checks that an event that defines the retention policy for a room respects the
boundaries imposed by the server's administrator.
Args:
event (FrozenEvent): The event to validate.
config (Config): The homeserver's configuration.
"""
min_lifetime = event.content.get("min_lifetime")
max_lifetime = event.content.get("max_lifetime")
if min_lifetime is not None:
if not isinstance(min_lifetime, integer_types):
raise SynapseError(
code=400,
msg="'min_lifetime' must be an integer",
errcode=Codes.BAD_JSON,
)
if (
config.retention_allowed_lifetime_min is not None
and min_lifetime < config.retention_allowed_lifetime_min
):
raise SynapseError(
code=400,
msg=(
"'min_lifetime' can't be lower than the minimum allowed"
" value enforced by the server's administrator"
),
errcode=Codes.BAD_JSON,
)
if (
config.retention_allowed_lifetime_max is not None
and min_lifetime > config.retention_allowed_lifetime_max
):
raise SynapseError(
code=400,
msg=(
"'min_lifetime' can't be greater than the maximum allowed"
" value enforced by the server's administrator"
),
errcode=Codes.BAD_JSON,
)
if max_lifetime is not None:
if not isinstance(max_lifetime, integer_types):
raise SynapseError(
code=400,
msg="'max_lifetime' must be an integer",
errcode=Codes.BAD_JSON,
)
if (
config.retention_allowed_lifetime_min is not None
and max_lifetime < config.retention_allowed_lifetime_min
):
raise SynapseError(
code=400,
msg=(
"'max_lifetime' can't be lower than the minimum allowed value"
" enforced by the server's administrator"
),
errcode=Codes.BAD_JSON,
)
if (
config.retention_allowed_lifetime_max is not None
and max_lifetime > config.retention_allowed_lifetime_max
):
raise SynapseError(
code=400,
msg=(
"'max_lifetime' can't be greater than the maximum allowed"
" value enforced by the server's administrator"
),
errcode=Codes.BAD_JSON,
)
if (
min_lifetime is not None
and max_lifetime is not None
and min_lifetime > max_lifetime
):
raise SynapseError(
code=400,
msg="'min_lifetime' can't be greater than 'max_lifetime",
errcode=Codes.BAD_JSON,
)
def validate_builder(self, event):
"""Validates that the builder/event has roughly the right format. Only
checks values that we expect a proto event to have, rather than all the

View File

@@ -720,15 +720,15 @@ class PublicRoomList(BaseFederationServlet):
PATH = "/publicRooms"
def __init__(self, handler, authenticator, ratelimiter, server_name, deny_access):
def __init__(self, handler, authenticator, ratelimiter, server_name, allow_access):
super(PublicRoomList, self).__init__(
handler, authenticator, ratelimiter, server_name,
)
self.deny_access = deny_access
self.allow_access = allow_access
@defer.inlineCallbacks
def on_GET(self, origin, content, query):
if self.deny_access:
if not self.allow_access:
raise FederationDeniedError(origin)
limit = parse_integer_from_args(query, "limit", 0)
@@ -1455,7 +1455,7 @@ def register_servlets(hs, resource, authenticator, ratelimiter, servlet_groups=N
authenticator=authenticator,
ratelimiter=ratelimiter,
server_name=hs.hostname,
deny_access=hs.config.restrict_public_rooms_to_local_users,
allow_access=hs.config.allow_public_rooms_over_federation,
).register(resource)
if "group_server" in servlet_groups:

View File

@@ -42,6 +42,8 @@ class AccountValidityHandler(object):
self.clock = self.hs.get_clock()
self._account_validity = self.hs.config.account_validity
self._show_users_in_user_directory = self.hs.config.show_users_in_user_directory
self.profile_handler = self.hs.get_profile_handler()
if self._account_validity.renew_by_email_enabled and load_jinja2_templates:
# Don't do email-specific configuration if renewal by email is disabled.
@@ -74,6 +76,12 @@ class AccountValidityHandler(object):
30 * 60 * 1000,
)
# Check every hour to remove expired users from the user directory
self.clock.looping_call(
self._mark_expired_users_as_inactive,
60 * 60 * 1000,
)
@defer.inlineCallbacks
def send_renewal_emails(self):
"""Gets the list of users whose account is expiring in the amount of time
@@ -110,6 +118,9 @@ class AccountValidityHandler(object):
# Stop right here if the user doesn't have at least one email address.
# In this case, they will have to ask their server admin to renew their
# account manually.
# We don't need to do a specific check to make sure the account isn't
# deactivated, as a deactivated account isn't supposed to have any
# email address attached to it.
if not addresses:
return
@@ -220,11 +231,19 @@ class AccountValidityHandler(object):
Args:
renewal_token (str): Token sent with the renewal request.
Returns:
bool: Whether the provided token is valid.
"""
user_id = yield self.store.get_user_from_renewal_token(renewal_token)
try:
user_id = yield self.store.get_user_from_renewal_token(renewal_token)
except StoreError:
defer.returnValue(False)
logger.debug("Renewing an account for user %s", user_id)
yield self.renew_account_for_user(user_id)
defer.returnValue(True)
@defer.inlineCallbacks
def renew_account_for_user(self, user_id, expiration_ts=None, email_sent=False):
"""Renews the account attached to a given user by pushing back the
@@ -250,4 +269,28 @@ class AccountValidityHandler(object):
email_sent=email_sent,
)
# Check if renewed users should be reintroduced to the user directory
if self._show_users_in_user_directory:
# Show the user in the directory again by setting them to active
yield self.profile_handler.set_active(UserID.from_string(user_id), True, True)
defer.returnValue(expiration_ts)
@defer.inlineCallbacks
def _mark_expired_users_as_inactive(self):
"""Iterate over expired users. Mark them as inactive in order to hide them from the
user directory.
Returns:
Deferred
"""
# Get expired users
expired_user_ids = yield self.store.get_expired_users()
expired_users = [
UserID.from_string(user_id)
for user_id in expired_user_ids
]
# Mark each one as non-active
for user in expired_users:
yield self.profile_handler.set_active(user, False, True)

View File

@@ -420,7 +420,7 @@ class AuthHandler(BaseHandler):
# TODO: get this from the homeserver rather than creating a new one for
# each request
try:
client = self.hs.get_simple_http_client()
client = self.hs.get_proxied_http_client()
resp_body = yield client.post_urlencoded_get_json(
self.hs.config.recaptcha_siteverify_api,
args={

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2017, 2018 New Vector Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -33,6 +34,7 @@ class DeactivateAccountHandler(BaseHandler):
self._device_handler = hs.get_device_handler()
self._room_member_handler = hs.get_room_member_handler()
self._identity_handler = hs.get_handlers().identity_handler
self._profile_handler = hs.get_profile_handler()
self.user_directory_handler = hs.get_user_directory_handler()
# Flag that indicates whether the process to part users from rooms is running
@@ -42,6 +44,8 @@ class DeactivateAccountHandler(BaseHandler):
# it left off (if it has work left to do).
hs.get_reactor().callWhenRunning(self._start_user_parting)
self._account_validity_enabled = hs.config.account_validity.enabled
@defer.inlineCallbacks
def deactivate_account(self, user_id, erase_data, id_server=None):
"""Deactivate a user's account
@@ -98,6 +102,9 @@ class DeactivateAccountHandler(BaseHandler):
yield self.store.user_set_password_hash(user_id, None)
user = UserID.from_string(user_id)
yield self._profile_handler.set_active(user, False, False)
# Add the user to a table of users pending deactivation (ie.
# removal from all the rooms they're a member of)
yield self.store.add_user_pending_deactivation(user_id)
@@ -114,8 +121,52 @@ class DeactivateAccountHandler(BaseHandler):
# parts users from rooms (if it isn't already running)
self._start_user_parting()
# Reject all pending invites for the user, so that the user doesn't show up in the
# "invited" section of rooms' members list.
yield self._reject_pending_invites_for_user(user_id)
# Remove all information on the user from the account_validity table.
if self._account_validity_enabled:
yield self.store.delete_account_validity_for_user(user_id)
# Mark the user as deactivated.
yield self.store.set_user_deactivated_status(user_id, True)
defer.returnValue(identity_server_supports_unbinding)
@defer.inlineCallbacks
def _reject_pending_invites_for_user(self, user_id):
"""Reject pending invites addressed to a given user ID.
Args:
user_id (str): The user ID to reject pending invites for.
"""
user = UserID.from_string(user_id)
pending_invites = yield self.store.get_invited_rooms_for_user(user_id)
for room in pending_invites:
try:
yield self._room_member_handler.update_membership(
create_requester(user),
user,
room.room_id,
"leave",
ratelimit=False,
require_consent=False,
)
logger.info(
"Rejected invite for deactivated user %r in room %r",
user_id,
room.room_id,
)
except Exception:
logger.exception(
"Failed to reject invite for user %r in room %r:"
" ignoring and continuing",
user_id,
room.room_id,
)
def _start_user_parting(self):
"""
Start the process that goes through the table of users

View File

@@ -568,6 +568,12 @@ class DeviceListEduUpdater(object):
stream_id = result["stream_id"]
devices = result["devices"]
for device in devices:
logger.debug(
"Handling resync update %r/%r, ID: %r",
user_id, device["device_id"], stream_id,
)
# If the remote server has more than ~1000 devices for this user
# we assume that something is going horribly wrong (e.g. a bot
# that logs in and creates a new device every time it tries to

View File

@@ -1363,8 +1363,12 @@ class FederationHandler(BaseHandler):
if self.hs.config.block_non_admin_invites:
raise SynapseError(403, "This server does not accept room invites")
is_published = yield self.store.is_room_published(event.room_id)
if not self.spam_checker.user_may_invite(
event.sender, event.state_key, event.room_id,
event.sender, event.state_key, None,
room_id=event.room_id, new_room=False,
published_room=is_published,
):
raise SynapseError(
403, "This user is not permitted to send invites to this server/user"
@@ -2606,7 +2610,7 @@ class FederationHandler(BaseHandler):
room_version, event_dict, event, context
)
EventValidator().validate_new(event)
EventValidator().validate_new(event, self.config)
# We need to tell the transaction queue to send this out, even
# though the sender isn't a local user.
@@ -2667,7 +2671,7 @@ class FederationHandler(BaseHandler):
)
try:
self.auth.check_from_context(room_version, event, context)
yield self.auth.check_from_context(room_version, event, context)
except AuthError as e:
logger.warn("Denying third party invite %r because %s", event, e)
raise e
@@ -2677,12 +2681,6 @@ class FederationHandler(BaseHandler):
# though the sender isn't a local user.
event.internal_metadata.send_on_behalf_of = get_domain_from_id(event.sender)
# XXX we send the invite here, but send_membership_event also sends it,
# so we end up making two requests. I think this is redundant.
returned_invite = yield self.send_invite(origin, event)
# TODO: Make sure the signatures actually are correct.
event.signatures.update(returned_invite.signatures)
member_handler = self.hs.get_room_member_handler()
yield member_handler.send_membership_event(None, event, context)
@@ -2701,7 +2699,12 @@ class FederationHandler(BaseHandler):
original_invite_id, allow_none=True
)
if original_invite:
display_name = original_invite.content["display_name"]
# If the m.room.third_party_invite event's content is empty, it means the
# invite has been revoked. In this case, we don't have to raise an error here
# because the auth check will fail on the invite (because it's not able to
# fetch public keys from the m.room.third_party_invite event's content, which
# is empty).
display_name = original_invite.content.get("display_name")
event_dict["content"]["third_party_invite"]["display_name"] = display_name
else:
logger.info(
@@ -2717,7 +2720,7 @@ class FederationHandler(BaseHandler):
event, context = yield self.event_creation_handler.create_new_client_event(
builder=builder,
)
EventValidator().validate_new(event)
EventValidator().validate_new(event, self.config)
defer.returnValue((event, context))
@defer.inlineCallbacks

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd
# Copyright 2017 Vector Creations Ltd
# Copyright 2018 New Vector Ltd
# Copyright 2018, 2019 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,13 +20,18 @@
import logging
from canonicaljson import json
from signedjson.key import decode_verify_key_bytes
from signedjson.sign import verify_signed_json
from unpaddedbase64 import decode_base64
from twisted.internet import defer
from synapse.api.errors import (
AuthError,
CodeMessageException,
Codes,
HttpResponseException,
ProxiedRequestError,
SynapseError,
)
@@ -47,6 +52,8 @@ class IdentityHandler(BaseHandler):
self.trust_any_id_server_just_for_testing_do_not_use = (
hs.config.use_insecure_ssl_client_just_for_testing_do_not_use
)
self.rewrite_identity_server_urls = hs.config.rewrite_identity_server_urls
self._enable_lookup = hs.config.enable_3pid_lookup
def _should_trust_id_server(self, id_server):
if id_server not in self.trusted_id_servers:
@@ -84,7 +91,10 @@ class IdentityHandler(BaseHandler):
'credentials', id_server
)
defer.returnValue(None)
# if we have a rewrite rule set for the identity server,
# apply it now.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
try:
data = yield self.http_client.get_json(
"https://%s%s" % (
@@ -120,10 +130,18 @@ class IdentityHandler(BaseHandler):
else:
raise SynapseError(400, "No client_secret in creds")
# if we have a rewrite rule set for the identity server,
# apply it now, but only for sending the request (not
# storing in the database).
if id_server in self.rewrite_identity_server_urls:
id_server_host = self.rewrite_identity_server_urls[id_server]
else:
id_server_host = id_server
try:
data = yield self.http_client.post_urlencoded_get_json(
"https://%s%s" % (
id_server, "/_matrix/identity/api/v1/3pid/bind"
id_server_host, "/_matrix/identity/api/v1/3pid/bind"
),
{
'sid': creds['sid'],
@@ -221,6 +239,16 @@ class IdentityHandler(BaseHandler):
b"Authorization": auth_headers,
}
# if we have a rewrite rule set for the identity server,
# apply it now.
#
# Note that destination_is has to be the real id_server, not
# the server we connect to.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
url = "https://%s/_matrix/identity/api/v1/3pid/unbind" % (id_server,)
try:
yield self.http_client.post_json_get_json(
url,
@@ -267,6 +295,11 @@ class IdentityHandler(BaseHandler):
'send_attempt': send_attempt,
}
# if we have a rewrite rule set for the identity server,
# apply it now.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
if next_link:
params.update({'next_link': next_link})
@@ -301,7 +334,10 @@ class IdentityHandler(BaseHandler):
'send_attempt': send_attempt,
}
params.update(kwargs)
# if we have a rewrite rule set for the identity server,
# apply it now.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
try:
data = yield self.http_client.post_json_get_json(
"https://%s%s" % (
@@ -314,3 +350,125 @@ class IdentityHandler(BaseHandler):
except HttpResponseException as e:
logger.info("Proxied requestToken failed: %r", e)
raise e.to_synapse_error()
@defer.inlineCallbacks
def lookup_3pid(self, id_server, medium, address):
"""Looks up a 3pid in the passed identity server.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
medium (str): The type of the third party identifier (e.g. "email").
address (str): The third party identifier (e.g. "foo@example.com").
Returns:
Deferred[dict]: The result of the lookup. See
https://matrix.org/docs/spec/identity_service/r0.1.0.html#association-lookup
for details
"""
if not self._should_trust_id_server(id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server,
Codes.SERVER_NOT_TRUSTED
)
if not self._enable_lookup:
raise AuthError(
403, "Looking up third-party identifiers is denied from this server",
)
target = self.rewrite_identity_server_urls.get(id_server, id_server)
try:
data = yield self.http_client.get_json(
"https://%s/_matrix/identity/api/v1/lookup" % (target,),
{
"medium": medium,
"address": address,
}
)
if "mxid" in data:
if "signatures" not in data:
raise AuthError(401, "No signatures on 3pid binding")
yield self._verify_any_signature(data, id_server)
except HttpResponseException as e:
logger.info("Proxied lookup failed: %r", e)
raise e.to_synapse_error()
except IOError as e:
logger.info("Failed to contact %r: %s", id_server, e)
raise ProxiedRequestError(503, "Failed to contact identity server")
defer.returnValue(data)
@defer.inlineCallbacks
def bulk_lookup_3pid(self, id_server, threepids):
"""Looks up given 3pids in the passed identity server.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
threepids ([[str, str]]): The third party identifiers to lookup, as
a list of 2-string sized lists ([medium, address]).
Returns:
Deferred[dict]: The result of the lookup. See
https://matrix.org/docs/spec/identity_service/r0.1.0.html#association-lookup
for details
"""
if not self._should_trust_id_server(id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server,
Codes.SERVER_NOT_TRUSTED
)
if not self._enable_lookup:
raise AuthError(
403, "Looking up third-party identifiers is denied from this server",
)
target = self.rewrite_identity_server_urls.get(id_server, id_server)
try:
data = yield self.http_client.post_json_get_json(
"https://%s/_matrix/identity/api/v1/bulk_lookup" % (target,),
{
"threepids": threepids,
}
)
except HttpResponseException as e:
logger.info("Proxied lookup failed: %r", e)
raise e.to_synapse_error()
except IOError as e:
logger.info("Failed to contact %r: %s", id_server, e)
raise ProxiedRequestError(503, "Failed to contact identity server")
defer.returnValue(data)
@defer.inlineCallbacks
def _verify_any_signature(self, data, server_hostname):
if server_hostname not in data["signatures"]:
raise AuthError(401, "No signature from server %s" % (server_hostname,))
for key_name, signature in data["signatures"][server_hostname].items():
target = self.rewrite_identity_server_urls.get(
server_hostname, server_hostname,
)
key_data = yield self.http_client.get_json(
"https://%s/_matrix/identity/api/v1/pubkey/%s" %
(target, key_name,),
)
if "public_key" not in key_data:
raise AuthError(401, "No public key named %s from %s" %
(key_name, server_hostname,))
verify_signed_json(
data,
server_hostname,
decode_verify_key_bytes(key_name, decode_base64(key_data["public_key"]))
)
return
raise AuthError(401, "No signature from server %s" % (server_hostname,))

View File

@@ -130,7 +130,7 @@ class MessageHandler(object):
raise NotFoundError("Can't find event for token %s" % (at_token, ))
visible_events = yield filter_events_for_client(
self.store, user_id, last_events,
self.store, user_id, last_events, apply_retention_policies=False
)
event = last_events[0]
@@ -372,7 +372,7 @@ class EventCreationHandler(object):
"You must be in the room to create an alias for it",
)
self.validator.validate_new(event)
self.validator.validate_new(event, self.config)
defer.returnValue((event, context))
@@ -604,7 +604,7 @@ class EventCreationHandler(object):
if requester:
context.app_service = requester.app_service
self.validator.validate_new(event)
self.validator.validate_new(event, self.config)
# If this event is an annotation then we check that that the sender
# can't annotate the same way twice (e.g. stops users from liking an

View File

@@ -15,11 +15,14 @@
# limitations under the License.
import logging
from six import iteritems
from twisted.internet import defer
from twisted.python.failure import Failure
from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import SynapseError
from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.storage.state import StateFilter
from synapse.types import RoomStreamToken
from synapse.util.async_helpers import ReadWriteLock
@@ -79,6 +82,114 @@ class PaginationHandler(object):
self._purges_by_id = {}
self._event_serializer = hs.get_event_client_serializer()
self._retention_default_max_lifetime = hs.config.retention_default_max_lifetime
if hs.config.retention_enabled:
# Run the purge jobs described in the configuration file.
for job in hs.config.retention_purge_jobs:
self.clock.looping_call(
run_as_background_process,
job["interval"],
"purge_history_for_rooms_in_range",
self.purge_history_for_rooms_in_range,
job["shortest_max_lifetime"],
job["longest_max_lifetime"],
)
@defer.inlineCallbacks
def purge_history_for_rooms_in_range(self, min_ms, max_ms):
"""Purge outdated events from rooms within the given retention range.
If a default retention policy is defined in the server's configuration and its
'max_lifetime' is within this range, also targets rooms which don't have a
retention policy.
Args:
min_ms (int|None): Duration in milliseconds that define the lower limit of
the range to handle (exclusive). If None, it means that the range has no
lower limit.
max_ms (int|None): Duration in milliseconds that define the upper limit of
the range to handle (inclusive). If None, it means that the range has no
upper limit.
"""
# We want the storage layer to to include rooms with no retention policy in its
# return value only if a default retention policy is defined in the server's
# configuration and that policy's 'max_lifetime' is either lower (or equal) than
# max_ms or higher than min_ms (or both).
if self._retention_default_max_lifetime is not None:
include_null = True
if min_ms is not None and min_ms >= self._retention_default_max_lifetime:
# The default max_lifetime is lower than (or equal to) min_ms.
include_null = False
if max_ms is not None and max_ms < self._retention_default_max_lifetime:
# The default max_lifetime is higher than max_ms.
include_null = False
else:
include_null = False
rooms = yield self.store.get_rooms_for_retention_period_in_range(
min_ms, max_ms, include_null
)
for room_id, retention_policy in iteritems(rooms):
if room_id in self._purges_in_progress_by_room:
logger.warning(
"[purge] not purging room %s as there's an ongoing purge running"
" for this room",
room_id,
)
continue
max_lifetime = retention_policy["max_lifetime"]
if max_lifetime is None:
# If max_lifetime is None, it means that include_null equals True,
# therefore we can safely assume that there is a default policy defined
# in the server's configuration.
max_lifetime = self._retention_default_max_lifetime
# Figure out what token we should start purging at.
ts = self.clock.time_msec() - max_lifetime
stream_ordering = (
yield self.store.find_first_stream_ordering_after_ts(ts)
)
r = (
yield self.store.get_room_event_after_stream_ordering(
room_id, stream_ordering,
)
)
if not r:
logger.warning(
"[purge] purging events not possible: No event found "
"(ts %i => stream_ordering %i)",
ts, stream_ordering,
)
continue
(stream, topo, _event_id) = r
token = "t%d-%d" % (topo, stream)
purge_id = random_string(16)
self._purges_by_id[purge_id] = PurgeStatus()
logger.info(
"Starting purging events in room %s (purge_id %s)" % (room_id, purge_id)
)
# We want to purge everything, including local events, and to run the purge in
# the background so that it's not blocking any other operation apart from
# other purges in the same room.
run_as_background_process(
"_purge_history",
self._purge_history,
purge_id, room_id, token, True,
)
def start_purge_history(self, room_id, token,
delete_local_events=False):
"""Start off a history purge on a room.

View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
# Copyright 2019 New Vector Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import re
from synapse.api.errors import Codes, PasswordRefusedError
logger = logging.getLogger(__name__)
class PasswordPolicyHandler(object):
def __init__(self, hs):
self.policy = hs.config.password_policy
self.enabled = hs.config.password_policy_enabled
# Regexps for the spec'd policy parameters.
self.regexp_digit = re.compile("[0-9]")
self.regexp_symbol = re.compile("[^a-zA-Z0-9]")
self.regexp_uppercase = re.compile("[A-Z]")
self.regexp_lowercase = re.compile("[a-z]")
def validate_password(self, password):
"""Checks whether a given password complies with the server's policy.
Args:
password (str): The password to check against the server's policy.
Raises:
PasswordRefusedError: The password doesn't comply with the server's policy.
"""
if not self.enabled:
return
minimum_accepted_length = self.policy.get("minimum_length", 0)
if len(password) < minimum_accepted_length:
raise PasswordRefusedError(
msg=(
"The password must be at least %d characters long"
% minimum_accepted_length
),
errcode=Codes.PASSWORD_TOO_SHORT,
)
if (
self.policy.get("require_digit", False) and
self.regexp_digit.search(password) is None
):
raise PasswordRefusedError(
msg="The password must include at least one digit",
errcode=Codes.PASSWORD_NO_DIGIT,
)
if (
self.policy.get("require_symbol", False) and
self.regexp_symbol.search(password) is None
):
raise PasswordRefusedError(
msg="The password must include at least one symbol",
errcode=Codes.PASSWORD_NO_SYMBOL,
)
if (
self.policy.get("require_uppercase", False) and
self.regexp_uppercase.search(password) is None
):
raise PasswordRefusedError(
msg="The password must include at least one uppercase letter",
errcode=Codes.PASSWORD_NO_UPPERCASE,
)
if (
self.policy.get("require_lowercase", False) and
self.regexp_lowercase.search(password) is None
):
raise PasswordRefusedError(
msg="The password must include at least one lowercase letter",
errcode=Codes.PASSWORD_NO_LOWERCASE,
)

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2018 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +16,11 @@
import logging
from twisted.internet import defer
from six.moves import range
from signedjson.sign import sign_json
from twisted.internet import defer, reactor
from synapse.api.errors import (
AuthError,
@@ -26,6 +31,7 @@ from synapse.api.errors import (
)
from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.types import UserID, get_domain_from_id
from synapse.util.logcontext import run_in_background
from ._base import BaseHandler
@@ -43,6 +49,8 @@ class BaseProfileHandler(BaseHandler):
subclass MasterProfileHandler
"""
PROFILE_REPLICATE_INTERVAL = 2 * 60 * 1000
def __init__(self, hs):
super(BaseProfileHandler, self).__init__(hs)
@@ -53,6 +61,87 @@ class BaseProfileHandler(BaseHandler):
self.user_directory_handler = hs.get_user_directory_handler()
self.http_client = hs.get_simple_http_client()
self.max_avatar_size = hs.config.max_avatar_size
self.allowed_avatar_mimetypes = hs.config.allowed_avatar_mimetypes
if hs.config.worker_app is None:
self.clock.looping_call(
self._start_update_remote_profile_cache, self.PROFILE_UPDATE_MS,
)
if len(self.hs.config.replicate_user_profiles_to) > 0:
reactor.callWhenRunning(self._assign_profile_replication_batches)
reactor.callWhenRunning(self._replicate_profiles)
# Add a looping call to replicate_profiles: this handles retries
# if the replication is unsuccessful when the user updated their
# profile.
self.clock.looping_call(
self._replicate_profiles, self.PROFILE_REPLICATE_INTERVAL
)
@defer.inlineCallbacks
def _assign_profile_replication_batches(self):
"""If no profile replication has been done yet, allocate replication batch
numbers to each profile to start the replication process.
"""
logger.info("Assigning profile batch numbers...")
total = 0
while True:
assigned = yield self.store.assign_profile_batch()
total += assigned
if assigned == 0:
break
logger.info("Assigned %d profile batch numbers", total)
@defer.inlineCallbacks
def _replicate_profiles(self):
"""If any profile data has been updated and not pushed to the replication targets,
replicate it.
"""
host_batches = yield self.store.get_replication_hosts()
latest_batch = yield self.store.get_latest_profile_replication_batch_number()
if latest_batch is None:
latest_batch = -1
for repl_host in self.hs.config.replicate_user_profiles_to:
if repl_host not in host_batches:
host_batches[repl_host] = -1
try:
for i in range(host_batches[repl_host] + 1, latest_batch + 1):
yield self._replicate_host_profile_batch(repl_host, i)
except Exception:
logger.exception(
"Exception while replicating to %s: aborting for now", repl_host,
)
@defer.inlineCallbacks
def _replicate_host_profile_batch(self, host, batchnum):
logger.info("Replicating profile batch %d to %s", batchnum, host)
batch_rows = yield self.store.get_profile_batch(batchnum)
batch = {
UserID(r["user_id"], self.hs.hostname).to_string(): ({
"display_name": r["displayname"],
"avatar_url": r["avatar_url"],
} if r["active"] else None) for r in batch_rows
}
url = "https://%s/_matrix/identity/api/v1/replicate_profiles" % (host,)
body = {
"batchnum": batchnum,
"batch": batch,
"origin_server": self.hs.hostname,
}
signed_body = sign_json(body, self.hs.hostname, self.hs.config.signing_key[0])
try:
yield self.http_client.post_json_get_json(url, signed_body)
yield self.store.update_replication_batch_for_host(host, batchnum)
logger.info("Sucessfully replicated profile batch %d to %s", batchnum, host)
except Exception:
# This will get retried when the looping call next comes around
logger.exception("Failed to replicate profile batch %d to %s", batchnum, host)
raise
@defer.inlineCallbacks
def get_profile(self, user_id):
target_user = UserID.from_string(user_id)
@@ -162,9 +251,14 @@ class BaseProfileHandler(BaseHandler):
if not self.hs.is_mine(target_user):
raise SynapseError(400, "User is not hosted on this Home Server")
if not by_admin and target_user != requester.user:
if not by_admin and requester and target_user != requester.user:
raise AuthError(400, "Cannot set another user's displayname")
if not by_admin and self.hs.config.disable_set_displayname:
profile = yield self.store.get_profileinfo(target_user.localpart)
if profile.display_name:
raise SynapseError(400, "Changing displayname is disabled on this server")
if len(new_displayname) > MAX_DISPLAYNAME_LEN:
raise SynapseError(
400, "Displayname is too long (max %i)" % (MAX_DISPLAYNAME_LEN, ),
@@ -173,8 +267,14 @@ class BaseProfileHandler(BaseHandler):
if new_displayname == '':
new_displayname = None
if len(self.hs.config.replicate_user_profiles_to) > 0:
cur_batchnum = yield self.store.get_latest_profile_replication_batch_number()
new_batchnum = 0 if cur_batchnum is None else cur_batchnum + 1
else:
new_batchnum = None
yield self.store.set_profile_displayname(
target_user.localpart, new_displayname
target_user.localpart, new_displayname, new_batchnum
)
if self.hs.config.user_directory_search_all_users:
@@ -183,7 +283,37 @@ class BaseProfileHandler(BaseHandler):
target_user.to_string(), profile
)
yield self._update_join_states(requester, target_user)
if requester:
yield self._update_join_states(requester, target_user)
# start a profile replication push
run_in_background(self._replicate_profiles)
@defer.inlineCallbacks
def set_active(self, target_user, active, hide):
"""
Sets the 'active' flag on a user profile. If set to false, the user
account is considered deactivated or hidden.
If 'hide' is true, then we interpret active=False as a request to try to
hide the user rather than deactivating it. This means withholding the
profile from replication (and mark it as inactive) rather than clearing
the profile from the HS DB. Note that unlike set_displayname and
set_avatar_url, this does *not* perform authorization checks! This is
because the only place it's used currently is in account deactivation
where we've already done these checks anyway.
"""
if len(self.hs.config.replicate_user_profiles_to) > 0:
cur_batchnum = yield self.store.get_latest_profile_replication_batch_number()
new_batchnum = 0 if cur_batchnum is None else cur_batchnum + 1
else:
new_batchnum = None
yield self.store.set_profile_active(
target_user.localpart, active, hide, new_batchnum
)
# start a profile replication push
run_in_background(self._replicate_profiles)
@defer.inlineCallbacks
def get_avatar_url(self, target_user):
@@ -225,13 +355,53 @@ class BaseProfileHandler(BaseHandler):
if not by_admin and target_user != requester.user:
raise AuthError(400, "Cannot set another user's avatar_url")
if not by_admin and self.hs.config.disable_set_avatar_url:
profile = yield self.store.get_profileinfo(target_user.localpart)
if profile.avatar_url:
raise SynapseError(400, "Changing avatar url is disabled on this server")
if len(self.hs.config.replicate_user_profiles_to) > 0:
cur_batchnum = yield self.store.get_latest_profile_replication_batch_number()
new_batchnum = 0 if cur_batchnum is None else cur_batchnum + 1
else:
new_batchnum = None
if len(new_avatar_url) > MAX_AVATAR_URL_LEN:
raise SynapseError(
400, "Avatar URL is too long (max %i)" % (MAX_AVATAR_URL_LEN, ),
)
# Enforce a max avatar size if one is defined
if self.max_avatar_size or self.allowed_avatar_mimetypes:
media_id = self._validate_and_parse_media_id_from_avatar_url(new_avatar_url)
# Check that this media exists locally
media_info = yield self.store.get_local_media(media_id)
if not media_info:
raise SynapseError(
400, "Unknown media id supplied", errcode=Codes.NOT_FOUND
)
# Ensure avatar does not exceed max allowed avatar size
media_size = media_info["media_length"]
if self.max_avatar_size and media_size > self.max_avatar_size:
raise SynapseError(
400, "Avatars must be less than %s bytes in size" %
(self.max_avatar_size,), errcode=Codes.TOO_LARGE,
)
# Ensure the avatar's file type is allowed
if (
self.allowed_avatar_mimetypes
and media_info["media_type"] not in self.allowed_avatar_mimetypes
):
raise SynapseError(
400, "Avatar file type '%s' not allowed" %
media_info["media_type"],
)
yield self.store.set_profile_avatar_url(
target_user.localpart, new_avatar_url
target_user.localpart, new_avatar_url, new_batchnum,
)
if self.hs.config.user_directory_search_all_users:
@@ -242,6 +412,23 @@ class BaseProfileHandler(BaseHandler):
yield self._update_join_states(requester, target_user)
# start a profile replication push
run_in_background(self._replicate_profiles)
def _validate_and_parse_media_id_from_avatar_url(self, mxc):
"""Validate and parse a provided avatar url and return the local media id
Args:
mxc (str): A mxc URL
Returns:
str: The ID of the media
"""
avatar_pieces = mxc.split("/")
if len(avatar_pieces) != 4 or avatar_pieces[0] != "mxc:":
raise SynapseError(400, "Invalid avatar URL '%s' supplied" % mxc)
return avatar_pieces[-1]
@defer.inlineCallbacks
def on_profile_query(self, args):
user = UserID.from_string(args["user_id"])
@@ -300,7 +487,7 @@ class BaseProfileHandler(BaseHandler):
@defer.inlineCallbacks
def check_profile_query_allowed(self, target_user, requester=None):
"""Checks whether a profile query is allowed. If the
'require_auth_for_profile_requests' config flag is set to True and a
'limit_profile_requests_to_known_users' config flag is set to True and a
'requester' is provided, the query is only allowed if the two users
share a room.
@@ -318,7 +505,11 @@ class BaseProfileHandler(BaseHandler):
# be None when this function is called outside of a profile query, e.g.
# when building a membership event. In this case, we must allow the
# lookup.
if not self.hs.config.require_auth_for_profile_requests or not requester:
if not self.hs.config.limit_profile_requests_to_known_users or not requester:
return
# Always allow the user to query their own profile.
if target_user.to_string() == requester.to_string():
return
try:

View File

@@ -61,6 +61,7 @@ class RegistrationHandler(BaseHandler):
self.profile_handler = hs.get_profile_handler()
self.user_directory_handler = hs.get_user_directory_handler()
self.captcha_client = CaptchaServerHttpClient(hs)
self.http_client = hs.get_simple_http_client()
self.identity_handler = self.hs.get_handlers().identity_handler
self.ratelimiter = hs.get_registration_ratelimiter()
@@ -73,6 +74,8 @@ class RegistrationHandler(BaseHandler):
)
self._server_notices_mxid = hs.config.server_notices_mxid
self._show_in_user_directory = self.hs.config.show_users_in_user_directory
if hs.config.worker_app:
self._register_client = ReplicationRegisterServlet.make_client(hs)
self._register_device_client = (
@@ -234,6 +237,11 @@ class RegistrationHandler(BaseHandler):
address=address,
)
if default_display_name:
yield self.profile_handler.set_displayname(
user, None, default_display_name, by_admin=True,
)
if self.hs.config.user_directory_search_all_users:
profile = yield self.store.get_profileinfo(localpart)
yield self.user_directory_handler.handle_local_profile_change(
@@ -263,6 +271,11 @@ class RegistrationHandler(BaseHandler):
create_profile_with_displayname=default_display_name,
address=address,
)
yield self.profile_handler.set_displayname(
user, None, default_display_name, by_admin=True,
)
except SynapseError:
# if user id is taken, just generate another
user = None
@@ -287,6 +300,14 @@ class RegistrationHandler(BaseHandler):
user_id, threepid_dict, None, False,
)
# Prevent the new user from showing up in the user directory if the server
# mandates it.
if not self._show_in_user_directory:
yield self.store.add_account_data_for_user(
user_id, "im.vector.hide_profile", {'hide_profile': True},
)
yield self.profile_handler.set_active(user, False, True)
defer.returnValue((user_id, token))
@defer.inlineCallbacks
@@ -356,7 +377,9 @@ class RegistrationHandler(BaseHandler):
yield self._auto_join_rooms(user_id)
@defer.inlineCallbacks
def appservice_register(self, user_localpart, as_token):
def appservice_register(self, user_localpart, as_token, password, display_name):
# FIXME: this should be factored out and merged with normal register()
user = UserID(user_localpart, self.hs.hostname)
user_id = user.to_string()
service = self.store.get_app_service_by_token(as_token)
@@ -374,12 +397,29 @@ class RegistrationHandler(BaseHandler):
user_id, allowed_appservice=service
)
password_hash = ""
if password:
password_hash = yield self.auth_handler().hash(password)
display_name = display_name or user.localpart
yield self.register_with_store(
user_id=user_id,
password_hash="",
password_hash=password_hash,
appservice_id=service_id,
create_profile_with_displayname=user.localpart,
create_profile_with_displayname=display_name,
)
yield self.profile_handler.set_displayname(
user, None, display_name, by_admin=True,
)
if self.hs.config.user_directory_search_all_users:
profile = yield self.store.get_profileinfo(user_localpart)
yield self.user_directory_handler.handle_local_profile_change(
user_id, profile
)
defer.returnValue(user_id)
@defer.inlineCallbacks
@@ -405,6 +445,39 @@ class RegistrationHandler(BaseHandler):
else:
logger.info("Valid captcha entered from %s", ip)
@defer.inlineCallbacks
def register_saml2(self, localpart):
"""
Registers email_id as SAML2 Based Auth.
"""
if types.contains_invalid_mxid_characters(localpart):
raise SynapseError(
400,
"User ID can only contain characters a-z, 0-9, or '=_-./'",
)
yield self.auth.check_auth_blocking()
user = UserID(localpart, self.hs.hostname)
user_id = user.to_string()
yield self.check_user_id_not_appservice_exclusive(user_id)
token = self.macaroon_gen.generate_access_token(user_id)
try:
yield self.register_with_store(
user_id=user_id,
token=token,
password_hash=None,
create_profile_with_displayname=user.localpart,
)
yield self.profile_handler.set_displayname(
user, None, user.localpart, by_admin=True,
)
except Exception as e:
yield self.store.add_access_token_to_user(user_id, token)
# Ignore Registration errors
logger.exception(e)
defer.returnValue((user_id, token))
@defer.inlineCallbacks
def register_email(self, threepidCreds):
"""
@@ -427,7 +500,9 @@ class RegistrationHandler(BaseHandler):
logger.info("got threepid with medium '%s' and address '%s'",
threepid['medium'], threepid['address'])
if not check_3pid_allowed(self.hs, threepid['medium'], threepid['address']):
if not (
yield check_3pid_allowed(self.hs, threepid['medium'], threepid['address'])
):
raise RegistrationError(
403, "Third party identifier is not allowed"
)
@@ -468,6 +543,39 @@ class RegistrationHandler(BaseHandler):
errcode=Codes.EXCLUSIVE
)
@defer.inlineCallbacks
def shadow_register(self, localpart, display_name, auth_result, params):
"""Invokes the current registration on another server, using
shared secret registration, passing in any auth_results from
other registration UI auth flows (e.g. validated 3pids)
Useful for setting up shadow/backup accounts on a parallel deployment.
"""
# TODO: retries
shadow_hs_url = self.hs.config.shadow_server.get("hs_url")
as_token = self.hs.config.shadow_server.get("as_token")
yield self.http_client.post_json_get_json(
"%s/_matrix/client/r0/register?access_token=%s" % (
shadow_hs_url, as_token,
),
{
# XXX: auth_result is an unspecified extension for shadow registration
'auth_result': auth_result,
# XXX: another unspecified extension for shadow registration to ensure
# that the displayname is correctly set by the masters erver
'display_name': display_name,
'username': localpart,
'password': params.get("password"),
'bind_email': params.get("bind_email"),
'bind_msisdn': params.get("bind_msisdn"),
'device_id': params.get("device_id"),
'initial_device_display_name': params.get("initial_device_display_name"),
'inhibit_login': False,
'access_token': as_token,
}
)
@defer.inlineCallbacks
def _generate_user_id(self, reseed=False):
if reseed or self._next_generated_user_id is None:
@@ -556,18 +664,16 @@ class RegistrationHandler(BaseHandler):
user_id=user_id,
token=token,
password_hash=password_hash,
create_profile_with_displayname=user.localpart,
create_profile_with_displayname=displayname or user.localpart,
)
if displayname is not None:
yield self.profile_handler.set_displayname(
user, None, displayname or user.localpart, by_admin=True,
)
else:
yield self._auth_handler.delete_access_tokens_for_user(user_id)
yield self.store.add_access_token_to_user(user_id=user_id, token=token)
if displayname is not None:
logger.info("setting user display name: %s -> %s", user_id, displayname)
yield self.profile_handler.set_displayname(
user, requester, displayname, by_admin=True,
)
defer.returnValue((user_id, token))
@defer.inlineCallbacks

View File

@@ -49,12 +49,14 @@ class RoomCreationHandler(BaseHandler):
"history_visibility": "shared",
"original_invitees_have_ops": False,
"guest_can_join": True,
"encryption_alg": "m.megolm.v1.aes-sha2",
},
RoomCreationPreset.TRUSTED_PRIVATE_CHAT: {
"join_rules": JoinRules.INVITE,
"history_visibility": "shared",
"original_invitees_have_ops": True,
"guest_can_join": True,
"encryption_alg": "m.megolm.v1.aes-sha2",
},
RoomCreationPreset.PUBLIC_CHAT: {
"join_rules": JoinRules.PUBLIC,
@@ -75,6 +77,10 @@ class RoomCreationHandler(BaseHandler):
# linearizer to stop two upgrades happening at once
self._upgrade_linearizer = Linearizer("room_upgrade_linearizer")
self._server_notices_mxid = hs.config.server_notices_mxid
self.third_party_event_rules = hs.get_third_party_event_rules()
@defer.inlineCallbacks
def upgrade_room(self, requester, old_room_id, new_version):
"""Replace a room with a new room with a different version
@@ -248,7 +254,22 @@ class RoomCreationHandler(BaseHandler):
"""
user_id = requester.user.to_string()
if not self.spam_checker.user_may_create_room(user_id):
if (self._server_notices_mxid is not None and
requester.user.to_string() == self._server_notices_mxid):
# allow the server notices mxid to create rooms
is_requester_admin = True
else:
is_requester_admin = yield self.auth.is_server_admin(
requester.user,
)
if not is_requester_admin and not self.spam_checker.user_may_create_room(
user_id,
invite_list=[],
third_party_invite_list=[],
cloning=True,
):
raise SynapseError(403, "You are not permitted to create rooms")
creation_content = {
@@ -470,7 +491,32 @@ class RoomCreationHandler(BaseHandler):
yield self.auth.check_auth_blocking(user_id)
if not self.spam_checker.user_may_create_room(user_id):
if (self._server_notices_mxid is not None and
requester.user.to_string() == self._server_notices_mxid):
# allow the server notices mxid to create rooms
is_requester_admin = True
else:
is_requester_admin = yield self.auth.is_server_admin(
requester.user,
)
# Check whether the third party rules allows/changes the room create
# request.
yield self.third_party_event_rules.on_create_room(
requester,
config,
is_requester_admin=is_requester_admin,
)
invite_list = config.get("invite", [])
invite_3pid_list = config.get("invite_3pid", [])
if not is_requester_admin and not self.spam_checker.user_may_create_room(
user_id,
invite_list=invite_list,
third_party_invite_list=invite_3pid_list,
cloning=False,
):
raise SynapseError(403, "You are not permitted to create rooms")
if ratelimit:
@@ -517,7 +563,6 @@ class RoomCreationHandler(BaseHandler):
else:
room_alias = None
invite_list = config.get("invite", [])
for i in invite_list:
try:
UserID.from_string(i)
@@ -528,8 +573,6 @@ class RoomCreationHandler(BaseHandler):
requester,
)
invite_3pid_list = config.get("invite_3pid", [])
visibility = config.get("visibility", None)
is_public = visibility == "public"
@@ -615,6 +658,7 @@ class RoomCreationHandler(BaseHandler):
"invite",
ratelimit=False,
content=content,
new_room=True,
)
for invite_3pid in invite_3pid_list:
@@ -629,6 +673,7 @@ class RoomCreationHandler(BaseHandler):
id_server,
requester,
txn_id=None,
new_room=True,
)
result = {"room_id": room_id}
@@ -699,6 +744,7 @@ class RoomCreationHandler(BaseHandler):
"join",
ratelimit=False,
content=creator_join_profile,
new_room=True,
)
# We treat the power levels override specially as this needs to be one
@@ -774,6 +820,15 @@ class RoomCreationHandler(BaseHandler):
content=content,
)
if "encryption_alg" in config:
yield send(
etype=EventTypes.Encryption,
state_key="",
content={
'algorithm': config["encryption_alg"],
}
)
@defer.inlineCallbacks
def _generate_room_id(self, creator_id, is_public):
# autogen room IDs and try to create it. We may clash, so just

View File

@@ -20,22 +20,17 @@ import logging
from six.moves import http_client
from signedjson.key import decode_verify_key_bytes
from signedjson.sign import verify_signed_json
from unpaddedbase64 import decode_base64
from twisted.internet import defer
import synapse.server
import synapse.types
from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import AuthError, Codes, SynapseError
from synapse.api.errors import AuthError, Codes, ProxiedRequestError, SynapseError
from synapse.api.ratelimiting import Ratelimiter
from synapse.types import RoomID, UserID
from synapse.util.async_helpers import Linearizer
from synapse.util.distributor import user_joined_room, user_left_room
from ._base import BaseHandler
logger = logging.getLogger(__name__)
id_server_scheme = "https://"
@@ -67,19 +62,18 @@ class RoomMemberHandler(object):
self.registration_handler = hs.get_registration_handler()
self.profile_handler = hs.get_profile_handler()
self.event_creation_handler = hs.get_event_creation_handler()
self.identity_handler = hs.get_handlers().identity_handler
self.member_linearizer = Linearizer(name="member")
self.clock = hs.get_clock()
self.spam_checker = hs.get_spam_checker()
self.third_party_event_rules = hs.get_third_party_event_rules()
self._server_notices_mxid = self.config.server_notices_mxid
self.rewrite_identity_server_urls = self.config.rewrite_identity_server_urls
self._enable_lookup = hs.config.enable_3pid_lookup
self.allow_per_room_profiles = self.config.allow_per_room_profiles
# This is only used to get at ratelimit function, and
# maybe_kick_guest_users. It's fine there are multiple of these as
# it doesn't store state.
self.base_handler = BaseHandler(hs)
self.ratelimiter = Ratelimiter()
@abc.abstractmethod
def _remote_join(self, requester, remote_room_hosts, room_id, user, content):
@@ -317,8 +311,31 @@ class RoomMemberHandler(object):
third_party_signed=None,
ratelimit=True,
content=None,
new_room=False,
require_consent=True,
):
"""Update a users membership in a room
Args:
requester (Requester)
target (UserID)
room_id (str)
action (str): The "action" the requester is performing against the
target. One of join/leave/kick/ban/invite/unban.
txn_id (str|None): The transaction ID associated with the request,
or None not provided.
remote_room_hosts (list[str]|None): List of remote servers to try
and join via if server isn't already in the room.
third_party_signed (dict|None): The signed object for third party
invites.
ratelimit (bool): Whether to apply ratelimiting to this request.
content (dict|None): Fields to include in the new events content.
new_room (bool): Whether these membership changes are happening
as part of a room creation (e.g. initial joins and invites)
Returns:
Deferred[FrozenEvent]
"""
key = (room_id,)
with (yield self.member_linearizer.queue(key)):
@@ -332,6 +349,7 @@ class RoomMemberHandler(object):
third_party_signed=third_party_signed,
ratelimit=ratelimit,
content=content,
new_room=new_room,
require_consent=require_consent,
)
@@ -349,6 +367,7 @@ class RoomMemberHandler(object):
third_party_signed=None,
ratelimit=True,
content=None,
new_room=False,
require_consent=True,
):
content_specified = bool(content)
@@ -416,8 +435,14 @@ class RoomMemberHandler(object):
)
block_invite = True
is_published = yield self.store.is_room_published(room_id)
if not self.spam_checker.user_may_invite(
requester.user.to_string(), target.to_string(), room_id,
requester.user.to_string(), target.to_string(),
third_party_invite=None,
room_id=room_id,
new_room=new_room,
published_room=is_published,
):
logger.info("Blocking invite due to spam checker")
block_invite = True
@@ -496,8 +521,29 @@ class RoomMemberHandler(object):
# so don't really fit into the general auth process.
raise AuthError(403, "Guest access not allowed")
if (self._server_notices_mxid is not None and
requester.user.to_string() == self._server_notices_mxid):
# allow the server notices mxid to join rooms
is_requester_admin = True
else:
is_requester_admin = yield self.auth.is_server_admin(
requester.user,
)
inviter = yield self._get_inviter(target.to_string(), room_id)
if not is_requester_admin:
# We assume that if the spam checker allowed the user to create
# a room then they're allowed to join it.
if not new_room and not self.spam_checker.user_may_join_room(
target.to_string(), room_id,
is_invited=inviter is not None,
):
raise SynapseError(
403, "Not allowed to join this room",
)
if not is_host_in_room:
inviter = yield self._get_inviter(target.to_string(), room_id)
if inviter and not self.hs.is_mine(inviter):
remote_room_hosts.append(inviter.domain)
@@ -707,7 +753,8 @@ class RoomMemberHandler(object):
address,
id_server,
requester,
txn_id
txn_id,
new_room=False,
):
if self.config.block_non_admin_invites:
is_requester_admin = yield self.auth.is_server_admin(
@@ -721,12 +768,43 @@ class RoomMemberHandler(object):
# We need to rate limit *before* we send out any 3PID invites, so we
# can't just rely on the standard ratelimiting of events.
yield self.base_handler.ratelimit(requester)
self.ratelimiter.ratelimit(
requester.user.to_string(), time_now_s=self.hs.clock.time(),
rate_hz=self.hs.config.rc_third_party_invite.per_second,
burst_count=self.hs.config.rc_third_party_invite.burst_count,
update=True,
)
can_invite = yield self.third_party_event_rules.check_threepid_can_be_invited(
medium, address, room_id,
)
if not can_invite:
raise SynapseError(
403, "This third-party identifier can not be invited in this room",
Codes.FORBIDDEN,
)
invitee = yield self._lookup_3pid(
id_server, medium, address
)
is_published = yield self.store.is_room_published(room_id)
if not self.spam_checker.user_may_invite(
requester.user.to_string(), invitee,
third_party_invite={
"medium": medium,
"address": address,
},
room_id=room_id,
new_room=new_room,
published_room=is_published,
):
logger.info("Blocking invite due to spam checker")
raise SynapseError(
403, "Invites have been disabled on this server",
)
if invitee:
yield self.update_membership(
requester,
@@ -746,6 +824,20 @@ class RoomMemberHandler(object):
txn_id=txn_id
)
def _get_id_server_target(self, id_server):
"""Looks up an id_server's actual http endpoint
Args:
id_server (str): the server name to lookup.
Returns:
the http endpoint to connect to.
"""
if id_server in self.rewrite_identity_server_urls:
return self.rewrite_identity_server_urls[id_server]
return id_server
@defer.inlineCallbacks
def _lookup_3pid(self, id_server, medium, address):
"""Looks up a 3pid in the passed identity server.
@@ -759,48 +851,13 @@ class RoomMemberHandler(object):
Returns:
str: the matrix ID of the 3pid, or None if it is not recognized.
"""
if not self._enable_lookup:
raise SynapseError(
403, "Looking up third-party identifiers is denied from this server",
)
try:
data = yield self.simple_http_client.get_json(
"%s%s/_matrix/identity/api/v1/lookup" % (id_server_scheme, id_server,),
{
"medium": medium,
"address": address,
}
)
if "mxid" in data:
if "signatures" not in data:
raise AuthError(401, "No signatures on 3pid binding")
yield self._verify_any_signature(data, id_server)
defer.returnValue(data["mxid"])
except IOError as e:
data = yield self.identity_handler.lookup_3pid(id_server, medium, address)
defer.returnValue(data.get("mxid"))
except ProxiedRequestError as e:
logger.warn("Error from identity server lookup: %s" % (e,))
defer.returnValue(None)
@defer.inlineCallbacks
def _verify_any_signature(self, data, server_hostname):
if server_hostname not in data["signatures"]:
raise AuthError(401, "No signature from server %s" % (server_hostname,))
for key_name, signature in data["signatures"][server_hostname].items():
key_data = yield self.simple_http_client.get_json(
"%s%s/_matrix/identity/api/v1/pubkey/%s" %
(id_server_scheme, server_hostname, key_name,),
)
if "public_key" not in key_data:
raise AuthError(401, "No public key named %s from %s" %
(key_name, server_hostname,))
verify_signed_json(
data,
server_hostname,
decode_verify_key_bytes(key_name, decode_base64(key_data["public_key"]))
)
return
@defer.inlineCallbacks
def _make_and_store_3pid_invite(
self,
@@ -878,6 +935,7 @@ class RoomMemberHandler(object):
"sender": user.to_string(),
"state_key": token,
},
ratelimit=False,
txn_id=txn_id,
)
@@ -926,8 +984,9 @@ class RoomMemberHandler(object):
user.
"""
target = self._get_id_server_target(id_server)
is_url = "%s%s/_matrix/identity/api/v1/store-invite" % (
id_server_scheme, id_server,
id_server_scheme, target,
)
invite_config = {
@@ -967,7 +1026,7 @@ class RoomMemberHandler(object):
fallback_public_key = {
"public_key": data["public_key"],
"key_validity_url": "%s%s/_matrix/identity/api/v1/pubkey/isvalid" % (
id_server_scheme, id_server,
id_server_scheme, target,
),
}
else:

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2017 New Vector Ltd
# Copyright 2017-2018 New Vector Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -29,9 +30,12 @@ class SetPasswordHandler(BaseHandler):
super(SetPasswordHandler, self).__init__(hs)
self._auth_handler = hs.get_auth_handler()
self._device_handler = hs.get_device_handler()
self._password_policy_handler = hs.get_password_policy_handler()
@defer.inlineCallbacks
def set_password(self, user_id, newpassword, requester=None):
self._password_policy_handler.validate_password(newpassword)
password_hash = yield self._auth_handler.hash(newpassword)
except_device_id = requester.device_id if requester else None

View File

@@ -45,6 +45,7 @@ from synapse.http import (
cancelled_to_request_timed_out_error,
redact_uri,
)
from synapse.http.proxyagent import ProxyAgent
from synapse.util.async_helpers import timeout_deferred
from synapse.util.caches import CACHE_SIZE_FACTOR
from synapse.util.logcontext import make_deferred_yieldable
@@ -185,7 +186,15 @@ class SimpleHttpClient(object):
using HTTP in Matrix
"""
def __init__(self, hs, treq_args={}, ip_whitelist=None, ip_blacklist=None):
def __init__(
self,
hs,
treq_args={},
ip_whitelist=None,
ip_blacklist=None,
http_proxy=None,
https_proxy=None,
):
"""
Args:
hs (synapse.server.HomeServer)
@@ -194,6 +203,8 @@ class SimpleHttpClient(object):
we may not request.
ip_whitelist (netaddr.IPSet): The whitelisted IP addresses, that we can
request if it were otherwise caught in a blacklist.
http_proxy (bytes): proxy server to use for http connections. host[:port]
https_proxy (bytes): proxy server to use for https connections. host[:port]
"""
self.hs = hs
@@ -238,11 +249,13 @@ class SimpleHttpClient(object):
# The default context factory in Twisted 14.0.0 (which we require) is
# BrowserLikePolicyForHTTPS which will do regular cert validation
# 'like a browser'
self.agent = Agent(
self.agent = ProxyAgent(
self.reactor,
connectTimeout=15,
contextFactory=self.hs.get_http_client_context_factory(),
pool=pool,
http_proxy=http_proxy,
https_proxy=https_proxy,
)
if self._ip_blacklist:

View File

@@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from zope.interface import implementer
from twisted.internet import defer, protocol
from twisted.internet.error import ConnectError
from twisted.internet.interfaces import IStreamClientEndpoint
from twisted.internet.protocol import connectionDone
from twisted.web import http
logger = logging.getLogger(__name__)
class ProxyConnectError(ConnectError):
pass
@implementer(IStreamClientEndpoint)
class HTTPConnectProxyEndpoint(object):
"""An Endpoint implementation which will send a CONNECT request to an http proxy
Wraps an existing HostnameEndpoint for the proxy.
When we get the connect() request from the connection pool (via the TLS wrapper),
we'll first connect to the proxy endpoint with a ProtocolFactory which will make the
CONNECT request. Once that completes, we invoke the protocolFactory which was passed
in.
Args:
reactor: the Twisted reactor to use for the connection
proxy_endpoint (IStreamClientEndpoint): the endpoint to use to connect to the
proxy
host (bytes): hostname that we want to CONNECT to
port (int): port that we want to connect to
"""
def __init__(self, reactor, proxy_endpoint, host, port):
self._reactor = reactor
self._proxy_endpoint = proxy_endpoint
self._host = host
self._port = port
def __repr__(self):
return "<HTTPConnectProxyEndpoint %s>" % (self._proxy_endpoint,)
def connect(self, protocolFactory):
f = HTTPProxiedClientFactory(self._host, self._port, protocolFactory)
d = self._proxy_endpoint.connect(f)
# once the tcp socket connects successfully, we need to wait for the
# CONNECT to complete.
d.addCallback(lambda conn: f.on_connection)
return d
class HTTPProxiedClientFactory(protocol.ClientFactory):
"""ClientFactory wrapper that triggers an HTTP proxy CONNECT on connect.
Once the CONNECT completes, invokes the original ClientFactory to build the
HTTP Protocol object and run the rest of the connection.
Args:
dst_host (bytes): hostname that we want to CONNECT to
dst_port (int): port that we want to connect to
wrapped_factory (protocol.ClientFactory): The original Factory
"""
def __init__(self, dst_host, dst_port, wrapped_factory):
self.dst_host = dst_host
self.dst_port = dst_port
self.wrapped_factory = wrapped_factory
self.on_connection = defer.Deferred()
def startedConnecting(self, connector):
return self.wrapped_factory.startedConnecting(connector)
def buildProtocol(self, addr):
wrapped_protocol = self.wrapped_factory.buildProtocol(addr)
return HTTPConnectProtocol(
self.dst_host, self.dst_port, wrapped_protocol, self.on_connection
)
def clientConnectionFailed(self, connector, reason):
logger.debug("Connection to proxy failed: %s", reason)
if not self.on_connection.called:
self.on_connection.errback(reason)
return self.wrapped_factory.clientConnectionFailed(connector, reason)
def clientConnectionLost(self, connector, reason):
logger.debug("Connection to proxy lost: %s", reason)
if not self.on_connection.called:
self.on_connection.errback(reason)
return self.wrapped_factory.clientConnectionLost(connector, reason)
class HTTPConnectProtocol(protocol.Protocol):
"""Protocol that wraps an existing Protocol to do a CONNECT handshake at connect
Args:
host (bytes): The original HTTP(s) hostname or IPv4 or IPv6 address literal
to put in the CONNECT request
port (int): The original HTTP(s) port to put in the CONNECT request
wrapped_protocol (interfaces.IProtocol): the original protocol (probably
HTTPChannel or TLSMemoryBIOProtocol, but could be anything really)
connected_deferred (Deferred): a Deferred which will be callbacked with
wrapped_protocol when the CONNECT completes
"""
def __init__(self, host, port, wrapped_protocol, connected_deferred):
self.host = host
self.port = port
self.wrapped_protocol = wrapped_protocol
self.connected_deferred = connected_deferred
self.http_setup_client = HTTPConnectSetupClient(self.host, self.port)
self.http_setup_client.on_connected.addCallback(self.proxyConnected)
def connectionMade(self):
self.http_setup_client.makeConnection(self.transport)
def connectionLost(self, reason=connectionDone):
if self.wrapped_protocol.connected:
self.wrapped_protocol.connectionLost(reason)
self.http_setup_client.connectionLost(reason)
if not self.connected_deferred.called:
self.connected_deferred.errback(reason)
def proxyConnected(self, _):
self.wrapped_protocol.makeConnection(self.transport)
self.connected_deferred.callback(self.wrapped_protocol)
# Get any pending data from the http buf and forward it to the original protocol
buf = self.http_setup_client.clearLineBuffer()
if buf:
self.wrapped_protocol.dataReceived(buf)
def dataReceived(self, data):
# if we've set up the HTTP protocol, we can send the data there
if self.wrapped_protocol.connected:
return self.wrapped_protocol.dataReceived(data)
# otherwise, we must still be setting up the connection: send the data to the
# setup client
return self.http_setup_client.dataReceived(data)
class HTTPConnectSetupClient(http.HTTPClient):
"""HTTPClient protocol to send a CONNECT message for proxies and read the response.
Args:
host (bytes): The hostname to send in the CONNECT message
port (int): The port to send in the CONNECT message
"""
def __init__(self, host, port):
self.host = host
self.port = port
self.on_connected = defer.Deferred()
def connectionMade(self):
logger.debug("Connected to proxy, sending CONNECT")
self.sendCommand(b"CONNECT", b"%s:%d" % (self.host, self.port))
self.endHeaders()
def handleStatus(self, version, status, message):
logger.debug("Got Status: %s %s %s", status, message, version)
if status != b"200":
raise ProxyConnectError("Unexpected status on CONNECT: %s" % status)
def handleEndHeaders(self):
logger.debug("End Headers")
self.on_connected.callback(None)
def handleResponse(self, body):
pass

Some files were not shown because too many files have changed in this diff Show More