Compare commits

...

29 Commits

Author SHA1 Message Date
RiotRobot a58e7a34e7 v5.0.1 2020-02-19 15:03:04 +00:00
RiotRobot 7a481beec6 Prepare changelog for v5.0.1 2020-02-19 15:03:03 +00:00
Bruno Windels d51fad2de4 Merge pull request #1219 from matrix-org/bwindels/fixaliases
add method for new /aliases endpoint
2020-02-19 10:02:32 +00:00
Bruno Windels c66755a756 jsdoc 2020-02-19 10:13:32 +01:00
Bruno Windels 886ad03505 add method to check server feature flag 2020-02-19 10:08:05 +01:00
Bruno Windels ba33ef0a68 use unstable prefix 2020-02-19 10:07:52 +01:00
Bruno Windels fe97dc3ece add method for new /aliases endpoint 2020-02-18 15:33:41 +01:00
Bruno Windels 04a3aaee35 Merge pull request #1213 from matrix-org/bwindels/filterverifmethods
method for checking if other party supports verification method
2020-02-18 10:15:49 +00:00
Bruno Windels fef03cda9b Update src/crypto/verification/request/VerificationRequest.js
Co-Authored-By: J. Ryan Stinnett <jryans@gmail.com>
2020-02-18 10:03:02 +00:00
Bruno Windels 3292fde41b Merge pull request #1210 from matrix-org/bwindels/localecho2
add local echo state for accepting or declining a verif req
2020-02-18 09:55:09 +00:00
RiotRobot 38cf25ac5a Merge branch 'master' into develop 2020-02-17 11:58:01 +00:00
Bruno Windels 62c344b633 Merge pull request #1214 from matrix-org/bwindels/workswithrageshakes
make logging compatible with rageshakes
2020-02-14 16:39:05 +00:00
Bruno Windels 75ce2729f9 comment typo 2020-02-14 17:35:07 +01:00
Bruno Windels 6669554867 make logging compatible with rageshakes 2020-02-14 17:31:40 +01:00
Bruno Windels d3294da37c Merge pull request #1209 from matrix-org/bwindels/oneverifrequest
Find existing requests when starting a new verification request
2020-02-14 15:33:06 +00:00
Bruno Windels 9b56bf25cf Update src/crypto/verification/request/InRoomChannel.js
Co-Authored-By: J. Ryan Stinnett <jryans@gmail.com>
2020-02-14 14:43:50 +00:00
Bruno Windels e1a33d8a7b Update src/crypto/verification/request/ToDeviceChannel.js
Co-Authored-By: J. Ryan Stinnett <jryans@gmail.com>
2020-02-14 13:41:38 +00:00
Bruno Windels 47a1224c13 Merge pull request #1211 from matrix-org/bwindels/logsasmac
log MAC calculation during SAS
2020-02-14 12:54:40 +00:00
Bruno Windels 5c57d81e94 method for checking if other party supports verification method 2020-02-14 13:47:24 +01:00
Bruno Windels edefd3ec88 log MAC calculation 2020-02-14 12:20:02 +01:00
Bruno Windels f15098efde add local echo state for accepting or declining a verif req 2020-02-13 17:27:18 +01:00
Bruno Windels 365bb772bc also find existing request for to-device verification 2020-02-13 15:37:21 +01:00
Bruno Windels 5ee6ada973 use pending instead of individual checks 2020-02-13 15:37:04 +01:00
Bruno Windels ee0fa0e687 fix lint 2020-02-13 14:47:35 +01:00
Bruno Windels 0d41f6aafc remove commented out logging 2020-02-13 14:36:18 +01:00
Bruno Windels 91b6499815 more consistent naming 2020-02-13 14:36:09 +01:00
Bruno Windels 7cd1166a47 allow finding existing verif req without starting a new one 2020-02-13 14:31:33 +01:00
Bruno Windels f76cb677ff store sasEvent on verifier so we can get it if we missed show_sas event 2020-02-13 14:31:03 +01:00
Bruno Windels 05e7f4e6f7 look for existing verification request when trying to start a new one 2020-02-13 14:30:38 +01:00
10 changed files with 198 additions and 13 deletions
+17
View File
@@ -1,3 +1,20 @@
Changes in [5.0.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v5.0.1) (2020-02-19)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v5.0.0...v5.0.1)
* add method for new /aliases endpoint
[\#1219](https://github.com/matrix-org/matrix-js-sdk/pull/1219)
* method for checking if other party supports verification method
[\#1213](https://github.com/matrix-org/matrix-js-sdk/pull/1213)
* add local echo state for accepting or declining a verif req
[\#1210](https://github.com/matrix-org/matrix-js-sdk/pull/1210)
* make logging compatible with rageshakes
[\#1214](https://github.com/matrix-org/matrix-js-sdk/pull/1214)
* Find existing requests when starting a new verification request
[\#1209](https://github.com/matrix-org/matrix-js-sdk/pull/1209)
* log MAC calculation during SAS
[\#1211](https://github.com/matrix-org/matrix-js-sdk/pull/1211)
Changes in [5.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v5.0.0) (2020-02-17)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v5.0.0-rc.1...v5.0.0)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "5.0.0",
"version": "5.0.1",
"description": "Matrix Client-Server SDK for Javascript",
"scripts": {
"prepare": "yarn build",
+15
View File
@@ -1119,6 +1119,21 @@ MatrixBaseApis.prototype.deleteAlias = function(alias, callback) {
);
};
/**
* @param {string} roomId
* @param {module:client.callback} callback Optional.
* @return {Promise} Resolves: an object with an `aliases` property, containing an array of local aliases
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
MatrixBaseApis.prototype.unstableGetLocalAliases =
function(roomId, callback) {
const path = utils.encodeUri("/rooms/$roomId/aliases",
{$roomId: roomId});
const prefix = PREFIX_UNSTABLE + "/org.matrix.msc2432";
return this._http.authedRequest(callback, "GET", path,
null, null, { prefix });
};
/**
* Get room info for the given alias.
* @param {string} alias The room alias to resolve.
+27
View File
@@ -918,6 +918,20 @@ MatrixClient.prototype.requestVerificationDM = function(userId, roomId) {
return this._crypto.requestVerificationDM(userId, roomId);
};
/**
* Finds a DM verification request that is already in progress for the given room id
*
* @param {string} roomId the room to use for verification
*
* @returns {module:crypto/verification/request/VerificationRequest?} the VerificationRequest that is in progress, if any
*/
MatrixClient.prototype.findVerificationRequestDMInProgress = function(roomId) {
if (this._crypto === null) {
throw new Error("End-to-end encryption disabled");
}
return this._crypto.findVerificationRequestDMInProgress(roomId);
};
/**
* Request a key verification from another user.
*
@@ -4783,6 +4797,19 @@ MatrixClient.prototype.doesServerSupportSeparateAddAndBind = async function() {
|| (unstableFeatures && unstableFeatures["m.separate_add_and_bind"]);
};
/**
* Query the server to see if it lists support for an unstable feature
* in the /versions response
* @param {string} feature the feature name
* @return {Promise<boolean>} true if the feature is supported
*/
MatrixClient.prototype.doesServerSupportUnstableFeature = async function(feature) {
const response = await this.getVersions();
if (!response) return false;
const unstableFeatures = response["unstable_features"];
return unstableFeatures && !!unstableFeatures[feature];
};
/**
* Get if lazy loading members is being used.
* @return {boolean} Whether or not members are lazy loaded by this client
+14
View File
@@ -1619,7 +1619,16 @@ Crypto.prototype.setDeviceVerification = async function(
return deviceObj;
};
Crypto.prototype.findVerificationRequestDMInProgress = function(roomId) {
return this._inRoomVerificationRequests.findRequestInProgress(roomId);
};
Crypto.prototype.requestVerificationDM = function(userId, roomId) {
const existingRequest = this._inRoomVerificationRequests.
findRequestInProgress(roomId);
if (existingRequest) {
return Promise.resolve(existingRequest);
}
const channel = new InRoomChannel(this._baseApis, roomId, userId);
return this._requestVerificationWithChannel(
userId,
@@ -1632,6 +1641,11 @@ Crypto.prototype.requestVerification = function(userId, devices) {
if (!devices) {
devices = Object.keys(this._deviceList.getRawStoredDevicesForUser(userId));
}
const existingRequest = this._toDeviceVerificationRequests
.findRequestInProgress(userId, devices);
if (existingRequest) {
return Promise.resolve(existingRequest);
}
const channel = new ToDeviceChannel(this._baseApis, userId, devices);
return this._requestVerificationWithChannel(
userId,
+21 -9
View File
@@ -28,6 +28,7 @@ import {
newUnknownMethodError,
newUserCancelledError,
} from './Error';
import {logger} from '../../logger';
const START_TYPE = "m.key.verification.start";
@@ -165,6 +166,15 @@ const macMethods = {
"hmac-sha256": "calculate_mac_long_kdf",
};
function calculateMAC(olmSAS, method) {
return function(...args) {
const macFunction = olmSAS[macMethods[method]];
const mac = macFunction.apply(olmSAS, args);
logger.log("SAS calculateMAC:", method, args, mac);
return mac;
};
}
/* lists of algorithms/methods that are supported. The key agreement, hashes,
* and MAC lists should be sorted in order of preference (most preferred
* first).
@@ -306,7 +316,7 @@ export class SAS extends Base {
+ this._channel.transactionId;
const sasBytes = olmSAS.generate_bytes(sasInfo, 6);
const verifySAS = new Promise((resolve, reject) => {
this.emit("show_sas", {
this.sasEvent = {
sas: generateSas(sasBytes, sasMethods),
confirm: () => {
this._sendMAC(olmSAS, macMethod);
@@ -314,7 +324,8 @@ export class SAS extends Base {
},
cancel: () => reject(newUserCancelledError()),
mismatch: () => reject(newMismatchedSASError()),
});
};
this.emit("show_sas", this.sasEvent);
});
@@ -390,7 +401,7 @@ export class SAS extends Base {
+ this._channel.transactionId;
const sasBytes = olmSAS.generate_bytes(sasInfo, 6);
const verifySAS = new Promise((resolve, reject) => {
this.emit("show_sas", {
this.sasEvent = {
sas: generateSas(sasBytes, sasMethods),
confirm: () => {
this._sendMAC(olmSAS, macMethod);
@@ -398,7 +409,8 @@ export class SAS extends Base {
},
cancel: () => reject(newUserCancelledError()),
mismatch: () => reject(newMismatchedSASError()),
});
};
this.emit("show_sas", this.sasEvent);
});
@@ -429,7 +441,7 @@ export class SAS extends Base {
+ this._channel.transactionId;
const deviceKeyId = `ed25519:${this._baseApis.deviceId}`;
mac[deviceKeyId] = olmSAS[macMethods[method]](
mac[deviceKeyId] = calculateMAC(olmSAS, method)(
this._baseApis.getDeviceEd25519Key(),
baseInfo + deviceKeyId,
);
@@ -438,14 +450,14 @@ export class SAS extends Base {
const crossSigningId = this._baseApis.getCrossSigningId();
if (crossSigningId) {
const crossSigningKeyId = `ed25519:${crossSigningId}`;
mac[crossSigningKeyId] = olmSAS[macMethods[method]](
mac[crossSigningKeyId] = calculateMAC(olmSAS, method)(
crossSigningId,
baseInfo + crossSigningKeyId,
);
keyList.push(crossSigningKeyId);
}
const keys = olmSAS[macMethods[method]](
const keys = calculateMAC(olmSAS, method)(
keyList.sort().join(","),
baseInfo + "KEY_IDS",
);
@@ -458,7 +470,7 @@ export class SAS extends Base {
+ this._baseApis.getUserId() + this._baseApis.deviceId
+ this._channel.transactionId;
if (content.keys !== olmSAS[macMethods[method]](
if (content.keys !== calculateMAC(olmSAS, method)(
Object.keys(content.mac).sort().join(","),
baseInfo + "KEY_IDS",
)) {
@@ -466,7 +478,7 @@ export class SAS extends Base {
}
await this._verifyKeys(this.userId, content.mac, (keyId, device, keyInfo) => {
if (keyInfo !== olmSAS[macMethods[method]](
if (keyInfo !== calculateMAC(olmSAS, method)(
device.keys[keyId],
baseInfo + keyId,
)) {
@@ -305,7 +305,6 @@ export class InRoomRequests {
getRequest(event) {
const roomId = event.getRoomId();
const txnId = InRoomChannel.getTransactionId(event);
// console.log(`looking for request in room ${roomId} with txnId ${txnId} for an ${event.getType()} from ${event.getSender()}...`);
return this._getRequestByTxnId(roomId, txnId);
}
@@ -351,4 +350,15 @@ export class InRoomRequests {
}
}
}
findRequestInProgress(roomId) {
const requestsByTxnId = this._requestsByRoomId.get(roomId);
if (requestsByTxnId) {
for (const request of requestsByTxnId.values()) {
if (request.pending) {
return request;
}
}
}
}
}
@@ -43,6 +43,20 @@ export class ToDeviceChannel {
this._deviceId = deviceId;
}
isToDevices(devices) {
if (devices.length === this._devices.length) {
for (const device of devices) {
const d = this._devices.find(d => d.deviceId === device.deviceId);
if (!d) {
return false;
}
}
return true;
} else {
return false;
}
}
get deviceId() {
return this._deviceId;
}
@@ -335,4 +349,15 @@ export class ToDeviceRequests {
}
}
}
findRequestInProgress(userId, devices) {
const requestsByTxnId = this._requestsByUserId.get(userId);
if (requestsByTxnId) {
for (const request of requestsByTxnId.values()) {
if (request.pending && request.channel.isToDevices(devices)) {
return request;
}
}
}
}
}
@@ -71,6 +71,8 @@ export class VerificationRequest extends EventEmitter {
this._observeOnly = false;
this._timeoutTimer = null;
this._sharedSecret = null; // used for QR codes
this._accepting = false;
this._declining = false;
}
/**
@@ -179,10 +181,50 @@ export class VerificationRequest extends EventEmitter {
return this._verifier;
}
get canAccept() {
return this.phase < PHASE_READY && !this._accepting && !this._declining;
}
get accepting() {
return this._accepting;
}
get declining() {
return this._declining;
}
/** whether this request has sent it's initial event and needs more events to complete */
get pending() {
return this._phase !== PHASE_DONE
&& this._phase !== PHASE_CANCELLED;
return !this.observeOnly &&
this._phase !== PHASE_DONE &&
this._phase !== PHASE_CANCELLED;
}
/** Checks whether the other party supports a given verification method.
* This is useful when setting up the QR code UI, as it is somewhat asymmetrical:
* if the other party supports SCAN_QR, we should show a QR code in the UI, and vice versa.
* For methods that need to be supported by both ends, use the `methods` property.
* @param {string} method the method to check
* @return {bool} whether or not the other party said the supported the method */
otherPartySupportsMethod(method) {
if (!this.ready && !this.started) {
return false;
}
const theirMethodEvent = this._eventsByThem.get(REQUEST_TYPE) ||
this._eventsByThem.get(READY_TYPE);
if (!theirMethodEvent) {
return false;
}
const content = theirMethodEvent.getContent();
if (!content) {
return false;
}
const {methods} = content;
if (!Array.isArray(methods)) {
return false;
}
return methods.includes(method);
}
/** Whether this request was initiated by the syncing user.
@@ -342,6 +384,8 @@ export class VerificationRequest extends EventEmitter {
*/
async cancel({reason = "User declined", code = "m.user"} = {}) {
if (!this.observeOnly && this._phase !== PHASE_CANCELLED) {
this._declining = true;
this.emit("change");
if (this._verifier) {
return this._verifier.cancel(errorFactory(code, reason)());
} else {
@@ -358,6 +402,8 @@ export class VerificationRequest extends EventEmitter {
async accept() {
if (!this.observeOnly && this.phase === PHASE_REQUESTED && !this.initiatedByMe) {
const methods = [...this._verificationMethods.keys()];
this._accepting = true;
this.emit("change");
await this.channel.send(READY_TYPE, {methods});
this._generateSharedSecret();
}
+19
View File
@@ -29,6 +29,25 @@ import log from "loglevel";
// Part of #332 is introducing a logging library in the first place.
const DEFAULT_NAMESPACE = "matrix";
// because rageshakes in react-sdk hijack the console log, also at module load time,
// initializing the logger here races with the initialization of rageshakes.
// to avoid the issue, we override the methodFactory of loglevel that binds to the
// console methods at initialization time by a factory that looks up the console methods
// when logging so we always get the current value of console methods.
log.methodFactory = function(methodName, logLevel, loggerName) {
return function(...args) {
const supportedByConsole = methodName === "error" ||
methodName === "warn" ||
methodName === "trace" ||
methodName === "info";
if (supportedByConsole) {
return console[methodName](...args);
} else {
return console.log(...args);
}
};
};
/**
* Drop-in replacement for <code>console</code> using {@link https://www.npmjs.com/package/loglevel|loglevel}.
* Can be tailored down to specific use cases if needed.