Compare commits

...

96 Commits

Author SHA1 Message Date
RiotRobot acd4dcb56e v2.0.0 2019-05-31 10:29:21 +01:00
RiotRobot c170456cde Prepare changelog for v2.0.0 2019-05-31 10:29:20 +01:00
J. Ryan Stinnett 4e739e4b06 Merge pull request #932 from matrix-org/jryans/login-change-release
Saves access_token and user_id after login for all login types
2019-05-31 10:05:34 +01:00
J. Ryan Stinnett df1539040c Fix lint error in login.spec.js 2019-05-31 09:54:11 +01:00
Sergii Stotskyi 2a04459bb2 fix(login): saves access_token and user_id after login for all login types
Signed-off-by: Sergii Stotskyi <sergiy.stotskiy@gmail.com>

Fixes #876
2019-05-31 09:40:51 +01:00
J. Ryan Stinnett 6367bf7c75 Merge pull request #931 from matrix-org/jryans/key-backup-base-x
Fix recovery key encoding for base-x 3.0.5
2019-05-30 18:29:17 +01:00
J. Ryan Stinnett 8263062fab Fix recovery key encoding for base-x 3.0.5
This fixes our recovery key encoding to work with base-x 3.0.5, which requires the
encoding input to be in a `Buffer`. (base-x is a dependency of bs58.)

Unfortunately, base-x hasn't marked this as breaking change through a major
version increment, so semantic versioning can't help us here to ensure we get
particular version.

I have verified that the change to `Buffer` works with both old and new base-x,
so we should be okay no matter what version is actually selected.

For extra fun, base-x 3.0.5 also uses newer JS features, which `uglify-js`
doesn't support. I have migrated to `terser` instead, which is what we're using
for Riot these days (via Webpack).

Fixes https://github.com/vector-im/riot-web/issues/9901
2019-05-30 15:42:39 +01:00
RiotRobot a9543df6db v1.2.0 2019-05-29 15:52:20 +01:00
RiotRobot aae388be93 Prepare changelog for v1.2.0 2019-05-29 15:52:19 +01:00
RiotRobot 26a8439ce4 Upgrade jsdoc 2019-05-23 16:28:26 +01:00
RiotRobot 2c2e8fa1ac v1.2.0-rc.1 2019-05-23 16:11:35 +01:00
RiotRobot ddc2fa74b9 Prepare changelog for v1.2.0-rc.1 2019-05-23 16:11:35 +01:00
David Baker 93d51b83c3 Merge pull request #926 from matrix-org/dbkr/uiauth_send_email
interactive-auth now handles requesting email tokens
2019-05-22 14:24:08 +01:00
David Baker f83eae4a46 typing hard 2019-05-22 13:11:05 +01:00
David Baker 87c6d11fca PR feedback 2019-05-22 13:09:24 +01:00
David Baker e87ac86e48 interactive-auth now handles requesting email tokens
interactive-auth now has a callback to request the email token which
it will call at the appropriate time (now at the start of the
auth process if the chosen flow contain an email auth stage).

This does make this a breaking change, although not sure this is
used outside of Riot. We could make it backwards compatible by
having an option for the new behaviour. It may not be worthwhile
though.

https://github.com/vector-im/riot-web/issues/9586
2019-05-22 11:51:05 +01:00
Bruno Windels 7782e81101 Merge pull request #923 from matrix-org/bwindels/caneditcheckfix
allow access to unreplaced message content
2019-05-17 12:32:45 +00:00
Bruno Windels aa70687d9e allow access to unreplaced message content 2019-05-17 13:25:21 +01:00
Bruno Windels 38d32de06b Merge pull request #922 from matrix-org/bwindels/editedmarker
Add method to retrieve replacing event
2019-05-17 11:04:00 +00:00
Bruno Windels 7720c72b73 correct return type 2019-05-17 12:03:36 +01:00
Bruno Windels ff9505073f add method to retrieve replacing event 2019-05-17 11:56:28 +01:00
David Baker 21ee1c31a7 Merge pull request #921 from matrix-org/dbkr/really_log_useful_info_on_verify_failure
More logging when signature verification fails
2019-05-17 10:18:34 +01:00
David Baker fd01ba1fcf More logging when signature verification fails
Still no luck diagnosing https://github.com/vector-im/riot-web/issues/9357
so adding more logging.
2019-05-17 10:08:27 +01:00
Bruno Windels fbf53524ed Merge pull request #920 from matrix-org/bwindels/message-editing-local-echo
Local echo for m.replace relations
2019-05-16 15:22:12 +00:00
Bruno Windels 1f2a701ace remove double newline 2019-05-16 16:14:53 +01:00
Bruno Windels 0b87a573b3 reduce indenting by returning early, also actually pass replacement!
also add comment
2019-05-16 16:14:19 +01:00
Bruno Windels 74438716af PR feedback/cleanup 2019-05-16 15:54:15 +01:00
Bruno Windels d10b348e74 clear event replacement on redaction
as redaction supersedes a replacement
2019-05-16 15:53:46 +01:00
Bruno Windels 68e9be47d9 check if an incoming event is the target of a Relations 2019-05-16 15:49:55 +01:00
Bruno Windels bddd03c2fd separate setTargetEvent method
call makeReplaced from addEvent instead so it's all done from Relations
2019-05-16 15:48:03 +01:00
Bruno Windels e23ba50dd8 only call aggregation code for local echo for relations 2019-05-16 14:42:09 +01:00
Bruno Windels 261ab7ae68 don't block local echo for m.replace anymore! 2019-05-16 14:40:55 +01:00
Bruno Windels 21c8c76dc3 helper method to get sending status of event or replacement 2019-05-16 14:40:39 +01:00
Bruno Windels 266d0f9d05 remove flag for edits as it's not handled separately anymore 2019-05-16 14:40:17 +01:00
Bruno Windels 69d25c1498 emit from MatrixEvent.makeReplaced instead of Room
now that event can be replaced from Relations instead of Room

Also make `makeReplaced` non-destructive by not touching the original
event.content, so it can be undone by later calls.
2019-05-16 14:38:48 +01:00
Bruno Windels 3cd2b3925a re-evaluate last replacement on redaction and local echo cancellation 2019-05-16 14:36:38 +01:00
Bruno Windels 33e9eb371e use relation handling in timelineset for replacements 2019-05-16 14:35:50 +01:00
Bruno Windels 07572d1e8d helper method to get last valid replacement 2019-05-16 14:34:08 +01:00
Bruno Windels dde4f558f3 set targetEvent on Relations, once known 2019-05-16 14:33:24 +01:00
J. Ryan Stinnett 79d2574ea7 Merge pull request #919 from matrix-org/jryans/reactions-status-bar
Track relations as pending and remove when cancelled
2019-05-16 13:39:41 +01:00
J. Ryan Stinnett 51fb5c4a15 Update aggregation by sender on remove
This updates the aggregation by sender in the relations collection on removal.
It also changes this aggregation to use a Set, so consumers will need to update.
2019-05-16 12:40:19 +01:00
J. Ryan Stinnett 875c6b973b Remove cancelled relations from the relations collection
This listens for event status changes on sending events in case they might be
cancelled and removes them from aggregation if so.

Part of https://github.com/vector-im/riot-web/issues/9731
2019-05-16 12:29:28 +01:00
J. Ryan Stinnett 21e1312dd7 Allow relations into the pending event list
Relations actually should go into the pending event list, just like messages.
This is the easiest way to keep them in a holding area in case of unverified
devices, etc.

We still want the relations to local echo immediately, so we directly trigger
the aggregation on the timeline sets.
2019-05-16 12:26:36 +01:00
J. Ryan Stinnett a722ef3b03 Merge pull request #916 from matrix-org/jryans/stringify-events
Add stringify helper to summarise events when debugging
2019-05-16 09:44:39 +01:00
J. Ryan Stinnett 80ba5d29f2 Add stringify helper to summarise events when debugging 2019-05-16 09:31:19 +01:00
Bruno Windels a35e6a0f54 Merge pull request #918 from matrix-org/bwindels/message-edit-editor3
Message editing: filter out replacements for senders that are not the original sender
2019-05-15 17:21:03 +00:00
J. Ryan Stinnett bdc1958c08 Merge pull request #917 from matrix-org/jryans/encrypted-reactions
Wait until decrypt before aggregating
2019-05-15 17:26:07 +01:00
Bruno Windels 3f2bac71c6 filter out replacements for senders that are not the original sender 2019-05-15 15:52:37 +01:00
J. Ryan Stinnett 6b9a11b697 Wait until decrypt before aggregating
For encrypted annotations, we need to wait until the event has been decrypted
before adding it to the relations collection.
2019-05-15 15:48:33 +01:00
J. Ryan Stinnett f17ecba519 Add getRelation helper
This adds a `getRelation` helper to ensure we always read relation info from the
wire content as required in E2E rooms.
2019-05-15 15:48:33 +01:00
Bruno Windels ce0b014a5a Merge pull request #914 from matrix-org/bwindels/message-edit-editor2
Message editing: mark original event as replaced instead of replacing the event object
2019-05-15 14:11:38 +00:00
Bruno Windels ad48d2997e prevent earlier replacements from messing things up 2019-05-15 14:54:52 +01:00
Bruno Windels 1c1781ce76 make replacements work in e2e rooms 2019-05-15 14:54:21 +01:00
Bruno Windels 5fd001354a replace content when replacing instead of evaluating in getContent 2019-05-15 14:53:44 +01:00
Bruno Windels a18bdad44f dont replace a redacted event 2019-05-15 13:56:13 +01:00
Bruno Windels 600dff62e8 detect relations on encrypted events properly 2019-05-15 13:56:00 +01:00
Bruno Windels db7a402e9b mark original event as replaced instead of replacing the event object
this is more in line with what happens on the server-side,
and also doesn't break existing reply relations.
2019-05-15 12:05:39 +01:00
Bruno Windels 0e53f9052f Merge pull request #913 from matrix-org/bwindels/message-edit-editor
Support for replacing message through m.replace relationship.
2019-05-15 09:22:34 +00:00
Bruno Windels 62e69cacb7 remove leftover code, fix lint 2019-05-14 15:52:02 +01:00
Bruno Windels 852c88c341 add unstableClientRelationReplacements in js-sdk 2019-05-14 15:33:49 +01:00
Bruno Windels 455f52f1f5 remove logging 2019-05-14 15:25:47 +01:00
Bruno Windels df6012c58d completely avoid local echo for edits for now 2019-05-14 15:25:07 +01:00
Bruno Windels f68a3dde46 cleanup 2019-05-14 15:24:57 +01:00
Bruno Windels 25e6b1cac8 handle m.replace relations in room, emit Room.replaceEvent 2019-05-14 15:24:36 +01:00
Travis Ralston 4ad20526db Merge pull request #912 from matrix-org/travis/wk/timeouts
Use a short timeout for .well-known requests
2019-05-14 08:24:09 -06:00
Bruno Windels 18cd017f58 support marking an as replacing another
and take if the timestamp of the original event if so
also helper methods
2019-05-14 15:23:22 +01:00
Bruno Windels 0161664b6c add support for replacing an existing event in a timeline(set) 2019-05-14 15:22:46 +01:00
Travis Ralston 25df31bf96 Use a short timeout for .well-known requests
Applies to verification of the homeserver, identity server, and fetching of the .well-known objects. Does not affect other HTTP requests.

See https://github.com/vector-im/riot-web/issues/9290
2019-05-13 18:39:59 -06:00
Travis Ralston 09438b440e Fix spelling error in txnId for redactions
Fixes https://github.com/vector-im/riot-web/issues/9700
2019-05-13 13:43:44 -06:00
J. Ryan Stinnett 6a5f5b249e Merge pull request #911 from matrix-org/jryans/aggregations
Redaction and change events for relations
2019-05-13 15:20:15 +01:00
J. Ryan Stinnett 3a20114c39 Change to event-level beforeRedaction event for efficiency
To avoid an O(n^2) situation with every relations container trying to process
every redaction that may occur in a room, this switches to an event-level
notification, so that the specific relations container who cares can listen to
just the events it wants to know about.
2019-05-13 14:35:39 +01:00
J. Ryan Stinnett f411d50253 Clarify before redaction event timing 2019-05-13 14:17:23 +01:00
J. Ryan Stinnett 00851df25c Always add pending relation events to the timeline sets directly
This special cases pending relation events to go directly to the timeline sets
and ignores the `pendingEventOrdering` option. This feels a bit strange in the
code, so we should revisit this choice when we stabilized relation support.
2019-05-13 13:52:37 +01:00
J. Ryan Stinnett 8822d255b3 Fix indentation in src/models/event.js 2019-05-13 13:52:37 +01:00
J. Ryan Stinnett 4b4ba86167 Add Relations.add event for additional relations in collection
This adds a `Relations.add` event that consumers can listen for to be notified
each time an additional relation event is added to a relations collection.

Part of https://github.com/vector-im/riot-web/issues/9485
Part of https://github.com/vector-im/riot-web/issues/9572
2019-05-13 13:52:37 +01:00
J. Ryan Stinnett 7ea820f6e1 Add Event.relationsCreated event to listen for future relations collections
If you ask for relations but none currently exist, we return `null` to avoid the
overhead of many empty relations objects in memory. However, we still want some
way to alert consumers when one _is_ later made, so this event level event
provides that.

Part of https://github.com/vector-im/riot-web/issues/9572
Part of https://github.com/vector-im/riot-web/issues/9485
2019-05-13 13:52:37 +01:00
J. Ryan Stinnett 53d8cf0852 Update relation collections after redaction
This watches for redactions of relations and updates the relations collection
to match, including various aggregations. In addition, a redaction event is
emitted on the redaction collection to notify consumers of the change.

Part of https://github.com/vector-im/riot-web/issues/9574
Part of https://github.com/vector-im/riot-web/issues/9485
2019-05-13 13:52:37 +01:00
J. Ryan Stinnett 761806c678 Add support for class properties
This enables compiler and linting features to allow class properties like we do
in the React SDK.
2019-05-13 13:52:37 +01:00
J. Ryan Stinnett d6abd639f3 Merge pull request #910 from matrix-org/jryans/aggregations
Add basic read path for relations
2019-05-09 12:01:57 +01:00
J. Ryan Stinnett 6078bbbe24 Add basic read path for relations
This adds a read path for relations (gated behind an unstable option). A few
basic client-side grouping and sorting operations are supported. Consumers are
expected to ask the `EventTimelineSet` for a relation container when desired.
2019-05-08 18:05:52 +01:00
J. Ryan Stinnett c1c81df4de Intern rel_type for relations
In anticipation of relations being quite frequently used, we should intern
strings of common fields, such as `rel_type`.
2019-05-08 17:41:06 +01:00
David Baker ee8a4698a9 Merge branch 'master' into develop 2019-05-07 15:25:23 +01:00
David Baker c1956d3f05 v1.1.0 2019-05-07 15:23:32 +01:00
David Baker 56316dc5d9 Prepare changelog for v1.1.0 2019-05-07 15:23:32 +01:00
Travis Ralston b5c74b5666 Merge pull request #860 from matrix-org/travis/tombstone-notif
Add a concept of default push rules, using it for tombstone notifications
2019-05-03 11:21:37 -06:00
Travis Ralston dc946dffbc Add some words to explain why we do things the way we do 2019-05-03 11:19:46 -06:00
David Baker 937baadb9b Merge pull request #907 from matrix-org/dbkr/yarn_upgrade_may19
yarn upgrade
2019-05-03 12:00:03 +01:00
David Baker 8d0c03b4f0 Add customer resolution for base-x
to fix dependency version to 3.0.4 (ie. the version that exports
ES5 rather than ES6)
2019-05-03 11:46:11 +01:00
David Baker a3fba73044 Set base-x back to 3.0.4
3.0.5 exports ES6 which breaks the build.

Also specifically depending on version 3.0.4 in the package.json
doesn't look like it has the desired effect now (yarn just installs
two separate versions) so remove that.
2019-05-03 11:03:29 +01:00
David Baker 116cf31199 yarn upgrade 2019-05-03 10:50:23 +01:00
J. Ryan Stinnett cdb78e4c75 Remove noisy debug logs
The debug logs in the sync loop haven't been helpful so far, and they are quite
noisy pushing other logs out of the way, so this change removes them.
2019-04-30 15:43:54 +01:00
David Baker 0bb9c56e94 Merge branch 'develop' into release-v1.1.0 2019-04-30 11:50:24 +01:00
David Baker 821f1c876b Undo unintentional commenting 2019-04-30 11:48:38 +01:00
Travis Ralston 42f181cc7b Appease the linter 2019-03-15 14:11:29 -06:00
Travis Ralston b3d2d39b60 Add tombstone rule as a default rule in support of MSC1930
Part of https://github.com/vector-im/riot-web/issues/8447

See also https://github.com/matrix-org/matrix-doc/pull/1930
2019-03-15 14:07:15 -06:00
Travis Ralston e323d917a4 Support default push rules for when servers are outdated 2019-03-15 14:06:28 -06:00
51 changed files with 1513 additions and 660 deletions
+2
View File
@@ -1,6 +1,8 @@
{
"presets": ["es2015"],
"plugins": [
"transform-class-properties",
// this transforms async functions into generator functions, which
// are then made to use the regenerator module by babel's
// transform-regnerator plugin (which is enabled by es2015).
+8
View File
@@ -14,6 +14,9 @@ module.exports = {
es6: true,
},
extends: ["eslint:recommended", "google"],
plugins: [
"babel",
],
rules: {
// rules we've always adhered to or now do
"max-len": ["error", {
@@ -73,5 +76,10 @@ module.exports = {
"asyncArrow": "always",
}],
"arrow-parens": "off",
// eslint's built in no-invalid-this rule breaks with class properties
"no-invalid-this": "off",
// so we replace it with a version that is class property aware
"babel/no-invalid-this": "error",
}
}
+63
View File
@@ -1,3 +1,66 @@
Changes in [2.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.0.0) (2019-05-31)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v1.2.0...v2.0.0)
BREAKING CHANGES
----------------
* This package now publishes in ES6 / ES2015 syntax to NPM
* Saves access_token and user_id after login for all login types
[\#932](https://github.com/matrix-org/matrix-js-sdk/pull/932)
* Fix recovery key encoding for base-x 3.0.5
[\#931](https://github.com/matrix-org/matrix-js-sdk/pull/931)
Changes in [1.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v1.2.0) (2019-05-29)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v1.2.0-rc.1...v1.2.0)
Changes in [1.2.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v1.2.0-rc.1) (2019-05-23)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v1.1.0...v1.2.0-rc.1)
* interactive-auth now handles requesting email tokens
[\#926](https://github.com/matrix-org/matrix-js-sdk/pull/926)
* allow access to unreplaced message content
[\#923](https://github.com/matrix-org/matrix-js-sdk/pull/923)
* Add method to retrieve replacing event
[\#922](https://github.com/matrix-org/matrix-js-sdk/pull/922)
* More logging when signature verification fails
[\#921](https://github.com/matrix-org/matrix-js-sdk/pull/921)
* Local echo for m.replace relations
[\#920](https://github.com/matrix-org/matrix-js-sdk/pull/920)
* Track relations as pending and remove when cancelled
[\#919](https://github.com/matrix-org/matrix-js-sdk/pull/919)
* Add stringify helper to summarise events when debugging
[\#916](https://github.com/matrix-org/matrix-js-sdk/pull/916)
* Message editing: filter out replacements for senders that are not the
original sender
[\#918](https://github.com/matrix-org/matrix-js-sdk/pull/918)
* Wait until decrypt before aggregating
[\#917](https://github.com/matrix-org/matrix-js-sdk/pull/917)
* Message editing: mark original event as replaced instead of replacing the
event object
[\#914](https://github.com/matrix-org/matrix-js-sdk/pull/914)
* Support for replacing message through m.replace relationship.
[\#913](https://github.com/matrix-org/matrix-js-sdk/pull/913)
* Use a short timeout for .well-known requests
[\#912](https://github.com/matrix-org/matrix-js-sdk/pull/912)
* Redaction and change events for relations
[\#911](https://github.com/matrix-org/matrix-js-sdk/pull/911)
* Add basic read path for relations
[\#910](https://github.com/matrix-org/matrix-js-sdk/pull/910)
* Add a concept of default push rules, using it for tombstone notifications
[\#860](https://github.com/matrix-org/matrix-js-sdk/pull/860)
* yarn upgrade
[\#907](https://github.com/matrix-org/matrix-js-sdk/pull/907)
Changes in [1.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v1.1.0) (2019-05-07)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v1.1.0-rc.1...v1.1.0)
* No Changes since rc.1
Changes in [1.1.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v1.1.0-rc.1) (2019-04-30)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v1.0.4...v1.1.0-rc.1)
+6 -5
View File
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "1.1.0-rc.1",
"version": "2.0.0",
"description": "Matrix Client-Server SDK for Javascript",
"main": "index.js",
"scripts": {
@@ -9,12 +9,12 @@
"test:watch": "mocha --watch --compilers js:babel-core/register --recursive spec --colors",
"test": "yarn test:build && yarn test:run",
"check": "yarn test:build && _mocha --recursive specbuild --colors",
"gendoc": "babel --no-babelrc -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc",
"gendoc": "babel --no-babelrc --plugins transform-class-properties -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc",
"start": "yarn start:init && yarn start:watch",
"start:watch": "babel -s -w --skip-initial-build -d lib src",
"start:init": "babel -s -d lib src",
"clean": "rimraf lib dist",
"build": "babel -s -d lib src && rimraf dist && mkdir dist && browserify -d browser-index.js | exorcist dist/browser-matrix.js.map > dist/browser-matrix.js && uglifyjs -c -m -o dist/browser-matrix.min.js --source-map dist/browser-matrix.min.js.map --in-source-map dist/browser-matrix.js.map dist/browser-matrix.js",
"build": "babel -s -d lib src && rimraf dist && mkdir dist && browserify -d browser-index.js | exorcist dist/browser-matrix.js.map > dist/browser-matrix.js && terser -c -m -o dist/browser-matrix.min.js --source-map \"content='dist/browser-matrix.js.map'\" dist/browser-matrix.js",
"dist": "yarn build",
"watch": "watchify -d browser-index.js -o 'exorcist dist/browser-matrix.js.map > dist/browser-matrix.js' -v",
"lint": "eslint --max-warnings 101 src spec",
@@ -54,7 +54,6 @@
"dependencies": {
"another-json": "^0.2.0",
"babel-runtime": "^6.26.0",
"base-x": "3.0.4",
"bluebird": "^3.5.0",
"browser-request": "^0.3.3",
"bs58": "^4.0.1",
@@ -68,12 +67,14 @@
"babel-cli": "^6.18.0",
"babel-eslint": "^10.0.1",
"babel-plugin-transform-async-to-bluebird": "^1.1.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.18.0",
"browserify": "^16.2.3",
"browserify-shim": "^3.8.13",
"eslint": "^5.12.0",
"eslint-config-google": "^0.7.1",
"eslint-plugin-babel": "^5.3.0",
"exorcist": "^0.4.0",
"expect": "^1.20.2",
"istanbul": "^0.4.5",
@@ -86,7 +87,7 @@
"rimraf": "^2.5.4",
"source-map-support": "^0.4.11",
"sourceify": "^0.1.0",
"uglify-js": "^2.8.26",
"terser": "^4.0.0",
"watchify": "^3.11.1"
},
"browserify": {
+4 -4
View File
@@ -172,10 +172,10 @@ git commit package.json $pkglock -m "$tag"
# figure out if we should be signing this release
signing_id=releases@riot.im
#if [ -f release_config.yaml ]; then
#signing_id=`cat release_config.yaml | python -c "import yaml; import sys; print yaml.load(sys.stdin)['signing_id']"`
#fi
signing_id=
if [ -f release_config.yaml ]; then
signing_id=`cat release_config.yaml | python -c "import yaml; import sys; print yaml.load(sys.stdin)['signing_id']"`
fi
# If there is a 'dist' script in the package.json,
+1 -1
View File
@@ -87,7 +87,7 @@ describe("DeviceList management:", function() {
}
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
// we create our own sessionStoreBackend so that we can use it for
// another TestClient.
+1 -1
View File
@@ -405,7 +405,7 @@ describe("MatrixClient crypto", function() {
}
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
await aliTestClient.client.initCrypto();
@@ -15,7 +15,7 @@ describe("MatrixClient events", function() {
const selfAccessToken = "aseukfgwef";
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
client = sdk.createClient({
@@ -102,7 +102,7 @@ describe("getEventTimeline support", function() {
let client;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
});
@@ -227,7 +227,7 @@ describe("MatrixClient event timelines", function() {
let httpBackend = null;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
+1 -1
View File
@@ -21,7 +21,7 @@ describe("MatrixClient", function() {
const accessToken = "aseukfgwef";
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
store = new MemoryStore();
+1 -1
View File
@@ -58,7 +58,7 @@ describe("MatrixClient opts", function() {
};
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
});
+1 -1
View File
@@ -20,7 +20,7 @@ describe("MatrixClient retrying", function() {
let room;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
scheduler = new sdk.MatrixScheduler();
@@ -104,7 +104,7 @@ describe("MatrixClient room timelines", function() {
}
beforeEach(function(done) {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
client = sdk.createClient({
+1 -1
View File
@@ -23,7 +23,7 @@ describe("MatrixClient syncing", function() {
const roomTwo = "!bar:localhost";
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
client = sdk.createClient({
+1 -1
View File
@@ -282,7 +282,7 @@ describe("megolm", function() {
}
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
aliceTestClient = new TestClient(
"@alice:localhost", "xzcvb", "akjgkrgjs",
+1 -1
View File
@@ -30,7 +30,7 @@ describe("AutoDiscovery", function() {
let httpBackend = null;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new MockHttpBackend();
sdk.request(httpBackend.requestFn);
});
+1 -1
View File
@@ -9,7 +9,7 @@ describe("ContentRepo", function() {
const baseUrl = "https://my.home.server";
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("getHttpUriForMxc", function() {
+1 -1
View File
@@ -59,7 +59,7 @@ describe('DeviceList', function() {
let deviceLists = [];
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
deviceLists = [];
+1 -1
View File
@@ -31,7 +31,7 @@ describe("MegolmDecryption", function() {
let mockBaseApis;
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
await Olm.init();
+1 -1
View File
@@ -53,7 +53,7 @@ describe("OlmDecryption", function() {
let bobOlmDevice;
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
await global.Olm.init();
+1 -1
View File
@@ -125,7 +125,7 @@ describe("MegolmBackup", function() {
let megolmDecryption;
beforeEach(async function() {
await Olm.init();
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
mockCrypto = testUtils.mock(Crypto, 'Crypto');
mockCrypto.backupKey = new Olm.PkEncryption();
+1 -1
View File
@@ -29,7 +29,7 @@ export async function makeTestClients(userInfos, options) {
for (const [deviceId, msg] of Object.entries(devMap)) {
if (deviceId in clientMap[userId]) {
const event = new MatrixEvent({
sender: this.getUserId(), // eslint-disable-line no-invalid-this
sender: this.getUserId(), // eslint-disable-line babel/no-invalid-this
type: type,
content: msg,
});
+1 -1
View File
@@ -18,7 +18,7 @@ describe("EventTimeline", function() {
let timeline;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
// XXX: this is a horrid hack; should use sinon or something instead to mock
const timelineSet = { room: { roomId: roomId }};
+1 -1
View File
@@ -24,7 +24,7 @@ import Promise from 'bluebird';
describe("MatrixEvent", () => {
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe(".attemptDecryption", () => {
+1 -1
View File
@@ -12,7 +12,7 @@ describe("Filter", function() {
let filter;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
filter = new Filter(userId);
});
+1 -1
View File
@@ -35,7 +35,7 @@ class FakeClient {
describe("InteractiveAuth", function() {
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
it("should start an auth stage and complete it", function(done) {
+25
View File
@@ -0,0 +1,25 @@
import expect from 'expect';
import TestClient from '../TestClient';
describe('Login request', function() {
let client;
beforeEach(function() {
client = new TestClient();
});
afterEach(function() {
client.stop();
});
it('should store "access_token" and "user_id" if in response', async function() {
const response = { user_id: 1, access_token: Date.now().toString(16) };
client.httpBackend.when('POST', '/login').respond(200, response);
client.httpBackend.flush('/login', 1, 100);
await client.client.login('m.login.any', { user: 'test', password: '12312za' });
expect(client.client.getAccessToken()).toBe(response.access_token);
expect(client.client.getUserId()).toBe(response.user_id);
});
});
+1 -1
View File
@@ -124,7 +124,7 @@ describe("MatrixClient", function() {
}
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
clock = lolex.install();
scheduler = [
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
+3 -3
View File
@@ -15,7 +15,7 @@ describe("realtime-callbacks", function() {
}
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
clock = lolex.install();
const fakeDate = clock.Date;
callbacks.setNow(fakeDate.now.bind(fakeDate));
@@ -56,8 +56,8 @@ describe("realtime-callbacks", function() {
it("should set 'this' to the global object", function() {
let passed = false;
const callback = function() {
expect(this).toBe(global); // eslint-disable-line no-invalid-this
expect(this.console).toBeTruthy(); // eslint-disable-line no-invalid-this
expect(this).toBe(global); // eslint-disable-line babel/no-invalid-this
expect(this.console).toBeTruthy(); // eslint-disable-line babel/no-invalid-this
passed = true;
};
callbacks.setTimeout(callback);
+1 -1
View File
@@ -14,7 +14,7 @@ describe("RoomMember", function() {
let member;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
member = new RoomMember(roomId, userA);
});
+1 -1
View File
@@ -17,7 +17,7 @@ describe("RoomState", function() {
let state;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
state = new RoomState(roomId);
state.setStateEvents([
utils.mkMembership({ // userA joined
+1 -1
View File
@@ -19,7 +19,7 @@ describe("Room", function() {
let room;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
room = new Room(roomId);
// mock RoomStates
room.oldState = room.getLiveTimeline()._startState =
+1 -1
View File
@@ -26,7 +26,7 @@ describe("MatrixScheduler", function() {
});
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
clock = lolex.install();
scheduler = new MatrixScheduler(function(ev, attempts, err) {
if (retryFn) {
+1 -1
View File
@@ -26,7 +26,7 @@ describe("SyncAccumulator", function() {
let sa;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
sa = new SyncAccumulator({
maxTimelineEntries: 10,
});
+2 -2
View File
@@ -68,7 +68,7 @@ function createLinkedTimelines() {
describe("TimelineIndex", function() {
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("minIndex", function() {
@@ -164,7 +164,7 @@ describe("TimelineWindow", function() {
}
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("load", function() {
+1 -1
View File
@@ -11,7 +11,7 @@ describe("User", function() {
let user;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line no-invalid-this
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
user = new User(userId);
});
+1 -1
View File
@@ -7,7 +7,7 @@ import expect from 'expect';
describe("utils", function() {
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("encodeParams", function() {
+1 -1
View File
@@ -480,7 +480,7 @@ export class AutoDiscovery {
const request = require("./matrix").getRequest();
if (!request) throw new Error("No request library available");
request(
{ method: "GET", uri: url },
{ method: "GET", uri: url, timeout: 5000 },
(err, response, body) => {
if (err || response.statusCode < 200 || response.statusCode >= 300) {
let action = "FAIL_PROMPT";
+2 -3
View File
@@ -263,8 +263,7 @@ MatrixBaseApis.prototype.login = function(loginType, data, callback) {
return this._http.authedRequest(
(error, response) => {
if (loginType === "m.login.password" && response &&
response.access_token && response.user_id) {
if (response && response.access_token && response.user_id) {
this._http.opts.accessToken = response.access_token;
this.credentials = {
userId: response.user_id,
@@ -904,7 +903,7 @@ MatrixBaseApis.prototype.redactEvent = function(
callback = txnId;
}
const path = utils.encodeUri("/rooms/$roomId/redact/$eventId/$tnxId", {
const path = utils.encodeUri("/rooms/$roomId/redact/$eventId/$txnId", {
$roomId: roomId,
$eventId: eventId,
$txnId: txnId ? txnId : this.makeTxnId(),
+12 -2
View File
@@ -148,6 +148,11 @@ function keyFromRecoverySession(session, decryptionKey) {
* maintain support for back-paginating the live timeline after a '/sync'
* result with a gap.
*
* @param {boolean} [opts.unstableClientRelationAggregation = false]
* Optional. Set to true to enable client-side aggregation of event relations
* via `EventTimelineSet#getRelationsForEvent`.
* This feature is currently unstable and the API may change without notice.
*
* @param {Array} [opts.verificationMethods] Optional. The verification method
* that the application can handle. Each element should be an item from {@link
* module:crypto~verificationMethods verificationMethods}, or a class that
@@ -213,6 +218,7 @@ function MatrixClient(opts) {
this.timelineSupport = Boolean(opts.timelineSupport);
this.urlPreviewCache = {};
this._notifTimelineSet = null;
this.unstableClientRelationAggregation = !!opts.unstableClientRelationAggregation;
this._crypto = null;
this._cryptoStore = opts.cryptoStore;
@@ -1711,7 +1717,7 @@ MatrixClient.prototype.sendEvent = function(roomId, eventType, content, txnId,
content: content,
});
localEvent._txnId = txnId;
localEvent.status = EventStatus.SENDING;
localEvent.setStatus(EventStatus.SENDING);
// add this event immediately to the local store as 'sending'.
if (room) {
@@ -1841,7 +1847,7 @@ function _updatePendingEventStatus(room, event, newStatus) {
if (room) {
room.updatePendingEvent(event, newStatus);
} else {
event.status = newStatus;
event.setStatus(newStatus);
}
}
@@ -4156,6 +4162,10 @@ function _PojoToMatrixEventMapper(client) {
]);
event.attemptDecryption(client._crypto);
}
const room = client.getRoom(event.getRoomId());
if (room) {
room.reEmitter.reEmit(event, ["Event.replaced"]);
}
return event;
}
return mapper;
+5 -1
View File
@@ -378,7 +378,11 @@ Crypto.prototype.isKeyBackupTrusted = async function(backupInfo) {
);
sigInfo.valid = true;
} catch (e) {
logger.info("Bad signature from key ID " + keyId, e);
logger.info(
"Bad signature from key ID " + keyId + " userID " + this._userId +
" device ID " + device.deviceId + " fingerprint: " +
device.getFingerprint(), backupInfo.auth_data, e,
);
sigInfo.valid = false;
}
} else {
+1 -1
View File
@@ -21,7 +21,7 @@ import bs58 from 'bs58';
const OLM_RECOVERY_KEY_PREFIX = [0x8B, 0x01];
export function encodeRecoveryKey(key) {
const buf = new Uint8Array(OLM_RECOVERY_KEY_PREFIX.length + key.length + 1);
const buf = new Buffer(OLM_RECOVERY_KEY_PREFIX.length + key.length + 1);
buf.set(OLM_RECOVERY_KEY_PREFIX, 0);
buf.set(key, OLM_RECOVERY_KEY_PREFIX.length);
+91 -59
View File
@@ -1,6 +1,7 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -88,6 +89,12 @@ const MSISDN_STAGE_TYPE = "m.login.msisdn";
* @param {string?} opts.emailSid If returning from having completed m.login.email.identity
* auth, the sid for the email verification session.
*
* @param {function?} opts.requestEmailToken A function that takes the email address (string),
* clientSecret (string), attempt number (int) and sessionId (string) and calls the
* relevant requestToken function and returns the promise returned by that function.
* If the resulting promise rejects, the rejection will propagate through to the
* attemptAuth promise.
*
*/
function InteractiveAuth(opts) {
this._matrixClient = opts.matrixClient;
@@ -95,14 +102,17 @@ function InteractiveAuth(opts) {
this._requestCallback = opts.doRequest;
// startAuthStage included for backwards compat
this._stateUpdatedCallback = opts.stateUpdated || opts.startAuthStage;
this._completionDeferred = null;
this._resolveFunc = null;
this._rejectFunc = null;
this._inputs = opts.inputs || {};
this._requestEmailTokenCallback = opts.requestEmailToken;
if (opts.sessionId) this._data.session = opts.sessionId;
this._clientSecret = opts.clientSecret || this._matrixClient.generateClientSecret();
this._emailSid = opts.emailSid;
if (this._emailSid === undefined) this._emailSid = null;
this._chosenFlow = null;
this._currentStage = null;
}
@@ -115,11 +125,12 @@ InteractiveAuth.prototype = {
* no suitable authentication flow can be found
*/
attemptAuth: function() {
this._completionDeferred = Promise.defer();
// This promise will be quite long-lived and will resolve when the
// request is authenticated and completes successfully.
return new Promise((resolve, reject) => {
this._resolveFunc = resolve;
this._rejectFunc = reject;
// wrap in a promise so that if _startNextAuthStage
// throws, it rejects the promise in a consistent way
return Promise.resolve().then(() => {
// if we have no flows, try a request (we'll have
// just a session ID in _data if resuming)
if (!this._data.flows) {
@@ -127,7 +138,6 @@ InteractiveAuth.prototype = {
} else {
this._startNextAuthStage();
}
return this._completionDeferred.promise;
});
},
@@ -194,6 +204,10 @@ InteractiveAuth.prototype = {
return params[loginType];
},
getChosenFlow() {
return this._chosenFlow;
},
/**
* submit a new auth dict and fire off the request. This will either
* make attemptAuth resolve/reject, or cause the startAuthStage callback
@@ -207,7 +221,7 @@ InteractiveAuth.prototype = {
* for requests that just poll to see if auth has been completed elsewhere.
*/
submitAuthDict: function(authData, background) {
if (!this._completionDeferred) {
if (!this._resolveFunc) {
throw new Error("submitAuthDict() called before attemptAuth()");
}
@@ -253,58 +267,74 @@ InteractiveAuth.prototype = {
* This can be set to true for requests that just poll to see if auth has
* been completed elsewhere.
*/
_doRequest: function(auth, background) {
const self = this;
// hackery to make sure that synchronous exceptions end up in the catch
// handler (without the additional event loop entailed by q.fcall or an
// extra Promise.resolve().then)
let prom;
_doRequest: async function(auth, background) {
try {
prom = this._requestCallback(auth, background);
} catch (e) {
prom = Promise.reject(e);
}
const result = await this._requestCallback(auth, background);
this._resolveFunc(result);
} catch (error) {
// sometimes UI auth errors don't come with flows
const errorFlows = error.data ? error.data.flows : null;
const haveFlows = Boolean(this._data.flows) || Boolean(errorFlows);
if (error.httpStatus !== 401 || !error.data || !haveFlows) {
// doesn't look like an interactive-auth failure.
if (!background) {
this._rejectFunc(error);
} else {
// We ignore all failures here (even non-UI auth related ones)
// since we don't want to suddenly fail if the internet connection
// had a blip whilst we were polling
console.log(
"Background poll request failed doing UI auth: ignoring",
error,
);
}
}
// if the error didn't come with flows, completed flows or session ID,
// copy over the ones we have. Synapse sometimes sends responses without
// any UI auth data (eg. when polling for email validation, if the email
// has not yet been validated). This appears to be a Synapse bug, which
// we workaround here.
if (!error.data.flows && !error.data.completed && !error.data.session) {
error.data.flows = this._data.flows;
error.data.completed = this._data.completed;
error.data.session = this._data.session;
}
this._data = error.data;
this._startNextAuthStage();
prom = prom.then(
function(result) {
console.log("result from request: ", result);
self._completionDeferred.resolve(result);
}, function(error) {
// sometimes UI auth errors don't come with flows
const errorFlows = error.data ? error.data.flows : null;
const haveFlows = Boolean(self._data.flows) || Boolean(errorFlows);
if (error.httpStatus !== 401 || !error.data || !haveFlows) {
// doesn't look like an interactive-auth failure. fail the whole lot.
throw error;
if (
!this._emailSid &&
this._chosenFlow.stages.includes('m.login.email.identity')
) {
// If we've picked a flow with email auth, we send the email
// now because we want the request to fail as soon as possible
// if the email address is not valid (ie. already taken or not
// registered, depending on what the operation is).
try {
const requestTokenResult = await this._requestEmailTokenCallback(
this._inputs.emailAddress,
this._clientSecret,
1, // TODO: Multiple send attempts?
this._data.session,
);
this._emailSid = requestTokenResult.sid;
// NB. promise is not resolved here - at some point, doRequest
// will be called again and if the user has jumped through all
// the hoops correctly, auth will be complete and the request
// will succeed.
// Also, we should expose the fact that this request has compledted
// so clients can know that the email has actually been sent.
} catch (e) {
// we failed to request an email token, so fail the request.
// This could be due to the email already beeing registered
// (or not being registered, depending on what we're trying
// to do) or it could be a network failure. Either way, pass
// the failure up as the user can't complete auth if we can't
// send the email, foe whatever reason.
this._rejectFunc(e);
}
// if the error didn't come with flows, completed flows or session ID,
// copy over the ones we have. Synapse sometimes sends responses without
// any UI auth data (eg. when polling for email validation, if the email
// has not yet been validated). This appears to be a Synapse bug, which
// we workaround here.
if (!error.data.flows && !error.data.completed && !error.data.session) {
error.data.flows = self._data.flows;
error.data.completed = self._data.completed;
error.data.session = self._data.session;
}
self._data = error.data;
self._startNextAuthStage();
},
);
if (!background) {
prom = prom.catch((e) => {
this._completionDeferred.reject(e);
});
} else {
// We ignore all failures here (even non-UI auth related ones)
// since we don't want to suddenly fail if the internet connection
// had a blip whilst we were polling
prom = prom.catch((error) => {
console.log("Ignoring error from UI auth: " + error);
});
}
}
prom.done();
},
/**
@@ -320,7 +350,7 @@ InteractiveAuth.prototype = {
}
this._currentStage = nextStage;
if (nextStage == 'm.login.dummy') {
if (nextStage === 'm.login.dummy') {
this.submitAuthDict({
type: 'm.login.dummy',
});
@@ -350,9 +380,11 @@ InteractiveAuth.prototype = {
* @throws {NoAuthFlowFoundError} If no suitable authentication flow can be found
*/
_chooseStage: function() {
const flow = this._chooseFlow();
console.log("Active flow => %s", JSON.stringify(flow));
const nextStage = this._firstUncompletedStage(flow);
if (this._chosenFlow === null) {
this._chosenFlow = this._chooseFlow();
}
console.log("Active flow => %s", JSON.stringify(this._chosenFlow));
const nextStage = this._firstUncompletedStage(this._chosenFlow);
console.log("Next stage: %s", nextStage);
return nextStage;
},
+140 -4
View File
@@ -20,6 +20,7 @@ limitations under the License.
const EventEmitter = require("events").EventEmitter;
const utils = require("../utils");
const EventTimeline = require("./event-timeline");
import Relations from './relations';
// var DEBUG = false;
const DEBUG = true;
@@ -54,22 +55,38 @@ if (DEBUG) {
* map from event_id to timeline and index.
*
* @constructor
* @param {?Room} room the optional room for this timelineSet
* @param {Object} opts hash of options inherited from Room.
* opts.timelineSupport gives whether timeline support is enabled
* opts.filter is the filter object, if any, for this timelineSet.
* @param {?Room} room
* Room for this timelineSet. May be null for non-room cases, such as the
* notification timeline.
* @param {Object} opts Options inherited from Room.
*
* @param {boolean} [opts.timelineSupport = false]
* Set to true to enable improved timeline support.
* @param {Object} [opts.filter = null]
* The filter object, if any, for this timelineSet.
* @param {boolean} [opts.unstableClientRelationAggregation = false]
* Optional. Set to true to enable client-side aggregation of event relations
* via `getRelationsForEvent`.
* This feature is currently unstable and the API may change without notice.
*/
function EventTimelineSet(room, opts) {
this.room = room;
this._timelineSupport = Boolean(opts.timelineSupport);
this._liveTimeline = new EventTimeline(this);
this._unstableClientRelationAggregation = !!opts.unstableClientRelationAggregation;
// just a list - *not* ordered.
this._timelines = [this._liveTimeline];
this._eventIdToTimeline = {};
this._filter = opts.filter || null;
if (this._unstableClientRelationAggregation) {
// A tree of objects to access a set of relations for an event, as in:
// this._relations[relatesToEventId][relationType][relationEventType]
this._relations = {};
}
}
utils.inherits(EventTimelineSet, EventEmitter);
@@ -523,6 +540,9 @@ EventTimelineSet.prototype.addEventToTimeline = function(event, timeline,
timeline.addEvent(event, toStartOfTimeline);
this._eventIdToTimeline[eventId] = timeline;
this.setRelationsTarget(event);
this.aggregateRelations(event);
const data = {
timeline: timeline,
liveEvent: !toStartOfTimeline && timeline == this._liveTimeline,
@@ -657,6 +677,122 @@ EventTimelineSet.prototype.compareEventOrdering = function(eventId1, eventId2) {
return null;
};
/**
* Get a collection of relations to a given event in this timeline set.
*
* @param {String} eventId
* The ID of the event that you'd like to access relation events for.
* For example, with annotations, this would be the ID of the event being annotated.
* @param {String} relationType
* The type of relation involved, such as "m.annotation", "m.reference", "m.replace", etc.
* @param {String} eventType
* The relation event's type, such as "m.reaction", etc.
*
* @returns {Relations}
* A container for relation events.
*/
EventTimelineSet.prototype.getRelationsForEvent = function(
eventId, relationType, eventType,
) {
if (!this._unstableClientRelationAggregation) {
throw new Error("Client-side relation aggregation is disabled");
}
if (!eventId || !relationType || !eventType) {
throw new Error("Invalid arguments for `getRelationsForEvent`");
}
// debuglog("Getting relations for: ", eventId, relationType, eventType);
const relationsForEvent = this._relations[eventId] || {};
const relationsWithRelType = relationsForEvent[relationType] || {};
return relationsWithRelType[eventType];
};
/**
* Set an event as the target event if any Relations exist for it already
*
* @param {MatrixEvent} event
* The event to check as relation target.
*/
EventTimelineSet.prototype.setRelationsTarget = function(event) {
if (!this._unstableClientRelationAggregation) {
return;
}
const relationsForEvent = this._relations[event.getId()];
if (!relationsForEvent) {
return;
}
// don't need it for non m.replace relations for now
const relationsWithRelType = relationsForEvent["m.replace"];
if (!relationsWithRelType) {
return;
}
// only doing replacements for messages for now (e.g. edits)
const relationsWithEventType = relationsWithRelType["m.room.message"];
if (relationsWithEventType) {
relationsWithEventType.setTargetEvent(event);
}
};
/**
* Add relation events to the relevant relation collection.
*
* @param {MatrixEvent} event
* The new relation event to be aggregated.
*/
EventTimelineSet.prototype.aggregateRelations = function(event) {
if (!this._unstableClientRelationAggregation) {
return;
}
// If the event is currently encrypted, wait until it has been decrypted.
if (event.isBeingDecrypted()) {
event.once("Event.decrypted", () => {
this.aggregateRelations(event);
});
return;
}
const relation = event.getRelation();
if (!relation) {
return;
}
const relatesToEventId = relation.event_id;
const relationType = relation.rel_type;
const eventType = event.getType();
// debuglog("Aggregating relation: ", event.getId(), eventType, relation);
let relationsForEvent = this._relations[relatesToEventId];
if (!relationsForEvent) {
relationsForEvent = this._relations[relatesToEventId] = {};
}
let relationsWithRelType = relationsForEvent[relationType];
if (!relationsWithRelType) {
relationsWithRelType = relationsForEvent[relationType] = {};
}
let relationsWithEventType = relationsWithRelType[eventType];
if (!relationsWithEventType) {
relationsWithEventType = relationsWithRelType[eventType] = new Relations(
relationType,
eventType,
this.room,
);
const relatesToEvent = this.findEventById(relatesToEventId);
if (relatesToEvent) {
relationsWithEventType.setTargetEvent(relatesToEvent);
relatesToEvent.emit("Event.relationsCreated", relationType, eventType);
}
}
relationsWithEventType.addEvent(event);
};
/**
* The EventTimelineSet class.
*/
+176 -21
View File
@@ -50,6 +50,12 @@ module.exports.EventStatus = {
};
const interns = {};
function intern(str) {
if (!interns[str]) {
interns[str] = str;
}
return interns[str];
}
/**
* Construct a Matrix Event object
@@ -87,20 +93,25 @@ module.exports.MatrixEvent = function MatrixEvent(
if (!event[prop]) {
return;
}
if (!interns[event[prop]]) {
interns[event[prop]] = event[prop];
}
event[prop] = interns[event[prop]];
event[prop] = intern(event[prop]);
});
["membership", "avatar_url", "displayname"].forEach((prop) => {
if (!event.content || !event.content[prop]) {
return;
}
if (!interns[event.content[prop]]) {
interns[event.content[prop]] = event.content[prop];
event.content[prop] = intern(event.content[prop]);
});
["rel_type"].forEach((prop) => {
if (
!event.content ||
!event.content["m.relates_to"] ||
!event.content["m.relates_to"][prop]
) {
return;
}
event.content[prop] = interns[event.content[prop]];
event.content["m.relates_to"][prop] = intern(event.content["m.relates_to"][prop]);
});
this.event = event || {};
@@ -111,6 +122,7 @@ module.exports.MatrixEvent = function MatrixEvent(
this.error = null;
this.forwardLooking = true;
this._pushActions = null;
this._replacingEvent = null;
this._clearEvent = {};
@@ -209,12 +221,28 @@ utils.extend(module.exports.MatrixEvent.prototype, {
},
/**
* Get the (decrypted, if necessary) event content JSON.
* Get the (decrypted, if necessary) event content JSON, even if the event
* was replaced by another event.
*
* @return {Object} The event content JSON, or an empty object.
*/
getOriginalContent: function() {
return this._clearEvent.content || this.event.content || {};
},
/**
* Get the (decrypted, if necessary) event content JSON,
* or the content from the replacing event, if any.
* See `makeReplaced`.
*
* @return {Object} The event content JSON, or an empty object.
*/
getContent: function() {
return this._clearEvent.content || this.event.content || {};
if (this._replacingEvent) {
return this._replacingEvent.getContent()["m.new_content"] || {};
} else {
return this.getOriginalContent();
}
},
/**
@@ -352,7 +380,7 @@ utils.extend(module.exports.MatrixEvent.prototype, {
if (
this._clearEvent && this._clearEvent.content &&
this._clearEvent.content.msgtype !== "m.bad.encrypted"
this._clearEvent.content.msgtype !== "m.bad.encrypted"
) {
// we may want to just ignore this? let's start with rejecting it.
throw new Error(
@@ -650,6 +678,9 @@ utils.extend(module.exports.MatrixEvent.prototype, {
throw new Error("invalid redaction_event in makeRedacted");
}
this.emit("Event.beforeRedaction", this, redaction_event);
this._replacingEvent = null;
// we attempt to replicate what we would see from the server if
// the event had been redacted before we saw it.
//
@@ -697,28 +728,152 @@ utils.extend(module.exports.MatrixEvent.prototype, {
*
* @return {?Object} push actions
*/
getPushActions: function() {
getPushActions: function() {
return this._pushActions;
},
},
/**
* Set the push actions for this event.
*
* @param {Object} pushActions push actions
*/
setPushActions: function(pushActions) {
setPushActions: function(pushActions) {
this._pushActions = pushActions;
},
},
/**
* Replace the `event` property and recalculate any properties based on it.
* @param {Object} event the object to assign to the `event` property
*/
handleRemoteEcho: function(event) {
/**
* Replace the `event` property and recalculate any properties based on it.
* @param {Object} event the object to assign to the `event` property
*/
handleRemoteEcho: function(event) {
this.event = event;
// successfully sent.
this.status = null;
},
this.setStatus(null);
},
/**
* Whether the event is in any phase of sending, send failure, waiting for
* remote echo, etc.
*
* @return {boolean}
*/
isSending() {
return !!this.status;
},
/**
* Update the event's sending status and emit an event as well.
*
* @param {String} status The new status
*/
setStatus(status) {
this.status = status;
this.emit("Event.status", this, status);
},
/**
* Get whether the event is a relation event, and of a given type if
* `relType` is passed in.
*
* @param {string?} relType if given, checks that the relation is of the
* given type
* @return {boolean}
*/
isRelation(relType = undefined) {
// Relation info is lifted out of the encrypted content when sent to
// encrypted rooms, so we have to check `getWireContent` for this.
const content = this.getWireContent();
const relation = content && content["m.relates_to"];
return relation && relation.rel_type && relation.event_id &&
((relType && relation.rel_type === relType) || !relType);
},
/**
* Get relation info for the event, if any.
*
* @return {Object}
*/
getRelation() {
if (!this.isRelation()) {
return null;
}
return this.getWireContent()["m.relates_to"];
},
/**
* Set an event that replaces the content of this event, through an m.replace relation.
*
* @param {MatrixEvent?} newEvent the event with the replacing content, if any.
*/
makeReplaced(newEvent) {
if (this.isRedacted()) {
return;
}
if (this._replacingEvent !== newEvent) {
this._replacingEvent = newEvent;
this.emit("Event.replaced", this);
}
},
/**
* Returns the status of the event, or the replacing event in case `makeReplace` has been called.
*
* @return {EventStatus}
*/
replacementOrOwnStatus() {
if (this._replacingEvent) {
return this._replacingEvent.status;
} else {
return this.status;
}
},
/**
* Returns the event ID of the event replacing the content of this event, if any.
*
* @return {string?}
*/
replacingEventId() {
return this._replacingEvent && this._replacingEvent.getId();
},
/**
* Returns the event replacing the content of this event, if any.
*
* @return {MatrixEvent?}
*/
replacingEvent() {
return this._replacingEvent;
},
/**
* Summarise the event as JSON for debugging. If encrypted, include both the
* decrypted and encrypted view of the event. This is named `toJSON` for use
* with `JSON.stringify` which checks objects for functions named `toJSON`
* and will call them to customise the output if they are defined.
*
* @return {Object}
*/
toJSON() {
const event = {
type: this.getType(),
sender: this.getSender(),
content: this.getContent(),
event_id: this.getId(),
origin_server_ts: this.getTs(),
unsigned: this.getUnsigned(),
room_id: this.getRoomId(),
};
if (!this.isEncrypted()) {
return event;
}
return {
decrypted: event,
encrypted: this.event,
};
},
});
+337
View File
@@ -0,0 +1,337 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import EventEmitter from 'events';
import { EventStatus } from '../../lib/models/event';
/**
* A container for relation events that supports easy access to common ways of
* aggregating such events. Each instance holds events that of a single relation
* type and event type. All of the events also relate to the same original event.
*
* The typical way to get one of these containers is via
* EventTimelineSet#getRelationsForEvent.
*/
export default class Relations extends EventEmitter {
/**
* @param {String} relationType
* The type of relation involved, such as "m.annotation", "m.reference",
* "m.replace", etc.
* @param {String} eventType
* The relation event's type, such as "m.reaction", etc.
* @param {?Room} room
* Room for this container. May be null for non-room cases, such as the
* notification timeline.
*/
constructor(relationType, eventType, room) {
super();
this.relationType = relationType;
this.eventType = eventType;
this._relations = new Set();
this._annotationsByKey = {};
this._annotationsBySender = {};
this._sortedAnnotationsByKey = [];
this._targetEvent = null;
}
/**
* Add relation events to this collection.
*
* @param {MatrixEvent} event
* The new relation event to be added.
*/
addEvent(event) {
if (this._relations.has(event)) {
return;
}
const relation = event.getRelation();
if (!relation) {
console.error("Event must have relation info");
return;
}
const relationType = relation.rel_type;
const eventType = event.getType();
if (this.relationType !== relationType || this.eventType !== eventType) {
console.error("Event relation info doesn't match this container");
return;
}
// If the event is in the process of being sent, listen for cancellation
// so we can remove the event from the collection.
if (event.isSending()) {
event.on("Event.status", this._onEventStatus);
}
this._relations.add(event);
if (this.relationType === "m.annotation") {
this._addAnnotationToAggregation(event);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
}
event.on("Event.beforeRedaction", this._onBeforeRedaction);
this.emit("Relations.add", event);
}
/**
* Remove relation event from this collection.
*
* @param {MatrixEvent} event
* The relation event to remove.
*/
_removeEvent(event) {
if (!this._relations.has(event)) {
return;
}
const relation = event.getRelation();
if (!relation) {
console.error("Event must have relation info");
return;
}
const relationType = relation.rel_type;
const eventType = event.getType();
if (this.relationType !== relationType || this.eventType !== eventType) {
console.error("Event relation info doesn't match this container");
return;
}
this._relations.delete(event);
if (this.relationType === "m.annotation") {
this._removeAnnotationFromAggregation(event);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
}
this.emit("Relations.remove", event);
}
/**
* Listens for event status changes to remove cancelled events.
*
* @param {MatrixEvent} event The event whose status has changed
* @param {EventStatus} status The new status
*/
_onEventStatus = (event, status) => {
if (!event.isSending()) {
// Sending is done, so we don't need to listen anymore
event.removeListener("Event.status", this._onEventStatus);
return;
}
if (status !== EventStatus.CANCELLED) {
return;
}
// Event was cancelled, remove from the collection
event.removeListener("Event.status", this._onEventStatus);
this._removeEvent(event);
}
/**
* Get all relation events in this collection.
*
* These are currently in the order of insertion to this collection, which
* won't match timeline order in the case of scrollback.
* TODO: Tweak `addEvent` to insert correctly for scrollback.
*
* @return {Array}
* Relation events in insertion order.
*/
getRelations() {
return [...this._relations];
}
_addAnnotationToAggregation(event) {
const { key } = event.getRelation();
if (!key) {
return;
}
let eventsForKey = this._annotationsByKey[key];
if (!eventsForKey) {
eventsForKey = this._annotationsByKey[key] = new Set();
this._sortedAnnotationsByKey.push([key, eventsForKey]);
}
// Add the new event to the set for this key
eventsForKey.add(event);
// Re-sort the [key, events] pairs in descending order of event count
this._sortedAnnotationsByKey.sort((a, b) => {
const aEvents = a[1];
const bEvents = b[1];
return bEvents.size - aEvents.size;
});
const sender = event.getSender();
let eventsFromSender = this._annotationsBySender[sender];
if (!eventsFromSender) {
eventsFromSender = this._annotationsBySender[sender] = new Set();
}
// Add the new event to the set for this sender
eventsFromSender.add(event);
}
_removeAnnotationFromAggregation(event) {
const { key } = event.getRelation();
if (!key) {
return;
}
const eventsForKey = this._annotationsByKey[key];
if (eventsForKey) {
eventsForKey.delete(event);
// Re-sort the [key, events] pairs in descending order of event count
this._sortedAnnotationsByKey.sort((a, b) => {
const aEvents = a[1];
const bEvents = b[1];
return bEvents.size - aEvents.size;
});
}
const sender = event.getSender();
const eventsFromSender = this._annotationsBySender[sender];
if (eventsFromSender) {
eventsFromSender.delete(event);
}
}
/**
* For relations that have been redacted, we want to remove them from
* aggregation data sets and emit an update event.
*
* To do so, we listen for `Event.beforeRedaction`, which happens:
* - after the server accepted the redaction and remote echoed back to us
* - before the original event has been marked redacted in the client
*
* @param {MatrixEvent} redactedEvent
* The original relation event that is about to be redacted.
*/
_onBeforeRedaction = (redactedEvent) => {
if (!this._relations.has(redactedEvent)) {
return;
}
this._relations.delete(redactedEvent);
if (this.relationType === "m.annotation") {
// Remove the redacted annotation from aggregation by key
this._removeAnnotationFromAggregation(redactedEvent);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
}
redactedEvent.removeListener("Event.beforeRedaction", this._onBeforeRedaction);
// Dispatch a redaction event on this collection. `setTimeout` is used
// to wait until the next event loop iteration by which time the event
// has actually been marked as redacted.
setTimeout(() => {
this.emit("Relations.redaction");
}, 0);
}
/**
* Get all events in this collection grouped by key and sorted by descending
* event count in each group.
*
* This is currently only supported for the annotation relation type.
*
* @return {Array}
* An array of [key, events] pairs sorted by descending event count.
* The events are stored in a Set (which preserves insertion order).
*/
getSortedAnnotationsByKey() {
if (this.relationType !== "m.annotation") {
// Other relation types are not grouped currently.
return null;
}
return this._sortedAnnotationsByKey;
}
/**
* Get all events in this collection grouped by sender.
*
* This is currently only supported for the annotation relation type.
*
* @return {Object}
* An object with each relation sender as a key and the matching Set of
* events for that sender as a value.
*/
getAnnotationsBySender() {
if (this.relationType !== "m.annotation") {
// Other relation types are not grouped currently.
return null;
}
return this._annotationsBySender;
}
/**
* Returns the most recent (and allowed) m.replace relation, if any.
*
* This is currently only supported for the m.replace relation type,
* once the target event is known, see `addEvent`.
*
* @return {MatrixEvent?}
*/
getLastReplacement() {
if (this.relationType !== "m.replace") {
// Aggregating on last only makes sense for this relation type
return null;
}
if (!this._targetEvent) {
// Don't know which replacements to accept yet.
// This method shouldn't be called before the original
// event is known anyway.
return null;
}
return this.getRelations().reduce((last, event) => {
if (event.getSender() !== this._targetEvent.getSender()) {
return last;
}
if (last && last.getTs() > event.getTs()) {
return last;
}
return event;
}, null);
}
/*
* @param {MatrixEvent} targetEvent the event the relations are related to.
*/
setTargetEvent(event) {
if (this._targetEvent) {
return;
}
this._targetEvent = event;
if (this.relationType === "m.replace") {
const replacement = this.getLastReplacement();
// this is the initial update, so only call it if we already have something
// to not emit Event.replaced needlessly
if (replacement) {
this._targetEvent.makeReplaced(replacement);
}
}
}
}
+25 -5
View File
@@ -92,9 +92,12 @@ function synthesizeReceipt(userId, event, receiptType) {
* "<b>detached</b>", pending messages will appear in a separate list,
* accessbile via {@link module:models/room#getPendingEvents}. Default:
* "chronological".
*
* @param {boolean} [opts.timelineSupport = false] Set to true to enable improved
* timeline support.
* @param {boolean} [opts.unstableClientRelationAggregation = false]
* Optional. Set to true to enable client-side aggregation of event relations
* via `EventTimelineSet#getRelationsForEvent`.
* This feature is currently unstable and the API may change without notice.
*
* @prop {string} roomId The ID of this room.
* @prop {string} name The human-readable display name for this room.
@@ -1001,7 +1004,6 @@ Room.prototype.removeFilteredTimelineSet = function(filter) {
* @private
*/
Room.prototype._addLiveEvent = function(event, duplicateStrategy) {
let i;
if (event.getType() === "m.room.redaction") {
const redactId = event.event.redacts;
@@ -1035,7 +1037,7 @@ Room.prototype._addLiveEvent = function(event, duplicateStrategy) {
}
// add to our timeline sets
for (i = 0; i < this._timelineSets.length; i++) {
for (let i = 0; i < this._timelineSets.length; i++) {
this._timelineSets[i].addLiveEvent(event, duplicateStrategy);
}
@@ -1100,9 +1102,27 @@ Room.prototype.addPendingEvent = function(event, txnId) {
if (this._opts.pendingEventOrdering == "detached") {
if (this._pendingEventList.some((e) => e.status === EventStatus.NOT_SENT)) {
console.warn("Setting event as NOT_SENT due to messages in the same state");
event.status = EventStatus.NOT_SENT;
event.setStatus(EventStatus.NOT_SENT);
}
this._pendingEventList.push(event);
if (event.isRelation()) {
// For pending events, add them to the relations collection immediately.
// (The alternate case below already covers this as part of adding to
// the timeline set.)
// TODO: We should consider whether this means it would be a better
// design to lift the relations handling up to the room instead.
for (let i = 0; i < this._timelineSets.length; i++) {
const timelineSet = this._timelineSets[i];
if (timelineSet.getFilter()) {
if (this._filter.filterRoomTimeline([event]).length) {
timelineSet.aggregateRelations(event);
}
} else {
timelineSet.aggregateRelations(event);
}
}
}
} else {
for (let i = 0; i < this._timelineSets.length; i++) {
const timelineSet = this._timelineSets[i];
@@ -1241,7 +1261,7 @@ Room.prototype.updatePendingEvent = function(event, newStatus, newEventId) {
newStatus);
}
event.status = newStatus;
event.setStatus(newStatus);
if (newStatus == EventStatus.SENT) {
// update the event id
+60 -1
View File
@@ -23,6 +23,37 @@ import {escapeRegExp, globToRegexp} from "./utils";
const RULEKINDS_IN_ORDER = ['override', 'content', 'room', 'sender', 'underride'];
// The default override rules to apply when calculating actions for an event. These
// defaults apply under no other circumstances to avoid confusing the client with server
// state. We do this for two reasons:
// 1. Synapse is unlikely to send us the push rule in an incremental sync - see
// https://github.com/matrix-org/synapse/pull/4867#issuecomment-481446072 for
// more details.
// 2. We often want to start using push rules ahead of the server supporting them,
// and so we can put them here.
const DEFAULT_OVERRIDE_RULES = [
{
// For homeservers which don't support MSC1930 yet
rule_id: ".m.rule.tombstone",
default: true,
enabled: true,
conditions: [
{
kind: "event_match",
key: "type",
pattern: "m.room.tombstone",
},
],
actions: [
"notify",
{
set_tweak: "highlight",
value: true,
},
],
},
];
/**
* Construct a Push Processor.
* @constructor
@@ -312,6 +343,33 @@ function PushProcessor(client) {
return actionObj;
};
const applyRuleDefaults = function(clientRuleset) {
// Deep clone the object before we mutate it
const ruleset = JSON.parse(JSON.stringify(clientRuleset));
if (!clientRuleset['global']) {
clientRuleset['global'] = {};
}
if (!clientRuleset['global']['override']) {
clientRuleset['global']['override'] = [];
}
// Apply default overrides
const globalOverrides = clientRuleset['global']['override'];
for (const override of DEFAULT_OVERRIDE_RULES) {
const existingRule = globalOverrides
.find((r) => r.rule_id === override.rule_id);
if (!existingRule) {
const ruleId = override.rule_id;
console.warn(`Adding default global override for ${ruleId}`);
globalOverrides.push(override);
}
}
return ruleset;
};
this.ruleMatchesEvent = function(rule, ev) {
let ret = true;
for (let i = 0; i < rule.conditions.length; ++i) {
@@ -331,7 +389,8 @@ function PushProcessor(client) {
* @return {PushAction}
*/
this.actionsForEvent = function(ev) {
return pushActionsForEventAndRulesets(ev, client.pushRules);
const rules = applyRuleDefaults(client.pushRules);
return pushActionsForEventAndRulesets(ev, rules);
};
/**
+1 -1
View File
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
/* eslint-disable no-invalid-this */
/* eslint-disable babel/no-invalid-this */
import Promise from 'bluebird';
import {MemoryStore} from "./memory";
+7 -5
View File
@@ -116,10 +116,15 @@ function SyncApi(client, opts) {
*/
SyncApi.prototype.createRoom = function(roomId) {
const client = this.client;
const {
timelineSupport,
unstableClientRelationAggregation,
} = client;
const room = new Room(roomId, client, client.getUserId(), {
lazyLoadMembers: this.opts.lazyLoadMembers,
pendingEventOrdering: this.opts.pendingEventOrdering,
timelineSupport: client.timelineSupport,
timelineSupport,
unstableClientRelationAggregation,
});
client.reEmitter.reEmit(room, ["Room.name", "Room.timeline", "Room.redaction",
"Room.receipt", "Room.tags",
@@ -127,6 +132,7 @@ SyncApi.prototype.createRoom = function(roomId) {
"Room.localEchoUpdated",
"Room.accountData",
"Room.myMembership",
"Room.replaceEvent",
]);
this._registerStateListeners(room);
return room;
@@ -711,7 +717,6 @@ SyncApi.prototype._syncFromCache = async function(savedSync) {
* @param {boolean} syncOptions.hasSyncedBefore
*/
SyncApi.prototype._sync = async function(syncOptions) {
debuglog("Starting sync request processing...");
const client = this.client;
if (!this._running) {
@@ -750,9 +755,7 @@ SyncApi.prototype._sync = async function(syncOptions) {
// Reset after a successful sync
this._failedSyncCount = 0;
debuglog("Storing sync data...");
await client.store.setSyncData(data);
debuglog("Sync data stored");
const syncEventData = {
oldSyncToken: syncToken,
@@ -767,7 +770,6 @@ SyncApi.prototype._sync = async function(syncOptions) {
}
try {
debuglog("Processing sync response...");
await this._processSyncResponse(syncEventData, data);
} catch(e) {
// log the exception with stack if we have it, else fall back
+512 -512
View File
File diff suppressed because it is too large Load Diff