1
0

Compare commits

...

480 Commits

Author SHA1 Message Date
Erik Johnston 92dbb8a62f update proxy 2019-02-13 15:16:05 +00:00
Erik Johnston 816f5a502f Update proxy 2019-02-13 15:16:05 +00:00
Erik Johnston 561fa571c3 Fix fetching media when using proxy 2019-02-13 15:16:05 +00:00
Erik Johnston b76f1e2cb8 Fix bug in DTG 2019-02-13 15:16:05 +00:00
Erik Johnston 549e580dc9 Reduce send invite request size 2019-02-13 15:16:05 +00:00
Erik Johnston c3f36414bf Update proxy 2019-02-13 15:16:05 +00:00
Erik Johnston 17eb4504a8 Update flate file 2019-02-13 15:16:05 +00:00
Erik Johnston a066b00487 Compress some client data 2019-02-13 15:16:05 +00:00
Erik Johnston 4e0ac33053 Handle slow/lossy connections better when sending transactions 2019-02-13 15:16:05 +00:00
Erik Johnston 76d888cf48 pep8 2019-02-13 15:16:05 +00:00
Erik Johnston dde7110c0d Reduce transaction response size 2019-02-13 15:16:05 +00:00
Erik Johnston 5e6b5ccd26 Actually fix exceptions 2019-02-13 15:16:04 +00:00
Erik Johnston 1d7420ed2f Don't log ERROR when no profile exists 2019-02-13 15:16:04 +00:00
Travis Ralston a527fbaae6 Catch room profile errors and anything else that can go wrong
Fixes an issue where things become unhappy when the room profile for a user is missing.
2019-02-13 15:16:04 +00:00
Erik Johnston b951f35572 Reduce size of fed transaction IDs 2019-02-13 15:16:04 +00:00
Brendan Abolivier 6eca7dc3e8 Update maps and proxy 2019-02-13 15:16:04 +00:00
Erik Johnston 1466adf427 Make event_ids smaller 2019-02-13 15:16:04 +00:00
Erik Johnston a99c2f56b5 Mangle some more PDU fields 2019-02-13 15:16:04 +00:00
Brendan Abolivier 306b670371 Update proxy maps 2019-02-13 15:16:04 +00:00
Brendan Abolivier 31825c10d6 Update proxy & maps 2019-02-13 15:16:04 +00:00
Erik Johnston a01468c1a8 Change access tokens to be base64'ed 4 bytes 2019-02-13 15:16:04 +00:00
Brendan Abolivier 31c910a9a2 Update proxy 2019-02-13 15:16:04 +00:00
Erik Johnston 62fa8570ec Route full mesh if message contains 'mesh' 2019-02-13 15:16:04 +00:00
Brendan Abolivier 5f52a2c25e Update proxy 2019-02-13 15:16:04 +00:00
Travis Ralston 645d5c8c35 Use run_as_background_process 2019-02-13 15:16:04 +00:00
Travis Ralston 0463d9ba75 Safer execution 2019-02-13 15:16:04 +00:00
Travis Ralston b26d8cea66 Preserve log contexts in the room_member_handler 2019-02-13 15:16:04 +00:00
Travis Ralston de6d002d01 Proof of concept for auto-accepting invites
This is for demonstration purposes only. In practice this would actually look up the right profile and use the right thing, not to mention be in a more reasonable location.
2019-02-13 15:16:04 +00:00
Neil Johnson 2b77c8d50e Remove riot.im from the list of trusted Identity Servers in the default configuration (#4207) 2019-02-13 15:16:04 +00:00
Richard van der Hoff fa78a83ac3 changelog 2019-02-13 15:16:04 +00:00
Richard van der Hoff 5eceb4dc0f Fix logcontext leak in test_url_preview 2019-02-13 15:16:04 +00:00
Richard van der Hoff 07577e0542 Fix logcontext leak in http pusher test 2019-02-13 15:16:04 +00:00
Richard van der Hoff 3cda7da827 Fix some tests which leaked logcontexts 2019-02-13 15:16:04 +00:00
Richard van der Hoff cb7c2ad85a Fix logcontext leak in EmailPusher 2019-02-13 15:16:04 +00:00
Amber Brown a29da814c6 towncrier 2019-02-13 15:16:04 +00:00
Amber Brown 5e499c58fd version 2019-02-13 15:16:03 +00:00
Neil Johnson fa574331fb release 0.33.9rc1 2019-02-13 15:16:03 +00:00
Amber Brown ca05b679e3 Fix fallback auth on Python 3 (#4197) 2019-02-13 15:16:03 +00:00
Aaron Raimist 83ed2c494b Fix case
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2019-02-13 15:16:03 +00:00
Aaron Raimist 5d4dfc0313 Add SUPPORT.md
https://help.github.com/articles/adding-support-resources-to-your-project/
2019-02-13 15:16:03 +00:00
Aaron Raimist 7d4b700204 Add changelog
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2019-02-13 15:16:03 +00:00
Aaron Raimist c01605da24 Add a pull request template and add multiple issue templates
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2019-02-13 15:16:03 +00:00
Aaron Raimist 76b251c599 Add changelog
Signed-off-by: Aaron Raimist <aaron@raim.ist>
2019-02-13 15:16:03 +00:00
Aaron Raimist 26708be7f8 Add a note saying you need to manually reclaim disk space
People keep asking why their database hasn't gotten smaller after using this API.

Signed-off-by: Aaron Raimist <aaron@raim.ist>
2019-02-13 15:16:03 +00:00
Erik Johnston 6baa32fd65 Update coap-proxy 2019-02-13 15:16:03 +00:00
Matthew Hodgson 32df91cbcb de-hardcode IP for jaeger 2019-02-13 15:16:03 +00:00
Erik Johnston 42f555393a GAH FILES WHY 2019-02-13 15:16:03 +00:00
Erik Johnston 224df403ea Fixup opentracing error logging 2019-02-13 15:16:03 +00:00
Erik Johnston 2d8da62feb Only relay 'live' events 2019-02-13 15:16:03 +00:00
Erik Johnston e2230b28fb Mangle PDUs some more. Disable presence/typing/receipts. Don't die if we can't parse an EDU 2019-02-13 15:16:03 +00:00
Erik Johnston 28c3a43a7e Make using proxy optional 2019-02-13 15:16:03 +00:00
Brendan Abolivier c11388b1ce Update proxy version and maps 2019-02-13 15:16:03 +00:00
Erik Johnston 9dfb6b6c52 Drop unnecessary keys from transactions 2019-02-13 15:16:03 +00:00
Erik Johnston caa0004466 Track PDU in opentracing 2019-02-13 15:16:03 +00:00
Erik Johnston ae7460b9f4 Make room ID smaller 2019-02-13 15:16:03 +00:00
Erik Johnston fe6e221cfa Opentracing. Reduce event ID size 2019-02-13 15:16:03 +00:00
Erik Johnston b071101729 Strip signatures and hashes on outgoing events 2019-02-13 15:16:03 +00:00
Matthew Hodgson 3405156c4b use right script 2019-02-13 15:16:03 +00:00
Matthew Hodgson 1682ee95ac switch to registering users via add_users.sh 2019-02-13 15:16:03 +00:00
Erik Johnston e7b70e272f Fix jaeger over federation 2019-02-13 15:16:03 +00:00
Erik Johnston ec288b48fd add basic jaeger support 2019-02-13 15:16:03 +00:00
Erik Johnston 27ca009b0a Reenable retries for sending transactions 2019-02-13 15:16:03 +00:00
Erik Johnston 6284acf910 Add API to force new threads 2019-02-13 15:16:03 +00:00
Erik Johnston 93db2124ec Add timestamp lookup API 2019-02-13 15:16:03 +00:00
Brendan Abolivier ca0e0892ca Fix proxy 2019-02-13 15:16:03 +00:00
Brendan Abolivier 8cccbc6f47 Use UDP-able proxy 2019-02-13 15:16:02 +00:00
Brendan Abolivier 799112b0fd Fix cbor encoding in the proxy and enable it by default 2019-02-13 15:16:02 +00:00
Brendan Abolivier 4f7b42c20f Update proxy 2019-02-13 15:16:02 +00:00
Brendan Abolivier 72779ec93f Start synapse + proxy in the same container 2019-02-13 15:16:02 +00:00
Brendan Abolivier fc99d3dab3 Make the Docker image run both synapse and the proxy 2019-02-13 15:16:02 +00:00
Brendan Abolivier 55bfb3caa8 Make synapse talk HTTP to the local proxy only when federating 2019-02-13 15:16:02 +00:00
Erik Johnston e8be4ca1ad Join via closest server 2019-02-13 15:16:02 +00:00
Erik Johnston 781bd4fb96 FILES 2019-02-13 15:16:02 +00:00
Erik Johnston 4b5ad3dd12 Add SYNAPSE_LOG_HOST to enable HTTP logging for PDU tracking 2019-02-13 15:15:56 +00:00
Matthew Hodgson a688d10bca secret password; more timeout 2019-02-13 14:24:42 +00:00
Matthew Hodgson fe3b9d085f meshsim Dockerfile 2019-02-13 14:24:42 +00:00
Ashe Connor dad89a4902 add changelog.d entry 2019-02-13 14:24:42 +00:00
Ashe Connor d5243f0ff3 add jpeg to OpenBSD prereq list
Signed-off-by: Ashe Connor <ashe@kivikakk.ee>
2019-02-13 14:24:42 +00:00
Travis Ralston 037a5b48a6 Fix the terms UI auth tests
By setting the config value directly, we skip the block that adds the slash automatically for us.
2019-02-13 14:24:42 +00:00
Travis Ralston 5abcb455b2 Changelog 2019-02-13 14:24:42 +00:00
Travis Ralston 8d98c4e3e3 Remove duplicate slashes in generated consent URLs 2019-02-13 14:24:42 +00:00
Amber Brown e0581ccf0e Fix Content-Disposition in media repository (#4176) 2019-02-13 14:24:42 +00:00
Travis Ralston ac9b734e31 Add option to track MAU stats (but not limit people) (#3830) 2019-02-13 14:24:42 +00:00
Amber Brown dc768f208e Use <meta> tags to discover the per-page encoding of html previews (#4183) 2019-02-13 14:24:42 +00:00
Amber Brown 404cee9853 Add a coveragerc (#4180) 2019-02-13 14:24:42 +00:00
Richard van der Hoff 166cc35a48 Update README for #1491 fix 2019-02-13 14:24:42 +00:00
Richard van der Hoff 0d934b9ae1 changelog 2019-02-13 14:24:42 +00:00
Richard van der Hoff ba2b6229c1 Add a test for the public T&Cs form 2019-02-13 14:24:42 +00:00
Richard van der Hoff 7cee15c47d Fix an internal server error when viewing the public privacy policy 2019-02-13 14:24:42 +00:00
David Baker 71f866d54d pep8 2019-02-13 14:24:42 +00:00
David Baker 785f5ef0f3 add docs 2019-02-13 14:24:42 +00:00
David Baker daf28668d0 Remove unnecessary str() 2019-02-13 14:24:42 +00:00
David Baker e750d031c8 Cast to int here too 2019-02-13 14:24:42 +00:00
David Baker efb77b87d1 Cast bacjup version to int when querying 2019-02-13 14:24:42 +00:00
David Baker b0ac23319a Convert version back to a string 2019-02-13 14:24:42 +00:00
David Baker 515a6cb0d3 news fragment 2019-02-13 14:24:42 +00:00
David Baker 8f46b61aed Try & make it work on postgres 2019-02-13 14:24:42 +00:00
David Baker f814a1ec5a Make e2e backup versions numeric in the DB
We were doing max(version) which does not do what we wanted
on a column of type TEXT.
2019-02-13 14:24:42 +00:00
Brendan Abolivier 7b28b058e1 Add a Content-Type header on POST requests to the federation client 2019-02-13 14:24:42 +00:00
Erik Johnston 06132f1f0b Add test to assert set_e2e_device_keys correctly returns False on no-op 2019-02-13 14:24:42 +00:00
Erik Johnston b8077ca8cd Lets convert bytes to unicode instead 2019-02-13 14:24:42 +00:00
Erik Johnston e56d0456cb Newsfile 2019-02-13 14:24:42 +00:00
Erik Johnston 755f42d769 Fix noop checks when updating device keys
Clients often reupload their device keys (for some reason) so its
important for the server to check for no-ops before sending out device
list update notifications.

The check is broken in python 3 due to the fact comparing bytes and
unicode always fails, and that we write bytes to the DB but get unicode
when we read.
2019-02-13 14:24:42 +00:00
Richard van der Hoff ef77ab59a7 fix parse_string docstring 2019-02-13 14:24:42 +00:00
Richard van der Hoff d26852e9d8 changelog 2019-02-13 14:24:42 +00:00
hera 1f8a82077e Fix encoding error for consent form on python3
The form was rendering this as "b'01234....'".

-- richvdh
2019-02-13 14:24:42 +00:00
Erik Johnston 14059e2300 pep8 2019-02-13 14:24:41 +00:00
Erik Johnston 3223f415e2 Add server health apis and server presence 2019-02-13 14:23:21 +00:00
Erik Johnston f57e71645a Missing file 2019-02-13 14:22:59 +00:00
Erik Johnston c400d9dcca Add backchatter 2019-02-13 14:22:58 +00:00
Erik Johnston ed43a63fcf Don't verify stuff 2019-02-13 14:22:18 +00:00
Erik Johnston e6896040c7 Merge branch 'erikj/thread_demo' of github.com:matrix-org/synapse into erikj/add_routing_hooks 2018-11-21 11:45:11 +00:00
Erik Johnston d0d3c63705 Fix threading when pulling in via get_missing_events 2018-11-21 10:45:35 +00:00
Erik Johnston 5ae1644d3d Send down new thread marker 2018-11-20 17:42:43 +00:00
Erik Johnston 115e4bb4c6 Fix threading 2018-11-20 17:04:19 +00:00
Erik Johnston 607ac7ea37 Lower all the timeouts 2018-11-20 13:32:47 +00:00
Erik Johnston 775441105a Reduce timeouts for sending transaction 2018-11-20 11:30:43 +00:00
Erik Johnston e644f49b46 Delta file 2018-11-19 15:09:07 +00:00
Erik Johnston 712caeba60 Add hooks in federation for funky event routing 2018-11-14 16:12:33 +00:00
Erik Johnston 956b47da2b Dont' log so aggressively 2018-11-14 15:32:33 +00:00
Erik Johnston 822fcc3bb8 Add concept of internal events 2018-11-13 15:33:54 +00:00
Erik Johnston 5daa2b9dbc Fix sync for archived rooms 2018-11-13 15:13:03 +00:00
Erik Johnston 08395c7f89 Implemented thread support for backfills 2018-11-13 14:56:38 +00:00
Erik Johnston c67953748d Add thread_id to filter 2018-11-13 10:34:38 +00:00
Erik Johnston 78fec6b3c9 Add flag to sync to exclude threads 2018-11-12 16:20:14 +00:00
Erik Johnston dfa830e61a Store and fetch thread IDs 2018-11-12 15:44:22 +00:00
Erik Johnston dc59ad5334 Remove hack to support rejoining rooms 2018-11-09 14:58:09 +00:00
Erik Johnston 30dd27afff Simplify to always drop events if server isn't in the room 2018-11-09 11:36:45 +00:00
Richard van der Hoff 3cecf5340d Update synapse/federation/federation_server.py
Co-Authored-By: erikjohnston <erikj@jki.re>
2018-11-09 11:28:25 +00:00
Richard van der Hoff 9bce065a53 Update synapse/federation/federation_server.py
Co-Authored-By: erikjohnston <erikj@jki.re>
2018-11-09 11:28:22 +00:00
Erik Johnston 94896d7ffe Newsfile 2018-11-08 12:30:25 +00:00
Erik Johnston 9417986f77 Drop PDUs of unknown rooms
When we receive events over federation we will need to know the room
version to be able to correctly handle them, e.g. once we start changing
event formats. Currently, we attempt to handle events in unknown rooms.
2018-11-08 12:11:20 +00:00
Amber Brown 264cb14402 Port hash_password to Python 3 (#4161)
* port hash_password

* changelog
2018-11-08 04:57:28 +11:00
Amber Brown b3708830b8 Fix URL preview bugs (type error when loading cache from db, content-type including quotes) (#4157) 2018-11-08 01:37:43 +11:00
Richard van der Hoff c8ba79327b Merge pull request #4155 from rubo77/purge-api
add purge_history.sh and purge_remote_media.sh scripts
2018-11-07 14:06:41 +00:00
rubo77 2904d133f3 add purge_history.sh and purge_remote_media.sh scripts to contrib/purge_api/
Signed-off-by: Ruben Barkow <github@r.z11.de>
2018-11-07 14:02:41 +01:00
Amber Brown e62f7f17b3 Remove some boilerplate in tests (#4156) 2018-11-07 03:00:00 +11:00
Travis Ralston 0f5e51f726 Add config variables for enabling terms auth and the policy name (#4142)
So people can still collect consent the old way if they want to.
2018-11-06 10:32:34 +00:00
Hubert Chathi f1087106cf handle empty backups according to latest spec proposal (#4123)
fixes #4056
2018-11-05 17:59:29 -05:00
Amber Brown efdcbbe46b Tests for user consent resource (#4140) 2018-11-06 05:53:44 +11:00
Amber Brown 5a63589e80 Add some tests for the HTTP pusher (#4149) 2018-11-06 05:53:24 +11:00
Erik Johnston bc80b3f454 Add helpers for getting prev and auth events (#4139)
* Add helpers for getting prev and auth events

This is in preparation for allowing the event format to change between
room versions.
2018-11-06 00:35:15 +11:00
Amber Brown 0467384d2f Set the encoding to UTF8 in the default logconfig (#4138) 2018-11-03 02:28:07 +11:00
Erik Johnston 90d713b8c6 Merge pull request #4137 from matrix-org/erikj/clean_up_events
Clean up event accesses and tests
2018-11-02 14:12:49 +00:00
Erik Johnston 76cd7de108 Newsfile 2018-11-02 13:45:56 +00:00
Erik Johnston b86d05a279 Clean up event accesses and tests
This is in preparation to refactor FrozenEvent to support different
event formats for different room versions
2018-11-02 13:44:14 +00:00
Amber Brown cb7a6b2379 Fix typing being reset causing infinite syncs (#4127) 2018-11-03 00:19:23 +11:00
Richard van der Hoff efb9343c8c Merge pull request #4132 from matrix-org/rav/fix_device_list_locking
Fix locked upsert on device_lists_remote_cache
2018-11-02 10:50:53 +00:00
Richard van der Hoff 00f12e00f8 Merge pull request #4133 from matrix-org/travis/fix-terms-auth
Fix logic error that prevented guests from seeing the privacy policy
2018-11-02 10:50:43 +00:00
Erik Johnston b199534518 Merge pull request #4135 from matrix-org/erikj/fix_state_res_none
Fix None exception in state res v2
2018-11-02 10:45:57 +00:00
Richard van der Hoff 1cc6671ec4 changelog 2018-11-02 10:36:13 +00:00
Richard van der Hoff 350f654e7b Add unique indexes to a couple of tables
The indexes on device_lists_remote_extremeties can be unique, and they
therefore should, to ensure that the db remains consistent.
2018-11-02 10:36:13 +00:00
Richard van der Hoff 50e328d1e7 Remove redundant database locks for device list updates
We can rely on the application-level per-user linearizer.
2018-11-02 10:36:13 +00:00
Erik Johnston f05d97e283 Newsfile 2018-11-02 10:32:06 +00:00
Erik Johnston 54aec35867 Fix None exception in state res v2 2018-11-02 10:29:19 +00:00
Travis Ralston 552f090f62 Changelog 2018-11-01 16:51:11 -06:00
Travis Ralston 642505abc3 Fix logic error that prevented guests from seeing the privacy policy 2018-11-01 16:48:32 -06:00
Richard van der Hoff 3149d55b7d Merge pull request #3778 from z3ntu/patch-1
Fix build of Docker image with docker-compose
2018-11-01 17:34:56 +00:00
Travis Ralston c68aab1536 Merge pull request #4004 from matrix-org/travis/login-terms
Add m.login.terms to the registration flow
2018-11-01 11:03:38 -06:00
Erik Johnston 1b21e771d0 Merge pull request #4128 from matrix-org/erikj/state_res_v2_version
Add STATE_V2_TEST room version
2018-11-01 13:17:57 +00:00
Erik Johnston 62d683161e Newsfile 2018-11-01 11:44:44 +00:00
Erik Johnston b3dd6fa981 Add STATE_V2_TEST room version 2018-11-01 11:43:46 +00:00
Amber Brown 073d400b84 Merge branch 'master' into develop 2018-11-01 21:32:12 +11:00
Amber Brown 907e6da5be Merge branch 'release-v0.33.8' 2018-11-01 21:31:46 +11:00
Amber Brown d0ebe82871 changelog 2018-11-01 21:29:11 +11:00
Amber Brown aa98e38896 version 2018-11-01 21:28:35 +11:00
Travis Ralston a8c9faa9a2 The tests also need a version parameter 2018-10-31 13:28:08 -06:00
Travis Ralston a8d41c6aff Include a version query string arg for the consent route 2018-10-31 13:19:28 -06:00
Travis Ralston d1e7b9c44c Merge branch 'develop' into travis/login-terms 2018-10-31 13:15:14 -06:00
Richard van der Hoff 1729ba1650 Merge pull request #4101 from matrix-org/rav/aliases_for_upgrades
Attempt to move room aliases on room upgrades
2018-10-31 17:52:18 +00:00
Richard van der Hoff 4ecb8b7de8 Merge pull request #4125 from MazeChaZer/fix-typo-in-docker-compose
Fix typo in docker-compose.yml
2018-10-31 15:55:01 +00:00
Richard van der Hoff 0f8591a5a8 Avoid else clause on exception for clarity 2018-10-31 15:43:57 +00:00
Richard van der Hoff 94c7fadc98 Attempt to move room aliases on room upgrades 2018-10-31 15:43:57 +00:00
Richard van der Hoff 9b827c40ca Log some bits about event creation (#4121)
I found these helpful in debugging my room upgrade tests.
2018-10-31 15:42:23 +00:00
Richard van der Hoff 60f128a401 Merge pull request #4124 from matrix-org/rav/fix_tox
Attempt to fix tox installs
2018-10-31 15:41:55 +00:00
Jonas Schürmann e3758c8c92 Fix typo in docker-compose.yml
Signed-off-by: Jonas Schürmann <jonasschuermann@aol.de>
2018-10-31 15:46:47 +01:00
Amber Brown 916efc8249 Remove fetching keys via the deprecated v1 kex method (#4120) 2018-10-31 23:14:39 +11:00
Amber Brown f79f454485 Remove deprecated v1 key exchange endpoint (#4119) 2018-10-31 22:29:02 +11:00
Richard van der Hoff a2d8bff0dc changelog 2018-10-30 21:21:05 +00:00
Richard van der Hoff 0f6ec6d1ae Attempt to fix tox installs
It seems that, at some point, the ability to run tox on old servers (with old
setuptools) got broken - and it was only working on our Jenkins instance by
dint of reusing the tox environments.

Let's try to get tox to do the right thing, and remove the guff from
jenkins/prepare_synapse.sh.

(There is a separate question about whether the jenkins builds should be using
tox to prepare the virtualenv at all here, but that is somewhat orthogonal).
2018-10-30 21:00:31 +00:00
Amber Brown e615e95590 changelog 2018-10-31 06:28:11 +11:00
Amber Brown 67c1924899 version bump 2018-10-31 06:27:05 +11:00
Amber Brown 086e1a8f3e Fix search 500ing (#4122) 2018-10-31 06:26:46 +11:00
Amber Brown 3bade14ec0 Fix search 500ing (#4122) 2018-10-31 04:33:41 +11:00
Amber Brown 2e223a8c22 Remove the unused /pull federation API (#4118) 2018-10-31 04:24:59 +11:00
Erik Johnston 0794504bce Merge pull request #4006 from matrix-org/erikj/purge_state_groups
Delete unreferenced state groups during purge
2018-10-30 16:58:22 +00:00
Amber Brown 0dce9e1379 Write some tests for the email pusher (#4095) 2018-10-30 23:55:43 +11:00
Erik Johnston 169851b412 Merge pull request #4109 from matrix-org/erikj/repl_devices
A couple of replication fixes for device lists
2018-10-29 18:16:48 +00:00
Erik Johnston 00fdfbc213 Merge pull request #4111 from matrix-org/erikj/repl_names
Erikj/repl names
2018-10-29 18:16:03 +00:00
Erik Johnston 4f0fa7a120 Newsfile 2018-10-29 18:15:42 +00:00
Erik Johnston 39f419868f Newsfile 2018-10-29 17:38:09 +00:00
Erik Johnston 88e5ffe6fe Deduplicate device updates sent over replication
We currently send several kHz of device list updates over replication
occisonally, which often causes the replications streams to lag and then
get dropped.

A lot of those updates will actually be duplicates, since we don't send
e.g. device_ids across replication, so let's deduplicate it when we pull
them out of the database.
2018-10-29 17:34:34 +00:00
Erik Johnston a163b748a5 Don't truncate command name in metrics 2018-10-29 17:34:21 +00:00
Erik Johnston ad88460e0d Move _find_unreferenced_groups 2018-10-29 14:24:19 +00:00
Erik Johnston 664b192a3b Fix set operations thinko 2018-10-29 14:21:43 +00:00
Erik Johnston f4f223aa44 Don't make temporary list 2018-10-29 14:01:49 +00:00
Erik Johnston b2399f6281 Make SQL a bit cleaner 2018-10-29 14:01:11 +00:00
Amber Brown 4cd1c9f2ff Delete the disused & unspecced identicon functionality (#4106) 2018-10-29 23:57:24 +11:00
Richard van der Hoff 7fbfea062e Merge pull request #4100 from matrix-org/rav/room_upgrade_avatar
Remember to copy the avatar on room upgrades
2018-10-29 12:49:21 +00:00
Richard van der Hoff 56ca578f77 Merge pull request #4099 from matrix-org/rav/upgrade_odd_pls
Better handling of odd PLs during room upgrades
2018-10-29 12:48:51 +00:00
Richard van der Hoff bf33eed609 Merge pull request #4091 from matrix-org/rav/room_version_upgrades
Room version upgrade support
2018-10-29 12:47:20 +00:00
Amber Brown c4b3698a80 Make the replication logger quieter (#4108) 2018-10-29 22:59:44 +11:00
Amber Brown 3b0a85fc8e changelog 2018-10-29 21:54:01 +11:00
Amber Brown 2b791865c4 version bump 2018-10-29 21:52:52 +11:00
Richard van der Hoff db24d7f15e Better handling of odd PLs during room upgrades
Fixes handling of rooms where we have permission to send the tombstone, but not
other state. We need to (a) fail more gracefully when we can't send the PLs in
the old room, and (b) not set the PLs in the new room until we are done with
the other stuff.
2018-10-27 00:54:26 +01:00
Richard van der Hoff 5caf79b312 Remember to copy the avatar on room upgrades 2018-10-26 23:56:40 +01:00
Richard van der Hoff 54bbe71867 optimise state copying 2018-10-26 22:51:34 +01:00
Richard van der Hoff 193cadc988 Address review comments
Improve comments, get old room state from the context we already have
2018-10-26 17:10:30 +01:00
Erik Johnston 03e634dad4 Merge branch 'develop' of github.com:matrix-org/synapse into erikj/purge_state_groups 2018-10-26 16:22:45 +01:00
Amber Brown 77d70a7646 Port register_new_matrix_user to Python 3 and add tests (#4085) 2018-10-26 22:05:22 +11:00
Richard van der Hoff 474810d9d5 fix broken test
This test stubbed out some stuff in a very weird way. I have no idea why. It broke.
2018-10-25 23:15:03 +01:00
Richard van der Hoff 6cb2e2448a Merge pull request #4089 from dekonnection/master
Make Docker image listen on ipv6 as well as ipv4
2018-10-25 19:23:37 +01:00
Richard van der Hoff 68c0ce62d8 changelog 2018-10-25 19:18:25 +01:00
Richard van der Hoff e6babc27d5 restrict PLs in old room 2018-10-25 19:18:25 +01:00
Richard van der Hoff 3a263bf3ae copy state 2018-10-25 19:18:25 +01:00
Richard van der Hoff 1b9f253e20 preserve PLs 2018-10-25 19:10:24 +01:00
Richard van der Hoff 4cda300058 preserve room visibility 2018-10-25 19:10:24 +01:00
Richard van der Hoff 0f7d1c9906 Basic initial support for room upgrades
Currently just creates a new, empty, room, and sends a tombstone in the old
room.
2018-10-25 19:10:24 +01:00
Richard van der Hoff e1948175ee Allow power_level_content_override=None for _send_events_for_new_room 2018-10-25 19:10:24 +01:00
Richard van der Hoff 7f7b2cd3de Make room_member_handler a member of RoomCreationHandler
... to save passing it into `_send_events_for_new_room`
2018-10-25 19:10:18 +01:00
Cédric Laudrel 379376e5e6 Make Docker image listening on ipv6 as well as ipv4
Signed-off-by: Cédric Laudrel <dek@iono.me>
2018-10-25 20:03:47 +02:00
Richard van der Hoff 871c4abfec Factor _generate_room_id out of create_room
we're going to need this for room upgrades.
2018-10-25 18:23:09 +01:00
Erik Johnston cb53ce9d64 Refactor state group lookup to reduce DB hits (#4011)
Currently when fetching state groups from the data store we make two
hits two the database: once for members and once for non-members (unless
request is filtered to one or the other). This adds needless load to the
datbase, so this PR refactors the lookup to make only a single database
hit.
2018-10-25 17:49:55 +01:00
Richard van der Hoff e5da60d75d Merge remote-tracking branch 'origin/master' into develop 2018-10-25 17:08:09 +01:00
Erik Johnston c85e063302 Merge pull request #4051 from matrix-org/erikj/alias_disallow_list
Add config option to control alias creation
2018-10-25 17:04:59 +01:00
Neil Johnson 95ad128851 Merge pull request #4081 from matrix-org/neilj/fix_mau_init
fix race condiftion in calling initialise_reserved_users
2018-10-25 16:33:40 +01:00
Neil Johnson fcbd488e9a add new line 2018-10-25 16:13:43 +01:00
Erik Johnston b94a43d5b5 Merge branch 'develop' of github.com:matrix-org/synapse into erikj/alias_disallow_list 2018-10-25 15:25:31 +01:00
Erik Johnston e5481b22aa Use allow/deny 2018-10-25 15:25:21 +01:00
Neil Johnson c99b6c66bf Merge pull request #3975 from matrix-org/matthew/autocreate_autojoin
Autocreate autojoin rooms
2018-10-25 15:00:40 +01:00
Neil Johnson f8fe98812b improve comments 2018-10-25 14:58:59 +01:00
Neil Johnson f7f487e14c Merge branch 'develop' of github.com:matrix-org/synapse into matthew/autocreate_autojoin 2018-10-25 14:40:06 +01:00
Richard van der Hoff edd2d82809 oops, run the check_isort build 2018-10-25 01:06:39 +01:00
Richard van der Hoff 46f98a6a29 Only cache the wheels 2018-10-25 01:00:58 +01:00
Richard van der Hoff fc33e81323 Combine the pep8 and check_isort builds into one
there's really no point spinning up two separate jobs for these.
2018-10-25 00:59:49 +01:00
Richard van der Hoff 77d3b5772f disable coverage checking
I don't think we ever use this, and it slows things down. If we want to use it,
we should just do so on a couple of builds rather than all of them.
2018-10-25 00:36:00 +01:00
Travis Ralston a5468eaadf pep8 2018-10-24 13:54:38 -06:00
Travis Ralston 81880beff4 It helps to import things 2018-10-24 13:32:13 -06:00
Travis Ralston 4acb6fe8a3 Move test to where the other integration tests are 2018-10-24 13:24:24 -06:00
Travis Ralston 9283987f7e Fix test
Debug tests

Try printing the channel

fix

Import and use six

Remove debugging

Disable captcha

Add some mocks

Define the URL

Fix the clock?

Less rendering?

use the other render

Complete the dummy auth stage

Fix last stage of the test

Remove mocks we don't need
2018-10-24 13:23:08 -06:00
Travis Ralston 54def42c19 Merge branch 'develop' into travis/login-terms 2018-10-24 13:22:59 -06:00
Neil Johnson ea69a84bbb fix style inconsistencies 2018-10-24 17:18:08 +01:00
Neil Johnson 663d9db8e7 commit transaction before closing 2018-10-24 17:17:30 +01:00
Neil Johnson 07126e43a4 Merge branch 'develop' of github.com:matrix-org/synapse into neilj/fix_mau_init 2018-10-24 16:25:39 +01:00
Neil Johnson 9ec2186586 isort 2018-10-24 16:09:21 +01:00
Neil Johnson 9532caf6ef remove trailing whiter space 2018-10-24 16:08:25 +01:00
Richard van der Hoff 83d9ca7122 only fetch develop for check-newsfragments 2018-10-24 15:32:18 +01:00
Richard van der Hoff 480d98c91f Disable newsfragment checks on branch builds 2018-10-24 15:31:00 +01:00
Richard van der Hoff ab96ee29c9 reduce git clone depth 2018-10-24 15:30:54 +01:00
Richard van der Hoff 0f4fb537ce fix branch regexp 2018-10-24 15:09:05 +01:00
Richard van der Hoff 3e438bfec8 also build on release branches 2018-10-24 15:04:55 +01:00
Richard van der Hoff 56a05583ae Disable travis-ci branch builds for most branches
(We really don't need to kick off 10 builds for the branch as well as 10 for
the PR)
2018-10-24 14:43:55 +01:00
Richard van der Hoff 94a49e0636 fix tuple
Co-Authored-By: neilisfragile <neil@matrix.org>
2018-10-24 14:39:23 +01:00
Richard van der Hoff 9f72c209ee Update changelog.d/3975.feature
Co-Authored-By: neilisfragile <neil@matrix.org>
2018-10-24 14:37:36 +01:00
Richard van der Hoff 78e8d4c3a5 Merge pull request #4083 from matrix-org/rav/fix_event_filter_validation
Allow backslashes in event field filters
2018-10-24 12:05:19 +01:00
Richard van der Hoff 3ad359e5be Merge remote-tracking branch 'origin/develop' into rav/fix_event_filter_validation 2018-10-24 11:23:49 +01:00
Richard van der Hoff 7328039117 Merge pull request #4082 from matrix-org/rav/fix_pep8
Fix a number of flake8 errors
2018-10-24 11:23:35 +01:00
Erik Johnston 3904cbf307 Merge pull request #4040 from matrix-org/erikj/states_res_v2_rebase
Add v2 state resolution algorithm
2018-10-24 11:12:12 +01:00
Richard van der Hoff 7e07d25ed6 Allow backslashes in event field filters
Fixes a bug introduced in https://github.com/matrix-org/synapse/pull/1783 which
meant that single backslashes were not allowed in event field filters.

The intention here is to allow single-backslashes, but disallow
double-backslashes.
2018-10-24 11:11:24 +01:00
Richard van der Hoff ef771cc4c2 Fix a number of flake8 errors
Broadly three things here:

* disable W504 which seems a bit whacko
* remove a bunch of `as e` expressions from exception handlers that don't use
  them
* use `r""` for strings which include backslashes

Also, we don't use pep8 any more, so we can get rid of the duplicate config
there.
2018-10-24 10:39:03 +01:00
Erik Johnston b313b9b009 isort 2018-10-24 10:02:41 +01:00
Erik Johnston 47a9ba435d Use match rather than search 2018-10-24 09:54:57 +01:00
Richard van der Hoff e0b9d5f0af Merge pull request #4075 from matrix-org/rav/fix_pusher_logcontexts
Clean up the way logcontexts and threads work in the pushers
2018-10-24 09:53:57 +01:00
Erik Johnston dacbeb2e03 Comment 2018-10-24 09:47:49 +01:00
Erik Johnston 810715f79a Rename resolve_events_with_factory 2018-10-24 09:44:22 +01:00
Erik Johnston cb23aa4c42 Merge pull request #4063 from matrix-org/erikj/cleaup_alias_creation
Clean up room alias creation
2018-10-24 09:40:27 +01:00
Richard van der Hoff c573794b22 Fix start_pushers vs _start_pushers confusion 2018-10-24 09:24:55 +01:00
Richard van der Hoff e564306e31 sanity-check the is_processing flag
... and rename it, for even more sanity
2018-10-24 09:23:33 +01:00
Neil Johnson a67d8ace9b remove errant exception and style 2018-10-23 17:44:39 +01:00
Travis Ralston 43c3f0b02f Merge pull request #3969 from turt2live/travis/fix-federated-group-requests
Handle HttpResponseException more safely for federated groups
2018-10-23 10:41:04 -06:00
Travis Ralston 3e704822be Comments help 2018-10-23 10:25:31 -06:00
Neil Johnson 329d18b39c remove white space 2018-10-23 15:27:20 +01:00
Neil Johnson 6105c6101f fix race condiftion in calling initialise_reserved_users 2018-10-23 15:24:58 +01:00
Richard van der Hoff b3f6dddad2 Give some more things logcontexts (#4077) 2018-10-23 14:29:17 +01:00
Richard van der Hoff 5c445114d3 Correctly account for cpu usage by background threads (#4074)
Wrap calls to deferToThread() in a thing which uses a child logcontext to
attribute CPU usage to the right request.

While we're in the area, remove the logcontext_tracer stuff, which is never
used, and afaik doesn't work.

Fixes #4064
2018-10-23 13:12:32 +01:00
Richard van der Hoff 1fe6bbb555 Merge pull request #3698 from spantaleev/add-matrix-docker-ansible-deploy
Add information about the matrix-docker-ansible-deploy playbook
2018-10-23 10:11:58 +01:00
Richard van der Hoff 047ac0cbba Merge pull request #4072 from steamp0rt/patch-1
Add Caddy example to README
2018-10-23 09:39:55 +01:00
Richard van der Hoff 6340141300 README.rst: fix minor grammar 2018-10-22 16:17:27 +01:00
Richard van der Hoff abd9914683 Changelog 2018-10-22 16:12:11 +01:00
Richard van der Hoff 026cd91ac8 Run PusherPool.start as a background process
We don't do anything with the result, so this is needed to give this code a
logcontext.
2018-10-22 16:12:11 +01:00
Richard van der Hoff f749607c91 Make on_started synchronous too
This brings it into line with on_new_notifications and on_new_receipts. It
requires a little bit of hoop-jumping in EmailPusher to load the throttle
params before the first loop.
2018-10-22 16:12:11 +01:00
Richard van der Hoff e7a16c6210 Remove redundant run_as_background_process() from pusherpool
`on_new_notifications` and `on_new_receipts` in `HttpPusher` and `EmailPusher`
now always return synchronously, so we can remove the `defer.gatherResults` on
their results, and the `run_as_background_process` wrappers can be removed too
because the PusherPool methods will now complete quickly enough.
2018-10-22 16:12:11 +01:00
Richard van der Hoff c7273c11bc Give pushers their own background logcontext
Each pusher has its own loop which runs for as long as it has work to do. This
should run in its own background thread with its own logcontext, as other
similar loops elsewhere in the system do - which means that CPU usage is
consistently attributed to that loop, rather than to whatever request happened
to start the loop.
2018-10-22 16:12:11 +01:00
Richard van der Hoff 5110f4e425 move get_all_pushers call down
simplifies the interface to _start_pushers
2018-10-22 16:12:11 +01:00
Richard van der Hoff 04277d0ed8 Factor PusherPool._start_pusher out of _start_pushers
... and use it from start_pusher_by_id. This mostly simplifies
start_pusher_by_id.
2018-10-22 16:12:11 +01:00
Richard van der Hoff 3e8b02c939 Rename _refresh_pusher
This is public (or at least, called from outside the class), so ought to have a
better name.
2018-10-22 16:12:11 +01:00
Richard van der Hoff 7aea00069c Merge pull request #4076 from matrix-org/rav/fix_init_logcontexts
Run MAU queries as background processes
2018-10-22 14:46:59 +01:00
Richard van der Hoff 911db96658 Merge pull request #4073 from matrix-org/rav/require_psutil
Make psutil an explicit dependency
2018-10-22 12:33:21 +01:00
Matthew Hodgson 058934b1cf uh, Matrix is called Matrix these days... 2018-10-21 12:18:30 +01:00
Richard van der Hoff a6f421e812 Run MAU queries as background processes
Fixes #3820
2018-10-20 02:14:35 +01:00
Amber Brown e1728dfcbe Make scripts/ and scripts-dev/ pass pyflakes (and the rest of the codebase on py3) (#4068) 2018-10-20 11:16:55 +11:00
steamport 5c3d6ea9c7 Whoops! 2018-10-19 22:00:27 +00:00
steamport 3f357583ce I HATE RST 2018-10-19 21:59:39 +00:00
steamport 9c2f99a3b7 Fix 2018-10-19 21:59:14 +00:00
steamport 08760b0d9a Fix formatting. 2018-10-19 21:57:28 +00:00
steamport b85fe45f46 Add CL 2018-10-19 21:55:38 +00:00
Richard van der Hoff e5b52d0f94 Make psutil an explicit dependency
As of #4027, we require psutil to be installed, so it should be in our
dependency list. We can also remove some of the conditional import code
introduced by #992.

Fixes #4062.
2018-10-19 21:51:15 +01:00
Richard van der Hoff 81d4f51524 Merge branch 'rav/fix_email_templates_4065' into develop 2018-10-19 21:37:32 +01:00
Richard van der Hoff 593389a077 Remove notes on fallback for email_templates
This fallback didn't work, and was removed in #4069.
2018-10-19 21:35:57 +01:00
steamport eba48c0f16 Add Caddy example to README 2018-10-19 19:58:28 +00:00
Richard van der Hoff f62c597d14 Merge pull request #4069 from matrix-org/rav/fix_email_templates_4065
Calculate absolute path for email templates
2018-10-19 16:33:54 +01:00
Erik Johnston 67f7b9cb50 pep8 2018-10-19 16:06:59 +01:00
Erik Johnston 056f099126 Merge branch 'develop' of github.com:matrix-org/synapse into erikj/purge_state_groups 2018-10-19 15:48:59 +01:00
Erik Johnston 47a9da28ca Batch process handling state groups 2018-10-19 15:48:15 +01:00
Richard van der Hoff cc325c7069 Calculate absolute path for email templates 2018-10-19 14:01:59 +01:00
Amber Brown e404ba9aac Fix manhole on py3 (pt 2) (#4067) 2018-10-19 22:26:00 +11:00
Amber Brown b69216f768 Make the metrics less racy (#4061) 2018-10-19 21:45:45 +11:00
Richard van der Hoff 6a4d01ee94 Merge pull request #4060 from matrix-org/hawkowl/ssh-key-py3
Make manhole work on Python 3 again
2018-10-19 10:23:44 +01:00
Erik Johnston 3c580c2b47 Add tests for alias creation rules 2018-10-19 10:22:45 +01:00
Erik Johnston 1b4bf232b9 Add tests for config generation 2018-10-19 10:22:45 +01:00
Erik Johnston 9fafdfa97d Anchor returned regex to start and end of string 2018-10-19 10:22:45 +01:00
Erik Johnston f9d6c677ea Newsfile 2018-10-19 10:22:45 +01:00
Erik Johnston 084046456e Add config option to control alias creation 2018-10-19 10:22:45 +01:00
Erik Johnston 0d31109ed5 Newsfile 2018-10-19 10:14:29 +01:00
Erik Johnston 74e7617083 Clean up room alias creation 2018-10-19 10:11:56 +01:00
Amber Brown 1d17fc52ae changelog 2018-10-19 09:27:10 +11:00
Amber Brown a36b0ec195 make a bytestring 2018-10-19 09:24:00 +11:00
Amber Brown 6190abe8da Merge pull request #4057 from matrix-org/rav/use_correct_python
Use the right python when starting workers
2018-10-19 09:09:08 +11:00
Richard van der Hoff c69026a758 Use the right python when starting workers
We should use the same python to start the workers as we do for the main
synapse (ie, the same one used to run synctl.)
2018-10-18 21:06:30 +01:00
Travis Ralston dba84fa69c Fix terms UI auth test 2018-10-18 12:45:21 -06:00
Travis Ralston 88c5ffec33 Test for terms UI auth 2018-10-18 12:35:30 -06:00
Richard van der Hoff 2baebace6a Merge branch 'master' into develop 2018-10-18 17:29:57 +01:00
Richard van der Hoff c00f4d237b Add warnings about the upgrade to 0.33.7 2018-10-18 17:17:39 +01:00
Travis Ralston 49a044aa5f Merge branch 'develop' into travis/login-terms 2018-10-18 09:57:58 -06:00
Richard van der Hoff 03287c350e remove redundant changelog file
this change has been released
2018-10-18 15:09:34 +01:00
Richard van der Hoff c632bc8654 Merge branch 'master' into develop 2018-10-18 15:07:03 +01:00
Richard van der Hoff 926da4dda8 0.33.7 2018-10-18 14:57:32 +01:00
Erik Johnston e77f24d80a Merge pull request #4049 from matrix-org/erikj/synctl_colour
Only colourise synctl output when attached to tty
2018-10-18 10:51:14 +01:00
Richard van der Hoff 8c2b8d7f0b fix changelog formatting 2018-10-17 17:42:12 +01:00
Richard van der Hoff c7d0f34a3c v0.33.7rc2 2018-10-17 17:40:19 +01:00
Richard van der Hoff 52e3d3813b prep changelog 2018-10-17 17:40:01 +01:00
Richard van der Hoff 0fd2321629 Fix incorrect truncation in get_missing_events
It's quite important that get_missing_events returns the *latest* events in the
room; however we were pulling event ids out of the database until we got *at
least* 10, and then taking the *earliest* of the results.

We also shouldn't really be relying on depth, and should be checking the
room_id.
2018-10-17 17:35:26 +01:00
Richard van der Hoff f1bfe6167a Merge pull request #4052 from matrix-org/rav/ship_resources_as_package_data
Ship the email templates as package_data
2018-10-17 17:34:22 +01:00
Erik Johnston 4e726783ea Merge pull request #4050 from matrix-org/erikj/fix_py37_iteration
Fix bug where we raised StopIteration in a generator
2018-10-17 17:07:19 +01:00
Erik Johnston a5aea15a6b Assume isatty is always defined, and catch AttributeError. Also don't bother checking colour==Normal 2018-10-17 17:06:49 +01:00
Richard van der Hoff c8f2c19991 Put the warning blob at the top of the file 2018-10-17 16:56:22 +01:00
Richard van der Hoff 1519572961 Ship the email templates as package_data
move the example email templates into the synapse package so that they can be
used as package data, which should mean that all of the packaging mechanisms
(pip, docker, debian, arch, etc) should now come with the example templates.

In order to grandfather in people who relied on the templates being in the old
place, check for that situation and fall back to using the defaults if the
templates directory does not exist.
2018-10-17 16:46:02 +01:00
Erik Johnston 3a5d8d5891 Newsfile 2018-10-17 16:12:45 +01:00
Erik Johnston f6a0a02a62 Fix bug where we raised StopIteration in a generator
This made python 3.7 unhappy
2018-10-17 16:10:52 +01:00
Erik Johnston 1af16acd4c Newsfile 2018-10-17 13:48:09 +01:00
Erik Johnston df33c164de Only colourise synctl output when attached to tty 2018-10-17 13:47:53 +01:00
Will Hunt d6a7797dd1 Fix roomlist since tokens on Python 3 (#4046)
Thanks @Half-Shot !!!
2018-10-17 23:04:55 +11:00
Richard van der Hoff 6ec9d8ba0a Merge pull request #4045 from matrix-org/rav/fix_get_missing_events
Fix incorrect truncation in get_missing_events
2018-10-17 11:40:03 +01:00
Neil Johnson c6584f4b5f clean up config error logic and imports 2018-10-17 11:36:41 +01:00
Amber Brown 80736fd8ed Merge pull request #4041 from matrix-org/rav/run_tests_in_docker
run the circle builds in docker containers
2018-10-17 20:10:44 +11:00
Richard van der Hoff fc0f13dd03 Fix incorrect truncation in get_missing_events
It's quite important that get_missing_events returns the *latest* events in the
room; however we were pulling event ids out of the database until we got *at
least* 10, and then taking the *earliest* of the results.

We also shouldn't really be relying on depth, and should be checking the
room_id.
2018-10-16 21:10:04 +01:00
Richard van der Hoff 10405153c2 Use wget rather than curl
the docker image doesn't have wget
2018-10-16 16:47:26 +01:00
Richard van der Hoff 017eb9d17a changelog 2018-10-16 16:31:47 +01:00
Erik Johnston 4a28d3d36f Update event_auth table for rejected events 2018-10-16 16:28:42 +01:00
Erik Johnston 15133477ee Fix up use of resolve_events_with_factory 2018-10-16 16:28:42 +01:00
Erik Johnston fc954960e9 Newsfile 2018-10-16 16:28:42 +01:00
Erik Johnston 947c7443eb Add some state res v2 tests 2018-10-16 16:28:39 +01:00
Erik Johnston 6bd856caa2 User event.sender rather than alias event.user_id 2018-10-16 16:16:13 +01:00
Erik Johnston e238013c44 Add v2 state res algorithm.
We hook this up to the vdh test room version.
2018-10-16 16:16:13 +01:00
Richard van der Hoff a94967bc5f run the circle builds in docker containers
Docker containers spin up faster than entire VMs.
2018-10-16 15:29:08 +01:00
Richard van der Hoff b8a5b0097c Various cleanups in the federation client code (#4031)
- Improve logging: log things in the right order, include destination and txids
  in all log lines, don't log successful responses twice

- Fix the docstring on TransportLayerClient.send_transaction

- Don't use treq.request, which is overcomplicated for our purposes: just use a
  twisted.web.client.Agent.

- simplify the logic for setting up the bodyProducer

- fix bytes/str confusions
2018-10-16 10:44:49 +01:00
Travis Ralston a8ed93a4b5 pep8 2018-10-15 16:10:29 -06:00
Travis Ralston 442734ff9e Ensure the terms params are actually provided 2018-10-15 14:56:13 -06:00
Travis Ralston 762a0982aa Python is hard 2018-10-15 14:46:09 -06:00
Travis Ralston f293d124b6 Merge branch 'develop' into travis/login-terms 2018-10-15 14:44:32 -06:00
Amber Brown 24bc15eab4 update changelog 2018-10-15 22:23:13 +11:00
Amber Brown 4e50fe3edb update changelog 2018-10-15 22:22:49 +11:00
Amber Brown f726f2dc6c version bump 2018-10-15 22:21:45 +11:00
David Baker 03c11032c3 Merge pull request #4019 from matrix-org/dbkr/e2e_backups
E2E backups
2018-10-15 10:19:43 +01:00
Amber Brown f9ce1b4eb0 Merge pull request #4033 from intelfx/py37-hotfixes
py3: python3.7 hotfixes
2018-10-15 20:13:19 +11:00
Slavi Pantaleev c187638ee9 Add information about the matrix-docker-ansible-deploy playbook
Signed-off-by: Slavi Pantaleev <slavi@devture.com>
2018-10-14 21:50:18 +03:00
Ivan Shapovalov 06bc8d2fe5 synapse/app: frontend_proxy.py: actually make workers work on py3 2018-10-14 20:08:39 +03:00
Ivan Shapovalov fb216a22db synapse/visibility.py: fix SyntaxError on py3.7 2018-10-14 20:08:17 +03:00
Neil Johnson 1ccafb0c5e no need to join room if creator 2018-10-13 21:14:21 +01:00
Travis Ralston dd99db846d Update login terms structure for the proposed language support 2018-10-12 18:03:27 -06:00
Travis Ralston 5119818e9d Rely on the lack of ?u to represent public access
also general cleanup
2018-10-12 18:03:17 -06:00
Travis Ralston 22a2004428 Update documentation and templates for new consent 2018-10-12 17:53:14 -06:00
Travis Ralston 7ede650956 Merge branch 'develop' into travis/login-terms 2018-10-12 16:24:07 -06:00
Travis Ralston 164f8e4843 isort 2018-10-12 15:11:59 -06:00
Travis Ralston 7bb651de6a More sane handling of group errors and pep8 2018-10-12 14:53:30 -06:00
Travis Ralston e3586f7c06 Merge branch 'develop' into travis/fix-federated-group-requests 2018-10-12 14:49:58 -06:00
Neil Johnson a2bfb778c8 improve auto room join logic, comments and tests 2018-10-12 18:17:36 +01:00
David Baker a45f2c3a00 missed one 2018-10-12 14:33:55 +01:00
Amber Brown 381d2cfdf0 Make workers work on Py3 (#4027) 2018-10-13 00:14:08 +11:00
Erik Johnston 67a1e315cc Fix up comments 2018-10-12 13:49:48 +01:00
David Baker 8c0ff0287a Linting soothes the savage PEP8 monster 2018-10-12 13:47:43 +01:00
David Baker 306361b31b Misc PR feedback bits 2018-10-12 11:48:56 +01:00
David Baker bddfad253a Don't mangle exceptions 2018-10-12 11:48:02 +01:00
David Baker 86ef9760a7 Split /room_keys/version into 2 servlets 2018-10-12 11:35:08 +01:00
David Baker 83e72bb2f0 PR feedback pt. 1 2018-10-12 11:26:18 +01:00
Richard van der Hoff 8ddd0f273c Comments on get_all_new_events_stream
just some docstrings to clarify the behaviour here
2018-10-12 09:55:41 +01:00
Erik Johnston e97d93948d Merge pull request #4022 from matrix-org/erikj/metrics_lazy_loaded_count
Add metric to count lazy member sync requests
2018-10-10 14:39:18 +01:00
Erik Johnston 7e561b5c1a Add description to counter metric 2018-10-10 11:41:15 +01:00
Erik Johnston 49840f5ab2 Update newsfile 2018-10-10 11:31:02 +01:00
Erik Johnston 3cbe8331e6 Track number of non-empty sync responses instead 2018-10-10 11:23:17 +01:00
Erik Johnston 395276b405 Append _total to metric and fix up spelling 2018-10-10 09:24:39 +01:00
David Baker b8d9e108be Fix mergefail 2018-10-09 18:04:21 +01:00
Erik Johnston 20733857ab Newsfile 2018-10-09 14:18:16 +01:00
Erik Johnston bdc27d6716 Add metric to count lazy member sync requests 2018-10-09 14:17:52 +01:00
David Baker d34657e1f2 Add changelog 2018-10-09 11:15:54 +01:00
David Baker d3464ce708 isort 2018-10-09 10:33:59 +01:00
Erik Johnston 9eb1a79100 Merge pull request #4008 from matrix-org/erikj/log_looping_exceptions
Log looping call exceptions
2018-10-09 10:12:10 +01:00
David Baker dc045ef202 Merge remote-tracking branch 'origin/develop' into dbkr/e2e_backups 2018-10-09 10:05:02 +01:00
Richard van der Hoff 2418e7811a Merge pull request #4017 from matrix-org/rav/optimise_filter_events_for_server
Optimisation for filter_events_for_server
2018-10-09 09:48:56 +01:00
David Baker f4a4dbcad1 Apparently this blank line is Very Important 2018-10-09 09:47:04 +01:00
David Baker 0c905ee015 be python3 compatible 2018-10-09 09:39:13 +01:00
Erik Johnston 6982320572 Remove unnecessary extra function call layer 2018-10-08 14:06:19 +01:00
Richard van der Hoff 495975e231 Optimisation for filter_events_for_server
We're better off hashing just the event_id than the whole ((type, state_key),
event_id) tuple - so use a dict instead of a set.

Also, iteritems > items.
2018-10-08 13:46:52 +01:00
Erik Johnston 8a1817f0d2 Use errback pattern and catch async failures 2018-10-08 13:29:47 +01:00
David Baker 497444f1fd Don't reuse backup versions
Since we don't actually delete the keys, just mark the versions
as deleted in the db rather than actually deleting them, then we
won't reuse versions.

Fixes https://github.com/vector-im/riot-web/issues/7448
2018-10-05 15:08:36 +01:00
Erik Johnston 8164f6daf3 Newsfile 2018-10-05 11:25:09 +01:00
Erik Johnston f7199e8734 Log looping call exceptions
If a looping call function errors, then it kills the loop entirely.
Currently it throws away the exception logs, so we should make it
actually log them.

Fixes #3929
2018-10-05 11:24:12 +01:00
Neil Johnson ed82043efb Merge branch 'develop' into matthew/autocreate_autojoin 2018-10-04 17:26:59 +01:00
Neil Johnson 2dadc092b8 move logic into register, fix room alias localpart bug, tests 2018-10-04 17:00:27 +01:00
Richard van der Hoff c6dbd216e6 Merge pull request #3995 from matrix-org/rav/no_deextrem_outliers
Fix bug in forward_extremity update logic
2018-10-04 16:27:05 +01:00
Erik Johnston d9f3db5081 Newsfile 2018-10-04 16:03:08 +01:00
Erik Johnston 4917ff5523 Add state_group index to event_to_state_groups
This is needed to efficiently check for unreferenced state groups during
purge.
2018-10-04 16:03:08 +01:00
Erik Johnston 17d585753f Delete unreferened state groups during purge 2018-10-04 16:03:06 +01:00
Amber Brown d86794325f Merge branch 'master' into develop 2018-10-04 22:41:52 +10:00
Travis Ralston 158d6c75b6 Changelog 2018-10-03 17:54:08 -06:00
Travis Ralston 537d0b7b36 Use a flag rather than a new route for the public policy
This also means that the template now has optional parameters, which will need to be documented somehow.
2018-10-03 17:50:11 -06:00
Travis Ralston f9d34a763c Auto-consent to the privacy policy if the user registered with terms 2018-10-03 17:39:45 -06:00
Travis Ralston dfcad5fad5 Make the terms flow requried 2018-10-03 17:39:00 -06:00
Travis Ralston 3099d96dba Flesh out the fallback auth for terms 2018-10-03 17:39:00 -06:00
Travis Ralston 149c4f1765 Supply params for terms auth stage
As per https://github.com/matrix-org/matrix-doc/pull/1692
2018-10-03 15:57:42 -06:00
Travis Ralston fd99787162 Incorporate Dave's work for GDPR login flows
As per https://github.com/vector-im/riot-web/issues/7168#issuecomment-419996117
2018-10-03 15:57:42 -06:00
Erik Johnston 8935ec5a93 Merge pull request #3999 from matrix-org/erikj/fix_3pid_invite_rejetion
Fix handling of rejected threepid invites
2018-10-03 14:47:41 +01:00
Erik Johnston 81e2813948 Merge pull request #3996 from matrix-org/erikj/fix_bg_iteration
Fix exception in background metrics collection
2018-10-03 14:14:38 +01:00
Erik Johnston 52e6e815be Sanitise error messages when user doesn't have permission to invite 2018-10-03 14:13:07 +01:00
Erik Johnston 01afcfc4e9 Merge pull request #3997 from matrix-org/erikj/fix_profile_error_handling
Fix exception handling in fetching remote profiles
2018-10-03 14:11:09 +01:00
Erik Johnston 93a8603904 Newsfile 2018-10-03 11:59:05 +01:00
Erik Johnston 69e857853f Fix handling of rejected threepid invites 2018-10-03 11:57:30 +01:00
Erik Johnston 6e0c66f651 Newsfile 2018-10-03 11:40:02 +01:00
Erik Johnston 495a9d06bb Fix exception handling in fetching remote profiles 2018-10-03 11:34:30 +01:00
Erik Johnston c69faf8c4a Newsfile 2018-10-03 11:29:44 +01:00
Erik Johnston 7c570bff74 Fix exception in background metrics collection
We attempted to iterate through a list on a separate thread without
doing the necessary copying.
2018-10-03 11:28:01 +01:00
Richard van der Hoff 9693625e55 actually exclude outliers 2018-10-03 10:19:41 +01:00
Richard van der Hoff 2a4ea3baa8 fix newsfile name 2018-10-03 07:09:25 +01:00
Richard van der Hoff 3e39783d5d remove debugging 2018-10-02 23:44:14 +01:00
Richard van der Hoff ae61ade891 Fix bug in forward_extremity update logic
An event does not stop being a forward_extremity just because an outlier or
rejected event refers to it.
2018-10-02 23:36:08 +01:00
Matthew Hodgson faa462ef79 changelog 2018-09-29 02:21:01 +01:00
Matthew Hodgson 23b6a0537f emit room aliases event 2018-09-29 02:19:37 +01:00
Matthew Hodgson 5b68f29f48 fix thinkos 2018-09-29 02:14:40 +01:00
Matthew Hodgson 8f646f2d04 fix UTs 2018-09-28 15:37:28 +01:00
Matthew Hodgson 07340cdaca untested stab at autocreating autojoin rooms 2018-09-28 01:42:53 +01:00
Travis Ralston 82fa31799c Remove debugging statement 2018-09-26 14:01:02 -06:00
Travis Ralston 2a7b3439de Changelog 2018-09-26 13:51:34 -06:00
Travis Ralston b4c3bc1734 Handle HttpResponseException more safely for federated groups 2018-09-26 13:48:04 -06:00
Travis Ralston 219606a6ed Fix exception documentation in matrixfederationclient.py 2018-09-26 13:26:27 -06:00
David Baker bc74925c5b WIP e2e key backups
Continues from uhoreg's branch

This just fixed the errcode on /room_keys/version if no backup and
updates the schema delta to be on the latest so it gets run
2018-09-13 17:02:59 +01:00
Luca Weiss f8825748dd changelog.d entry somehow got lost 2018-09-11 12:56:31 +02:00
Luca Weiss a40802bcbc Fix build of Docker image with docker-compose
... and fix a typo
2018-09-11 12:11:22 +02:00
Hubert Chathi 3801b8aa03 try to make flake8 and isort happy 2018-09-06 11:35:19 -04:00
Hubert Chathi 16a31c6fce update to newer Synapse APIs 2018-08-24 22:51:25 -04:00
Hubert Chathi 83caead95a Merge branch 'develop' into e2e_backups 2018-08-24 11:44:26 -04:00
Hubert Chathi 42a394caa2 allow session_data to be any JSON instead of just a string 2018-08-21 14:51:34 -04:00
Hubert Chathi 8550a7e9c2 allow auth_data to be any JSON instead of a string 2018-08-21 10:38:00 -04:00
Matthew Hodgson 4f7064f6b5 missing import 2018-08-12 19:14:31 -04:00
Matthew Hodgson f0cede5556 missing import 2018-08-12 19:14:31 -04:00
Matthew Hodgson 54ac18e832 use parse_string 2018-08-12 19:14:31 -04:00
Matthew Hodgson 66a4ca1d28 404 nicely if you try to interact with a missing current version 2018-08-12 19:14:31 -04:00
Matthew Hodgson 72788cf9c1 support DELETE /version with no args 2018-08-12 19:14:31 -04:00
Matthew Hodgson edc427a351 flake8 2018-08-12 19:14:31 -04:00
Matthew Hodgson fe87890b18 implement remaining tests and make them work 2018-08-12 19:14:31 -04:00
Matthew Hodgson f6a3067868 linting 2018-08-12 19:14:31 -04:00
Matthew Hodgson 15d513f16f fix idiocies and so make tests pass 2018-08-12 19:14:31 -04:00
Matthew Hodgson 174be586e5 first cut at a UT 2018-08-12 19:14:31 -04:00
Matthew Hodgson b5eee511c7 don't needlessly return user_id 2018-08-12 19:14:31 -04:00
Matthew Hodgson 93d174bcc4 improve docstring 2018-08-12 19:14:31 -04:00
Matthew Hodgson 5e42c45c96 switch get_current_version_info back to being get_version_info 2018-08-12 19:14:31 -04:00
Matthew Hodgson 982edca380 fix flakes 2018-08-12 19:14:31 -04:00
Matthew Hodgson 234611f347 fix typos 2018-08-12 19:14:31 -04:00
Matthew Hodgson 14b3da63a3 add a tonne of docstring; make upload_room_keys properly assert version 2018-08-12 19:14:31 -04:00
Matthew Hodgson 9f0791b7bd add a tonne of docstring; make upload_room_keys properly assert version 2018-08-12 19:14:31 -04:00
Matthew Hodgson 9f500cb39e more docstring for the e2e_room_keys rest 2018-08-12 19:14:31 -04:00
Matthew Hodgson 8d14598e90 add storage docstring; remove unused set_e2e_room_keys 2018-08-12 19:14:31 -04:00
Matthew Hodgson ca0b052307 fix factoring out of _should_replace_room_key 2018-08-12 19:14:31 -04:00
Matthew Hodgson cac0253799 rename room_key_version table correctly, and fix opt args 2018-08-12 19:14:31 -04:00
Matthew Hodgson 0abb205b47 blindly incorporate PR review - needs testing & fixing 2018-08-12 19:14:31 -04:00
Matthew Hodgson 69e51c7ba4 make /room_keys/version work 2018-08-12 19:14:31 -04:00
Matthew Hodgson 8ae64b270f implement /room_keys/version too (untested) 2018-08-12 19:14:31 -04:00
Matthew Hodgson cf1e2000f6 document the API 2018-08-12 19:13:09 -04:00
Matthew Hodgson 6b8c07abc2 make it work and fix pep8 2018-08-12 19:13:09 -04:00
Matthew Hodgson 0bc4627a73 interim WIP checkin; doesn't build yet 2018-08-12 18:23:10 -04:00
Matthew Hodgson 53ace904b2 total WIP skeleton for /room_keys API 2018-08-12 18:23:10 -04:00
248 changed files with 11579 additions and 3336 deletions
+48 -41
View File
@@ -23,99 +23,106 @@ jobs:
- run: docker push matrixdotorg/synapse:latest
- run: docker push matrixdotorg/synapse:latest-py3
sytestpy2:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: docker pull matrixdotorg/sytest-synapsepy2
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs matrixdotorg/sytest-synapsepy2
- run: /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy2postgres:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: docker pull matrixdotorg/sytest-synapsepy2
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs -e POSTGRES=1 matrixdotorg/sytest-synapsepy2
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy2merged:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: docker pull matrixdotorg/sytest-synapsepy2
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs matrixdotorg/sytest-synapsepy2
- run: /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy2postgresmerged:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy2
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: docker pull matrixdotorg/sytest-synapsepy2
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs -e POSTGRES=1 matrixdotorg/sytest-synapsepy2
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy3:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: docker pull matrixdotorg/sytest-synapsepy3
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs matrixdotorg/sytest-synapsepy3
- run: /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy3postgres:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: docker pull matrixdotorg/sytest-synapsepy3
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs -e POSTGRES=1 matrixdotorg/sytest-synapsepy3
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy3merged:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: docker pull matrixdotorg/sytest-synapsepy3
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs matrixdotorg/sytest-synapsepy3
- run: /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
sytestpy3postgresmerged:
machine: true
docker:
- image: matrixdotorg/sytest-synapsepy3
working_directory: /src
steps:
- checkout
- run: bash .circleci/merge_base_branch.sh
- run: docker pull matrixdotorg/sytest-synapsepy3
- run: docker run --rm -it -v $(pwd)\:/src -v $(pwd)/logs\:/logs -e POSTGRES=1 matrixdotorg/sytest-synapsepy3
- run: POSTGRES=1 /synapse_sytest.sh
- store_artifacts:
path: ~/project/logs
path: /logs
destination: logs
- store_test_results:
path: logs
path: /logs
workflows:
version: 2
+2 -2
View File
@@ -16,7 +16,7 @@ then
GITBASE="develop"
else
# Get the reference, using the GitHub API
GITBASE=`curl -q https://api.github.com/repos/matrix-org/synapse/pulls/${CIRCLE_PR_NUMBER} | jq -r '.base.ref'`
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
@@ -31,4 +31,4 @@ git fetch -u origin $GITBASE
git merge --no-edit origin/$GITBASE
# Show what we are after.
git show -s
git show -s
+12
View File
@@ -0,0 +1,12 @@
[run]
branch = True
parallel = True
source = synapse
[paths]
source=
coverage
[report]
precision = 2
ignore_errors = True
@@ -1,3 +1,9 @@
---
name: Bug report
about: Create a report to help us improve
---
<!--
**IF YOU HAVE SUPPORT QUESTIONS ABOUT RUNNING OR CONFIGURING YOUR OWN HOME SERVER**:
@@ -11,38 +17,50 @@ the necessary data to fix your issue.
You can also preview your report before submitting it. You may remove sections
that aren't relevant to your particular case.
Text between <!-- and --> marks will be invisible in the report.
Text between <!-- and --> marks will be invisible in the report.
-->
### Description
Describe here the problem that you are experiencing, or the feature you are requesting.
<!-- Describe here the problem that you are experiencing -->
### Steps to reproduce
- For bugs, list the steps
- list the steps
- that reproduce the bug
- using hyphens as bullet points
<!--
Describe how what happens differs from what you expected.
<!-- If you can identify any relevant log snippets from _homeserver.log_, please include
If you can identify any relevant log snippets from _homeserver.log_, please include
those (please be careful to remove any personal or private data). Please surround them with
``` (three backticks, on a line on their own), so that they are formatted legibly. -->
``` (three backticks, on a line on their own), so that they are formatted legibly.
-->
### Version information
<!-- IMPORTANT: please answer the following questions, to help us narrow down the problem -->
- **Homeserver**: Was this issue identified on matrix.org or another homeserver?
<!-- Was this issue identified on matrix.org or another homeserver? -->
- **Homeserver**:
If not matrix.org:
- **Version**: What version of Synapse is running? <!--
<!--
What version of Synapse is running?
You can find the Synapse version by inspecting the server headers (replace matrix.org with
your own homeserver domain):
$ curl -v https://matrix.org/_matrix/client/versions 2>&1 | grep "Server:"
-->
- **Install method**: package manager/git clone/pip
- **Platform**: Tell us about the environment in which your homeserver is operating
- distro, hardware, if it's running in a vm/container, etc.
- **Version**:
- **Install method**:
<!-- examples: package manager/git clone/pip -->
- **Platform**:
<!--
Tell us about the environment in which your homeserver is operating
distro, hardware, if it's running in a vm/container, etc.
-->
@@ -0,0 +1,9 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Description:**
<!-- Describe here the feature you are requesting. -->
@@ -0,0 +1,9 @@
---
name: Support request
about: I need support for Synapse
---
# Please ask for support in [**#matrix:matrix.org**](https://matrix.to/#/#matrix:matrix.org)
## Don't file an issue as a support request.
+7
View File
@@ -0,0 +1,7 @@
### Pull Request Checklist
<!-- Please read CONTRIBUTING.rst before submitting your pull request -->
* [ ] Pull request is based on the develop branch
* [ ] Pull request includes a [changelog file](CONTRIBUTING.rst#changelog)
* [ ] Pull request includes a [sign off](CONTRIBUTING.rst#sign-off)
+3
View File
@@ -0,0 +1,3 @@
[**#matrix:matrix.org**](https://matrix.to/#/#matrix:matrix.org) is the official support room for Matrix, and can be accessed by any client from https://matrix.org/docs/projects/try-matrix-now.html
It can also be access via IRC bridge at irc://irc.freenode.net/matrix or on the web here: https://webchat.freenode.net/?channels=matrix
+36 -15
View File
@@ -1,27 +1,45 @@
sudo: false
language: python
# tell travis to cache ~/.cache/pip
cache: pip
cache:
directories:
# we only bother to cache the wheels; parts of the http cache get
# invalidated every build (because they get served with a max-age of 600
# seconds), which means that we end up re-uploading the whole cache for
# every build, which is time-consuming In any case, it's not obvious that
# downloading the cache from S3 would be much faster than downloading the
# originals from pypi.
#
- $HOME/.cache/pip/wheels
before_script:
- git remote set-branches --add origin develop
- git fetch origin develop
# don't clone the whole repo history, one commit will do
git:
depth: 1
# only build branches we care about (PRs are built seperately)
branches:
only:
- master
- develop
- /^release-v/
# When running the tox environments that call Twisted Trial, we can pass the -j
# flag to run the tests concurrently. We set this to 2 for CPU bound tests
# (SQLite) and 4 for I/O bound tests (PostgreSQL).
matrix:
fast_finish: true
include:
- python: 2.7
env: TOX_ENV=packaging
- python: 2.7
env: TOX_ENV=pep8
- python: 3.6
env: TOX_ENV="pep8,check_isort"
- python: 2.7
env: TOX_ENV=py27
env: TOX_ENV=py27 TRIAL_FLAGS="-j 2"
- python: 2.7
env: TOX_ENV=py27-old
env: TOX_ENV=py27-old TRIAL_FLAGS="-j 2"
- python: 2.7
env: TOX_ENV=py27-postgres TRIAL_FLAGS="-j 4"
@@ -29,21 +47,24 @@ matrix:
- postgresql
- python: 3.5
env: TOX_ENV=py35
env: TOX_ENV=py35 TRIAL_FLAGS="-j 2"
- python: 3.6
env: TOX_ENV=py36
env: TOX_ENV=py36 TRIAL_FLAGS="-j 2"
- python: 3.6
env: TOX_ENV=py36-postgres TRIAL_FLAGS="-j 4"
services:
- postgresql
- python: 3.6
env: TOX_ENV=check_isort
- python: 3.6
- # we only need to check for the newsfragment if it's a PR build
if: type = pull_request
python: 3.6
env: TOX_ENV=check-newsfragment
script:
- git remote set-branches --add origin develop
- git fetch origin develop
- tox -e $TOX_ENV
install:
- pip install tox
+179
View File
@@ -1,3 +1,182 @@
Synapse 0.33.9 (2018-11-19)
===========================
No significant changes.
Synapse 0.33.9rc1 (2018-11-14)
==============================
Features
--------
- Include flags to optionally add `m.login.terms` to the registration flow when consent tracking is enabled. ([\#4004](https://github.com/matrix-org/synapse/issues/4004), [\#4133](https://github.com/matrix-org/synapse/issues/4133), [\#4142](https://github.com/matrix-org/synapse/issues/4142), [\#4184](https://github.com/matrix-org/synapse/issues/4184))
- Support for replacing rooms with new ones ([\#4091](https://github.com/matrix-org/synapse/issues/4091), [\#4099](https://github.com/matrix-org/synapse/issues/4099), [\#4100](https://github.com/matrix-org/synapse/issues/4100), [\#4101](https://github.com/matrix-org/synapse/issues/4101))
Bugfixes
--------
- Fix exceptions when using the email mailer on Python 3. ([\#4095](https://github.com/matrix-org/synapse/issues/4095))
- Fix e2e key backup with more than 9 backup versions ([\#4113](https://github.com/matrix-org/synapse/issues/4113))
- Searches that request profile info now no longer fail with a 500. ([\#4122](https://github.com/matrix-org/synapse/issues/4122))
- fix return code of empty key backups ([\#4123](https://github.com/matrix-org/synapse/issues/4123))
- If the typing stream ID goes backwards (as on a worker when the master restarts), the worker's typing handler will no longer erroneously report rooms containing new typing events. ([\#4127](https://github.com/matrix-org/synapse/issues/4127))
- Fix table lock of device_lists_remote_cache which could freeze the application ([\#4132](https://github.com/matrix-org/synapse/issues/4132))
- Fix exception when using state res v2 algorithm ([\#4135](https://github.com/matrix-org/synapse/issues/4135))
- Generating the user consent URI no longer fails on Python 3. ([\#4140](https://github.com/matrix-org/synapse/issues/4140), [\#4163](https://github.com/matrix-org/synapse/issues/4163))
- Loading URL previews from the DB cache on Postgres will no longer cause Unicode type errors when responding to the request, and URL previews will no longer fail if the remote server returns a Content-Type header with the chartype in quotes. ([\#4157](https://github.com/matrix-org/synapse/issues/4157))
- The hash_password script now works on Python 3. ([\#4161](https://github.com/matrix-org/synapse/issues/4161))
- Fix noop checks when updating device keys, reducing spurious device list update notifications. ([\#4164](https://github.com/matrix-org/synapse/issues/4164))
Deprecations and Removals
-------------------------
- The disused and un-specced identicon generator has been removed. ([\#4106](https://github.com/matrix-org/synapse/issues/4106))
- The obsolete and non-functional /pull federation endpoint has been removed. ([\#4118](https://github.com/matrix-org/synapse/issues/4118))
- The deprecated v1 key exchange endpoints have been removed. ([\#4119](https://github.com/matrix-org/synapse/issues/4119))
- Synapse will no longer fetch keys using the fallback deprecated v1 key exchange method and will now always use v2. ([\#4120](https://github.com/matrix-org/synapse/issues/4120))
Internal Changes
----------------
- Fix build of Docker image with docker-compose ([\#3778](https://github.com/matrix-org/synapse/issues/3778))
- Delete unreferenced state groups during history purge ([\#4006](https://github.com/matrix-org/synapse/issues/4006))
- The "Received rdata" log messages on workers is now logged at DEBUG, not INFO. ([\#4108](https://github.com/matrix-org/synapse/issues/4108))
- Reduce replication traffic for device lists ([\#4109](https://github.com/matrix-org/synapse/issues/4109))
- Fix `synapse_replication_tcp_protocol_*_commands` metric label to be full command name, rather than just the first character ([\#4110](https://github.com/matrix-org/synapse/issues/4110))
- Log some bits about room creation ([\#4121](https://github.com/matrix-org/synapse/issues/4121))
- Fix `tox` failure on old systems ([\#4124](https://github.com/matrix-org/synapse/issues/4124))
- Add STATE_V2_TEST room version ([\#4128](https://github.com/matrix-org/synapse/issues/4128))
- Clean up event accesses and tests ([\#4137](https://github.com/matrix-org/synapse/issues/4137))
- The default logging config will now set an explicit log file encoding of UTF-8. ([\#4138](https://github.com/matrix-org/synapse/issues/4138))
- Add helpers functions for getting prev and auth events of an event ([\#4139](https://github.com/matrix-org/synapse/issues/4139))
- Add some tests for the HTTP pusher. ([\#4149](https://github.com/matrix-org/synapse/issues/4149))
- add purge_history.sh and purge_remote_media.sh scripts to contrib/ ([\#4155](https://github.com/matrix-org/synapse/issues/4155))
- HTTP tests have been refactored to contain less boilerplate. ([\#4156](https://github.com/matrix-org/synapse/issues/4156))
- Drop incoming events from federation for unknown rooms ([\#4165](https://github.com/matrix-org/synapse/issues/4165))
Synapse 0.33.8 (2018-11-01)
===========================
No significant changes.
Synapse 0.33.8rc2 (2018-10-31)
==============================
Bugfixes
--------
- Searches that request profile info now no longer fail with a 500. Fixes
a regression in 0.33.8rc1. ([\#4122](https://github.com/matrix-org/synapse/issues/4122))
Synapse 0.33.8rc1 (2018-10-29)
==============================
Features
--------
- Servers with auto-join rooms will now automatically create those rooms when the first user registers ([\#3975](https://github.com/matrix-org/synapse/issues/3975))
- Add config option to control alias creation ([\#4051](https://github.com/matrix-org/synapse/issues/4051))
- The register_new_matrix_user script is now ported to Python 3. ([\#4085](https://github.com/matrix-org/synapse/issues/4085))
- Configure Docker image to listen on both ipv4 and ipv6. ([\#4089](https://github.com/matrix-org/synapse/issues/4089))
Bugfixes
--------
- Fix HTTP error response codes for federated group requests. ([\#3969](https://github.com/matrix-org/synapse/issues/3969))
- Fix issue where Python 3 users couldn't paginate /publicRooms ([\#4046](https://github.com/matrix-org/synapse/issues/4046))
- Fix URL previewing to work in Python 3.7 ([\#4050](https://github.com/matrix-org/synapse/issues/4050))
- synctl will use the right python executable to run worker processes ([\#4057](https://github.com/matrix-org/synapse/issues/4057))
- Manhole now works again on Python 3, instead of failing with a "couldn't match all kex parts" when connecting. ([\#4060](https://github.com/matrix-org/synapse/issues/4060), [\#4067](https://github.com/matrix-org/synapse/issues/4067))
- Fix some metrics being racy and causing exceptions when polled by Prometheus. ([\#4061](https://github.com/matrix-org/synapse/issues/4061))
- Fix bug which prevented email notifications from being sent unless an absolute path was given for `email_templates`. ([\#4068](https://github.com/matrix-org/synapse/issues/4068))
- Correctly account for cpu usage by background threads ([\#4074](https://github.com/matrix-org/synapse/issues/4074))
- Fix race condition where config defined reserved users were not being added to
the monthly active user list prior to the homeserver reactor firing up ([\#4081](https://github.com/matrix-org/synapse/issues/4081))
- Fix bug which prevented backslashes being used in event field filters ([\#4083](https://github.com/matrix-org/synapse/issues/4083))
Internal Changes
----------------
- Add information about the [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy) playbook ([\#3698](https://github.com/matrix-org/synapse/issues/3698))
- Add initial implementation of new state resolution algorithm ([\#3786](https://github.com/matrix-org/synapse/issues/3786))
- Reduce database load when fetching state groups ([\#4011](https://github.com/matrix-org/synapse/issues/4011))
- Various cleanups in the federation client code ([\#4031](https://github.com/matrix-org/synapse/issues/4031))
- Run the CircleCI builds in docker containers ([\#4041](https://github.com/matrix-org/synapse/issues/4041))
- Only colourise synctl output when attached to tty ([\#4049](https://github.com/matrix-org/synapse/issues/4049))
- Refactor room alias creation code ([\#4063](https://github.com/matrix-org/synapse/issues/4063))
- Make the Python scripts in the top-level scripts folders meet pep8 and pass flake8. ([\#4068](https://github.com/matrix-org/synapse/issues/4068))
- The README now contains example for the Caddy web server. Contributed by steamp0rt. ([\#4072](https://github.com/matrix-org/synapse/issues/4072))
- Add psutil as an explicit dependency ([\#4073](https://github.com/matrix-org/synapse/issues/4073))
- Clean up threading and logcontexts in pushers ([\#4075](https://github.com/matrix-org/synapse/issues/4075))
- Correctly manage logcontexts during startup to fix some "Unexpected logging context" warnings ([\#4076](https://github.com/matrix-org/synapse/issues/4076))
- Give some more things logcontexts ([\#4077](https://github.com/matrix-org/synapse/issues/4077))
- Clean up some bits of code which were flagged by the linter ([\#4082](https://github.com/matrix-org/synapse/issues/4082))
Synapse 0.33.7 (2018-10-18)
===========================
**Warning**: This release removes the example email notification templates from
`res/templates` (they are now internal to the python package). This should only
affect you if you (a) deploy your Synapse instance from a git checkout or a
github snapshot URL, and (b) have email notifications enabled.
If you have email notifications enabled, you should ensure that
`email.template_dir` is either configured to point at a directory where you
have installed customised templates, or leave it unset to use the default
templates.
Synapse 0.33.7rc2 (2018-10-17)
==============================
Features
--------
- Ship the example email templates as part of the package ([\#4052](https://github.com/matrix-org/synapse/issues/4052))
Bugfixes
--------
- Fix bug which made get_missing_events return too few events ([\#4045](https://github.com/matrix-org/synapse/issues/4045))
Synapse 0.33.7rc1 (2018-10-15)
==============================
Features
--------
- Add support for end-to-end key backup (MSC1687) ([\#4019](https://github.com/matrix-org/synapse/issues/4019))
Bugfixes
--------
- Fix bug in event persistence logic which caused 'NoneType is not iterable' ([\#3995](https://github.com/matrix-org/synapse/issues/3995))
- Fix exception in background metrics collection ([\#3996](https://github.com/matrix-org/synapse/issues/3996))
- Fix exception handling in fetching remote profiles ([\#3997](https://github.com/matrix-org/synapse/issues/3997))
- Fix handling of rejected threepid invites ([\#3999](https://github.com/matrix-org/synapse/issues/3999))
- Workers now start on Python 3. ([\#4027](https://github.com/matrix-org/synapse/issues/4027))
- Synapse now starts on Python 3.7. ([\#4033](https://github.com/matrix-org/synapse/issues/4033))
Internal Changes
----------------
- Log exceptions in looping calls ([\#4008](https://github.com/matrix-org/synapse/issues/4008))
- Optimisation for serving federation requests ([\#4017](https://github.com/matrix-org/synapse/issues/4017))
- Add metric to count number of non-empty sync responses ([\#4022](https://github.com/matrix-org/synapse/issues/4022))
Synapse 0.33.6 (2018-10-04)
===========================
+2 -1
View File
@@ -12,12 +12,12 @@ recursive-include synapse/storage/schema *.sql
recursive-include synapse/storage/schema *.py
recursive-include docs *
recursive-include res *
recursive-include scripts *
recursive-include scripts-dev *
recursive-include synapse *.pyi
recursive-include tests *.py
recursive-include synapse/res *
recursive-include synapse/static *.css
recursive-include synapse/static *.gif
recursive-include synapse/static *.html
@@ -34,6 +34,7 @@ prune .github
prune demo/etc
prune docker
prune .circleci
prune .coveragerc
exclude jenkins*
recursive-exclude jenkins *.sh
+22 -6
View File
@@ -142,7 +142,7 @@ Installing prerequisites on openSUSE::
Installing prerequisites on OpenBSD::
doas pkg_add python libffi py-pip py-setuptools sqlite3 py-virtualenv \
libxslt
libxslt jpeg
To install the Synapse homeserver run::
@@ -174,6 +174,12 @@ Alternatively, Andreas Peters (previously Silvio Fricke) has contributed a
Dockerfile to automate a synapse server in a single Docker image, at
https://hub.docker.com/r/avhost/docker-matrix/tags/
Slavi Pantaleev has created an Ansible playbook,
which installs the offical Docker image of Matrix Synapse
along with many other Matrix-related services (Postgres database, riot-web, coturn, mxisd, SSL support, etc.).
For more details, see
https://github.com/spantaleev/matrix-docker-ansible-deploy
Configuring Synapse
-------------------
@@ -651,7 +657,8 @@ Using a reverse proxy with Synapse
It is recommended to put a reverse proxy such as
`nginx <https://nginx.org/en/docs/http/ngx_http_proxy_module.html>`_,
`Apache <https://httpd.apache.org/docs/current/mod/mod_proxy_http.html>`_ or
`Apache <https://httpd.apache.org/docs/current/mod/mod_proxy_http.html>`_,
`Caddy <https://caddyserver.com/docs/proxy>`_ or
`HAProxy <https://www.haproxy.org/>`_ in front of Synapse. One advantage of
doing so is that it means that you can expose the default https port (443) to
Matrix clients without needing to run Synapse with root privileges.
@@ -682,7 +689,15 @@ so an example nginx configuration might look like::
}
}
and an example apache configuration may look like::
an example Caddy configuration might look like::
matrix.example.com {
proxy /_matrix http://localhost:8008 {
transparent
}
}
and an example Apache configuration might look like::
<VirtualHost *:443>
SSLEngine on
@@ -714,9 +729,10 @@ port:
.. __: `key_management`_
* Synapse does not currently support SNI on the federation protocol
(`bug #1491 <https://github.com/matrix-org/synapse/issues/1491>`_), which
means that using name-based virtual hosting is unreliable.
* Until v0.33.3, Synapse did not support SNI on the federation port
(`bug #1491 <https://github.com/matrix-org/synapse/issues/1491>`_). This bug
is now fixed, but means that federating with older servers can be unreliable
when using name-based virtual hosting.
Furthermore, a number of the normal reasons for using a reverse-proxy do not
apply:
+13
View File
@@ -48,6 +48,19 @@ returned by the Client-Server API:
# configured on port 443.
curl -kv https://<host.name>/_matrix/client/versions 2>&1 | grep "Server:"
Upgrading to v0.33.7
====================
This release removes the example email notification templates from
``res/templates`` (they are now internal to the python package). This should
only affect you if you (a) deploy your Synapse instance from a git checkout or
a github snapshot URL, and (b) have email notifications enabled.
If you have email notifications enabled, you should ensure that
``email.template_dir`` is either configured to point at a directory where you
have installed customised templates, or leave it unset to use the default
templates.
Upgrading to v0.27.3
====================
+1
View File
@@ -0,0 +1 @@
Add option to track MAU stats (but not limit people)
+1
View File
@@ -0,0 +1 @@
The media repository now no longer fails to decode UTF-8 filenames when downloading remote media.
+1
View File
@@ -0,0 +1 @@
A coveragerc file, as well as the py36-coverage tox target, have been added.
+1
View File
@@ -0,0 +1 @@
Add a GitHub pull request template and add multiple issue templates
+1
View File
@@ -0,0 +1 @@
URL previews now correctly decode non-UTF-8 text if the header contains a `<meta http-equiv="Content-Type"` header.
+1
View File
@@ -0,0 +1 @@
Update README to reflect the fact that #1491 is fixed
+1
View File
@@ -0,0 +1 @@
Fix an issue where public consent URLs had two slashes.
+1
View File
@@ -0,0 +1 @@
Add missing `jpeg` package prerequisite for OpenBSD in README.
+1
View File
@@ -0,0 +1 @@
Fallback auth now accepts the session parameter on Python 3.
+1
View File
@@ -0,0 +1 @@
Add a note saying you need to manually reclaim disk space after using the Purge History API
+1
View File
@@ -0,0 +1 @@
Fix logcontext leaks in EmailPusher and in tests
+1
View File
@@ -0,0 +1 @@
Remove riot.im from the list of trusted Identity Servers in the default configuration
+5 -3
View File
@@ -6,9 +6,11 @@ version: '3'
services:
synapse:
build: ../..
build:
context: ../..
dockerfile: docker/Dockerfile
image: docker.io/matrixdotorg/synapse:latest
# Since snyapse does not retry to connect to the database, restart upon
# Since synapse does not retry to connect to the database, restart upon
# failure
restart: unless-stopped
# See the readme for a full documentation of the environment settings
@@ -47,4 +49,4 @@ services:
# You may store the database tables in a local folder..
- ./schemas:/var/lib/postgresql/data
# .. or store them on some high performance storage for better results
# - /path/to/ssd/storage:/var/lib/postfesql/data
# - /path/to/ssd/storage:/var/lib/postgresql/data
+16
View File
@@ -0,0 +1,16 @@
Purge history API examples
==========================
# `purge_history.sh`
A bash file, that uses the [purge history API](/docs/admin_api/README.rst) to
purge all messages in a list of rooms up to a certain event. You can select a
timeframe or a number of messages that you want to keep in the room.
Just configure the variables DOMAIN, ADMIN, ROOMS_ARRAY and TIME at the top of
the script.
# `purge_remote_media.sh`
A bash file, that uses the [purge history API](/docs/admin_api/README.rst) to
purge all old cached remote media.
+141
View File
@@ -0,0 +1,141 @@
#!/bin/bash
# this script will use the api:
# https://github.com/matrix-org/synapse/blob/master/docs/admin_api/purge_history_api.rst
#
# It will purge all messages in a list of rooms up to a cetrain event
###################################################################################################
# define your domain and admin user
###################################################################################################
# add this user as admin in your home server:
DOMAIN=yourserver.tld
# add this user as admin in your home server:
ADMIN="@you_admin_username:$DOMAIN"
API_URL="$DOMAIN:8008/_matrix/client/r0"
###################################################################################################
#choose the rooms to prune old messages from (add a free comment at the end)
###################################################################################################
# the room_id's you can get e.g. from your Riot clients "View Source" button on each message
ROOMS_ARRAY=(
'!DgvjtOljKujDBrxyHk:matrix.org#riot:matrix.org'
'!QtykxKocfZaZOUrTwp:matrix.org#Matrix HQ'
)
# ALTERNATIVELY:
# you can select all the rooms that are not encrypted and loop over the result:
# SELECT room_id FROM rooms WHERE room_id NOT IN (SELECT DISTINCT room_id FROM events WHERE type ='m.room.encrypted')
# or
# select all rooms with at least 100 members:
# SELECT q.room_id FROM (select count(*) as numberofusers, room_id FROM current_state_events WHERE type ='m.room.member'
# GROUP BY room_id) AS q LEFT JOIN room_aliases a ON q.room_id=a.room_id WHERE q.numberofusers > 100 ORDER BY numberofusers desc
###################################################################################################
# evaluate the EVENT_ID before which should be pruned
###################################################################################################
# choose a time before which the messages should be pruned:
TIME='12 months ago'
# ALTERNATIVELY:
# a certain time:
# TIME='2016-08-31 23:59:59'
# creates a timestamp from the given time string:
UNIX_TIMESTAMP=$(date +%s%3N --date='TZ="UTC+2" '"$TIME")
# ALTERNATIVELY:
# prune all messages that are older than 1000 messages ago:
# LAST_MESSAGES=1000
# SQL_GET_EVENT="SELECT event_id from events WHERE type='m.room.message' AND room_id ='$ROOM' ORDER BY received_ts DESC LIMIT 1 offset $(($LAST_MESSAGES - 1))"
# ALTERNATIVELY:
# select the EVENT_ID manually:
#EVENT_ID='$1471814088343495zpPNI:matrix.org' # an example event from 21st of Aug 2016 by Matthew
###################################################################################################
# make the admin user a server admin in the database with
###################################################################################################
# psql -A -t --dbname=synapse -c "UPDATE users SET admin=1 WHERE name LIKE '$ADMIN'"
###################################################################################################
# database function
###################################################################################################
sql (){
# for sqlite3:
#sqlite3 homeserver.db "pragma busy_timeout=20000;$1" | awk '{print $2}'
# for postgres:
psql -A -t --dbname=synapse -c "$1" | grep -v 'Pager'
}
###################################################################################################
# get an access token
###################################################################################################
# for example externally by watching Riot in your browser's network inspector
# or internally on the server locally, use this:
TOKEN=$(sql "SELECT token FROM access_tokens WHERE user_id='$ADMIN' ORDER BY id DESC LIMIT 1")
AUTH="Authorization: Bearer $TOKEN"
###################################################################################################
# check, if your TOKEN works. For example this works:
###################################################################################################
# $ curl --header "$AUTH" "$API_URL/rooms/$ROOM/state/m.room.power_levels"
###################################################################################################
# finally start pruning the room:
###################################################################################################
POSTDATA='{"delete_local_events":"true"}' # this will really delete local events, so the messages in the room really disappear unless they are restored by remote federation
for ROOM in "${ROOMS_ARRAY[@]}"; do
echo "########################################### $(date) ################# "
echo "pruning room: $ROOM ..."
ROOM=${ROOM%#*}
#set -x
echo "check for alias in db..."
# for postgres:
sql "SELECT * FROM room_aliases WHERE room_id='$ROOM'"
echo "get event..."
# for postgres:
EVENT_ID=$(sql "SELECT event_id FROM events WHERE type='m.room.message' AND received_ts<'$UNIX_TIMESTAMP' AND room_id='$ROOM' ORDER BY received_ts DESC LIMIT 1;")
if [ "$EVENT_ID" == "" ]; then
echo "no event $TIME"
else
echo "event: $EVENT_ID"
SLEEP=2
set -x
# call purge
OUT=$(curl --header "$AUTH" -s -d $POSTDATA POST "$API_URL/admin/purge_history/$ROOM/$EVENT_ID")
PURGE_ID=$(echo "$OUT" |grep purge_id|cut -d'"' -f4 )
if [ "$PURGE_ID" == "" ]; then
# probably the history purge is already in progress for $ROOM
: "continuing with next room"
else
while : ; do
# get status of purge and sleep longer each time if still active
sleep $SLEEP
STATUS=$(curl --header "$AUTH" -s GET "$API_URL/admin/purge_history_status/$PURGE_ID" |grep status|cut -d'"' -f4)
: "$ROOM --> Status: $STATUS"
[[ "$STATUS" == "active" ]] || break
SLEEP=$((SLEEP + 1))
done
fi
set +x
sleep 1
fi
done
###################################################################################################
# additionally
###################################################################################################
# to benefit from pruning large amounts of data, you need to call VACUUM to free the unused space.
# This can take a very long time (hours) and the client have to be stopped while you do so:
# $ synctl stop
# $ sqlite3 -line homeserver.db "vacuum;"
# $ synctl start
# This could be set, so you don't need to prune every time after deleting some rows:
# $ sqlite3 homeserver.db "PRAGMA auto_vacuum = FULL;"
# be cautious, it could make the database somewhat slow if there are a lot of deletions
exit
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
DOMAIN=yourserver.tld
# add this user as admin in your home server:
ADMIN="@you_admin_username:$DOMAIN"
API_URL="$DOMAIN:8008/_matrix/client/r0"
# choose a time before which the messages should be pruned:
# TIME='2016-08-31 23:59:59'
TIME='12 months ago'
# creates a timestamp from the given time string:
UNIX_TIMESTAMP=$(date +%s%3N --date='TZ="UTC+2" '"$TIME")
###################################################################################################
# database function
###################################################################################################
sql (){
# for sqlite3:
#sqlite3 homeserver.db "pragma busy_timeout=20000;$1" | awk '{print $2}'
# for postgres:
psql -A -t --dbname=synapse -c "$1" | grep -v 'Pager'
}
###############################################################################
# make the admin user a server admin in the database with
###############################################################################
# sql "UPDATE users SET admin=1 WHERE name LIKE '$ADMIN'"
###############################################################################
# get an access token
###############################################################################
# for example externally by watching Riot in your browser's network inspector
# or internally on the server locally, use this:
TOKEN=$(sql "SELECT token FROM access_tokens WHERE user_id='$ADMIN' ORDER BY id DESC LIMIT 1")
###############################################################################
# check, if your TOKEN works. For example this works:
###############################################################################
# curl --header "Authorization: Bearer $TOKEN" "$API_URL/rooms/$ROOM/state/m.room.power_levels"
###############################################################################
# optional check size before
###############################################################################
# echo calculate used storage before ...
# du -shc ../.synapse/media_store/*
###############################################################################
# finally start pruning media:
###############################################################################
set -x # for debugging the generated string
curl --header "Authorization: Bearer $TOKEN" -v POST "$API_URL/admin/purge_media_cache/?before_ts=$UNIX_TIMESTAMP"
+54 -22
View File
@@ -1,21 +1,26 @@
ARG PYTHON_VERSION=2
ARG PYTHON_VERSION=3
###
### Stage 0: builder
###
FROM docker.io/python:${PYTHON_VERSION}-alpine3.8 as builder
FROM docker.io/python:${PYTHON_VERSION}-slim-stretch as builder
# install the OS build deps
RUN apk add \
build-base \
RUN apt-get update && apt-get install -y \
build-essential \
libffi-dev \
libjpeg-turbo-dev \
libressl-dev \
libxslt-dev \
linux-headers \
postgresql-dev \
zlib-dev
sqlite3 \
libssl-dev \
libjpeg-dev \
libxslt1-dev \
libxml2-dev \
libpq-dev
# for ksm_preload
RUN apt-get install -y \
git \
cmake
# build things which have slow build steps, before we copy synapse, so that
# the layer can be cached.
@@ -34,30 +39,57 @@ RUN pip install --prefix="/install" --no-warn-script-location \
COPY . /synapse
RUN pip install --prefix="/install" --no-warn-script-location \
lxml \
psycopg2 \
psycopg2-binary \
/synapse
# N.B. to work, this needs:
# echo 1 > /sys/kernel/mm/ksm/run
# echo 31250 > /sys/kernel/mm/ksm/pages_to_scan # 128MB of 4KB pages at a time
# echo 10000 > /sys/kernel/mm/ksm/pages_to_scan # 40MB of pages at a time
# ...to be run in the Docker host
RUN git clone https://github.com/unbrice/ksm_preload && \
cd ksm_preload && \
cmake . && \
make && \
cp libksm_preload.so /install/lib
###
### Stage 1: runtime
###
FROM docker.io/python:${PYTHON_VERSION}-alpine3.8
FROM docker.io/python:${PYTHON_VERSION}-slim-stretch
RUN apk add --no-cache --virtual .runtime_deps \
libffi \
libjpeg-turbo \
libressl \
libxslt \
libpq \
zlib \
su-exec
RUN apt-get update && apt-get install -y \
procps \
net-tools \
iproute2 \
tcpdump \
traceroute \
mtr-tiny \
inetutils-ping \
less \
lsof \
supervisor \
netcat
# for topologiser
RUN pip install flask
COPY --from=builder /install /usr/local
COPY ./docker/start.py /start.py
COPY ./docker/conf /conf
COPY ./docker/proxy/proxy /proxy/proxy
COPY ./docker/proxy/maps /proxy/maps
COPY ./docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
VOLUME ["/data"]
EXPOSE 8008/tcp 8448/tcp
EXPOSE 8008/tcp 8448/tcp 3000/tcp 5683/udp
ENTRYPOINT ["/start.py"]
ENV LD_PRELOAD=/usr/local/lib/libksm_preload.so
# default is 32768 (8 4KB pages)
ENV KSMP_MERGE_THRESHOLD=16384
ENTRYPOINT ["/usr/bin/supervisord"]
+10 -6
View File
@@ -21,7 +21,7 @@ listeners:
{% if not SYNAPSE_NO_TLS %}
-
port: 8448
bind_addresses: ['0.0.0.0']
bind_addresses: ['::']
type: http
tls: true
x_forwarded: false
@@ -34,7 +34,7 @@ listeners:
- port: 8008
tls: false
bind_addresses: ['0.0.0.0']
bind_addresses: ['::']
type: http
x_forwarded: false
@@ -55,7 +55,7 @@ database:
database: "{{ POSTGRES_DB or "synapse" }}"
host: "{{ POSTGRES_HOST or "db" }}"
port: "{{ POSTGRES_PORT or "5432" }}"
cp_min: 5
cp_min: 1
cp_max: 10
{% else %}
database:
@@ -73,7 +73,7 @@ log_config: "/compiled/log.config"
## Ratelimiting ##
rc_messages_per_second: 0.2
rc_messages_per_second: 50
rc_message_burst_count: 10.0
federation_rc_window_size: 1000
federation_rc_sleep_limit: 10
@@ -150,10 +150,12 @@ enable_group_creation: true
# The list of identity servers trusted to verify third party
# identifiers by this server.
#
# Also defines the ID server which will be called when an account is
# deactivated (one will be picked arbitrarily).
trusted_third_party_id_servers:
- matrix.org
- vector.im
- riot.im
## Metrics ###
@@ -211,7 +213,9 @@ email:
require_transport_security: False
notif_from: "{{ SYNAPSE_SMTP_FROM or "hostmaster@" + SYNAPSE_SERVER_NAME }}"
app_name: Matrix
template_dir: res/templates
# if template_dir is unset, uses the example templates that are part of
# the Synapse distribution.
#template_dir: res/templates
notif_template_html: notif_mail.html
notif_template_text: notif_mail.txt
notif_for_new_users: True
+13
View File
@@ -15,6 +15,13 @@ handlers:
formatter: precise
filters: [context]
{% if SYNAPSE_LOG_HOST %}
http_meshsim:
class: logging.handlers.HTTPHandler
host: {{ SYNAPSE_LOG_HOST }}:3000
url: "/log"
{% endif %}
loggers:
synapse:
level: {{ SYNAPSE_LOG_LEVEL or "WARNING" }}
@@ -24,6 +31,12 @@ loggers:
# information such as access tokens.
level: {{ SYNAPSE_LOG_LEVEL or "WARNING" }}
{% if SYNAPSE_LOG_HOST %}
synapse.federation.pdu_destination_logger:
level: INFO
handlers: [http_meshsim,console]
{% endif %}
root:
level: {{ SYNAPSE_LOG_LEVEL or "WARNING" }}
handlers: [console]
+35
View File
@@ -0,0 +1,35 @@
[
"errcode",
"error",
"msgtype",
"body",
"formatted_body",
"format",
"avatar_url",
"displayname",
"membership",
"url",
"name",
"origin",
"origin_server_ts",
"pdus",
"edus",
"sender",
"type",
"auth_events",
"unsigned",
"prev_events",
"depth",
"redacts",
"event_id",
"room_id",
"state_key",
"content",
"edu_type",
"sha256",
"typing",
"user_id",
"m.read",
"data",
"event_ids"
]
+5
View File
@@ -0,0 +1,5 @@
[
"m.text",
"m.emote",
"m.notice"
]
+8
View File
@@ -0,0 +1,8 @@
[
"m.presence_invite",
"m.presence_accept",
"m.presence_deny",
"m.presence",
"m.typing",
"m.receipt"
]
+36
View File
@@ -0,0 +1,36 @@
[
"M_BAD_JSON",
"M_BAD_STATE",
"M_CANNOT_LEAVE_SERVER_NOTICE_ROOM",
"M_CAPTCHA_INVALID",
"M_CAPTCHA_NEEDED",
"M_CONSENT_NOT_GIVEN",
"M_EXAMPLE_ERROR",
"M_EXCLUSIVE",
"M_FORBIDDEN",
"M_GUEST_ACCESS_FORBIDDEN",
"M_INCOMPATIBLE_ROOM_VERSION",
"M_INVALID_PARAM",
"M_INVALID_ROOM_STATE",
"M_INVALID_USERNAME",
"M_LIMIT_EXCEEDED",
"M_MISSING_PARAM",
"M_MISSING_TOKEN",
"M_NOT_FOUND",
"M_NOT_JSON",
"M_RESOURCE_LIMIT_EXCEEDED",
"M_ROOM_IN_USE",
"M_SERVER_NOT_TRUSTED",
"M_THREEPID_AUTH_FAILED",
"M_THREEPID_DENIED",
"M_THREEPID_IN_USE",
"M_THREEPID_NOT_FOUND",
"M_TOO_LARGE",
"M_UNAUTHORIZED",
"M_UNKNOWN",
"M_UNKNOWN_TOKEN",
"M_UNRECOGNIZED",
"M_UNSUPPORTED_ROOM_VERSION",
"M_USER_IN_USE",
"M_WEAK_PASSWORD"
]
+26
View File
@@ -0,0 +1,26 @@
[
"m.call.answer",
"m.call.candidates",
"m.call.hangup",
"m.call.invite",
"m.direct",
"m.presence",
"m.receipt",
"m.room.aliases",
"m.room.avatar",
"m.room.canonical_alias",
"m.room.create",
"m.room.guest_access",
"m.room.history_visibility",
"m.room.join_rules",
"m.room.member",
"m.room.message",
"m.room.message.feedback",
"m.room.name",
"m.room.power_levels",
"m.room.redaction",
"m.room.third_party_invite",
"m.room.topic",
"m.tag",
"m.typing"
]
+80
View File
@@ -0,0 +1,80 @@
kdisplayname
javatar_url
mdid_not_relay
fage_ts
dpdus
gmsgtypefm.text
gcontent¢dbody
dbody
bhunsigned
ddtab
kauth_events
edepth
foriginhsynapse
porigin_server_ts
fsender
typenm.room.message
hevent_ido$
kprev_events
groom_idn!
cXJGX%
dtypenm.room.message
dtypemm.room.member
events
:synapse0
:synapse1
:synapse2
:synapse3
:synapse4
:synapse5
:synapse7
:synapse8
&exclude_threaded=true
chunk
start
end
thread_id
=%7B%22thread_id%22%3A0%7D&2=20&dir=b&from=
transaction_id
m.room.room_version
m.room.power_levels
m.room.join_rule
m.room.guest_access
user_id
dtypenm.room.aliases
dtypevm.room.canonical_aliasfsender
device_id
home_server
access_token
"dpdus\x81\xaadtypenm.room.messageedepth"
"gcontent\xa2dbody"
"gmsgtypefm.textgroom_idn"
"porigin_server_ts\x1b\x00\x00\x01gZ\xe3\xfd\x1c"
"\x11*\xd1\x02\x06\xd1\x14"
"B\x03\x00:\x8d\x87\xb10\x021Q\x00\x11* \xd1\x00\x06\xd2\x14\x01\x06\xff\xa1dpdus\x81\xaadtypenm.room.messageedepth\x18"
"bE\x00\x01\x1dr\xc1*\xb1\x06Q\x07\xff\xa1dpdus\xa0"
"\xa1dpdus\xa0"
"\xa8erooms\xa3djoin\xa0eleave\xa0finvite\xa0fgroups\xa3djoin\xa0eleave\xa0finvite\xa0hpresence\xa1fevents\x80ito_device\xa1fevents\x80jnext_batchts58_10_0_1_1_1_1_3_1laccount_data\xa1fevents\x80ldevice_lists\xa2dleft\x80gchanged\x80x\x1adevice_one_time_keys_count\xa1qsigned_curve25519\x182"
"\xa8erooms\xa3djoin\xa1n!DQQ0:synapse0\xa6estate\xa1fevents\x80gsummary\xa0htimeline\xa3fevents\x81\xa6dtypenm.room.messagefsender"
"`Zy\x1eglimited\xf4jprev_batchss16_3_0_1_1_1_1_3_1iephemeral\xa1fevents\x80laccount_data\xa1fevents\x80tunread_notifications\xa0eleave"
"ephemeral\xa1fevents\x80laccount_data\xa1fevents\x81\xa2dtypelm.fully_readgcontent\xa1hevent_idk"
"chunk\x8a\xaacage\x0cdtypemm.room.memberfsenderqgcontent\xa3javatar_url\xf6jmembershipdjoinkdisplayname\xf6groom_id"
"gcontent\xa1rhistory_visibilityfsharedgroom_id"
"dtypex\x19m.room.history_visibility"
"gcontent\xa1ijoin_rulefpublicgroom_idn"
"dtypesm.room.power_levelsfsenderq"
"gcontent\xa9cban\x182dkick\x182eusers\xa1q"
"\x18dfevents\xa5km.room.name\x182mm.room.avatar\x182sm.room.power_levels\x18dvm.room.canonical_alias\x182x\x19m.room.history_visibility\x18dfinvite\x00fredact\x182mstate_default\x182musers_default\x00nevents_default\x00groom_idn"
"gcontent\xa2gcreatorqlroom_versiona1groom_idn"
"\xa1eflows\x81\xa1dtypepm.login.password"
"\xa2eerroroNo backup foundgerrcodekM_NOT_FOUND"
"xa1kdevice_keys\xa5dkeys\xa2red25519:J"
"jalgorithms\x82x\x1cm.olm.v1.curve25519-aes-sha2tm.megolm.v1.aes-sha2jsignatures\xa1"
"\xa2fdevice\xa0fglobal\xa5droom\x80fsender\x80gcontent\x81\xa5gactions\x83fnotify\xa2evaluegdefaultiset_tweakesound\xa1iset_tweakihighlightgdefault\xf5genabled\xf5gpatternggrule_idx\x1a.m.rule.contains_user_namehoverride\x86\xa5gactions\x81kdont_notifygdefault\xf5genabled\xf4grule_idn.m.rule.masterjconditions\x80\xa5gactions\x81kdont_notifygdefault\xf5genabled\xf5grule_idx\x18.m.rule.suppress_noticesjconditions\x81\xa3ckeyocontent.msgtypedkindkevent_matchgpatternhm.notice\xa5gactions\x83fnotify\xa2evaluegdefaultiset_tweakesound\xa2evalue\xf4iset_tweakihighlightgdefault\xf5genabled\xf5grule_idu.m.rule.invite_for_mejconditions\x83\xa3ckeydtypedkindkevent_matchgpatternmm.room.member\xa3ckeyrcontent.membershipdkindkevent_matchgpatternfinvite\xa3ckeyistate_keydkindkevent_matchgpatternq\xa5gactions\x81kdont_notifygdefault\xf5genabled\xf5grule_idt.m.rule.member_eventjconditions\x81\xa3ckeydtypedkindkevent_matchgpatternmm.room.member\xa5gactions\x83fnotify\xa2evaluegdefaultiset_tweakesound\xa1iset_tweakihighlightgdefault\xf5genabled\xf5grule_idx\x1d.m.rule.contains_display_namejconditions\x81\xa1dkinducontains_display_name\xa5gactions\x82fnotify\xa2evalue\xf5iset_tweakihighlightgdefault\xf5genabled\xf5grule_idq.m.rule.roomnotifjconditions\x82\xa3ckeylcontent.bodydkindkevent_matchgpatterne@room\xa2ckeydroomdkindx\x1esender_notification_permissioniunderride\x85\xa5gactions\x83fnotify\xa2evaluedringiset_tweakesound\xa2evalue\xf4iset_tweakihighlightgdefault\xf5genabled\xf5grule_idl.m.rule.calljconditions\x81\xa3ckeydtypedkindkevent_matchgpatternmm.call.invite\xa5gactions\x83fnotify\xa2evaluegdefaultiset_tweakesound\xa2evalue\xf4iset_tweakihighlightgdefault\xf5genabled\xf5grule_idw.m.rule.room_one_to_onejconditions\x82\xa2bisa2dkindqroom_member_count\xa3ckeydtypedkindkevent_matchgpatternnm.room.message\xa5gactions\x83fnotify\xa2evaluegdefaultiset_tweakesound\xa2evalue\xf4iset_tweakihighlightgdefault\xf5genabled\xf5grule_idx!.m.rule.encrypted_room_one_to_onejconditions\x82\xa2bisa2dkindqroom_member_count\xa3ckeydtypedkindkevent_matchgpatternpm.room.encrypted\xa5gactions\x82fnotify\xa2evalue\xf4iset_tweakihighlightgdefault\xf5genabled\xf5grule_ido.m.rule.messagejconditions\x81\xa3ckeydtypedkindkevent_matchgpatternnm.room.message\xa5gactions\x82fnotify\xa2evalue\xf4iset_tweakihighlightgdefault\xf5genabled\xf5grule_idq.m.rule.encryptedjconditions\x81\xa3ckeydtypedkindkevent_matchgpatternpm.room.encrypted"
"\xa1droom\xa1htimeline\xa1elimit\x14"
"\xa8erooms\xa3djoin\xa1n!eYB0:synapse0\xa6estate\xa1fevents\x80gsummary\xa0htimeline\xa3fevents\x8e\xa7dtypemm.room.createfsenderq"
"\xa1mone_time_keys\xa5x\x18signed_curve25519:"
"\xa1sone_time_key_counts\xa1qsigned_curve25519\x05"
"\xa4jexpires_in\xfb@\xac \x00\x00\x00\x00\x00jtoken_typefBearerlaccess_tokenxrmatrix_server_namehsynapse"
+18
View File
@@ -0,0 +1,18 @@
[
"minimum_valid_until_ts",
"v",
"limit",
"event_id",
"ver",
"limit",
"since",
"include_all_networks",
"third_party_instance_id",
"room_alias",
"user_id",
"field",
"minimum_valid_until_ts",
"filter",
"access_token",
"timeout"
]
+519
View File
@@ -0,0 +1,519 @@
[
{
"path": "/_matrix/federation/v1/send/{txnId}",
"method": "put",
"name": "send_transaction"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}",
"method": "put"
},
{
"path": "/_matrix/client/r0/profile/{userId}/displayname",
"method": "get"
},
{
"path": "/_matrix/client/r0/profile/{userId}/displayname",
"method": "put"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/join",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/kick",
"method": "post"
},
{
"path": "/_matrix/client/r0/admin/whois/{userId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/receipt/{receiptType}/{eventId}",
"method": "post"
},
{
"path": "/_matrix/client/versions",
"method": "get"
},
{
"path": "/_matrix/media/r0/config",
"method": "get"
},
{
"path": "/_matrix/media/r0/download/{serverName}/{mediaId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/invite ",
"method": "post"
},
{
"path": "/_matrix/client/r0/join/{roomIdOrAlias}",
"method": "post"
},
{
"path": "/_matrix/client/r0/presence/list/{userId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/presence/list/{userId}",
"method": "post"
},
{
"path": "/_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}",
"method": "delete"
},
{
"path": "/_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}",
"method": "put"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/state/{eventType}",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/state/{eventType}",
"method": "put"
},
{
"path": "/_matrix/client/r0/account/whoami",
"method": "get"
},
{
"path": "/_matrix/client/r0/devices",
"method": "get"
},
{
"path": "/_matrix/client/r0/keys/claim",
"method": "post"
},
{
"path": "/_matrix/client/r0/login",
"method": "get"
},
{
"path": "/_matrix/client/r0/login",
"method": "post"
},
{
"path": "/_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions",
"method": "put"
},
{
"path": "/_matrix/client/r0/register/available",
"method": "get"
},
{
"path": "/_matrix/client/r0/user/{userId}/filter",
"method": "post"
},
{
"path": "/_matrix/client/r0/user_directory/search",
"method": "post"
},
{
"path": "/_matrix/client/r0/account/3pid",
"method": "get"
},
{
"path": "/_matrix/client/r0/account/3pid",
"method": "post"
},
{
"path": "/_matrix/client/r0/publicRooms",
"method": "get"
},
{
"path": "/_matrix/client/r0/publicRooms",
"method": "post"
},
{
"path": "/_matrix/client/r0/register",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/ban",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/typing/{userId}",
"method": "put"
},
{
"path": "/_matrix/client/r0/search",
"method": "post"
},
{
"path": "/_matrix/client/r0/account/password",
"method": "post"
},
{
"path": "/_matrix/client/r0/initialSync",
"method": "get"
},
{
"path": "/_matrix/client/r0/logout/all",
"method": "post"
},
{
"path": "/_matrix/client/r0/account/deactivate",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/forget",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}",
"method": "put"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/unban",
"method": "post"
},
{
"path": "/_matrix/client/r0/keys/query",
"method": "post"
},
{
"path": "/_matrix/client/r0/user/{userId}/account_data/{type}",
"method": "put"
},
{
"path": "/_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}",
"method": "delete"
},
{
"path": "/_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}",
"method": "put"
},
{
"path": "/_matrix/media/r0/upload",
"method": "post"
},
{
"path": "/_matrix/client/r0/events",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/context/{eventId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/invite",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/messages",
"method": "get"
},
{
"path": "/_matrix/client/r0/account/3pid/delete",
"method": "post"
},
{
"path": "/_matrix/client/r0/createRoom",
"method": "post"
},
{
"path": "/_matrix/client/r0/profile/{userId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/enabled",
"method": "put"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/leave",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/members",
"method": "get"
},
{
"path": "/_matrix/client/r0/sendToDevice/{eventType}/{txnId}",
"method": "put"
},
{
"path": "/_matrix/client/r0/voip/turnServer",
"method": "get"
},
{
"path": "/.well-known/matrix/client",
"method": "get"
},
{
"path": "/_matrix/client/r0/directory/list/appservice/{networkId}/{roomId}",
"method": "put"
},
{
"path": "/_matrix/client/r0/keys/upload",
"method": "post"
},
{
"path": "/_matrix/client/r0/pushrules/",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/initialSync",
"method": "get"
},
{
"path": "/_matrix/client/r0/user/{userId}/openid/request_token",
"method": "post"
},
{
"path": "/_matrix/client/r0/user/{userId}/rooms/{roomId}/tags",
"method": "get"
},
{
"path": "/_matrix/media/r0/download/{serverName}/{mediaId}/{fileName}",
"method": "get"
},
{
"path": "/_matrix/client/r0/delete_devices",
"method": "post"
},
{
"path": "/_matrix/client/r0/events/{eventId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/profile/{userId}/avatar_url",
"method": "get"
},
{
"path": "/_matrix/client/r0/profile/{userId}/avatar_url",
"method": "put"
},
{
"path": "/_matrix/client/r0/pushers/set",
"method": "post"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/event/{eventId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/report/{eventId}",
"method": "post"
},
{
"path": "/_matrix/media/r0/preview_url",
"method": "get"
},
{
"path": "/_matrix/client/r0/directory/room/{roomAlias}",
"method": "delete"
},
{
"path": "/_matrix/client/r0/directory/room/{roomAlias}",
"method": "get"
},
{
"path": "/_matrix/client/r0/directory/room/{roomAlias}",
"method": "put"
},
{
"path": "/_matrix/client/r0/sync",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/read_markers",
"method": "post"
},
{
"path": "/_matrix/client/r0/logout",
"method": "post"
},
{
"path": "/_matrix/client/r0/notifications",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/joined_members",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}",
"method": "put"
},
{
"path": "/_matrix/client/r0/user/{userId}/filter/{filterId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}",
"method": "put"
},
{
"path": "/_matrix/client/r0/joined_rooms",
"method": "get"
},
{
"path": "/_matrix/client/r0/keys/changes",
"method": "get"
},
{
"path": "/_matrix/client/r0/presence/{userId}/status",
"method": "get"
},
{
"path": "/_matrix/client/r0/presence/{userId}/status",
"method": "put"
},
{
"path": "/_matrix/client/r0/pushers",
"method": "get"
},
{
"path": "/_matrix/client/r0/rooms/{roomId}/state",
"method": "get"
},
{
"path": "/_matrix/media/r0/thumbnail/{serverName}/{mediaId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/devices/{deviceId}",
"method": "delete"
},
{
"path": "/_matrix/client/r0/devices/{deviceId}",
"method": "get"
},
{
"path": "/_matrix/client/r0/devices/{deviceId}",
"method": "put"
},
{
"path": "/_matrix/federation/v1/backfill/{roomId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/get_missing_events/{roomId}",
"method": "post"
},
{
"path": "/_matrix/federation/v1/event_auth/{roomId}/{eventId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/query_auth/{roomId}/{eventId}",
"method": "post"
},
{
"path": "/_matrix/federation/v1/state/{roomId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/state_ids/{roomId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/event/{eventId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/invite/{roomId}/{eventId}",
"method": "put"
},
{
"path": "/_matrix/federation/v1/make_join/{roomId}/{userId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/send_join/{roomId}/{eventId}",
"method": "put"
},
{
"path": "/_matrix/federation/v1/query/{serverName}/{keyId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/query",
"method": "post"
},
{
"path": "/_matrix/federation/v1/server/{keyId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/make_leave/{roomId}/{userId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/send_leave/{roomId}/{eventId}",
"method": "put"
},
{
"path": "/_matrix/federation/v1/openid/userinfo",
"method": "get"
},
{
"path": "/_matrix/federation/v1/publicRooms",
"method": "get"
},
{
"path": "/_matrix/federation/v1/query/directory",
"method": "get"
},
{
"path": "/_matrix/federation/v1/query/profile",
"method": "get"
},
{
"path": "/_matrix/federation/v1/query/{queryType}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/query_auth/{roomId}/{eventId}",
"method": "post"
},
{
"path": "/_matrix/federation/v1/state/{roomId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/state_ids/{roomId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/event/{eventId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/event_auth/{roomId}/{eventId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/exchange_third_party_invite/{roomId}",
"method": "put"
},
{
"path": "/_matrix/federation/v1/3pid/onbind",
"method": "put"
},
{
"path": "/_matrix/federation/v1/user/devices/{userId}",
"method": "get"
},
{
"path": "/_matrix/federation/v1/user/keys/claim",
"method": "post"
},
{
"path": "/_matrix/federation/v1/user/keys/query",
"method": "post"
}
]
BIN
View File
Binary file not shown.
+11 -1
View File
@@ -6,6 +6,7 @@ import sys
import subprocess
import glob
import codecs
import time
# Utility functions
convert = lambda src, dst, environ: open(dst, "w").write(jinja2.Template(open(src).read()).render(**environ))
@@ -31,6 +32,10 @@ def generate_secrets(environ, secrets):
# Prepare the configuration
mode = sys.argv[1] if len(sys.argv) > 1 else None
environ = os.environ.copy()
for e in environ:
print("%s:%s" % (e, environ[e]))
ownership = "{}:{}".format(environ.get("UID", 991), environ.get("GID", 991))
args = ["python", "-m", "synapse.app.homeserver"]
@@ -64,4 +69,9 @@ else:
args += ["--config-path", "/compiled/homeserver.yaml"]
# Generate missing keys and start synapse
subprocess.check_output(args + ["--generate-keys"])
os.execv("/sbin/su-exec", ["su-exec", ownership] + args)
# we register our test users in add_accounts.sh now to avoid having to wait for HS launch
#os.system("(sleep 10; /usr/local/bin/register_new_matrix_user -u matthew -p secret -c /compiled/homeserver.yaml -a) &");
os.execv("/usr/local/bin/python", args)
+8
View File
@@ -0,0 +1,8 @@
[supervisord]
nodaemon=true
[program:synapse]
command=/start.py
[program:proxy]
command=/proxy/proxy --maps-dir /proxy/maps --debug-log
+8
View File
@@ -61,3 +61,11 @@ the following:
}
The status will be one of ``active``, ``complete``, or ``failed``.
Reclaim disk space (Postgres)
-----------------------------
To reclaim the disk space and return it to the operating system, you need to run
`VACUUM FULL;` on the database.
https://www.postgresql.org/docs/current/sql-vacuum.html
+38 -1
View File
@@ -31,7 +31,7 @@ Note that the templates must be stored under a name giving the language of the
template - currently this must always be `en` (for "English");
internationalisation support is intended for the future.
The template for the policy itself should be versioned and named according to
The template for the policy itself should be versioned and named according to
the version: for example `1.0.html`. The version of the policy which the user
has agreed to is stored in the database.
@@ -85,6 +85,37 @@ Once this is complete, and the server has been restarted, try visiting
an error "Missing string query parameter 'u'". It is now possible to manually
construct URIs where users can give their consent.
### Enabling consent tracking at registration
1. Add the following to your configuration:
```yaml
user_consent:
require_at_registration: true
policy_name: "Privacy Policy" # or whatever you'd like to call the policy
```
2. In your consent templates, make use of the `public_version` variable to
see if an unauthenticated user is viewing the page. This is typically
wrapped around the form that would be used to actually agree to the document:
```
{% if not public_version %}
<!-- The variables used here are only provided when the 'u' param is given to the homeserver -->
<form method="post" action="consent">
<input type="hidden" name="v" value="{{version}}"/>
<input type="hidden" name="u" value="{{user}}"/>
<input type="hidden" name="h" value="{{userhmac}}"/>
<input type="submit" value="Sure thing!"/>
</form>
{% endif %}
```
3. Restart Synapse to apply the changes.
Visiting `https://<server>/_matrix/consent` should now give you a view of the privacy
document. This is what users will be able to see when registering for accounts.
### Constructing the consent URI
It may be useful to manually construct the "consent URI" for a given user - for
@@ -106,6 +137,12 @@ query parameters:
`https://<server>/_matrix/consent?u=<user>&h=68a152465a4d...`.
Note that not providing a `u` parameter will be interpreted as wanting to view
the document from an unauthenticated perspective, such as prior to registration.
Therefore, the `h` parameter is not required in this scenario. To enable this
behaviour, set `require_at_registration` to `true` in your `user_consent` config.
Sending users a server notice asking them to agree to the policy
----------------------------------------------------------------
+9 -6
View File
@@ -12,12 +12,15 @@
<p>
All your base are belong to us.
</p>
<form method="post" action="consent">
<input type="hidden" name="v" value="{{version}}"/>
<input type="hidden" name="u" value="{{user}}"/>
<input type="hidden" name="h" value="{{userhmac}}"/>
<input type="submit" value="Sure thing!"/>
</form>
{% if not public_version %}
<!-- The variables used here are only provided when the 'u' param is given to the homeserver -->
<form method="post" action="consent">
<input type="hidden" name="v" value="{{version}}"/>
<input type="hidden" name="u" value="{{user}}"/>
<input type="hidden" name="h" value="{{userhmac}}"/>
<input type="submit" value="Sure thing!"/>
</form>
{% endif %}
{% endif %}
</body>
</html>
-19
View File
@@ -14,22 +14,3 @@ fi
# set up the virtualenv
tox -e py27 --notest -v
TOX_BIN=$TOX_DIR/py27/bin
# cryptography 2.2 requires setuptools >= 18.5.
#
# older versions of virtualenv (?) give us a virtualenv with the same version
# of setuptools as is installed on the system python (and tox runs virtualenv
# under python3, so we get the version of setuptools that is installed on that).
#
# anyway, make sure that we have a recent enough setuptools.
$TOX_BIN/pip install 'setuptools>=18.5'
# we also need a semi-recent version of pip, because old ones fail to install
# the "enum34" dependency of cryptography.
$TOX_BIN/pip install 'pip>=10'
{ python synapse/python_dependencies.py
echo lxml
} | xargs $TOX_BIN/pip install
+15 -21
View File
@@ -1,21 +1,20 @@
from synapse.events import FrozenEvent
from synapse.api.auth import Auth
from mock import Mock
from __future__ import print_function
import argparse
import itertools
import json
import sys
from mock import Mock
from synapse.api.auth import Auth
from synapse.events import FrozenEvent
def check_auth(auth, auth_chain, events):
auth_chain.sort(key=lambda e: e.depth)
auth_map = {
e.event_id: e
for e in auth_chain
}
auth_map = {e.event_id: e for e in auth_chain}
create_events = {}
for e in auth_chain:
@@ -25,31 +24,26 @@ def check_auth(auth, auth_chain, events):
for e in itertools.chain(auth_chain, events):
auth_events_list = [auth_map[i] for i, _ in e.auth_events]
auth_events = {
(e.type, e.state_key): e
for e in auth_events_list
}
auth_events = {(e.type, e.state_key): e for e in auth_events_list}
auth_events[("m.room.create", "")] = create_events[e.room_id]
try:
auth.check(e, auth_events=auth_events)
except Exception as ex:
print "Failed:", e.event_id, e.type, e.state_key
print "Auth_events:", auth_events
print ex
print json.dumps(e.get_dict(), sort_keys=True, indent=4)
print("Failed:", e.event_id, e.type, e.state_key)
print("Auth_events:", auth_events)
print(ex)
print(json.dumps(e.get_dict(), sort_keys=True, indent=4))
# raise
print "Success:", e.event_id, e.type, e.state_key
print("Success:", e.event_id, e.type, e.state_key)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'json',
nargs='?',
type=argparse.FileType('r'),
default=sys.stdin,
'json', nargs='?', type=argparse.FileType('r'), default=sys.stdin
)
args = parser.parse_args()
+18 -14
View File
@@ -1,10 +1,15 @@
from synapse.crypto.event_signing import *
from unpaddedbase64 import encode_base64
import argparse
import hashlib
import sys
import json
import logging
import sys
from unpaddedbase64 import encode_base64
from synapse.crypto.event_signing import (
check_event_content_hash,
compute_event_reference_hash,
)
class dictobj(dict):
@@ -24,27 +29,26 @@ class dictobj(dict):
def main():
parser = argparse.ArgumentParser()
parser.add_argument("input_json", nargs="?", type=argparse.FileType('r'),
default=sys.stdin)
parser.add_argument(
"input_json", nargs="?", type=argparse.FileType('r'), default=sys.stdin
)
args = parser.parse_args()
logging.basicConfig()
event_json = dictobj(json.load(args.input_json))
algorithms = {
"sha256": hashlib.sha256,
}
algorithms = {"sha256": hashlib.sha256}
for alg_name in event_json.hashes:
if check_event_content_hash(event_json, algorithms[alg_name]):
print "PASS content hash %s" % (alg_name,)
print("PASS content hash %s" % (alg_name,))
else:
print "FAIL content hash %s" % (alg_name,)
print("FAIL content hash %s" % (alg_name,))
for algorithm in algorithms.values():
name, h_bytes = compute_event_reference_hash(event_json, algorithm)
print "Reference hash %s: %s" % (name, encode_base64(h_bytes))
print("Reference hash %s: %s" % (name, encode_base64(h_bytes)))
if __name__=="__main__":
if __name__ == "__main__":
main()
+19 -17
View File
@@ -1,15 +1,15 @@
from signedjson.sign import verify_signed_json
import argparse
import json
import logging
import sys
import urllib2
import dns.resolver
from signedjson.key import decode_verify_key_bytes, write_signing_keys
from signedjson.sign import verify_signed_json
from unpaddedbase64 import decode_base64
import urllib2
import json
import sys
import dns.resolver
import pprint
import argparse
import logging
def get_targets(server_name):
if ":" in server_name:
@@ -23,6 +23,7 @@ def get_targets(server_name):
except dns.resolver.NXDOMAIN:
yield (server_name, 8448)
def get_server_keys(server_name, target, port):
url = "https://%s:%i/_matrix/key/v1" % (target, port)
keys = json.load(urllib2.urlopen(url))
@@ -33,12 +34,14 @@ def get_server_keys(server_name, target, port):
verify_keys[key_id] = verify_key
return verify_keys
def main():
parser = argparse.ArgumentParser()
parser.add_argument("signature_name")
parser.add_argument("input_json", nargs="?", type=argparse.FileType('r'),
default=sys.stdin)
parser.add_argument(
"input_json", nargs="?", type=argparse.FileType('r'), default=sys.stdin
)
args = parser.parse_args()
logging.basicConfig()
@@ -48,24 +51,23 @@ def main():
for target, port in get_targets(server_name):
try:
keys = get_server_keys(server_name, target, port)
print "Using keys from https://%s:%s/_matrix/key/v1" % (target, port)
print("Using keys from https://%s:%s/_matrix/key/v1" % (target, port))
write_signing_keys(sys.stdout, keys.values())
break
except:
except Exception:
logging.exception("Error talking to %s:%s", target, port)
json_to_check = json.load(args.input_json)
print "Checking JSON:"
print("Checking JSON:")
for key_id in json_to_check["signatures"][args.signature_name]:
try:
key = keys[key_id]
verify_signed_json(json_to_check, args.signature_name, key)
print "PASS %s" % (key_id,)
except:
print("PASS %s" % (key_id,))
except Exception:
logging.exception("Check for key %s failed" % (key_id,))
print "FAIL %s" % (key_id,)
print("FAIL %s" % (key_id,))
if __name__ == '__main__':
main()
+22 -18
View File
@@ -1,13 +1,21 @@
import hashlib
import json
import sys
import time
import six
import psycopg2
import yaml
import sys
import json
import time
import hashlib
from unpaddedbase64 import encode_base64
from canonicaljson import encode_canonical_json
from signedjson.key import read_signing_keys
from signedjson.sign import sign_json
from canonicaljson import encode_canonical_json
from unpaddedbase64 import encode_base64
if six.PY2:
db_type = six.moves.builtins.buffer
else:
db_type = memoryview
def select_v1_keys(connection):
@@ -39,7 +47,9 @@ def select_v2_json(connection):
cursor.close()
results = {}
for server_name, key_id, key_json in rows:
results.setdefault(server_name, {})[key_id] = json.loads(str(key_json).decode("utf-8"))
results.setdefault(server_name, {})[key_id] = json.loads(
str(key_json).decode("utf-8")
)
return results
@@ -47,10 +57,7 @@ def convert_v1_to_v2(server_name, valid_until, keys, certificate):
return {
"old_verify_keys": {},
"server_name": server_name,
"verify_keys": {
key_id: {"key": key}
for key_id, key in keys.items()
},
"verify_keys": {key_id: {"key": key} for key_id, key in keys.items()},
"valid_until_ts": valid_until,
"tls_fingerprints": [fingerprint(certificate)],
}
@@ -65,7 +72,7 @@ def rows_v2(server, json):
valid_until = json["valid_until_ts"]
key_json = encode_canonical_json(json)
for key_id in json["verify_keys"]:
yield (server, key_id, "-", valid_until, valid_until, buffer(key_json))
yield (server, key_id, "-", valid_until, valid_until, db_type(key_json))
def main():
@@ -87,7 +94,7 @@ def main():
result = {}
for server in keys:
if not server in json:
if server not in json:
v2_json = convert_v1_to_v2(
server, valid_until, keys[server], certificates[server]
)
@@ -96,10 +103,7 @@ def main():
yaml.safe_dump(result, sys.stdout, default_flow_style=False)
rows = list(
row for server, json in result.items()
for row in rows_v2(server, json)
)
rows = list(row for server, json in result.items() for row in rows_v2(server, json))
cursor = connection.cursor()
cursor.executemany(
@@ -107,7 +111,7 @@ def main():
" server_name, key_id, from_server,"
" ts_added_ms, ts_valid_until_ms, key_json"
") VALUES (%s, %s, %s, %s, %s, %s)",
rows
rows,
)
connection.commit()
+34 -20
View File
@@ -1,8 +1,16 @@
#! /usr/bin/python
from __future__ import print_function
import argparse
import ast
import os
import re
import sys
import yaml
class DefinitionVisitor(ast.NodeVisitor):
def __init__(self):
super(DefinitionVisitor, self).__init__()
@@ -42,15 +50,18 @@ def non_empty(defs):
functions = {name: non_empty(f) for name, f in defs['def'].items()}
classes = {name: non_empty(f) for name, f in defs['class'].items()}
result = {}
if functions: result['def'] = functions
if classes: result['class'] = classes
if functions:
result['def'] = functions
if classes:
result['class'] = classes
names = defs['names']
uses = []
for name in names.get('Load', ()):
if name not in names.get('Param', ()) and name not in names.get('Store', ()):
uses.append(name)
uses.extend(defs['attrs'])
if uses: result['uses'] = uses
if uses:
result['uses'] = uses
result['names'] = names
result['attrs'] = defs['attrs']
return result
@@ -95,7 +106,6 @@ def used_names(prefix, item, defs, names):
if __name__ == '__main__':
import sys, os, argparse, re
parser = argparse.ArgumentParser(description='Find definitions.')
parser.add_argument(
@@ -105,24 +115,28 @@ if __name__ == '__main__':
"--ignore", action="append", metavar="REGEXP", help="Ignore a pattern"
)
parser.add_argument(
"--pattern", action="append", metavar="REGEXP",
help="Search for a pattern"
"--pattern", action="append", metavar="REGEXP", help="Search for a pattern"
)
parser.add_argument(
"directories", nargs='+', metavar="DIR",
help="Directories to search for definitions"
"directories",
nargs='+',
metavar="DIR",
help="Directories to search for definitions",
)
parser.add_argument(
"--referrers", default=0, type=int,
help="Include referrers up to the given depth"
"--referrers",
default=0,
type=int,
help="Include referrers up to the given depth",
)
parser.add_argument(
"--referred", default=0, type=int,
help="Include referred down to the given depth"
"--referred",
default=0,
type=int,
help="Include referred down to the given depth",
)
parser.add_argument(
"--format", default="yaml",
help="Output format, one of 'yaml' or 'dot'"
"--format", default="yaml", help="Output format, one of 'yaml' or 'dot'"
)
args = parser.parse_args()
@@ -162,7 +176,7 @@ if __name__ == '__main__':
for used_by in entry.get("used", ()):
referrers.add(used_by)
for name, definition in names.items():
if not name in referrers:
if name not in referrers:
continue
if ignore and any(pattern.match(name) for pattern in ignore):
continue
@@ -176,7 +190,7 @@ if __name__ == '__main__':
for uses in entry.get("uses", ()):
referred.add(uses)
for name, definition in names.items():
if not name in referred:
if name not in referred:
continue
if ignore and any(pattern.match(name) for pattern in ignore):
continue
@@ -185,12 +199,12 @@ if __name__ == '__main__':
if args.format == 'yaml':
yaml.dump(result, sys.stdout, default_flow_style=False)
elif args.format == 'dot':
print "digraph {"
print("digraph {")
for name, entry in result.items():
print name
print(name)
for used_by in entry.get("used", ()):
if used_by in result:
print used_by, "->", name
print "}"
print(used_by, "->", name)
print("}")
else:
raise ValueError("Unknown format %r" % (args.format))
+8 -5
View File
@@ -1,8 +1,11 @@
#!/usr/bin/env python2
import pymacaroons
from __future__ import print_function
import sys
import pymacaroons
if len(sys.argv) == 1:
sys.stderr.write("usage: %s macaroon [key]\n" % (sys.argv[0],))
sys.exit(1)
@@ -11,14 +14,14 @@ macaroon_string = sys.argv[1]
key = sys.argv[2] if len(sys.argv) > 2 else None
macaroon = pymacaroons.Macaroon.deserialize(macaroon_string)
print macaroon.inspect()
print(macaroon.inspect())
print ""
print("")
verifier = pymacaroons.Verifier()
verifier.satisfy_general(lambda c: True)
try:
verifier.verify(macaroon, key)
print "Signature is correct"
print("Signature is correct")
except Exception as e:
print str(e)
print(str(e))
+54 -52
View File
@@ -18,21 +18,21 @@
from __future__ import print_function
import argparse
import base64
import json
import sys
from urlparse import urlparse, urlunparse
import nacl.signing
import json
import base64
import requests
import sys
from requests.adapters import HTTPAdapter
import srvlookup
import yaml
from requests.adapters import HTTPAdapter
# uncomment the following to enable debug logging of http requests
#from httplib import HTTPConnection
#HTTPConnection.debuglevel = 1
# from httplib import HTTPConnection
# HTTPConnection.debuglevel = 1
def encode_base64(input_bytes):
"""Encode bytes as a base64 string without any padding."""
@@ -58,15 +58,15 @@ def decode_base64(input_string):
def encode_canonical_json(value):
return json.dumps(
value,
# Encode code-points outside of ASCII as UTF-8 rather than \u escapes
ensure_ascii=False,
# Remove unecessary white space.
separators=(',',':'),
# Sort the keys of dictionaries.
sort_keys=True,
# Encode the resulting unicode as UTF-8 bytes.
).encode("UTF-8")
value,
# Encode code-points outside of ASCII as UTF-8 rather than \u escapes
ensure_ascii=False,
# Remove unecessary white space.
separators=(',', ':'),
# Sort the keys of dictionaries.
sort_keys=True,
# Encode the resulting unicode as UTF-8 bytes.
).encode("UTF-8")
def sign_json(json_object, signing_key, signing_name):
@@ -88,6 +88,7 @@ def sign_json(json_object, signing_key, signing_name):
NACL_ED25519 = "ed25519"
def decode_signing_key_base64(algorithm, version, key_base64):
"""Decode a base64 encoded signing key
Args:
@@ -143,25 +144,25 @@ def request_json(method, origin_name, origin_key, destination, path, content):
authorization_headers = []
for key, sig in signed_json["signatures"][origin_name].items():
header = "X-Matrix origin=%s,key=\"%s\",sig=\"%s\"" % (
origin_name, key, sig,
)
header = "X-Matrix origin=%s,key=\"%s\",sig=\"%s\"" % (origin_name, key, sig)
authorization_headers.append(bytes(header))
print ("Authorization: %s" % header, file=sys.stderr)
print("Authorization: %s" % header, file=sys.stderr)
dest = "matrix://%s%s" % (destination, path)
print ("Requesting %s" % dest, file=sys.stderr)
print("Requesting %s" % dest, file=sys.stderr)
s = requests.Session()
s.mount("matrix://", MatrixConnectionAdapter())
headers = {"Host": destination, "Authorization": authorization_headers[0]}
if method == "POST":
headers["Content-Type"] = "application/json"
result = s.request(
method=method,
url=dest,
headers={
"Host": destination,
"Authorization": authorization_headers[0]
},
headers=headers,
verify=False,
data=content,
)
@@ -171,50 +172,50 @@ def request_json(method, origin_name, origin_key, destination, path, content):
def main():
parser = argparse.ArgumentParser(
description=
"Signs and sends a federation request to a matrix homeserver",
description="Signs and sends a federation request to a matrix homeserver"
)
parser.add_argument(
"-N", "--server-name",
"-N",
"--server-name",
help="Name to give as the local homeserver. If unspecified, will be "
"read from the config file.",
"read from the config file.",
)
parser.add_argument(
"-k", "--signing-key-path",
"-k",
"--signing-key-path",
help="Path to the file containing the private ed25519 key to sign the "
"request with.",
"request with.",
)
parser.add_argument(
"-c", "--config",
"-c",
"--config",
default="homeserver.yaml",
help="Path to server config file. Ignored if --server-name and "
"--signing-key-path are both given.",
"--signing-key-path are both given.",
)
parser.add_argument(
"-d", "--destination",
"-d",
"--destination",
default="matrix.org",
help="name of the remote homeserver. We will do SRV lookups and "
"connect appropriately.",
"connect appropriately.",
)
parser.add_argument(
"-X", "--method",
help="HTTP method to use for the request. Defaults to GET if --data is"
"unspecified, POST if it is."
"-X",
"--method",
help="HTTP method to use for the request. Defaults to GET if --body is"
"unspecified, POST if it is.",
)
parser.add_argument(
"--body",
help="Data to send as the body of the HTTP request"
)
parser.add_argument("--body", help="Data to send as the body of the HTTP request")
parser.add_argument(
"path",
help="request path. We will add '/_matrix/federation/v1/' to this."
"path", help="request path. We will add '/_matrix/federation/v1/' to this."
)
args = parser.parse_args()
@@ -227,13 +228,15 @@ def main():
result = request_json(
args.method,
args.server_name, key, args.destination,
args.server_name,
key,
args.destination,
"/_matrix/federation/v1/" + args.path,
content=args.body,
)
json.dump(result, sys.stdout)
print ("")
print("")
def read_args_from_config(args):
@@ -253,7 +256,7 @@ class MatrixConnectionAdapter(HTTPAdapter):
return s, 8448
if ":" in s:
out = s.rsplit(":",1)
out = s.rsplit(":", 1)
try:
port = int(out[1])
except ValueError:
@@ -263,7 +266,7 @@ class MatrixConnectionAdapter(HTTPAdapter):
try:
srv = srvlookup.lookup("matrix", "tcp", s)[0]
return srv.host, srv.port
except:
except Exception:
return s, 8448
def get_connection(self, url, proxies=None):
@@ -272,10 +275,9 @@ class MatrixConnectionAdapter(HTTPAdapter):
(host, port) = self.lookup(parsed.netloc)
netloc = "%s:%d" % (host, port)
print("Connecting to %s" % (netloc,), file=sys.stderr)
url = urlunparse((
"https", netloc, parsed.path, parsed.params, parsed.query,
parsed.fragment,
))
url = urlunparse(
("https", netloc, parsed.path, parsed.params, parsed.query, parsed.fragment)
)
return super(MatrixConnectionAdapter, self).get_connection(url, proxies)
+38 -24
View File
@@ -1,23 +1,31 @@
from synapse.storage.pdu import PduStore
from synapse.storage.signatures import SignatureStore
from synapse.storage._base import SQLBaseStore
from synapse.federation.units import Pdu
from synapse.crypto.event_signing import (
add_event_pdu_content_hash, compute_pdu_event_reference_hash
)
from synapse.api.events.utils import prune_pdu
from unpaddedbase64 import encode_base64, decode_base64
from canonicaljson import encode_canonical_json
from __future__ import print_function
import sqlite3
import sys
from unpaddedbase64 import decode_base64, encode_base64
from synapse.crypto.event_signing import (
add_event_pdu_content_hash,
compute_pdu_event_reference_hash,
)
from synapse.federation.units import Pdu
from synapse.storage._base import SQLBaseStore
from synapse.storage.pdu import PduStore
from synapse.storage.signatures import SignatureStore
class Store(object):
_get_pdu_tuples = PduStore.__dict__["_get_pdu_tuples"]
_get_pdu_content_hashes_txn = SignatureStore.__dict__["_get_pdu_content_hashes_txn"]
_get_prev_pdu_hashes_txn = SignatureStore.__dict__["_get_prev_pdu_hashes_txn"]
_get_pdu_origin_signatures_txn = SignatureStore.__dict__["_get_pdu_origin_signatures_txn"]
_get_pdu_origin_signatures_txn = SignatureStore.__dict__[
"_get_pdu_origin_signatures_txn"
]
_store_pdu_content_hash_txn = SignatureStore.__dict__["_store_pdu_content_hash_txn"]
_store_pdu_reference_hash_txn = SignatureStore.__dict__["_store_pdu_reference_hash_txn"]
_store_pdu_reference_hash_txn = SignatureStore.__dict__[
"_store_pdu_reference_hash_txn"
]
_store_prev_pdu_hash_txn = SignatureStore.__dict__["_store_prev_pdu_hash_txn"]
_simple_insert_txn = SQLBaseStore.__dict__["_simple_insert_txn"]
@@ -26,9 +34,7 @@ store = Store()
def select_pdus(cursor):
cursor.execute(
"SELECT pdu_id, origin FROM pdus ORDER BY depth ASC"
)
cursor.execute("SELECT pdu_id, origin FROM pdus ORDER BY depth ASC")
ids = cursor.fetchall()
@@ -41,23 +47,30 @@ def select_pdus(cursor):
for pdu in pdus:
try:
if pdu.prev_pdus:
print "PROCESS", pdu.pdu_id, pdu.origin, pdu.prev_pdus
print("PROCESS", pdu.pdu_id, pdu.origin, pdu.prev_pdus)
for pdu_id, origin, hashes in pdu.prev_pdus:
ref_alg, ref_hsh = reference_hashes[(pdu_id, origin)]
hashes[ref_alg] = encode_base64(ref_hsh)
store._store_prev_pdu_hash_txn(cursor, pdu.pdu_id, pdu.origin, pdu_id, origin, ref_alg, ref_hsh)
print "SUCCESS", pdu.pdu_id, pdu.origin, pdu.prev_pdus
store._store_prev_pdu_hash_txn(
cursor, pdu.pdu_id, pdu.origin, pdu_id, origin, ref_alg, ref_hsh
)
print("SUCCESS", pdu.pdu_id, pdu.origin, pdu.prev_pdus)
pdu = add_event_pdu_content_hash(pdu)
ref_alg, ref_hsh = compute_pdu_event_reference_hash(pdu)
reference_hashes[(pdu.pdu_id, pdu.origin)] = (ref_alg, ref_hsh)
store._store_pdu_reference_hash_txn(cursor, pdu.pdu_id, pdu.origin, ref_alg, ref_hsh)
store._store_pdu_reference_hash_txn(
cursor, pdu.pdu_id, pdu.origin, ref_alg, ref_hsh
)
for alg, hsh_base64 in pdu.hashes.items():
print alg, hsh_base64
store._store_pdu_content_hash_txn(cursor, pdu.pdu_id, pdu.origin, alg, decode_base64(hsh_base64))
print(alg, hsh_base64)
store._store_pdu_content_hash_txn(
cursor, pdu.pdu_id, pdu.origin, alg, decode_base64(hsh_base64)
)
except Exception:
print("FAILED_", pdu.pdu_id, pdu.origin, pdu.prev_pdus)
except:
print "FAILED_", pdu.pdu_id, pdu.origin, pdu.prev_pdus
def main():
conn = sqlite3.connect(sys.argv[1])
@@ -65,5 +78,6 @@ def main():
select_pdus(cursor)
conn.commit()
if __name__=='__main__':
if __name__ == '__main__':
main()
+8 -8
View File
@@ -1,18 +1,17 @@
#! /usr/bin/python
import ast
import argparse
import ast
import os
import sys
import yaml
PATTERNS_V1 = []
PATTERNS_V2 = []
RESULT = {
"v1": PATTERNS_V1,
"v2": PATTERNS_V2,
}
RESULT = {"v1": PATTERNS_V1, "v2": PATTERNS_V2}
class CallVisitor(ast.NodeVisitor):
def visit_Call(self, node):
@@ -21,7 +20,6 @@ class CallVisitor(ast.NodeVisitor):
else:
return
if name == "client_path_patterns":
PATTERNS_V1.append(node.args[0].s)
elif name == "client_v2_patterns":
@@ -42,8 +40,10 @@ def find_patterns_in_file(filepath):
parser = argparse.ArgumentParser(description='Find url patterns.')
parser.add_argument(
"directories", nargs='+', metavar="DIR",
help="Directories to search for definitions"
"directories",
nargs='+',
metavar="DIR",
help="Directories to search for definitions",
)
args = parser.parse_args()
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/env perl
use strict;
use warnings;
use DBI;
use DBD::SQLite;
use JSON;
use Getopt::Long;
my $db; # = "homeserver.db";
my $server = "http://localhost:8008";
my $size = 320;
GetOptions("db|d=s", \$db,
"server|s=s", \$server,
"width|w=i", \$size) or usage();
usage() unless $db;
my $dbh = DBI->connect("dbi:SQLite:dbname=$db","","") || die $DBI::errstr;
my $res = $dbh->selectall_arrayref("select token, name from access_tokens, users where access_tokens.user_id = users.id group by user_id") || die $DBI::errstr;
foreach (@$res) {
my ($token, $mxid) = ($_->[0], $_->[1]);
my ($user_id) = ($mxid =~ m/@(.*):/);
my ($url) = $dbh->selectrow_array("select avatar_url from profiles where user_id=?", undef, $user_id);
if (!$url || $url =~ /#auto$/) {
`curl -s -o tmp.png "$server/_matrix/media/v1/identicon?name=${mxid}&width=$size&height=$size"`;
my $json = `curl -s -X POST -H "Content-Type: image/png" -T "tmp.png" $server/_matrix/media/v1/upload?access_token=$token`;
my $content_uri = from_json($json)->{content_uri};
`curl -X PUT -H "Content-Type: application/json" --data '{ "avatar_url": "${content_uri}#auto"}' $server/_matrix/client/api/v1/profile/${mxid}/avatar_url?access_token=$token`;
}
}
sub usage {
die "usage: ./make-identicons.pl\n\t-d database [e.g. homeserver.db]\n\t-s homeserver (default: http://localhost:8008)\n\t-w identicon size in pixels (default 320)";
}
+13 -13
View File
@@ -1,8 +1,9 @@
import requests
import collections
import json
import sys
import time
import json
import requests
Entry = collections.namedtuple("Entry", "name position rows")
@@ -30,11 +31,11 @@ def parse_response(content):
def replicate(server, streams):
return parse_response(requests.get(
server + "/_synapse/replication",
verify=False,
params=streams
).content)
return parse_response(
requests.get(
server + "/_synapse/replication", verify=False, params=streams
).content
)
def main():
@@ -45,16 +46,16 @@ def main():
try:
streams = {
row.name: row.position
for row in replicate(server, {"streams":"-1"})["streams"].rows
for row in replicate(server, {"streams": "-1"})["streams"].rows
}
except requests.exceptions.ConnectionError as e:
except requests.exceptions.ConnectionError:
time.sleep(0.1)
while True:
try:
results = replicate(server, streams)
except:
sys.stdout.write("connection_lost("+ repr(streams) + ")\n")
except Exception:
sys.stdout.write("connection_lost(" + repr(streams) + ")\n")
break
for update in results.values():
for row in update.rows:
@@ -62,6 +63,5 @@ def main():
streams[update.name] = update.position
if __name__=='__main__':
if __name__ == '__main__':
main()
+34 -10
View File
@@ -1,17 +1,17 @@
#!/usr/bin/env python
import argparse
import getpass
import sys
import unicodedata
import bcrypt
import getpass
import yaml
bcrypt_rounds=12
bcrypt_rounds = 12
password_pepper = ""
def prompt_for_pass():
password = getpass.getpass("Password: ")
@@ -25,19 +25,27 @@ def prompt_for_pass():
return password
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Calculate the hash of a new password, so that passwords"
" can be reset")
description=(
"Calculate the hash of a new password, so that passwords can be reset"
)
)
parser.add_argument(
"-p", "--password",
"-p",
"--password",
default=None,
help="New password for user. Will prompt if omitted.",
)
parser.add_argument(
"-c", "--config",
"-c",
"--config",
type=argparse.FileType('r'),
help="Path to server config file. Used to read in bcrypt_rounds and password_pepper.",
help=(
"Path to server config file. "
"Used to read in bcrypt_rounds and password_pepper."
),
)
args = parser.parse_args()
@@ -51,5 +59,21 @@ if __name__ == "__main__":
if not password:
password = prompt_for_pass()
print bcrypt.hashpw(password + password_pepper, bcrypt.gensalt(bcrypt_rounds))
# On Python 2, make sure we decode it to Unicode before we normalise it
if isinstance(password, bytes):
try:
password = password.decode(sys.stdin.encoding)
except UnicodeDecodeError:
print(
"ERROR! Your password is not decodable using your terminal encoding (%s)."
% (sys.stdin.encoding,)
)
pw = unicodedata.normalize("NFKC", password)
hashed = bcrypt.hashpw(
pw.encode('utf8') + password_pepper.encode("utf8"),
bcrypt.gensalt(bcrypt_rounds),
).decode('ascii')
print(hashed)
+12 -24
View File
@@ -36,12 +36,9 @@ from __future__ import print_function
import argparse
import logging
import sys
import os
import shutil
import sys
from synapse.rest.media.v1.filepath import MediaFilePaths
@@ -77,24 +74,23 @@ def move_media(origin_server, file_id, src_paths, dest_paths):
if not os.path.exists(original_file):
logger.warn(
"Original for %s/%s (%s) does not exist",
origin_server, file_id, original_file,
origin_server,
file_id,
original_file,
)
else:
mkdir_and_move(
original_file,
dest_paths.remote_media_filepath(origin_server, file_id),
original_file, dest_paths.remote_media_filepath(origin_server, file_id)
)
# now look for thumbnails
original_thumb_dir = src_paths.remote_media_thumbnail_dir(
origin_server, file_id,
)
original_thumb_dir = src_paths.remote_media_thumbnail_dir(origin_server, file_id)
if not os.path.exists(original_thumb_dir):
return
mkdir_and_move(
original_thumb_dir,
dest_paths.remote_media_thumbnail_dir(origin_server, file_id)
dest_paths.remote_media_thumbnail_dir(origin_server, file_id),
)
@@ -109,24 +105,16 @@ def mkdir_and_move(original_file, dest_file):
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class = argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"-v", action='store_true', help='enable debug logging')
parser.add_argument(
"src_repo",
help="Path to source content repo",
)
parser.add_argument(
"dest_repo",
help="Path to source content repo",
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("-v", action='store_true', help='enable debug logging')
parser.add_argument("src_repo", help="Path to source content repo")
parser.add_argument("dest_repo", help="Path to source content repo")
args = parser.parse_args()
logging_config = {
"level": logging.DEBUG if args.v else logging.INFO,
"format": "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s"
"format": "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s",
}
logging.basicConfig(**logging_config)
+3 -191
View File
@@ -14,197 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import getpass
import hashlib
import hmac
import json
import sys
import urllib2
import yaml
def request_registration(user, password, server_location, shared_secret, admin=False):
req = urllib2.Request(
"%s/_matrix/client/r0/admin/register" % (server_location,),
headers={'Content-Type': 'application/json'}
)
try:
if sys.version_info[:3] >= (2, 7, 9):
# As of version 2.7.9, urllib2 now checks SSL certs
import ssl
f = urllib2.urlopen(req, context=ssl.SSLContext(ssl.PROTOCOL_SSLv23))
else:
f = urllib2.urlopen(req)
body = f.read()
f.close()
nonce = json.loads(body)["nonce"]
except urllib2.HTTPError as e:
print "ERROR! Received %d %s" % (e.code, e.reason,)
if 400 <= e.code < 500:
if e.info().type == "application/json":
resp = json.load(e)
if "error" in resp:
print resp["error"]
sys.exit(1)
mac = hmac.new(
key=shared_secret,
digestmod=hashlib.sha1,
)
mac.update(nonce)
mac.update("\x00")
mac.update(user)
mac.update("\x00")
mac.update(password)
mac.update("\x00")
mac.update("admin" if admin else "notadmin")
mac = mac.hexdigest()
data = {
"nonce": nonce,
"username": user,
"password": password,
"mac": mac,
"admin": admin,
}
server_location = server_location.rstrip("/")
print "Sending registration request..."
req = urllib2.Request(
"%s/_matrix/client/r0/admin/register" % (server_location,),
data=json.dumps(data),
headers={'Content-Type': 'application/json'}
)
try:
if sys.version_info[:3] >= (2, 7, 9):
# As of version 2.7.9, urllib2 now checks SSL certs
import ssl
f = urllib2.urlopen(req, context=ssl.SSLContext(ssl.PROTOCOL_SSLv23))
else:
f = urllib2.urlopen(req)
f.read()
f.close()
print "Success."
except urllib2.HTTPError as e:
print "ERROR! Received %d %s" % (e.code, e.reason,)
if 400 <= e.code < 500:
if e.info().type == "application/json":
resp = json.load(e)
if "error" in resp:
print resp["error"]
sys.exit(1)
def register_new_user(user, password, server_location, shared_secret, admin):
if not user:
try:
default_user = getpass.getuser()
except:
default_user = None
if default_user:
user = raw_input("New user localpart [%s]: " % (default_user,))
if not user:
user = default_user
else:
user = raw_input("New user localpart: ")
if not user:
print "Invalid user name"
sys.exit(1)
if not password:
password = getpass.getpass("Password: ")
if not password:
print "Password cannot be blank."
sys.exit(1)
confirm_password = getpass.getpass("Confirm password: ")
if password != confirm_password:
print "Passwords do not match"
sys.exit(1)
if admin is None:
admin = raw_input("Make admin [no]: ")
if admin in ("y", "yes", "true"):
admin = True
else:
admin = False
request_registration(user, password, server_location, shared_secret, bool(admin))
from synapse._scripts.register_new_matrix_user import main
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Used to register new users with a given home server when"
" registration has been disabled. The home server must be"
" configured with the 'registration_shared_secret' option"
" set.",
)
parser.add_argument(
"-u", "--user",
default=None,
help="Local part of the new user. Will prompt if omitted.",
)
parser.add_argument(
"-p", "--password",
default=None,
help="New password for user. Will prompt if omitted.",
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
"-a", "--admin",
action="store_true",
help="Register new user as an admin. Will prompt if --no-admin is not set either.",
)
admin_group.add_argument(
"--no-admin",
action="store_true",
help="Register new user as a regular user. Will prompt if --admin is not set either.",
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"-c", "--config",
type=argparse.FileType('r'),
help="Path to server config file. Used to read in shared secret.",
)
group.add_argument(
"-k", "--shared-secret",
help="Shared secret as defined in server config file.",
)
parser.add_argument(
"server_url",
default="https://localhost:8448",
nargs='?',
help="URL to use to talk to the home server. Defaults to "
" 'https://localhost:8448'.",
)
args = parser.parse_args()
if "config" in args and args.config:
config = yaml.safe_load(args.config)
secret = config.get("registration_shared_secret", None)
if not secret:
print "No 'registration_shared_secret' defined in config."
sys.exit(1)
else:
secret = args.shared_secret
admin = None
if args.admin or args.no_admin:
admin = args.admin
register_new_user(args.user, args.password, args.server_url, secret, admin)
main()
+124 -151
View File
@@ -15,23 +15,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from twisted.internet import defer, reactor
from twisted.enterprise import adbapi
from synapse.storage._base import LoggingTransaction, SQLBaseStore
from synapse.storage.engines import create_engine
from synapse.storage.prepare_database import prepare_database
import argparse
import curses
import logging
import sys
import time
import traceback
import yaml
from six import string_types
import yaml
from twisted.enterprise import adbapi
from twisted.internet import defer, reactor
from synapse.storage._base import LoggingTransaction, SQLBaseStore
from synapse.storage.engines import create_engine
from synapse.storage.prepare_database import prepare_database
logger = logging.getLogger("synapse_port_db")
@@ -105,6 +105,7 @@ class Store(object):
*All* database interactions should go through this object.
"""
def __init__(self, db_pool, engine):
self.db_pool = db_pool
self.database_engine = engine
@@ -135,7 +136,8 @@ class Store(object):
txn = conn.cursor()
return func(
LoggingTransaction(txn, desc, self.database_engine, [], []),
*args, **kwargs
*args,
**kwargs
)
except self.database_engine.module.DatabaseError as e:
if self.database_engine.is_deadlock(e):
@@ -158,22 +160,20 @@ class Store(object):
def r(txn):
txn.execute(sql, args)
return txn.fetchall()
return self.runInteraction("execute_sql", r)
def insert_many_txn(self, txn, table, headers, rows):
sql = "INSERT INTO %s (%s) VALUES (%s)" % (
table,
", ".join(k for k in headers),
", ".join("%s" for _ in headers)
", ".join("%s" for _ in headers),
)
try:
txn.executemany(sql, rows)
except:
logger.exception(
"Failed to insert: %s",
table,
)
except Exception:
logger.exception("Failed to insert: %s", table)
raise
@@ -206,7 +206,7 @@ class Porter(object):
"table_name": table,
"forward_rowid": 1,
"backward_rowid": 0,
}
},
)
forward_chunk = 1
@@ -221,10 +221,10 @@ class Porter(object):
table, forward_chunk, backward_chunk
)
else:
def delete_all(txn):
txn.execute(
"DELETE FROM port_from_sqlite3 WHERE table_name = %s",
(table,)
"DELETE FROM port_from_sqlite3 WHERE table_name = %s", (table,)
)
txn.execute("TRUNCATE %s CASCADE" % (table,))
@@ -232,11 +232,7 @@ class Porter(object):
yield self.postgres_store._simple_insert(
table="port_from_sqlite3",
values={
"table_name": table,
"forward_rowid": 1,
"backward_rowid": 0,
}
values={"table_name": table, "forward_rowid": 1, "backward_rowid": 0},
)
forward_chunk = 1
@@ -251,12 +247,16 @@ class Porter(object):
)
@defer.inlineCallbacks
def handle_table(self, table, postgres_size, table_size, forward_chunk,
backward_chunk):
def handle_table(
self, table, postgres_size, table_size, forward_chunk, backward_chunk
):
logger.info(
"Table %s: %i/%i (rows %i-%i) already ported",
table, postgres_size, table_size,
backward_chunk+1, forward_chunk-1,
table,
postgres_size,
table_size,
backward_chunk + 1,
forward_chunk - 1,
)
if not table_size:
@@ -271,7 +271,9 @@ class Porter(object):
return
if table in (
"user_directory", "user_directory_search", "users_who_share_rooms",
"user_directory",
"user_directory_search",
"users_who_share_rooms",
"users_in_pubic_room",
):
# We don't port these tables, as they're a faff and we can regenreate
@@ -283,37 +285,35 @@ class Porter(object):
# We need to make sure there is a single row, `(X, null), as that is
# what synapse expects to be there.
yield self.postgres_store._simple_insert(
table=table,
values={"stream_id": None},
table=table, values={"stream_id": None}
)
self.progress.update(table, table_size) # Mark table as done
return
forward_select = (
"SELECT rowid, * FROM %s WHERE rowid >= ? ORDER BY rowid LIMIT ?"
% (table,)
"SELECT rowid, * FROM %s WHERE rowid >= ? ORDER BY rowid LIMIT ?" % (table,)
)
backward_select = (
"SELECT rowid, * FROM %s WHERE rowid <= ? ORDER BY rowid LIMIT ?"
% (table,)
"SELECT rowid, * FROM %s WHERE rowid <= ? ORDER BY rowid LIMIT ?" % (table,)
)
do_forward = [True]
do_backward = [True]
while True:
def r(txn):
forward_rows = []
backward_rows = []
if do_forward[0]:
txn.execute(forward_select, (forward_chunk, self.batch_size,))
txn.execute(forward_select, (forward_chunk, self.batch_size))
forward_rows = txn.fetchall()
if not forward_rows:
do_forward[0] = False
if do_backward[0]:
txn.execute(backward_select, (backward_chunk, self.batch_size,))
txn.execute(backward_select, (backward_chunk, self.batch_size))
backward_rows = txn.fetchall()
if not backward_rows:
do_backward[0] = False
@@ -325,9 +325,7 @@ class Porter(object):
return headers, forward_rows, backward_rows
headers, frows, brows = yield self.sqlite_store.runInteraction(
"select", r
)
headers, frows, brows = yield self.sqlite_store.runInteraction("select", r)
if frows or brows:
if frows:
@@ -339,9 +337,7 @@ class Porter(object):
rows = self._convert_rows(table, headers, rows)
def insert(txn):
self.postgres_store.insert_many_txn(
txn, table, headers[1:], rows
)
self.postgres_store.insert_many_txn(txn, table, headers[1:], rows)
self.postgres_store._simple_update_one_txn(
txn,
@@ -362,8 +358,9 @@ class Porter(object):
return
@defer.inlineCallbacks
def handle_search_table(self, postgres_size, table_size, forward_chunk,
backward_chunk):
def handle_search_table(
self, postgres_size, table_size, forward_chunk, backward_chunk
):
select = (
"SELECT es.rowid, es.*, e.origin_server_ts, e.stream_ordering"
" FROM event_search as es"
@@ -373,8 +370,9 @@ class Porter(object):
)
while True:
def r(txn):
txn.execute(select, (forward_chunk, self.batch_size,))
txn.execute(select, (forward_chunk, self.batch_size))
rows = txn.fetchall()
headers = [column[0] for column in txn.description]
@@ -402,18 +400,21 @@ class Porter(object):
else:
rows_dict.append(d)
txn.executemany(sql, [
(
row["event_id"],
row["room_id"],
row["key"],
row["sender"],
row["value"],
row["origin_server_ts"],
row["stream_ordering"],
)
for row in rows_dict
])
txn.executemany(
sql,
[
(
row["event_id"],
row["room_id"],
row["key"],
row["sender"],
row["value"],
row["origin_server_ts"],
row["stream_ordering"],
)
for row in rows_dict
],
)
self.postgres_store._simple_update_one_txn(
txn,
@@ -437,7 +438,8 @@ class Porter(object):
def setup_db(self, db_config, database_engine):
db_conn = database_engine.module.connect(
**{
k: v for k, v in db_config.get("args", {}).items()
k: v
for k, v in db_config.get("args", {}).items()
if not k.startswith("cp_")
}
)
@@ -450,13 +452,11 @@ class Porter(object):
def run(self):
try:
sqlite_db_pool = adbapi.ConnectionPool(
self.sqlite_config["name"],
**self.sqlite_config["args"]
self.sqlite_config["name"], **self.sqlite_config["args"]
)
postgres_db_pool = adbapi.ConnectionPool(
self.postgres_config["name"],
**self.postgres_config["args"]
self.postgres_config["name"], **self.postgres_config["args"]
)
sqlite_engine = create_engine(sqlite_config)
@@ -465,9 +465,7 @@ class Porter(object):
self.sqlite_store = Store(sqlite_db_pool, sqlite_engine)
self.postgres_store = Store(postgres_db_pool, postgres_engine)
yield self.postgres_store.execute(
postgres_engine.check_database
)
yield self.postgres_store.execute(postgres_engine.check_database)
# Step 1. Set up databases.
self.progress.set_state("Preparing SQLite3")
@@ -477,6 +475,7 @@ class Porter(object):
self.setup_db(postgres_config, postgres_engine)
self.progress.set_state("Creating port tables")
def create_port_table(txn):
txn.execute(
"CREATE TABLE IF NOT EXISTS port_from_sqlite3 ("
@@ -501,10 +500,9 @@ class Porter(object):
)
try:
yield self.postgres_store.runInteraction(
"alter_table", alter_table
)
except Exception as e:
yield self.postgres_store.runInteraction("alter_table", alter_table)
except Exception:
# On Error Resume Next
pass
yield self.postgres_store.runInteraction(
@@ -514,11 +512,7 @@ class Porter(object):
# Step 2. Get tables.
self.progress.set_state("Fetching tables")
sqlite_tables = yield self.sqlite_store._simple_select_onecol(
table="sqlite_master",
keyvalues={
"type": "table",
},
retcol="name",
table="sqlite_master", keyvalues={"type": "table"}, retcol="name"
)
postgres_tables = yield self.postgres_store._simple_select_onecol(
@@ -545,18 +539,14 @@ class Porter(object):
# Step 4. Do the copying.
self.progress.set_state("Copying to postgres")
yield defer.gatherResults(
[
self.handle_table(*res)
for res in setup_res
],
consumeErrors=True,
[self.handle_table(*res) for res in setup_res], consumeErrors=True
)
# Step 5. Do final post-processing
yield self._setup_state_group_id_seq()
self.progress.done()
except:
except Exception:
global end_error_exec_info
end_error_exec_info = sys.exc_info()
logger.exception("")
@@ -566,9 +556,7 @@ class Porter(object):
def _convert_rows(self, table, headers, rows):
bool_col_names = BOOLEAN_COLUMNS.get(table, [])
bool_cols = [
i for i, h in enumerate(headers) if h in bool_col_names
]
bool_cols = [i for i, h in enumerate(headers) if h in bool_col_names]
class BadValueException(Exception):
pass
@@ -577,18 +565,21 @@ class Porter(object):
if j in bool_cols:
return bool(col)
elif isinstance(col, string_types) and "\0" in col:
logger.warn("DROPPING ROW: NUL value in table %s col %s: %r", table, headers[j], col)
raise BadValueException();
logger.warn(
"DROPPING ROW: NUL value in table %s col %s: %r",
table,
headers[j],
col,
)
raise BadValueException()
return col
outrows = []
for i, row in enumerate(rows):
try:
outrows.append(tuple(
conv(j, col)
for j, col in enumerate(row)
if j > 0
))
outrows.append(
tuple(conv(j, col) for j, col in enumerate(row) if j > 0)
)
except BadValueException:
pass
@@ -616,9 +607,7 @@ class Porter(object):
return headers, [r for r in rows if r[ts_ind] < yesterday]
headers, rows = yield self.sqlite_store.runInteraction(
"select", r,
)
headers, rows = yield self.sqlite_store.runInteraction("select", r)
rows = self._convert_rows("sent_transactions", headers, rows)
@@ -639,7 +628,7 @@ class Porter(object):
txn.execute(
"SELECT rowid FROM sent_transactions WHERE ts >= ?"
" ORDER BY rowid ASC LIMIT 1",
(yesterday,)
(yesterday,),
)
rows = txn.fetchall()
@@ -657,21 +646,17 @@ class Porter(object):
"table_name": "sent_transactions",
"forward_rowid": next_chunk,
"backward_rowid": 0,
}
},
)
def get_sent_table_size(txn):
txn.execute(
"SELECT count(*) FROM sent_transactions"
" WHERE ts >= ?",
(yesterday,)
"SELECT count(*) FROM sent_transactions" " WHERE ts >= ?", (yesterday,)
)
size, = txn.fetchone()
return int(size)
remaining_count = yield self.sqlite_store.execute(
get_sent_table_size
)
remaining_count = yield self.sqlite_store.execute(get_sent_table_size)
total_count = remaining_count + inserted_rows
@@ -680,13 +665,11 @@ class Porter(object):
@defer.inlineCallbacks
def _get_remaining_count_to_port(self, table, forward_chunk, backward_chunk):
frows = yield self.sqlite_store.execute_sql(
"SELECT count(*) FROM %s WHERE rowid >= ?" % (table,),
forward_chunk,
"SELECT count(*) FROM %s WHERE rowid >= ?" % (table,), forward_chunk
)
brows = yield self.sqlite_store.execute_sql(
"SELECT count(*) FROM %s WHERE rowid <= ?" % (table,),
backward_chunk,
"SELECT count(*) FROM %s WHERE rowid <= ?" % (table,), backward_chunk
)
defer.returnValue(frows[0][0] + brows[0][0])
@@ -694,7 +677,7 @@ class Porter(object):
@defer.inlineCallbacks
def _get_already_ported_count(self, table):
rows = yield self.postgres_store.execute_sql(
"SELECT count(*) FROM %s" % (table,),
"SELECT count(*) FROM %s" % (table,)
)
defer.returnValue(rows[0][0])
@@ -717,22 +700,21 @@ class Porter(object):
def _setup_state_group_id_seq(self):
def r(txn):
txn.execute("SELECT MAX(id) FROM state_groups")
next_id = txn.fetchone()[0]+1
txn.execute(
"ALTER SEQUENCE state_group_id_seq RESTART WITH %s",
(next_id,),
)
next_id = txn.fetchone()[0] + 1
txn.execute("ALTER SEQUENCE state_group_id_seq RESTART WITH %s", (next_id,))
return self.postgres_store.runInteraction("setup_state_group_id_seq", r)
##############################################
###### The following is simply UI stuff ######
# The following is simply UI stuff
##############################################
class Progress(object):
"""Used to report progress of the port
"""
def __init__(self):
self.tables = {}
@@ -758,6 +740,7 @@ class Progress(object):
class CursesProgress(Progress):
"""Reports progress to a curses window
"""
def __init__(self, stdscr):
self.stdscr = stdscr
@@ -801,7 +784,7 @@ class CursesProgress(Progress):
duration = int(now) - int(self.start_time)
minutes, seconds = divmod(duration, 60)
duration_str = '%02dm %02ds' % (minutes, seconds,)
duration_str = '%02dm %02ds' % (minutes, seconds)
if self.finished:
status = "Time spent: %s (Done!)" % (duration_str,)
@@ -814,16 +797,12 @@ class CursesProgress(Progress):
est_remaining_str = '%02dm %02ds remaining' % divmod(est_remaining, 60)
else:
est_remaining_str = "Unknown"
status = (
"Time spent: %s (est. remaining: %s)"
% (duration_str, est_remaining_str,)
status = "Time spent: %s (est. remaining: %s)" % (
duration_str,
est_remaining_str,
)
self.stdscr.addstr(
0, 0,
status,
curses.A_BOLD,
)
self.stdscr.addstr(0, 0, status, curses.A_BOLD)
max_len = max([len(t) for t in self.tables.keys()])
@@ -831,9 +810,7 @@ class CursesProgress(Progress):
middle_space = 1
items = self.tables.items()
items.sort(
key=lambda i: (i[1]["perc"], i[0]),
)
items.sort(key=lambda i: (i[1]["perc"], i[0]))
for i, (table, data) in enumerate(items):
if i + 2 >= rows:
@@ -844,9 +821,7 @@ class CursesProgress(Progress):
color = curses.color_pair(2) if perc == 100 else curses.color_pair(1)
self.stdscr.addstr(
i + 2, left_margin + max_len - len(table),
table,
curses.A_BOLD | color,
i + 2, left_margin + max_len - len(table), table, curses.A_BOLD | color
)
size = 20
@@ -857,15 +832,13 @@ class CursesProgress(Progress):
)
self.stdscr.addstr(
i + 2, left_margin + max_len + middle_space,
i + 2,
left_margin + max_len + middle_space,
"%s %3d%% (%d/%d)" % (progress, perc, data["num_done"], data["total"]),
)
if self.finished:
self.stdscr.addstr(
rows - 1, 0,
"Press any key to exit...",
)
self.stdscr.addstr(rows - 1, 0, "Press any key to exit...")
self.stdscr.refresh()
self.last_update = time.time()
@@ -877,29 +850,25 @@ class CursesProgress(Progress):
def set_state(self, state):
self.stdscr.clear()
self.stdscr.addstr(
0, 0,
state + "...",
curses.A_BOLD,
)
self.stdscr.addstr(0, 0, state + "...", curses.A_BOLD)
self.stdscr.refresh()
class TerminalProgress(Progress):
"""Just prints progress to the terminal
"""
def update(self, table, num_done):
super(TerminalProgress, self).update(table, num_done)
data = self.tables[table]
print "%s: %d%% (%d/%d)" % (
table, data["perc"],
data["num_done"], data["total"],
print(
"%s: %d%% (%d/%d)" % (table, data["perc"], data["num_done"], data["total"])
)
def set_state(self, state):
print state + "..."
print(state + "...")
##############################################
@@ -909,34 +878,38 @@ class TerminalProgress(Progress):
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="A script to port an existing synapse SQLite database to"
" a new PostgreSQL database."
" a new PostgreSQL database."
)
parser.add_argument("-v", action='store_true')
parser.add_argument(
"--sqlite-database", required=True,
"--sqlite-database",
required=True,
help="The snapshot of the SQLite database file. This must not be"
" currently used by a running synapse server"
" currently used by a running synapse server",
)
parser.add_argument(
"--postgres-config", type=argparse.FileType('r'), required=True,
help="The database config file for the PostgreSQL database"
"--postgres-config",
type=argparse.FileType('r'),
required=True,
help="The database config file for the PostgreSQL database",
)
parser.add_argument(
"--curses", action='store_true',
help="display a curses based progress UI"
"--curses", action='store_true', help="display a curses based progress UI"
)
parser.add_argument(
"--batch-size", type=int, default=1000,
"--batch-size",
type=int,
default=1000,
help="The number of rows to select from the SQLite table each"
" iteration [default=1000]",
" iteration [default=1000]",
)
args = parser.parse_args()
logging_config = {
"level": logging.DEBUG if args.v else logging.INFO,
"format": "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s"
"format": "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s",
}
if args.curses:
+8 -9
View File
@@ -14,17 +14,16 @@ ignore =
pylint.cfg
tox.ini
[pep8]
max-line-length = 90
# W503 requires that binary operators be at the end, not start, of lines. Erik
# doesn't like it. E203 is contrary to PEP8. E731 is silly.
ignore = W503,E203,E731
[flake8]
# note that flake8 inherits the "ignore" settings from "pep8" (because it uses
# pep8 to do those checks), but not the "max-line-length" setting
max-line-length = 90
ignore=W503,E203,E731
# see https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes
# for error codes. The ones we ignore are:
# W503: line break before binary operator
# W504: line break after binary operator
# E203: whitespace before ':' (which is contrary to pep8?)
# E731: do not assign a lambda expression, use a def
ignore=W503,W504,E203,E731
[isort]
line_length = 89
+4 -2
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env python
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2014-2017 OpenMarket Ltd
# Copyright 2017 Vector Creations Ltd
# Copyright 2017-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.
@@ -86,7 +88,7 @@ setup(
name="matrix-synapse",
version=version,
packages=find_packages(exclude=["tests", "tests.*"]),
description="Reference Synapse Home Server",
description="Reference homeserver for the Matrix decentralised comms protocol",
install_requires=dependencies['requirements'](include_conditional=True).keys(),
dependency_links=dependencies["DEPENDENCY_LINKS"].values(),
include_package_data=True,
+1 -1
View File
@@ -27,4 +27,4 @@ try:
except ImportError:
pass
__version__ = "0.33.6"
__version__ = "0.33.9"
View File
@@ -0,0 +1,215 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd
# Copyright 2018 New Vector
#
# 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.
from __future__ import print_function
import argparse
import getpass
import hashlib
import hmac
import logging
import sys
from six.moves import input
import requests as _requests
import yaml
def request_registration(
user,
password,
server_location,
shared_secret,
admin=False,
requests=_requests,
_print=print,
exit=sys.exit,
):
url = "%s/_matrix/client/r0/admin/register" % (server_location,)
# Get the nonce
r = requests.get(url, verify=False)
if r.status_code is not 200:
_print("ERROR! Received %d %s" % (r.status_code, r.reason))
if 400 <= r.status_code < 500:
try:
_print(r.json()["error"])
except Exception:
pass
return exit(1)
nonce = r.json()["nonce"]
mac = hmac.new(key=shared_secret.encode('utf8'), digestmod=hashlib.sha1)
mac.update(nonce.encode('utf8'))
mac.update(b"\x00")
mac.update(user.encode('utf8'))
mac.update(b"\x00")
mac.update(password.encode('utf8'))
mac.update(b"\x00")
mac.update(b"admin" if admin else b"notadmin")
mac = mac.hexdigest()
data = {
"nonce": nonce,
"username": user,
"password": password,
"mac": mac,
"admin": admin,
}
_print("Sending registration request...")
r = requests.post(url, json=data, verify=False)
if r.status_code is not 200:
_print("ERROR! Received %d %s" % (r.status_code, r.reason))
if 400 <= r.status_code < 500:
try:
_print(r.json()["error"])
except Exception:
pass
return exit(1)
_print("Success!")
def register_new_user(user, password, server_location, shared_secret, admin):
if not user:
try:
default_user = getpass.getuser()
except Exception:
default_user = None
if default_user:
user = input("New user localpart [%s]: " % (default_user,))
if not user:
user = default_user
else:
user = input("New user localpart: ")
if not user:
print("Invalid user name")
sys.exit(1)
if not password:
password = getpass.getpass("Password: ")
if not password:
print("Password cannot be blank.")
sys.exit(1)
confirm_password = getpass.getpass("Confirm password: ")
if password != confirm_password:
print("Passwords do not match")
sys.exit(1)
if admin is None:
admin = input("Make admin [no]: ")
if admin in ("y", "yes", "true"):
admin = True
else:
admin = False
request_registration(user, password, server_location, shared_secret, bool(admin))
def main():
logging.captureWarnings(True)
parser = argparse.ArgumentParser(
description="Used to register new users with a given home server when"
" registration has been disabled. The home server must be"
" configured with the 'registration_shared_secret' option"
" set."
)
parser.add_argument(
"-u",
"--user",
default=None,
help="Local part of the new user. Will prompt if omitted.",
)
parser.add_argument(
"-p",
"--password",
default=None,
help="New password for user. Will prompt if omitted.",
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
"-a",
"--admin",
action="store_true",
help=(
"Register new user as an admin. "
"Will prompt if --no-admin is not set either."
),
)
admin_group.add_argument(
"--no-admin",
action="store_true",
help=(
"Register new user as a regular user. "
"Will prompt if --admin is not set either."
),
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"-c",
"--config",
type=argparse.FileType('r'),
help="Path to server config file. Used to read in shared secret.",
)
group.add_argument(
"-k", "--shared-secret", help="Shared secret as defined in server config file."
)
parser.add_argument(
"server_url",
default="https://localhost:8448",
nargs='?',
help="URL to use to talk to the home server. Defaults to "
" 'https://localhost:8448'.",
)
args = parser.parse_args()
if "config" in args and args.config:
config = yaml.safe_load(args.config)
secret = config.get("registration_shared_secret", None)
if not secret:
print("No 'registration_shared_secret' defined in config.")
sys.exit(1)
else:
secret = args.shared_secret
admin = None
if args.admin or args.no_admin:
admin = args.admin
register_new_user(args.user, args.password, args.server_url, secret, admin)
if __name__ == "__main__":
main()
+8 -1
View File
@@ -51,6 +51,7 @@ class LoginType(object):
EMAIL_IDENTITY = u"m.login.email.identity"
MSISDN = u"m.login.msisdn"
RECAPTCHA = u"m.login.recaptcha"
TERMS = u"m.login.terms"
DUMMY = u"m.login.dummy"
# Only for C/S API v1
@@ -61,6 +62,7 @@ class LoginType(object):
class EventTypes(object):
Member = "m.room.member"
Create = "m.room.create"
Tombstone = "m.room.tombstone"
JoinRules = "m.room.join_rules"
PowerLevels = "m.room.power_levels"
Aliases = "m.room.aliases"
@@ -101,6 +103,7 @@ class ThirdPartyEntityKind(object):
class RoomVersions(object):
V1 = "1"
VDH_TEST = "vdh-test-version"
STATE_V2_TEST = "state-v2-test"
# the version we will give rooms which are created on this server
@@ -108,7 +111,11 @@ DEFAULT_ROOM_VERSION = RoomVersions.V1
# vdh-test-version is a placeholder to get room versioning support working and tested
# until we have a working v2.
KNOWN_ROOM_VERSIONS = {RoomVersions.V1, RoomVersions.VDH_TEST}
KNOWN_ROOM_VERSIONS = {
RoomVersions.V1,
RoomVersions.VDH_TEST,
RoomVersions.STATE_V2_TEST,
}
ServerNoticeMsgType = "m.server_notice"
ServerNoticeLimitReached = "m.server_notice.usage_limit_reached"
+15
View File
@@ -59,6 +59,7 @@ class Codes(object):
RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED"
UNSUPPORTED_ROOM_VERSION = "M_UNSUPPORTED_ROOM_VERSION"
INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION"
WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
class CodeMessageException(RuntimeError):
@@ -312,6 +313,20 @@ class LimitExceededError(SynapseError):
)
class RoomKeysVersionError(SynapseError):
"""A client has tried to upload to a non-current version of the room_keys store
"""
def __init__(self, current_version):
"""
Args:
current_version (str): the current version of the store they should have used
"""
super(RoomKeysVersionError, self).__init__(
403, "Wrong room_keys version", Codes.WRONG_ROOM_KEYS_VERSION
)
self.current_version = current_version
class IncompatibleRoomVersionError(SynapseError):
"""A server is trying to join a room whose version it does not support."""
+9 -1
View File
@@ -120,6 +120,9 @@ ROOM_EVENT_FILTER_SCHEMA = {
"include_redundant_members": {
"type": "boolean"
},
"thread_id": {
"type": "number",
}
}
}
@@ -172,7 +175,10 @@ USER_FILTER_SCHEMA = {
# events a lot easier as we can then use a negative lookbehind
# assertion to split '\.' If we allowed \\ then it would
# incorrectly split '\\.' See synapse.events.utils.serialize_event
"pattern": "^((?!\\\).)*$"
#
# Note that because this is a regular expression, we have to escape
# each backslash in the pattern.
"pattern": r"^((?!\\\\).)*$"
}
}
},
@@ -328,6 +334,8 @@ class Filter(object):
self.contains_url = self.filter_json.get("contains_url", None)
self.thread_id = self.filter_json.get("thread_id", None)
def filters_all_types(self):
return "*" in self.not_types
-1
View File
@@ -28,7 +28,6 @@ FEDERATION_PREFIX = "/_matrix/federation/v1"
STATIC_PREFIX = "/_matrix/static"
WEB_CLIENT_PREFIX = "/_matrix/client"
CONTENT_REPO_PREFIX = "/_matrix/content"
SERVER_KEY_PREFIX = "/_matrix/key/v1"
SERVER_KEY_V2_PREFIX = "/_matrix/key/v2"
MEDIA_PREFIX = "/_matrix/media/r0"
LEGACY_MEDIA_PREFIX = "/_matrix/media/v1"
+15 -15
View File
@@ -17,6 +17,7 @@ import gc
import logging
import sys
import psutil
from daemonize import Daemonize
from twisted.internet import error, reactor
@@ -24,12 +25,6 @@ from twisted.internet import error, reactor
from synapse.util import PreserveLoggingContext
from synapse.util.rlimit import change_resource_limit
try:
import affinity
except Exception:
affinity = None
logger = logging.getLogger(__name__)
@@ -89,15 +84,20 @@ def start_reactor(
with PreserveLoggingContext():
logger.info("Running")
if cpu_affinity is not None:
if not affinity:
quit_with_error(
"Missing package 'affinity' required for cpu_affinity\n"
"option\n\n"
"Install by running:\n\n"
" pip install affinity\n\n"
)
logger.info("Setting CPU affinity to %s" % cpu_affinity)
affinity.set_process_affinity_mask(0, cpu_affinity)
# Turn the bitmask into bits, reverse it so we go from 0 up
mask_to_bits = bin(cpu_affinity)[2:][::-1]
cpus = []
cpu_num = 0
for i in mask_to_bits:
if i == "1":
cpus.append(cpu_num)
cpu_num += 1
p = psutil.Process()
p.cpu_affinity(cpus)
change_resource_limit(soft_file_limit)
if gc_thresholds:
gc.set_threshold(*gc_thresholds)
+3
View File
@@ -178,6 +178,9 @@ def start(config_options):
setup_logging(config, use_worker_options=True)
# This should only be done on the user directory worker or the master
config.update_user_directory = False
events.USE_FROZEN_DICTS = config.use_frozen_dicts
database_engine = create_engine(config.database_config)
+2 -2
View File
@@ -68,7 +68,7 @@ class PresenceStatusStubServlet(ClientV1RestServlet):
"Authorization": auth_headers,
}
result = yield self.http_client.get_json(
self.main_uri + request.uri,
self.main_uri + request.uri.decode('ascii'),
headers=headers,
)
defer.returnValue((200, result))
@@ -125,7 +125,7 @@ class KeyUploadServlet(RestServlet):
"Authorization": auth_headers,
}
result = yield self.http_client.post_json_get_json(
self.main_uri + request.uri,
self.main_uri + request.uri.decode('ascii'),
body,
headers=headers,
)
+22 -24
View File
@@ -20,6 +20,7 @@ import sys
from six import iteritems
import psutil
from prometheus_client import Gauge
from twisted.application import service
@@ -36,7 +37,6 @@ from synapse.api.urls import (
FEDERATION_PREFIX,
LEGACY_MEDIA_PREFIX,
MEDIA_PREFIX,
SERVER_KEY_PREFIX,
SERVER_KEY_V2_PREFIX,
STATIC_PREFIX,
WEB_CLIENT_PREFIX,
@@ -58,7 +58,6 @@ from synapse.python_dependencies import CONDITIONAL_REQUIREMENTS, check_requirem
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory
from synapse.rest import ClientRestResource
from synapse.rest.key.v1.server_key_resource import LocalKey
from synapse.rest.key.v2 import KeyApiV2Resource
from synapse.rest.media.v0.content_repository import ContentRepoResource
from synapse.server import HomeServer
@@ -235,10 +234,7 @@ class SynapseHomeServer(HomeServer):
)
if name in ["keys", "federation"]:
resources.update({
SERVER_KEY_PREFIX: LocalKey(self),
SERVER_KEY_V2_PREFIX: KeyApiV2Resource(self),
})
resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
if name == "webclient":
resources[WEB_CLIENT_PREFIX] = build_resource_for_web_client(self)
@@ -502,7 +498,6 @@ def run(hs):
def performance_stats_init():
try:
import psutil
process = psutil.Process()
# Ensure we can fetch both, and make the initial request for cpu_percent
# so the next request will use this as the initial point.
@@ -510,12 +505,9 @@ def run(hs):
process.cpu_percent(interval=None)
logger.info("report_stats can use psutil")
stats_process.append(process)
except (ImportError, AttributeError):
logger.warn(
"report_stats enabled but psutil is not installed or incorrect version."
" Disabling reporting of memory/cpu stats."
" Ensuring psutil is available will help matrix.org track performance"
" changes across releases."
except (AttributeError):
logger.warning(
"Unable to read memory/cpu stats. Disabling reporting."
)
def generate_user_daily_visit_stats():
@@ -530,29 +522,35 @@ def run(hs):
clock.looping_call(generate_user_daily_visit_stats, 5 * 60 * 1000)
# monthly active user limiting functionality
clock.looping_call(
hs.get_datastore().reap_monthly_active_users, 1000 * 60 * 60
)
hs.get_datastore().reap_monthly_active_users()
def reap_monthly_active_users():
return run_as_background_process(
"reap_monthly_active_users",
hs.get_datastore().reap_monthly_active_users,
)
clock.looping_call(reap_monthly_active_users, 1000 * 60 * 60)
reap_monthly_active_users()
@defer.inlineCallbacks
def generate_monthly_active_users():
current_mau_count = 0
reserved_count = 0
store = hs.get_datastore()
if hs.config.limit_usage_by_mau:
if hs.config.limit_usage_by_mau or hs.config.mau_stats_only:
current_mau_count = yield store.get_monthly_active_count()
reserved_count = yield store.get_registered_reserved_users_count()
current_mau_gauge.set(float(current_mau_count))
registered_reserved_users_mau_gauge.set(float(reserved_count))
max_mau_gauge.set(float(hs.config.max_mau_value))
hs.get_datastore().initialise_reserved_users(
hs.config.mau_limits_reserved_threepids
)
generate_monthly_active_users()
def start_generate_monthly_active_users():
return run_as_background_process(
"generate_monthly_active_users",
generate_monthly_active_users,
)
start_generate_monthly_active_users()
if hs.config.limit_usage_by_mau:
clock.looping_call(generate_monthly_active_users, 5 * 60 * 1000)
clock.looping_call(start_generate_monthly_active_users, 5 * 60 * 1000)
# End of monthly active user settings
if hs.config.report_stats:
@@ -568,7 +566,7 @@ def run(hs):
clock.call_later(5 * 60, start_phone_stats_home)
if hs.config.daemonize and hs.config.print_pidfile:
print (hs.config.pid_file)
print(hs.config.pid_file)
_base.start_reactor(
"synapse-homeserver",
+11 -10
View File
@@ -28,6 +28,7 @@ from synapse.config.logger import setup_logging
from synapse.http.site import SynapseSite
from synapse.metrics import RegistryProxy
from synapse.metrics.resource import METRICS_PREFIX, MetricsResource
from synapse.replication.slave.storage._base import __func__
from synapse.replication.slave.storage.account_data import SlavedAccountDataStore
from synapse.replication.slave.storage.events import SlavedEventStore
from synapse.replication.slave.storage.pushers import SlavedPusherStore
@@ -49,31 +50,31 @@ class PusherSlaveStore(
SlavedAccountDataStore
):
update_pusher_last_stream_ordering_and_success = (
DataStore.update_pusher_last_stream_ordering_and_success.__func__
__func__(DataStore.update_pusher_last_stream_ordering_and_success)
)
update_pusher_failing_since = (
DataStore.update_pusher_failing_since.__func__
__func__(DataStore.update_pusher_failing_since)
)
update_pusher_last_stream_ordering = (
DataStore.update_pusher_last_stream_ordering.__func__
__func__(DataStore.update_pusher_last_stream_ordering)
)
get_throttle_params_by_room = (
DataStore.get_throttle_params_by_room.__func__
__func__(DataStore.get_throttle_params_by_room)
)
set_throttle_params = (
DataStore.set_throttle_params.__func__
__func__(DataStore.set_throttle_params)
)
get_time_of_last_push_action_before = (
DataStore.get_time_of_last_push_action_before.__func__
__func__(DataStore.get_time_of_last_push_action_before)
)
get_profile_displayname = (
DataStore.get_profile_displayname.__func__
__func__(DataStore.get_profile_displayname)
)
@@ -160,11 +161,11 @@ class PusherReplicationHandler(ReplicationClientHandler):
else:
yield self.start_pusher(row.user_id, row.app_id, row.pushkey)
elif stream_name == "events":
self.pusher_pool.on_new_notifications(
yield self.pusher_pool.on_new_notifications(
token, token,
)
elif stream_name == "receipts":
self.pusher_pool.on_new_receipts(
yield self.pusher_pool.on_new_receipts(
token, token, set(row.room_id for row in rows)
)
except Exception:
@@ -182,7 +183,7 @@ class PusherReplicationHandler(ReplicationClientHandler):
def start_pusher(self, user_id, app_id, pushkey):
key = "%s:%s" % (app_id, pushkey)
logger.info("Starting pusher %r / %r", user_id, key)
return self.pusher_pool._refresh_pusher(app_id, pushkey, user_id)
return self.pusher_pool.start_pusher_by_id(app_id, pushkey, user_id)
def start(config_options):
+20 -6
View File
@@ -33,7 +33,7 @@ from synapse.http.server import JsonResource
from synapse.http.site import SynapseSite
from synapse.metrics import RegistryProxy
from synapse.metrics.resource import METRICS_PREFIX, MetricsResource
from synapse.replication.slave.storage._base import BaseSlavedStore
from synapse.replication.slave.storage._base import BaseSlavedStore, __func__
from synapse.replication.slave.storage.account_data import SlavedAccountDataStore
from synapse.replication.slave.storage.appservice import SlavedApplicationServiceStore
from synapse.replication.slave.storage.client_ips import SlavedClientIpStore
@@ -147,7 +147,7 @@ class SynchrotronPresence(object):
and haven't come back yet. If there are poke the master about them.
"""
now = self.clock.time_msec()
for user_id, last_sync_ms in self.users_going_offline.items():
for user_id, last_sync_ms in list(self.users_going_offline.items()):
if now - last_sync_ms > 10 * 1000:
self.users_going_offline.pop(user_id, None)
self.send_user_sync(user_id, False, last_sync_ms)
@@ -156,9 +156,9 @@ class SynchrotronPresence(object):
# TODO Hows this supposed to work?
pass
get_states = PresenceHandler.get_states.__func__
get_state = PresenceHandler.get_state.__func__
current_state_for_users = PresenceHandler.current_state_for_users.__func__
get_states = __func__(PresenceHandler.get_states)
get_state = __func__(PresenceHandler.get_state)
current_state_for_users = __func__(PresenceHandler.current_state_for_users)
def user_syncing(self, user_id, affect_presence):
if affect_presence:
@@ -208,7 +208,7 @@ class SynchrotronPresence(object):
) for row in rows]
for state in states:
self.user_to_current_state[row.user_id] = state
self.user_to_current_state[state.user_id] = state
stream_id = token
yield self.notify_from_replication(states, stream_id)
@@ -226,7 +226,15 @@ class SynchrotronPresence(object):
class SynchrotronTyping(object):
def __init__(self, hs):
self._latest_room_serial = 0
self._reset()
def _reset(self):
"""
Reset the typing handler's data caches.
"""
# map room IDs to serial numbers
self._room_serials = {}
# map room IDs to sets of users currently typing
self._room_typing = {}
def stream_positions(self):
@@ -236,6 +244,12 @@ class SynchrotronTyping(object):
return {"typing": self._latest_room_serial}
def process_replication_rows(self, token, rows):
if self._latest_room_serial > token:
# The master has gone backwards. To prevent inconsistent data, just
# clear everything.
self._reset()
# Set the latest serial token to whatever the server gave us.
self._latest_room_serial = token
for row in rows:
+1 -1
View File
@@ -28,7 +28,7 @@ if __name__ == "__main__":
sys.stderr.write("\n" + str(e) + "\n")
sys.exit(1)
print (getattr(config, key))
print(getattr(config, key))
sys.exit(0)
else:
sys.stderr.write("Unknown command %r\n" % (action,))
+59 -62
View File
@@ -106,10 +106,7 @@ class Config(object):
@classmethod
def check_file(cls, file_path, config_name):
if file_path is None:
raise ConfigError(
"Missing config for %s."
% (config_name,)
)
raise ConfigError("Missing config for %s." % (config_name,))
try:
os.stat(file_path)
except OSError as e:
@@ -128,9 +125,7 @@ class Config(object):
if e.errno != errno.EEXIST:
raise
if not os.path.isdir(dir_path):
raise ConfigError(
"%s is not a directory" % (dir_path,)
)
raise ConfigError("%s is not a directory" % (dir_path,))
return dir_path
@classmethod
@@ -156,21 +151,20 @@ class Config(object):
return results
def generate_config(
self,
config_dir_path,
server_name,
is_generating_file,
report_stats=None,
self, config_dir_path, server_name, is_generating_file, report_stats=None
):
default_config = "# vim:ft=yaml\n"
default_config += "\n\n".join(dedent(conf) for conf in self.invoke_all(
"default_config",
config_dir_path=config_dir_path,
server_name=server_name,
is_generating_file=is_generating_file,
report_stats=report_stats,
))
default_config += "\n\n".join(
dedent(conf)
for conf in self.invoke_all(
"default_config",
config_dir_path=config_dir_path,
server_name=server_name,
is_generating_file=is_generating_file,
report_stats=report_stats,
)
)
config = yaml.load(default_config)
@@ -178,23 +172,22 @@ class Config(object):
@classmethod
def load_config(cls, description, argv):
config_parser = argparse.ArgumentParser(
description=description,
)
config_parser = argparse.ArgumentParser(description=description)
config_parser.add_argument(
"-c", "--config-path",
"-c",
"--config-path",
action="append",
metavar="CONFIG_FILE",
help="Specify config file. Can be given multiple times and"
" may specify directories containing *.yaml files."
" may specify directories containing *.yaml files.",
)
config_parser.add_argument(
"--keys-directory",
metavar="DIRECTORY",
help="Where files such as certs and signing keys are stored when"
" their location is given explicitly in the config."
" Defaults to the directory containing the last config file",
" their location is given explicitly in the config."
" Defaults to the directory containing the last config file",
)
config_args = config_parser.parse_args(argv)
@@ -203,9 +196,7 @@ class Config(object):
obj = cls()
obj.read_config_files(
config_files,
keys_directory=config_args.keys_directory,
generate_keys=False,
config_files, keys_directory=config_args.keys_directory, generate_keys=False
)
return obj
@@ -213,38 +204,38 @@ class Config(object):
def load_or_generate_config(cls, description, argv):
config_parser = argparse.ArgumentParser(add_help=False)
config_parser.add_argument(
"-c", "--config-path",
"-c",
"--config-path",
action="append",
metavar="CONFIG_FILE",
help="Specify config file. Can be given multiple times and"
" may specify directories containing *.yaml files."
" may specify directories containing *.yaml files.",
)
config_parser.add_argument(
"--generate-config",
action="store_true",
help="Generate a config file for the server name"
help="Generate a config file for the server name",
)
config_parser.add_argument(
"--report-stats",
action="store",
help="Whether the generated config reports anonymized usage statistics",
choices=["yes", "no"]
choices=["yes", "no"],
)
config_parser.add_argument(
"--generate-keys",
action="store_true",
help="Generate any missing key files then exit"
help="Generate any missing key files then exit",
)
config_parser.add_argument(
"--keys-directory",
metavar="DIRECTORY",
help="Used with 'generate-*' options to specify where files such as"
" certs and signing keys should be stored in, unless explicitly"
" specified in the config."
" certs and signing keys should be stored in, unless explicitly"
" specified in the config.",
)
config_parser.add_argument(
"-H", "--server-name",
help="The server name to generate a config file for"
"-H", "--server-name", help="The server name to generate a config file for"
)
config_args, remaining_args = config_parser.parse_known_args(argv)
@@ -257,8 +248,8 @@ class Config(object):
if config_args.generate_config:
if config_args.report_stats is None:
config_parser.error(
"Please specify either --report-stats=yes or --report-stats=no\n\n" +
MISSING_REPORT_STATS_SPIEL
"Please specify either --report-stats=yes or --report-stats=no\n\n"
+ MISSING_REPORT_STATS_SPIEL
)
if not config_files:
config_parser.error(
@@ -287,26 +278,32 @@ class Config(object):
config_dir_path=config_dir_path,
server_name=server_name,
report_stats=(config_args.report_stats == "yes"),
is_generating_file=True
is_generating_file=True,
)
obj.invoke_all("generate_files", config)
config_file.write(config_str)
print((
"A config file has been generated in %r for server name"
" %r with corresponding SSL keys and self-signed"
" certificates. Please review this file and customise it"
" to your needs."
) % (config_path, server_name))
print(
(
"A config file has been generated in %r for server name"
" %r with corresponding SSL keys and self-signed"
" certificates. Please review this file and customise it"
" to your needs."
)
% (config_path, server_name)
)
print(
"If this server name is incorrect, you will need to"
" regenerate the SSL certificates"
)
return
else:
print((
"Config file %r already exists. Generating any missing key"
" files."
) % (config_path,))
print(
(
"Config file %r already exists. Generating any missing key"
" files."
)
% (config_path,)
)
generate_keys = True
parser = argparse.ArgumentParser(
@@ -338,8 +335,7 @@ class Config(object):
return obj
def read_config_files(self, config_files, keys_directory=None,
generate_keys=False):
def read_config_files(self, config_files, keys_directory=None, generate_keys=False):
if not keys_directory:
keys_directory = os.path.dirname(config_files[-1])
@@ -364,8 +360,9 @@ class Config(object):
if "report_stats" not in config:
raise ConfigError(
MISSING_REPORT_STATS_CONFIG_INSTRUCTIONS + "\n" +
MISSING_REPORT_STATS_SPIEL
MISSING_REPORT_STATS_CONFIG_INSTRUCTIONS
+ "\n"
+ MISSING_REPORT_STATS_SPIEL
)
if generate_keys:
@@ -399,16 +396,16 @@ def find_config_files(search_paths):
for entry in os.listdir(config_path):
entry_path = os.path.join(config_path, entry)
if not os.path.isfile(entry_path):
print (
"Found subdirectory in config directory: %r. IGNORING."
) % (entry_path, )
err = "Found subdirectory in config directory: %r. IGNORING."
print(err % (entry_path,))
continue
if not entry.endswith(".yaml"):
print (
"Found file in config directory that does not"
" end in '.yaml': %r. IGNORING."
) % (entry_path, )
err = (
"Found file in config directory that does not end in "
"'.yaml': %r. IGNORING."
)
print(err % (entry_path,))
continue
files.append(entry_path)
+18
View File
@@ -42,6 +42,14 @@ DEFAULT_CONFIG = """\
# until the user consents to the privacy policy. The value of the setting is
# used as the text of the error.
#
# 'require_at_registration', if enabled, will add a step to the registration
# process, similar to how captcha works. Users will be required to accept the
# policy before their account is created.
#
# 'policy_name' is the display name of the policy users will see when registering
# for an account. Has no effect unless `require_at_registration` is enabled.
# Defaults to "Privacy Policy".
#
# user_consent:
# template_dir: res/templates/privacy
# version: 1.0
@@ -54,6 +62,8 @@ DEFAULT_CONFIG = """\
# block_events_error: >-
# To continue using this homeserver you must review and agree to the
# terms and conditions at %(consent_uri)s
# require_at_registration: False
# policy_name: Privacy Policy
#
"""
@@ -67,6 +77,8 @@ class ConsentConfig(Config):
self.user_consent_server_notice_content = None
self.user_consent_server_notice_to_guests = False
self.block_events_without_consent_error = None
self.user_consent_at_registration = False
self.user_consent_policy_name = "Privacy Policy"
def read_config(self, config):
consent_config = config.get("user_consent")
@@ -83,6 +95,12 @@ class ConsentConfig(Config):
self.user_consent_server_notice_to_guests = bool(consent_config.get(
"send_server_notice_to_guests", False,
))
self.user_consent_at_registration = bool(consent_config.get(
"require_at_registration", False,
))
self.user_consent_policy_name = consent_config.get(
"policy_name", "Privacy Policy",
)
def default_config(self, **kwargs):
return DEFAULT_CONFIG
+30 -4
View File
@@ -13,10 +13,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
# This file can't be called email.py because if it is, we cannot:
import email.utils
import logging
import os
from ._base import Config
import pkg_resources
from ._base import Config, ConfigError
logger = logging.getLogger(__name__)
class EmailConfig(Config):
@@ -38,7 +46,6 @@ class EmailConfig(Config):
"smtp_host",
"smtp_port",
"notif_from",
"template_dir",
"notif_template_html",
"notif_template_text",
]
@@ -62,9 +69,26 @@ class EmailConfig(Config):
self.email_smtp_host = email_config["smtp_host"]
self.email_smtp_port = email_config["smtp_port"]
self.email_notif_from = email_config["notif_from"]
self.email_template_dir = email_config["template_dir"]
self.email_notif_template_html = email_config["notif_template_html"]
self.email_notif_template_text = email_config["notif_template_text"]
template_dir = email_config.get("template_dir")
# we need an absolute path, because we change directory after starting (and
# we don't yet know what auxilliary templates like mail.css we will need).
# (Note that loading as package_resources with jinja.PackageLoader doesn't
# work for the same reason.)
if not template_dir:
template_dir = pkg_resources.resource_filename(
'synapse', 'res/templates'
)
template_dir = os.path.abspath(template_dir)
for f in self.email_notif_template_text, self.email_notif_template_html:
p = os.path.join(template_dir, f)
if not os.path.isfile(p):
raise ConfigError("Unable to find email template file %s" % (p, ))
self.email_template_dir = template_dir
self.email_notif_for_new_users = email_config.get(
"notif_for_new_users", True
)
@@ -113,7 +137,9 @@ class EmailConfig(Config):
# require_transport_security: False
# notif_from: "Your Friendly %(app)s Home Server <noreply@example.com>"
# app_name: Matrix
# template_dir: res/templates
# # if template_dir is unset, uses the example templates that are part of
# # the Synapse distribution.
# #template_dir: res/templates
# notif_template_html: notif_mail.html
# notif_template_text: notif_mail.txt
# notif_for_new_users: True
+2 -1
View File
@@ -31,6 +31,7 @@ from .push import PushConfig
from .ratelimiting import RatelimitConfig
from .registration import RegistrationConfig
from .repository import ContentRepositoryConfig
from .room_directory import RoomDirectoryConfig
from .saml2 import SAML2Config
from .server import ServerConfig
from .server_notices_config import ServerNoticesConfig
@@ -49,7 +50,7 @@ class HomeServerConfig(TlsConfig, ServerConfig, DatabaseConfig, LoggingConfig,
WorkerConfig, PasswordAuthProviderConfig, PushConfig,
SpamCheckerConfig, GroupsConfig, UserDirectoryConfig,
ConsentConfig,
ServerNoticesConfig,
ServerNoticesConfig, RoomDirectoryConfig,
):
pass
+1
View File
@@ -50,6 +50,7 @@ handlers:
maxBytes: 104857600
backupCount: 10
filters: [context]
encoding: utf8
console:
class: logging.StreamHandler
formatter: precise
+16 -3
View File
@@ -15,10 +15,10 @@
from distutils.util import strtobool
from synapse.config._base import Config, ConfigError
from synapse.types import RoomAlias
from synapse.util.stringutils import random_string_with_symbols
from ._base import Config
class RegistrationConfig(Config):
@@ -44,6 +44,10 @@ class RegistrationConfig(Config):
)
self.auto_join_rooms = config.get("auto_join_rooms", [])
for room_alias in self.auto_join_rooms:
if not RoomAlias.is_valid(room_alias):
raise ConfigError('Invalid auto_join_rooms entry %s' % (room_alias,))
self.autocreate_auto_join_rooms = config.get("autocreate_auto_join_rooms", True)
def default_config(self, **kwargs):
registration_shared_secret = random_string_with_symbols(50)
@@ -89,15 +93,24 @@ class RegistrationConfig(Config):
# The list of identity servers trusted to verify third party
# identifiers by this server.
#
# Also defines the ID server which will be called when an account is
# deactivated (one will be picked arbitrarily).
trusted_third_party_id_servers:
- matrix.org
- vector.im
- riot.im
# Users who register on this homeserver will automatically be joined
# to these rooms
#auto_join_rooms:
# - "#example:example.com"
# Where auto_join_rooms are specified, setting this flag ensures that the
# the rooms exist by creating them when the first user on the
# homeserver registers.
# Setting to false means that if the rooms are not manually created,
# users cannot be auto-joined since they do not exist.
autocreate_auto_join_rooms: true
""" % locals()
def add_arguments(self, parser):
+1 -1
View File
@@ -178,7 +178,7 @@ class ContentRepositoryConfig(Config):
def default_config(self, **kwargs):
media_store = self.default_path("media_store")
uploads_path = self.default_path("uploads")
return """
return r"""
# Directory where uploaded images and attachments are stored.
media_store_path: "%(media_store)s"
+102
View File
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
# 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.
# 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.
from synapse.util import glob_to_regex
from ._base import Config, ConfigError
class RoomDirectoryConfig(Config):
def read_config(self, config):
alias_creation_rules = config["alias_creation_rules"]
self._alias_creation_rules = [
_AliasRule(rule)
for rule in alias_creation_rules
]
def default_config(self, config_dir_path, server_name, **kwargs):
return """
# The `alias_creation` option controls who's allowed to create aliases
# on this server.
#
# The format of this option is a list of rules that contain globs that
# match against user_id and the new alias (fully qualified with server
# name). The action in the first rule that matches is taken, which can
# currently either be "allow" or "deny".
#
# If no rules match the request is denied.
alias_creation_rules:
- user_id: "*"
alias: "*"
action: allow
"""
def is_alias_creation_allowed(self, user_id, alias):
"""Checks if the given user is allowed to create the given alias
Args:
user_id (str)
alias (str)
Returns:
boolean: True if user is allowed to crate the alias
"""
for rule in self._alias_creation_rules:
if rule.matches(user_id, alias):
return rule.action == "allow"
return False
class _AliasRule(object):
def __init__(self, rule):
action = rule["action"]
user_id = rule["user_id"]
alias = rule["alias"]
if action in ("allow", "deny"):
self.action = action
else:
raise ConfigError(
"alias_creation_rules rules can only have action of 'allow'"
" or 'deny'"
)
try:
self._user_id_regex = glob_to_regex(user_id)
self._alias_regex = glob_to_regex(alias)
except Exception as e:
raise ConfigError("Failed to parse glob into regex: %s", e)
def matches(self, user_id, alias):
"""Tests if this rule matches the given user_id and alias.
Args:
user_id (str)
alias (str)
Returns:
boolean
"""
# Note: The regexes are anchored at both ends
if not self._user_id_regex.match(user_id):
return False
if not self._alias_regex.match(alias):
return False
return True
+6
View File
@@ -77,6 +77,7 @@ class ServerConfig(Config):
self.max_mau_value = config.get(
"max_mau_value", 0,
)
self.mau_stats_only = config.get("mau_stats_only", False)
self.mau_limits_reserved_threepids = config.get(
"mau_limit_reserved_threepids", []
@@ -372,6 +373,11 @@ class ServerConfig(Config):
# max_mau_value: 50
# mau_trial_days: 2
#
# If enabled, the metrics for the number of monthly active users will
# be populated, however no one will be limited. If limit_usage_by_mau
# is true, this is implied to be true.
# mau_stats_only: False
#
# Sometimes the server admin will want to ensure certain accounts are
# never blocked by mau checking. These accounts are specified here.
#
+6 -4
View File
@@ -15,6 +15,8 @@
import logging
from six.moves import urllib
from canonicaljson import json
from twisted.internet import defer, reactor
@@ -28,15 +30,15 @@ from synapse.util import logcontext
logger = logging.getLogger(__name__)
KEY_API_V1 = b"/_matrix/key/v1/"
KEY_API_V2 = "/_matrix/key/v2/server/%s"
@defer.inlineCallbacks
def fetch_server_key(server_name, tls_client_options_factory, path=KEY_API_V1):
def fetch_server_key(server_name, tls_client_options_factory, key_id):
"""Fetch the keys for a remote server."""
factory = SynapseKeyClientFactory()
factory.path = path
factory.path = KEY_API_V2 % (urllib.parse.quote(key_id), )
factory.host = server_name
endpoint = matrix_federation_endpoint(
reactor, server_name, tls_client_options_factory, timeout=30
@@ -55,7 +57,7 @@ def fetch_server_key(server_name, tls_client_options_factory, path=KEY_API_V1):
raise IOError("Cannot get key for %r" % server_name)
except (ConnectError, DomainError) as e:
logger.warn("Error getting key for %r: %s", server_name, e)
except Exception as e:
except Exception:
logger.exception("Error getting key for %r", server_name)
raise IOError("Cannot get key for %r" % server_name)
+7 -103
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2017 New Vector Ltd.
# Copyright 2017, 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.
@@ -18,8 +18,6 @@ import hashlib
import logging
from collections import namedtuple
from six.moves import urllib
from signedjson.key import (
decode_verify_key_bytes,
encode_verify_key_base64,
@@ -395,32 +393,13 @@ class Keyring(object):
@defer.inlineCallbacks
def get_keys_from_server(self, server_name_and_key_ids):
@defer.inlineCallbacks
def get_key(server_name, key_ids):
keys = None
try:
keys = yield self.get_server_verify_key_v2_direct(
server_name, key_ids
)
except Exception as e:
logger.info(
"Unable to get key %r for %r directly: %s %s",
key_ids, server_name,
type(e).__name__, str(e),
)
if not keys:
keys = yield self.get_server_verify_key_v1_direct(
server_name, key_ids
)
keys = {server_name: keys}
defer.returnValue(keys)
results = yield logcontext.make_deferred_yieldable(defer.gatherResults(
[
run_in_background(get_key, server_name, key_ids)
run_in_background(
self.get_server_verify_key_v2_direct,
server_name,
key_ids,
)
for server_name, key_ids in server_name_and_key_ids
],
consumeErrors=True,
@@ -525,10 +504,7 @@ class Keyring(object):
continue
(response, tls_certificate) = yield fetch_server_key(
server_name, self.hs.tls_client_options_factory,
path=("/_matrix/key/v2/server/%s" % (
urllib.parse.quote(requested_key_id),
)).encode("ascii"),
server_name, self.hs.tls_client_options_factory, requested_key_id
)
if (u"signatures" not in response
@@ -657,78 +633,6 @@ class Keyring(object):
defer.returnValue(results)
@defer.inlineCallbacks
def get_server_verify_key_v1_direct(self, server_name, key_ids):
"""Finds a verification key for the server with one of the key ids.
Args:
server_name (str): The name of the server to fetch a key for.
keys_ids (list of str): The key_ids to check for.
"""
# Try to fetch the key from the remote server.
(response, tls_certificate) = yield fetch_server_key(
server_name, self.hs.tls_client_options_factory
)
# Check the response.
x509_certificate_bytes = crypto.dump_certificate(
crypto.FILETYPE_ASN1, tls_certificate
)
if ("signatures" not in response
or server_name not in response["signatures"]):
raise KeyLookupError("Key response not signed by remote server")
if "tls_certificate" not in response:
raise KeyLookupError("Key response missing TLS certificate")
tls_certificate_b64 = response["tls_certificate"]
if encode_base64(x509_certificate_bytes) != tls_certificate_b64:
raise KeyLookupError("TLS certificate doesn't match")
# Cache the result in the datastore.
time_now_ms = self.clock.time_msec()
verify_keys = {}
for key_id, key_base64 in response["verify_keys"].items():
if is_signing_algorithm_supported(key_id):
key_bytes = decode_base64(key_base64)
verify_key = decode_verify_key_bytes(key_id, key_bytes)
verify_key.time_added = time_now_ms
verify_keys[key_id] = verify_key
for key_id in response["signatures"][server_name]:
if key_id not in response["verify_keys"]:
raise KeyLookupError(
"Key response must include verification keys for all"
" signatures"
)
if key_id in verify_keys:
verify_signed_json(
response,
server_name,
verify_keys[key_id]
)
yield self.store.store_server_certificate(
server_name,
server_name,
time_now_ms,
tls_certificate,
)
yield self.store_keys(
server_name=server_name,
from_server=server_name,
verify_keys=verify_keys,
)
defer.returnValue(verify_keys)
def store_keys(self, server_name, from_server, verify_keys):
"""Store a collection of verify keys for a given server
Args:
+10 -10
View File
@@ -38,7 +38,7 @@ def check(event, auth_events, do_sig_check=True, do_size_check=True):
AuthError if the checks fail
Returns:
if the auth checks pass.
if the auth checks pass.
"""
if do_size_check:
_check_size_limits(event)
@@ -46,7 +46,7 @@ def check(event, auth_events, do_sig_check=True, do_size_check=True):
if not hasattr(event, "room_id"):
raise AuthError(500, "Event has no room_id: %s" % event)
if do_sig_check:
if False and do_sig_check: # Disable all sig checks
sender_domain = get_domain_from_id(event.sender)
event_id_domain = get_domain_from_id(event.event_id)
@@ -103,6 +103,9 @@ def check(event, auth_events, do_sig_check=True, do_size_check=True):
"No create event in auth events",
)
if event.type == "org.matrix.server_presence":
return
creating_domain = get_domain_from_id(event.room_id)
originating_domain = get_domain_from_id(event.sender)
if creating_domain != originating_domain:
@@ -155,10 +158,7 @@ def check(event, auth_events, do_sig_check=True, do_size_check=True):
if user_level < invite_level:
raise AuthError(
403, (
"You cannot issue a third party invite for %s." %
(event.content.display_name,)
)
403, "You don't have permission to invite users",
)
else:
logger.debug("Allowing! %s", event)
@@ -203,11 +203,11 @@ def _is_membership_change_allowed(event, auth_events):
membership = event.content["membership"]
# Check if this is the room creator joining:
if len(event.prev_events) == 1 and Membership.JOIN == membership:
if len(event.prev_event_ids()) == 1 and Membership.JOIN == membership:
# Get room creation event:
key = (EventTypes.Create, "", )
create = auth_events.get(key)
if create and event.prev_events[0][0] == create.event_id:
if create and event.prev_event_ids()[0] == create.event_id:
if create.content["creator"] == event.state_key:
return
@@ -305,7 +305,7 @@ def _is_membership_change_allowed(event, auth_events):
if user_level < invite_level:
raise AuthError(
403, "You cannot invite user %s." % target_user_id
403, "You don't have permission to invite users",
)
elif Membership.JOIN == membership:
# Joins are valid iff caller == target and they were:
@@ -693,7 +693,7 @@ def auth_types_for_event(event):
auth_types = []
auth_types.append((EventTypes.PowerLevels, "", ))
auth_types.append((EventTypes.Member, event.user_id, ))
auth_types.append((EventTypes.Member, event.sender, ))
auth_types.append((EventTypes.Create, "", ))
if event.type == EventTypes.Member:
+21
View File
@@ -44,6 +44,9 @@ class _EventInternalMetadata(object):
def is_invite_from_remote(self):
return getattr(self, "invite_from_remote", False)
def is_internal_event(self):
return getattr(self, "internal_event", False)
def get_send_on_behalf_of(self):
"""Whether this server should send the event on behalf of another server.
This is used by the federation "send_join" API to forward the initial join
@@ -159,6 +162,24 @@ class EventBase(object):
def keys(self):
return six.iterkeys(self._event_dict)
def prev_event_ids(self):
"""Returns the list of prev event IDs. The order matches the order
specified in the event, though there is no meaning to it.
Returns:
list[str]: The list of event IDs of this event's prev_events
"""
return [e for e, _ in self.prev_events]
def auth_event_ids(self):
"""Returns the list of auth event IDs. The order matches the order
specified in the event, though there is no meaning to it.
Returns:
list[str]: The list of event IDs of this event's auth_events
"""
return [e for e, _ in self.auth_events]
class FrozenEvent(EventBase):
def __init__(self, event_dict, internal_metadata_dict={}, rejected_reason=None):
+19 -3
View File
@@ -14,9 +14,9 @@
# limitations under the License.
import copy
import string
from synapse.types import EventID
from synapse.util.stringutils import random_string
from . import EventBase, FrozenEvent, _event_dict_property
@@ -49,10 +49,10 @@ class EventBuilderFactory(object):
self.event_id_count = 0
def create_event_id(self):
i = str(self.event_id_count)
i = self.event_id_count
self.event_id_count += 1
local_part = str(int(self.clock.time())) + i + random_string(5)
local_part = _encode_id(i)
e_id = EventID(local_part, self.hostname)
@@ -73,3 +73,19 @@ class EventBuilderFactory(object):
key_values["signatures"] = {}
return EventBuilder(key_values=key_values,)
def _numberToBase(n, b):
if n == 0:
return [0]
digits = []
while n:
digits.append(int(n % b))
n //= b
return digits[::-1]
def _encode_id(i):
digits = string.digits + string.ascii_letters
val_slice = _numberToBase(i, len(digits))
return "".join(digits[x] for x in val_slice)
+7 -2
View File
@@ -74,6 +74,7 @@ class EventContext(object):
"delta_ids",
"prev_state_events",
"app_service",
"thread_id",
"_current_state_ids",
"_prev_state_ids",
"_prev_state_id",
@@ -89,8 +90,9 @@ class EventContext(object):
@staticmethod
def with_state(state_group, current_state_ids, prev_state_ids,
prev_group=None, delta_ids=None):
thread_id, prev_group=None, delta_ids=None):
context = EventContext()
context.thread_id = thread_id
# The current state including the current event
context._current_state_ids = current_state_ids
@@ -141,7 +143,8 @@ class EventContext(object):
"prev_group": self.prev_group,
"delta_ids": _encode_state_dict(self.delta_ids),
"prev_state_events": self.prev_state_events,
"app_service_id": self.app_service.id if self.app_service else None
"app_service_id": self.app_service.id if self.app_service else None,
"thread_id": self.thread_id,
})
@staticmethod
@@ -158,6 +161,8 @@ class EventContext(object):
"""
context = EventContext()
context.thread_id = input["thread_input"]
# We use the state_group and prev_state_id stuff to pull the
# current_state_ids out of the DB and construct prev_state_ids.
context._prev_state_id = input["prev_state_id"]
+47 -12
View File
@@ -26,7 +26,7 @@ from synapse.crypto.event_signing import check_event_content_hash
from synapse.events import FrozenEvent
from synapse.events.utils import prune_event
from synapse.http.servlet import assert_params_in_dict
from synapse.types import get_domain_from_id
from synapse.types import get_domain_from_id, EventID
from synapse.util import logcontext, unwrapFirstError
logger = logging.getLogger(__name__)
@@ -79,16 +79,16 @@ class FederationBase(object):
allow_none=True,
)
if not res and pdu.origin != origin:
try:
res = yield self.get_pdu(
destinations=[pdu.origin],
event_id=pdu.event_id,
outlier=outlier,
timeout=10000,
)
except SynapseError:
pass
# if not res and pdu.origin != origin:
# try:
# res = yield self.get_pdu(
# destinations=[pdu.origin],
# event_id=pdu.event_id,
# outlier=outlier,
# timeout=10000,
# )
# except SynapseError:
# pass
if not res:
logger.warn(
@@ -136,6 +136,7 @@ class FederationBase(object):
* throws a SynapseError if the signature check failed.
The deferreds run their callbacks in the sentinel logcontext.
"""
return [defer.succeed(p) for p in pdus]
deferreds = _check_sigs_on_pdus(self.keyring, pdus)
ctx = logcontext.LoggingContext.current_context()
@@ -317,7 +318,7 @@ def event_from_pdu_json(pdu_json, outlier=False):
depth = pdu_json['depth']
if not isinstance(depth, six.integer_types):
raise SynapseError(400, "Depth %r not an intger" % (depth, ),
raise SynapseError(400, "Depth %r not an integer" % (depth, ),
Codes.BAD_JSON)
if depth < 0:
@@ -325,6 +326,40 @@ def event_from_pdu_json(pdu_json, outlier=False):
elif depth > MAX_DEPTH:
raise SynapseError(400, "Depth too large", Codes.BAD_JSON)
event_id = pdu_json["event_id"]
if event_id[0] != "$":
pdu_json["event_id"] = EventID(
event_id,
get_domain_from_id(pdu_json["sender"]),
).to_string()
event_id = pdu_json["event_id"]
dtab = pdu_json.get("unsigned", {}).pop("dtab", None)
if dtab:
pdu_json.setdefault("unsigned", {})["destinations"] = {
dest: cost
for cost, destinations in dtab
for dest in destinations
}
if "auth_events" in pdu_json:
pdu_json["auth_events"] = [
(e, {}) if isinstance(e, six.string_types) else e
for e in pdu_json["auth_events"]
]
if "prev_events" in pdu_json:
pdu_json["prev_events"] = [
(e, {}) if isinstance(e, six.string_types) else e
for e in pdu_json["prev_events"]
]
if "origin" not in pdu_json:
pdu_json["origin"] = get_domain_from_id(pdu_json["sender"])
logger.info("Unmangled event to: %s", pdu_json)
event = FrozenEvent(
pdu_json
)
+18 -1
View File
@@ -39,6 +39,7 @@ from synapse.util.caches.expiringcache import ExpiringCache
from synapse.util.logcontext import make_deferred_yieldable, run_in_background
from synapse.util.logutils import log_function
from synapse.util.retryutils import NotRetryingDestination
from synapse.federation.units import _mangle_pdu
logger = logging.getLogger(__name__)
@@ -486,6 +487,22 @@ class FederationClient(FederationBase):
RuntimeError if no servers were reachable.
"""
healths = yield self.store.get_destination_healths(destinations)
with_healths = []
without_healths = []
for d in destinations:
if healths.get(d):
with_healths.append(d)
else:
without_healths.append(d)
with_healths.sort(key=lambda d: healths[d])
destinations = with_healths + without_healths
logger.info("Trying destinations: %r", destinations)
for destination in destinations:
if destination == self.server_name:
continue
@@ -696,7 +713,7 @@ class FederationClient(FederationBase):
destination=destination,
room_id=room_id,
event_id=event_id,
content=pdu.get_pdu_json(time_now),
content=_mangle_pdu(pdu.get_pdu_json(time_now)),
)
except HttpResponseException as e:
if e.code == 403:
+123 -80
View File
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import re
import random
import six
from six import iteritems
@@ -37,18 +37,19 @@ from synapse.api.errors import (
from synapse.crypto.event_signing import compute_event_signature
from synapse.federation.federation_base import FederationBase, event_from_pdu_json
from synapse.federation.persistence import TransactionActions
from synapse.federation.units import Edu, Transaction
from synapse.federation.units import Edu, Transaction, _mangle_pdu
from synapse.http.endpoint import parse_server_name
from synapse.replication.http.federation import (
ReplicationFederationSendEduRestServlet,
ReplicationGetQueryRestServlet,
)
from synapse.types import get_domain_from_id
from synapse.util import glob_to_regex
from synapse.util.async_helpers import Linearizer, concurrently_execute
from synapse.util.caches.response_cache import ResponseCache
from synapse.util.logcontext import nested_logging_context
from synapse.util.logutils import log_function
# when processing incoming transactions, we try to handle multiple rooms in
# parallel, up to this limit.
TRANSACTION_CONCURRENCY_LIMIT = 10
@@ -71,6 +72,7 @@ class FederationServer(FederationBase):
self.auth = hs.get_auth()
self.handler = hs.get_handlers().federation_handler
self.clock = hs.get_clock()
self._server_linearizer = Linearizer("fed_server")
self._transaction_linearizer = Linearizer("fed_txn_handler")
@@ -83,6 +85,8 @@ class FederationServer(FederationBase):
# come in waves.
self._state_resp_cache = ResponseCache(hs, "state_resp", timeout_ms=30000)
self.tracer = hs.get_tracer()
@defer.inlineCallbacks
@log_function
def on_backfill_request(self, origin, room_id, versions, limit):
@@ -100,7 +104,7 @@ class FederationServer(FederationBase):
@defer.inlineCallbacks
@log_function
def on_incoming_transaction(self, origin, transaction_data):
def on_incoming_transaction(self, origin, transaction_data, span):
# keep this as early as possible to make the calculated origin ts as
# accurate as possible.
request_time = self._clock.time_msec()
@@ -118,13 +122,13 @@ class FederationServer(FederationBase):
(origin, transaction.transaction_id),
)):
result = yield self._handle_incoming_transaction(
origin, transaction, request_time,
origin, transaction, request_time, span,
)
defer.returnValue(result)
@defer.inlineCallbacks
def _handle_incoming_transaction(self, origin, transaction, request_time):
def _handle_incoming_transaction(self, origin, transaction, request_time, span):
""" Process an incoming transaction and return the HTTP response
Args:
@@ -162,8 +166,30 @@ class FederationServer(FederationBase):
p["age_ts"] = request_time - int(p["age"])
del p["age"]
# We try and pull out an event ID so that if later checks fail we
# can log something sensible. We don't mandate an event ID here in
# case future event formats get rid of the key.
possible_event_id = p.get("event_id", "<Unknown>")
# Now we get the room ID so that we can check that we know the
# version of the room.
room_id = p.get("room_id")
if not room_id:
logger.info(
"Ignoring PDU as does not have a room_id. Event ID: %s",
possible_event_id,
)
continue
try:
# In future we will actually use the room version to parse the
# PDU into an event.
yield self.store.get_room_version(room_id)
except NotFoundError:
logger.info("Ignoring PDU for unknown room_id: %s", room_id)
continue
event = event_from_pdu_json(p)
room_id = event.room_id
pdus_by_room.setdefault(room_id, []).append(event)
pdu_results = {}
@@ -186,24 +212,48 @@ class FederationServer(FederationBase):
pdu_results[event_id] = e.error_dict()
return
thread_id = random.randint(1, 999999999)
pdu_to_thread = {}
first_in_thread = True
for pdu in reversed(pdus_by_room[room_id]):
if self.handler.should_start_thread(pdu):
pdu_to_thread[pdu.event_id] = (thread_id, first_in_thread)
first_in_thread = False
else:
pdu_to_thread[pdu.event_id] = (0, False)
for pdu in pdus_by_room[room_id]:
event_id = pdu.event_id
with nested_logging_context(event_id):
try:
yield self._handle_received_pdu(
origin, pdu
)
pdu_results[event_id] = {}
except FederationError as e:
logger.warn("Error handling PDU %s: %s", event_id, e)
pdu_results[event_id] = {"error": str(e)}
except Exception as e:
f = failure.Failure()
pdu_results[event_id] = {"error": str(e)}
logger.error(
"Failed to handle PDU %s: %s",
event_id, f.getTraceback().rstrip(),
)
thread_id, new_thread = pdu_to_thread[pdu.event_id]
logger.info("Assigning thread %d to %s", thread_id, pdu.event_id)
child_span = self.tracer.start_span('handle_pdu', child_of=span)
with child_span:
child_span.set_tag("event_id", event_id)
try:
ret = yield self._handle_received_pdu(
origin, pdu, thread_id=thread_id,
new_thread=new_thread,
span=child_span,
)
if ret:
pdu_results[event_id] = ret
except FederationError as e:
logger.warn("Error handling PDU %s: %s", event_id, e)
pdu_results[event_id] = {"error": str(e)}
child_span.set_tag("error", True)
child_span.log_kv({"error", e})
except Exception as e:
f = failure.Failure()
pdu_results[event_id] = {"error": str(e)}
logger.error(
"Failed to handle PDU %s: %s",
event_id, f.getTraceback().rstrip(),
)
child_span.set_tag("error", True)
child_span.log_kv({"error", e})
child_span.log_kv({"pdu_result": pdu_results.get(event_id)})
yield concurrently_execute(
process_pdus_for_room, pdus_by_room.keys(),
@@ -211,7 +261,16 @@ class FederationServer(FederationBase):
)
if hasattr(transaction, "edus"):
for edu in (Edu(**x) for x in transaction.edus):
logger.info("Got edus: %s", transaction.edus)
edus = []
for x in transaction.edus:
try:
edus.append(Edu(**x))
except Exception:
logger.exception("Failed to handle EDU: %s", x)
for edu in edus:
yield self.received_edu(
origin,
edu.edu_type,
@@ -222,7 +281,7 @@ class FederationServer(FederationBase):
"pdus": pdu_results,
}
logger.debug("Returning: %s", str(response))
logger.info("Returning: %s", str(response))
yield self.transaction_actions.set_response(
origin,
@@ -307,8 +366,8 @@ class FederationServer(FederationBase):
)
defer.returnValue({
"pdus": [pdu.get_pdu_json() for pdu in pdus],
"auth_chain": [pdu.get_pdu_json() for pdu in auth_chain],
"pdus": [_mangle_pdu(pdu.get_pdu_json()) for pdu in pdus],
"auth_chain": [_mangle_pdu(pdu.get_pdu_json()) for pdu in auth_chain],
})
@defer.inlineCallbacks
@@ -323,11 +382,6 @@ class FederationServer(FederationBase):
else:
defer.returnValue((404, ""))
@defer.inlineCallbacks
@log_function
def on_pull_request(self, origin, versions):
raise NotImplementedError("Pull transactions not implemented")
@defer.inlineCallbacks
def on_query_request(self, query_type, args):
received_queries_counter.labels(query_type).inc()
@@ -358,7 +412,7 @@ class FederationServer(FederationBase):
yield self.check_server_matches_acl(origin_host, pdu.room_id)
ret_pdu = yield self.handler.on_invite_request(origin, pdu)
time_now = self._clock.time_msec()
defer.returnValue((200, {"event": ret_pdu.get_pdu_json(time_now)}))
defer.returnValue((200, {"event": _mangle_pdu(ret_pdu.get_pdu_json(time_now))}))
@defer.inlineCallbacks
def on_send_join_request(self, origin, content):
@@ -372,9 +426,9 @@ class FederationServer(FederationBase):
res_pdus = yield self.handler.on_send_join_request(origin, pdu)
time_now = self._clock.time_msec()
defer.returnValue((200, {
"state": [p.get_pdu_json(time_now) for p in res_pdus["state"]],
"state": [_mangle_pdu(p.get_pdu_json(time_now)) for p in res_pdus["state"]],
"auth_chain": [
p.get_pdu_json(time_now) for p in res_pdus["auth_chain"]
_mangle_pdu(p.get_pdu_json(time_now)) for p in res_pdus["auth_chain"]
],
}))
@@ -407,7 +461,7 @@ class FederationServer(FederationBase):
time_now = self._clock.time_msec()
auth_pdus = yield self.handler.on_event_auth(event_id)
res = {
"auth_chain": [a.get_pdu_json(time_now) for a in auth_pdus],
"auth_chain": [_mangle_pdu(a.get_pdu_json(time_now)) for a in auth_pdus],
}
defer.returnValue((200, res))
@@ -456,7 +510,7 @@ class FederationServer(FederationBase):
time_now = self._clock.time_msec()
send_content = {
"auth_chain": [
e.get_pdu_json(time_now)
_mangle_pdu(e.get_pdu_json(time_now))
for e in ret["auth_chain"]
],
"rejects": ret.get("rejects", []),
@@ -507,19 +561,19 @@ class FederationServer(FederationBase):
@defer.inlineCallbacks
@log_function
def on_get_missing_events(self, origin, room_id, earliest_events,
latest_events, limit, min_depth):
latest_events, limit):
with (yield self._server_linearizer.queue((origin, room_id))):
origin_host, _ = parse_server_name(origin)
yield self.check_server_matches_acl(origin_host, room_id)
logger.info(
"on_get_missing_events: earliest_events: %r, latest_events: %r,"
" limit: %d, min_depth: %d",
earliest_events, latest_events, limit, min_depth
" limit: %d",
earliest_events, latest_events, limit,
)
missing_events = yield self.handler.on_get_missing_events(
origin, room_id, earliest_events, latest_events, limit, min_depth
origin, room_id, earliest_events, latest_events, limit,
)
if len(missing_events) < 5:
@@ -532,7 +586,7 @@ class FederationServer(FederationBase):
time_now = self._clock.time_msec()
defer.returnValue({
"events": [ev.get_pdu_json(time_now) for ev in missing_events],
"events": [_mangle_pdu(ev.get_pdu_json(time_now)) for ev in missing_events],
})
@log_function
@@ -554,7 +608,7 @@ class FederationServer(FederationBase):
)
@defer.inlineCallbacks
def _handle_received_pdu(self, origin, pdu):
def _handle_received_pdu(self, origin, pdu, thread_id, new_thread, span):
""" Process a PDU received in a federation /send/ transaction.
If the event is invalid, then this method throws a FederationError.
@@ -584,30 +638,6 @@ class FederationServer(FederationBase):
if the event was unacceptable for any other reason (eg, too large,
too many prev_events, couldn't find the prev_events)
"""
# check that it's actually being sent from a valid destination to
# workaround bug #1753 in 0.18.5 and 0.18.6
if origin != get_domain_from_id(pdu.event_id):
# We continue to accept join events from any server; this is
# necessary for the federation join dance to work correctly.
# (When we join over federation, the "helper" server is
# responsible for sending out the join event, rather than the
# origin. See bug #1893).
if not (
pdu.type == 'm.room.member' and
pdu.content and
pdu.content.get("membership", None) == 'join'
):
logger.info(
"Discarding PDU %s from invalid origin %s",
pdu.event_id, origin
)
return
else:
logger.info(
"Accepting join PDU %s from %s",
pdu.event_id, origin
)
# Check signature.
try:
pdu = yield self._check_sigs_and_hash(pdu)
@@ -619,10 +649,35 @@ class FederationServer(FederationBase):
affected=pdu.event_id,
)
destinations = pdu.unsigned.get("destinations", {})
costs = yield self.store.get_destination_healths(list(destinations))
logger.info("Destinations: %s", destinations)
logger.info("Costs: %s", costs)
dont_relay = set()
for dest, their_cost in destinations.items():
our_cost = costs.get(dest)
if our_cost and their_cost and their_cost < our_cost:
dont_relay.add(dest)
if destinations:
pdu.unsigned["destinations"] = {
d: c for d, c in destinations.items() if d not in dont_relay
}
yield self.handler.on_receive_pdu(
origin, pdu, sent_to_us_directly=True,
thread_id=thread_id, new_thread=new_thread,
span=span,
)
ret = {}
if dont_relay:
ret = {"did_not_relay": list(dont_relay)}
defer.returnValue(ret)
def __str__(self):
return "<ReplicationLayer(%s)>" % self.server_name
@@ -729,22 +784,10 @@ def _acl_entry_matches(server_name, acl_entry):
if not isinstance(acl_entry, six.string_types):
logger.warn("Ignoring non-str ACL entry '%s' (is %s)", acl_entry, type(acl_entry))
return False
regex = _glob_to_regex(acl_entry)
regex = glob_to_regex(acl_entry)
return regex.match(server_name)
def _glob_to_regex(glob):
res = ''
for c in glob:
if c == '*':
res = res + '.*'
elif c == '?':
res = res + '.'
else:
res = res + re.escape(c)
return re.compile(res + "\\Z", re.IGNORECASE)
class FederationHandlerRegistry(object):
"""Allows classes to register themselves as handlers for a given EDU or
query type for incoming federation traffic.
@@ -800,7 +843,7 @@ class FederationHandlerRegistry(object):
yield handler(origin, content)
except SynapseError as e:
logger.info("Failed to handle edu %r: %r", edu_type, e)
except Exception as e:
except Exception:
logger.exception("Failed to handle edu %r", edu_type)
def on_query(self, query_type, args):
+278 -69
View File
@@ -14,6 +14,10 @@
# limitations under the License.
import datetime
import logging
import random
import json
import opentracing
import string
from six import itervalues
@@ -22,7 +26,9 @@ from prometheus_client import Counter
from twisted.internet import defer
import synapse.metrics
from synapse.api.constants import EventTypes
from synapse.api.errors import FederationDeniedError, HttpResponseException
from synapse.events import FrozenEvent
from synapse.handlers.presence import format_user_presence_state, get_interested_remotes
from synapse.metrics import (
LaterGauge,
@@ -42,6 +48,8 @@ from .units import Edu, Transaction
logger = logging.getLogger(__name__)
pdu_logger = logging.getLogger("synapse.federation.pdu_destination_logger")
sent_pdus_destination_dist_count = Counter(
"synapse_federation_client_sent_pdu_destinations:count", ""
)
@@ -128,7 +136,7 @@ class TransactionQueue(object):
self.last_device_list_stream_id_by_dest = {}
# HACK to get unique tx id
self._next_txn_id = int(self.clock.time_msec())
self._next_txn_id = 1
self._order = 1
@@ -137,6 +145,8 @@ class TransactionQueue(object):
self._processing_pending_presence = False
self.tracer = hs.get_tracer()
def notify_new_events(self, current_id):
"""This gets called when we have some new events we might want to
send out to other servers.
@@ -169,10 +179,9 @@ class TransactionQueue(object):
@defer.inlineCallbacks
def handle_event(event):
# Only send events for this server.
send_on_behalf_of = event.internal_metadata.get_send_on_behalf_of()
is_mine = self.is_mine_id(event.event_id)
if not is_mine and send_on_behalf_of is None:
should_relay = yield self._should_relay(event, False)
logger.info("Should relay event %s: %s", event.event_id, should_relay)
if not should_relay:
return
try:
@@ -183,9 +192,7 @@ class TransactionQueue(object):
# banned then it won't receive the event because it won't
# be in the room after the ban.
destinations = yield self.state.get_current_hosts_in_room(
event.room_id, latest_event_ids=[
prev_id for prev_id, _ in event.prev_events
],
event.room_id, latest_event_ids=event.prev_event_ids(),
)
except Exception:
logger.exception(
@@ -196,15 +203,9 @@ class TransactionQueue(object):
destinations = set(destinations)
if send_on_behalf_of is not None:
# If we are sending the event on behalf of another server
# then it already has the event and there is no reason to
# send the event to it.
destinations.discard(send_on_behalf_of)
logger.debug("Sending %s to %r", event, destinations)
self._send_pdu(event, destinations)
yield self._send_pdu(event, destinations)
@defer.inlineCallbacks
def handle_room_events(events):
@@ -250,24 +251,54 @@ class TransactionQueue(object):
finally:
self._is_processing = False
def _send_pdu(self, pdu, destinations):
@defer.inlineCallbacks
def received_new_event(self, origin, event, span):
should_relay = yield self._should_relay(event, True)
logger.info("Should relay event %s: %s", event.event_id, should_relay)
if not should_relay:
return
destinations = event.unsigned.get("destinations")
destinations = set(destinations)
logger.debug("Sending %s to %r", event, destinations)
yield self._send_pdu(event, destinations, span)
@defer.inlineCallbacks
def _send_pdu(self, pdu, destinations, span=None):
# We loop through all destinations to see whether we already have
# a transaction in progress. If we do, stick it in the pending_pdus
# table and we'll get back to it later.
order = self._order
self._order += 1
references = []
if span:
references = [opentracing.follows_from(span.context)]
with self.tracer.start_span('_send_pdu', references=references) as span:
span.set_tag("event_id", pdu.event_id)
span.set_tag("room_id", pdu.room_id)
span.set_tag("sender", pdu.sender)
destinations = yield self._compute_relay_destinations(
pdu, joined_hosts=destinations,
)
destinations = set(destinations)
destinations.discard(self.server_name)
logger.debug("Sending to: %s", str(destinations))
pdu_logger.info(
"Relaying PDU %s in %s to %s",
pdu.event_id, pdu.room_id, destinations,
)
if not destinations:
return
sent_pdus_destination_dist_total.inc(len(destinations))
sent_pdus_destination_dist_count.inc()
# XXX: Should we decide where to route here.
for destination in destinations:
self.pending_pdus_by_dest.setdefault(destination, []).append(
(pdu, order)
@@ -275,6 +306,36 @@ class TransactionQueue(object):
self._attempt_new_transaction(destination)
def _compute_relay_destinations(self, pdu, joined_hosts):
"""Compute where we should send an event. Returning an empty set stops
PDU from being sent anywhere.
"""
# XXX: Hook for routing shenanigans
send_on_behalf_of = pdu.internal_metadata.get_send_on_behalf_of()
if send_on_behalf_of is not None:
# If we are sending the event on behalf of another server
# then it already has the event and there is no reason to
# send the event to it.
joined_hosts.discard(send_on_behalf_of)
return joined_hosts
def _should_relay(self, event, from_federation):
"""Whether we should consider relaying this event.
"""
# XXX: Hook for routing shenanigans
send_on_behalf_of = event.internal_metadata.get_send_on_behalf_of()
is_mine = self.is_mine_id(event.event_id)
if not is_mine and send_on_behalf_of is None:
return False
if event.internal_metadata.is_internal_event():
return False
return True
@logcontext.preserve_fn # the caller should not yield on this
@defer.inlineCallbacks
def send_presence(self, states):
@@ -414,6 +475,7 @@ class TransactionQueue(object):
@defer.inlineCallbacks
def _transaction_transmission_loop(self, destination):
pdu_spans = {}
pending_pdus = []
try:
self.pending_transactions[destination] = 1
@@ -425,6 +487,12 @@ class TransactionQueue(object):
pending_pdus = []
while True:
txn_id = _encode_id(self._next_txn_id)
self._next_txn_id += 1
for s in pdu_spans.values():
s.set_tag("txn-id", txn_id)
device_message_edus, device_stream_id, dev_list_id = (
yield self._get_new_device_messages(destination)
)
@@ -441,16 +509,22 @@ class TransactionQueue(object):
pending_pdus = self.pending_pdus_by_dest.pop(destination, [])
# We can only include at most 50 PDUs per transactions
pending_pdus, leftover_pdus = pending_pdus[:50], pending_pdus[50:]
pending_pdus, leftover_pdus = pending_pdus[-5:], pending_pdus[:-5]
if leftover_pdus:
self.pending_pdus_by_dest[destination] = leftover_pdus
# self.pending_pdus_by_dest[destination] = leftover_pdus
for _, _, p_span in leftover_pdus:
p_span.set_tag("success", False)
p_span.log_kv({"result": "dropped"})
p_span.finish()
logger.info("TX [%s] Sending PDUs: %s", destination, pending_pdus)
pending_edus = self.pending_edus_by_dest.pop(destination, [])
# We can only include at most 100 EDUs per transactions
pending_edus, leftover_edus = pending_edus[:100], pending_edus[100:]
if leftover_edus:
self.pending_edus_by_dest[destination] = leftover_edus
pending_edus, leftover_edus = pending_edus[-5:], pending_edus[:-5]
# if leftover_edus:
# self.pending_edus_by_dest[destination] = leftover_edus
pending_presence = self.pending_presence_by_dest.pop(destination, {})
@@ -487,28 +561,70 @@ class TransactionQueue(object):
)
return
pdu_span_references = []
for pdu, _, p_span in pending_pdus:
pdu_spans[pdu.event_id] = p_span
p_span.set_tag("txn-id", txn_id)
pdu_span_references.append(opentracing.follows_from(p_span.context))
# END CRITICAL SECTION
success = yield self._send_new_transaction(
destination, pending_pdus, pending_edus,
span = self.tracer.start_span(
'_send_new_transaction', references=pdu_span_references,
)
if success:
sent_transactions_counter.inc()
# Remove the acknowledged device messages from the database
# Only bother if we actually sent some device messages
if device_message_edus:
yield self.store.delete_device_msgs_for_remote(
destination, device_stream_id
)
logger.info("Marking as sent %r %r", destination, dev_list_id)
yield self.store.mark_as_sent_devices_by_remote(
destination, dev_list_id
)
with span:
span.set_tag("destination", destination)
span.set_tag("txn-id", txn_id)
self.last_device_stream_id_by_dest[destination] = device_stream_id
self.last_device_list_stream_id_by_dest[destination] = dev_list_id
else:
break
try:
success = yield self._send_new_transaction(
destination, pending_pdus, pending_edus, span,
pdu_spans, txn_id,
)
except Exception as e:
success = False
span.set_tag("error", True)
span.log_kv({"error": e})
for s in pdu_spans.values():
s.set_tag("error", True)
s.log_kv({"transaction_error": e})
raise
finally:
if not success:
for p, _, _ in pending_pdus:
yield self._pdu_send_txn_failed(
destination, txn_id, p,
span=pdu_spans[p.event_id],
)
# We want to be *very* sure we del5ete this after we stop
# processing
self.pending_transactions.pop(destination, None)
for s in pdu_spans.values():
s.finish()
span.set_tag("success", success)
if success:
sent_transactions_counter.inc()
# Remove the acknowledged device messages from the database
# Only bother if we actually sent some device messages
if device_message_edus:
yield self.store.delete_device_msgs_for_remote(
destination, device_stream_id
)
logger.info(
"Marking as sent %r %r", destination, dev_list_id,
)
yield self.store.mark_as_sent_devices_by_remote(
destination, dev_list_id
)
self.last_device_stream_id_by_dest[destination] = device_stream_id
self.last_device_list_stream_id_by_dest[destination] = dev_list_id
else:
break
except NotRetryingDestination as e:
logger.debug(
"TX [%s] not ready for retry yet (next retry at %s) - "
@@ -521,17 +637,14 @@ class TransactionQueue(object):
except FederationDeniedError as e:
logger.info(e)
except Exception as e:
logger.warn(
logger.exception(
"TX [%s] Failed to send transaction: %s",
destination,
e,
)
for p, _ in pending_pdus:
for p, _, _ in pending_pdus:
logger.info("Failed to send event %s to %s", p.event_id,
destination)
finally:
# We want to be *very* sure we delete this after we stop processing
self.pending_transactions.pop(destination, None)
@defer.inlineCallbacks
def _get_new_device_messages(self, destination):
@@ -567,7 +680,8 @@ class TransactionQueue(object):
@measure_func("_send_new_transaction")
@defer.inlineCallbacks
def _send_new_transaction(self, destination, pending_pdus, pending_edus):
def _send_new_transaction(self, destination, pending_pdus, pending_edus,
span, pdu_spans, txn_id):
# Sort based on the order field
pending_pdus.sort(key=lambda t: t[1])
@@ -576,9 +690,13 @@ class TransactionQueue(object):
success = True
logger.debug("TX [%s] _attempt_new_transaction", destination)
logger.debug("TX [%s] _attempt_new_transaction", destination)
txn_id = str(self._next_txn_id)
span.log_kv({
"pdus": len(pdus),
"edus": len(edus),
})
logger.debug(
"TX [%s] {%s} Attempting new transaction"
@@ -599,8 +717,6 @@ class TransactionQueue(object):
edus=edus,
)
self._next_txn_id += 1
yield self.transaction_actions.prepare_to_send(transaction)
logger.debug("TX [%s] Persisted transaction", destination)
@@ -630,21 +746,16 @@ class TransactionQueue(object):
try:
response = yield self.transport_layer.send_transaction(
transaction, json_data_cb
transaction, json_data_cb, span,
)
code = 200
if response:
for e_id, r in response.get("pdus", {}).items():
if "error" in r:
logger.warn(
"Transaction returned error for %s: %s",
e_id, r,
)
except HttpResponseException as e:
code = e.code
response = e.response
span.set_tag("error", True)
span.log_kv({"error": e})
if e.code in (401, 404, 429) or 500 <= e.code:
logger.info(
"TX [%s] {%s} got %d response",
@@ -657,20 +768,118 @@ class TransactionQueue(object):
destination, txn_id, code
)
logger.debug("TX [%s] Sent transaction", destination)
logger.debug("TX [%s] Marking as delivered...", destination)
yield self.transaction_actions.delivered(
transaction, code, response
)
logger.debug("TX [%s] Marked as delivered", destination)
logger.debug("TX [%s] {%s} Marked as delivered", destination, txn_id)
if code != 200:
if code == 200:
logger.info(
"TX [%s] {%s} got response json %s",
destination, txn_id, response
)
pdu_results = response.get("pdus", {})
for p in pdus:
logger.info(
"Failed to send event %s to %s", p.event_id, destination
yield self._pdu_send_result(
destination, txn_id, p,
response=pdu_results.get(p.event_id, {}),
span=pdu_spans[p.event_id],
)
else:
success = False
defer.returnValue(success)
@defer.inlineCallbacks
def _pdu_send_result(self, destination, txn_id, pdu, response, span):
"""Gets called after sending the event in a transaction, with the
result for the event from the remote server.
"""
# XXX: Hook for routing shenanigans
if "error" in response:
span.set_tag("error", True)
span.log_kv({
"error.kind": "pdu",
"response.error": response["error"],
})
logger.warn(
"TX [%s] {%s} Remote returned error for %s: %s",
destination, txn_id, pdu.event_id, response,
)
pdu_logger.info(
"SendErrorPDU",
extra={
"event_id": pdu.event_id, "room_id": pdu.room_id,
"destination": destination,
"server": self.server_name,
},
)
new_destinations = set(pdu.unsigned.get("destinations", []))
new_destinations.discard(destination)
yield self._send_pdu(pdu, list(new_destinations), span)
elif "did_not_relay" in response and response["did_not_relay"]:
new_destinations = set(response["did_not_relay"])
new_destinations.discard(destination)
pdu_logger.info(
"DidNotRelayPDU",
extra={
"event_id": pdu.event_id, "room_id": pdu.room_id,
"destination": destination,
"new_destinations": json.dumps(list(new_destinations)),
"server": self.server_name,
},
)
span.log_kv({
"did_not_relay_to": list(new_destinations),
})
yield self._send_pdu(pdu, list(new_destinations), span)
# @defer.inlineCallbacks
def _pdu_send_txn_failed(self, destination, txn_id, pdu, span):
"""Gets called when sending a transaction failed (after retries)
"""
# XXX: Hook for routing shenanigans
logger.warn(
"TX [%s] {%s} Failed to send event %s",
destination, txn_id, pdu.event_id,
)
span.set_tag("error", True)
span.log_kv({
"error.kind": "transaction",
})
pdu_logger.info(
"SendFailPDU",
extra={
"event_id": pdu.event_id, "room_id": pdu.room_id,
"destination": destination,
"server": self.server_name,
},
)
# new_destinations = set(pdu.unsigned.get("destinations", []))
# new_destinations.discard(destination)
# yield self._send_pdu(pdu, list(new_destinations), span)
def _numberToBase(n, b):
if n == 0:
return [0]
digits = []
while n:
digits.append(int(n % b))
n //= b
return digits[::-1]
def _encode_id(i):
digits = string.digits + string.ascii_letters
val_slice = _numberToBase(i, len(digits))
return "".join(digits[x] for x in val_slice)
+14 -10
View File
@@ -136,16 +136,24 @@ class TransportLayerClient(object):
@defer.inlineCallbacks
@log_function
def send_transaction(self, transaction, json_data_callback=None):
def send_transaction(self, transaction, json_data_callback=None, span=None):
""" Sends the given Transaction to its destination
Args:
transaction (Transaction)
Returns:
Deferred: Results of the deferred is a tuple in the form of
(response_code, response_body) where the response_body is a
python dict decoded from json
Deferred: Succeeds when we get a 2xx HTTP response. The result
will be the decoded JSON body.
Fails with ``HTTPRequestException`` if we get an HTTP response
code >= 300.
Fails with ``NotRetryingDestination`` if we are not yet ready
to retry this server.
Fails with ``FederationDeniedError`` if this destination
is not on our federation whitelist
"""
logger.debug(
"send_data dest=%s, txid=%s",
@@ -166,13 +174,9 @@ class TransportLayerClient(object):
path=path,
data=json_data,
json_data_callback=json_data_callback,
long_retries=True,
long_retries=False,
backoff_on_404=True, # If we get a 404 the other side has gone
)
logger.debug(
"send_data dest=%s, txid=%s, got response: 200",
transaction.destination, transaction.transaction_id,
span=span,
)
defer.returnValue(response)
+82 -43
View File
@@ -15,8 +15,11 @@
# limitations under the License.
import functools
import inspect
import logging
import re
import opentracing
from opentracing.ext import tags
from twisted.internet import defer
@@ -120,12 +123,12 @@ class Authenticator(object):
):
raise FederationDeniedError(origin)
if not json_request["signatures"]:
raise NoAuthenticationError(
401, "Missing Authorization headers", Codes.UNAUTHORIZED,
)
# if not json_request["signatures"]:
# raise NoAuthenticationError(
# 401, "Missing Authorization headers", Codes.UNAUTHORIZED,
# )
yield self.keyring.verify_json_for_server(origin, json_request)
# yield self.keyring.verify_json_for_server(origin, json_request)
logger.info("Request from %s", origin)
request.authenticated_entity = origin
@@ -227,15 +230,22 @@ class BaseFederationServlet(object):
"""
REQUIRE_AUTH = True
def __init__(self, handler, authenticator, ratelimiter, server_name):
def __init__(self, handler, authenticator, ratelimiter, server_name, hs):
self.handler = handler
self.authenticator = authenticator
self.ratelimiter = ratelimiter
self.tracer = hs.get_tracer()
def _wrap(self, func):
authenticator = self.authenticator
ratelimiter = self.ratelimiter
arg_spec = inspect.signature(func)
all_args = arg_spec.parameters
include_span = "request_span" in all_args
logger.info("include_span: %s for %s", include_span, self)
@defer.inlineCallbacks
@functools.wraps(func)
def new_func(request, *args, **kwargs):
@@ -251,32 +261,67 @@ class BaseFederationServlet(object):
Deferred[(int, object)|None]: (response code, response object) as returned
by the callback method. None if the request has already been handled.
"""
content = None
if request.method in [b"PUT", b"POST"]:
# TODO: Handle other method types? other content types?
content = parse_json_object_from_request(request)
try:
origin = yield authenticator.authenticate_request(request, content)
except NoAuthenticationError:
origin = None
if self.REQUIRE_AUTH:
logger.warn("authenticate_request failed: missing authentication")
raise
except Exception as e:
logger.warn("authenticate_request failed: %s", e)
raise
if origin:
with ratelimiter.ratelimit(origin) as d:
yield d
response = yield func(
origin, content, request.args, *args, **kwargs
)
else:
response = yield func(
origin, content, request.args, *args, **kwargs
carrier = {}
for key, value in request.requestHeaders.getAllRawHeaders():
carrier[key.decode("ascii")] = value[0].decode("ascii")
parent_ctx = self.tracer.extract(
format=opentracing.Format.HTTP_HEADERS, carrier=carrier
)
except Exception:
logger.exception("trace extract failed")
parent_ctx = None
tags_dict = {
tags.HTTP_METHOD: request.method.decode('ascii'),
tags.HTTP_URL: request.uri.decode('ascii'),
tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER,
}
span = self.tracer.start_span(
operation_name="federation-server",
child_of=parent_ctx,
tags=tags_dict,
)
with span:
content = None
if request.method in [b"PUT", b"POST"]:
# TODO: Handle other method types? other content types?
content = parse_json_object_from_request(request)
try:
origin = yield authenticator.authenticate_request(request, content)
except NoAuthenticationError:
origin = None
if self.REQUIRE_AUTH:
logger.warn("authenticate_request failed: missing authentication")
raise
except Exception as e:
logger.warn("authenticate_request failed: %s", e)
raise
if include_span:
kwargs["request_span"] = span
try:
if origin:
span.set_tag("origin", origin)
with ratelimiter.ratelimit(origin) as d:
yield d
response = yield func(
origin, content, request.args, *args, **kwargs
)
else:
response = yield func(
origin, content, request.args, *args, **kwargs
)
except Exception as e:
span.set_tag("error", True)
span.log_kv({"error": e})
raise
span.set_tag(tags.HTTP_STATUS_CODE, response[0])
defer.returnValue(response)
@@ -307,7 +352,7 @@ class FederationSendServlet(BaseFederationServlet):
# This is when someone is trying to send us a bunch of data.
@defer.inlineCallbacks
def on_PUT(self, origin, content, query, transaction_id):
def on_PUT(self, origin, content, query, transaction_id, request_span):
""" Called on PUT /send/<transaction_id>/
Args:
@@ -353,7 +398,7 @@ class FederationSendServlet(BaseFederationServlet):
try:
code, response = yield self.handler.on_incoming_transaction(
origin, transaction_data,
origin, transaction_data, request_span,
)
except Exception:
logger.exception("on_incoming_transaction failed")
@@ -362,14 +407,6 @@ class FederationSendServlet(BaseFederationServlet):
defer.returnValue((code, response))
class FederationPullServlet(BaseFederationServlet):
PATH = "/pull/"
# This is for when someone asks us for everything since version X
def on_GET(self, origin, content, query):
return self.handler.on_pull_request(query["origin"][0], query["v"])
class FederationEventServlet(BaseFederationServlet):
PATH = "/event/(?P<event_id>[^/]*)/"
@@ -560,7 +597,6 @@ class FederationGetMissingEventsServlet(BaseFederationServlet):
@defer.inlineCallbacks
def on_POST(self, origin, content, query, room_id):
limit = int(content.get("limit", 10))
min_depth = int(content.get("min_depth", 0))
earliest_events = content.get("earliest_events", [])
latest_events = content.get("latest_events", [])
@@ -569,7 +605,6 @@ class FederationGetMissingEventsServlet(BaseFederationServlet):
room_id=room_id,
earliest_events=earliest_events,
latest_events=latest_events,
min_depth=min_depth,
limit=limit,
)
@@ -1263,7 +1298,6 @@ class FederationGroupsSettingJoinPolicyServlet(BaseFederationServlet):
FEDERATION_SERVLET_CLASSES = (
FederationSendServlet,
FederationPullServlet,
FederationEventServlet,
FederationStateServlet,
FederationStateIdsServlet,
@@ -1333,6 +1367,7 @@ def register_servlets(hs, resource, authenticator, ratelimiter):
authenticator=authenticator,
ratelimiter=ratelimiter,
server_name=hs.hostname,
hs=hs,
).register(resource)
for servletclass in ROOM_LIST_CLASSES:
@@ -1341,6 +1376,7 @@ def register_servlets(hs, resource, authenticator, ratelimiter):
authenticator=authenticator,
ratelimiter=ratelimiter,
server_name=hs.hostname,
hs=hs,
).register(resource)
for servletclass in GROUP_SERVER_SERVLET_CLASSES:
@@ -1349,6 +1385,7 @@ def register_servlets(hs, resource, authenticator, ratelimiter):
authenticator=authenticator,
ratelimiter=ratelimiter,
server_name=hs.hostname,
hs=hs,
).register(resource)
for servletclass in GROUP_LOCAL_SERVLET_CLASSES:
@@ -1357,6 +1394,7 @@ def register_servlets(hs, resource, authenticator, ratelimiter):
authenticator=authenticator,
ratelimiter=ratelimiter,
server_name=hs.hostname,
hs=hs,
).register(resource)
for servletclass in GROUP_ATTESTATION_SERVLET_CLASSES:
@@ -1365,4 +1403,5 @@ def register_servlets(hs, resource, authenticator, ratelimiter):
authenticator=authenticator,
ratelimiter=ratelimiter,
server_name=hs.hostname,
hs=hs,
).register(resource)
+58 -18
View File
@@ -17,13 +17,18 @@
server protocol.
"""
import itertools
import logging
from synapse.types import get_localpart_from_id, get_domain_from_id
from synapse.util.jsonobject import JsonEncodedObject
logger = logging.getLogger(__name__)
BUCKETS = [0, 50, 100, 200, 350, 500, 750, 1000, 2000, 5000, 10000, 100000]
class Edu(JsonEncodedObject):
""" An Edu represents a piece of data sent from one homeserver to another.
@@ -76,15 +81,14 @@ class Transaction(JsonEncodedObject):
]
internal_keys = [
"transaction_id",
"destination",
]
required_keys = [
"transaction_id",
"origin",
"destination",
"origin_server_ts",
"previous_ids",
]
required_keys = [
"pdus",
]
@@ -108,18 +112,54 @@ class Transaction(JsonEncodedObject):
""" Used to create a new transaction. Will auto fill out
transaction_id and origin_server_ts keys.
"""
if "origin_server_ts" not in kwargs:
raise KeyError(
"Require 'origin_server_ts' to construct a Transaction"
)
if "transaction_id" not in kwargs:
raise KeyError(
"Require 'transaction_id' to construct a Transaction"
)
for p in pdus:
p.transaction_id = kwargs["transaction_id"]
kwargs["pdus"] = [p.get_pdu_json() for p in pdus]
kwargs["pdus"] = [
_mangle_pdu(p.get_pdu_json())
for p in pdus
]
return Transaction(**kwargs)
def _mangle_pdu(pdu_json):
pdu_json.pop("origin", None)
pdu_json.pop("hashes", None)
pdu_json.pop("signatures", None)
pdu_json.get("unsigned", {}).pop("age_ts", None)
pdu_json.get("unsigned", {}).pop("age", None)
pdu_json["auth_events"] = list(_strip_hashes(pdu_json["auth_events"]))
pdu_json["prev_events"] = list(_strip_hashes(pdu_json["prev_events"]))
if get_domain_from_id(pdu_json["event_id"]) == get_domain_from_id(pdu_json["sender"]):
pdu_json["event_id"] = get_localpart_from_id(pdu_json["event_id"])
destinations = pdu_json["unsigned"].pop("destinations", None)
if destinations:
new_destinations = {}
for dest, cost in destinations.items():
for first, second in pairwise(BUCKETS):
if first <= cost <= second:
b = first if cost - first < second - cost else second
new_destinations.setdefault(b, []).append(dest)
break
else:
new_destinations.setdefault(b[-1], []).append(dest)
pdu_json["unsigned"]["dtab"] = list(new_destinations.items())
logger.info("Mangled PDU: %s", pdu_json)
return pdu_json
def _strip_hashes(iterable):
return (
e for e, hashes in iterable
)
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)

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