Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d310cd461 | |||
| 88c5c39fcb | |||
| eeddfd4919 | |||
| fa16da86b3 | |||
| af1b26ae95 | |||
| f72f5b43e1 | |||
| c7e1e07262 | |||
| 24a1bec23d | |||
| 89ad104423 | |||
| c2f3324302 | |||
| 04a969b997 | |||
| 630dfa9499 | |||
| 95668950c2 | |||
| 3012501e4b | |||
| 0e81dfb004 | |||
| 35b7f358b6 | |||
| e3e48944e0 | |||
| 94bbba72f5 | |||
| c429ca67b9 | |||
| bce2ba0785 | |||
| 2613690064 | |||
| 7283076bc8 | |||
| f43d05b54e | |||
| c6b500bc09 | |||
| c3972015c7 | |||
| 3c18c57857 | |||
| f562a06707 | |||
| 7f50dd205f | |||
| c4fe15400c | |||
| 6e3e8f7310 | |||
| 5ae2c26130 | |||
| d8d35f4022 | |||
| fadb4d9219 | |||
| b63149b36a | |||
| 79f92abcfa | |||
| 0137fb468b | |||
| 70ef8760cc | |||
| c74d2d831b |
@@ -1,3 +1,52 @@
|
||||
Changes in [0.10.8](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.8) (2018-08-20)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.8-rc.1...v0.10.8)
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
Changes in [0.10.8-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.8-rc.1) (2018-08-16)
|
||||
============================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.7...v0.10.8-rc.1)
|
||||
|
||||
* Add getVersion to Room
|
||||
[\#689](https://github.com/matrix-org/matrix-js-sdk/pull/689)
|
||||
* Add getSyncStateData()
|
||||
[\#680](https://github.com/matrix-org/matrix-js-sdk/pull/680)
|
||||
* Send sync error to listener
|
||||
[\#679](https://github.com/matrix-org/matrix-js-sdk/pull/679)
|
||||
* make sure room.tags is always a valid object to avoid crashes
|
||||
[\#675](https://github.com/matrix-org/matrix-js-sdk/pull/675)
|
||||
* Fix infinite spinner upon joining a room
|
||||
[\#673](https://github.com/matrix-org/matrix-js-sdk/pull/673)
|
||||
|
||||
Changes in [0.10.7](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.7) (2018-07-30)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.7-rc.1...v0.10.7)
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
Changes in [0.10.7-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.7-rc.1) (2018-07-24)
|
||||
============================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.6...v0.10.7-rc.1)
|
||||
|
||||
* encrypt for invited users if history visibility allows.
|
||||
[\#666](https://github.com/matrix-org/matrix-js-sdk/pull/666)
|
||||
|
||||
Changes in [0.10.6](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.6) (2018-07-09)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.6-rc.1...v0.10.6)
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
Changes in [0.10.6-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.6-rc.1) (2018-07-06)
|
||||
============================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.5...v0.10.6-rc.1)
|
||||
|
||||
* Expose event decryption error via Event.decrypted event
|
||||
[\#665](https://github.com/matrix-org/matrix-js-sdk/pull/665)
|
||||
* Add decryption error codes to base.DecryptionError
|
||||
[\#663](https://github.com/matrix-org/matrix-js-sdk/pull/663)
|
||||
|
||||
Changes in [0.10.5](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.10.5) (2018-06-29)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.10.5-rc.1...v0.10.5)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "matrix-js-sdk",
|
||||
"version": "0.10.5",
|
||||
"version": "0.10.8",
|
||||
"description": "Matrix Client-Server SDK for Javascript",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -162,6 +162,7 @@ describe("RoomState", function() {
|
||||
];
|
||||
let emitCount = 0;
|
||||
state.on("RoomState.newMember", function(ev, st, mem) {
|
||||
expect(state.getMember(mem.userId)).toEqual(mem);
|
||||
expect(mem.userId).toEqual(memberEvents[emitCount].getSender());
|
||||
expect(mem.membership).toBeFalsy(); // not defined yet
|
||||
emitCount += 1;
|
||||
|
||||
@@ -287,6 +287,21 @@ MatrixClient.prototype.getSyncState = function() {
|
||||
return this._syncApi.getSyncState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the additional data object associated with
|
||||
* the current sync state, or null if there is no
|
||||
* such data.
|
||||
* Sync errors, if available, are put in the 'error' key of
|
||||
* this object.
|
||||
* @return {?Object}
|
||||
*/
|
||||
MatrixClient.prototype.getSyncStateData = function() {
|
||||
if (!this._syncApi) {
|
||||
return null;
|
||||
}
|
||||
return this._syncApi.getSyncStateData();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return whether the client is configured for a guest account.
|
||||
* @return {boolean} True if this is a guest access_token (or no token is supplied).
|
||||
|
||||
@@ -176,8 +176,9 @@ export {DecryptionAlgorithm}; // https://github.com/jsdoc3/jsdoc/issues/1272
|
||||
* @extends Error
|
||||
*/
|
||||
class DecryptionError extends Error {
|
||||
constructor(msg, details) {
|
||||
constructor(code, msg, details) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
this.name = 'DecryptionError';
|
||||
this.detailedString = _detailedStringForDecryptionError(this, details);
|
||||
}
|
||||
|
||||
@@ -536,8 +536,7 @@ MegolmEncryption.prototype._checkForUnknownDevices = function(devicesInRoom) {
|
||||
* from userId to deviceId to deviceInfo
|
||||
*/
|
||||
MegolmEncryption.prototype._getDevicesInRoom = function(room) {
|
||||
// XXX what about rooms where invitees can see the content?
|
||||
const roomMembers = utils.map(room.getJoinedMembers(), function(u) {
|
||||
const roomMembers = utils.map(room.getEncryptionTargetMembers(), function(u) {
|
||||
return u.userId;
|
||||
});
|
||||
|
||||
@@ -618,7 +617,10 @@ MegolmDecryption.prototype.decryptEvent = async function(event) {
|
||||
if (!content.sender_key || !content.session_id ||
|
||||
!content.ciphertext
|
||||
) {
|
||||
throw new base.DecryptionError("Missing fields in input");
|
||||
throw new base.DecryptionError(
|
||||
"MEGOLM_MISSING_FIELDS",
|
||||
"Missing fields in input",
|
||||
);
|
||||
}
|
||||
|
||||
// we add the event to the pending list *before* we start decryption.
|
||||
@@ -635,10 +637,16 @@ MegolmDecryption.prototype.decryptEvent = async function(event) {
|
||||
event.getId(), event.getTs(),
|
||||
);
|
||||
} catch (e) {
|
||||
let errorCode = "OLM_DECRYPT_GROUP_MESSAGE_ERROR";
|
||||
|
||||
if (e.message === 'OLM.UNKNOWN_MESSAGE_INDEX') {
|
||||
this._requestKeysForEvent(event);
|
||||
|
||||
errorCode = 'OLM_UNKNOWN_MESSAGE_INDEX';
|
||||
}
|
||||
|
||||
throw new base.DecryptionError(
|
||||
errorCode,
|
||||
e.toString(), {
|
||||
session: content.sender_key + '|' + content.session_id,
|
||||
},
|
||||
@@ -655,6 +663,7 @@ MegolmDecryption.prototype.decryptEvent = async function(event) {
|
||||
// scheduled, so we needn't send out the request here.)
|
||||
this._requestKeysForEvent(event);
|
||||
throw new base.DecryptionError(
|
||||
"MEGOLM_UNKNOWN_INBOUND_SESSION_ID",
|
||||
"The sender's device has not sent us the keys for this message.",
|
||||
{
|
||||
session: content.sender_key + '|' + content.session_id,
|
||||
@@ -673,6 +682,7 @@ MegolmDecryption.prototype.decryptEvent = async function(event) {
|
||||
// room, so neither the sender nor a MITM can lie about the room_id).
|
||||
if (payload.room_id !== event.getRoomId()) {
|
||||
throw new base.DecryptionError(
|
||||
"MEGOLM_BAD_ROOM",
|
||||
"Message intended for room " + payload.room_id,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ OlmEncryption.prototype.encryptMessage = function(room, eventType, content) {
|
||||
// TODO: there is a race condition here! What if a new user turns up
|
||||
// just as you are sending a secret message?
|
||||
|
||||
const users = utils.map(room.getJoinedMembers(), function(u) {
|
||||
const users = utils.map(room.getEncryptionTargetMembers(), function(u) {
|
||||
return u.userId;
|
||||
});
|
||||
|
||||
@@ -168,11 +168,17 @@ OlmDecryption.prototype.decryptEvent = async function(event) {
|
||||
const ciphertext = content.ciphertext;
|
||||
|
||||
if (!ciphertext) {
|
||||
throw new base.DecryptionError("Missing ciphertext");
|
||||
throw new base.DecryptionError(
|
||||
"OLM_MISSING_CIPHERTEXT",
|
||||
"Missing ciphertext",
|
||||
);
|
||||
}
|
||||
|
||||
if (!(this._olmDevice.deviceCurve25519Key in ciphertext)) {
|
||||
throw new base.DecryptionError("Not included in recipients");
|
||||
throw new base.DecryptionError(
|
||||
"OLM_NOT_INCLUDED_IN_RECIPIENTS",
|
||||
"Not included in recipients",
|
||||
);
|
||||
}
|
||||
const message = ciphertext[this._olmDevice.deviceCurve25519Key];
|
||||
let payloadString;
|
||||
@@ -181,6 +187,7 @@ OlmDecryption.prototype.decryptEvent = async function(event) {
|
||||
payloadString = await this._decryptMessage(deviceKey, message);
|
||||
} catch (e) {
|
||||
throw new base.DecryptionError(
|
||||
"OLM_BAD_ENCRYPTED_MESSAGE",
|
||||
"Bad Encrypted Message", {
|
||||
sender: deviceKey,
|
||||
err: e,
|
||||
@@ -194,12 +201,14 @@ OlmDecryption.prototype.decryptEvent = async function(event) {
|
||||
// https://github.com/vector-im/vector-web/issues/2483
|
||||
if (payload.recipient != this._userId) {
|
||||
throw new base.DecryptionError(
|
||||
"OLM_BAD_RECIPIENT",
|
||||
"Message was intented for " + payload.recipient,
|
||||
);
|
||||
}
|
||||
|
||||
if (payload.recipient_keys.ed25519 != this._olmDevice.deviceEd25519Key) {
|
||||
throw new base.DecryptionError(
|
||||
"OLM_BAD_RECIPIENT_KEY",
|
||||
"Message not intended for this device", {
|
||||
intended: payload.recipient_keys.ed25519,
|
||||
our_key: this._olmDevice.deviceEd25519Key,
|
||||
@@ -213,6 +222,7 @@ OlmDecryption.prototype.decryptEvent = async function(event) {
|
||||
// which is checked elsewhere).
|
||||
if (payload.sender != event.getSender()) {
|
||||
throw new base.DecryptionError(
|
||||
"OLM_FORWARDED_MESSAGE",
|
||||
"Message forwarded from " + payload.sender, {
|
||||
reported_sender: event.getSender(),
|
||||
},
|
||||
@@ -222,6 +232,7 @@ OlmDecryption.prototype.decryptEvent = async function(event) {
|
||||
// Olm events intended for a room have a room_id.
|
||||
if (payload.room_id !== event.getRoomId()) {
|
||||
throw new base.DecryptionError(
|
||||
"OLM_BAD_ROOM",
|
||||
"Message intended for room " + payload.room_id, {
|
||||
reported_room: event.room_id,
|
||||
},
|
||||
|
||||
+7
-2
@@ -652,7 +652,7 @@ Crypto.prototype.setRoomEncryption = async function(roomId, config, inhibitDevic
|
||||
throw new Error(`Unable to enable encryption in unknown room ${roomId}`);
|
||||
}
|
||||
|
||||
const members = room.getJoinedMembers();
|
||||
const members = room.getEncryptionTargetMembers();
|
||||
members.forEach((m) => {
|
||||
this._deviceList.startTrackingDeviceList(m.userId);
|
||||
});
|
||||
@@ -986,7 +986,7 @@ Crypto.prototype._evalDeviceListChanges = async function(deviceLists) {
|
||||
Crypto.prototype._getE2eUsers = function() {
|
||||
const e2eUserIds = [];
|
||||
for (const room of this._getE2eRooms()) {
|
||||
const members = room.getJoinedMembers();
|
||||
const members = room.getEncryptionTargetMembers();
|
||||
for (const member of members) {
|
||||
e2eUserIds.push(member.userId);
|
||||
}
|
||||
@@ -1085,6 +1085,10 @@ Crypto.prototype._onRoomMembership = function(event, member, oldMembership) {
|
||||
console.log('Join event for ' + member.userId + ' in ' + roomId);
|
||||
// make sure we are tracking the deviceList for this user
|
||||
this._deviceList.startTrackingDeviceList(member.userId);
|
||||
} else if (member.membership == 'invite' &&
|
||||
this._clientStore.getRoom(roomId).shouldEncryptForInvitedMembers()) {
|
||||
console.log('Invite event for ' + member.userId + ' in ' + roomId);
|
||||
this._deviceList.startTrackingDeviceList(member.userId);
|
||||
}
|
||||
|
||||
alg.onRoomMembership(event, member, oldMembership);
|
||||
@@ -1275,6 +1279,7 @@ Crypto.prototype._getRoomDecryptor = function(roomId, algorithm) {
|
||||
const AlgClass = algorithms.DECRYPTION_CLASSES[algorithm];
|
||||
if (!AlgClass) {
|
||||
throw new algorithms.DecryptionError(
|
||||
'UNKNOWN_ENCRYPTION_ALGORITHM',
|
||||
'Unknown encryption algorithm "' + algorithm + '".',
|
||||
);
|
||||
}
|
||||
|
||||
+9
-1
@@ -404,6 +404,7 @@ utils.extend(module.exports.MatrixEvent.prototype, {
|
||||
this._retryDecryption = false;
|
||||
|
||||
let res;
|
||||
let err;
|
||||
try {
|
||||
if (!crypto) {
|
||||
res = this._badEncryptedMessage("Encryption not enabled");
|
||||
@@ -422,6 +423,8 @@ utils.extend(module.exports.MatrixEvent.prototype, {
|
||||
return;
|
||||
}
|
||||
|
||||
err = e;
|
||||
|
||||
// see if we have a retry queued.
|
||||
//
|
||||
// NB: make sure to keep this check in the same tick of the
|
||||
@@ -467,6 +470,9 @@ utils.extend(module.exports.MatrixEvent.prototype, {
|
||||
this._decryptionPromise = null;
|
||||
this._retryDecryption = false;
|
||||
this._setClearData(res);
|
||||
|
||||
this.emit("Event.decrypted", this, err);
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
@@ -503,7 +509,6 @@ utils.extend(module.exports.MatrixEvent.prototype, {
|
||||
decryptionResult.claimedEd25519Key || null;
|
||||
this._forwardingCurve25519KeyChain =
|
||||
decryptionResult.forwardingCurve25519KeyChain || [];
|
||||
this.emit("Event.decrypted", this);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -708,4 +713,7 @@ const _REDACT_KEEP_CONTENT_MAP = {
|
||||
*
|
||||
* @param {module:models/event.MatrixEvent} event
|
||||
* The matrix event which has been decrypted
|
||||
* @param {module:crypto/algorithms/base.DecryptionError?} err
|
||||
* The error that occured during decryption, or `undefined` if no
|
||||
* error occured.
|
||||
*/
|
||||
|
||||
@@ -229,18 +229,23 @@ function calculateDisplayName(member, event, roomState) {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
// First check if the displayname is something we consider truthy
|
||||
// after stripping it of zero width characters and padding spaces
|
||||
const strippedDisplayName = utils.removeHiddenChars(displayName);
|
||||
if (!strippedDisplayName) {
|
||||
return selfUserId;
|
||||
}
|
||||
|
||||
// Check if the name contains something that look like a mxid
|
||||
// Next check if the name contains something that look like a mxid
|
||||
// If it does, it may be someone trying to impersonate someone else
|
||||
// Show full mxid in this case
|
||||
// Also show mxid if there are other people with the same displayname
|
||||
// ignoring any zero width chars (unicode 200B-200D)
|
||||
// if their displayname is made up of just zero width chars, show full mxid
|
||||
let disambiguate = /@.+:.+/.test(displayName);
|
||||
if (!disambiguate) {
|
||||
const userIds = roomState.getUserIdsWithDisplayName(displayName);
|
||||
const otherUsers = userIds.filter(function(u) {
|
||||
return u !== selfUserId;
|
||||
});
|
||||
disambiguate = otherUsers.length > 0;
|
||||
const userIds = roomState.getUserIdsWithDisplayName(strippedDisplayName);
|
||||
disambiguate = userIds.some((u) => u !== selfUserId);
|
||||
}
|
||||
|
||||
if (disambiguate) {
|
||||
|
||||
+22
-14
@@ -217,8 +217,13 @@ RoomState.prototype.setStateEvents = function(stateEvents) {
|
||||
}
|
||||
|
||||
let member = self.members[userId];
|
||||
self._joinedMemberCount = null;
|
||||
|
||||
if (!member) {
|
||||
member = new RoomMember(event.getRoomId(), userId);
|
||||
// add member to members before emitting any events,
|
||||
// as event handlers often lookup the member
|
||||
self.members[userId] = member;
|
||||
self.emit("RoomState.newMember", event, self, member);
|
||||
}
|
||||
|
||||
@@ -232,8 +237,6 @@ RoomState.prototype.setStateEvents = function(stateEvents) {
|
||||
// blow away the sentinel which is now outdated
|
||||
delete self._sentinels[userId];
|
||||
|
||||
self.members[userId] = member;
|
||||
self._joinedMemberCount = null;
|
||||
self.emit("RoomState.members", event, self, member);
|
||||
} else if (event.getType() === "m.room.power_levels") {
|
||||
const members = utils.values(self.members);
|
||||
@@ -494,22 +497,26 @@ function _updateDisplayNameCache(roomState, userId, displayName) {
|
||||
// We clobber the user_id > name lookup but the name -> [user_id] lookup
|
||||
// means we need to remove that user ID from that array rather than nuking
|
||||
// the lot.
|
||||
const existingUserIds = roomState._displayNameToUserIds[oldName] || [];
|
||||
for (let i = 0; i < existingUserIds.length; i++) {
|
||||
if (existingUserIds[i] === userId) {
|
||||
// remove this user ID from this array
|
||||
existingUserIds.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
const strippedOldName = utils.removeHiddenChars(oldName);
|
||||
|
||||
const existingUserIds = roomState._displayNameToUserIds[strippedOldName];
|
||||
if (existingUserIds) {
|
||||
// remove this user ID from this array
|
||||
const filteredUserIDs = existingUserIds.filter((id) => id !== userId);
|
||||
roomState._displayNameToUserIds[strippedOldName] = filteredUserIDs;
|
||||
}
|
||||
roomState._displayNameToUserIds[oldName] = existingUserIds;
|
||||
}
|
||||
|
||||
roomState._userIdsToDisplayNames[userId] = displayName;
|
||||
if (!roomState._displayNameToUserIds[displayName]) {
|
||||
roomState._displayNameToUserIds[displayName] = [];
|
||||
|
||||
const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);
|
||||
// an empty stripped displayname (undefined/'') will be set to MXID in room-member.js
|
||||
if (strippedDisplayname) {
|
||||
if (!roomState._displayNameToUserIds[strippedDisplayname]) {
|
||||
roomState._displayNameToUserIds[strippedDisplayname] = [];
|
||||
}
|
||||
roomState._displayNameToUserIds[strippedDisplayname].push(userId);
|
||||
}
|
||||
roomState._displayNameToUserIds[displayName].push(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -539,7 +546,8 @@ function _updateDisplayNameCache(roomState, userId, displayName) {
|
||||
|
||||
/**
|
||||
* Fires whenever a member is added to the members dictionary. The RoomMember
|
||||
* will not be fully populated yet (e.g. no membership state).
|
||||
* will not be fully populated yet (e.g. no membership state) but will already
|
||||
* be available in the members dictionary.
|
||||
* @event module:client~MatrixClient#"RoomState.newMember"
|
||||
* @param {MatrixEvent} event The matrix event which caused this event to fire.
|
||||
* @param {RoomState} state The room state whose RoomState.members dictionary
|
||||
|
||||
+35
-2
@@ -174,6 +174,18 @@ function Room(roomId, opts) {
|
||||
}
|
||||
utils.inherits(Room, EventEmitter);
|
||||
|
||||
/**
|
||||
* Gets the version of the room
|
||||
* @returns {string} The version of the room, or null if it could not be determined
|
||||
*/
|
||||
Room.prototype.getVersion = function() {
|
||||
const createEvent = this.currentState.getStateEvents("m.room.create", "");
|
||||
if (!createEvent) return null;
|
||||
const ver = createEvent.getContent()['room_version'];
|
||||
if (ver === undefined) return '1';
|
||||
return ver;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of pending sent events for this room
|
||||
*
|
||||
@@ -456,6 +468,28 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of members we should be encrypting for in this room
|
||||
* @return {RoomMember[]} A list of members who we should encrypt messages for
|
||||
* in this room.
|
||||
*/
|
||||
Room.prototype.getEncryptionTargetMembers = function() {
|
||||
let members = this.getMembersWithMembership("join");
|
||||
if (this.shouldEncryptForInvitedMembers()) {
|
||||
members = members.concat(this.getMembersWithMembership("invite"));
|
||||
}
|
||||
return members;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether we should encrypt messages for invited users in this room
|
||||
* @return {boolean} if we should encrypt messages for invited users
|
||||
*/
|
||||
Room.prototype.shouldEncryptForInvitedMembers = function() {
|
||||
const ev = this.currentState.getStateEvents("m.room.history_visibility", "");
|
||||
return (ev && ev.getContent() && ev.getContent().history_visibility !== "joined");
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the default room name (i.e. what a given user would see if the
|
||||
* room had no m.room.name)
|
||||
@@ -950,7 +984,6 @@ Room.prototype.recalculate = function(userId) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of user IDs who have <b>read up to</b> the given event.
|
||||
* @param {MatrixEvent} event the event to get read receipts for.
|
||||
@@ -1122,7 +1155,7 @@ Room.prototype.addTags = function(event) {
|
||||
// }
|
||||
|
||||
// XXX: do we need to deep copy here?
|
||||
this.tags = event.getContent().tags;
|
||||
this.tags = event.getContent().tags || {};
|
||||
|
||||
// XXX: we could do a deep-comparison to see if the tags have really
|
||||
// changed - but do we want to bother?
|
||||
|
||||
+16
-1
@@ -93,6 +93,7 @@ function SyncApi(client, opts) {
|
||||
this._peekRoomId = null;
|
||||
this._currentSyncRequest = null;
|
||||
this._syncState = null;
|
||||
this._syncStateData = null; // additional data (eg. error object for failed sync)
|
||||
this._catchingUp = false;
|
||||
this._running = false;
|
||||
this._keepAliveTimer = null;
|
||||
@@ -396,6 +397,18 @@ SyncApi.prototype.getSyncState = function() {
|
||||
return this._syncState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the additional data object associated with
|
||||
* the current sync state, or null if there is no
|
||||
* such data.
|
||||
* Sync errors, if available, are put in the 'error' key of
|
||||
* this object.
|
||||
* @return {?Object}
|
||||
*/
|
||||
SyncApi.prototype.getSyncStateData = function() {
|
||||
return this._syncStateData;
|
||||
};
|
||||
|
||||
SyncApi.prototype.recoverFromSyncStartupError = async function(savedSyncPromise, err) {
|
||||
// Wait for the saved sync to complete - we send the pushrules and filter requests
|
||||
// before the saved sync has finished so they can run in parallel, but only process
|
||||
@@ -763,7 +776,7 @@ SyncApi.prototype._onSyncError = function(err, syncOptions) {
|
||||
// fails, since long lived HTTP connections will
|
||||
// go away sometimes and we shouldn't treat this as
|
||||
// erroneous. We set the state to 'reconnecting'
|
||||
// instead, so that clients can onserve this state
|
||||
// instead, so that clients can observe this state
|
||||
// if they wish.
|
||||
this._startKeepAlives().then(() => {
|
||||
this._sync(syncOptions);
|
||||
@@ -774,6 +787,7 @@ SyncApi.prototype._onSyncError = function(err, syncOptions) {
|
||||
this._updateSyncState(
|
||||
this._failedSyncCount >= FAILED_SYNC_ERROR_THRESHOLD ?
|
||||
"ERROR" : "RECONNECTING",
|
||||
{ error: err },
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1451,6 +1465,7 @@ SyncApi.prototype._getGuestFilter = function() {
|
||||
SyncApi.prototype._updateSyncState = function(newState, data) {
|
||||
const old = this._syncState;
|
||||
this._syncState = newState;
|
||||
this._syncStateData = data;
|
||||
this.client.emit("sync", this._syncState, old, data);
|
||||
};
|
||||
|
||||
|
||||
@@ -662,3 +662,13 @@ module.exports.inherits = function(ctor, superCtor) {
|
||||
module.exports.isNumber = function(value) {
|
||||
return typeof value === 'number' && isFinite(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes zero width chars, diacritics and whitespace from the string
|
||||
* @param {string} str the string to remove hidden characters from
|
||||
* @return {string} a string with the hidden characters removed
|
||||
*/
|
||||
module.exports.removeHiddenChars = function(str) {
|
||||
return str.normalize('NFD').replace(removeHiddenCharsRegex, '');
|
||||
};
|
||||
const removeHiddenCharsRegex = /[\u200B-\u200D\u0300-\u036f\uFEFF\s]/g;
|
||||
|
||||
Reference in New Issue
Block a user