1
0

Compare commits

..

342 Commits

Author SHA1 Message Date
Brendan Abolivier
84e695f506 Merge pull request #5932 from matrix-org/babolivier/account_validity_template_encode
Fix encoding for account validity HTML files on Python 2
2019-08-29 16:50:10 +01:00
Brendan Abolivier
91694227b6 Bump requirement for six to 1.12 2019-08-29 16:20:21 +01:00
Brendan Abolivier
7a95d8fff9 Fix encoding for account validity HTML files on Python 2 2019-08-29 16:03:59 +01:00
Brendan Abolivier
99eec6d2d5 Merge pull request #5815 from matrix-org/babolivier/dinsic-message-retention
Message retention policies at the room and server levels
2019-08-28 18:49:13 +01:00
Brendan Abolivier
e5df12ad16 Merge branch 'dinsic' into babolivier/dinsic-message-retention 2019-08-28 18:17:26 +01:00
Brendan Abolivier
70714595bc Implement per-room message retention policies 2019-08-28 18:16:17 +01:00
Michael Kaye
62f5e3bc4c Merge pull request #5812 from matrix-org/babolivier/account-validity-messages
Account validity: allow defining HTML templates to serve the user on account renewal attempt
2019-08-12 13:26:49 +01:00
Michael Kaye
63d0d21a28 Merge pull request #5781 from matrix-org/baboliver/loopingcall-args
Add ability to pass arguments to looping calls
2019-08-08 12:10:36 +01:00
Michael Kaye
8551b4f336 Merge pull request #5760 from matrix-org/babolivier/access-rules-public-restricted
Force the access rule to be "restricted" if the join rule is "public"
2019-08-08 12:10:22 +01:00
Brendan Abolivier
359aed4168 Lint 2019-08-01 16:08:39 +02:00
Brendan Abolivier
cd47482257 Sample config 2019-08-01 16:08:39 +02:00
Brendan Abolivier
a9567ee1a6 Changelog 2019-08-01 16:08:38 +02:00
Brendan Abolivier
9502bd8d78 Add tests 2019-08-01 16:08:38 +02:00
Brendan Abolivier
235271be4f Allow defining HTML templates to serve the user on account renewal 2019-08-01 16:08:38 +02:00
Brendan Abolivier
0c6500a08b Explain rationale 2019-08-01 10:19:04 +02:00
Brendan Abolivier
c862d5baf6 Check room ID and type of redacted event (#5784)
Check room ID and type of redacted event
2019-07-31 16:44:19 +02:00
Brendan Abolivier
35ec13baab Ignore redactions of redactions in get_events_as_list 2019-07-31 15:48:57 +02:00
Brendan Abolivier
c4e56a8ee9 Ignore invalid redactions in _get_event_from_row 2019-07-31 15:11:27 +02:00
Brendan Abolivier
d2bb51080e Incorporate review 2019-07-30 16:15:01 +02:00
Brendan Abolivier
0fda4e2e50 Should now work, unless we can't find the redaction event which happens for some reason (need to investigate) 2019-07-30 15:56:02 +02:00
Brendan Abolivier
8ced9a2f58 Don't make the checks depend on recheck_redaction 2019-07-30 15:55:18 +02:00
Brendan Abolivier
bbd6208b3e Do checks sooner 2019-07-29 17:22:42 +02:00
Brendan Abolivier
36c61df659 Check room ID and type of redacted event 2019-07-29 16:07:12 +02:00
Brendan Abolivier
132887db8c Changelog 2019-07-29 11:06:43 +02:00
Brendan Abolivier
bec6d9e090 Add kwargs and doc 2019-07-29 11:06:43 +02:00
Brendan Abolivier
8a47155763 Add ability to pass arguments to looping calls 2019-07-29 11:06:43 +02:00
Brendan Abolivier
ffa30b507f Fix changelog 2019-07-25 10:19:13 +02:00
Brendan Abolivier
00b47fdfc7 Changelog 2019-07-25 10:17:07 +02:00
Brendan Abolivier
2526b79ce6 Merge ifs 2019-07-25 10:15:44 +02:00
Brendan Abolivier
aea03c9d73 Doc 2019-07-25 10:14:41 +02:00
Brendan Abolivier
ddf256c77f Fix status code for forbidden events 2019-07-25 10:03:59 +02:00
Brendan Abolivier
dd92685179 Only check the join rule on room creation if an access rule is also provided 2019-07-25 10:03:36 +02:00
Brendan Abolivier
0bb375c124 Turns out the default preset is public_chat 2019-07-24 17:29:17 +02:00
Brendan Abolivier
ea5f86304e Implement restrictions on new events 2019-07-24 17:27:07 +02:00
Brendan Abolivier
d1a78ba2a3 Implement restriction on public room creation 2019-07-24 17:06:23 +02:00
Brendan Abolivier
dcdfdb3f17 Add test case 2019-07-24 16:38:49 +02:00
Brendan Abolivier
4dc2eda1d3 Merge pull request #5702 from matrix-org/babolivier/3pid-invite
Fix check of the association between a 3PID invite and the subsequent m.room.member event in the 3rd party rules
2019-07-18 13:38:05 +02:00
Brendan Abolivier
13ad3f5ab1 Fix changelog 2019-07-17 15:10:16 +02:00
Brendan Abolivier
28803ad56a Merge branch 'dinsic' into babolivier/3pid-invite 2019-07-17 15:06:41 +02:00
Brendan Abolivier
446fb64d50 Changelog 2019-07-17 15:05:35 +02:00
Brendan Abolivier
34dd738e4b There's no third_party_signed property in an invite's content 2019-07-17 15:03:23 +02:00
Brendan Abolivier
048f86ef5d Fix check of the association between a 3PID invite and the subsequent m.room.member event in the 3rd party rules 2019-07-17 14:54:58 +02:00
Brendan Abolivier
3bc4ea841d Merge pull request #5646 from matrix-org/babolivier/profile-allow-self
Port #5644 to dinsic
2019-07-09 13:19:57 +01:00
Amber H. Brown
4e954f4bbd make the base branch dinsic for dinsic 2019-07-09 20:53:38 +10:00
Amber H. Brown
f10b6f7385 cut down circleci config to just what dinsic needs 2019-07-09 20:38:24 +10:00
Brendan Abolivier
9fc40f7b3f Lint 2019-07-09 10:30:43 +01:00
Brendan Abolivier
cf22aae355 Add test case 2019-07-09 10:27:53 +01:00
Brendan Abolivier
6b9d27d793 Changelog 2019-07-09 10:27:53 +01:00
Brendan Abolivier
25fff95448 Allow newly-registered users to lookup their own profiles
When a user creates an account and the 'require_auth_for_profile_requests' config flag is set, and a client that performed the registration wants to lookup the newly-created profile, the request will be denied because the user doesn't share a room with themselves yet.
2019-07-09 10:27:53 +01:00
Brendan Abolivier
5fe0cea37e Merge pull request #5610 from matrix-org/babolivier/power-levels
Implement new restrictions on power levels
2019-07-04 11:12:47 +01:00
Brendan Abolivier
95b5d4ad54 Merge branch 'babolivier/power-levels' of github.com:matrix-org/synapse into babolivier/power-levels 2019-07-03 18:30:13 +01:00
Brendan Abolivier
4dd7de17b7 Incorporate review 2019-07-03 18:26:48 +01:00
Brendan Abolivier
8b44097771 Update synapse/third_party_rules/access_rules.py
Co-Authored-By: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2019-07-03 18:21:42 +01:00
Brendan Abolivier
6b83a1826c Incorporate review 2019-07-03 17:32:52 +01:00
Brendan Abolivier
aeda7fde78 Changelog 2019-07-03 15:47:58 +01:00
Brendan Abolivier
d085e0df2a Change the rule for applying PL restrictions 2019-07-03 15:44:22 +01:00
Brendan Abolivier
8d28817eac Add tests 2019-07-03 15:43:52 +01:00
Brendan Abolivier
aa3ba41933 Default return value for events we're not interested in 2019-07-03 12:05:56 +01:00
Brendan Abolivier
724ddaddb3 Refactor part of the access rules module
Since we're not processing only membership events and 3PID invites anymore, it's nice to know which function is supposed to process what.
2019-07-03 12:03:22 +01:00
Brendan Abolivier
8636ec042b Implement restrictions for power levels 2019-07-03 11:45:07 +01:00
Brendan Abolivier
78b737ff71 Merge pull request #5577 from matrix-org/babolivier/3pid-invite-ratelimit
Port #5576 to dinsic
2019-06-28 18:23:53 +01:00
Brendan Abolivier
a7a8bbf502 Only ratelimit when sending the email
If we do the opposite, an event can arrive after or while sending the email and the 3PID invite event will get ratelimited.
2019-06-28 17:47:38 +01:00
Brendan Abolivier
f304996c61 Changelog 2019-06-28 17:44:28 +01:00
Brendan Abolivier
7c644198c8 Don't update the ratelimiter before sending a 3PID invite
This would cause emails being sent, but Synapse responding with a 429 when creating the event. The client would then retry, and with bad timing the same scenario would happen again. Some testing I did ended up sending me 10 emails for one single invite because of this.
2019-06-28 17:44:28 +01:00
Brendan Abolivier
ee0ee97447 Add test case for #5574
There's no test that makes sure #5574 didn't break things or works correctly (my bad), so this PR adds a test case that makes sure of it.
2019-06-28 10:29:02 +01:00
Brendan Abolivier
f370fd01ec Merge pull request #5574 from matrix-org/babolivier/fix-3pid-bind
Fix new 3PID bindings being associated with rewritten IS's server names instead of the original one
2019-06-27 15:17:15 +01:00
Brendan Abolivier
1ef3627b05 Fix new 3PID bindings being associated with rewritten IS's server names instead of the original one
This would make unbind requests fail because Synapse is using the server name it has in DB as destination_is to generate signature, and Sydent uses its own server name there when verifying it, so if a mismatch happens, which is the case if the name gets rewritten for routing purposes, the unbind requests fail on the signature verification.
2019-06-27 14:53:10 +01:00
Brendan Abolivier
fbc5b58d21 Merge pull request #5542 from matrix-org/babolivier/federation-publicrooms
Port "Split public rooms directory auth config in two" to dinsic
2019-06-24 16:42:21 +01:00
Brendan Abolivier
84875301b6 Split public rooms directory auth config in two 2019-06-24 16:41:48 +01:00
Brendan Abolivier
18f0b69c49 Merge pull request #5495 from matrix-org/babolivier/deactivate_bg_job_typo
Port "Fix typo in deactivation background job" to dinsic
2019-06-19 11:58:52 +01:00
Brendan Abolivier
4875746d82 Fix typo in deactivation background job 2019-06-19 11:39:18 +01:00
Brendan Abolivier
fa4efb5967 Merge pull request #5484 from matrix-org/babolivier/dinsic_access_rules
Implement custom access rules
2019-06-19 10:41:37 +01:00
Brendan Abolivier
c1bc48f9d4 Add tests for constraints on changing the rule for a room 2019-06-18 18:07:05 +01:00
Brendan Abolivier
9b3c69f661 Add tests for 3PID invites 2019-06-18 17:59:07 +01:00
Brendan Abolivier
7157276124 Don't process 3PIDs in _apply_restricted 2019-06-18 17:43:34 +01:00
Brendan Abolivier
1532369dcd Remove unused import 2019-06-18 16:46:57 +01:00
Brendan Abolivier
145291108d Add tests for inviting with access rules 2019-06-18 16:32:54 +01:00
Brendan Abolivier
cefc5542fb Lint 2019-06-18 14:59:05 +01:00
Brendan Abolivier
2a1f35193b Remove unused imports 2019-06-18 14:57:04 +01:00
Brendan Abolivier
a09767d57d Lint 2019-06-18 14:55:24 +01:00
Brendan Abolivier
bc0fd8f170 Add tests for room creation hook 2019-06-18 14:54:19 +01:00
Brendan Abolivier
d36a876d2d Incorporate review 2019-06-18 14:53:33 +01:00
Brendan Abolivier
f7339d42ee Fixes 2019-06-18 11:28:33 +01:00
Brendan Abolivier
8aea2c3be1 Docstrings 2019-06-17 20:24:36 +01:00
Brendan Abolivier
1cd0ecc1f2 Rename into RoomAccessRules 2019-06-17 20:24:30 +01:00
Brendan Abolivier
19a4298a51 Fix function call 2019-06-17 20:24:26 +01:00
Brendan Abolivier
073dd7778e Implement rules change 2019-06-17 20:24:22 +01:00
Brendan Abolivier
00736c8935 Improve doc 2019-06-17 20:24:16 +01:00
Brendan Abolivier
112a48a5aa Implement 3PID invite hook 2019-06-17 20:24:07 +01:00
Brendan Abolivier
53aff08ebe Implement restricted rules and room creation hook 2019-06-17 20:22:53 +01:00
Brendan Abolivier
8b2f655589 Implement rules for direct 2019-06-17 20:22:27 +01:00
Brendan Abolivier
bd8448ccb2 Backbone 2019-06-17 20:19:12 +01:00
Brendan Abolivier
110608d1d6 Base 2019-06-17 20:19:08 +01:00
Brendan Abolivier
5a28504c08 Merge pull request #5481 from matrix-org/babolivier/third_party_rules_3pid
Port "Add third party rules hook for 3PID invites" to dinsic
2019-06-17 18:35:54 +01:00
Brendan Abolivier
9bb7cec90f Make check_threepid_can_be_invited async 2019-06-17 18:10:00 +01:00
Brendan Abolivier
8a8644045f Changelog 2019-06-17 18:10:00 +01:00
Brendan Abolivier
08d4534771 Add third party rules hook for 3PID invites 2019-06-17 18:10:00 +01:00
Erik Johnston
c8349787b7 Merge pull request #5474 from matrix-org/erikj/add_create_room_hook
Add third party rules hook into create room
2019-06-17 17:30:08 +01:00
Erik Johnston
e5e690041d Newsfile 2019-06-17 15:52:15 +01:00
Erik Johnston
fb1b76ff4c Add third party rules hook into create room 2019-06-17 15:48:57 +01:00
Brendan Abolivier
40ea934de0 Merge pull request #5471 from matrix-org/erikj/3pid_remote_invite_state
Port "Fix 3PID invite room state over federation" to dinsic
2019-06-17 11:43:02 +01:00
Brendan Abolivier
5c4296b47a Merge branch 'babolivier/third_party_event_rules' into dinsic 2019-06-14 19:38:44 +01:00
Brendan Abolivier
8b2543c0ec Merge pull request #5466 from matrix-org/babolivier/fix_deactivation_bg_job
Port "Fix background job for deactivated flag" to dinsic
2019-06-14 19:22:56 +01:00
Brendan Abolivier
bd59e154c1 Fix changelog 2019-06-14 18:29:13 +01:00
Brendan Abolivier
66378d13ce Changelog 2019-06-14 18:29:13 +01:00
Brendan Abolivier
65d3652cb7 Fix background job for deactivated flag 2019-06-14 18:29:13 +01:00
Brendan Abolivier
c644755123 Merge pull request #5463 from matrix-org/babolivier/account_validity_deactivated_accounts_2
Port "Don't send renewal emails to deactivated users" to dinsic
2019-06-14 17:19:57 +01:00
Brendan Abolivier
c7964e7430 Fix test 2019-06-14 16:25:18 +01:00
Brendan Abolivier
aded5cfb72 Don't send renewal emails to deactivated users 2019-06-14 15:39:18 +01:00
Brendan Abolivier
57bd5cfc9a Track deactivated accounts in the database (#5378) 2019-06-14 13:45:36 +01:00
Brendan Abolivier
ad566df746 Merge pull request #5420 from matrix-org/babolivier/userdir_hide_users
Add configuration option to hide new users from the user directory
2019-06-14 10:59:45 +01:00
Brendan Abolivier
c4759cd041 Merge branch 'dinsic' into babolivier/userdir_hide_users 2019-06-14 10:37:43 +01:00
Brendan Abolivier
4dda68da9a Make index unique 2019-06-14 10:37:12 +01:00
Brendan Abolivier
adf3eee668 Merge branch 'babolivier/fix_profile_replication' into babolivier/userdir_hide_users 2019-06-13 18:11:11 +01:00
Brendan Abolivier
a6cf1e079e Merge pull request #5416 from matrix-org/babolivier/fix_profile_replication
Add unique index to the profile_replication_status table.
2019-06-13 18:10:14 +01:00
Brendan Abolivier
996cf15d42 Lint 2019-06-13 17:41:13 +01:00
Brendan Abolivier
27cd0b3037 Fix snafu 2019-06-13 17:40:14 +01:00
Brendan Abolivier
26a27e06b9 Create the index in a background update 2019-06-13 15:57:55 +01:00
Brendan Abolivier
5283f65316 Fix bogus changelog 2019-06-12 16:49:10 +01:00
Brendan Abolivier
4a1b749582 Lint 2019-06-12 16:48:51 +01:00
Brendan Abolivier
e0c56d6527 Merge branch 'dinsic' into babolivier/fix_profile_replication 2019-06-12 16:41:08 +01:00
Brendan Abolivier
7c2d936802 Fix bogus changelog 2019-06-12 16:38:00 +01:00
Brendan Abolivier
1c7628eb3a Lint 2019-06-12 16:36:28 +01:00
Brendan Abolivier
8400e5f624 Merge branch 'dinsic' into babolivier/userdir_hide_users 2019-06-12 16:29:56 +01:00
Brendan Abolivier
02a659ae30 Regenerate full schemas 2019-06-12 15:51:59 +01:00
Brendan Abolivier
a55b2efca1 Fix path for password policy endpoints 2019-06-12 15:51:42 +01:00
Brendan Abolivier
d907e8f599 Merge branch 'master' into dinsic 2019-06-12 14:36:44 +01:00
Brendan Abolivier
3c8262b181 Merge branch 'master' into dinsic 2019-06-11 10:55:53 +01:00
Brendan Abolivier
389aa20170 Generate sample config 2019-06-10 17:31:45 +01:00
Brendan Abolivier
c10226581a Lint 2019-06-10 17:25:42 +01:00
Brendan Abolivier
10510f1e7e Lint 2019-06-10 17:23:11 +01:00
Brendan Abolivier
9ece96f5c8 Changelog 2019-06-10 17:17:18 +01:00
Brendan Abolivier
1924848dfa Add test case 2019-06-10 17:16:17 +01:00
Brendan Abolivier
deee82aebc Fix variable definition 2019-06-10 17:16:03 +01:00
Brendan Abolivier
0e63dd89a4 Fix condition 2019-06-10 16:56:53 +01:00
Brendan Abolivier
d331119758 Hide new users from the user directory if enabled in the server config. 2019-06-10 16:56:53 +01:00
Brendan Abolivier
9cce175bf0 Move schema update to 54 and add a warning comment 2019-06-10 15:34:41 +01:00
Brendan Abolivier
4f0e9a3f01 New line 2019-06-10 15:22:55 +01:00
Brendan Abolivier
35eea39c8c Add unique index to the profile_replication_status table. 2019-06-10 15:18:22 +01:00
Brendan Abolivier
8d16321edc Merge branch 'babolivier/account_validity_send_mail_auth' into dinsic 2019-06-10 11:59:20 +01:00
Brendan Abolivier
116f7778f4 Merge branch 'babolivier/email_config' into dinsic 2019-06-04 14:49:55 +01:00
Erik Johnston
d8fdba7bfb Merge branch 'babolivier/account_validity_job_delta' of github.com:matrix-org/synapse into dinsic 2019-05-31 12:12:24 +01:00
Brendan Abolivier
dde07c6859 Merge branch 'babolivier/account_validity_fix_schema' into dinsic 2019-05-28 11:36:11 +01:00
Brendan Abolivier
64365fcbdd Merge pull request #5214 from matrix-org/babolivier/password-policy
Allow server admins to define and enforce a password policy (MSC2000)
2019-05-22 11:09:42 +01:00
Brendan Abolivier
4a9eba9576 Test whole dict instead of individual fields 2019-05-22 10:43:23 +01:00
Brendan Abolivier
50cd07a836 Merge branch 'babolivier/account_validity_expiration_date' into dinsic 2019-05-21 14:56:05 +01:00
Brendan Abolivier
7dfc3c327c Improve documentation on generated configuration 2019-05-21 10:49:44 +01:00
Brendan Abolivier
42cea6b437 Make error messages more explicit 2019-05-21 10:21:27 +01:00
Brendan Abolivier
d9105b5ed8 Also test the /password client route 2019-05-21 09:55:32 +01:00
Brendan Abolivier
6fbf2ae9a8 Remove unused import 2019-05-20 19:49:19 +01:00
Brendan Abolivier
ed2b5b77f2 Config and changelog 2019-05-20 19:44:37 +01:00
Brendan Abolivier
6d54f1534a First implementation of MSC2000 2019-05-20 19:42:39 +01:00
Brendan Abolivier
d6e2f9f9da Merge branch 'babolivier/per_room_profiles' into dinsic 2019-05-17 15:07:41 +01:00
Brendan Abolivier
f608ddbe5c Merge branch 'release-v0.99.4' into dinsic 2019-05-14 11:43:03 +01:00
Brendan Abolivier
38e3d9ed67 Merge pull request #5115 from matrix-org/babolivier/lookup_path
[DINSIC] Move 3PID lookup endpoint to CS API and proxy bulk lookups
2019-05-09 15:02:21 +01:00
Brendan Abolivier
aa5c42f5bc Fix failing test 2019-05-09 13:59:57 +01:00
Brendan Abolivier
8bcb78891e Merge branch 'babolivier/lookup_path' of github.com:matrix-org/synapse into babolivier/lookup_path 2019-05-09 13:09:19 +01:00
Brendan Abolivier
f304f1a574 Incorporate review 2019-05-09 13:07:43 +01:00
Brendan Abolivier
532ba44add Fix test 2019-05-09 13:01:40 +01:00
Brendan Abolivier
10e3ed83e9 Check if Synapse should check given ISs 2019-05-09 12:53:24 +01:00
Richard van der Hoff
622ecec24b Merge remote-tracking branch 'origin/dinsic' into babolivier/lookup_path 2019-05-09 11:06:02 +01:00
Richard van der Hoff
09ea63ae7a Merge pull request #5098 from matrix-org/rav/fix_pep_517
Workarounds for pep-517 errors
2019-05-08 18:13:15 +01:00
Brendan Abolivier
f059a91085 /bulk_lookup doesn't return a signature 2019-05-07 14:16:26 +01:00
Brendan Abolivier
66f7588f87 Fix expected key in bulk lookup response 2019-05-07 12:06:24 +01:00
Brendan Abolivier
b4f3d70b21 Incorporate review 2019-05-07 11:47:37 +01:00
Brendan Abolivier
3d031c211d Fix error message 2019-05-01 10:10:38 +01:00
Andrew Morgan
371296443f Update synapse/handlers/identity.py
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-05-01 10:03:46 +01:00
Andrew Morgan
1973eb11d2 Update synapse/rest/client/v2_alpha/account.py
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-05-01 10:02:18 +01:00
Andrew Morgan
26c004129f Update synapse/rest/client/v2_alpha/account.py
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-05-01 10:01:57 +01:00
Richard van der Hoff
0cc91efd6a Merge pull request #5098 from matrix-org/rav/fix_pep_517
Workarounds for pep-517 errors
2019-04-30 18:33:19 +01:00
Brendan Abolivier
fe6ac9c5d7 Fixed return value 2019-04-30 18:28:01 +01:00
Brendan Abolivier
96bd70f6d0 Bunch of tests 2019-04-30 18:22:52 +01:00
Brendan Abolivier
3a9c405a0f Fix url and method 2019-04-30 18:22:42 +01:00
Brendan Abolivier
909ceecc28 Tests 2019-04-30 17:27:58 +01:00
Brendan Abolivier
70da5202ba Fixes 2019-04-30 17:27:47 +01:00
Brendan Abolivier
34bbbe81a6 Fix method 2019-04-30 16:59:46 +01:00
Brendan Abolivier
2d979e639d Register servlets 2019-04-30 16:51:50 +01:00
Brendan Abolivier
d296cdc9dd Add bulk lookup 2019-04-30 15:15:02 +01:00
Brendan Abolivier
8df16a8aee Move lookup endpoint to CS API (and s/is_server/id_server/) 2019-04-30 15:11:21 +01:00
Matthew Hodgson
15b7a84aa8 changelog 2019-04-21 01:01:40 +01:00
Andrew Morgan
2f61dd058d [DINSIC] Add ability to proxy identity lookups (#5048) 2019-04-16 17:41:01 +01:00
Andrew Morgan
e6218e4880 [DINSIC] Block internal users from inviting external users to a public room (#5061)
Co-Authored-By: babolivier <contact@brendanabolivier.com>
2019-04-16 16:41:01 +01:00
Andrew Morgan
7d71975e6a Merge branch 'develop' into dinsic 2019-04-15 15:22:14 +01:00
Brendan Abolivier
0fcf7e5c57 Add config option to block users from looking up 3PIDs (#5010) 2019-04-05 14:25:27 +01:00
Erik Johnston
9bf49abc07 Merge branch 'master' of github.com:matrix-org/synapse into dinsic 2019-04-05 14:10:16 +01:00
Michael Kaye
dd747ba045 Prevent exception when hs or shadow_hs missing (#5012)
* Prevent exception when hs or shadow_hs missing
2019-04-04 17:45:12 +01:00
Erik Johnston
b00a8d870c Fix registration with register_mxid_from_3pid enabled (#5011) 2019-04-04 16:45:15 +01:00
Michael Kaye
8fa09c7479 Rewrite more internal IS urls. (#5006)
* Rewrite more internal IS urls.
2019-04-04 15:28:37 +01:00
Erik Johnston
d94873d525 Merge pull request #4997 from matrix-org/erikj/dinsic_email_display_name
Add config option to use email as display name for new users
2019-04-03 10:57:20 +01:00
Erik Johnston
f2fa172375 Sample config 2019-04-03 10:40:40 +01:00
Erik Johnston
8c0ebe3026 Add config option to use email as display name for new users 2019-04-03 10:26:56 +01:00
Erik Johnston
53dd358c83 Merge pull request #4910 from matrix-org/erikj/third_party_invite_create_spam
Add third party invite support to spam checker
2019-03-21 16:07:27 +00:00
Erik Johnston
f5c944c7f2 Fix comments 2019-03-21 15:31:34 +00:00
Erik Johnston
aefb7a1146 Update sample config 2019-03-21 12:52:22 +00:00
Erik Johnston
479b7b1eff Add another test 2019-03-21 12:48:37 +00:00
Erik Johnston
f04ee0b351 Run black on tests/rulecheck/ 2019-03-21 12:48:37 +00:00
Erik Johnston
164798ec32 Add 3PID invite support to spam checker 2019-03-21 12:48:37 +00:00
Erik Johnston
b7d7d20a38 Correctly handle 3PID invites in create room spam check
We also add an option to outright deny third party invites
2019-03-21 12:48:37 +00:00
Erik Johnston
2bb6d85736 Turn off newsfile check 2019-03-21 12:48:25 +00:00
Erik Johnston
0f0671e5e0 Merge branch 'develop' of github.com:matrix-org/synapse into erikj/dinsic-merged 2019-03-21 12:41:42 +00:00
Erik Johnston
8eb9f37a01 Merge pull request #4875 from matrix-org/erikj/spam_checker
Extend spam checking rules
2019-03-18 16:28:46 +00:00
Erik Johnston
ea89e73ebf Add unit tests 2019-03-18 15:56:08 +00:00
Erik Johnston
68a9d1fc34 Add rules to DomainRuleChecker 2019-03-18 15:56:04 +00:00
Erik Johnston
feae387576 Don't spam check actions by admins 2019-03-18 15:51:00 +00:00
Erik Johnston
e64f7c0188 Run black on tests/rulecheck/test_domainrulecheck.py 2019-03-18 15:51:00 +00:00
Erik Johnston
b85ff4b894 Add user_may_join_room spam check 2019-03-18 15:51:00 +00:00
Erik Johnston
4eca8d3fb3 Add invite_list and cloning param to create room rule 2019-03-18 15:50:55 +00:00
Michael Kaye
aa3dc78f65 Merge pull request #4862 from matrix-org/erikj/dinsic-merged-master
Merge master into dinsic
2019-03-15 17:21:22 +01:00
Erik Johnston
de874364e7 Fixup config 2019-03-15 14:41:27 +00:00
Erik Johnston
7e94e2ad94 Disable changelog CI checks 2019-03-15 14:40:28 +00:00
Erik Johnston
e7ec6f78ca Manifest 2019-03-15 14:39:25 +00:00
Erik Johnston
7a9aa4b81b Isort 2019-03-15 14:39:25 +00:00
Erik Johnston
5827e976fe Fixups 2019-03-15 14:39:25 +00:00
Erik Johnston
44c0661d97 Merge branch 'master' of github.com:matrix-org/synapse into erikj/dinsic-merged-master 2019-03-15 14:36:44 +00:00
Erik Johnston
85db96cc81 Add some debug logging for device list handling 2019-03-08 12:31:41 +00:00
Andrew Morgan
3271742905 Merge pull request #4681 from matrix-org/dinsic_anoa/info_split
[DINSIC] Use internal-info for identity server
2019-02-28 11:28:55 +00:00
Andrew Morgan
0a23bf442f Merge branch 'dinsic_anoa/info_split' of github.com:matrix-org/synapse into dinsic_anoa/info_split 2019-02-27 15:23:19 +00:00
Andrew Morgan
9b13038d05 Check shadow_hs as well as hs during 3pid reg 2019-02-27 15:22:41 +00:00
Andrew Morgan
dfe09ec313 Merge pull request #4747 from matrix-org/anoa/public_rooms_federate
[DINSIC] Prevent showing non-fed rooms in fed /publicRooms
2019-02-26 14:40:45 +00:00
Richard van der Hoff
13bc1e5307 Update synapse/util/threepids.py
Co-Authored-By: anoadragon453 <1342360+anoadragon453@users.noreply.github.com>
2019-02-25 16:08:58 +00:00
Andrew Morgan
70e039c7ae Use internal-info for identity server. Block reg on fields 2019-02-19 15:29:49 +00:00
Michael Kaye
2712a9ef8f Fix to keep the signature valid for the request. (#4480) 2019-01-28 14:24:28 +00:00
Michael Kaye
da757b7759 Rewrite identity server URLs as required. (#4393)
This takes a mapping of <old> -> <new> and looks up and replaces as
required.
2019-01-21 15:48:15 +00:00
Michael Kaye
59bc7debf0 When performing shadow registration, don't inhibit login. (#4385) 2019-01-14 18:01:34 +00:00
Matthew Hodgson
cf68593544 Synchronise account metadata onto another server. (#4145)
* implement shadow registration via AS (untested)
* shadow support for 3pid binding/unbinding (untested)
2019-01-11 15:50:28 +00:00
Michael Kaye
9cc95fd0a5 Merge pull request #4148 from matrix-org/matthew/red_list
add im.vector.hide_profile to user account_data
2018-12-19 15:42:19 +00:00
Matthew Hodgson
82886e4c8f hide_profile: false should mean not to hide the profile :/ 2018-12-12 00:57:39 +00:00
Matthew Hodgson
08919847c1 fix sense of 'hide' 2018-11-04 23:49:57 +00:00
Matthew Hodgson
c3acc45a87 pull in profile_handler correctly 2018-11-04 23:49:19 +00:00
Matthew Hodgson
ae5bb32ad0 add im.vector.hide_profile to user account_data 2018-11-04 23:46:11 +00:00
Matthew Hodgson
7ed3232b08 fix tests 2018-11-03 12:58:25 +00:00
Matthew Hodgson
6e7488ce11 merge master into dinsic, again... 2018-11-03 12:14:24 +00:00
Michael Kaye
41585e1340 Merge pull request #4047 from matrix-org/michaelkaye/dinsic_allow_user_directory_url
user_directory.defer_to_id_server should be an URL, not a hostname
2018-11-02 12:00:18 +00:00
Matthew Hodgson
9498cd3e7b fix conflict and reinstate 6372dff771 2018-10-22 20:27:25 +02:00
Matthew Hodgson
c7503f8f33 merge in master 2018-10-22 20:19:40 +02:00
Michael Kaye
9d8baa1595 Allow us to configure http vs https for user_directory 2018-10-17 11:38:48 +01:00
Matthew Hodgson
4ff8486f0f fix missing import and run isort 2018-07-20 11:29:18 +01:00
David Baker
2669e494e0 Merge remote-tracking branch 'origin/master' into dinsic 2018-07-19 18:25:25 +01:00
David Baker
b6d8a808a4 Merge pull request #3557 from matrix-org/dbkr/delete_profiles
Remove deactivated users from profile search
2018-07-19 15:58:40 +01:00
David Baker
0cb5d34756 Hopefully fix postgres 2018-07-19 15:12:48 +01:00
David Baker
650761666d More run_on_reactor 2018-07-19 14:52:35 +01:00
David Baker
aa2a4b4b42 run_on_reactor is dead 2018-07-19 14:48:24 +01:00
David Baker
022469d819 Change column def so it works on pgsql & sqlite
Now I remember discovering previously there was no way to make boolean
columns work
2018-07-19 10:28:26 +01:00
David Baker
45d06c754a Add hopefully enlightening comment 2018-07-18 20:52:21 +01:00
David Baker
dbd0821c43 Oops, didn't mean to commit that 2018-07-18 20:50:20 +01:00
David Baker
0476852fc6 Remove deactivated users from profile search 2018-07-18 18:05:29 +01:00
David Baker
1d11d9323d Merge remote-tracking branch 'origin/master' into dinsic 2018-07-17 15:43:33 +01:00
Michael Kaye
261e4f2542 Merge pull request #3502 from matrix-org/matthew/dinsic-tweak-display-names
tweak dinsic display names
2018-07-10 15:59:26 +01:00
Matthew Hodgson
11728561f3 improve domain matches 2018-07-10 15:21:14 +01:00
Matthew Hodgson
9d57abcadd fix bounds error 2018-07-10 13:58:01 +01:00
Matthew Hodgson
cb0bbde981 tweak dinsic display names 2018-07-10 13:56:32 +01:00
Matthew Hodgson
abc97bd1de Merge pull request #3487 from matrix-org/matthew/dinsic-encrypt-for-invited-users
Query the device lists of users when they are invited to a room.
2018-07-10 12:21:57 +01:00
Matthew Hodgson
ee238254a0 Query the device lists of users when they are invited to a room.
Previously we only queried the device list when the user joined the room; now we
do it when they are invited too.  This means that new messages can be encrypted
for the devices of the invited user as of the point they were invited.

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

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

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

View File

@@ -0,0 +1,21 @@
version: '3.1'
services:
postgres:
image: postgres:9.4
environment:
POSTGRES_PASSWORD: postgres
testenv:
image: python:2.7
depends_on:
- postgres
env_file: .env
environment:
SYNAPSE_POSTGRES_HOST: postgres
SYNAPSE_POSTGRES_USER: postgres
SYNAPSE_POSTGRES_PASSWORD: postgres
working_dir: /app
volumes:
- ..:/app

View File

@@ -0,0 +1,21 @@
version: '3.1'
services:
postgres:
image: postgres:9.5
environment:
POSTGRES_PASSWORD: postgres
testenv:
image: python:2.7
depends_on:
- postgres
env_file: .env
environment:
SYNAPSE_POSTGRES_HOST: postgres
SYNAPSE_POSTGRES_USER: postgres
SYNAPSE_POSTGRES_PASSWORD: postgres
working_dir: /app
volumes:
- ..:/app

View File

@@ -0,0 +1,21 @@
version: '3.1'
services:
postgres:
image: postgres:9.4
environment:
POSTGRES_PASSWORD: postgres
testenv:
image: python:3.5
depends_on:
- postgres
env_file: .env
environment:
SYNAPSE_POSTGRES_HOST: postgres
SYNAPSE_POSTGRES_USER: postgres
SYNAPSE_POSTGRES_PASSWORD: postgres
working_dir: /app
volumes:
- ..:/app

View File

@@ -1,33 +0,0 @@
import sys
from tap.parser import Parser
from tap.line import Result, Unknown, Diagnostic
out = ["### TAP Output for " + sys.argv[2]]
p = Parser()
in_error = False
for line in p.parse_file(sys.argv[1]):
if isinstance(line, Result):
if in_error:
out.append("")
out.append("</pre></code></details>")
out.append("")
out.append("----")
out.append("")
in_error = False
if not line.ok and not line.todo:
in_error = True
out.append("FAILURE Test #%d: ``%s``" % (line.number, line.description))
out.append("")
out.append("<details><summary>Show log</summary><code><pre>")
elif isinstance(line, Diagnostic) and in_error:
out.append(line.text)
if out:
for line in out[:-3]:
print(line)

View File

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

View File

@@ -2,11 +2,10 @@ env:
CODECOV_TOKEN: "2dd7eb9b-0eda-45fe-a47c-9b5ac040045f"
steps:
- command:
- "python -m pip install tox"
- "tox -e check_codestyle"
label: "\U0001F9F9 Check Style"
- "tox -e pep8"
label: "\U0001F9F9 PEP-8"
plugins:
- docker#v3.0.1:
image: "python:3.6"
@@ -47,16 +46,15 @@ steps:
- wait
- command:
- "python -m pip install tox"
- "tox -e py35-old,codecov"
label: ":python: 3.5 / SQLite / Old Deps"
- "tox -e py27,codecov"
label: ":python: 2.7 / SQLite"
env:
TRIAL_FLAGS: "-j 2"
plugins:
- docker#v3.0.1:
image: "python:3.5"
image: "python:2.7"
propagate-environment: true
retry:
automatic:
@@ -116,6 +114,74 @@ steps:
- exit_status: 2
limit: 2
- command:
- "python -m pip install tox"
- "tox -e py27-old,codecov"
label: ":python: 2.7 / SQLite / Old Deps"
env:
TRIAL_FLAGS: "-j 2"
plugins:
- docker#v3.0.1:
image: "python:2.7"
propagate-environment: true
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2
- label: ":python: 2.7 / :postgres: 9.4"
env:
TRIAL_FLAGS: "-j 4"
command:
- "bash -c 'python -m pip install tox && python -m tox -e py27-postgres,codecov'"
plugins:
- docker-compose#v2.1.0:
run: testenv
config:
- .buildkite/docker-compose.py27.pg94.yaml
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2
- label: ":python: 2.7 / :postgres: 9.5"
env:
TRIAL_FLAGS: "-j 4"
command:
- "bash -c 'python -m pip install tox && python -m tox -e py27-postgres,codecov'"
plugins:
- docker-compose#v2.1.0:
run: testenv
config:
- .buildkite/docker-compose.py27.pg95.yaml
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2
- label: ":python: 3.5 / :postgres: 9.4"
env:
TRIAL_FLAGS: "-j 4"
command:
- "bash -c 'python -m pip install tox && python -m tox -e py35-postgres,codecov'"
plugins:
- docker-compose#v2.1.0:
run: testenv
config:
- .buildkite/docker-compose.py35.pg94.yaml
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2
- label: ":python: 3.5 / :postgres: 9.5"
env:
TRIAL_FLAGS: "-j 4"
@@ -166,61 +232,3 @@ steps:
limit: 2
- exit_status: 2
limit: 2
- label: "SyTest - :python: 3.5 / SQLite / Monolith"
agents:
queue: "medium"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash .buildkite/synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:py35"
propagate-environment: true
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2
- label: "SyTest - :python: 3.5 / :postgres: 9.6 / Monolith"
agents:
queue: "medium"
env:
POSTGRES: "1"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash .buildkite/synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:py35"
propagate-environment: true
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2
- label: "SyTest - :python: 3.5 / :postgres: 9.6 / Workers"
agents:
queue: "medium"
env:
POSTGRES: "1"
WORKERS: "1"
command:
- "bash .buildkite/merge_base_branch.sh"
- "bash .buildkite/synapse_sytest.sh"
plugins:
- docker#v3.0.1:
image: "matrixdotorg/sytest-synapse:py35"
propagate-environment: true
soft_fail: true
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 2
limit: 2

View File

@@ -1,145 +0,0 @@
#!/bin/bash
#
# Fetch sytest, and then run the tests for synapse. The entrypoint for the
# sytest-synapse docker images.
set -ex
if [ -n "$BUILDKITE" ]
then
SYNAPSE_DIR=`pwd`
else
SYNAPSE_DIR="/src"
fi
# Attempt to find a sytest to use.
# If /sytest exists, it means that a SyTest checkout has been mounted into the Docker image.
if [ -d "/sytest" ]; then
# If the user has mounted in a SyTest checkout, use that.
echo "Using local sytests..."
# create ourselves a working directory and dos2unix some scripts therein
mkdir -p /work/jenkins
for i in install-deps.pl run-tests.pl tap-to-junit-xml.pl jenkins/prep_sytest_for_postgres.sh; do
dos2unix -n "/sytest/$i" "/work/$i"
done
ln -sf /sytest/tests /work
ln -sf /sytest/keys /work
SYTEST_LIB="/sytest/lib"
else
if [ -n "BUILDKITE_BRANCH" ]
then
branch_name=$BUILDKITE_BRANCH
else
# Otherwise, try and find out what the branch that the Synapse checkout is using. Fall back to develop if it's not a branch.
branch_name="$(git --git-dir=/src/.git symbolic-ref HEAD 2>/dev/null)" || branch_name="develop"
fi
# Try and fetch the branch
echo "Trying to get same-named sytest branch..."
wget -q https://github.com/matrix-org/sytest/archive/$branch_name.tar.gz -O sytest.tar.gz || {
# Probably a 404, fall back to develop
echo "Using develop instead..."
wget -q https://github.com/matrix-org/sytest/archive/develop.tar.gz -O sytest.tar.gz
}
mkdir -p /work
tar -C /work --strip-components=1 -xf sytest.tar.gz
SYTEST_LIB="/work/lib"
fi
cd /work
# PostgreSQL setup
if [ -n "$POSTGRES" ]
then
export PGUSER=postgres
export POSTGRES_DB_1=pg1
export POSTGRES_DB_2=pg2
# Start the database
su -c 'eatmydata /usr/lib/postgresql/9.6/bin/pg_ctl -w -D /var/lib/postgresql/data start' postgres
# Use the Jenkins script to write out the configuration for a PostgreSQL using Synapse
jenkins/prep_sytest_for_postgres.sh
# Make the test databases for the two Synapse servers that will be spun up
su -c 'psql -c "CREATE DATABASE pg1;"' postgres
su -c 'psql -c "CREATE DATABASE pg2;"' postgres
fi
if [ -n "$OFFLINE" ]; then
# if we're in offline mode, just put synapse into the virtualenv, and
# hope that the deps are up-to-date.
#
# (`pip install -e` likes to reinstall setuptools even if it's already installed,
# so we just run setup.py explicitly.)
#
(cd $SYNAPSE_DIR && /venv/bin/python setup.py -q develop)
else
# We've already created the virtualenv, but lets double check we have all
# deps.
/venv/bin/pip install -q --upgrade --no-cache-dir -e $SYNAPSE_DIR
/venv/bin/pip install -q --upgrade --no-cache-dir \
lxml psycopg2 coverage codecov tap.py
# Make sure all Perl deps are installed -- this is done in the docker build
# so will only install packages added since the last Docker build
./install-deps.pl
fi
# Run the tests
>&2 echo "+++ Running tests"
RUN_TESTS=(
perl -I "$SYTEST_LIB" ./run-tests.pl --python=/venv/bin/python --synapse-directory=$SYNAPSE_DIR --coverage -O tap --all
)
TEST_STATUS=0
if [ -n "$WORKERS" ]; then
RUN_TESTS+=(-I Synapse::ViaHaproxy --dendron-binary=/pydron.py)
else
RUN_TESTS+=(-I Synapse)
fi
"${RUN_TESTS[@]}" "$@" > results.tap || TEST_STATUS=$?
if [ $TEST_STATUS -ne 0 ]; then
>&2 echo -e "run-tests \e[31mFAILED\e[0m: exit code $TEST_STATUS"
else
>&2 echo -e "run-tests \e[32mPASSED\e[0m"
fi
>&2 echo "--- Copying assets"
# Copy out the logs
mkdir -p /logs
cp results.tap /logs/results.tap
rsync --ignore-missing-args --min-size=1B -av server-0 server-1 /logs --include "*/" --include="*.log.*" --include="*.log" --exclude="*"
# Upload coverage to codecov and upload files, if running on Buildkite
if [ -n "$BUILDKITE" ]
then
/venv/bin/coverage combine || true
/venv/bin/coverage xml || true
/venv/bin/codecov -X gcov -f coverage.xml
wget -O buildkite.tar.gz https://github.com/buildkite/agent/releases/download/v3.13.0/buildkite-agent-linux-amd64-3.13.0.tar.gz
tar xvf buildkite.tar.gz
chmod +x ./buildkite-agent
# Upload the files
./buildkite-agent artifact upload "/logs/**/*.log*"
./buildkite-agent artifact upload "/logs/results.tap"
if [ $TEST_STATUS -ne 0 ]; then
# Annotate, if failure
/venv/bin/python $SYNAPSE_DIR/.buildkite/format_tap.py /logs/results.tap "$BUILDKITE_LABEL" | ./buildkite-agent annotate --style="error" --context="$BUILDKITE_LABEL"
fi
fi
exit $TEST_STATUS

View File

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

35
.circleci/merge_base_branch.sh Executable file
View File

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

View File

@@ -1,13 +1,9 @@
# ignore everything by default
*
# things to include
!docker
!scripts
!synapse
!MANIFEST.in
!README.rst
!setup.py
!synctl
**/__pycache__
Dockerfile
.travis.yml
.gitignore
demo/etc
tox.ini
.git/*
.tox/*
debian/matrix-synapse/
debian/matrix-synapse-*/

4
.github/FUNDING.yml vendored
View File

@@ -1,4 +0,0 @@
# One username per supported platform and one custom link
patreon: matrixdotorg
liberapay: matrixdotorg
custom: https://paypal.me/matrixdotorg

View File

@@ -4,7 +4,6 @@ about: I need support for Synapse
---
Please don't file github issues asking for support.
# Please ask for support in [**#matrix:matrix.org**](https://matrix.to/#/#matrix:matrix.org)
Instead, please join [`#synapse:matrix.org`](https://matrix.to/#/#synapse:matrix.org)
(from a matrix.org account if necessary), and ask there.
## Don't file an issue as a support request.

6
.github/SUPPORT.md vendored
View File

@@ -1,3 +1,3 @@
[**#synapse:matrix.org**](https://matrix.to/#/#synapse:matrix.org) is the official support room for
Synapse, and can be accessed by any client from https://matrix.org/docs/projects/try-matrix-now.html.
Please ask for support there, rather than filing github issues.
[**#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

View File

@@ -72,6 +72,3 @@ Jason Robinson <jasonr at matrix.org>
Joseph Weston <joseph at weston.cloud>
+ Add admin API for querying HS version
Benjamin Saunders <ben.e.saunders at gmail dot com>
* Documentation improvements

View File

@@ -1,107 +1,3 @@
Synapse 1.1.0rc1 (2019-07-02)
=============================
As of v1.1.0, Synapse no longer supports Python 2, nor Postgres version 9.4.
See the [upgrade notes](UPGRADE.rst#upgrading-to-v110) for more details.
Features
--------
- Added possibilty to disable local password authentication. Contributed by Daniel Hoffend. ([\#5092](https://github.com/matrix-org/synapse/issues/5092))
- Add monthly active users to phonehome stats. ([\#5252](https://github.com/matrix-org/synapse/issues/5252))
- Allow expired user to trigger renewal email sending manually. ([\#5363](https://github.com/matrix-org/synapse/issues/5363))
- Statistics on forward extremities per room are now exposed via Prometheus. ([\#5384](https://github.com/matrix-org/synapse/issues/5384), [\#5458](https://github.com/matrix-org/synapse/issues/5458), [\#5461](https://github.com/matrix-org/synapse/issues/5461))
- Add --no-daemonize option to run synapse in the foreground, per issue #4130. Contributed by Soham Gumaste. ([\#5412](https://github.com/matrix-org/synapse/issues/5412), [\#5587](https://github.com/matrix-org/synapse/issues/5587))
- Fully support SAML2 authentication. Contributed by [Alexander Trost](https://github.com/galexrt) - thank you! ([\#5422](https://github.com/matrix-org/synapse/issues/5422))
- Allow server admins to define implementations of extra rules for allowing or denying incoming events. ([\#5440](https://github.com/matrix-org/synapse/issues/5440), [\#5474](https://github.com/matrix-org/synapse/issues/5474), [\#5477](https://github.com/matrix-org/synapse/issues/5477))
- Add support for handling pagination APIs on client reader worker. ([\#5505](https://github.com/matrix-org/synapse/issues/5505), [\#5513](https://github.com/matrix-org/synapse/issues/5513), [\#5531](https://github.com/matrix-org/synapse/issues/5531))
- Improve help and cmdline option names for --generate-config options. ([\#5512](https://github.com/matrix-org/synapse/issues/5512))
- Allow configuration of the path used for ACME account keys. ([\#5516](https://github.com/matrix-org/synapse/issues/5516), [\#5521](https://github.com/matrix-org/synapse/issues/5521), [\#5522](https://github.com/matrix-org/synapse/issues/5522))
- Add --data-dir and --open-private-ports options. ([\#5524](https://github.com/matrix-org/synapse/issues/5524))
- Split public rooms directory auth config in two settings, in order to manage client auth independently from the federation part of it. Obsoletes the "restrict_public_rooms_to_local_users" configuration setting. If "restrict_public_rooms_to_local_users" is set in the config, Synapse will act as if both new options are enabled, i.e. require authentication through the client API and deny federation requests. ([\#5534](https://github.com/matrix-org/synapse/issues/5534))
- The minimum TLS version used for outgoing federation requests can now be set with `federation_client_minimum_tls_version`. ([\#5550](https://github.com/matrix-org/synapse/issues/5550))
- Optimise devices changed query to not pull unnecessary rows from the database, reducing database load. ([\#5559](https://github.com/matrix-org/synapse/issues/5559))
- Add new metrics for number of forward extremities being persisted and number of state groups involved in resolution. ([\#5476](https://github.com/matrix-org/synapse/issues/5476))
Bugfixes
--------
- Fix bug processing incoming events over federation if call to `/get_missing_events` fails. ([\#5042](https://github.com/matrix-org/synapse/issues/5042))
- Prevent more than one room upgrade happening simultaneously on the same room. ([\#5051](https://github.com/matrix-org/synapse/issues/5051))
- Fix a bug where running synapse_port_db would cause the account validity feature to fail because it didn't set the type of the email_sent column to boolean. ([\#5325](https://github.com/matrix-org/synapse/issues/5325))
- Warn about disabling email-based password resets when a reset occurs, and remove warning when someone attempts a phone-based reset. ([\#5387](https://github.com/matrix-org/synapse/issues/5387))
- Fix email notifications for unnamed rooms with multiple people. ([\#5388](https://github.com/matrix-org/synapse/issues/5388))
- Fix exceptions in federation reader worker caused by attempting to renew attestations, which should only happen on master worker. ([\#5389](https://github.com/matrix-org/synapse/issues/5389))
- Fix handling of failures fetching remote content to not log failures as exceptions. ([\#5390](https://github.com/matrix-org/synapse/issues/5390))
- Fix a bug where deactivated users could receive renewal emails if the account validity feature is on. ([\#5394](https://github.com/matrix-org/synapse/issues/5394))
- Fix missing invite state after exchanging 3PID invites over federaton. ([\#5464](https://github.com/matrix-org/synapse/issues/5464))
- Fix intermittent exceptions on Apple hardware. Also fix bug that caused database activity times to be under-reported in log lines. ([\#5498](https://github.com/matrix-org/synapse/issues/5498))
- Fix logging error when a tampered event is detected. ([\#5500](https://github.com/matrix-org/synapse/issues/5500))
- Fix bug where clients could tight loop calling `/sync` for a period. ([\#5507](https://github.com/matrix-org/synapse/issues/5507))
- Fix bug with `jinja2` preventing Synapse from starting. Users who had this problem should now simply need to run `pip install matrix-synapse`. ([\#5514](https://github.com/matrix-org/synapse/issues/5514))
- Fix a regression where homeservers on private IP addresses were incorrectly blacklisted. ([\#5523](https://github.com/matrix-org/synapse/issues/5523))
- Fixed m.login.jwt using unregistred user_id and added pyjwt>=1.6.4 as jwt conditional dependencies. Contributed by Pau Rodriguez-Estivill. ([\#5555](https://github.com/matrix-org/synapse/issues/5555), [\#5586](https://github.com/matrix-org/synapse/issues/5586))
- Fix a bug that would cause invited users to receive several emails for a single 3PID invite in case the inviter is rate limited. ([\#5576](https://github.com/matrix-org/synapse/issues/5576))
Updates to the Docker image
---------------------------
- Add ability to change Docker containers [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) with the `TZ` variable. ([\#5383](https://github.com/matrix-org/synapse/issues/5383))
- Update docker image to use Python 3.7. ([\#5546](https://github.com/matrix-org/synapse/issues/5546))
- Deprecate the use of environment variables for configuration, and make the use of a static configuration the default. ([\#5561](https://github.com/matrix-org/synapse/issues/5561), [\#5562](https://github.com/matrix-org/synapse/issues/5562), [\#5566](https://github.com/matrix-org/synapse/issues/5566), [\#5567](https://github.com/matrix-org/synapse/issues/5567))
- Increase default log level for docker image to INFO. It can still be changed by editing the generated log.config file. ([\#5547](https://github.com/matrix-org/synapse/issues/5547))
- Send synapse logs to the docker logging system, by default. ([\#5565](https://github.com/matrix-org/synapse/issues/5565))
- Open the non-TLS port by default. ([\#5568](https://github.com/matrix-org/synapse/issues/5568))
- Fix failure to start under docker with SAML support enabled. ([\#5490](https://github.com/matrix-org/synapse/issues/5490))
- Use a sensible location for data files when generating a config file. ([\#5563](https://github.com/matrix-org/synapse/issues/5563))
Deprecations and Removals
-------------------------
- Python 2.7 is no longer a supported platform. Synapse now requires Python 3.5+ to run. ([\#5425](https://github.com/matrix-org/synapse/issues/5425))
- PostgreSQL 9.4 is no longer supported. Synapse requires Postgres 9.5+ or above for Postgres support. ([\#5448](https://github.com/matrix-org/synapse/issues/5448))
- Remove support for cpu_affinity setting. ([\#5525](https://github.com/matrix-org/synapse/issues/5525))
Improved Documentation
----------------------
- Improve README section on performance troubleshooting. ([\#4276](https://github.com/matrix-org/synapse/issues/4276))
- Add information about how to install and run `black` on the codebase to code_style.rst. ([\#5537](https://github.com/matrix-org/synapse/issues/5537))
- Improve install docs on choosing server_name. ([\#5558](https://github.com/matrix-org/synapse/issues/5558))
Internal Changes
----------------
- Add logging to 3pid invite signature verification. ([\#5015](https://github.com/matrix-org/synapse/issues/5015))
- Update example haproxy config to a more compatible setup. ([\#5313](https://github.com/matrix-org/synapse/issues/5313))
- Track deactivated accounts in the database. ([\#5378](https://github.com/matrix-org/synapse/issues/5378), [\#5465](https://github.com/matrix-org/synapse/issues/5465), [\#5493](https://github.com/matrix-org/synapse/issues/5493))
- Clean up code for sending federation EDUs. ([\#5381](https://github.com/matrix-org/synapse/issues/5381))
- Add a sponsor button to the repo. ([\#5382](https://github.com/matrix-org/synapse/issues/5382), [\#5386](https://github.com/matrix-org/synapse/issues/5386))
- Don't log non-200 responses from federation queries as exceptions. ([\#5383](https://github.com/matrix-org/synapse/issues/5383))
- Update Python syntax in contrib/ to Python 3. ([\#5446](https://github.com/matrix-org/synapse/issues/5446))
- Update federation_client dev script to support `.well-known` and work with python3. ([\#5447](https://github.com/matrix-org/synapse/issues/5447))
- SyTest has been moved to Buildkite. ([\#5459](https://github.com/matrix-org/synapse/issues/5459))
- Demo script now uses python3. ([\#5460](https://github.com/matrix-org/synapse/issues/5460))
- Synapse can now handle RestServlets that return coroutines. ([\#5475](https://github.com/matrix-org/synapse/issues/5475), [\#5585](https://github.com/matrix-org/synapse/issues/5585))
- The demo servers talk to each other again. ([\#5478](https://github.com/matrix-org/synapse/issues/5478))
- Add an EXPERIMENTAL config option to try and periodically clean up extremities by sending dummy events. ([\#5480](https://github.com/matrix-org/synapse/issues/5480))
- Synapse's codebase is now formatted by `black`. ([\#5482](https://github.com/matrix-org/synapse/issues/5482))
- Some cleanups and sanity-checking in the CPU and database metrics. ([\#5499](https://github.com/matrix-org/synapse/issues/5499))
- Improve email notification logging. ([\#5502](https://github.com/matrix-org/synapse/issues/5502))
- Fix "Unexpected entry in 'full_schemas'" log warning. ([\#5509](https://github.com/matrix-org/synapse/issues/5509))
- Improve logging when generating config files. ([\#5510](https://github.com/matrix-org/synapse/issues/5510))
- Refactor and clean up Config parser for maintainability. ([\#5511](https://github.com/matrix-org/synapse/issues/5511))
- Make the config clearer in that email.template_dir is relative to the Synapse's root directory, not the `synapse/` folder within it. ([\#5543](https://github.com/matrix-org/synapse/issues/5543))
- Update v1.0.0 release changelog to include more information about changes to password resets. ([\#5545](https://github.com/matrix-org/synapse/issues/5545))
- Remove non-functioning check_event_hash.py dev script. ([\#5548](https://github.com/matrix-org/synapse/issues/5548))
- Synapse will now only allow TLS v1.2 connections when serving federation, if it terminates TLS. As Synapse's allowed ciphers were only able to be used in TLSv1.2 before, this does not change behaviour. ([\#5550](https://github.com/matrix-org/synapse/issues/5550))
- Logging when running GC collection on generation 0 is now at the DEBUG level, not INFO. ([\#5557](https://github.com/matrix-org/synapse/issues/5557))
- Reduce the amount of stuff we send in the docker context. ([\#5564](https://github.com/matrix-org/synapse/issues/5564))
- Point the reverse links in the Purge History contrib scripts at the intended location. ([\#5570](https://github.com/matrix-org/synapse/issues/5570))
Synapse 1.0.0 (2019-06-11)
==========================
@@ -156,11 +52,7 @@ Features
- Add a script to generate new signing-key files. ([\#5361](https://github.com/matrix-org/synapse/issues/5361))
- Update upgrade and installation guides ahead of 1.0. ([\#5371](https://github.com/matrix-org/synapse/issues/5371))
- Replace the `perspectives` configuration section with `trusted_key_servers`, and make validating the signatures on responses optional (since TLS will do this job for us). ([\#5374](https://github.com/matrix-org/synapse/issues/5374))
- Add ability to perform password reset via email without trusting the identity server. **As a result of this PR, password resets will now be disabled on the default configuration.**
Password reset emails are now sent from the homeserver by default, instead of the identity server. To enable this functionality, ensure `email` and `public_baseurl` config options are filled out.
If you would like to re-enable password resets being sent from the identity server (warning: this is dangerous! See [#5345](https://github.com/matrix-org/synapse/pull/5345)), set `email.trust_identity_server_for_password_resets` to true. ([\#5377](https://github.com/matrix-org/synapse/issues/5377))
- Add ability to perform password reset via email without trusting the identity server. ([\#5377](https://github.com/matrix-org/synapse/issues/5377))
- Set default room version to v4. ([\#5379](https://github.com/matrix-org/synapse/issues/5379))

View File

@@ -30,20 +30,21 @@ use github's pull request workflow to review the contribution, and either ask
you to make any refinements needed or merge it and make them ourselves. The
changes will then land on master when we next do a release.
We use `CircleCI <https://circleci.com/gh/matrix-org>`_ and `Buildkite
<https://buildkite.com/matrix-dot-org/synapse>`_ for continuous integration.
Buildkite builds need to be authorised by a maintainer. If your change breaks
the build, this will be shown in GitHub, so please keep an eye on the pull
request for feedback.
We use `CircleCI <https://circleci.com/gh/matrix-org>`_ and `Travis CI
<https://travis-ci.org/matrix-org/synapse>`_ for continuous integration. All
pull requests to synapse get automatically tested by Travis and CircleCI.
If your change breaks the build, this will be shown in GitHub, so please
keep an eye on the pull request for feedback.
To run unit tests in a local development environment, you can use:
- ``tox -e py35`` (requires tox to be installed by ``pip install tox``)
for SQLite-backed Synapse on Python 3.5.
- ``tox -e py27`` (requires tox to be installed by ``pip install tox``) for
SQLite-backed Synapse on Python 2.7.
- ``tox -e py35`` for SQLite-backed Synapse on Python 3.5.
- ``tox -e py36`` for SQLite-backed Synapse on Python 3.6.
- ``tox -e py36-postgres`` for PostgreSQL-backed Synapse on Python 3.6
- ``tox -e py27-postgres`` for PostgreSQL-backed Synapse on Python 2.7
(requires a running local PostgreSQL with access to create databases).
- ``./test_postgresql.sh`` for PostgreSQL-backed Synapse on Python 3.5
- ``./test_postgresql.sh`` for PostgreSQL-backed Synapse on Python 2.7
(requires Docker). Entirely self-contained, recommended if you don't want to
set up PostgreSQL yourself.

View File

@@ -1,4 +1,3 @@
- [Choosing your server name](#choosing-your-server-name)
- [Installing Synapse](#installing-synapse)
- [Installing from source](#installing-from-source)
- [Platform-Specific Instructions](#platform-specific-instructions)
@@ -11,22 +10,6 @@
- [Setting up a TURN server](#setting-up-a-turn-server)
- [URL previews](#url-previews)
# Choosing your server name
It is important to choose the name for your server before you install Synapse,
because it cannot be changed later.
The server name determines the "domain" part of user-ids for users on your
server: these will all be of the format `@user:my.domain.name`. It also
determines how other matrix servers will reach yours for federation.
For a test configuration, set this to the hostname of your server. For a more
production-ready setup, you will probably want to specify your domain
(`example.com`) rather than a matrix-specific hostname here (in the same way
that your email address is probably `user@example.com` rather than
`user@email.example.com`) - but doing so may require more advanced setup: see
[Setting up Federation](docs/federate.md).
# Installing Synapse
## Installing from source
@@ -81,7 +64,16 @@ python -m synapse.app.homeserver \
--report-stats=[yes|no]
```
... substituting an appropriate value for `--server-name`.
... substituting an appropriate value for `--server-name`. The server name
determines the "domain" part of user-ids for users on your server: these will
all be of the format `@user:my.domain.name`. It also determines how other
matrix servers will reach yours for Federation. For a test configuration,
set this to the hostname of your server. For a more production-ready setup, you
will probably want to specify your domain (`example.com`) rather than a
matrix-specific hostname here (in the same way that your email address is
probably `user@example.com` rather than `user@email.example.com`) - but
doing so may require more advanced setup: see [Setting up Federation](docs/federate.md).
Beware that the server name cannot be changed later.
This command will generate you a config file that you can then customise, but it will
also generate a set of keys for you. These keys will allow your Home Server to
@@ -94,6 +86,9 @@ different. See the
[spec](https://matrix.org/docs/spec/server_server/latest.html#retrieving-server-keys)
for more information on key management.)
You will need to give Synapse a TLS certficate before it will start - see [TLS
certificates](#tls-certificates).
To actually run your new homeserver, pick a working directory for Synapse to
run (e.g. `~/synapse`), and::

View File

@@ -48,3 +48,8 @@ prune .buildkite
exclude jenkins*
recursive-exclude jenkins *.sh
# FIXME: we shouldn't have these templates here
recursive-include res/templates-dinsic *.css
recursive-include res/templates-dinsic *.html
recursive-include res/templates-dinsic *.txt

View File

@@ -340,11 +340,8 @@ log lines and looking for any 'Processed request' lines which take more than
a few seconds to execute. Please let us know at #synapse:matrix.org if
you see this failure mode so we can help debug it, however.
Help!! Synapse is slow and eats all my RAM/CPU!
-----------------------------------------------
First, ensure you are running the latest version of Synapse, using Python 3
with a PostgreSQL database.
Help!! Synapse eats all my RAM!
-------------------------------
Synapse's architecture is quite RAM hungry currently - we deliberately
cache a lot of recent room data and metadata in RAM in order to speed up
@@ -355,29 +352,14 @@ variable. The default is 0.5, which can be decreased to reduce RAM usage
in memory constrained enviroments, or increased if performance starts to
degrade.
However, degraded performance due to a low cache factor, common on
machines with slow disks, often leads to explosions in memory use due
backlogged requests. In this case, reducing the cache factor will make
things worse. Instead, try increasing it drastically. 2.0 is a good
starting value.
Using `libjemalloc <http://jemalloc.net/>`_ can also yield a significant
improvement in overall memory use, and especially in terms of giving back
RAM to the OS. To use it, the library must simply be put in the
LD_PRELOAD environment variable when launching Synapse. On Debian, this
can be done by installing the ``libjemalloc1`` package and adding this
line to ``/etc/default/matrix-synapse``::
improvement in overall amount, and especially in terms of giving back RAM
to the OS. To use it, the library must simply be put in the LD_PRELOAD
environment variable when launching Synapse. On Debian, this can be done
by installing the ``libjemalloc1`` package and adding this line to
``/etc/default/matrix-synapse``::
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
This can make a significant difference on Python 2.7 - it's unclear how
much of an improvement it provides on Python 3.x.
If you're encountering high CPU use by the Synapse process itself, you
may be affected by a bug with presence tracking that leads to a
massive excess of outgoing federation requests (see `discussion
<https://github.com/matrix-org/synapse/issues/3971>`_). If metrics
indicate that your server is also issuing far more outgoing federation
requests than can be accounted for by your users' activity, this is a
likely cause. The misbehavior can be worked around by setting
``use_presence: false`` in the Synapse config file.

View File

@@ -49,33 +49,6 @@ returned by the Client-Server API:
# configured on port 443.
curl -kv https://<host.name>/_matrix/client/versions 2>&1 | grep "Server:"
Upgrading to v1.1.0
===================
Synapse v1.1.0 removes support for older Python and PostgreSQL versions, as
outlined in `our deprecation notice <https://matrix.org/blog/2019/04/08/synapse-deprecating-postgres-9-4-and-python-2-x>`_.
Minimum Python Version
----------------------
Synapse v1.1.0 has a minimum Python requirement of Python 3.5. Python 3.6 or
Python 3.7 are recommended as they have improved internal string handling,
significantly reducing memory usage.
If you use current versions of the Matrix.org-distributed Debian packages or
Docker images, action is not required.
If you install Synapse in a Python virtual environment, please see "Upgrading to
v0.34.0" for notes on setting up a new virtualenv under Python 3.
Minimum PostgreSQL Version
--------------------------
If using PostgreSQL under Synapse, you will need to use PostgreSQL 9.5 or above.
Please see the
`PostgreSQL documentation <https://www.postgresql.org/docs/11/upgrading.html>`_
for more details on upgrading your database.
Upgrading to v1.0
=================
@@ -98,11 +71,11 @@ server in a closed federation. This can be done in one of two ways:-
* Configure a whitelist of server domains to trust via ``federation_certificate_verification_whitelist``.
See the `sample configuration file <docs/sample_config.yaml>`_
for more details on these settings.
for more details on these settings.
Email
-----
When a user requests a password reset, Synapse will send an email to the
When a user requests a password reset, Synapse will send an email to the
user to confirm the request.
Previous versions of Synapse delegated the job of sending this email to an

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

@@ -1 +0,0 @@
Update github templates.

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

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

View File

@@ -1 +0,0 @@
Removed the `SYNAPSE_SMTP_*` docker container environment variables. Using these environment variables prevented the docker container from starting in Synapse v1.0, even though they didn't actually allow any functionality anyway. Users are advised to remove `SYNAPSE_SMTP_HOST`, `SYNAPSE_SMTP_PORT`, `SYNAPSE_SMTP_USER`, `SYNAPSE_SMTP_PASSWORD` and `SYNAPSE_SMTP_FROM` environment variables from their docker run commands.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

@@ -15,7 +15,6 @@
# limitations under the License.
""" Starts a synapse client console. """
from __future__ import print_function
from twisted.internet import reactor, defer, threads
from http import TwistedHttpClient
@@ -37,8 +36,9 @@ from signedjson.sign import verify_signed_json, SignatureVerifyException
CONFIG_JSON = "cmdclient_config.json"
TRUSTED_ID_SERVERS = ["localhost:8001"]
TRUSTED_ID_SERVERS = [
'localhost:8001'
]
class SynapseCmd(cmd.Cmd):
@@ -58,7 +58,7 @@ class SynapseCmd(cmd.Cmd):
"token": token,
"verbose": "on",
"complete_usernames": "on",
"send_delivery_receipts": "on",
"send_delivery_receipts": "on"
}
self.path_prefix = "/_matrix/client/api/v1"
self.event_stream_token = "END"
@@ -109,7 +109,7 @@ class SynapseCmd(cmd.Cmd):
by using $. E.g. 'config roomid room1' then 'raw get /rooms/$roomid'.
"""
if len(line) == 0:
print(json.dumps(self.config, indent=4))
print json.dumps(self.config, indent=4)
return
try:
@@ -119,11 +119,12 @@ class SynapseCmd(cmd.Cmd):
config_rules = [ # key, valid_values
("verbose", ["on", "off"]),
("complete_usernames", ["on", "off"]),
("send_delivery_receipts", ["on", "off"]),
("send_delivery_receipts", ["on", "off"])
]
for key, valid_vals in config_rules:
if key == args["key"] and args["val"] not in valid_vals:
print("%s value must be one of %s" % (args["key"], valid_vals))
print "%s value must be one of %s" % (args["key"],
valid_vals)
return
# toggle the http client verbosity
@@ -132,11 +133,11 @@ class SynapseCmd(cmd.Cmd):
# assign the new config
self.config[args["key"]] = args["val"]
print(json.dumps(self.config, indent=4))
print json.dumps(self.config, indent=4)
save_config(self.config)
except Exception as e:
print(e)
print e
def do_register(self, line):
"""Registers for a new account: "register <userid> <noupdate>"
@@ -152,32 +153,33 @@ class SynapseCmd(cmd.Cmd):
pwd = getpass.getpass("Type a password for this user: ")
pwd2 = getpass.getpass("Retype the password: ")
if pwd != pwd2 or len(pwd) == 0:
print("Password mismatch.")
print "Password mismatch."
pwd = None
else:
password = pwd
body = {"type": "m.login.password"}
body = {
"type": "m.login.password"
}
if "userid" in args:
body["user"] = args["userid"]
if password:
body["password"] = password
reactor.callFromThread(self._do_register, body, "noupdate" not in args)
reactor.callFromThread(self._do_register, body,
"noupdate" not in args)
@defer.inlineCallbacks
def _do_register(self, data, update_config):
# check the registration flows
url = self._url() + "/register"
json_res = yield self.http_client.do_request("GET", url)
print(json.dumps(json_res, indent=4))
print json.dumps(json_res, indent=4)
passwordFlow = None
for flow in json_res["flows"]:
if flow["type"] == "m.login.recaptcha" or (
"stages" in flow and "m.login.recaptcha" in flow["stages"]
):
print("Unable to register: Home server requires captcha.")
if flow["type"] == "m.login.recaptcha" or ("stages" in flow and "m.login.recaptcha" in flow["stages"]):
print "Unable to register: Home server requires captcha."
return
if flow["type"] == "m.login.password" and "stages" not in flow:
passwordFlow = flow
@@ -187,7 +189,7 @@ class SynapseCmd(cmd.Cmd):
return
json_res = yield self.http_client.do_request("POST", url, data=data)
print(json.dumps(json_res, indent=4))
print json.dumps(json_res, indent=4)
if update_config and "user_id" in json_res:
self.config["user"] = json_res["user_id"]
self.config["token"] = json_res["access_token"]
@@ -199,7 +201,9 @@ class SynapseCmd(cmd.Cmd):
"""
try:
args = self._parse(line, ["user_id"], force_keys=True)
can_login = threads.blockingCallFromThread(reactor, self._check_can_login)
can_login = threads.blockingCallFromThread(
reactor,
self._check_can_login)
if can_login:
p = getpass.getpass("Enter your password: ")
user = args["user_id"]
@@ -207,25 +211,29 @@ class SynapseCmd(cmd.Cmd):
domain = self._domain()
if domain:
user = "@" + user + ":" + domain
reactor.callFromThread(self._do_login, user, p)
# print " got %s " % p
#print " got %s " % p
except Exception as e:
print(e)
print e
@defer.inlineCallbacks
def _do_login(self, user, password):
path = "/login"
data = {"user": user, "password": password, "type": "m.login.password"}
data = {
"user": user,
"password": password,
"type": "m.login.password"
}
url = self._url() + path
json_res = yield self.http_client.do_request("POST", url, data=data)
print(json_res)
print json_res
if "access_token" in json_res:
self.config["user"] = user
self.config["token"] = json_res["access_token"]
save_config(self.config)
print("Login successful.")
print "Login successful."
@defer.inlineCallbacks
def _check_can_login(self):
@@ -234,19 +242,18 @@ class SynapseCmd(cmd.Cmd):
# submitting!
url = self._url() + path
json_res = yield self.http_client.do_request("GET", url)
print(json_res)
print json_res
if "flows" not in json_res:
print("Failed to find any login flows.")
print "Failed to find any login flows."
defer.returnValue(False)
flow = json_res["flows"][0] # assume first is the one we want.
if "type" not in flow or "m.login.password" != flow["type"] or "stages" in flow:
flow = json_res["flows"][0] # assume first is the one we want.
if ("type" not in flow or "m.login.password" != flow["type"] or
"stages" in flow):
fallback_url = self._url() + "/login/fallback"
print(
"Unable to login via the command line client. Please visit "
"%s to login." % fallback_url
)
print ("Unable to login via the command line client. Please visit "
"%s to login." % fallback_url)
defer.returnValue(False)
defer.returnValue(True)
@@ -256,33 +263,21 @@ class SynapseCmd(cmd.Cmd):
<clientSecret> A string of characters generated when requesting an email that you'll supply in subsequent calls to identify yourself
<sendAttempt> The number of times the user has requested an email. Leave this the same between requests to retry the request at the transport level. Increment it to request that the email be sent again.
"""
args = self._parse(line, ["address", "clientSecret", "sendAttempt"])
args = self._parse(line, ['address', 'clientSecret', 'sendAttempt'])
postArgs = {
"email": args["address"],
"clientSecret": args["clientSecret"],
"sendAttempt": args["sendAttempt"],
}
postArgs = {'email': args['address'], 'clientSecret': args['clientSecret'], 'sendAttempt': args['sendAttempt']}
reactor.callFromThread(self._do_emailrequest, postArgs)
@defer.inlineCallbacks
def _do_emailrequest(self, args):
url = (
self._identityServerUrl()
+ "/_matrix/identity/api/v1/validate/email/requestToken"
)
url = self._identityServerUrl()+"/_matrix/identity/api/v1/validate/email/requestToken"
json_res = yield self.http_client.do_request(
"POST",
url,
data=urllib.urlencode(args),
jsonreq=False,
headers={"Content-Type": ["application/x-www-form-urlencoded"]},
)
print(json_res)
if "sid" in json_res:
print("Token sent. Your session ID is %s" % (json_res["sid"]))
json_res = yield self.http_client.do_request("POST", url, data=urllib.urlencode(args), jsonreq=False,
headers={'Content-Type': ['application/x-www-form-urlencoded']})
print json_res
if 'sid' in json_res:
print "Token sent. Your session ID is %s" % (json_res['sid'])
def do_emailvalidate(self, line):
"""Validate and associate a third party ID
@@ -290,56 +285,39 @@ class SynapseCmd(cmd.Cmd):
<token> The token sent to your third party identifier address
<clientSecret> The same clientSecret you supplied in requestToken
"""
args = self._parse(line, ["sid", "token", "clientSecret"])
args = self._parse(line, ['sid', 'token', 'clientSecret'])
postArgs = {
"sid": args["sid"],
"token": args["token"],
"clientSecret": args["clientSecret"],
}
postArgs = { 'sid' : args['sid'], 'token' : args['token'], 'clientSecret': args['clientSecret'] }
reactor.callFromThread(self._do_emailvalidate, postArgs)
@defer.inlineCallbacks
def _do_emailvalidate(self, args):
url = (
self._identityServerUrl()
+ "/_matrix/identity/api/v1/validate/email/submitToken"
)
url = self._identityServerUrl()+"/_matrix/identity/api/v1/validate/email/submitToken"
json_res = yield self.http_client.do_request(
"POST",
url,
data=urllib.urlencode(args),
jsonreq=False,
headers={"Content-Type": ["application/x-www-form-urlencoded"]},
)
print(json_res)
json_res = yield self.http_client.do_request("POST", url, data=urllib.urlencode(args), jsonreq=False,
headers={'Content-Type': ['application/x-www-form-urlencoded']})
print json_res
def do_3pidbind(self, line):
"""Validate and associate a third party ID
<sid> The session ID (sid) given to you in the response to requestToken
<clientSecret> The same clientSecret you supplied in requestToken
"""
args = self._parse(line, ["sid", "clientSecret"])
args = self._parse(line, ['sid', 'clientSecret'])
postArgs = {"sid": args["sid"], "clientSecret": args["clientSecret"]}
postArgs["mxid"] = self.config["user"]
postArgs = { 'sid' : args['sid'], 'clientSecret': args['clientSecret'] }
postArgs['mxid'] = self.config["user"]
reactor.callFromThread(self._do_3pidbind, postArgs)
@defer.inlineCallbacks
def _do_3pidbind(self, args):
url = self._identityServerUrl() + "/_matrix/identity/api/v1/3pid/bind"
url = self._identityServerUrl()+"/_matrix/identity/api/v1/3pid/bind"
json_res = yield self.http_client.do_request(
"POST",
url,
data=urllib.urlencode(args),
jsonreq=False,
headers={"Content-Type": ["application/x-www-form-urlencoded"]},
)
print(json_res)
json_res = yield self.http_client.do_request("POST", url, data=urllib.urlencode(args), jsonreq=False,
headers={'Content-Type': ['application/x-www-form-urlencoded']})
print json_res
def do_join(self, line):
"""Joins a room: "join <roomid>" """
@@ -347,7 +325,7 @@ class SynapseCmd(cmd.Cmd):
args = self._parse(line, ["roomid"], force_keys=True)
self._do_membership_change(args["roomid"], "join", self._usr())
except Exception as e:
print(e)
print e
def do_joinalias(self, line):
try:
@@ -355,7 +333,7 @@ class SynapseCmd(cmd.Cmd):
path = "/join/%s" % urllib.quote(args["roomname"])
reactor.callFromThread(self._run_and_pprint, "POST", path, {})
except Exception as e:
print(e)
print e
def do_topic(self, line):
""""topic [set|get] <roomid> [<newtopic>]"
@@ -365,24 +343,26 @@ class SynapseCmd(cmd.Cmd):
try:
args = self._parse(line, ["action", "roomid", "topic"])
if "action" not in args or "roomid" not in args:
print("Must specify set|get and a room ID.")
print "Must specify set|get and a room ID."
return
if args["action"].lower() not in ["set", "get"]:
print("Must specify set|get, not %s" % args["action"])
print "Must specify set|get, not %s" % args["action"]
return
path = "/rooms/%s/topic" % urllib.quote(args["roomid"])
if args["action"].lower() == "set":
if "topic" not in args:
print("Must specify a new topic.")
print "Must specify a new topic."
return
body = {"topic": args["topic"]}
body = {
"topic": args["topic"]
}
reactor.callFromThread(self._run_and_pprint, "PUT", path, body)
elif args["action"].lower() == "get":
reactor.callFromThread(self._run_and_pprint, "GET", path)
except Exception as e:
print(e)
print e
def do_invite(self, line):
"""Invite a user to a room: "invite <userid> <roomid>" """
@@ -393,64 +373,49 @@ class SynapseCmd(cmd.Cmd):
reactor.callFromThread(self._do_invite, args["roomid"], user_id)
except Exception as e:
print(e)
print e
@defer.inlineCallbacks
def _do_invite(self, roomid, userstring):
if not userstring.startswith("@") and self._is_on("complete_usernames"):
url = self._identityServerUrl() + "/_matrix/identity/api/v1/lookup"
if (not userstring.startswith('@') and
self._is_on("complete_usernames")):
url = self._identityServerUrl()+"/_matrix/identity/api/v1/lookup"
json_res = yield self.http_client.do_request(
"GET", url, qparams={"medium": "email", "address": userstring}
)
json_res = yield self.http_client.do_request("GET", url, qparams={'medium':'email','address':userstring})
mxid = None
if "mxid" in json_res and "signatures" in json_res:
url = (
self._identityServerUrl()
+ "/_matrix/identity/api/v1/pubkey/ed25519"
)
if 'mxid' in json_res and 'signatures' in json_res:
url = self._identityServerUrl()+"/_matrix/identity/api/v1/pubkey/ed25519"
pubKey = None
pubKeyObj = yield self.http_client.do_request("GET", url)
if "public_key" in pubKeyObj:
pubKey = nacl.signing.VerifyKey(
pubKeyObj["public_key"], encoder=nacl.encoding.HexEncoder
)
if 'public_key' in pubKeyObj:
pubKey = nacl.signing.VerifyKey(pubKeyObj['public_key'], encoder=nacl.encoding.HexEncoder)
else:
print("No public key found in pubkey response!")
print "No public key found in pubkey response!"
sigValid = False
if pubKey:
for signame in json_res["signatures"]:
for signame in json_res['signatures']:
if signame not in TRUSTED_ID_SERVERS:
print(
"Ignoring signature from untrusted server %s"
% (signame)
)
print "Ignoring signature from untrusted server %s" % (signame)
else:
try:
verify_signed_json(json_res, signame, pubKey)
sigValid = True
print(
"Mapping %s -> %s correctly signed by %s"
% (userstring, json_res["mxid"], signame)
)
print "Mapping %s -> %s correctly signed by %s" % (userstring, json_res['mxid'], signame)
break
except SignatureVerifyException as e:
print("Invalid signature from %s" % (signame))
print(e)
print "Invalid signature from %s" % (signame)
print e
if sigValid:
print("Resolved 3pid %s to %s" % (userstring, json_res["mxid"]))
mxid = json_res["mxid"]
print "Resolved 3pid %s to %s" % (userstring, json_res['mxid'])
mxid = json_res['mxid']
else:
print(
"Got association for %s but couldn't verify signature"
% (userstring)
)
print "Got association for %s but couldn't verify signature" % (userstring)
if not mxid:
mxid = "@" + userstring + ":" + self._domain()
@@ -463,17 +428,18 @@ class SynapseCmd(cmd.Cmd):
args = self._parse(line, ["roomid"], force_keys=True)
self._do_membership_change(args["roomid"], "leave", self._usr())
except Exception as e:
print(e)
print e
def do_send(self, line):
"""Sends a message. "send <roomid> <body>" """
args = self._parse(line, ["roomid", "body"])
txn_id = "txn%s" % int(time.time())
path = "/rooms/%s/send/m.room.message/%s" % (
urllib.quote(args["roomid"]),
txn_id,
)
body_json = {"msgtype": "m.text", "body": args["body"]}
path = "/rooms/%s/send/m.room.message/%s" % (urllib.quote(args["roomid"]),
txn_id)
body_json = {
"msgtype": "m.text",
"body": args["body"]
}
reactor.callFromThread(self._run_and_pprint, "PUT", path, body_json)
def do_list(self, line):
@@ -487,10 +453,10 @@ class SynapseCmd(cmd.Cmd):
"""
args = self._parse(line, ["type", "roomid", "qp"])
if not "type" in args or not "roomid" in args:
print("Must specify type and room ID.")
print "Must specify type and room ID."
return
if args["type"] not in ["members", "messages"]:
print("Unrecognised type: %s" % args["type"])
print "Unrecognised type: %s" % args["type"]
return
room_id = args["roomid"]
path = "/rooms/%s/%s" % (urllib.quote(room_id), args["type"])
@@ -502,10 +468,11 @@ class SynapseCmd(cmd.Cmd):
key_value = key_value_str.split("=")
qp[key_value[0]] = key_value[1]
except:
print("Bad query param: %s" % key_value)
print "Bad query param: %s" % key_value
return
reactor.callFromThread(self._run_and_pprint, "GET", path, query_params=qp)
reactor.callFromThread(self._run_and_pprint, "GET", path,
query_params=qp)
def do_create(self, line):
"""Creates a room.
@@ -541,22 +508,14 @@ class SynapseCmd(cmd.Cmd):
args = self._parse(line, ["method", "path", "data"])
# sanity check
if "method" not in args or "path" not in args:
print("Must specify path and method.")
print "Must specify path and method."
return
args["method"] = args["method"].upper()
valid_methods = [
"PUT",
"GET",
"POST",
"DELETE",
"XPUT",
"XGET",
"XPOST",
"XDELETE",
]
valid_methods = ["PUT", "GET", "POST", "DELETE",
"XPUT", "XGET", "XPOST", "XDELETE"]
if args["method"] not in valid_methods:
print("Unsupported method: %s" % args["method"])
print "Unsupported method: %s" % args["method"]
return
if "data" not in args:
@@ -565,7 +524,7 @@ class SynapseCmd(cmd.Cmd):
try:
args["data"] = json.loads(args["data"])
except Exception as e:
print("Data is not valid JSON. %s" % e)
print "Data is not valid JSON. %s" % e
return
qp = {"access_token": self._tok()}
@@ -581,13 +540,10 @@ class SynapseCmd(cmd.Cmd):
except:
pass
reactor.callFromThread(
self._run_and_pprint,
args["method"],
args["path"],
args["data"],
query_params=qp,
)
reactor.callFromThread(self._run_and_pprint, args["method"],
args["path"],
args["data"],
query_params=qp)
def do_stream(self, line):
"""Stream data from the server: "stream <longpoll timeout ms>" """
@@ -597,29 +553,26 @@ class SynapseCmd(cmd.Cmd):
try:
timeout = int(args["timeout"])
except ValueError:
print("Timeout must be in milliseconds.")
print "Timeout must be in milliseconds."
return
reactor.callFromThread(self._do_event_stream, timeout)
@defer.inlineCallbacks
def _do_event_stream(self, timeout):
res = yield self.http_client.get_json(
self._url() + "/events",
{
"access_token": self._tok(),
"timeout": str(timeout),
"from": self.event_stream_token,
},
)
print(json.dumps(res, indent=4))
self._url() + "/events",
{
"access_token": self._tok(),
"timeout": str(timeout),
"from": self.event_stream_token
})
print json.dumps(res, indent=4)
if "chunk" in res:
for event in res["chunk"]:
if (
event["type"] == "m.room.message"
and self._is_on("send_delivery_receipts")
and event["user_id"] != self._usr()
): # not sent by us
if (event["type"] == "m.room.message" and
self._is_on("send_delivery_receipts") and
event["user_id"] != self._usr()): # not sent by us
self._send_receipt(event, "d")
# update the position in the stram
@@ -627,28 +580,18 @@ class SynapseCmd(cmd.Cmd):
self.event_stream_token = res["end"]
def _send_receipt(self, event, feedback_type):
path = "/rooms/%s/messages/%s/%s/feedback/%s/%s" % (
urllib.quote(event["room_id"]),
event["user_id"],
event["msg_id"],
self._usr(),
feedback_type,
)
path = ("/rooms/%s/messages/%s/%s/feedback/%s/%s" %
(urllib.quote(event["room_id"]), event["user_id"], event["msg_id"],
self._usr(), feedback_type))
data = {}
reactor.callFromThread(
self._run_and_pprint,
"PUT",
path,
data=data,
alt_text="Sent receipt for %s" % event["msg_id"],
)
reactor.callFromThread(self._run_and_pprint, "PUT", path, data=data,
alt_text="Sent receipt for %s" % event["msg_id"])
def _do_membership_change(self, roomid, membership, userid):
path = "/rooms/%s/state/m.room.member/%s" % (
urllib.quote(roomid),
urllib.quote(userid),
)
data = {"membership": membership}
path = "/rooms/%s/state/m.room.member/%s" % (urllib.quote(roomid), urllib.quote(userid))
data = {
"membership": membership
}
reactor.callFromThread(self._run_and_pprint, "PUT", path, data=data)
def do_displayname(self, line):
@@ -701,20 +644,15 @@ class SynapseCmd(cmd.Cmd):
for i, arg in enumerate(line_args):
for config_key in self.config:
if ("$" + config_key) in arg:
arg = arg.replace("$" + config_key, self.config[config_key])
arg = arg.replace("$" + config_key,
self.config[config_key])
line_args[i] = arg
return dict(zip(keys, line_args))
@defer.inlineCallbacks
def _run_and_pprint(
self,
method,
path,
data=None,
query_params={"access_token": None},
alt_text=None,
):
def _run_and_pprint(self, method, path, data=None,
query_params={"access_token": None}, alt_text=None):
""" Runs an HTTP request and pretty prints the output.
Args:
@@ -727,31 +665,31 @@ class SynapseCmd(cmd.Cmd):
if "access_token" in query_params:
query_params["access_token"] = self._tok()
json_res = yield self.http_client.do_request(
method, url, data=data, qparams=query_params
)
json_res = yield self.http_client.do_request(method, url,
data=data,
qparams=query_params)
if alt_text:
print(alt_text)
print alt_text
else:
print(json.dumps(json_res, indent=4))
print json.dumps(json_res, indent=4)
def save_config(config):
with open(CONFIG_JSON, "w") as out:
with open(CONFIG_JSON, 'w') as out:
json.dump(config, out)
def main(server_url, identity_server_url, username, token, config_path):
print("Synapse command line client")
print("===========================")
print("Server: %s" % server_url)
print("Type 'help' to get started.")
print("Close this console with CTRL+C then CTRL+D.")
print "Synapse command line client"
print "==========================="
print "Server: %s" % server_url
print "Type 'help' to get started."
print "Close this console with CTRL+C then CTRL+D."
if not username or not token:
print("- 'register <username>' - Register an account")
print("- 'stream' - Connect to the event stream")
print("- 'create <roomid>' - Create a room")
print("- 'send <roomid> <message>' - Send a message")
print "- 'register <username>' - Register an account"
print "- 'stream' - Connect to the event stream"
print "- 'create <roomid>' - Create a room"
print "- 'send <roomid> <message>' - Send a message"
http_client = TwistedHttpClient()
# the command line client
@@ -761,13 +699,13 @@ def main(server_url, identity_server_url, username, token, config_path):
global CONFIG_JSON
CONFIG_JSON = config_path # bit cheeky, but just overwrite the global
try:
with open(config_path, "r") as config:
with open(config_path, 'r') as config:
syn_cmd.config = json.load(config)
try:
http_client.verbose = "on" == syn_cmd.config["verbose"]
except:
pass
print("Loaded config from %s" % config_path)
print "Loaded config from %s" % config_path
except:
pass
@@ -778,37 +716,27 @@ def main(server_url, identity_server_url, username, token, config_path):
reactor.run()
if __name__ == "__main__":
if __name__ == '__main__':
parser = argparse.ArgumentParser("Starts a synapse client.")
parser.add_argument(
"-s",
"--server",
dest="server",
default="http://localhost:8008",
help="The URL of the home server to talk to.",
)
"-s", "--server", dest="server", default="http://localhost:8008",
help="The URL of the home server to talk to.")
parser.add_argument(
"-i",
"--identity-server",
dest="identityserver",
default="http://localhost:8090",
help="The URL of the identity server to talk to.",
)
"-i", "--identity-server", dest="identityserver", default="http://localhost:8090",
help="The URL of the identity server to talk to.")
parser.add_argument(
"-u", "--username", dest="username", help="Your username on the server."
)
parser.add_argument("-t", "--token", dest="token", help="Your access token.")
"-u", "--username", dest="username",
help="Your username on the server.")
parser.add_argument(
"-c",
"--config",
dest="config",
default=CONFIG_JSON,
help="The location of the config.json file to read from.",
)
"-t", "--token", dest="token",
help="Your access token.")
parser.add_argument(
"-c", "--config", dest="config", default=CONFIG_JSON,
help="The location of the config.json file to read from.")
args = parser.parse_args()
if not args.server:
print("You must supply a server URL to communicate with.")
print "You must supply a server URL to communicate with."
parser.print_help()
sys.exit(1)

View File

@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
from twisted.web.client import Agent, readBody
from twisted.web.http_headers import Headers
from twisted.internet import defer, reactor
@@ -73,7 +72,9 @@ class TwistedHttpClient(HttpClient):
@defer.inlineCallbacks
def put_json(self, url, data):
response = yield self._create_put_request(
url, data, headers_dict={"Content-Type": ["application/json"]}
url,
data,
headers_dict={"Content-Type": ["application/json"]}
)
body = yield readBody(response)
defer.returnValue((response.code, body))
@@ -93,34 +94,40 @@ class TwistedHttpClient(HttpClient):
"""
if "Content-Type" not in headers_dict:
raise defer.error(RuntimeError("Must include Content-Type header for PUTs"))
raise defer.error(
RuntimeError("Must include Content-Type header for PUTs"))
return self._create_request(
"PUT", url, producer=_JsonProducer(json_data), headers_dict=headers_dict
"PUT",
url,
producer=_JsonProducer(json_data),
headers_dict=headers_dict
)
def _create_get_request(self, url, headers_dict={}):
""" Wrapper of _create_request to issue a GET request
"""
return self._create_request("GET", url, headers_dict=headers_dict)
return self._create_request(
"GET",
url,
headers_dict=headers_dict
)
@defer.inlineCallbacks
def do_request(
self, method, url, data=None, qparams=None, jsonreq=True, headers={}
):
def do_request(self, method, url, data=None, qparams=None, jsonreq=True, headers={}):
if qparams:
url = "%s?%s" % (url, urllib.urlencode(qparams, True))
if jsonreq:
prod = _JsonProducer(data)
headers["Content-Type"] = ["application/json"]
headers['Content-Type'] = ["application/json"];
else:
prod = _RawProducer(data)
if method in ["POST", "PUT"]:
response = yield self._create_request(
method, url, producer=prod, headers_dict=headers
)
response = yield self._create_request(method, url,
producer=prod,
headers_dict=headers)
else:
response = yield self._create_request(method, url)
@@ -134,24 +141,27 @@ class TwistedHttpClient(HttpClient):
headers_dict["User-Agent"] = ["Synapse Cmd Client"]
retries_left = 5
print("%s to %s with headers %s" % (method, url, headers_dict))
print "%s to %s with headers %s" % (method, url, headers_dict)
if self.verbose and producer:
if "password" in producer.data:
temp = producer.data["password"]
producer.data["password"] = "[REDACTED]"
print(json.dumps(producer.data, indent=4))
print json.dumps(producer.data, indent=4)
producer.data["password"] = temp
else:
print(json.dumps(producer.data, indent=4))
print json.dumps(producer.data, indent=4)
while True:
try:
response = yield self.agent.request(
method, url.encode("UTF8"), Headers(headers_dict), producer
method,
url.encode("UTF8"),
Headers(headers_dict),
producer
)
break
except Exception as e:
print("uh oh: %s" % e)
print "uh oh: %s" % e
if retries_left:
yield self.sleep(2 ** (5 - retries_left))
retries_left -= 1
@@ -159,8 +169,8 @@ class TwistedHttpClient(HttpClient):
raise e
if self.verbose:
print("Status %s %s" % (response.code, response.phrase))
print(pformat(list(response.headers.getAllRawHeaders())))
print "Status %s %s" % (response.code, response.phrase)
print pformat(list(response.headers.getAllRawHeaders()))
defer.returnValue(response)
def sleep(self, seconds):
@@ -168,7 +178,6 @@ class TwistedHttpClient(HttpClient):
reactor.callLater(seconds, d.callback, seconds)
return d
class _RawProducer(object):
def __init__(self, data):
self.data = data
@@ -185,11 +194,9 @@ class _RawProducer(object):
def stopProducing(self):
pass
class _JsonProducer(object):
""" Used by the twisted http client to create the HTTP body from json
"""
def __init__(self, jsn):
self.data = jsn
self.body = json.dumps(jsn).encode("utf8")

View File

@@ -1,9 +1,5 @@
# Synapse Docker
FIXME: this is out-of-date as of
https://github.com/matrix-org/synapse/issues/5518. Contributions to bring it up
to date would be welcome.
### Automated configuration
It is recommended that you use Docker Compose to run your containers, including

View File

@@ -19,13 +19,13 @@ from curses.ascii import isprint
from twisted.internet import reactor
class CursesStdIO:
class CursesStdIO():
def __init__(self, stdscr, callback=None):
self.statusText = "Synapse test app -"
self.searchText = ""
self.searchText = ''
self.stdscr = stdscr
self.logLine = ""
self.logLine = ''
self.callback = callback
@@ -71,7 +71,8 @@ class CursesStdIO:
i = 0
index = len(self.lines) - 1
while i < (self.rows - 3) and index >= 0:
self.stdscr.addstr(self.rows - 3 - i, 0, self.lines[index], curses.A_NORMAL)
self.stdscr.addstr(self.rows - 3 - i, 0, self.lines[index],
curses.A_NORMAL)
i = i + 1
index = index - 1
@@ -84,13 +85,15 @@ class CursesStdIO:
raise RuntimeError("TextTooLongError")
self.stdscr.addstr(
self.rows - 2, 0, text + " " * (self.cols - len(text)), curses.A_STANDOUT
)
self.rows - 2, 0,
text + ' ' * (self.cols - len(text)),
curses.A_STANDOUT)
def printLogLine(self, text):
self.stdscr.addstr(
0, 0, text + " " * (self.cols - len(text)), curses.A_STANDOUT
)
0, 0,
text + ' ' * (self.cols - len(text)),
curses.A_STANDOUT)
def doRead(self):
""" Input is ready! """
@@ -102,7 +105,7 @@ class CursesStdIO:
elif c == curses.KEY_ENTER or c == 10:
text = self.searchText
self.searchText = ""
self.searchText = ''
self.print_line(">> %s" % text)
@@ -119,13 +122,11 @@ class CursesStdIO:
return
self.searchText = self.searchText + chr(c)
self.stdscr.addstr(
self.rows - 1,
0,
self.searchText + (" " * (self.cols - len(self.searchText) - 2)),
)
self.stdscr.addstr(self.rows - 1, 0,
self.searchText + (' ' * (
self.cols - len(self.searchText) - 2)))
self.paintStatus(self.statusText + " %d" % len(self.searchText))
self.paintStatus(self.statusText + ' %d' % len(self.searchText))
self.stdscr.move(self.rows - 1, len(self.searchText))
self.stdscr.refresh()
@@ -142,6 +143,7 @@ class CursesStdIO:
class Callback(object):
def __init__(self, stdio):
self.stdio = stdio
@@ -150,7 +152,7 @@ class Callback(object):
def main(stdscr):
screen = CursesStdIO(stdscr) # create Screen object
screen = CursesStdIO(stdscr) # create Screen object
callback = Callback(screen)
@@ -162,5 +164,5 @@ def main(stdscr):
screen.close()
if __name__ == "__main__":
if __name__ == '__main__':
curses.wrapper(main)

View File

@@ -28,7 +28,9 @@ Currently assumes the local address is localhost:<port>
"""
from synapse.federation import ReplicationHandler
from synapse.federation import (
ReplicationHandler
)
from synapse.federation.units import Pdu
@@ -36,7 +38,7 @@ from synapse.util import origin_from_ucid
from synapse.app.homeserver import SynapseHomeServer
# from synapse.util.logutils import log_function
#from synapse.util.logutils import log_function
from twisted.internet import reactor, defer
from twisted.python import log
@@ -81,7 +83,7 @@ class InputOutput(object):
room_name, = m.groups()
self.print_line("%s joining %s" % (self.user, room_name))
self.server.join_room(room_name, self.user, self.user)
# self.print_line("OK.")
#self.print_line("OK.")
return
m = re.match("^invite (\S+) (\S+)$", line)
@@ -90,7 +92,7 @@ class InputOutput(object):
room_name, invitee = m.groups()
self.print_line("%s invited to %s" % (invitee, room_name))
self.server.invite_to_room(room_name, self.user, invitee)
# self.print_line("OK.")
#self.print_line("OK.")
return
m = re.match("^send (\S+) (.*)$", line)
@@ -99,7 +101,7 @@ class InputOutput(object):
room_name, body = m.groups()
self.print_line("%s send to %s" % (self.user, room_name))
self.server.send_message(room_name, self.user, body)
# self.print_line("OK.")
#self.print_line("OK.")
return
m = re.match("^backfill (\S+)$", line)
@@ -123,6 +125,7 @@ class InputOutput(object):
class IOLoggerHandler(logging.Handler):
def __init__(self, io):
logging.Handler.__init__(self)
self.io = io
@@ -139,7 +142,6 @@ class Room(object):
""" Used to store (in memory) the current membership state of a room, and
which home servers we should send PDUs associated with the room to.
"""
def __init__(self, room_name):
self.room_name = room_name
self.invited = set()
@@ -173,7 +175,6 @@ class HomeServer(ReplicationHandler):
""" A very basic home server implentation that allows people to join a
room and then invite other people.
"""
def __init__(self, server_name, replication_layer, output):
self.server_name = server_name
self.replication_layer = replication_layer
@@ -196,27 +197,26 @@ class HomeServer(ReplicationHandler):
elif pdu.content["membership"] == "invite":
self._on_invite(pdu.origin, pdu.context, pdu.state_key)
else:
self.output.print_line(
"#%s (unrec) %s = %s"
% (pdu.context, pdu.pdu_type, json.dumps(pdu.content))
self.output.print_line("#%s (unrec) %s = %s" %
(pdu.context, pdu.pdu_type, json.dumps(pdu.content))
)
# def on_state_change(self, pdu):
##self.output.print_line("#%s (state) %s *** %s" %
##(pdu.context, pdu.state_key, pdu.pdu_type)
##)
#def on_state_change(self, pdu):
##self.output.print_line("#%s (state) %s *** %s" %
##(pdu.context, pdu.state_key, pdu.pdu_type)
##)
# if "joinee" in pdu.content:
# self._on_join(pdu.context, pdu.content["joinee"])
# elif "invitee" in pdu.content:
# self._on_invite(pdu.origin, pdu.context, pdu.content["invitee"])
#if "joinee" in pdu.content:
#self._on_join(pdu.context, pdu.content["joinee"])
#elif "invitee" in pdu.content:
#self._on_invite(pdu.origin, pdu.context, pdu.content["invitee"])
def _on_message(self, pdu):
""" We received a message
"""
self.output.print_line(
"#%s %s %s" % (pdu.context, pdu.content["sender"], pdu.content["body"])
)
self.output.print_line("#%s %s %s" %
(pdu.context, pdu.content["sender"], pdu.content["body"])
)
def _on_join(self, context, joinee):
""" Someone has joined a room, either a remote user or a local user
@@ -224,7 +224,9 @@ class HomeServer(ReplicationHandler):
room = self._get_or_create_room(context)
room.add_participant(joinee)
self.output.print_line("#%s %s %s" % (context, joinee, "*** JOINED"))
self.output.print_line("#%s %s %s" %
(context, joinee, "*** JOINED")
)
def _on_invite(self, origin, context, invitee):
""" Someone has been invited
@@ -232,7 +234,9 @@ class HomeServer(ReplicationHandler):
room = self._get_or_create_room(context)
room.add_invited(invitee)
self.output.print_line("#%s %s %s" % (context, invitee, "*** INVITED"))
self.output.print_line("#%s %s %s" %
(context, invitee, "*** INVITED")
)
if not room.have_got_metadata and origin is not self.server_name:
logger.debug("Get room state")
@@ -268,14 +272,14 @@ class HomeServer(ReplicationHandler):
try:
pdu = Pdu.create_new(
context=room_name,
pdu_type="sy.room.member",
is_state=True,
state_key=joinee,
content={"membership": "join"},
origin=self.server_name,
destinations=destinations,
)
context=room_name,
pdu_type="sy.room.member",
is_state=True,
state_key=joinee,
content={"membership": "join"},
origin=self.server_name,
destinations=destinations,
)
yield self.replication_layer.send_pdu(pdu)
except Exception as e:
logger.exception(e)
@@ -314,21 +318,21 @@ class HomeServer(ReplicationHandler):
return self.replication_layer.backfill(dest, room_name, limit)
def _get_room_remote_servers(self, room_name):
return [i for i in self.joined_rooms.setdefault(room_name).servers]
return [i for i in self.joined_rooms.setdefault(room_name,).servers]
def _get_or_create_room(self, room_name):
return self.joined_rooms.setdefault(room_name, Room(room_name))
def get_servers_for_context(self, context):
return defer.succeed(
self.joined_rooms.setdefault(context, Room(context)).servers
)
self.joined_rooms.setdefault(context, Room(context)).servers
)
def main(stdscr):
parser = argparse.ArgumentParser()
parser.add_argument("user", type=str)
parser.add_argument("-v", "--verbose", action="count")
parser.add_argument('user', type=str)
parser.add_argument('-v', '--verbose', action='count')
args = parser.parse_args()
user = args.user
@@ -338,9 +342,8 @@ def main(stdscr):
root_logger = logging.getLogger()
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(lineno)d - " "%(levelname)s - %(message)s"
)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(lineno)d - '
'%(levelname)s - %(message)s')
if not os.path.exists("logs"):
os.makedirs("logs")
fh = logging.FileHandler("logs/%s" % user)

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,3 @@
from __future__ import print_function
# Copyright 2014-2016 OpenMarket Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -50,7 +48,7 @@ def make_graph(pdus, room, filename_prefix):
c = colors.pop()
color_map[o] = c
except:
print("Run out of colours!")
print "Run out of colours!"
color_map[o] = "black"
graph = pydot.Dot(graph_name="Test")
@@ -59,9 +57,9 @@ def make_graph(pdus, room, filename_prefix):
name = make_name(pdu.get("pdu_id"), pdu.get("origin"))
pdu_map[name] = pdu
t = datetime.datetime.fromtimestamp(float(pdu["ts"]) / 1000).strftime(
"%Y-%m-%d %H:%M:%S,%f"
)
t = datetime.datetime.fromtimestamp(
float(pdu["ts"]) / 1000
).strftime('%Y-%m-%d %H:%M:%S,%f')
label = (
"<"
@@ -81,7 +79,11 @@ def make_graph(pdus, room, filename_prefix):
"depth": pdu.get("depth"),
}
node = pydot.Node(name=name, label=label, color=color_map[pdu.get("origin")])
node = pydot.Node(
name=name,
label=label,
color=color_map[pdu.get("origin")]
)
node_map[name] = node
graph.add_node(node)
@@ -91,7 +93,7 @@ def make_graph(pdus, room, filename_prefix):
end_name = make_name(i, o)
if end_name not in node_map:
print("%s not in nodes" % end_name)
print "%s not in nodes" % end_name
continue
edge = pydot.Edge(node_map[start_name], node_map[end_name])
@@ -105,13 +107,14 @@ def make_graph(pdus, room, filename_prefix):
if prev_state_name in node_map:
state_edge = pydot.Edge(
node_map[start_name], node_map[prev_state_name], style="dotted"
node_map[start_name], node_map[prev_state_name],
style='dotted'
)
graph.add_edge(state_edge)
graph.write("%s.dot" % filename_prefix, format="raw", prog="dot")
# graph.write_png("%s.png" % filename_prefix, prog='dot')
graph.write_svg("%s.svg" % filename_prefix, prog="dot")
graph.write('%s.dot' % filename_prefix, format='raw', prog='dot')
# graph.write_png("%s.png" % filename_prefix, prog='dot')
graph.write_svg("%s.svg" % filename_prefix, prog='dot')
def get_pdus(host, room):
@@ -127,14 +130,15 @@ def get_pdus(host, room):
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Generate a PDU graph for a given room by talking "
"to the given homeserver to get the list of PDUs. \n"
"Requires pydot."
"to the given homeserver to get the list of PDUs. \n"
"Requires pydot."
)
parser.add_argument(
"-p", "--prefix", dest="prefix", help="String to prefix output files with"
"-p", "--prefix", dest="prefix",
help="String to prefix output files with"
)
parser.add_argument("host")
parser.add_argument("room")
parser.add_argument('host')
parser.add_argument('room')
args = parser.parse_args()

View File

@@ -36,7 +36,10 @@ def make_graph(db_name, room_id, file_prefix, limit):
args = [room_id]
if limit:
sql += " ORDER BY topological_ordering DESC, stream_ordering DESC " "LIMIT ?"
sql += (
" ORDER BY topological_ordering DESC, stream_ordering DESC "
"LIMIT ?"
)
args.append(limit)
@@ -53,8 +56,9 @@ def make_graph(db_name, room_id, file_prefix, limit):
for event in events:
c = conn.execute(
"SELECT state_group FROM event_to_state_groups " "WHERE event_id = ?",
(event.event_id,),
"SELECT state_group FROM event_to_state_groups "
"WHERE event_id = ?",
(event.event_id,)
)
res = c.fetchone()
@@ -65,7 +69,7 @@ def make_graph(db_name, room_id, file_prefix, limit):
t = datetime.datetime.fromtimestamp(
float(event.origin_server_ts) / 1000
).strftime("%Y-%m-%d %H:%M:%S,%f")
).strftime('%Y-%m-%d %H:%M:%S,%f')
content = json.dumps(unfreeze(event.get_dict()["content"]))
@@ -89,7 +93,10 @@ def make_graph(db_name, room_id, file_prefix, limit):
"state_group": state_group,
}
node = pydot.Node(name=event.event_id, label=label)
node = pydot.Node(
name=event.event_id,
label=label,
)
node_map[event.event_id] = node
graph.add_node(node)
@@ -99,7 +106,10 @@ def make_graph(db_name, room_id, file_prefix, limit):
try:
end_node = node_map[prev_id]
except:
end_node = pydot.Node(name=prev_id, label="<<b>%s</b>>" % (prev_id,))
end_node = pydot.Node(
name=prev_id,
label="<<b>%s</b>>" % (prev_id,),
)
node_map[prev_id] = end_node
graph.add_node(end_node)
@@ -111,33 +121,36 @@ def make_graph(db_name, room_id, file_prefix, limit):
if len(event_ids) <= 1:
continue
cluster = pydot.Cluster(str(group), label="<State Group: %s>" % (str(group),))
cluster = pydot.Cluster(
str(group),
label="<State Group: %s>" % (str(group),)
)
for event_id in event_ids:
cluster.add_node(node_map[event_id])
graph.add_subgraph(cluster)
graph.write("%s.dot" % file_prefix, format="raw", prog="dot")
graph.write_svg("%s.svg" % file_prefix, prog="dot")
graph.write('%s.dot' % file_prefix, format='raw', prog='dot')
graph.write_svg("%s.svg" % file_prefix, prog='dot')
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Generate a PDU graph for a given room by talking "
"to the given homeserver to get the list of PDUs. \n"
"Requires pydot."
"to the given homeserver to get the list of PDUs. \n"
"Requires pydot."
)
parser.add_argument(
"-p",
"--prefix",
dest="prefix",
"-p", "--prefix", dest="prefix",
help="String to prefix output files with",
default="graph_output",
default="graph_output"
)
parser.add_argument("-l", "--limit", help="Only retrieve the last N events.")
parser.add_argument("db")
parser.add_argument("room")
parser.add_argument(
"-l", "--limit",
help="Only retrieve the last N events.",
)
parser.add_argument('db')
parser.add_argument('room')
args = parser.parse_args()

View File

@@ -1,5 +1,3 @@
from __future__ import print_function
# Copyright 2016 OpenMarket Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,22 +26,22 @@ from six import string_types
def make_graph(file_name, room_id, file_prefix, limit):
print("Reading lines")
print "Reading lines"
with open(file_name) as f:
lines = f.readlines()
print("Read lines")
print "Read lines"
events = [FrozenEvent(json.loads(line)) for line in lines]
print("Loaded events.")
print "Loaded events."
events.sort(key=lambda e: e.depth)
print("Sorted events")
print "Sorted events"
if limit:
events = events[-int(limit) :]
events = events[-int(limit):]
node_map = {}
@@ -52,12 +50,12 @@ def make_graph(file_name, room_id, file_prefix, limit):
for event in events:
t = datetime.datetime.fromtimestamp(
float(event.origin_server_ts) / 1000
).strftime("%Y-%m-%d %H:%M:%S,%f")
).strftime('%Y-%m-%d %H:%M:%S,%f')
content = json.dumps(unfreeze(event.get_dict()["content"]), indent=4)
content = content.replace("\n", "<br/>\n")
print(content)
print content
content = []
for key, value in unfreeze(event.get_dict()["content"]).items():
if value is None:
@@ -68,16 +66,15 @@ def make_graph(file_name, room_id, file_prefix, limit):
value = json.dumps(value)
content.append(
"<b>%s</b>: %s,"
% (
cgi.escape(key, quote=True).encode("ascii", "xmlcharrefreplace"),
cgi.escape(value, quote=True).encode("ascii", "xmlcharrefreplace"),
"<b>%s</b>: %s," % (
cgi.escape(key, quote=True).encode("ascii", 'xmlcharrefreplace'),
cgi.escape(value, quote=True).encode("ascii", 'xmlcharrefreplace'),
)
)
content = "<br/>\n".join(content)
print(content)
print content
label = (
"<"
@@ -97,19 +94,25 @@ def make_graph(file_name, room_id, file_prefix, limit):
"depth": event.depth,
}
node = pydot.Node(name=event.event_id, label=label)
node = pydot.Node(
name=event.event_id,
label=label,
)
node_map[event.event_id] = node
graph.add_node(node)
print("Created Nodes")
print "Created Nodes"
for event in events:
for prev_id, _ in event.prev_events:
try:
end_node = node_map[prev_id]
except:
end_node = pydot.Node(name=prev_id, label="<<b>%s</b>>" % (prev_id,))
end_node = pydot.Node(
name=prev_id,
label="<<b>%s</b>>" % (prev_id,),
)
node_map[prev_id] = end_node
graph.add_node(end_node)
@@ -117,33 +120,33 @@ def make_graph(file_name, room_id, file_prefix, limit):
edge = pydot.Edge(node_map[event.event_id], end_node)
graph.add_edge(edge)
print("Created edges")
print "Created edges"
graph.write("%s.dot" % file_prefix, format="raw", prog="dot")
graph.write('%s.dot' % file_prefix, format='raw', prog='dot')
print("Created Dot")
print "Created Dot"
graph.write_svg("%s.svg" % file_prefix, prog="dot")
print("Created svg")
graph.write_svg("%s.svg" % file_prefix, prog='dot')
print "Created svg"
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Generate a PDU graph for a given room by reading "
"from a file with line deliminated events. \n"
"Requires pydot."
"from a file with line deliminated events. \n"
"Requires pydot."
)
parser.add_argument(
"-p",
"--prefix",
dest="prefix",
"-p", "--prefix", dest="prefix",
help="String to prefix output files with",
default="graph_output",
default="graph_output"
)
parser.add_argument("-l", "--limit", help="Only retrieve the last N events.")
parser.add_argument("event_file")
parser.add_argument("room")
parser.add_argument(
"-l", "--limit",
help="Only retrieve the last N events.",
)
parser.add_argument('event_file')
parser.add_argument('room')
args = parser.parse_args()

View File

@@ -8,9 +8,8 @@ we set the remote SDP at which point the stream ends. Our video never gets to
the bridge.
Requires:
npm install jquery jsdom
npm install jquery jsdom
"""
from __future__ import print_function
import gevent
import grequests
@@ -20,25 +19,24 @@ import urllib
import subprocess
import time
# ACCESS_TOKEN="" #
#ACCESS_TOKEN="" #
MATRIXBASE = "https://matrix.org/_matrix/client/api/v1/"
MYUSERNAME = "@davetest:matrix.org"
MATRIXBASE = 'https://matrix.org/_matrix/client/api/v1/'
MYUSERNAME = '@davetest:matrix.org'
HTTPBIND = "https://meet.jit.si/http-bind"
# HTTPBIND = 'https://jitsi.vuc.me/http-bind'
# ROOMNAME = "matrix"
HTTPBIND = 'https://meet.jit.si/http-bind'
#HTTPBIND = 'https://jitsi.vuc.me/http-bind'
#ROOMNAME = "matrix"
ROOMNAME = "pibble"
HOST = "guest.jit.si"
# HOST="jitsi.vuc.me"
HOST="guest.jit.si"
#HOST="jitsi.vuc.me"
TURNSERVER = "turn.guest.jit.si"
# TURNSERVER="turn.jitsi.vuc.me"
ROOMDOMAIN = "meet.jit.si"
# ROOMDOMAIN="conference.jitsi.vuc.me"
TURNSERVER="turn.guest.jit.si"
#TURNSERVER="turn.jitsi.vuc.me"
ROOMDOMAIN="meet.jit.si"
#ROOMDOMAIN="conference.jitsi.vuc.me"
class TrivialMatrixClient:
def __init__(self, access_token):
@@ -47,50 +45,38 @@ class TrivialMatrixClient:
def getEvent(self):
while True:
url = (
MATRIXBASE
+ "events?access_token="
+ self.access_token
+ "&timeout=60000"
)
url = MATRIXBASE+'events?access_token='+self.access_token+"&timeout=60000"
if self.token:
url += "&from=" + self.token
url += "&from="+self.token
req = grequests.get(url)
resps = grequests.map([req])
obj = json.loads(resps[0].content)
print("incoming from matrix", obj)
if "end" not in obj:
print "incoming from matrix",obj
if 'end' not in obj:
continue
self.token = obj["end"]
if len(obj["chunk"]):
return obj["chunk"][0]
self.token = obj['end']
if len(obj['chunk']):
return obj['chunk'][0]
def joinRoom(self, roomId):
url = MATRIXBASE + "rooms/" + roomId + "/join?access_token=" + self.access_token
print(url)
headers = {"Content-Type": "application/json"}
req = grequests.post(url, headers=headers, data="{}")
url = MATRIXBASE+'rooms/'+roomId+'/join?access_token='+self.access_token
print url
headers={ 'Content-Type': 'application/json' }
req = grequests.post(url, headers=headers, data='{}')
resps = grequests.map([req])
obj = json.loads(resps[0].content)
print("response: ", obj)
print "response: ",obj
def sendEvent(self, roomId, evType, event):
url = (
MATRIXBASE
+ "rooms/"
+ roomId
+ "/send/"
+ evType
+ "?access_token="
+ self.access_token
)
print(url)
print(json.dumps(event))
headers = {"Content-Type": "application/json"}
url = MATRIXBASE+'rooms/'+roomId+'/send/'+evType+'?access_token='+self.access_token
print url
print json.dumps(event)
headers={ 'Content-Type': 'application/json' }
req = grequests.post(url, headers=headers, data=json.dumps(event))
resps = grequests.map([req])
obj = json.loads(resps[0].content)
print("response: ", obj)
print "response: ",obj
xmppClients = {}
@@ -99,40 +85,39 @@ xmppClients = {}
def matrixLoop():
while True:
ev = matrixCli.getEvent()
print(ev)
if ev["type"] == "m.room.member":
print("membership event")
if ev["membership"] == "invite" and ev["state_key"] == MYUSERNAME:
roomId = ev["room_id"]
print("joining room %s" % (roomId))
print ev
if ev['type'] == 'm.room.member':
print 'membership event'
if ev['membership'] == 'invite' and ev['state_key'] == MYUSERNAME:
roomId = ev['room_id']
print "joining room %s" % (roomId)
matrixCli.joinRoom(roomId)
elif ev["type"] == "m.room.message":
if ev["room_id"] in xmppClients:
print("already have a bridge for that user, ignoring")
elif ev['type'] == 'm.room.message':
if ev['room_id'] in xmppClients:
print "already have a bridge for that user, ignoring"
continue
print("got message, connecting")
xmppClients[ev["room_id"]] = TrivialXmppClient(ev["room_id"], ev["user_id"])
gevent.spawn(xmppClients[ev["room_id"]].xmppLoop)
elif ev["type"] == "m.call.invite":
print("Incoming call")
# sdp = ev['content']['offer']['sdp']
# print "sdp: %s" % (sdp)
# xmppClients[ev['room_id']] = TrivialXmppClient(ev['room_id'], ev['user_id'])
# gevent.spawn(xmppClients[ev['room_id']].xmppLoop)
elif ev["type"] == "m.call.answer":
print("Call answered")
sdp = ev["content"]["answer"]["sdp"]
if ev["room_id"] not in xmppClients:
print("We didn't have a call for that room")
print "got message, connecting"
xmppClients[ev['room_id']] = TrivialXmppClient(ev['room_id'], ev['user_id'])
gevent.spawn(xmppClients[ev['room_id']].xmppLoop)
elif ev['type'] == 'm.call.invite':
print "Incoming call"
#sdp = ev['content']['offer']['sdp']
#print "sdp: %s" % (sdp)
#xmppClients[ev['room_id']] = TrivialXmppClient(ev['room_id'], ev['user_id'])
#gevent.spawn(xmppClients[ev['room_id']].xmppLoop)
elif ev['type'] == 'm.call.answer':
print "Call answered"
sdp = ev['content']['answer']['sdp']
if ev['room_id'] not in xmppClients:
print "We didn't have a call for that room"
continue
# should probably check call ID too
xmppCli = xmppClients[ev["room_id"]]
xmppCli = xmppClients[ev['room_id']]
xmppCli.sendAnswer(sdp)
elif ev["type"] == "m.call.hangup":
if ev["room_id"] in xmppClients:
xmppClients[ev["room_id"]].stop()
del xmppClients[ev["room_id"]]
elif ev['type'] == 'm.call.hangup':
if ev['room_id'] in xmppClients:
xmppClients[ev['room_id']].stop()
del xmppClients[ev['room_id']]
class TrivialXmppClient:
def __init__(self, matrixRoom, userId):
@@ -146,155 +131,130 @@ class TrivialXmppClient:
def nextRid(self):
self.rid += 1
return "%d" % (self.rid)
return '%d' % (self.rid)
def sendIq(self, xml):
fullXml = (
"<body rid='%s' xmlns='http://jabber.org/protocol/httpbind' sid='%s'>%s</body>"
% (self.nextRid(), self.sid, xml)
)
# print "\t>>>%s" % (fullXml)
fullXml = "<body rid='%s' xmlns='http://jabber.org/protocol/httpbind' sid='%s'>%s</body>" % (self.nextRid(), self.sid, xml)
#print "\t>>>%s" % (fullXml)
return self.xmppPoke(fullXml)
def xmppPoke(self, xml):
headers = {"Content-Type": "application/xml"}
headers = {'Content-Type': 'application/xml'}
req = grequests.post(HTTPBIND, verify=False, headers=headers, data=xml)
resps = grequests.map([req])
obj = BeautifulSoup(resps[0].content)
return obj
def sendAnswer(self, answer):
print("sdp from matrix client", answer)
p = subprocess.Popen(
["node", "unjingle/unjingle.js", "--sdp"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
print "sdp from matrix client",answer
p = subprocess.Popen(['node', 'unjingle/unjingle.js', '--sdp'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
jingle, out_err = p.communicate(answer)
jingle = jingle % {
"tojid": self.callfrom,
"action": "session-accept",
"initiator": self.callfrom,
"responder": self.jid,
"sid": self.callsid,
'tojid': self.callfrom,
'action': 'session-accept',
'initiator': self.callfrom,
'responder': self.jid,
'sid': self.callsid
}
print("answer jingle from sdp", jingle)
print "answer jingle from sdp",jingle
res = self.sendIq(jingle)
print("reply from answer: ", res)
print "reply from answer: ",res
self.ssrcs = {}
jingleSoup = BeautifulSoup(jingle)
for cont in jingleSoup.iq.jingle.findAll("content"):
for cont in jingleSoup.iq.jingle.findAll('content'):
if cont.description:
self.ssrcs[cont["name"]] = cont.description["ssrc"]
print("my ssrcs:", self.ssrcs)
self.ssrcs[cont['name']] = cont.description['ssrc']
print "my ssrcs:",self.ssrcs
gevent.joinall([gevent.spawn(self.advertiseSsrcs)])
gevent.joinall([
gevent.spawn(self.advertiseSsrcs)
])
def advertiseSsrcs(self):
time.sleep(7)
print("SSRC spammer started")
time.sleep(7)
print "SSRC spammer started"
while self.running:
ssrcMsg = (
"<presence to='%(tojid)s' xmlns='jabber:client'><x xmlns='http://jabber.org/protocol/muc'/><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://jitsi.org/jitsimeet' ver='0WkSdhFnAUxrz4ImQQLdB80GFlE='/><nick xmlns='http://jabber.org/protocol/nick'>%(nick)s</nick><stats xmlns='http://jitsi.org/jitmeet/stats'><stat name='bitrate_download' value='175'/><stat name='bitrate_upload' value='176'/><stat name='packetLoss_total' value='0'/><stat name='packetLoss_download' value='0'/><stat name='packetLoss_upload' value='0'/></stats><media xmlns='http://estos.de/ns/mjs'><source type='audio' ssrc='%(assrc)s' direction='sendre'/><source type='video' ssrc='%(vssrc)s' direction='sendre'/></media></presence>"
% {
"tojid": "%s@%s/%s" % (ROOMNAME, ROOMDOMAIN, self.shortJid),
"nick": self.userId,
"assrc": self.ssrcs["audio"],
"vssrc": self.ssrcs["video"],
}
)
ssrcMsg = "<presence to='%(tojid)s' xmlns='jabber:client'><x xmlns='http://jabber.org/protocol/muc'/><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://jitsi.org/jitsimeet' ver='0WkSdhFnAUxrz4ImQQLdB80GFlE='/><nick xmlns='http://jabber.org/protocol/nick'>%(nick)s</nick><stats xmlns='http://jitsi.org/jitmeet/stats'><stat name='bitrate_download' value='175'/><stat name='bitrate_upload' value='176'/><stat name='packetLoss_total' value='0'/><stat name='packetLoss_download' value='0'/><stat name='packetLoss_upload' value='0'/></stats><media xmlns='http://estos.de/ns/mjs'><source type='audio' ssrc='%(assrc)s' direction='sendre'/><source type='video' ssrc='%(vssrc)s' direction='sendre'/></media></presence>" % { 'tojid': "%s@%s/%s" % (ROOMNAME, ROOMDOMAIN, self.shortJid), 'nick': self.userId, 'assrc': self.ssrcs['audio'], 'vssrc': self.ssrcs['video'] }
res = self.sendIq(ssrcMsg)
print("reply from ssrc announce: ", res)
print "reply from ssrc announce: ",res
time.sleep(10)
def xmppLoop(self):
self.matrixCallId = time.time()
res = self.xmppPoke(
"<body rid='%s' xmlns='http://jabber.org/protocol/httpbind' to='%s' xml:lang='en' wait='60' hold='1' content='text/xml; charset=utf-8' ver='1.6' xmpp:version='1.0' xmlns:xmpp='urn:xmpp:xbosh'/>"
% (self.nextRid(), HOST)
)
res = self.xmppPoke("<body rid='%s' xmlns='http://jabber.org/protocol/httpbind' to='%s' xml:lang='en' wait='60' hold='1' content='text/xml; charset=utf-8' ver='1.6' xmpp:version='1.0' xmlns:xmpp='urn:xmpp:xbosh'/>" % (self.nextRid(), HOST))
print(res)
self.sid = res.body["sid"]
print("sid %s" % (self.sid))
print res
self.sid = res.body['sid']
print "sid %s" % (self.sid)
res = self.sendIq(
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>"
)
res = self.sendIq("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>")
res = self.xmppPoke(
"<body rid='%s' xmlns='http://jabber.org/protocol/httpbind' sid='%s' to='%s' xml:lang='en' xmpp:restart='true' xmlns:xmpp='urn:xmpp:xbosh'/>"
% (self.nextRid(), self.sid, HOST)
)
res = self.xmppPoke("<body rid='%s' xmlns='http://jabber.org/protocol/httpbind' sid='%s' to='%s' xml:lang='en' xmpp:restart='true' xmlns:xmpp='urn:xmpp:xbosh'/>" % (self.nextRid(), self.sid, HOST))
res = self.sendIq(
"<iq type='set' id='_bind_auth_2' xmlns='jabber:client'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>"
)
print(res)
res = self.sendIq("<iq type='set' id='_bind_auth_2' xmlns='jabber:client'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>")
print res
self.jid = res.body.iq.bind.jid.string
print("jid: %s" % (self.jid))
self.shortJid = self.jid.split("-")[0]
print "jid: %s" % (self.jid)
self.shortJid = self.jid.split('-')[0]
res = self.sendIq(
"<iq type='set' id='_session_auth_2' xmlns='jabber:client'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>"
)
res = self.sendIq("<iq type='set' id='_session_auth_2' xmlns='jabber:client'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>")
# randomthing = res.body.iq['to']
# whatsitpart = randomthing.split('-')[0]
#randomthing = res.body.iq['to']
#whatsitpart = randomthing.split('-')[0]
# print "other random bind thing: %s" % (randomthing)
#print "other random bind thing: %s" % (randomthing)
# advertise preence to the jitsi room, with our nick
res = self.sendIq(
"<iq type='get' to='%s' xmlns='jabber:client' id='1:sendIQ'><services xmlns='urn:xmpp:extdisco:1'><service host='%s'/></services></iq><presence to='%s@%s/d98f6c40' xmlns='jabber:client'><x xmlns='http://jabber.org/protocol/muc'/><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://jitsi.org/jitsimeet' ver='0WkSdhFnAUxrz4ImQQLdB80GFlE='/><nick xmlns='http://jabber.org/protocol/nick'>%s</nick></presence>"
% (HOST, TURNSERVER, ROOMNAME, ROOMDOMAIN, self.userId)
)
self.muc = {"users": []}
for p in res.body.findAll("presence"):
res = self.sendIq("<iq type='get' to='%s' xmlns='jabber:client' id='1:sendIQ'><services xmlns='urn:xmpp:extdisco:1'><service host='%s'/></services></iq><presence to='%s@%s/d98f6c40' xmlns='jabber:client'><x xmlns='http://jabber.org/protocol/muc'/><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://jitsi.org/jitsimeet' ver='0WkSdhFnAUxrz4ImQQLdB80GFlE='/><nick xmlns='http://jabber.org/protocol/nick'>%s</nick></presence>" % (HOST, TURNSERVER, ROOMNAME, ROOMDOMAIN, self.userId))
self.muc = {'users': []}
for p in res.body.findAll('presence'):
u = {}
u["shortJid"] = p["from"].split("/")[1]
u['shortJid'] = p['from'].split('/')[1]
if p.c and p.c.nick:
u["nick"] = p.c.nick.string
self.muc["users"].append(u)
print("muc: ", self.muc)
u['nick'] = p.c.nick.string
self.muc['users'].append(u)
print "muc: ",self.muc
# wait for stuff
while True:
print("waiting...")
print "waiting..."
res = self.sendIq("")
print("got from stream: ", res)
print "got from stream: ",res
if res.body.iq:
jingles = res.body.iq.findAll("jingle")
jingles = res.body.iq.findAll('jingle')
if len(jingles):
self.callfrom = res.body.iq["from"]
self.callfrom = res.body.iq['from']
self.handleInvite(jingles[0])
elif "type" in res.body and res.body["type"] == "terminate":
elif 'type' in res.body and res.body['type'] == 'terminate':
self.running = False
del xmppClients[self.matrixRoom]
return
return
def handleInvite(self, jingle):
self.initiator = jingle["initiator"]
self.callsid = jingle["sid"]
p = subprocess.Popen(
["node", "unjingle/unjingle.js", "--jingle"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
print("raw jingle invite", str(jingle))
self.initiator = jingle['initiator']
self.callsid = jingle['sid']
p = subprocess.Popen(['node', 'unjingle/unjingle.js', '--jingle'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
print "raw jingle invite",str(jingle)
sdp, out_err = p.communicate(str(jingle))
print("transformed remote offer sdp", sdp)
print "transformed remote offer sdp",sdp
inviteEvent = {
"offer": {"type": "offer", "sdp": sdp},
"call_id": self.matrixCallId,
"version": 0,
"lifetime": 30000,
'offer': {
'type': 'offer',
'sdp': sdp
},
'call_id': self.matrixCallId,
'version': 0,
'lifetime': 30000
}
matrixCli.sendEvent(self.matrixRoom, "m.call.invite", inviteEvent)
matrixCli.sendEvent(self.matrixRoom, 'm.call.invite', inviteEvent)
matrixCli = TrivialMatrixClient(ACCESS_TOKEN)
matrixCli = TrivialMatrixClient(ACCESS_TOKEN) # Undefined name
gevent.joinall([
gevent.spawn(matrixLoop)
])
gevent.joinall([gevent.spawn(matrixLoop)])

View File

@@ -3,7 +3,7 @@ Purge history API examples
# `purge_history.sh`
A bash file, that uses the [purge history API](/docs/admin_api/purge_history_api.rst) to
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.
@@ -12,5 +12,5 @@ the script.
# `purge_remote_media.sh`
A bash file, that uses the [purge history API](/docs/admin_api/purge_history_api.rst) to
A bash file, that uses the [purge history API](/docs/admin_api/README.rst) to
purge all old cached remote media.

View File

@@ -1,40 +1,34 @@
#!/usr/bin/env python
from __future__ import print_function
from argparse import ArgumentParser
import json
import requests
import sys
import urllib
try:
raw_input
except NameError: # Python 3
raw_input = input
def _mkurl(template, kws):
for key in kws:
template = template.replace(key, kws[key])
return template
def main(hs, room_id, access_token, user_id_prefix, why):
if not why:
why = "Automated kick."
print(
"Kicking members on %s in room %s matching %s" % (hs, room_id, user_id_prefix)
)
print "Kicking members on %s in room %s matching %s" % (hs, room_id, user_id_prefix)
room_state_url = _mkurl(
"$HS/_matrix/client/api/v1/rooms/$ROOM/state?access_token=$TOKEN",
{"$HS": hs, "$ROOM": room_id, "$TOKEN": access_token},
{
"$HS": hs,
"$ROOM": room_id,
"$TOKEN": access_token
}
)
print("Getting room state => %s" % room_state_url)
print "Getting room state => %s" % room_state_url
res = requests.get(room_state_url)
print("HTTP %s" % res.status_code)
print "HTTP %s" % res.status_code
state_events = res.json()
if "error" in state_events:
print("FATAL")
print(state_events)
print "FATAL"
print state_events
return
kick_list = []
@@ -50,40 +44,47 @@ def main(hs, room_id, access_token, user_id_prefix, why):
kick_list.append(event["state_key"])
if len(kick_list) == 0:
print("No user IDs match the prefix '%s'" % user_id_prefix)
print "No user IDs match the prefix '%s'" % user_id_prefix
return
print("The following user IDs will be kicked from %s" % room_name)
print "The following user IDs will be kicked from %s" % room_name
for uid in kick_list:
print(uid)
print uid
doit = raw_input("Continue? [Y]es\n")
if len(doit) > 0 and doit.lower() == "y":
print("Kicking members...")
if len(doit) > 0 and doit.lower() == 'y':
print "Kicking members..."
# encode them all
kick_list = [urllib.quote(uid) for uid in kick_list]
for uid in kick_list:
kick_url = _mkurl(
"$HS/_matrix/client/api/v1/rooms/$ROOM/state/m.room.member/$UID?access_token=$TOKEN",
{"$HS": hs, "$UID": uid, "$ROOM": room_id, "$TOKEN": access_token},
{
"$HS": hs,
"$UID": uid,
"$ROOM": room_id,
"$TOKEN": access_token
}
)
kick_body = {"membership": "leave", "reason": why}
print("Kicking %s" % uid)
kick_body = {
"membership": "leave",
"reason": why
}
print "Kicking %s" % uid
res = requests.put(kick_url, data=json.dumps(kick_body))
if res.status_code != 200:
print("ERROR: HTTP %s" % res.status_code)
print "ERROR: HTTP %s" % res.status_code
if res.json().get("error"):
print("ERROR: JSON %s" % res.json())
print "ERROR: JSON %s" % res.json()
if __name__ == "__main__":
parser = ArgumentParser("Kick members in a room matching a certain user ID prefix.")
parser.add_argument("-u", "--user-id", help="The user ID prefix e.g. '@irc_'")
parser.add_argument("-t", "--token", help="Your access_token")
parser.add_argument("-r", "--room", help="The room ID to kick members in")
parser.add_argument(
"-s", "--homeserver", help="The base HS url e.g. http://matrix.org"
)
parser.add_argument("-w", "--why", help="Reason for the kick. Optional.")
parser.add_argument("-u","--user-id",help="The user ID prefix e.g. '@irc_'")
parser.add_argument("-t","--token",help="Your access_token")
parser.add_argument("-r","--room",help="The room ID to kick members in")
parser.add_argument("-s","--homeserver",help="The base HS url e.g. http://matrix.org")
parser.add_argument("-w","--why",help="Reason for the kick. Optional.")
args = parser.parse_args()
if not args.room or not args.token or not args.user_id or not args.homeserver:
parser.print_help()

View File

@@ -43,7 +43,7 @@ dh_virtualenv \
--preinstall="mock" \
--extra-pip-arg="--no-cache-dir" \
--extra-pip-arg="--compile" \
--extras="all,systemd"
--extras="all"
PACKAGE_BUILD_DIR="debian/matrix-synapse-py3"
VIRTUALENV_DIR="${PACKAGE_BUILD_DIR}${DH_VIRTUALENV_INSTALL_ROOT}/matrix-synapse"

7
debian/changelog vendored
View File

@@ -1,10 +1,3 @@
matrix-synapse-py3 (1.0.0+nmu1) UNRELEASED; urgency=medium
[ Silke Hofstra ]
* Include systemd-python to allow logging to the systemd journal.
-- Silke Hofstra <silke@slxh.eu> Wed, 29 May 2019 09:45:29 +0200
matrix-synapse-py3 (1.0.0) stable; urgency=medium
* New synapse release 1.0.0.

View File

@@ -1,13 +1,9 @@
DO NOT USE THESE DEMO SERVERS IN PRODUCTION
Requires you to have done:
python setup.py develop
The demo start.sh will start three synapse servers on ports 8080, 8081 and 8082, with host names localhost:$port. This can be easily changed to `hostname`:$port in start.sh if required.
To enable the servers to communicate untrusted ssl certs are used. In order to do this the servers do not check the certs
and are configured in a highly insecure way. Do not use these configuration files in production.
The demo start.sh will start three synapse servers on ports 8080, 8081 and 8082, with host names localhost:$port. This can be easily changed to `hostname`:$port in start.sh if required.
It will also start a web server on port 8000 pointed at the webclient.
stop.sh will stop the synapse servers and the webclient.

View File

@@ -21,76 +21,14 @@ for port in 8080 8081 8082; do
pushd demo/$port
#rm $DIR/etc/$port.config
python3 -m synapse.app.homeserver \
python -m synapse.app.homeserver \
--generate-config \
-H "localhost:$https_port" \
--config-path "$DIR/etc/$port.config" \
--report-stats no
if ! grep -F "Customisation made by demo/start.sh" -q $DIR/etc/$port.config; then
printf '\n\n# Customisation made by demo/start.sh\n' >> $DIR/etc/$port.config
echo 'enable_registration: true' >> $DIR/etc/$port.config
# Warning, this heredoc depends on the interaction of tabs and spaces. Please don't
# accidentaly bork me with your fancy settings.
listeners=$(cat <<-PORTLISTENERS
# Configure server to listen on both $https_port and $port
# This overides some of the default settings above
listeners:
- port: $https_port
type: http
tls: true
resources:
- names: [client, federation]
- port: $port
tls: false
bind_addresses: ['::1', '127.0.0.1']
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
PORTLISTENERS
)
echo "${listeners}" >> $DIR/etc/$port.config
# Disable tls for the servers
printf '\n\n# Disable tls on the servers.' >> $DIR/etc/$port.config
echo '# DO NOT USE IN PRODUCTION' >> $DIR/etc/$port.config
echo 'use_insecure_ssl_client_just_for_testing_do_not_use: true' >> $DIR/etc/$port.config
echo 'federation_verify_certificates: false' >> $DIR/etc/$port.config
# Set tls paths
echo "tls_certificate_path: \"$DIR/etc/localhost:$https_port.tls.crt\"" >> $DIR/etc/$port.config
echo "tls_private_key_path: \"$DIR/etc/localhost:$https_port.tls.key\"" >> $DIR/etc/$port.config
# Generate tls keys
openssl req -x509 -newkey rsa:4096 -keyout $DIR/etc/localhost\:$https_port.tls.key -out $DIR/etc/localhost\:$https_port.tls.crt -days 365 -nodes -subj "/O=matrix"
# Ignore keys from the trusted keys server
echo '# Ignore keys from the trusted keys server' >> $DIR/etc/$port.config
echo 'trusted_key_servers:' >> $DIR/etc/$port.config
echo ' - server_name: "matrix.org"' >> $DIR/etc/$port.config
echo ' accept_keys_insecurely: true' >> $DIR/etc/$port.config
# Reduce the blacklist
blacklist=$(cat <<-BLACK
# Set the blacklist so that it doesn't include 127.0.0.1
federation_ip_range_blacklist:
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '169.254.0.0/16'
- '::1/128'
- 'fe80::/64'
- 'fc00::/7'
BLACK
)
echo "${blacklist}" >> $DIR/etc/$port.config
fi
printf '\n\n# Customisation made by demo/start.sh\n' >> $DIR/etc/$port.config
echo 'enable_registration: true' >> $DIR/etc/$port.config
# Check script parameters
if [ $# -eq 1 ]; then
@@ -117,7 +55,7 @@ for port in 8080 8081 8082; do
echo "report_stats: false" >> $DIR/etc/$port.config
fi
python3 -m synapse.app.homeserver \
python -m synapse.app.homeserver \
--config-path "$DIR/etc/$port.config" \
-D \
-vv \

View File

@@ -6,25 +6,23 @@ import cgi, logging
from daemonize import Daemonize
class SimpleHTTPRequestHandlerWithPOST(SimpleHTTPServer.SimpleHTTPRequestHandler):
UPLOAD_PATH = "upload"
"""
Accept all post request as file upload
"""
def do_POST(self):
path = os.path.join(self.UPLOAD_PATH, os.path.basename(self.path))
length = self.headers["content-length"]
length = self.headers['content-length']
data = self.rfile.read(int(length))
with open(path, "wb") as fh:
with open(path, 'wb') as fh:
fh.write(data)
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header('Content-Type', 'application/json')
self.end_headers()
# Return the absolute path of the uploaded file
@@ -35,25 +33,30 @@ def setup():
parser = argparse.ArgumentParser()
parser.add_argument("directory")
parser.add_argument("-p", "--port", dest="port", type=int, default=8080)
parser.add_argument("-P", "--pid-file", dest="pid", default="web.pid")
parser.add_argument('-P', "--pid-file", dest="pid", default="web.pid")
args = parser.parse_args()
# Get absolute path to directory to serve, as daemonize changes to '/'
os.chdir(args.directory)
dr = os.getcwd()
httpd = BaseHTTPServer.HTTPServer(("", args.port), SimpleHTTPRequestHandlerWithPOST)
httpd = BaseHTTPServer.HTTPServer(
('', args.port),
SimpleHTTPRequestHandlerWithPOST
)
def run():
os.chdir(dr)
httpd.serve_forever()
daemon = Daemonize(
app="synapse-webclient", pid=args.pid, action=run, auto_close_fds=False
)
app="synapse-webclient",
pid=args.pid,
action=run,
auto_close_fds=False,
)
daemon.start()
if __name__ == "__main__":
if __name__ == '__main__':
setup()

View File

@@ -11,7 +11,7 @@
# docker build -f docker/Dockerfile --build-arg PYTHON_VERSION=3.6 .
#
ARG PYTHON_VERSION=3.7
ARG PYTHON_VERSION=2
###
### Stage 0: builder
@@ -57,7 +57,6 @@ RUN pip install --prefix="/install" --no-warn-script-location \
FROM docker.io/python:${PYTHON_VERSION}-alpine3.8
# xmlsec is required for saml support
RUN apk add --no-cache --virtual .runtime_deps \
libffi \
libjpeg-turbo \
@@ -65,9 +64,7 @@ RUN apk add --no-cache --virtual .runtime_deps \
libxslt \
libpq \
zlib \
su-exec \
tzdata \
xmlsec
su-exec
COPY --from=builder /install /usr/local
COPY ./docker/start.py /start.py

View File

@@ -3,10 +3,10 @@
FROM matrixdotorg/sytest:latest
# The Sytest image doesn't come with python, so install that
RUN apt-get update && apt-get -qq install -y python3 python3-dev python3-pip
RUN apt-get -qq install -y python python-dev python-pip
# We need tox to run the tests in run_pg_tests.sh
RUN python3 -m pip install tox
RUN pip install tox
ADD run_pg_tests.sh /pg_tests.sh
ENTRYPOINT /pg_tests.sh

View File

@@ -6,11 +6,39 @@ postgres database.
The image also does *not* provide a TURN server.
## Run
### Using docker-compose (easier)
This image is designed to run either with an automatically generated
configuration file or with a custom configuration that requires manual editing.
An easy way to make use of this image is via docker-compose. See the
[contrib/docker](https://github.com/matrix-org/synapse/tree/master/contrib/docker) section of the synapse project for
examples.
### Without Compose (harder)
If you do not wish to use Compose, you may still run this image using plain
Docker commands. Note that the following is just a guideline and you may need
to add parameters to the docker run command to account for the network situation
with your postgres database.
```
docker run \
-d \
--name synapse \
--mount type=volume,src=synapse-data,dst=/data \
-e SYNAPSE_SERVER_NAME=my.matrix.host \
-e SYNAPSE_REPORT_STATS=yes \
-p 8448:8448 \
matrixdotorg/synapse:latest
```
## Volumes
By default, the image expects a single volume, located at ``/data``, that will hold:
The image expects a single volume, located at ``/data``, that will hold:
* configuration files;
* temporary files during uploads;
* uploaded media and thumbnails;
* the SQLite database if you do not configure postgres;
@@ -25,106 +53,129 @@ In order to setup an application service, simply create an ``appservices``
directory in the data volume and write the application service Yaml
configuration file there. Multiple application services are supported.
## Generating a configuration file
## TLS certificates
The first step is to genearte a valid config file. To do this, you can run the
image with the `generate` commandline option.
Synapse requires a valid TLS certificate. You can do one of the following:
You will need to specify values for the `SYNAPSE_SERVER_NAME` and
`SYNAPSE_REPORT_STATS` environment variable, and mount a docker volume to store
the configuration on. For example:
* Provide your own certificate and key (as
`${DATA_PATH}/${SYNAPSE_SERVER_NAME}.tls.crt` and
`${DATA_PATH}/${SYNAPSE_SERVER_NAME}.tls.key`, or elsewhere by providing an
entire config as `${SYNAPSE_CONFIG_PATH}`). In this case, you should forward
traffic to port 8448 in the container, for example with `-p 443:8448`.
* Use a reverse proxy to terminate incoming TLS, and forward the plain http
traffic to port 8008 in the container. In this case you should set `-e
SYNAPSE_NO_TLS=1`.
* Use the ACME (Let's Encrypt) support built into Synapse. This requires
`${SYNAPSE_SERVER_NAME}` port 80 to be forwarded to port 8009 in the
container, for example with `-p 80:8009`. To enable it in the docker
container, set `-e SYNAPSE_ACME=1`.
If you don't do any of these, Synapse will fail to start with an error similar to:
synapse.config._base.ConfigError: Error accessing file '/data/<server_name>.tls.crt' (config for tls_certificate): No such file or directory
## Environment
Unless you specify a custom path for the configuration file, a very generic
file will be generated, based on the following environment settings.
These are a good starting point for setting up your own deployment.
Global settings:
* ``UID``, the user id Synapse will run as [default 991]
* ``GID``, the group id Synapse will run as [default 991]
* ``SYNAPSE_CONFIG_PATH``, path to a custom config file
If ``SYNAPSE_CONFIG_PATH`` is set, you should generate a configuration file
then customize it manually: see [Generating a config
file](#generating-a-config-file).
Otherwise, a dynamic configuration file will be used.
### Environment variables used to build a dynamic configuration file
The following environment variables are used to build the configuration file
when ``SYNAPSE_CONFIG_PATH`` is not set.
* ``SYNAPSE_SERVER_NAME`` (mandatory), the server public hostname.
* ``SYNAPSE_REPORT_STATS``, (mandatory, ``yes`` or ``no``), enable anonymous
statistics reporting back to the Matrix project which helps us to get funding.
* `SYNAPSE_NO_TLS`, (accepts `true`, `false`, `on`, `off`, `1`, `0`, `yes`, `no`]): disable
TLS in Synapse (use this if you run your own TLS-capable reverse proxy). Defaults
to `false` (ie, TLS is enabled by default).
* ``SYNAPSE_ENABLE_REGISTRATION``, set this variable to enable registration on
the Synapse instance.
* ``SYNAPSE_ALLOW_GUEST``, set this variable to allow guest joining this server.
* ``SYNAPSE_EVENT_CACHE_SIZE``, the event cache size [default `10K`].
* ``SYNAPSE_RECAPTCHA_PUBLIC_KEY``, set this variable to the recaptcha public
key in order to enable recaptcha upon registration.
* ``SYNAPSE_RECAPTCHA_PRIVATE_KEY``, set this variable to the recaptcha private
key in order to enable recaptcha upon registration.
* ``SYNAPSE_TURN_URIS``, set this variable to the coma-separated list of TURN
uris to enable TURN for this homeserver.
* ``SYNAPSE_TURN_SECRET``, set this to the TURN shared secret if required.
* ``SYNAPSE_MAX_UPLOAD_SIZE``, set this variable to change the max upload size
[default `10M`].
* ``SYNAPSE_ACME``: set this to enable the ACME certificate renewal support.
Shared secrets, that will be initialized to random values if not set:
* ``SYNAPSE_REGISTRATION_SHARED_SECRET``, secret for registrering users if
registration is disable.
* ``SYNAPSE_MACAROON_SECRET_KEY`` secret for signing access tokens
to the server.
Database specific values (will use SQLite if not set):
* `POSTGRES_DB` - The database name for the synapse postgres
database. [default: `synapse`]
* `POSTGRES_HOST` - The host of the postgres database if you wish to use
postgresql instead of sqlite3. [default: `db` which is useful when using a
container on the same docker network in a compose file where the postgres
service is called `db`]
* `POSTGRES_PASSWORD` - The password for the synapse postgres database. **If
this is set then postgres will be used instead of sqlite3.** [default: none]
**NOTE**: You are highly encouraged to use postgresql! Please use the compose
file to make it easier to deploy.
* `POSTGRES_USER` - The user for the synapse postgres database. [default:
`synapse`]
Mail server specific values (will not send emails if not set):
* ``SYNAPSE_SMTP_HOST``, hostname to the mail server.
* ``SYNAPSE_SMTP_PORT``, TCP port for accessing the mail server [default
``25``].
* ``SYNAPSE_SMTP_USER``, username for authenticating against the mail server if
any.
* ``SYNAPSE_SMTP_PASSWORD``, password for authenticating against the mail
server if any.
### Generating a config file
It is possible to generate a basic configuration file for use with
`SYNAPSE_CONFIG_PATH` using the `generate` commandline option. You will need to
specify values for `SYNAPSE_CONFIG_PATH`, `SYNAPSE_SERVER_NAME` and
`SYNAPSE_REPORT_STATS`, and mount a docker volume to store the data on. For
example:
```
docker run -it --rm \
--mount type=volume,src=synapse-data,dst=/data \
-e SYNAPSE_CONFIG_PATH=/data/homeserver.yaml \
-e SYNAPSE_SERVER_NAME=my.matrix.host \
-e SYNAPSE_REPORT_STATS=yes \
matrixdotorg/synapse:latest generate
```
For information on picking a suitable server name, see
https://github.com/matrix-org/synapse/blob/master/INSTALL.md.
The above command will generate a `homeserver.yaml` in (typically)
`/var/lib/docker/volumes/synapse-data/_data`. You should check this file, and
customise it to your needs.
The following environment variables are supported in `generate` mode:
* `SYNAPSE_SERVER_NAME` (mandatory): the server public hostname.
* `SYNAPSE_REPORT_STATS` (mandatory, `yes` or `no`): whether to enable
anonymous statistics reporting.
* `SYNAPSE_CONFIG_DIR`: where additional config files (such as the log config
and event signing key) will be stored. Defaults to `/data`.
* `SYNAPSE_CONFIG_PATH`: path to the file to be generated. Defaults to
`<SYNAPSE_CONFIG_DIR>/homeserver.yaml`.
* `SYNAPSE_DATA_DIR`: where the generated config will put persistent data
such as the datatase and media store. Defaults to `/data`.
* `UID`, `GID`: the user id and group id to use for creating the data
directories. Defaults to `991`, `991`.
## Running synapse
Once you have a valid configuration file, you can start synapse as follows:
This will generate a `homeserver.yaml` in (typically)
`/var/lib/docker/volumes/synapse-data/_data`, which you can then customise and
use with:
```
docker run -d --name synapse \
--mount type=volume,src=synapse-data,dst=/data \
-p 8008:8008 \
-e SYNAPSE_CONFIG_PATH=/data/homeserver.yaml \
matrixdotorg/synapse:latest
```
You can then check that it has started correctly with:
```
docker logs synapse
```
If all is well, you should now be able to connect to http://localhost:8008 and
see a confirmation message.
The following environment variables are supported in run mode:
* `SYNAPSE_CONFIG_DIR`: where additional config files are stored. Defaults to
`/data`.
* `SYNAPSE_CONFIG_PATH`: path to the config file. Defaults to
`<SYNAPSE_CONFIG_DIR>/homeserver.yaml`.
* `UID`, `GID`: the user and group id to run Synapse as. Defaults to `991`, `991`.
* `TZ`: the [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) the container will run with. Defaults to `UTC`.
## TLS support
The default configuration exposes a single HTTP port: http://localhost:8008. It
is suitable for local testing, but for any practical use, you will either need
to use a reverse proxy, or configure Synapse to expose an HTTPS port.
For documentation on using a reverse proxy, see
https://github.com/matrix-org/synapse/blob/master/docs/reverse_proxy.rst.
For more information on enabling TLS support in synapse itself, see
https://github.com/matrix-org/synapse/blob/master/INSTALL.md#tls-certificates. Of
course, you will need to expose the TLS port from the container with a `-p`
argument to `docker run`.
## Legacy dynamic configuration file support
For backwards-compatibility only, the docker image supports creating a dynamic
configuration file based on environment variables. This is now deprecated, but
is enabled when the `SYNAPSE_SERVER_NAME` variable is set (and `generate` is
not given).
To migrate from a dynamic configuration file to a static one, run the docker
container once with the environment variables set, and `migrate_config`
commandline option. For example:
```
docker run -it --rm \
--mount type=volume,src=synapse-data,dst=/data \
-e SYNAPSE_SERVER_NAME=my.matrix.host \
-e SYNAPSE_REPORT_STATS=yes \
matrixdotorg/synapse:latest migrate_config
```
This will generate the same configuration file as the legacy mode used, but
will store it in `/data/homeserver.yaml` instead of a temporary location. You
can then use it as shown above at [Running synapse](#running-synapse).

View File

@@ -21,7 +21,7 @@ server_name: "{{ SYNAPSE_SERVER_NAME }}"
pid_file: /homeserver.pid
web_client: False
soft_file_limit: 0
log_config: "{{ SYNAPSE_LOG_CONFIG }}"
log_config: "/compiled/log.config"
## Ports ##
@@ -207,3 +207,22 @@ perspectives:
password_config:
enabled: true
{% if SYNAPSE_SMTP_HOST %}
email:
enable_notifs: false
smtp_host: "{{ SYNAPSE_SMTP_HOST }}"
smtp_port: {{ SYNAPSE_SMTP_PORT or "25" }}
smtp_user: "{{ SYNAPSE_SMTP_USER }}"
smtp_pass: "{{ SYNAPSE_SMTP_PASSWORD }}"
require_transport_security: False
notif_from: "{{ SYNAPSE_SMTP_FROM or "hostmaster@" + SYNAPSE_SERVER_NAME }}"
app_name: Matrix
# 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
riot_base_url: "https://{{ SYNAPSE_SERVER_NAME }}"
{% endif %}

View File

@@ -16,11 +16,14 @@ handlers:
filters: [context]
loggers:
synapse:
level: {{ SYNAPSE_LOG_LEVEL or "WARNING" }}
synapse.storage.SQL:
# beware: increasing this to DEBUG will make synapse log sensitive
# information such as access tokens.
level: INFO
level: {{ SYNAPSE_LOG_LEVEL or "WARNING" }}
root:
level: {{ SYNAPSE_LOG_LEVEL or "INFO" }}
level: {{ SYNAPSE_LOG_LEVEL or "WARNING" }}
handlers: [console]

View File

@@ -17,4 +17,4 @@ su -c '/usr/lib/postgresql/9.6/bin/pg_ctl -w -D /var/lib/postgresql/data start'
# Run the tests
cd /src
export TRIAL_FLAGS="-j 4"
tox --workdir=/tmp -e py35-postgres
tox --workdir=/tmp -e py27-postgres

View File

@@ -1,243 +1,89 @@
#!/usr/local/bin/python
import codecs
import glob
import os
import subprocess
import sys
import jinja2
import os
import sys
import subprocess
import glob
import codecs
# Utility functions
def log(txt):
print(txt, file=sys.stderr)
convert = lambda src, dst, environ: open(dst, "w").write(jinja2.Template(open(src).read()).render(**environ))
def check_arguments(environ, args):
for argument in args:
if argument not in environ:
print("Environment variable %s is mandatory, exiting." % argument)
sys.exit(2)
def error(txt):
log(txt)
sys.exit(2)
def convert(src, dst, environ):
"""Generate a file from a template
Args:
src (str): path to input file
dst (str): path to file to write
environ (dict): environment dictionary, for replacement mappings.
"""
with open(src) as infile:
template = infile.read()
rendered = jinja2.Template(template).render(**environ)
with open(dst, "w") as outfile:
outfile.write(rendered)
def generate_config_from_template(config_dir, config_path, environ, ownership):
"""Generate a homeserver.yaml from environment variables
Args:
config_dir (str): where to put generated config files
config_path (str): where to put the main config file
environ (dict): environment dictionary
ownership (str): "<user>:<group>" string which will be used to set
ownership of the generated configs
"""
for v in ("SYNAPSE_SERVER_NAME", "SYNAPSE_REPORT_STATS"):
if v not in environ:
error(
"Environment variable '%s' is mandatory when generating a config file."
% (v,)
)
# populate some params from data files (if they exist, else create new ones)
environ = environ.copy()
secrets = {
"registration": "SYNAPSE_REGISTRATION_SHARED_SECRET",
"macaroon": "SYNAPSE_MACAROON_SECRET_KEY",
}
def generate_secrets(environ, secrets):
for name, secret in secrets.items():
if secret not in environ:
filename = "/data/%s.%s.key" % (environ["SYNAPSE_SERVER_NAME"], name)
# if the file already exists, load in the existing value; otherwise,
# generate a new secret and write it to a file
if os.path.exists(filename):
log("Reading %s from %s" % (secret, filename))
with open(filename) as handle:
value = handle.read()
with open(filename) as handle: value = handle.read()
else:
log("Generating a random secret for {}".format(secret))
print("Generating a random secret for {}".format(name))
value = codecs.encode(os.urandom(32), "hex").decode()
with open(filename, "w") as handle:
handle.write(value)
with open(filename, "w") as handle: handle.write(value)
environ[secret] = value
environ["SYNAPSE_APPSERVICES"] = glob.glob("/data/appservices/*.yaml")
if not os.path.exists(config_dir):
os.mkdir(config_dir)
# Prepare the configuration
mode = sys.argv[1] if len(sys.argv) > 1 else None
environ = os.environ.copy()
ownership = "{}:{}".format(environ.get("UID", 991), environ.get("GID", 991))
args = ["python", "-m", "synapse.app.homeserver"]
# Convert SYNAPSE_NO_TLS to boolean if exists
if "SYNAPSE_NO_TLS" in environ:
tlsanswerstring = str.lower(environ["SYNAPSE_NO_TLS"])
if tlsanswerstring in ("true", "on", "1", "yes"):
environ["SYNAPSE_NO_TLS"] = True
else:
if tlsanswerstring in ("false", "off", "0", "no"):
environ["SYNAPSE_NO_TLS"] = False
else:
error(
'Environment variable "SYNAPSE_NO_TLS" found but value "'
+ tlsanswerstring
+ '" unrecognized; exiting.'
)
if "SYNAPSE_LOG_CONFIG" not in environ:
environ["SYNAPSE_LOG_CONFIG"] = config_dir + "/log.config"
log("Generating synapse config file " + config_path)
convert("/conf/homeserver.yaml", config_path, environ)
log_config_file = environ["SYNAPSE_LOG_CONFIG"]
log("Generating log config file " + log_config_file)
convert("/conf/log.config", log_config_file, environ)
subprocess.check_output(["chown", "-R", ownership, "/data"])
# Hopefully we already have a signing key, but generate one if not.
subprocess.check_output(
[
"su-exec",
ownership,
"python",
"-m",
"synapse.app.homeserver",
"--config-path",
config_path,
# tell synapse to put generated keys in /data rather than /compiled
"--keys-directory",
config_dir,
"--generate-keys",
]
)
def run_generate_config(environ, ownership):
"""Run synapse with a --generate-config param to generate a template config file
Args:
environ (dict): env var dict
ownership (str): "userid:groupid" arg for chmod
Never returns.
"""
for v in ("SYNAPSE_SERVER_NAME", "SYNAPSE_REPORT_STATS"):
if v not in environ:
error("Environment variable '%s' is mandatory in `generate` mode." % (v,))
server_name = environ["SYNAPSE_SERVER_NAME"]
config_dir = environ.get("SYNAPSE_CONFIG_DIR", "/data")
config_path = environ.get("SYNAPSE_CONFIG_PATH", config_dir + "/homeserver.yaml")
data_dir = environ.get("SYNAPSE_DATA_DIR", "/data")
# create a suitable log config from our template
log_config_file = "%s/%s.log.config" % (config_dir, server_name)
if not os.path.exists(log_config_file):
log("Creating log config %s" % (log_config_file,))
convert("/conf/log.config", log_config_file, environ)
# make sure that synapse has perms to write to the data dir.
subprocess.check_output(["chown", ownership, data_dir])
args = [
"python",
"-m",
"synapse.app.homeserver",
"--server-name",
server_name,
"--report-stats",
environ["SYNAPSE_REPORT_STATS"],
"--config-path",
config_path,
"--config-directory",
config_dir,
"--data-directory",
data_dir,
"--generate-config",
"--open-private-ports",
# In generate mode, generate a configuration, missing keys, then exit
if mode == "generate":
check_arguments(environ, ("SYNAPSE_SERVER_NAME", "SYNAPSE_REPORT_STATS", "SYNAPSE_CONFIG_PATH"))
args += [
"--server-name", environ["SYNAPSE_SERVER_NAME"],
"--report-stats", environ["SYNAPSE_REPORT_STATS"],
"--config-path", environ["SYNAPSE_CONFIG_PATH"],
"--generate-config"
]
# log("running %s" % (args, ))
os.execv("/usr/local/bin/python", args)
def main(args, environ):
mode = args[1] if len(args) > 1 else None
ownership = "{}:{}".format(environ.get("UID", 991), environ.get("GID", 991))
# In generate mode, generate a configuration and missing keys, then exit
if mode == "generate":
return run_generate_config(environ, ownership)
if mode == "migrate_config":
# generate a config based on environment vars.
config_dir = environ.get("SYNAPSE_CONFIG_DIR", "/data")
config_path = environ.get(
"SYNAPSE_CONFIG_PATH", config_dir + "/homeserver.yaml"
)
return generate_config_from_template(
config_dir, config_path, environ, ownership
)
if mode is not None:
error("Unknown execution mode '%s'" % (mode,))
if "SYNAPSE_SERVER_NAME" in environ:
# backwards-compatibility generate-a-config-on-the-fly mode
if "SYNAPSE_CONFIG_PATH" in environ:
error(
"SYNAPSE_SERVER_NAME and SYNAPSE_CONFIG_PATH are mutually exclusive "
"except in `generate` or `migrate_config` mode."
)
# In normal mode, generate missing keys if any, then run synapse
else:
if "SYNAPSE_CONFIG_PATH" in environ:
config_path = environ["SYNAPSE_CONFIG_PATH"]
else:
check_arguments(environ, ("SYNAPSE_SERVER_NAME", "SYNAPSE_REPORT_STATS"))
generate_secrets(environ, {
"registration": "SYNAPSE_REGISTRATION_SHARED_SECRET",
"macaroon": "SYNAPSE_MACAROON_SECRET_KEY"
})
environ["SYNAPSE_APPSERVICES"] = glob.glob("/data/appservices/*.yaml")
if not os.path.exists("/compiled"): os.mkdir("/compiled")
config_path = "/compiled/homeserver.yaml"
log(
"Generating config file '%s' on-the-fly from environment variables.\n"
"Note that this mode is deprecated. You can migrate to a static config\n"
"file by running with 'migrate_config'. See the README for more details."
% (config_path,)
)
# Convert SYNAPSE_NO_TLS to boolean if exists
if "SYNAPSE_NO_TLS" in environ:
tlsanswerstring = str.lower(environ["SYNAPSE_NO_TLS"])
if tlsanswerstring in ("true", "on", "1", "yes"):
environ["SYNAPSE_NO_TLS"] = True
else:
if tlsanswerstring in ("false", "off", "0", "no"):
environ["SYNAPSE_NO_TLS"] = False
else:
print("Environment variable \"SYNAPSE_NO_TLS\" found but value \"" + tlsanswerstring + "\" unrecognized; exiting.")
sys.exit(2)
generate_config_from_template("/compiled", config_path, environ, ownership)
else:
config_dir = environ.get("SYNAPSE_CONFIG_DIR", "/data")
config_path = environ.get(
"SYNAPSE_CONFIG_PATH", config_dir + "/homeserver.yaml"
)
if not os.path.exists(config_path):
error(
"Config file '%s' does not exist. You should either create a new "
"config file by running with the `generate` argument (and then edit "
"the resulting file before restarting) or specify the path to an "
"existing config file with the SYNAPSE_CONFIG_PATH variable."
% (config_path,)
)
convert("/conf/homeserver.yaml", config_path, environ)
convert("/conf/log.config", "/compiled/log.config", environ)
subprocess.check_output(["chown", "-R", ownership, "/data"])
log("Starting synapse with config file " + config_path)
args = [
"su-exec",
ownership,
"python",
"-m",
"synapse.app.homeserver",
"--config-path",
config_path,
args += [
"--config-path", config_path,
# tell synapse to put any generated keys in /data rather than /compiled
"--keys-directory", "/data",
]
os.execv("/sbin/su-exec", args)
if __name__ == "__main__":
main(sys.argv, os.environ)
# Generate missing keys and start synapse
subprocess.check_output(args + ["--generate-keys"])
os.execv("/sbin/su-exec", ["su-exec", ownership] + args)

View File

@@ -14,7 +14,7 @@ upgraded, however it may be of use to those with old installs returning to the
project.
If you are setting up a server from scratch you almost certainly should look at
the [installation guide](../INSTALL.md) instead.
the [installation guide](INSTALL.md) instead.
## Introduction
The goal of Synapse 0.99.0 is to act as a stepping stone to Synapse 1.0.0. It

View File

@@ -1,60 +1,43 @@
# Code Style
- Everything should comply with PEP8. Code should pass
``pep8 --max-line-length=100`` without any warnings.
The Synapse codebase uses a number of code formatting tools in order to
quickly and automatically check for formatting (and sometimes logical) errors
in code.
- **Indenting**:
The necessary tools are detailed below.
- NEVER tabs. 4 spaces to indent.
## Formatting tools
- follow PEP8; either hanging indent or multiline-visual indent depending
on the size and shape of the arguments and what makes more sense to the
author. In other words, both this::
The Synapse codebase uses [black](https://pypi.org/project/black/) as an
opinionated code formatter, ensuring all comitted code is properly
formatted.
print("I am a fish %s" % "moo")
First install ``black`` with::
and this::
pip install --upgrade black
print("I am a fish %s" %
"moo")
Have ``black`` auto-format your code (it shouldn't change any
functionality) with::
and this::
black . --exclude="\.tox|build|env"
print(
"I am a fish %s" %
"moo",
)
- **flake8**
...are valid, although given each one takes up 2x more vertical space than
the previous, it's up to the author's discretion as to which layout makes
most sense for their function invocation. (e.g. if they want to add
comments per-argument, or put expressions in the arguments, or group
related arguments together, or want to deliberately extend or preserve
vertical/horizontal space)
``flake8`` is a code checking tool. We require code to pass ``flake8`` before being merged into the codebase.
- **Line length**:
Install ``flake8`` with::
Max line length is 79 chars (with flexibility to overflow by a "few chars" if
the overflowing content is not semantically significant and avoids an
explosion of vertical whitespace).
pip install --upgrade flake8
Check all application and test code with::
flake8 synapse tests
- **isort**
``isort`` ensures imports are nicely formatted, and can suggest and
auto-fix issues such as double-importing.
Install ``isort`` with::
pip install --upgrade isort
Auto-fix imports with::
isort -rc synapse tests
``-rc`` means to recursively search the given directories.
It's worth noting that modern IDEs and text editors can run these tools
automatically on save. It may be worth looking into whether this
functionality is supported in your editor for a more convenient development
workflow. It is not, however, recommended to run ``flake8`` on save as it
takes a while and is very resource intensive.
## General rules
Use parentheses instead of ``\`` for line continuation where ever possible
(which is pretty much everywhere).
- **Naming**:
@@ -63,6 +46,26 @@ takes a while and is very resource intensive.
- Use double quotes ``"foo"`` rather than single quotes ``'foo'``.
- **Blank lines**:
- There should be max a single new line between:
- statements
- functions in a class
- There should be two new lines between:
- definitions in a module (e.g., between different classes)
- **Whitespace**:
There should be spaces where spaces should be and not where there shouldn't
be:
- a single space after a comma
- a single space before and after for '=' when used as assignment
- no spaces before and after for '=' for default values and keyword arguments.
- **Comments**: should follow the `google code style
<http://google.github.io/styleguide/pyguide.html?showone=Comments#Comments>`_.
This is so that we can generate documentation with `sphinx
@@ -73,7 +76,7 @@ takes a while and is very resource intensive.
- **Imports**:
- Prefer to import classes and functions rather than packages or modules.
- Prefer to import classes and functions than packages or modules.
Example::

View File

@@ -1,7 +1,7 @@
Using Postgres
--------------
Postgres version 9.5 or later is known to work.
Postgres version 9.4 or later is known to work.
Install postgres client libraries
=================================
@@ -16,7 +16,7 @@ a postgres database.
* For other pre-built packages, please consult the documentation from the
relevant package.
* If you installed synapse `in a virtualenv
* If you installed synapse `in a virtualenv
<../INSTALL.md#installing-from-source>`_, you can install the library with::
~/synapse/env/bin/pip install matrix-synapse[postgres]

View File

@@ -89,10 +89,8 @@ Let's assume that we expect clients to connect to our server at
bind :::443 v4v6 ssl crt /etc/ssl/haproxy/ strict-sni alpn h2,http/1.1
# Matrix client traffic
acl matrix-host hdr(host) -i matrix.example.com
acl matrix-path path_beg /_matrix
use_backend matrix if matrix-host matrix-path
acl matrix hdr(host) -i matrix.example.com
use_backend matrix if matrix
frontend matrix-federation
bind :::8448 v4v6 ssl crt /etc/ssl/haproxy/synapse.pem alpn h2,http/1.1

View File

@@ -23,6 +23,29 @@ server_name: "SERVERNAME"
#
pid_file: DATADIR/homeserver.pid
# CPU affinity mask. Setting this restricts the CPUs on which the
# process will be scheduled. It is represented as a bitmask, with the
# lowest order bit corresponding to the first logical CPU and the
# highest order bit corresponding to the last logical CPU. Not all CPUs
# may exist on a given system but a mask may specify more CPUs than are
# present.
#
# For example:
# 0x00000001 is processor #0,
# 0x00000003 is processors #0 and #1,
# 0xFFFFFFFF is all processors (#0 through #31).
#
# Pinning a Python process to a single CPU is desirable, because Python
# is inherently single-threaded due to the GIL, and can suffer a
# 30-40% slowdown due to cache blow-out and thread context switching
# if the scheduler happens to schedule the underlying threads across
# different cores. See
# https://www.mirantis.com/blog/improve-performance-python-programs-restricting-single-cpu/.
#
# This setting requires the affinity package to be installed!
#
#cpu_affinity: 0xFFFFFFFF
# The path to the web client which will be served at /_matrix/client/
# if 'webclient' is configured under the 'listeners' configuration.
#
@@ -213,7 +236,7 @@ listeners:
- names: [client, federation]
compress: false
# example additional_resources:
# example additonal_resources:
#
#additional_resources:
# "/_matrix/my/custom/endpoint":
@@ -289,6 +312,74 @@ listeners:
#
#allow_per_room_profiles: false
# Whether to show the users on this homeserver in the user directory. Defaults to
# 'true'.
#
#show_users_in_user_directory: false
# Message retention policy at the server level.
#
# Room admins and mods can define a retention period for their rooms using the
# 'm.room.retention' state event, and server admins can cap this period by setting
# the 'allowed_lifetime_min' and 'allowed_lifetime_max' config options.
#
# If this feature is enabled, Synapse will regularly look for and purge events
# which are older than the room's maximum retention period. Synapse will also
# filter events received over federation so that events that should have been
# purged are ignored and not stored again.
#
retention:
# The message retention policies feature is disabled by default. Uncomment the
# following line to enable it.
#
#enabled: true
# Default retention policy. If set, Synapse will apply it to rooms that lack the
# 'm.room.retention' state event. Currently, the value of 'min_lifetime' doesn't
# matter much because Synapse doesn't take it into account yet.
#
#default_policy:
# min_lifetime: 1d
# max_lifetime: 1y
# Retention policy limits. If set, a user won't be able to send a
# 'm.room.retention' event which features a 'min_lifetime' or a 'max_lifetime'
# that's not within this range. This is especially useful in closed federations,
# in which server admins can make sure every federating server applies the same
# rules.
#
#allowed_lifetime_min: 1d
#allowed_lifetime_max: 1y
# Server admins can define the settings of the background jobs purging the
# events which lifetime has expired under the 'purge_jobs' section.
#
# If no configuration is provided, a single job will be set up to delete expired
# events in every room daily.
#
# Each job's configuration defines which range of message lifetimes the job
# takes care of. For example, if 'shortest_max_lifetime' is '2d' and
# 'longest_max_lifetime' is '3d', the job will handle purging expired events in
# rooms whose state defines a 'max_lifetime' that's both higher than 2 days, and
# lower than or equal to 3 days. Both the minimum and the maximum value of a
# range are optional, e.g. a job with no 'shortest_max_lifetime' and a
# 'longest_max_lifetime' of '3d' will handle every room with a retention policy
# which 'max_lifetime' is lower than or equal to three days.
#
# The rationale for this per-job configuration is that some rooms might have a
# retention policy with a low 'max_lifetime', where history needs to be purged
# of outdated messages on a very frequent basis (e.g. every 5min), but not want
# that purge to be performed by a job that's iterating over every room it knows,
# which would be quite heavy on the server.
#
#purge_jobs:
# - shortest_max_lifetime: 1d
# longest_max_lifetime: 3d
# interval: 5m:
# - shortest_max_lifetime: 3d
# longest_max_lifetime: 1y
# interval: 24h
## TLS ##
@@ -317,15 +408,6 @@ listeners:
#
#federation_verify_certificates: false
# The minimum TLS version that will be used for outbound federation requests.
#
# Defaults to `1`. Configurable to `1`, `1.1`, `1.2`, or `1.3`. Note
# that setting this value higher than `1.2` will prevent federation to most
# of the public Matrix network: only configure it to `1.3` if you have an
# entirely private federation setup and you can ensure TLS 1.3 support.
#
#federation_client_minimum_tls_version: 1.2
# Skip federation certificate verification on the following whitelist
# of domains.
#
@@ -415,13 +497,6 @@ acme:
#
#domain: matrix.example.com
# file to use for the account key. This will be generated if it doesn't
# exist.
#
# If unspecified, we will use CONFDIR/client.key.
#
account_key_file: DATADIR/acme_account.key
# List of allowed TLS fingerprints for this server to publish along
# with the signing keys for this server. Other matrix servers that
# make HTTPS requests to this server will check that the TLS
@@ -785,6 +860,16 @@ uploads_path: "DATADIR/uploads"
# period: 6w
# renew_at: 1w
# renew_email_subject: "Renew your %(app)s account"
# # Directory in which Synapse will try to find the HTML files to serve to the
# # user when trying to renew an account. Optional, defaults to
# # synapse/res/templates.
# template_dir: "res/templates"
# # HTML to be displayed to the user after they successfully renewed their
# # account. Optional.
# account_renewed_html_path: "account_renewed.html"
# # HTML to be displayed when the user tries to renew an account with an invalid
# # renewal token. Optional.
# invalid_token_html_path: "invalid_token.html"
# The user must provide all of the below types of 3PID when registering.
#
@@ -797,9 +882,32 @@ uploads_path: "DATADIR/uploads"
#
#disable_msisdn_registration: true
# Derive the user's matrix ID from a type of 3PID used when registering.
# This overrides any matrix ID the user proposes when calling /register
# The 3PID type should be present in registrations_require_3pid to avoid
# users failing to register if they don't specify the right kind of 3pid.
#
#register_mxid_from_3pid: email
# Uncomment to set the display name of new users to their email address,
# rather than using the default heuristic.
#
#register_just_use_email_for_display_name: true
# Mandate that users are only allowed to associate certain formats of
# 3PIDs with accounts on this server.
#
# Use an Identity Server to establish which 3PIDs are allowed to register?
# Overrides allowed_local_3pids below.
#
#check_is_for_allowed_local_3pids: matrix.org
#
# If you are using an IS you can also check whether that IS registers
# pending invites for the given 3PID (and then allow it to sign up on
# the platform):
#
#allow_invited_3pids: False
#
#allowed_local_3pids:
# - medium: email
# pattern: '.*@matrix\.org'
@@ -808,6 +916,11 @@ uploads_path: "DATADIR/uploads"
# - medium: msisdn
# pattern: '\+44'
# If true, stop users from trying to change the 3PIDs associated with
# their accounts.
#
#disable_3pid_changes: False
# Enable 3PIDs lookup requests to identity servers from this server.
#
#enable_3pid_lookup: true
@@ -849,6 +962,30 @@ uploads_path: "DATADIR/uploads"
# - matrix.org
# - vector.im
# If enabled, user IDs, display names and avatar URLs will be replicated
# to this server whenever they change.
# This is an experimental API currently implemented by sydent to support
# cross-homeserver user directories.
#
#replicate_user_profiles_to: example.com
# If specified, attempt to replay registrations, profile changes & 3pid
# bindings on the given target homeserver via the AS API. The HS is authed
# via a given AS token.
#
#shadow_server:
# hs_url: https://shadow.example.com
# hs: shadow.example.com
# as_token: 12u394refgbdhivsia
# If enabled, don't let users set their own display names/avatars
# other than for the very first time (unless they are a server admin).
# Useful when provisioning users based on the contents of a 3rd party
# directory and to avoid ambiguities.
#
#disable_set_displayname: False
#disable_set_avatar_url: False
# Users who register on this homeserver will automatically be joined
# to these rooms
#
@@ -997,12 +1134,6 @@ signing_key_path: "CONFDIR/SERVERNAME.signing.key"
# so it is not normally necessary to specify them unless you need to
# override them.
#
# Once SAML support is enabled, a metadata file will be exposed at
# https://<server>:<port>/_matrix/saml2/metadata.xml, which you may be able to
# use to configure your SAML IdP with. Alternatively, you can manually configure
# the IdP to use an ACS location of
# https://<server>:<port>/_matrix/saml2/authn_response.
#
#saml2_config:
# sp_config:
# # point this to the IdP's metadata. You can use either a local file or
@@ -1012,15 +1143,7 @@ signing_key_path: "CONFDIR/SERVERNAME.signing.key"
# remote:
# - url: https://our_idp/metadata.xml
#
# # By default, the user has to go to our login page first. If you'd like to
# # allow IdP-initiated login, set 'allow_unsolicited: True' in a
# # 'service.sp' section:
# #
# #service:
# # sp:
# # allow_unsolicited: True
#
# # The examples below are just used to generate our metadata xml, and you
# # The rest of sp_config is just used to generate our metadata xml, and you
# # may well not need it, depending on your setup. Alternatively you
# # may need a whole lot more detail - see the pysaml2 docs!
#
@@ -1043,12 +1166,6 @@ signing_key_path: "CONFDIR/SERVERNAME.signing.key"
# # separate pysaml2 configuration file:
# #
# config_path: "CONFDIR/sp_conf.py"
#
# # the lifetime of a SAML session. This defines how long a user has to
# # complete the authentication process, if allow_unsolicited is unset.
# # The default is 5 minutes.
# #
# # saml_session_lifetime: 5m
@@ -1075,17 +1192,41 @@ password_config:
#
#enabled: false
# Uncomment to disable authentication against the local password
# database. This is ignored if `enabled` is false, and is only useful
# if you have other password_providers.
#
#localdb_enabled: false
# Uncomment and change to a secret random string for extra security.
# DO NOT CHANGE THIS AFTER INITIAL SETUP!
#
#pepper: "EVEN_MORE_SECRET"
# Define and enforce a password policy. Each parameter is optional, boolean
# parameters default to 'false' and integer parameters default to 0.
# This is an early implementation of MSC2000.
#
#policy:
# Whether to enforce the password policy.
#
#enabled: true
# Minimum accepted length for a password.
#
#minimum_length: 15
# Whether a password must contain at least one digit.
#
#require_digit: true
# Whether a password must contain at least one symbol.
# A symbol is any character that's not a number or a letter.
#
#require_symbol: true
# Whether a password must contain at least one lowercase letter.
#
#require_lowercase: true
# Whether a password must contain at least one lowercase letter.
#
#require_uppercase: true
# Enable sending emails for password resets, notification events or
@@ -1105,13 +1246,11 @@ password_config:
# app_name: Matrix
#
# # Enable email notifications by default
# #
# notif_for_new_users: True
#
# # Defining a custom URL for Riot is only needed if email notifications
# # should contain links to a self-hosted installation of Riot; when set
# # the "app_name" setting is ignored
# #
# riot_base_url: "http://localhost/riot"
#
# # Enable sending password reset emails via the configured, trusted
@@ -1124,22 +1263,16 @@ password_config:
# #
# # If this option is set to false and SMTP options have not been
# # configured, resetting user passwords via email will be disabled
# #
# #trust_identity_server_for_password_resets: false
#
# # Configure the time that a validation email or text message code
# # will expire after sending
# #
# # This is currently used for password resets
# #
# #validation_token_lifetime: 1h
#
# # Template directory. All template files should be stored within this
# # directory. If not set, default templates from within the Synapse
# # package will be used
# #
# # For the list of default templates, please see
# # https://github.com/matrix-org/synapse/tree/master/synapse/res/templates
# # directory
# #
# #template_dir: res/templates
#
@@ -1230,6 +1363,11 @@ password_config:
#user_directory:
# enabled: true
# search_all_users: false
#
# # If this is set, user search will be delegated to this ID server instead
# # of synapse performing the search itself.
# # This is an experimental API.
# defer_to_id_server: https://id.example.com
# User Consent configuration

View File

@@ -18,220 +18,226 @@ import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(".."))
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.coverage",
"sphinx.ext.ifconfig",
"sphinxcontrib.napoleon",
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.ifconfig',
'sphinxcontrib.napoleon',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = ".rst"
source_suffix = '.rst'
# The encoding of source files.
# source_encoding = 'utf-8-sig'
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
master_doc = 'index'
# General information about the project.
project = "Synapse"
copyright = (
"Copyright 2014-2017 OpenMarket Ltd, 2017 Vector Creations Ltd, 2017 New Vector Ltd"
)
project = u'Synapse'
copyright = u'Copyright 2014-2017 OpenMarket Ltd, 2017 Vector Creations Ltd, 2017 New Vector Ltd'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "1.0"
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = "1.0"
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
#today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "default"
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
#html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
#html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
#html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
#html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = "Synapsedoc"
htmlhelp_basename = 'Synapsedoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [("index", "Synapse.tex", "Synapse Documentation", "TNG", "manual")]
latex_documents = [
('index', 'Synapse.tex', u'Synapse Documentation',
u'TNG', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
#latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
#latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [("index", "synapse", "Synapse Documentation", ["TNG"], 1)]
man_pages = [
('index', 'synapse', u'Synapse Documentation',
[u'TNG'], 1)
]
# If true, show URL addresses after external links.
# man_show_urls = False
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -240,32 +246,26 @@ man_pages = [("index", "synapse", "Synapse Documentation", ["TNG"], 1)]
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
"index",
"Synapse",
"Synapse Documentation",
"TNG",
"Synapse",
"One line description of project.",
"Miscellaneous",
)
('index', 'Synapse', u'Synapse Documentation',
u'TNG', 'Synapse', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
#texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
#texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {"http://docs.python.org/": None}
intersphinx_mapping = {'http://docs.python.org/': None}
napoleon_include_special_with_doc = True
napoleon_use_ivar = True

View File

@@ -239,13 +239,6 @@ be routed to the same instance::
^/_matrix/client/(r0|unstable)/register$
Pagination requests can also be handled, but all requests with the same path
room must be routed to the same instance. Additionally, care must be taken to
ensure that the purge history admin API is not used while pagination requests
for the room are in flight::
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/messages$
``synapse.app.user_dir``
~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -28,22 +28,3 @@
directory = "misc"
name = "Internal Changes"
showcontent = true
[tool.black]
target-version = ['py34']
exclude = '''
(
/(
\.eggs # exclude a few common directories in the
| \.git # root of the project
| \.tox
| \.venv
| _build
| _trial_temp.*
| build
| dist
| debian
)/
)
'''

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,11 +39,11 @@ def check_auth(auth, auth_chain, events):
print("Success:", e.event_id, e.type, e.state_key)
if __name__ == "__main__":
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()

View File

@@ -0,0 +1,54 @@
import argparse
import hashlib
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):
def __init__(self, *args, **kargs):
dict.__init__(self, *args, **kargs)
self.__dict__ = self
def get_dict(self):
return dict(self)
def get_full_dict(self):
return dict(self)
def get_pdu_json(self):
return dict(self)
def main():
parser = argparse.ArgumentParser()
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}
for alg_name in event_json.hashes:
if check_event_content_hash(event_json, algorithms[alg_name]):
print("PASS content hash %s" % (alg_name,))
else:
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)))
if __name__ == "__main__":
main()

View File

@@ -1,3 +1,4 @@
import argparse
import json
import logging
@@ -39,7 +40,7 @@ def main():
parser = argparse.ArgumentParser()
parser.add_argument("signature_name")
parser.add_argument(
"input_json", nargs="?", type=argparse.FileType("r"), default=sys.stdin
"input_json", nargs="?", type=argparse.FileType('r'), default=sys.stdin
)
args = parser.parse_args()
@@ -68,5 +69,5 @@ def main():
print("FAIL %s" % (key_id,))
if __name__ == "__main__":
if __name__ == '__main__':
main()

View File

@@ -116,5 +116,5 @@ def main():
connection.commit()
if __name__ == "__main__":
if __name__ == '__main__':
main()

View File

@@ -19,10 +19,10 @@ class DefinitionVisitor(ast.NodeVisitor):
self.names = {}
self.attrs = set()
self.definitions = {
"def": self.functions,
"class": self.classes,
"names": self.names,
"attrs": self.attrs,
'def': self.functions,
'class': self.classes,
'names': self.names,
'attrs': self.attrs,
}
def visit_Name(self, node):
@@ -47,23 +47,23 @@ class DefinitionVisitor(ast.NodeVisitor):
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()}
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
result['def'] = functions
if classes:
result["class"] = classes
names = defs["names"]
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", ()):
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"])
uses.extend(defs['attrs'])
if uses:
result["uses"] = uses
result["names"] = names
result["attrs"] = defs["attrs"]
result['uses'] = uses
result['names'] = names
result['attrs'] = defs['attrs']
return result
@@ -81,33 +81,33 @@ def definitions_in_file(filepath):
def defined_names(prefix, defs, names):
for name, funcs in defs.get("def", {}).items():
names.setdefault(name, {"defined": []})["defined"].append(prefix + name)
for name, funcs in defs.get('def', {}).items():
names.setdefault(name, {'defined': []})['defined'].append(prefix + name)
defined_names(prefix + name + ".", funcs, names)
for name, funcs in defs.get("class", {}).items():
names.setdefault(name, {"defined": []})["defined"].append(prefix + name)
for name, funcs in defs.get('class', {}).items():
names.setdefault(name, {'defined': []})['defined'].append(prefix + name)
defined_names(prefix + name + ".", funcs, names)
def used_names(prefix, item, defs, names):
for name, funcs in defs.get("def", {}).items():
for name, funcs in defs.get('def', {}).items():
used_names(prefix + name + ".", name, funcs, names)
for name, funcs in defs.get("class", {}).items():
for name, funcs in defs.get('class', {}).items():
used_names(prefix + name + ".", name, funcs, names)
path = prefix.rstrip(".")
for used in defs.get("uses", ()):
path = prefix.rstrip('.')
for used in defs.get('uses', ()):
if used in names:
if item:
names[item].setdefault("uses", []).append(used)
names[used].setdefault("used", {}).setdefault(item, []).append(path)
names[item].setdefault('uses', []).append(used)
names[used].setdefault('used', {}).setdefault(item, []).append(path)
if __name__ == "__main__":
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Find definitions.")
parser = argparse.ArgumentParser(description='Find definitions.')
parser.add_argument(
"--unused", action="store_true", help="Only list unused definitions"
)
@@ -119,7 +119,7 @@ if __name__ == "__main__":
)
parser.add_argument(
"directories",
nargs="+",
nargs='+',
metavar="DIR",
help="Directories to search for definitions",
)
@@ -164,7 +164,7 @@ if __name__ == "__main__":
continue
if ignore and any(pattern.match(name) for pattern in ignore):
continue
if args.unused and definition.get("used"):
if args.unused and definition.get('used'):
continue
result[name] = definition
@@ -196,9 +196,9 @@ if __name__ == "__main__":
continue
result[name] = definition
if args.format == "yaml":
if args.format == 'yaml':
yaml.dump(result, sys.stdout, default_flow_style=False)
elif args.format == "dot":
elif args.format == 'dot':
print("digraph {")
for name, entry in result.items():
print(name)

View File

@@ -21,8 +21,7 @@ import argparse
import base64
import json
import sys
from six.moves.urllib import parse as urlparse
from urlparse import urlparse, urlunparse
import nacl.signing
import requests
@@ -63,7 +62,7 @@ def encode_canonical_json(value):
# Encode code-points outside of ASCII as UTF-8 rather than \u escapes
ensure_ascii=False,
# Remove unecessary white space.
separators=(",", ":"),
separators=(',', ':'),
# Sort the keys of dictionaries.
sort_keys=True,
# Encode the resulting unicode as UTF-8 bytes.
@@ -145,8 +144,8 @@ 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)
authorization_headers.append(header.encode("ascii"))
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)
dest = "matrix://%s%s" % (destination, path)
@@ -161,7 +160,11 @@ def request_json(method, origin_name, origin_key, destination, path, content):
headers["Content-Type"] = "application/json"
result = s.request(
method=method, url=dest, headers=headers, verify=False, data=content
method=method,
url=dest,
headers=headers,
verify=False,
data=content,
)
sys.stderr.write("Status Code: %d\n" % (result.status_code,))
return result.json()
@@ -237,18 +240,18 @@ def main():
def read_args_from_config(args):
with open(args.config, "r") as fh:
with open(args.config, 'r') as fh:
config = yaml.safe_load(fh)
if not args.server_name:
args.server_name = config["server_name"]
args.server_name = config['server_name']
if not args.signing_key_path:
args.signing_key_path = config["signing_key_path"]
args.signing_key_path = config['signing_key_path']
class MatrixConnectionAdapter(HTTPAdapter):
@staticmethod
def lookup(s, skip_well_known=False):
if s[-1] == "]":
def lookup(s):
if s[-1] == ']':
# ipv6 literal (with no port)
return s, 8448
@@ -260,49 +263,19 @@ class MatrixConnectionAdapter(HTTPAdapter):
raise ValueError("Invalid host:port '%s'" % s)
return out[0], port
# try a .well-known lookup
if not skip_well_known:
well_known = MatrixConnectionAdapter.get_well_known(s)
if well_known:
return MatrixConnectionAdapter.lookup(well_known, skip_well_known=True)
try:
srv = srvlookup.lookup("matrix", "tcp", s)[0]
return srv.host, srv.port
except Exception:
return s, 8448
@staticmethod
def get_well_known(server_name):
uri = "https://%s/.well-known/matrix/server" % (server_name,)
print("fetching %s" % (uri,), file=sys.stderr)
try:
resp = requests.get(uri)
if resp.status_code != 200:
print("%s gave %i" % (uri, resp.status_code), file=sys.stderr)
return None
parsed_well_known = resp.json()
if not isinstance(parsed_well_known, dict):
raise Exception("not a dict")
if "m.server" not in parsed_well_known:
raise Exception("Missing key 'm.server'")
new_name = parsed_well_known["m.server"]
print("well-known lookup gave %s" % (new_name,), file=sys.stderr)
return new_name
except Exception as e:
print("Invalid response from %s: %s" % (uri, e), file=sys.stderr)
return None
def get_connection(self, url, proxies=None):
parsed = urlparse.urlparse(url)
parsed = urlparse(url)
(host, port) = self.lookup(parsed.netloc)
netloc = "%s:%d" % (host, port)
print("Connecting to %s" % (netloc,), file=sys.stderr)
url = urlparse.urlunparse(
url = urlunparse(
("https", netloc, parsed.path, parsed.params, parsed.query, parsed.fragment)
)
return super(MatrixConnectionAdapter, self).get_connection(url, proxies)

View File

@@ -79,5 +79,5 @@ def main():
conn.commit()
if __name__ == "__main__":
if __name__ == '__main__':
main()

View File

@@ -35,11 +35,11 @@ def find_patterns_in_file(filepath):
find_patterns_in_code(f.read())
parser = argparse.ArgumentParser(description="Find url patterns.")
parser = argparse.ArgumentParser(description='Find url patterns.')
parser.add_argument(
"directories",
nargs="+",
nargs='+',
metavar="DIR",
help="Directories to search for definitions",
)

View File

@@ -63,5 +63,5 @@ def main():
streams[update.name] = update.position
if __name__ == "__main__":
if __name__ == '__main__':
main()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
import argparse
import shutil

View File

@@ -16,7 +16,7 @@
import argparse
import sys
from signedjson.key import generate_signing_key, write_signing_keys
from signedjson.key import write_signing_keys, generate_signing_key
from synapse.util.stringutils import random_string
@@ -24,14 +24,14 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"-o",
"--output_file",
type=argparse.FileType("w"),
"-o", "--output_file",
type=argparse.FileType('w'),
default=sys.stdout,
help="Where to write the output to",
)
args = parser.parse_args()
key_id = "a_" + random_string(4)
key = (generate_signing_key(key_id),)
key = generate_signing_key(key_id),
write_signing_keys(args.output_file, key)

View File

@@ -50,7 +50,7 @@ def main(src_repo, dest_repo):
dest_paths = MediaFilePaths(dest_repo)
for line in sys.stdin:
line = line.strip()
parts = line.split("|")
parts = line.split('|')
if len(parts) != 2:
print("Unable to parse input line %s" % line, file=sys.stderr)
exit(1)
@@ -107,7 +107,7 @@ 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("-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()

View File

@@ -54,7 +54,6 @@ BOOLEAN_COLUMNS = {
"group_roles": ["is_public"],
"local_group_membership": ["is_publicised", "is_admin"],
"e2e_room_keys": ["is_verified"],
"account_validity": ["email_sent"],
}

View File

@@ -15,17 +15,18 @@ ignore =
tox.ini
[flake8]
max-line-length = 90
# 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
# E501: Line too long (black enforces this for us)
ignore=W503,W504,E203,E731,E501
ignore=W503,W504,E203,E731
[isort]
line_length = 88
line_length = 89
not_skip = __init__.py
sections=FUTURE,STDLIB,COMPAT,THIRDPARTY,TWISTED,FIRSTPARTY,TESTS,LOCALFOLDER
default_section=THIRDPARTY

View File

@@ -60,12 +60,9 @@ class TestCommand(Command):
pass
def run(self):
print(
"""Synapse's tests cannot be run via setup.py. To run them, try:
print ("""Synapse's tests cannot be run via setup.py. To run them, try:
PYTHONPATH="." trial tests
"""
)
""")
def read_file(path_segments):
"""Read a file from the package. Takes a list of strings to join to
@@ -87,9 +84,9 @@ version = exec_file(("synapse", "__init__.py"))["__version__"]
dependencies = exec_file(("synapse", "python_dependencies.py"))
long_description = read_file(("README.rst",))
REQUIREMENTS = dependencies["REQUIREMENTS"]
CONDITIONAL_REQUIREMENTS = dependencies["CONDITIONAL_REQUIREMENTS"]
ALL_OPTIONAL_REQUIREMENTS = dependencies["ALL_OPTIONAL_REQUIREMENTS"]
REQUIREMENTS = dependencies['REQUIREMENTS']
CONDITIONAL_REQUIREMENTS = dependencies['CONDITIONAL_REQUIREMENTS']
ALL_OPTIONAL_REQUIREMENTS = dependencies['ALL_OPTIONAL_REQUIREMENTS']
# Make `pip install matrix-synapse[all]` install all the optional dependencies.
CONDITIONAL_REQUIREMENTS["all"] = list(ALL_OPTIONAL_REQUIREMENTS)
@@ -105,16 +102,6 @@ setup(
include_package_data=True,
zip_safe=False,
long_description=long_description,
python_requires="~=3.5",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Topic :: Communications :: Chat",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
],
scripts=["synctl"] + glob.glob("scripts/*"),
cmdclass={"test": TestCommand},
cmdclass={'test': TestCommand},
)

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