Compare commits

...

89 Commits

Author SHA1 Message Date
RiotRobot 93f6bc3780 v9.6.0-rc.1 2021-01-29 17:20:04 +00:00
RiotRobot dde8f23cc3 Prepare changelog for v9.6.0-rc.1 2021-01-29 17:20:03 +00:00
RiotRobot 7cfbd0da95 Merge branch 'master' into develop 2021-01-26 11:42:21 +00:00
RiotRobot a27ddfaaaf v9.5.1 2021-01-26 11:39:39 +00:00
RiotRobot b53f616015 Prepare changelog for v9.5.1 2021-01-26 11:39:38 +00:00
J. Ryan Stinnett 22dc175879 Merge pull request #1585 from matrix-org/dbkr/voip-v0-release
[Release] Fix compatibility with v0 calls
2021-01-26 11:24:07 +00:00
David Baker 5f23e4699c We were using undefined here too 2021-01-26 11:17:44 +00:00
David Baker a1bd258a7b Remove unintentional commit 2021-01-26 11:17:44 +00:00
David Baker 39a9c54589 Fix compatability with v0 calls
https://github.com/matrix-org/matrix-js-sdk/pull/1567 introduced a
bug where we'd leave opponentPartyId undefined, but we compared it
to null later when testing for its presence.

Fixes https://github.com/vector-im/element-web/issues/16239
2021-01-26 11:17:44 +00:00
David Baker 5f68370e07 Merge pull request #1584 from matrix-org/dbkr/callstats
Add support for getting call stats
2021-01-26 10:53:53 +00:00
David Baker dae2de703d Add support for getting call stats
Also add a few 'public' annotations
2021-01-26 09:40:20 +00:00
David Baker fa19c40868 Merge pull request #1583 from matrix-org/dbkr/fix_v0_compat
Fix compatibility with v0 calls
2021-01-25 17:29:59 +00:00
David Baker 1df69d259a We were using undefined here too 2021-01-25 16:34:28 +00:00
David Baker 90dda0ca68 Remove unintentional commit 2021-01-25 16:13:13 +00:00
David Baker e2d138cac6 Fix compatability with v0 calls
https://github.com/matrix-org/matrix-js-sdk/pull/1567 introduced a
bug where we'd leave opponentPartyId undefined, but we compared it
to null later when testing for its presence.

Fixes https://github.com/vector-im/element-web/issues/16239
2021-01-25 16:09:39 +00:00
J. Ryan Stinnett 15f968d5f8 Merge pull request #1582 from matrix-org/jryans/upgrade-deps-2021-01
Upgrade deps 2021-01
2021-01-22 10:16:41 +00:00
David Baker f6aec7f763 Merge pull request #1581 from matrix-org/dbkr/log_the_call_id
Log the call ID when logging that we've received VoIP events
2021-01-21 17:59:49 +00:00
J. Ryan Stinnett 212b6c3a0f Resolve linting errors after upgrades 2021-01-20 13:54:45 +00:00
J. Ryan Stinnett 820256d451 Nested upgrades via yarn upgrade 2021-01-20 11:07:11 +00:00
J. Ryan Stinnett 3aba538db3 Update to latest deps 2021-01-20 11:05:17 +00:00
David Baker 4820cf8cac Log call ID here too 2021-01-19 19:28:08 +00:00
David Baker c289effba0 Log the call ID when logging that we've received VoIP events
Should make the logs a bit clearer
2021-01-19 18:11:41 +00:00
David Baker 3edccf496a Merge pull request #1579 from matrix-org/dbkr/foxes_dont_like_to_be_held
Fix extra negotiate message in Firefox
2021-01-19 17:51:35 +00:00
J. Ryan Stinnett 97b4171b3e Merge pull request #1580 from matrix-org/jryans/debug-encryption-prep
Add debug logs to encryption prep
2021-01-19 15:47:34 +00:00
J. Ryan Stinnett 4a073a7ba5 Fix lint 2021-01-19 15:36:08 +00:00
J. Ryan Stinnett 9f275d57a9 Add debug logs to encryption prep
This extra debug logs may help isolate the cause of
https://github.com/vector-im/element-web/issues/16194.

These changes also fix a related (but most likely different) failure mode: if a
failure occurred in the `encryptionPreparation` async task, we would skip trying
to prepare in all future attempts for that room. This change ensures prep
failures are logged and we resume prep attempts on the next call from the
application.
2021-01-19 15:28:28 +00:00
David Baker d23bbaeb06 Fix extra negotiate message in Firefox
Hopefully explained by the comments: Firefox sees that it's been
put on hold and tries to negotiate itself off hold again.

Fixes https://github.com/vector-im/element-web/issues/16190
2021-01-19 12:25:36 +00:00
J. Ryan Stinnett c64f7a9ec4 Merge pull request #1578 from tzyl/tzyl/get-presence-endpoint
Expose getPresence endpoint
2021-01-19 11:03:02 +00:00
RiotRobot 214a9df382 Resetting package fields for development 2021-01-18 15:06:36 +00:00
RiotRobot 90f6620f1e Merge branch 'master' into develop 2021-01-18 15:06:36 +00:00
RiotRobot 45f3a2f909 v9.5.0 2021-01-18 15:04:00 +00:00
RiotRobot 5904378170 Prepare changelog for v9.5.0 2021-01-18 15:03:59 +00:00
tzyl f6e8048d9e Expose getPresence endpoint 2021-01-18 10:17:46 +00:00
Hubert Chathi 5afca17d27 Merge pull request #1577 from uhoreg/always_queue_backup
Queue keys for backup even if backup isn't enabled yet
2021-01-15 12:28:06 -05:00
J. Ryan Stinnett 2d7f5ae279 Merge pull request #1576 from matrix-org/jryans/forbidden-turn
Stop retrying TURN access when forbidden
2021-01-15 10:06:18 +00:00
Hubert Chathi 458384d658 queue keys for backup even if backup isn't enabled yet
We may not have managed to set up the backup yet when we get keys.  So we should
unconditionally queue up the keys for backup, so that when the backup is set up,
they will be sent instead of dropped.
2021-01-14 19:55:02 -05:00
J. Ryan Stinnett 159b98132d Stop retrying TURN access when forbidden
If we're not allowed to have TURN access, there's no reason to ask in a loop.
2021-01-14 17:49:15 +00:00
David Baker f6d3b50b08 Merge pull request #1573 from matrix-org/dbkr/dtmf
Add DTMF sending support
2021-01-13 13:07:18 +00:00
RiotRobot 50ee489079 v9.5.0-rc.1 2021-01-13 12:54:37 +00:00
RiotRobot b60e5f40ab Prepare changelog for v9.5.0-rc.1 2021-01-13 12:54:36 +00:00
David Baker 5b1fdb7b37 Typo
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2021-01-13 11:37:30 +00:00
David Baker 65d4015300 Merge pull request #1574 from matrix-org/dbkr/dont_log_on_no_webrtc
Don't log if no WebRTC
2021-01-12 18:03:27 +00:00
David Baker b692cd109e Don't log if no WebRTC
as hopefully explained in comment
2021-01-12 17:58:35 +00:00
Will Hunt 0f90f055ba Merge pull request #1417 from matrix-org/hs/shared-rooms-api
Add _unstable_getSharedRooms
2021-01-11 22:38:56 +00:00
J. Ryan Stinnett 28d5ce288c Merge pull request #1568 from matrix-org/dependabot/npm_and_yarn/node-notifier-8.0.1
Bump node-notifier from 8.0.0 to 8.0.1
2021-01-11 13:12:59 +00:00
David Baker 6039066e7f Merge pull request #1567 from matrix-org/dbkr/ignore_party_id_v0_3
Ignore party ID if opponent is v0
2021-01-05 17:23:15 +00:00
David Baker c9a2f8b170 Merge pull request #1566 from matrix-org/dbkr/call_transfer_2
Basic call transfer initiation support
2021-01-05 17:22:08 +00:00
David Baker b34a36d853 Rename other supportsTransfers 2021-01-05 17:11:49 +00:00
David Baker f8f76f6806 Add DTMF sending support 2021-01-04 19:58:12 +00:00
David Baker e25ae546fc Merge pull request #1572 from matrix-org/dbkr/room_version_6
Room version 6 is now a thing
2021-01-04 15:23:01 +00:00
David Baker 5b73bf3e5d Room version 6 is now a thing
MSC2788 (https://github.com/matrix-org/matrix-doc/pull/2788) etc
2021-01-04 15:16:09 +00:00
Hubert Chathi c16b093bd7 Merge pull request #1571 from Sorunome/soru/receive-real-key-later
Store keys with same index but better trust level
2020-12-30 11:13:30 -05:00
Sorunome e406f32386 Store keys with same index but better trust level 2020-12-29 17:02:01 +01:00
David Baker 489d188966 Add a separate file for types 2020-12-22 15:37:58 +00:00
J. Ryan Stinnett 79fb7bab0b Merge pull request #1561 from matrix-org/jryans/prepublish-only
Use TypeScript source for development, swap to build during release
2020-12-22 13:48:15 +00:00
J. Ryan Stinnett c410954bad Replace dot-json with jq equivalents 2020-12-22 13:39:42 +00:00
J. Ryan Stinnett 53a8a7d50f Remove temporary prepare script
This was as a temporary measure during the last release so that downstream
layers would still have types as they expect.
2020-12-22 11:49:59 +00:00
J. Ryan Stinnett 1c7f95c0ee Use TypeScript source for development, swap to build during release
This changes the JS SDK to point `main` to TypeScript source and remove any
indication of `typings`. For local development and CI workflows, it means many
steps can run without building first, which saves lots of time.

During release, we still build for Node and browsers as before. The release
script adjusts the `main` and `typings` fields before publishing and
distribution to point to the built output for those that use them.
2020-12-22 11:48:57 +00:00
RiotRobot 1717fcf499 Merge branch 'master' into develop 2020-12-21 17:34:12 +00:00
RiotRobot b25453cf87 v9.4.1 2020-12-21 17:31:21 +00:00
RiotRobot 07b596bf30 Prepare changelog for v9.4.1 2020-12-21 17:29:58 +00:00
RiotRobot 1166947c21 Further tweaks to get all layers building again 2020-12-21 17:29:22 +00:00
dependabot[bot] 6e7b9ca6c0 Bump node-notifier from 8.0.0 to 8.0.1
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-21 16:54:57 +00:00
RiotRobot 5b1e3537cc Merge branch 'master' into develop 2020-12-21 16:53:35 +00:00
David Baker 712335789e Yes, thank you test, you've made your point 2020-12-21 16:30:16 +00:00
David Baker cdf8186f44 and also in the other direction 2020-12-21 16:30:08 +00:00
David Baker d06942d602 Ignore party ID if opponent is v0 2020-12-21 16:30:00 +00:00
David Baker 4f244da3ec Makean interface for the replaces event 2020-12-21 15:42:34 +00:00
David Baker 4eefa05d3f Another typo 2020-12-21 15:20:45 +00:00
David Baker 40fb31099a Typo 2020-12-21 15:18:21 +00:00
David Baker bcd85f5397 Rename to supportsCallTransfer
to be less ambiguous
2020-12-21 15:14:59 +00:00
David Baker 89aeda45c6 Basic call transfer initiation support
Re-commit of f3ee164a7d after I accidentally
merged to develop
2020-12-21 13:54:16 +00:00
David Baker 7581e5ffdc Merge pull request #1565 from matrix-org/revert-1559-dbkr/ignore_party_id_v0
Revert "Ignore party ID if opponent is v0"
2020-12-21 13:48:40 +00:00
David Baker 7046fa3224 Revert "Ignore party ID if opponent is v0" 2020-12-21 13:48:06 +00:00
David Baker ef392785e8 Merge pull request #1559 from matrix-org/dbkr/ignore_party_id_v0
Ignore party ID if opponent is v0
2020-12-21 13:47:33 +00:00
David Baker 5bd029115c Merge pull request #1562 from matrix-org/dbkr/honour_reject_from_self
Honour a call reject event from another of our own devices
2020-12-18 17:24:32 +00:00
David Baker b6f42b25dd Honour a call reject event from another of our own devices
Fixes a bug where the call would ring again when you refreshed,
even though you'd previously rejected it.
2020-12-18 13:45:13 +00:00
David Baker c0a88b7f4e Yes, thank you test, you've made your point 2020-12-15 18:06:48 +00:00
David Baker 150e5fede4 and also in the other direction 2020-12-15 16:22:11 +00:00
David Baker bb3ec322fb Ignore party ID if opponent is v0 2020-12-15 16:21:14 +00:00
David Baker f3ee164a7d Basic call transfer initiation support
Sends an m.call.replaces event and flag for whether to advertise
support.

MSC2747 (https://github.com/matrix-org/matrix-doc/pull/2747)
2020-12-15 14:51:29 +00:00
Will Hunt 6ec7e3a0b7 UserId must be sane 2020-08-18 18:42:55 +01:00
Will Hunt 1a1fe759c3 fix encoding bug 2020-08-18 18:41:45 +01:00
Will Hunt a919c798f8 Update _unstable_getSharedRooms to match spec 2020-08-18 18:34:44 +01:00
Will Hunt 80fe66c481 Add /uk.half-shot.msc2666/ prefix 2020-08-18 18:34:44 +01:00
Will Hunt 4577dc8f44 s/msc2644/msc2666/ 2020-08-18 18:34:44 +01:00
Will Hunt cf0a5305e0 Throw if server does not support getSharedRooms 2020-08-18 18:34:44 +01:00
Will Hunt e69e6e1981 Update _unstable_getSharedRooms response format 2020-08-18 18:34:44 +01:00
Will Hunt 0febd99fbe Add _unstable_getSharedRooms 2020-08-18 18:34:43 +01:00
17 changed files with 1118 additions and 522 deletions
+2
View File
@@ -35,6 +35,8 @@ module.exports = {
"files": ["src/**/*.ts"],
"extends": ["matrix-org/ts"],
"rules": {
// We're okay being explicit at the moment
"@typescript-eslint/no-empty-interface": "off",
// While we're converting to ts we make heavy use of this
"@typescript-eslint/no-explicit-any": "off",
"quotes": "off",
+73
View File
@@ -1,3 +1,76 @@
Changes in [9.6.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.6.0-rc.1) (2021-01-29)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.5.1...v9.6.0-rc.1)
* Add support for getting call stats
[\#1584](https://github.com/matrix-org/matrix-js-sdk/pull/1584)
* Fix compatibility with v0 calls
[\#1583](https://github.com/matrix-org/matrix-js-sdk/pull/1583)
* Upgrade deps 2021-01
[\#1582](https://github.com/matrix-org/matrix-js-sdk/pull/1582)
* Log the call ID when logging that we've received VoIP events
[\#1581](https://github.com/matrix-org/matrix-js-sdk/pull/1581)
* Fix extra negotiate message in Firefox
[\#1579](https://github.com/matrix-org/matrix-js-sdk/pull/1579)
* Add debug logs to encryption prep
[\#1580](https://github.com/matrix-org/matrix-js-sdk/pull/1580)
* Expose getPresence endpoint
[\#1578](https://github.com/matrix-org/matrix-js-sdk/pull/1578)
* Queue keys for backup even if backup isn't enabled yet
[\#1577](https://github.com/matrix-org/matrix-js-sdk/pull/1577)
* Stop retrying TURN access when forbidden
[\#1576](https://github.com/matrix-org/matrix-js-sdk/pull/1576)
* Add DTMF sending support
[\#1573](https://github.com/matrix-org/matrix-js-sdk/pull/1573)
Changes in [9.5.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.5.1) (2021-01-26)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.5.0...v9.5.1)
* [Release] Fix compatibility with v0 calls
[\#1585](https://github.com/matrix-org/matrix-js-sdk/pull/1585)
Changes in [9.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.5.0) (2021-01-18)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.5.0-rc.1...v9.5.0)
* No changes since rc.1
Changes in [9.5.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.5.0-rc.1) (2021-01-13)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.4.1...v9.5.0-rc.1)
* Don't log if no WebRTC
[\#1574](https://github.com/matrix-org/matrix-js-sdk/pull/1574)
* Add _unstable_getSharedRooms
[\#1417](https://github.com/matrix-org/matrix-js-sdk/pull/1417)
* Bump node-notifier from 8.0.0 to 8.0.1
[\#1568](https://github.com/matrix-org/matrix-js-sdk/pull/1568)
* Ignore party ID if opponent is v0
[\#1567](https://github.com/matrix-org/matrix-js-sdk/pull/1567)
* Basic call transfer initiation support
[\#1566](https://github.com/matrix-org/matrix-js-sdk/pull/1566)
* Room version 6 is now a thing
[\#1572](https://github.com/matrix-org/matrix-js-sdk/pull/1572)
* Store keys with same index but better trust level
[\#1571](https://github.com/matrix-org/matrix-js-sdk/pull/1571)
* Use TypeScript source for development, swap to build during release
[\#1561](https://github.com/matrix-org/matrix-js-sdk/pull/1561)
* Revert "Ignore party ID if opponent is v0"
[\#1565](https://github.com/matrix-org/matrix-js-sdk/pull/1565)
* Basic call transfer initiation support
[\#1558](https://github.com/matrix-org/matrix-js-sdk/pull/1558)
* Ignore party ID if opponent is v0
[\#1559](https://github.com/matrix-org/matrix-js-sdk/pull/1559)
* Honour a call reject event from another of our own devices
[\#1562](https://github.com/matrix-org/matrix-js-sdk/pull/1562)
Changes in [9.4.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.4.1) (2020-12-21)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.4.0...v9.4.1)
* Further script tweaks to get all layers building again
Changes in [9.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.4.0) (2020-12-21)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.4.0-rc.2...v9.4.0)
+17 -16
View File
@@ -1,10 +1,9 @@
{
"name": "matrix-js-sdk",
"version": "9.4.0",
"version": "9.6.0-rc.1",
"description": "Matrix Client-Server SDK for Javascript",
"scripts": {
"prepublishOnly": "yarn build",
"postinstall": "yarn build:dev",
"start": "echo THIS IS FOR LEGACY PURPOSES ONLY. && babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
"dist": "echo 'This is for the release script so it can make assets (browser bundle).' && yarn build",
"clean": "rimraf lib dist",
@@ -29,10 +28,11 @@
"matrix-org"
],
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"browser": "./lib/browser-index.js",
"matrix_src_main": "./src/index.ts",
"matrix_src_browser": "./src/browser-index.js",
"matrix_lib_main": "./lib/index.js",
"matrix_lib_typings": "./lib/index.d.ts",
"author": "matrix.org",
"license": "Apache-2.0",
"files": [
@@ -54,22 +54,22 @@
"bs58": "^4.0.1",
"content-type": "^1.0.4",
"loglevel": "^1.7.1",
"qs": "^6.9.4",
"qs": "^6.9.6",
"request": "^2.88.2",
"unhomoglyph": "^1.0.6"
},
"devDependencies": {
"@babel/cli": "^7.12.8",
"@babel/core": "^7.12.9",
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@babel/register": "^7.12.1",
"@types/jest": "^26.0.15",
"@babel/register": "^7.12.10",
"@types/jest": "^26.0.20",
"@types/node": "12",
"@types/request": "^2.48.5",
"babel-eslint": "^10.1.0",
@@ -78,22 +78,23 @@
"better-docs": "^2.3.2",
"browserify": "^17.0.0",
"docdash": "^1.2.0",
"eslint": "7.14.0",
"eslint-config-matrix-org": "^0.1.2",
"eslint": "7.18.0",
"eslint-config-matrix-org": "^0.2.0",
"eslint-plugin-babel": "^5.3.1",
"exorcist": "^1.0.1",
"fake-indexeddb": "^3.1.2",
"jest": "^26.6.3",
"jest-localstorage-mock": "^2.4.3",
"jest-localstorage-mock": "^2.4.6",
"jsdoc": "^3.6.6",
"matrix-mock-request": "^1.2.3",
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
"rimraf": "^3.0.2",
"terser": "^5.5.0",
"terser": "^5.5.1",
"tsify": "^5.0.2",
"typescript": "^4.1.2"
"typescript": "^4.1.3"
},
"jest": {
"testEnvironment": "node"
}
},
"typings": "./lib/index.d.ts"
}
+38
View File
@@ -178,6 +178,19 @@ echo "yarn version"
# manually commit the result.
yarn version --no-git-tag-version --new-version "$release"
# For the published and dist versions of the package, we copy the
# `matrix_lib_main` and `matrix_lib_typings` fields to `main` and `typings` (if
# they exist). This small bit of gymnastics allows us to use the TypeScript
# source directly for development without needing to build before linting or
# testing.
for i in main typings
do
lib_value=$(jq -r ".matrix_lib_$i" package.json)
if [ "$lib_value" != "null" ]; then
jq ".$i = .matrix_lib_$i" package.json > package.json.new && mv package.json.new package.json
fi
done
# commit yarn.lock if it exists, is versioned, and is modified
if [[ -f yarn.lock && `git status --porcelain yarn.lock | grep '^ M'` ]];
then
@@ -353,5 +366,30 @@ if [ $(git branch -lr | grep origin/develop -c) -ge 1 ]; then
git checkout develop
git pull
git merge master --no-edit
# When merging to develop, we need revert the `main` and `typings` fields if
# we adjusted them previously.
for i in main typings
do
# If a `lib` prefixed value is present, it means we adjusted the field
# earlier at publish time, so we should revert it now.
if [ "$(jq -r ".matrix_lib_$i" package.json)" != "null" ]; then
# If there's a `src` prefixed value, use that, otherwise delete.
# This is used to delete the `typings` field and reset `main` back
# to the TypeScript source.
src_value=$(jq -r ".matrix_src_$i" package.json)
if [ "$src_value" != "null" ]; then
jq ".$i = .matrix_src_$i" package.json > package.json.new && mv package.json.new package.json
else
jq "del(.$i)" package.json > package.json.new && mv package.json.new package.json
fi
fi
done
if [ -n "$(git ls-files --modified package.json)" ]; then
echo "Committing develop package.json"
git commit package.json -m "Resetting package fields for development"
fi
git push origin develop
fi
+56
View File
@@ -971,4 +971,60 @@ describe("megolm", function() {
expect(event.getContent().body).toEqual('42');
});
});
it("Alice receives an untrusted megolm key, only to receive the trusted one shortly after", function() {
const testClient = new TestClient(
"@alice:localhost", "device2", "access_token2",
);
const groupSession = new Olm.OutboundGroupSession();
groupSession.create();
const inboundGroupSession = new Olm.InboundGroupSession();
inboundGroupSession.create(groupSession.session_key());
const rawEvent = encryptMegolmEvent({
senderKey: testSenderKey,
groupSession: groupSession,
room_id: ROOM_ID,
});
return testClient.client.initCrypto().then(() => {
const keys = [{
room_id: ROOM_ID,
algorithm: 'm.megolm.v1.aes-sha2',
session_id: groupSession.session_id(),
session_key: inboundGroupSession.export_session(0),
sender_key: testSenderKey,
}];
return testClient.client.importRoomKeys(keys, { untrusted: true });
}).then(() => {
const event = testUtils.mkEvent({
event: true,
...rawEvent,
room: ROOM_ID,
});
return event.attemptDecryption(testClient.client._crypto, true).then(() => {
expect(event.isKeySourceUntrusted()).toBeTruthy();
});
}).then(() => {
const event = testUtils.mkEvent({
type: 'm.room_key',
content: {
room_id: ROOM_ID,
algorithm: 'm.megolm.v1.aes-sha2',
session_id: groupSession.session_id(),
session_key: groupSession.session_key(),
},
event: true,
});
event._senderCurve25519Key = testSenderKey;
return testClient.client._crypto._onRoomKeyEvent(event);
}).then(() => {
const event = testUtils.mkEvent({
event: true,
...rawEvent,
room: ROOM_ID,
});
return event.attemptDecryption(testClient.client._crypto, true).then(() => {
expect(event.isKeySourceUntrusted()).toBeFalsy();
});
});
});
});
+15
View File
@@ -521,4 +521,19 @@ describe("MatrixClient", function() {
xit("should be able to peek into a room using peekInRoom", function(done) {
});
});
describe("getPresence", function() {
it("should send a presence HTTP GET", function() {
httpLookups = [{
method: "GET",
path: `/presence/${encodeURIComponent(userId)}/status`,
data: {
"presence": "unavailable",
"last_active_ago": 420845,
},
}];
client.getPresence(userId);
expect(httpLookups.length).toEqual(0);
});
});
});
+3 -3
View File
@@ -142,7 +142,7 @@ describe('Call', function() {
await call.onAnswerReceived({
getContent: () => {
return {
version: 0,
version: 1,
call_id: call.callId,
party_id: 'the_correct_party_id',
answer: {
@@ -156,7 +156,7 @@ describe('Call', function() {
call.onRemoteIceCandidatesReceived({
getContent: () => {
return {
version: 0,
version: 1,
call_id: call.callId,
party_id: 'the_correct_party_id',
candidates: [
@@ -173,7 +173,7 @@ describe('Call', function() {
call.onRemoteIceCandidatesReceived({
getContent: () => {
return {
version: 0,
version: 1,
call_id: call.callId,
party_id: 'some_other_party_id',
candidates: [
+1
View File
@@ -48,6 +48,7 @@ export enum EventType {
CallReject = "m.call.reject",
CallSelectAnswer = "m.call.select_answer",
CallNegotiate = "m.call.negotiate",
CallReplaces = "m.call.replaces",
KeyVerificationRequest = "m.key.verification.request",
KeyVerificationStart = "m.key.verification.start",
KeyVerificationCancel = "m.key.verification.cancel",
+50
View File
@@ -180,6 +180,9 @@ function keyFromRecoverySession(session, decryptionKey) {
* @param {boolean} [opts.forceTURN]
* Optional. Whether relaying calls through a TURN server should be forced.
*
* @param {boolean} [opts.supportsCallTransfer]
* Optional. True to advertise support for call transfers to other parties on Matrix calls.
*
* @param {boolean} [opts.fallbackICEServerAllowed]
* Optional. Whether to allow a fallback ICE server should be used for negotiating a
* WebRTC connection if the homeserver doesn't provide any servers. Defaults to false.
@@ -364,6 +367,7 @@ export function MatrixClient(opts) {
this._cryptoCallbacks = opts.cryptoCallbacks || {};
this._forceTURN = opts.forceTURN || false;
this._supportsCallTransfer = opts.supportsCallTransfer || false;
this._fallbackICEServerAllowed = opts.fallbackICEServerAllowed || false;
// List of which rooms have encryption enabled: separate from crypto because
@@ -696,6 +700,14 @@ MatrixClient.prototype.setForceTURN = function(forceTURN) {
this._forceTURN = forceTURN;
};
/**
* Set whether to advertise transfer support to other parties on Matrix calls.
* @param {bool} supportsCallTransfer True to advertise the 'm.call.transferee' capability
*/
MatrixClient.prototype.setSupportsCallTransfer = function(supportsCallTransfer) {
this._supportsCallTransfer = supportsCallTransfer;
};
/**
* Get the current sync state.
* @return {?string} the sync state, which may be null.
@@ -3829,6 +3841,19 @@ MatrixClient.prototype.setPresence = function(opts, callback) {
);
};
/**
* @param {string} userId The user to get presence for
* @param {module:client.callback} callback Optional.
* @return {Promise} Resolves: The presence state for this user.
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
MatrixClient.prototype.getPresence = function(userId, callback) {
const path = utils.encodeUri("/presence/$userId/status", {
$userId: userId,
});
return this._http.authedRequest(callback, "GET", path, undefined, undefined);
};
/**
* Retrieve older messages from the given room and put them in the timeline.
@@ -5131,6 +5156,26 @@ MatrixClient.prototype._storeClientOptions = function() {
return this.store.storeClientOptions(serializableOpts);
};
/**
* Gets a set of room IDs in common with another user
* @param {string} userId The userId to check.
* @return {Promise<string[]>} Resolves to a set of rooms
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
MatrixClient.prototype._unstable_getSharedRooms = async function(userId) {
if (!(await this.doesServerSupportUnstableFeature("uk.half-shot.msc2666"))) {
throw Error('Server does not support shared_rooms API');
}
const path = utils.encodeUri("/uk.half-shot.msc2666/user/shared_rooms/$userId", {
$userId: userId,
});
const res = await this._http.authedRequest(
undefined, "GET", path, undefined, undefined,
{prefix: PREFIX_UNSTABLE},
);
return res.joined;
};
/**
* High level helper method to stop the client from polling and allow a
* clean shutdown.
@@ -5393,6 +5438,11 @@ function checkTurnServers(client) {
}
}, function(err) {
logger.error("Failed to get TURN URIs");
// If we get a 403, there's no point in looping forever.
if (err.httpStatus === 403) {
logger.info("TURN access unavailable for this account");
return;
}
client._checkTurnServersTimeoutID = setTimeout(function() {
checkTurnServers(client);
}, 60000);
+7 -2
View File
@@ -1059,9 +1059,14 @@ OlmDevice.prototype.addInboundGroupSession = async function(
+ senderKey + "/" + sessionId,
);
if (existingSession.first_known_index()
<= session.first_known_index()) {
<= session.first_known_index()
&& !(existingSession.first_known_index() == session.first_known_index()
&& !extraSessionData.untrusted
&& existingSessionData.untrusted)) {
// existing session has lower index (i.e. can
// decrypt more), so keep it
// decrypt more), or they have the same index and
// the new sessions trust does not win over the old
// sessions trust, so keep it
logger.log(
`Keeping existing megolm session ${sessionId}`,
);
+50 -34
View File
@@ -264,11 +264,14 @@ MegolmEncryption.prototype._ensureOutboundSession = async function(
await Promise.all([
(async () => {
// share keys with devices that we already have a session for
logger.debug(`Sharing keys with existing Olm sessions in ${this._roomId}`);
await this._shareKeyWithOlmSessions(
session, key, payload, olmSessions,
);
logger.debug(`Shared keys with existing Olm sessions in ${this._roomId}`);
})(),
(async () => {
logger.debug(`Sharing keys with new Olm sessions in ${this._roomId}`);
const errorDevices = [];
// meanwhile, establish olm sessions for devices that we don't
@@ -319,8 +322,10 @@ MegolmEncryption.prototype._ensureOutboundSession = async function(
} else {
await this._notifyFailedOlmDevices(session, key, errorDevices);
}
logger.debug(`Shared keys with new Olm sessions in ${this._roomId}`);
})(),
(async () => {
logger.debug(`Notifying blocked devices in ${this._roomId}`);
// also, notify blocked devices that they're blocked
const blockedMap = {};
for (const [userId, userBlockedDevices] of Object.entries(blocked)) {
@@ -336,6 +341,7 @@ MegolmEncryption.prototype._ensureOutboundSession = async function(
}
await this._notifyBlockedDevices(session, blockedMap);
logger.debug(`Notified blocked devices in ${this._roomId}`);
})(),
]);
};
@@ -348,6 +354,11 @@ MegolmEncryption.prototype._ensureOutboundSession = async function(
// first wait for the previous share to complete
const prom = this._setupPromise.then(prepareSession);
// Ensure any failures are logged for debugging
prom.catch(e => {
logger.error(`Failed to ensure outbound session in ${this._roomId}`, e);
});
// _setupPromise resolves to `session` whether or not the share succeeds
this._setupPromise = prom.then(returnSession, returnSession);
@@ -369,17 +380,11 @@ MegolmEncryption.prototype._prepareNewSession = async function() {
key.key, {ed25519: this._olmDevice.deviceEd25519Key},
);
if (this._crypto.backupInfo) {
// don't wait for it to complete
this._crypto.backupGroupSession(
this._roomId, this._olmDevice.deviceCurve25519Key, [],
sessionId, key.key,
).catch((e) => {
// This throws if the upload failed, but this is fine
// since it will have written it to the db and will retry.
logger.log("Failed to back up megolm session", e);
});
}
// don't wait for it to complete
this._crypto.backupGroupSession(
this._roomId, this._olmDevice.deviceCurve25519Key, [],
sessionId, key.key,
);
return new OutboundSessionInfo(sessionId);
};
@@ -846,24 +851,41 @@ MegolmEncryption.prototype.prepareToEncrypt = function(room) {
// We're already preparing something, so don't do anything else.
// FIXME: check if we need to restart
// (https://github.com/matrix-org/matrix-js-sdk/issues/1255)
const elapsedTime = Date.now() - this.encryptionPreparationMetadata.startTime;
logger.debug(
`Already started preparing to encrypt for ${this._roomId} ` +
`${elapsedTime} ms ago, skipping`,
);
return;
}
logger.debug(`Preparing to encrypt events for ${this._roomId}`);
this.encryptionPreparationMetadata = {
startTime: Date.now(),
};
this.encryptionPreparation = (async () => {
const [devicesInRoom, blocked] = await this._getDevicesInRoom(room);
try {
logger.debug(`Getting devices in ${this._roomId}`);
const [devicesInRoom, blocked] = await this._getDevicesInRoom(room);
if (this._crypto.getGlobalErrorOnUnknownDevices()) {
// Drop unknown devices for now. When the message gets sent, we'll
// throw an error, but we'll still be prepared to send to the known
// devices.
this._removeUnknownDevices(devicesInRoom);
if (this._crypto.getGlobalErrorOnUnknownDevices()) {
// Drop unknown devices for now. When the message gets sent, we'll
// throw an error, but we'll still be prepared to send to the known
// devices.
this._removeUnknownDevices(devicesInRoom);
}
logger.debug(`Ensuring outbound session in ${this._roomId}`);
await this._ensureOutboundSession(devicesInRoom, blocked, true);
logger.debug(`Ready to encrypt events for ${this._roomId}`);
} catch (e) {
logger.error(`Failed to prepare to encrypt events for ${this._roomId}`, e);
} finally {
delete this.encryptionPreparationMetadata;
delete this.encryptionPreparation;
}
await this._ensureOutboundSession(devicesInRoom, blocked, true);
delete this.encryptionPreparation;
})();
};
@@ -1347,18 +1369,12 @@ MegolmDecryption.prototype.onRoomKeyEvent = function(event) {
}
});
}).then(() => {
if (this._crypto.backupInfo) {
// don't wait for the keys to be backed up for the server
this._crypto.backupGroupSession(
content.room_id, senderKey, forwardingKeyChain,
content.session_id, content.session_key, keysClaimed,
exportFormat,
).catch((e) => {
// This throws if the upload failed, but this is fine
// since it will have written it to the db and will retry.
logger.log("Failed to back up megolm session", e);
});
}
// don't wait for the keys to be backed up for the server
this._crypto.backupGroupSession(
content.room_id, senderKey, forwardingKeyChain,
content.session_id, content.session_key, keysClaimed,
exportFormat,
);
}).catch((e) => {
logger.error(`Error handling m.room_key_event: ${e}`);
});
@@ -1564,7 +1580,7 @@ MegolmDecryption.prototype.importRoomKey = function(session, opts = {}) {
true,
opts.untrusted ? { untrusted: opts.untrusted } : {},
).then(() => {
if (this._crypto.backupInfo && opts.source !== "backup") {
if (opts.source !== "backup") {
// don't wait for it to complete
this._crypto.backupGroupSession(
session.room_id,
+7 -7
View File
@@ -2884,18 +2884,18 @@ Crypto.prototype.backupGroupSession = async function(
sessionId, sessionKey, keysClaimed,
exportFormat,
) {
if (!this.backupInfo) {
throw new Error("Key backups are not enabled");
}
await this._cryptoStore.markSessionsNeedingBackup([{
senderKey: senderKey,
sessionId: sessionId,
}]);
// don't wait for this to complete: it will delay so
// happens in the background
this.scheduleKeyBackupSend();
if (this.backupInfo) {
// don't wait for this to complete: it will delay so
// happens in the background
this.scheduleKeyBackupSend();
}
// if this.backupInfo is not set, then the keys will be backed up when
// client.enableKeyBackup is called
};
/**
+1
View File
@@ -142,6 +142,7 @@ export interface ICreateClientOpts {
unstableClientRelationAggregation?: boolean;
verificationMethods?: Array<any>;
forceTURN?: boolean;
supportsCallTransfer?: boolean,
fallbackICEServerAllowed?: boolean;
cryptoCallbacks?: ICryptoCallbacks;
}
+2 -2
View File
@@ -37,8 +37,8 @@ import {ReEmitter} from '../ReEmitter';
// room versions which are considered okay for people to run without being asked
// to upgrade (ie: "stable"). Eventually, we should remove these when all homeservers
// return an m.room_versions capability.
const KNOWN_SAFE_ROOM_VERSION = '5';
const SAFE_ROOM_VERSIONS = ['1', '2', '3', '4', '5'];
const KNOWN_SAFE_ROOM_VERSION = '6';
const SAFE_ROOM_VERSIONS = ['1', '2', '3', '4', '5', '6'];
function synthesizeReceipt(userId, event, receiptType) {
// console.log("synthesizing receipt for "+event.getId());
+148 -23
View File
@@ -27,6 +27,8 @@ import * as utils from '../utils';
import MatrixEvent from '../models/event';
import {EventType} from '../@types/event';
import { RoomMember } from '../models/room-member';
import { randomString } from '../randomstring';
import { MCallReplacesEvent, MCallAnswer, MCallOfferNegotiate, CallCapabilities } from './callEventTypes';
// events: hangup, error(err), replaced(call), state(state, oldState)
@@ -194,6 +196,10 @@ export class CallError extends Error {
}
}
function genCallID() {
return Date.now() + randomString(16);
}
/**
* Construct a new Matrix Call.
* @constructor
@@ -240,6 +246,7 @@ export class MatrixCall extends EventEmitter {
// The party ID of the other side: undefined if we haven't chosen a partner
// yet, null if we have but they didn't send a party ID.
private opponentPartyId: string;
private opponentCaps: CallCapabilities;
private inviteTimeout: NodeJS.Timeout; // in the browser it's 'number'
// The logic of when & if a call is on hold is nontrivial and explained in is*OnHold
@@ -253,6 +260,11 @@ export class MatrixCall extends EventEmitter {
private micMuted;
private vidMuted;
// the stats for the call at the point it ended. We can't get these after we
// tear the call down, so we just grab a snapshot before we stop the call.
// The typescript definitions have this type as 'any' :(
private callStatsAtEnd: any[];
// Perfect negotiation state: https://www.w3.org/TR/webrtc/#perfect-negotiation-example
private makingOffer: boolean;
private ignoreOffer: boolean;
@@ -264,6 +276,9 @@ export class MatrixCall extends EventEmitter {
this.type = null;
this.forceTURN = opts.forceTURN;
this.ourPartyId = this.client.deviceId;
// We compare this to null to checks the presence of a party ID:
// make sure it's null, not undefined
this.opponentPartyId = null;
// Array of Objects with urls, username, credential keys
this.turnServers = opts.turnServers || [];
if (this.turnServers.length === 0 && this.client.isFallbackICEServerAllowed()) {
@@ -275,7 +290,7 @@ export class MatrixCall extends EventEmitter {
utils.checkObjectHasKeys(server, ["urls"]);
}
this.callId = "c" + new Date().getTime() + Math.random();
this.callId = genCallID();
this.state = CallState.Fledgling;
// A queue for candidates waiting to go out.
@@ -354,15 +369,19 @@ export class MatrixCall extends EventEmitter {
this.type = CallType.Video;
}
getOpponentMember() {
public getOpponentMember() {
return this.opponentMember;
}
public opponentCanBeTransferred() {
return Boolean(this.opponentCaps && this.opponentCaps["m.call.transferee"]);
}
/**
* Retrieve the local <code>&lt;video&gt;</code> DOM element.
* @return {Element} The dom element
*/
getLocalVideoElement(): HTMLVideoElement {
public getLocalVideoElement(): HTMLVideoElement {
return this.localVideoElement;
}
@@ -371,7 +390,7 @@ export class MatrixCall extends EventEmitter {
* used for playing back video capable streams.
* @return {Element} The dom element
*/
getRemoteVideoElement(): HTMLVideoElement {
public getRemoteVideoElement(): HTMLVideoElement {
return this.remoteVideoElement;
}
@@ -380,7 +399,7 @@ export class MatrixCall extends EventEmitter {
* used for playing back audio only streams.
* @return {Element} The dom element
*/
getRemoteAudioElement(): HTMLAudioElement {
public getRemoteAudioElement(): HTMLAudioElement {
return this.remoteAudioElement;
}
@@ -389,7 +408,7 @@ export class MatrixCall extends EventEmitter {
* video will be rendered to it immediately.
* @param {Element} element The <code>&lt;video&gt;</code> DOM element.
*/
async setLocalVideoElement(element : HTMLVideoElement) {
public async setLocalVideoElement(element : HTMLVideoElement) {
this.localVideoElement = element;
if (element && this.localAVStream && this.type === CallType.Video) {
@@ -410,7 +429,7 @@ export class MatrixCall extends EventEmitter {
* the first received video-capable stream will be rendered to it immediately.
* @param {Element} element The <code>&lt;video&gt;</code> DOM element.
*/
setRemoteVideoElement(element : HTMLVideoElement) {
public setRemoteVideoElement(element : HTMLVideoElement) {
if (element === this.remoteVideoElement) return;
element.autoplay = true;
@@ -432,7 +451,7 @@ export class MatrixCall extends EventEmitter {
* The audio will *not* be rendered from the remoteVideoElement.
* @param {Element} element The <code>&lt;video&gt;</code> DOM element.
*/
async setRemoteAudioElement(element: HTMLAudioElement) {
public async setRemoteAudioElement(element: HTMLAudioElement) {
if (element === this.remoteAudioElement) return;
this.remoteAudioElement = element;
@@ -440,12 +459,32 @@ export class MatrixCall extends EventEmitter {
if (this.remoteStream) this.playRemoteAudio();
}
// The typescript definitions have this type as 'any' :(
public async getCurrentCallStats(): Promise<any[]> {
if (this.callHasEnded()) {
return this.callStatsAtEnd;
}
return this.collectCallStats();
}
private async collectCallStats(): Promise<any[]> {
const statsReport = await this.peerConn.getStats();
const stats = [];
for (const item of statsReport) {
stats.push(item[1]);
}
return stats;
}
/**
* Configure this call from an invite event. Used by MatrixClient.
* @param {MatrixEvent} event The m.call.invite event
*/
async initWithInvite(event: MatrixEvent) {
this.msg = event.getContent();
this.direction = CallDirection.Inbound;
this.peerConn = this.createPeerConnection();
try {
await this.peerConn.setRemoteDescription(this.msg.offer);
@@ -467,9 +506,12 @@ export class MatrixCall extends EventEmitter {
this.type = this.remoteStream.getTracks().some(t => t.kind === 'video') ? CallType.Video : CallType.Voice;
this.setState(CallState.Ringing);
this.direction = CallDirection.Inbound;
this.opponentVersion = this.msg.version;
this.opponentPartyId = this.msg.party_id || null;
if (this.opponentVersion !== 0) {
// ignore party ID in v0 calls: party ID isn't a thing until v1
this.opponentPartyId = this.msg.party_id || null;
}
this.opponentCaps = this.msg.capabilities || {};
this.opponentMember = event.sender;
if (event.getLocalAge()) {
@@ -694,6 +736,21 @@ export class MatrixCall extends EventEmitter {
return callOnHold;
}
/**
* Sends a DTMF digit to the other party
* @param digit The digit (nb. string - '#' and '*' are dtmf too)
*/
sendDtmfDigit(digit: string) {
for (const sender of this.peerConn.getSenders()) {
if (sender.track.kind === 'audio' && sender.dtmf) {
sender.dtmf.insertDTMF(digit);
return;
}
}
throw new Error("Unable to find a track to send DTMF on");
}
private updateMuteStatus() {
if (!this.localAVStream) {
return;
@@ -779,7 +836,14 @@ export class MatrixCall extends EventEmitter {
// required to still be sent for backwards compat
type: this.peerConn.localDescription.type,
},
};
} as MCallAnswer;
if (this.client._supportsCallTransfer) {
answerContent.capabilities = {
'm.call.transferee': true,
}
}
// We have just taken the local description from the peerconnection which will
// contain all the local candidates added so far, so we can discard any candidates
// we had queued up because they'll be in the answer.
@@ -950,7 +1014,7 @@ export class MatrixCall extends EventEmitter {
return;
}
if (this.opponentPartyId !== undefined) {
if (this.opponentPartyId !== null) {
logger.info(
`Ignoring answer from party ID ${event.getContent().party_id}: ` +
`we already have an answer/reject from ${this.opponentPartyId}`,
@@ -959,7 +1023,10 @@ export class MatrixCall extends EventEmitter {
}
this.opponentVersion = event.getContent().version;
this.opponentPartyId = event.getContent().party_id || null;
if (this.opponentVersion !== 0) {
this.opponentPartyId = event.getContent().party_id || null;
}
this.opponentCaps = event.getContent().capabilities || {};
this.opponentMember = event.sender;
this.setState(CallState.Connecting);
@@ -1044,8 +1111,21 @@ export class MatrixCall extends EventEmitter {
await this.peerConn.setRemoteDescription(description);
if (description.type === 'offer') {
// First we sent the direction of the tranciever to what we'd like it to be,
// irresepective of whether the other side has us on hold - so just whether we
// want the call to be on hold or not. This is necessary because in a few lines,
// we'll adjust the direction and unless we do this too, we'll never come off hold.
for (const tranceiver of this.peerConn.getTransceivers()) {
tranceiver.direction = this.isRemoteOnHold() ? 'inactive' : 'sendrecv';
}
const localDescription = await this.peerConn.createAnswer();
await this.peerConn.setLocalDescription(localDescription);
// Now we've got our answer, set the direction to the outcome of the negotiation.
// We need to do this otherwise Firefox will notice that the direction is not the
// currentDirection and try to negotiate itself off hold again.
for (const tranceiver of this.peerConn.getTransceivers()) {
tranceiver.direction = tranceiver.currentDirection;
}
this.sendVoipEvent(EventType.CallNegotiate, {
description: this.peerConn.localDescription,
@@ -1096,13 +1176,24 @@ export class MatrixCall extends EventEmitter {
if (this.callHasEnded()) return;
const keyName = this.state === CallState.CreateOffer ? 'offer' : 'description';
const eventType = this.state === CallState.CreateOffer ? EventType.CallInvite : EventType.CallNegotiate;
const content = {
[keyName]: this.peerConn.localDescription,
lifetime: CALL_TIMEOUT_MS,
};
} as MCallOfferNegotiate;
// clunky because TypeScript can't folow the types through if we use an expression as the key
if (this.state === CallState.CreateOffer) {
content.offer = this.peerConn.localDescription;
} else {
content.description = this.peerConn.localDescription;
}
if (this.client._supportsCallTransfer) {
content.capabilities = {
'm.call.transferee': true,
}
}
// Get rid of any candidates waiting to be sent: they'll be included in the local
// description we just got and will send in the offer.
@@ -1178,7 +1269,7 @@ export class MatrixCall extends EventEmitter {
return; // because ICE can still complete as we're ending the call
}
logger.debug(
"ICE connection state changed to: " + this.peerConn.iceConnectionState,
"Call ID " + this.callId + ": ICE connection state changed to: " + this.peerConn.iceConnectionState,
);
// ideally we'd consider the call to be connected when we get media but
// chrome doesn't implement any of the 'onstarted' events yet
@@ -1296,11 +1387,11 @@ export class MatrixCall extends EventEmitter {
}
onHangupReceived = (msg) => {
logger.debug("Hangup received");
logger.debug("Hangup received for call ID " + + this.callId);
// party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen
// a partner yet but we're treating the hangup as a reject as per VoIP v0)
if (this.partyIdMatches(msg) || this.opponentPartyId === undefined || this.state === CallState.Ringing) {
if (this.partyIdMatches(msg) || this.state === CallState.Ringing) {
// default reason is user_hangup
this.terminate(CallParty.Remote, msg.reason || CallErrorCode.UserHangup, true);
} else {
@@ -1309,12 +1400,21 @@ export class MatrixCall extends EventEmitter {
};
onRejectReceived = (msg) => {
logger.debug("Reject received");
logger.debug("Reject received for call ID " + this.callId);
// No need to check party_id for reject because if we'd received either
// an answer or reject, we wouldn't be in state InviteSent
if (this.state === CallState.InviteSent) {
const shouldTerminate = (
// reject events also end the call if it's ringing: it's another of
// our devices rejecting the call.
([CallState.InviteSent, CallState.Ringing].includes(this.state)) ||
// also if we're in the init state and it's an inbound call, since
// this means we just haven't entered the ringing state yet
this.state === CallState.Fledgling && this.direction === CallDirection.Inbound
);
if (shouldTerminate) {
this.terminate(CallParty.Remote, CallErrorCode.UserHangup, true);
} else {
logger.debug(`Call is in state: ${this.state}: ignoring reject`);
@@ -1322,7 +1422,7 @@ export class MatrixCall extends EventEmitter {
};
onAnsweredElsewhere = (msg) => {
logger.debug("Answered elsewhere");
logger.debug("Call ID " + this.callId + " answered elsewhere");
this.terminate(CallParty.Remote, CallErrorCode.AnsweredElsewhere, true);
};
@@ -1370,9 +1470,33 @@ export class MatrixCall extends EventEmitter {
}
}
async transfer(targetUserId: string, targetRoomId?: string) {
// Fetch the target user's global profile info: their room avatar / displayname
// could be different in whatever room we shae with them.
const profileInfo = await this.client.getProfileInfo(targetUserId);
const replacementId = genCallID();
const body = {
replacement_id: genCallID(),
target_user: {
id: targetUserId,
display_name: profileInfo.display_name,
avatar_url: profileInfo.avatar_url,
},
create_call: replacementId,
} as MCallReplacesEvent;
if (targetRoomId) body.target_room = targetRoomId;
return this.sendVoipEvent(EventType.CallReplaces, body);
}
private async terminate(hangupParty: CallParty, hangupReason: CallErrorCode, shouldEmit: boolean) {
if (this.callHasEnded()) return;
this.callStatsAtEnd = await this.collectCallStats();
if (this.inviteTimeout) {
clearTimeout(this.inviteTimeout);
this.inviteTimeout = null;
@@ -1596,7 +1720,8 @@ export function setVideoInput(deviceId: string) { videoInput = deviceId; }
export function createNewMatrixCall(client: any, roomId: string, options?: CallOpts) {
// typeof prevents Node from erroring on an undefined reference
if (typeof(window) === 'undefined' || typeof(document) === 'undefined') {
logger.info("No window or document object: WebRTC is not supported in this environment");
// NB. We don't log here as apps try to create a call object as a test for
// whether calls are supported, so we shouldn't fill the logs up.
return null;
}
+37
View File
@@ -0,0 +1,37 @@
// allow camelcase as these are events type that go onto the wire
/* eslint-disable camelcase */
interface CallOfferAnswer {
type: string;
sdp: string;
}
export interface CallCapabilities {
'm.call.transferee': boolean;
}
export interface MCallAnswer {
answer: CallOfferAnswer;
capabilities: CallCapabilities;
}
export interface MCallOfferNegotiate {
offer: CallOfferAnswer;
description: CallOfferAnswer;
lifetime: number;
capabilities: CallCapabilities;
}
export interface MCallReplacesTarget {
id: string;
display_name: string;
avatar_url: string;
}
export interface MCallReplacesEvent {
replacement_id: string;
target_user: MCallReplacesTarget;
create_call: string;
target_room: string;
}
/* eslint-enable camelcase */
+611 -435
View File
File diff suppressed because it is too large Load Diff