Compare commits
20 Commits
v8.1.0
...
v8.2.0-rc.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b6b16067b | |||
| a2da0de17d | |||
| 93ff3edb6b | |||
| 7c67fd69dd | |||
| ed978f69fb | |||
| 743f2465ea | |||
| 41fffa233a | |||
| e45377166b | |||
| 24939bf0b0 | |||
| 3221be4855 | |||
| 3135f1ed24 | |||
| 1b0834ffb0 | |||
| d79d613cb7 | |||
| d8cc1f7b7a | |||
| d7c8856fdd | |||
| 9d80a332aa | |||
| e14f7b63c7 | |||
| 3bd2880923 | |||
| 2401ad7159 | |||
| 5d95398621 |
@@ -1,3 +1,22 @@
|
||||
Changes in [8.2.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.2.0-rc.1) (2020-08-26)
|
||||
==========================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.1.0...v8.2.0-rc.1)
|
||||
|
||||
* Add state event check
|
||||
[\#1449](https://github.com/matrix-org/matrix-js-sdk/pull/1449)
|
||||
* Add method to check whether client .well-known has been fetched
|
||||
[\#1444](https://github.com/matrix-org/matrix-js-sdk/pull/1444)
|
||||
* Handle auth errors during cross-signing key upload
|
||||
[\#1443](https://github.com/matrix-org/matrix-js-sdk/pull/1443)
|
||||
* Don't fail if the requested audio output isn't available
|
||||
[\#1448](https://github.com/matrix-org/matrix-js-sdk/pull/1448)
|
||||
* Fix logging failures
|
||||
[\#1447](https://github.com/matrix-org/matrix-js-sdk/pull/1447)
|
||||
* Log the constraints we pass to getUserMedia
|
||||
[\#1446](https://github.com/matrix-org/matrix-js-sdk/pull/1446)
|
||||
* Use SAS emoji data from matrix-doc
|
||||
[\#1440](https://github.com/matrix-org/matrix-js-sdk/pull/1440)
|
||||
|
||||
Changes in [8.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.1.0) (2020-08-17)
|
||||
================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.1.0-rc.1...v8.1.0)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "matrix-js-sdk",
|
||||
"version": "8.1.0",
|
||||
"version": "8.2.0-rc.1",
|
||||
"description": "Matrix Client-Server SDK for Javascript",
|
||||
"scripts": {
|
||||
"prepare": "yarn build",
|
||||
|
||||
@@ -21,6 +21,7 @@ import * as olmlib from "../../../src/crypto/olmlib";
|
||||
import {TestClient} from '../../TestClient';
|
||||
import {HttpResponse, setHttpResponses} from '../../test-utils';
|
||||
import {resetCrossSigningKeys, createSecretStorageKey} from "./crypto-utils";
|
||||
import { MatrixError } from '../../../src/http-api';
|
||||
|
||||
async function makeTestClient(userInfo, options, keys) {
|
||||
if (!keys) keys = {};
|
||||
@@ -77,6 +78,58 @@ describe("Cross Signing", function() {
|
||||
expect(alice.uploadDeviceSigningKeys).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should abort bootstrap if device signing auth fails", async function() {
|
||||
const alice = await makeTestClient(
|
||||
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
||||
);
|
||||
alice.uploadDeviceSigningKeys = async (auth, keys) => {
|
||||
const errorResponse = {
|
||||
session: "sessionId",
|
||||
flows: [
|
||||
{
|
||||
stages: [
|
||||
"m.login.password",
|
||||
],
|
||||
},
|
||||
],
|
||||
params: {},
|
||||
};
|
||||
|
||||
// If we're not just polling for flows, add on error rejecting the
|
||||
// auth attempt.
|
||||
if (auth) {
|
||||
Object.assign(errorResponse, {
|
||||
completed: [],
|
||||
error: "Invalid password",
|
||||
errcode: "M_FORBIDDEN",
|
||||
});
|
||||
}
|
||||
|
||||
const error = new MatrixError(errorResponse);
|
||||
error.httpStatus == 401;
|
||||
throw error;
|
||||
};
|
||||
alice.uploadKeySignatures = async () => {};
|
||||
alice.setAccountData = async () => {};
|
||||
alice.getAccountDataFromServer = async () => { };
|
||||
const authUploadDeviceSigningKeys = async func => await func({});
|
||||
|
||||
// Try bootstrap, expecting `authUploadDeviceSigningKeys` to pass
|
||||
// through failure, stopping before actually applying changes.
|
||||
let bootstrapDidThrow = false;
|
||||
try {
|
||||
await alice.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.errcode === "M_FORBIDDEN") {
|
||||
bootstrapDidThrow = true;
|
||||
}
|
||||
}
|
||||
expect(bootstrapDidThrow).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should upload a signature when a user is verified", async function() {
|
||||
const alice = await makeTestClient(
|
||||
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
||||
|
||||
+21
-8
@@ -357,6 +357,9 @@ export function MatrixClient(opts) {
|
||||
|
||||
this._cachedCapabilities = null; // { capabilities: {}, lastUpdated: timestamp }
|
||||
|
||||
this._clientWellKnown = undefined;
|
||||
this._clientWellKnownPromise = undefined;
|
||||
|
||||
// The SDK doesn't really provide a clean way for events to recalculate the push
|
||||
// actions for themselves, so we have to kinda help them out when they are encrypted.
|
||||
// We do this so that push rules are correctly executed on events in their decrypted
|
||||
@@ -4810,20 +4813,23 @@ MatrixClient.prototype.startClient = async function(opts) {
|
||||
};
|
||||
|
||||
MatrixClient.prototype._fetchClientWellKnown = async function() {
|
||||
try {
|
||||
this._clientWellKnown = await AutoDiscovery.getRawClientConfig(this.getDomain());
|
||||
this.emit("WellKnown.client", this._clientWellKnown);
|
||||
} catch (err) {
|
||||
logger.error("Failed to get client well-known", err);
|
||||
this._clientWellKnown = undefined;
|
||||
this.emit("WellKnown.error", err);
|
||||
}
|
||||
// `getRawClientConfig` does not throw or reject on network errors, instead
|
||||
// it absorbs errors and returns `{}`.
|
||||
this._clientWellKnownPromise = AutoDiscovery.getRawClientConfig(
|
||||
this.getDomain(),
|
||||
);
|
||||
this._clientWellKnown = await this._clientWellKnownPromise;
|
||||
this.emit("WellKnown.client", this._clientWellKnown);
|
||||
};
|
||||
|
||||
MatrixClient.prototype.getClientWellKnown = function() {
|
||||
return this._clientWellKnown;
|
||||
};
|
||||
|
||||
MatrixClient.prototype.waitForClientWellKnown = function() {
|
||||
return this._clientWellKnownPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* store client options with boolean/string/numeric values
|
||||
* to know in the next session what flags the sync data was
|
||||
@@ -5698,6 +5704,13 @@ MatrixClient.prototype.generateClientSecret = function() {
|
||||
* @param {string} data.request_id The ID of the original request.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fires when the client .well-known info is fetched.
|
||||
*
|
||||
* @event module:client~MatrixClient#"WellKnown.client"
|
||||
* @param {object} data The JSON object returned by the server
|
||||
*/
|
||||
|
||||
// EventEmitter JSDocs
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
*/
|
||||
export class EncryptionSetupBuilder {
|
||||
/**
|
||||
* @param {Object.<String, MatrixEvent>} accountData pre-existing account data, will only be read, not written.
|
||||
* @param {Object.<String, MatrixEvent>} accountData pre-existing account data, will only be read, not written.
|
||||
* @param {CryptoCallbacks} delegateCryptoCallbacks crypto callbacks to delegate to if the key isn't in cache yet
|
||||
*/
|
||||
constructor(accountData, delegateCryptoCallbacks) {
|
||||
@@ -33,11 +33,17 @@ export class EncryptionSetupBuilder {
|
||||
|
||||
/**
|
||||
* Adds new cross-signing public keys
|
||||
* @param {Object} auth auth dictionary needed to upload the new keys
|
||||
*
|
||||
* @param {function} authUpload Function called to await an interactive auth
|
||||
* flow when uploading device signing keys.
|
||||
* Args:
|
||||
* {function} A function that makes the request requiring auth. Receives
|
||||
* the auth data as an object. Can be called multiple times, first with
|
||||
* an empty authDict, to obtain the flows.
|
||||
* @param {Object} keys the new keys
|
||||
*/
|
||||
addCrossSigningKeys(auth, keys) {
|
||||
this._crossSigningKeys = {auth, keys};
|
||||
addCrossSigningKeys(authUpload, keys) {
|
||||
this._crossSigningKeys = {authUpload, keys};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,25 +171,28 @@ export class EncryptionSetupOperation {
|
||||
*/
|
||||
async apply(crypto) {
|
||||
const baseApis = crypto._baseApis;
|
||||
// set account data
|
||||
if (this._accountData) {
|
||||
for (const [type, content] of this._accountData) {
|
||||
await baseApis.setAccountData(type, content);
|
||||
}
|
||||
}
|
||||
// upload cross-signing keys
|
||||
if (this._crossSigningKeys) {
|
||||
const keys = {};
|
||||
for (const [name, key] of Object.entries(this._crossSigningKeys.keys)) {
|
||||
keys[name + "_key"] = key;
|
||||
}
|
||||
await baseApis.uploadDeviceSigningKeys(
|
||||
this._crossSigningKeys.auth,
|
||||
keys,
|
||||
);
|
||||
|
||||
// We must only call `uploadDeviceSigningKeys` from inside this auth
|
||||
// helper to ensure we properly handle auth errors.
|
||||
await this._crossSigningKeys.authUpload(authDict => {
|
||||
return baseApis.uploadDeviceSigningKeys(authDict, keys);
|
||||
});
|
||||
|
||||
// pass the new keys to the main instance of our own CrossSigningInfo.
|
||||
crypto._crossSigningInfo.setKeys(this._crossSigningKeys.keys);
|
||||
}
|
||||
// set account data
|
||||
if (this._accountData) {
|
||||
for (const [type, content] of this._accountData) {
|
||||
await baseApis.setAccountData(type, content);
|
||||
}
|
||||
}
|
||||
// upload first cross-signing signatures with the new key
|
||||
// (e.g. signing our own device)
|
||||
if (this._keySignatures) {
|
||||
|
||||
+5
-12
@@ -453,7 +453,8 @@ Crypto.prototype.isCrossSigningReady = async function() {
|
||||
* called to await an interactive auth flow when uploading device signing keys.
|
||||
* Args:
|
||||
* {function} A function that makes the request requiring auth. Receives the
|
||||
* auth data as an object. Can be called multiple times, first with an empty authDict, to obtain the flows.
|
||||
* auth data as an object. Can be called multiple times, first with an empty
|
||||
* authDict, to obtain the flows.
|
||||
* @param {function} [opts.createSecretStorageKey] Optional. Function
|
||||
* called to await a secret storage key creation flow.
|
||||
* Returns:
|
||||
@@ -525,17 +526,9 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
// sign master key with device key
|
||||
await this._signObject(crossSigningInfo.keys.master);
|
||||
|
||||
await authUploadDeviceSigningKeys(authDict => {
|
||||
if (authDict) {
|
||||
builder.addCrossSigningKeys(authDict, crossSigningInfo.keys);
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
// This callback also gets called to obtain the IUA flows,
|
||||
// so do a call to obtain those if we don't have the authDict yet
|
||||
// We should get called again at a later point with the authDict.
|
||||
return this._baseApis.uploadDeviceSigningKeys(null, {});
|
||||
}
|
||||
});
|
||||
// Store auth flow helper function, as we need to call it when uploading
|
||||
// to ensure we handle auth errors properly.
|
||||
builder.addCrossSigningKeys(authUploadDeviceSigningKeys, crossSigningInfo.keys);
|
||||
|
||||
// cross-sign own device
|
||||
const device = this._deviceList.getStoredDevice(this._userId, this._deviceId);
|
||||
|
||||
+1
-1
@@ -626,7 +626,7 @@ utils.extend(MatrixEvent.prototype, {
|
||||
* @return {boolean} True if this event is encrypted.
|
||||
*/
|
||||
isEncrypted: function() {
|
||||
return this.event.type === "m.room.encrypted";
|
||||
return !this.isState() && this.event.type === "m.room.encrypted";
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+13
-6
@@ -403,7 +403,7 @@ MatrixCall.prototype._initWithHangup = function(event) {
|
||||
* Answer a call.
|
||||
*/
|
||||
MatrixCall.prototype.answer = function() {
|
||||
debuglog("Answering call %s of type %s", this.callId, this.type);
|
||||
debuglog(`Answering call ${this.callId} of type ${this.type}`);
|
||||
const self = this;
|
||||
|
||||
if (self._answerContent) {
|
||||
@@ -412,8 +412,10 @@ MatrixCall.prototype.answer = function() {
|
||||
}
|
||||
|
||||
if (!this.localAVStream && !this.waitForLocalAVStream) {
|
||||
const constraints = _getUserMediaVideoContraints(this.type);
|
||||
logger.log("Getting user media with constraints", constraints);
|
||||
this.webRtc.getUserMedia(
|
||||
_getUserMediaVideoContraints(this.type),
|
||||
constraints,
|
||||
hookCallback(self, self._maybeGotUserMediaForAnswer),
|
||||
hookCallback(self, self._maybeGotUserMediaForAnswer),
|
||||
);
|
||||
@@ -1065,7 +1067,7 @@ const terminate = function(self, hangupParty, hangupReason, shouldEmit) {
|
||||
};
|
||||
|
||||
const stopAllMedia = function(self) {
|
||||
debuglog("stopAllMedia (stream=%s)", self.localAVStream);
|
||||
debuglog(`stopAllMedia (stream=${self.localAVStream})`);
|
||||
if (self.localAVStream) {
|
||||
forAllTracksOnStream(self.localAVStream, function(t) {
|
||||
if (t.stop) {
|
||||
@@ -1127,7 +1129,11 @@ const _tryPlayRemoteAudioStream = async function(self) {
|
||||
const player = self.getRemoteAudioElement();
|
||||
|
||||
// if audioOutput is non-default:
|
||||
if (audioOutput) await player.setSinkId(audioOutput);
|
||||
try {
|
||||
if (audioOutput) await player.setSinkId(audioOutput);
|
||||
} catch (e) {
|
||||
logger.warn("Couldn't set requested audio output device: using default", e);
|
||||
}
|
||||
|
||||
player.autoplay = true;
|
||||
self.assignElement(player, self.remoteAStream, "remoteAudio");
|
||||
@@ -1188,8 +1194,8 @@ const _sendCandidateQueue = function(self) {
|
||||
|
||||
if (self.candidateSendTries > 5) {
|
||||
debuglog(
|
||||
"Failed to send candidates on attempt %s. Giving up for now.",
|
||||
self.candidateSendTries,
|
||||
"Failed to send candidates on attempt " + self.candidateSendTries +
|
||||
". Giving up for now.",
|
||||
);
|
||||
self.candidateSendTries = 0;
|
||||
return;
|
||||
@@ -1205,6 +1211,7 @@ const _sendCandidateQueue = function(self) {
|
||||
};
|
||||
|
||||
const _placeCallWithConstraints = function(self, constraints) {
|
||||
logger.log("Getting user media with constraints", constraints);
|
||||
self.client.callList[self.callId] = self;
|
||||
self.webRtc.getUserMedia(
|
||||
constraints,
|
||||
|
||||
Reference in New Issue
Block a user