- {_t(
- "If you can't find someone, ask them for their username, or share your " +
- "username (%(userId)s) or profile link.",
- {userId},
- {a: (sub) => {sub}},
- )}
-
{this._renderEditor()}
- {_t("Go")}
+ {buttonText}
{spinner}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index b6f61570cd..f8b17db7c5 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -372,7 +372,7 @@
"Render simple counters in room header": "Render simple counters in room header",
"Multiple integration managers": "Multiple integration managers",
"Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)",
- "New DM invite dialog (under development)": "New DM invite dialog (under development)",
+ "New invite dialog": "New invite dialog",
"Show a presence dot next to DMs in the room list": "Show a presence dot next to DMs in the room list",
"Enable cross-signing to verify per-user instead of per-device (in development)": "Enable cross-signing to verify per-user instead of per-device (in development)",
"Enable local event indexing and E2EE search (requires restart)": "Enable local event indexing and E2EE search (requires restart)",
@@ -1438,16 +1438,6 @@
"View Servers in Room": "View Servers in Room",
"Toolbox": "Toolbox",
"Developer Tools": "Developer Tools",
- "Failed to invite the following users to chat: %(csvUsers)s": "Failed to invite the following users to chat: %(csvUsers)s",
- "We couldn't create your DM. Please check the users you want to invite and try again.": "We couldn't create your DM. Please check the users you want to invite and try again.",
- "Failed to find the following users": "Failed to find the following users",
- "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
- "Recent Conversations": "Recent Conversations",
- "Suggestions": "Suggestions",
- "Show more": "Show more",
- "Direct Messages": "Direct Messages",
- "If you can't find someone, ask them for their username, or share your username (%(userId)s) or
profile link.": "If you can't find someone, ask them for their username, or share your username (%(userId)s) or
profile link.",
- "Go": "Go",
"An error has occurred.": "An error has occurred.",
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
"Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.",
@@ -1457,6 +1447,20 @@
"Enable 'Manage Integrations' in Settings to do this.": "Enable 'Manage Integrations' in Settings to do this.",
"Integrations not allowed": "Integrations not allowed",
"Your Riot doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "Your Riot doesn't allow you to use an Integration Manager to do this. Please contact an admin.",
+ "Failed to invite the following users to chat: %(csvUsers)s": "Failed to invite the following users to chat: %(csvUsers)s",
+ "We couldn't create your DM. Please check the users you want to invite and try again.": "We couldn't create your DM. Please check the users you want to invite and try again.",
+ "Something went wrong trying to invite the users.": "Something went wrong trying to invite the users.",
+ "We couldn't invite those users. Please check the users you want to invite and try again.": "We couldn't invite those users. Please check the users you want to invite and try again.",
+ "Failed to find the following users": "Failed to find the following users",
+ "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
+ "Recent Conversations": "Recent Conversations",
+ "Suggestions": "Suggestions",
+ "Recently Direct Messaged": "Recently Direct Messaged",
+ "Show more": "Show more",
+ "Direct Messages": "Direct Messages",
+ "If you can't find someone, ask them for their username, or share your username (%(userId)s) or
profile link.": "If you can't find someone, ask them for their username, or share your username (%(userId)s) or
profile link.",
+ "Go": "Go",
+ "If you can't find someone, ask them for their username (e.g. @user:server.com) or
share this room.": "If you can't find someone, ask them for their username (e.g. @user:server.com) or
share this room.",
"You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.",
"Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.",
"Start verification": "Start verification",
From 1a961358f0fe7956cefc246281960c9761f500ae Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Thu, 16 Jan 2020 14:40:25 -0700
Subject: [PATCH 13/26] Don't show recents and suggestions for users already in
the room
---
src/components/views/dialogs/InviteDialog.js | 28 +++++++++++++++++---
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index 7448b1a5a3..e176d3b105 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -300,12 +300,24 @@ export default class InviteDialog extends React.PureComponent {
throw new Error("When using KIND_INVITE a roomId is required for an InviteDialog");
}
+ let alreadyInvited = [];
+ if (props.roomId) {
+ const room = MatrixClientPeg.get().getRoom(props.roomId);
+ if (!room) throw new Error("Room ID given to InviteDialog does not look like a room");
+ alreadyInvited = [
+ ...room.getMembersWithMembership('invite'),
+ ...room.getMembersWithMembership('join'),
+ ...room.getMembersWithMembership('ban'), // so we don't try to invite them
+ ].map(m => m.userId);
+ }
+
+
this.state = {
targets: [], // array of Member objects (see interface above)
filterText: "",
- recents: this._buildRecents(),
+ recents: this._buildRecents(alreadyInvited),
numRecentsShown: INITIAL_ROOMS_SHOWN,
- suggestions: this._buildSuggestions(),
+ suggestions: this._buildSuggestions(alreadyInvited),
numSuggestionsShown: INITIAL_ROOMS_SHOWN,
serverResultsMixin: [], // { user: DirectoryMember, userId: string }[], like recents and suggestions
threepidResultsMixin: [], // { user: ThreepidMember, userId: string}[], like recents and suggestions
@@ -320,10 +332,13 @@ export default class InviteDialog extends React.PureComponent {
this._editorRef = createRef();
}
- _buildRecents(): {userId: string, user: RoomMember, lastActive: number} {
+ _buildRecents(excludedTargetIds: string[]): {userId: string, user: RoomMember, lastActive: number} {
const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals();
const recents = [];
for (const userId in rooms) {
+ // Filter out user IDs that are already in the room / should be excluded
+ if (excludedTargetIds.includes(userId)) continue;
+
const room = rooms[userId];
const member = room.getMember(userId);
if (!member) continue; // just skip people who don't have memberships for some reason
@@ -342,7 +357,7 @@ export default class InviteDialog extends React.PureComponent {
return recents;
}
- _buildSuggestions(): {userId: string, user: RoomMember} {
+ _buildSuggestions(excludedTargetIds: string[]): {userId: string, user: RoomMember} {
const maxConsideredMembers = 200;
const client = MatrixClientPeg.get();
const excludedUserIds = [client.getUserId(), SdkConfig.get()['welcomeUserId']];
@@ -359,6 +374,11 @@ export default class InviteDialog extends React.PureComponent {
const joinedMembers = room.getJoinedMembers().filter(u => !excludedUserIds.includes(u.userId));
for (const member of joinedMembers) {
+ // Filter out user IDs that are already in the room / should be excluded
+ if (excludedTargetIds.includes(member.userId)) {
+ continue;
+ }
+
if (!members[member.userId]) {
members[member.userId] = {
member: member,
From e42663fc627187cee9a59e65cd8ff1abccb95bf3 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Thu, 16 Jan 2020 14:45:17 -0700
Subject: [PATCH 14/26] Appease the linter
---
src/components/views/dialogs/InviteDialog.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index e176d3b105..1b7a50c084 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -509,7 +509,9 @@ export default class InviteDialog extends React.PureComponent {
console.error(err);
this.setState({
busy: false,
- errorText: _t("We couldn't invite those users. Please check the users you want to invite and try again."),
+ errorText: _t(
+ "We couldn't invite those users. Please check the users you want to invite and try again.",
+ ),
});
});
};
From 03448313e6b4f0ad41b329d08d95f1d8188bb84c Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Thu, 16 Jan 2020 21:52:33 +0000
Subject: [PATCH 15/26] Fix event handler leak in MemberStatusMessageAvatar
A typo led to an event handler leak with the custom status labs feature. A new
handler would leak each time you change rooms, which can add up over the course
of a long-lived session.
---
src/components/views/avatars/MemberStatusMessageAvatar.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js
index aaac61ce7d..54f11e8e91 100644
--- a/src/components/views/avatars/MemberStatusMessageAvatar.js
+++ b/src/components/views/avatars/MemberStatusMessageAvatar.js
@@ -63,7 +63,7 @@ export default class MemberStatusMessageAvatar extends React.Component {
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
}
- componentWillUmount() {
+ componentWillUnmount() {
const { user } = this.props.member;
if (!user) {
return;
From f535fdbcaa5f6f43f1b10ee61feaa8071953ff32 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Thu, 16 Jan 2020 15:39:07 -0700
Subject: [PATCH 16/26] Update chokidar to fix reskindex not working
The major version bump doesn't appear to affect us. It wasn't working before on Windows, but now it is.
---
package.json | 2 +-
yarn.lock | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/package.json b/package.json
index 16e7f943f1..3686966870 100644
--- a/package.json
+++ b/package.json
@@ -123,7 +123,7 @@
"@peculiar/webcrypto": "^1.0.22",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
- "chokidar": "^2.1.2",
+ "chokidar": "^3.3.1",
"concurrently": "^4.0.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
diff --git a/yarn.lock b/yarn.lock
index d2135f7aa6..81602b4e3d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1570,6 +1570,14 @@ anymatch@^2.0.0:
micromatch "^3.1.4"
normalize-path "^2.1.1"
+anymatch@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
+ integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
aproba@^1.0.3, aproba@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -1884,6 +1892,11 @@ binary-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
+binary-extensions@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
+ integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
+
bluebird@^3.5.0, bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@@ -1928,6 +1941,13 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
+braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -2232,7 +2252,7 @@ cheerio@^1.0.0-rc.3:
lodash "^4.15.0"
parse5 "^3.0.1"
-chokidar@^2.0.2, chokidar@^2.1.2, chokidar@^2.1.8:
+chokidar@^2.0.2, chokidar@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
@@ -2251,6 +2271,21 @@ chokidar@^2.0.2, chokidar@^2.1.2, chokidar@^2.1.8:
optionalDependencies:
fsevents "^1.2.7"
+chokidar@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
+ integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
+ dependencies:
+ anymatch "~3.1.1"
+ braces "~3.0.2"
+ glob-parent "~5.1.0"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.3.0"
+ optionalDependencies:
+ fsevents "~2.1.2"
+
chownr@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
@@ -3654,6 +3689,13 @@ fill-range@^4.0.0:
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
@@ -3815,6 +3857,11 @@ fsevents@^1.2.7:
nan "^2.12.1"
node-pre-gyp "^0.12.0"
+fsevents@~2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
+ integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
+
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -3909,6 +3956,13 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
+glob-parent@~5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
+ integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
+ dependencies:
+ is-glob "^4.0.1"
+
glob-to-regexp@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
@@ -4463,6 +4517,13 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
is-boolean-object@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
@@ -4622,7 +4683,7 @@ is-glob@^3.1.0:
dependencies:
is-extglob "^2.1.0"
-is-glob@^4.0.0, is-glob@^4.0.1:
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -4663,6 +4724,11 @@ is-number@^3.0.0:
dependencies:
kind-of "^3.0.2"
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
is-obj@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
@@ -6104,7 +6170,7 @@ normalize-path@^2.1.1:
dependencies:
remove-trailing-separator "^1.0.1"
-normalize-path@^3.0.0:
+normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@@ -6578,6 +6644,11 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+picomatch@^2.0.4, picomatch@^2.0.7:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
+ integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
+
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
@@ -7169,6 +7240,13 @@ readdirp@^2.2.1:
micromatch "^3.1.10"
readable-stream "^2.0.2"
+readdirp@~3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
+ integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
+ dependencies:
+ picomatch "^2.0.7"
+
realpath-native@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c"
@@ -8375,6 +8453,13 @@ to-regex-range@^2.1.0:
is-number "^3.0.0"
repeat-string "^1.6.1"
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
From 8efc45b31a504cfe65593077a9c6e8fc01f3c857 Mon Sep 17 00:00:00 2001
From: Zoe
Date: Fri, 17 Jan 2020 10:04:34 +0000
Subject: [PATCH 17/26] no need to verify our own devices for every room
---
src/components/structures/RoomView.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 3cdc308758..e0997f87da 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -820,7 +820,7 @@ export default createReactClass({
/* At this point, either `verified` or `unverified` is empty, or both */
/* Check all verified user devices. We don't care if everyone's unverified anyway. */
- for (const userId of [...verified, cli.getUserId()]) {
+ for (const userId of verified) {
const devices = await cli.getStoredDevicesForUser(userId);
const allDevicesVerified = devices.every(({deviceId}) => {
return cli.checkDeviceTrust(userId, deviceId).isCrossSigningVerified();
From 9877fd9e85c04fe03d9dfa0ae8cfd08ab3694392 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 17 Jan 2020 10:04:38 +0000
Subject: [PATCH 18/26] Fix Array.concat undefined
---
src/components/views/settings/tabs/room/BridgeSettingsTab.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.js b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
index 71b0169788..19c19d3bc6 100644
--- a/src/components/views/settings/tabs/room/BridgeSettingsTab.js
+++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.js
@@ -137,7 +137,7 @@ export default class BridgeSettingsTab extends React.Component {
const client = MatrixClientPeg.get();
const roomState = (client.getRoom(roomId)).currentState;
- const bridgeEvents = Array.concat(...BRIDGE_EVENT_TYPES.map((typeName) =>
+ const bridgeEvents = [].concat(...BRIDGE_EVENT_TYPES.map((typeName) =>
Object.values(roomState.events[typeName] || {}),
));
From 510b08c88bd6f0dfeac1f56c39a12855f67990c1 Mon Sep 17 00:00:00 2001
From: Zoe
Date: Fri, 17 Jan 2020 10:18:50 +0000
Subject: [PATCH 19/26] changed logic to reflect the task
---
src/components/structures/RoomView.js | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index e0997f87da..aa3e86fa60 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -809,17 +809,16 @@ export default createReactClass({
debuglog("e2e verified", verified, "unverified", unverified);
- /* If we verify any users in this room, expect to verify every user in the room */
- if (verified.length > 0 && unverified.length > 0) {
+ /* If we've not verified anyone, set state to "normal" */
+ if (verified.length == 0) {
this.setState({
- e2eStatus: "warning",
+ e2eStatus: "normal",
});
- debuglog("e2e status set to warning as some, but not all, users are verified");
+ debuglog("e2e state set to normal as we have no verified users to worry about");
return;
}
- /* At this point, either `verified` or `unverified` is empty, or both */
- /* Check all verified user devices. We don't care if everyone's unverified anyway. */
+ /* Check all verified user devices. */
for (const userId of verified) {
const devices = await cli.getStoredDevicesForUser(userId);
const allDevicesVerified = devices.every(({deviceId}) => {
@@ -836,7 +835,7 @@ export default createReactClass({
}
this.setState({
- e2eStatus: unverified.length === 0 ? "verified" : "normal",
+ e2eStatus: "verified",
});
},
From d02185e4af661542e39a568d43aa58f19670ec0c Mon Sep 17 00:00:00 2001
From: Zoe
Date: Fri, 17 Jan 2020 10:22:53 +0000
Subject: [PATCH 20/26] whoops, the number of unverified users matters to the
logic
---
src/components/structures/RoomView.js | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index aa3e86fa60..8ecb6a6a02 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -809,15 +809,6 @@ export default createReactClass({
debuglog("e2e verified", verified, "unverified", unverified);
- /* If we've not verified anyone, set state to "normal" */
- if (verified.length == 0) {
- this.setState({
- e2eStatus: "normal",
- });
- debuglog("e2e state set to normal as we have no verified users to worry about");
- return;
- }
-
/* Check all verified user devices. */
for (const userId of verified) {
const devices = await cli.getStoredDevicesForUser(userId);
@@ -835,7 +826,7 @@ export default createReactClass({
}
this.setState({
- e2eStatus: "verified",
+ e2eStatus: unverified.length === 0 ? "verified" : "normal",
});
},
From 908630c0d942de6ec9115c7b197b0d2b47f87488 Mon Sep 17 00:00:00 2001
From: Zoe
Date: Fri, 17 Jan 2020 11:30:45 +0000
Subject: [PATCH 21/26] *rude grumbling noises about @dbkr*
---
src/components/structures/RoomView.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 8ecb6a6a02..9b02f6d503 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -813,7 +813,7 @@ export default createReactClass({
for (const userId of verified) {
const devices = await cli.getStoredDevicesForUser(userId);
const allDevicesVerified = devices.every(({deviceId}) => {
- return cli.checkDeviceTrust(userId, deviceId).isCrossSigningVerified();
+ return cli.checkDeviceTrust(userId, deviceId).isVerified();
});
if (!allDevicesVerified) {
this.setState({
From 9e43abaf3aa5eb4e76492c34209a46f8e8796c7c Mon Sep 17 00:00:00 2001
From: David Baker
Date: Fri, 17 Jan 2020 11:43:35 +0000
Subject: [PATCH 22/26] Toasts for new, unverified sessions
Fixes https://github.com/vector-im/riot-web/issues/11218
---
res/css/structures/_ToastContainer.scss | 6 +-
src/DeviceListener.js | 90 +++++++++++++++++++
src/Lifecycle.js | 8 ++
src/components/structures/ToastContainer.js | 2 +-
.../views/toasts/NewSessionToast.js | 57 ++++++++++++
src/i18n/strings/en_EN.json | 5 +-
src/stores/ToastStore.js | 4 +
7 files changed, 169 insertions(+), 3 deletions(-)
create mode 100644 src/DeviceListener.js
create mode 100644 src/components/views/toasts/NewSessionToast.js
diff --git a/res/css/structures/_ToastContainer.scss b/res/css/structures/_ToastContainer.scss
index 4c5e746e66..5634a97c53 100644
--- a/res/css/structures/_ToastContainer.scss
+++ b/res/css/structures/_ToastContainer.scss
@@ -51,7 +51,7 @@ limitations under the License.
&.mx_Toast_hasIcon {
&::after {
content: "";
- width: 20px;
+ width: 21px;
height: 20px;
grid-column: 1;
grid-row: 1;
@@ -64,6 +64,10 @@ limitations under the License.
background-color: $primary-fg-color;
}
+ &.mx_Toast_icon_verification_warning::after {
+ background-image: url("$(res)/img/e2e/warning.svg");
+ }
+
h2, .mx_Toast_body {
grid-column: 2;
}
diff --git a/src/DeviceListener.js b/src/DeviceListener.js
new file mode 100644
index 0000000000..4b779377e8
--- /dev/null
+++ b/src/DeviceListener.js
@@ -0,0 +1,90 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { MatrixClientPeg } from './MatrixClientPeg';
+import SettingsStore from './settings/SettingsStore';
+import * as sdk from './index';
+import { _t } from './languageHandler';
+import ToastStore from './stores/ToastStore';
+
+function toastKey(device) {
+ return 'newsession_' + device.deviceId;
+}
+
+export default class DeviceListener {
+ static sharedInstance() {
+ if (!global.mx_DeviceListener) global.mx_DeviceListener = new DeviceListener();
+ return global.mx_DeviceListener;
+ }
+
+ constructor() {
+ // device IDs for which the user has dismissed the verify toast ('Later')
+ this._dismissed = new Set();
+ }
+
+ start() {
+ MatrixClientPeg.get().on('crypto.devicesUpdated', this._onDevicesUpdated);
+ MatrixClientPeg.get().on('deviceVerificationChanged', this._onDeviceVerificationChanged);
+ this.recheck();
+ }
+
+ stop() {
+ if (MatrixClientPeg.get()) {
+ MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this._onDevicesUpdated);
+ MatrixClientPeg.get().removeListener('deviceVerificationChanged', this._onDeviceVerificationChanged);
+ }
+ this._dismissed.clear();
+ }
+
+ dismissVerification(deviceId) {
+ this._dismissed.add(deviceId);
+ this.recheck();
+ }
+
+ _onDevicesUpdated = (users) => {
+ if (!users.includes(MatrixClientPeg.get().getUserId())) return;
+ if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) return;
+ this.recheck();
+ }
+
+ _onDeviceVerificationChanged = (users) => {
+ if (!users.includes(MatrixClientPeg.get().getUserId())) return;
+ if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) return;
+ this.recheck();
+ }
+
+ async recheck() {
+ const cli = MatrixClientPeg.get();
+
+ const devices = await cli.getStoredDevicesForUser(cli.getUserId());
+ for (const device of devices) {
+ if (device.deviceId == cli.deviceId) continue;
+
+ const deviceTrust = await cli.checkDeviceTrust(cli.getUserId(), device.deviceId);
+ if (deviceTrust.isVerified() || this._dismissed.has(device.deviceId)) {
+ ToastStore.sharedInstance().dismissToast(toastKey(device));
+ } else {
+ ToastStore.sharedInstance().addOrReplaceToast({
+ key: toastKey(device),
+ title: _t("New Session"),
+ icon: "verification_warning",
+ props: {deviceId: device.deviceId},
+ component: sdk.getComponent("toasts.NewSessionToast"),
+ });
+ }
+ }
+ }
+}
diff --git a/src/Lifecycle.js b/src/Lifecycle.js
index 0796e326a0..1603c73d25 100644
--- a/src/Lifecycle.js
+++ b/src/Lifecycle.js
@@ -2,6 +2,7 @@
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
+Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -35,8 +36,10 @@ import { sendLoginRequest } from "./Login";
import * as StorageManager from './utils/StorageManager';
import SettingsStore from "./settings/SettingsStore";
import TypingStore from "./stores/TypingStore";
+import ToastStore from "./stores/ToastStore";
import {IntegrationManagers} from "./integrations/IntegrationManagers";
import {Mjolnir} from "./mjolnir/Mjolnir";
+import DeviceListener from "./DeviceListener";
/**
* Called at startup, to attempt to build a logged-in Matrix session. It tries
@@ -575,6 +578,7 @@ async function startMatrixClient(startSyncing=true) {
Notifier.start();
UserActivity.sharedInstance().start();
TypingStore.sharedInstance().reset(); // just in case
+ ToastStore.sharedInstance().reset();
if (!SettingsStore.getValue("lowBandwidth")) {
Presence.start();
}
@@ -595,6 +599,9 @@ async function startMatrixClient(startSyncing=true) {
await MatrixClientPeg.assign();
}
+ // This needs to be started after crypto is set up
+ DeviceListener.sharedInstance().start();
+
// dispatch that we finished starting up to wire up any other bits
// of the matrix client that cannot be set prior to starting up.
dis.dispatch({action: 'client_started'});
@@ -651,6 +658,7 @@ export function stopMatrixClient(unsetClient=true) {
ActiveWidgetStore.stop();
IntegrationManagers.sharedInstance().stopWatching();
Mjolnir.sharedInstance().stop();
+ DeviceListener.sharedInstance().stop();
if (DMRoomMap.shared()) DMRoomMap.shared().stop();
EventIndexPeg.stop();
const cli = MatrixClientPeg.get();
diff --git a/src/components/structures/ToastContainer.js b/src/components/structures/ToastContainer.js
index bc74133433..8a05f62e61 100644
--- a/src/components/structures/ToastContainer.js
+++ b/src/components/structures/ToastContainer.js
@@ -22,7 +22,7 @@ import classNames from "classnames";
export default class ToastContainer extends React.Component {
constructor() {
super();
- this.state = {toasts: []};
+ this.state = {toasts: ToastStore.sharedInstance().getToasts()};
}
componentDidMount() {
diff --git a/src/components/views/toasts/NewSessionToast.js b/src/components/views/toasts/NewSessionToast.js
new file mode 100644
index 0000000000..f83326121b
--- /dev/null
+++ b/src/components/views/toasts/NewSessionToast.js
@@ -0,0 +1,57 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import * as sdk from "../../../index";
+import { _t } from '../../../languageHandler';
+import Modal from "../../../Modal";
+import { MatrixClientPeg } from '../../../MatrixClientPeg';
+import DeviceListener from '../../../DeviceListener';
+
+export default class VerifySessionToast extends React.PureComponent {
+ static propTypes = {
+ toastKey: PropTypes.string.isRequired,
+ deviceId: PropTypes.string,
+ };
+
+ _onLaterClick = () => {
+ DeviceListener.sharedInstance().dismissVerification(this.props.deviceId);
+ };
+
+ _onVerifyClick = async () => {
+ const cli = MatrixClientPeg.get();
+ const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
+
+ const device = await cli.getStoredDevice(cli.getUserId(), this.props.deviceId);
+
+ Modal.createTrackedDialog('New Session Verify', 'Starting dialog', DeviceVerifyDialog, {
+ userId: MatrixClientPeg.get().getUserId(),
+ device,
+ }, null, /* priority = */ false, /* static = */ true);
+ };
+
+ render() {
+ const FormButton = sdk.getComponent("elements.FormButton");
+ return (
+
{_t("Other users may not trust it")}
+
+
+
+
+
);
+ }
+}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index f8b17db7c5..4af203177c 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -85,6 +85,7 @@
"%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(time)s",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s",
+ "New Session": "New Session",
"Who would you like to add to this community?": "Who would you like to add to this community?",
"Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID",
"Invite new community members": "Invite new community members",
@@ -513,6 +514,9 @@
"Headphones": "Headphones",
"Folder": "Folder",
"Pin": "Pin",
+ "Other users may not trust it": "Other users may not trust it",
+ "Later": "Later",
+ "Verify": "Verify",
"Decline (%(counter)s)": "Decline (%(counter)s)",
"Accept to continue:": "Accept to continue:",
"Upload": "Upload",
@@ -1130,7 +1134,6 @@
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
"Messages in this room are not end-to-end encrypted.": "Messages in this room are not end-to-end encrypted.",
"Messages in this room are end-to-end encrypted.": "Messages in this room are end-to-end encrypted.",
- "Verify": "Verify",
"Security": "Security",
"Sunday": "Sunday",
"Monday": "Monday",
diff --git a/src/stores/ToastStore.js b/src/stores/ToastStore.js
index f6cc30db67..2c4464813b 100644
--- a/src/stores/ToastStore.js
+++ b/src/stores/ToastStore.js
@@ -31,6 +31,10 @@ export default class ToastStore extends EventEmitter {
this._toasts = [];
}
+ reset() {
+ this._toasts = [];
+ }
+
addOrReplaceToast(newToast) {
const oldIndex = this._toasts.findIndex(t => t.key === newToast.key);
if (oldIndex === -1) {
From fb9962b08e702081572fbf7c1263496f747fd3fc Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Fri, 17 Jan 2020 13:09:08 +0000
Subject: [PATCH 23/26] Disable key request dialogs with cross-signing
Cross-signing verification is meant to replace the old key share between devices
flow. This disables it when the cross-signing lab is enabled.
Fixes https://github.com/vector-im/riot-web/issues/11904
---
src/KeyRequestHandler.js | 13 +++++++++++++
src/components/structures/MatrixChat.js | 2 ++
src/components/views/dialogs/KeyShareDialog.js | 3 +++
3 files changed, 18 insertions(+)
diff --git a/src/KeyRequestHandler.js b/src/KeyRequestHandler.js
index 65dc7fdb0f..0aca6529e4 100644
--- a/src/KeyRequestHandler.js
+++ b/src/KeyRequestHandler.js
@@ -1,5 +1,6 @@
/*
Copyright 2017 Vector Creations Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -17,6 +18,8 @@ limitations under the License.
import * as sdk from './index';
import Modal from './Modal';
+// TODO: We can remove this once cross-signing is the only way.
+// https://github.com/vector-im/riot-web/issues/11908
export default class KeyRequestHandler {
constructor(matrixClient) {
this._matrixClient = matrixClient;
@@ -30,6 +33,11 @@ export default class KeyRequestHandler {
}
handleKeyRequest(keyRequest) {
+ // Ignore own device key requests if cross-signing lab enabled
+ if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
+ return;
+ }
+
const userId = keyRequest.userId;
const deviceId = keyRequest.deviceId;
const requestId = keyRequest.requestId;
@@ -60,6 +68,11 @@ export default class KeyRequestHandler {
}
handleKeyRequestCancellation(cancellation) {
+ // Ignore own device key requests if cross-signing lab enabled
+ if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
+ return;
+ }
+
// see if we can find the request in the queue
const userId = cancellation.userId;
const deviceId = cancellation.deviceId;
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 978743ca87..2797887f29 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -1383,6 +1383,8 @@ export default createReactClass({
cli.on("Session.logged_out", () => dft.stop());
cli.on("Event.decrypted", (e, err) => dft.eventDecrypted(e, err));
+ // TODO: We can remove this once cross-signing is the only way.
+ // https://github.com/vector-im/riot-web/issues/11908
const krh = new KeyRequestHandler(cli);
cli.on("crypto.roomKeyRequest", (req) => {
krh.handleKeyRequest(req);
diff --git a/src/components/views/dialogs/KeyShareDialog.js b/src/components/views/dialogs/KeyShareDialog.js
index 3afb5546cf..507f8b4678 100644
--- a/src/components/views/dialogs/KeyShareDialog.js
+++ b/src/components/views/dialogs/KeyShareDialog.js
@@ -22,6 +22,9 @@ import * as sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
+// TODO: We can remove this once cross-signing is the only way.
+// https://github.com/vector-im/riot-web/issues/11908
+
/**
* Dialog which asks the user whether they want to share their keys with
* an unverified device.
From 066a01ae94444f7c13f5709bcd74dbd445bd0e2c Mon Sep 17 00:00:00 2001
From: David Baker
Date: Fri, 17 Jan 2020 13:35:51 +0000
Subject: [PATCH 24/26] Check for a matrixclient before trying to use it
Was being caught by the try block but still logging an error to the
console unnecessarily: we should not expect there to necessarily
be a matrix client since we run this from the constructor and
there's a shared instance which could be constructed at any point.
---
src/integrations/IntegrationManagers.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/integrations/IntegrationManagers.js b/src/integrations/IntegrationManagers.js
index b482ec73ce..c933e5c433 100644
--- a/src/integrations/IntegrationManagers.js
+++ b/src/integrations/IntegrationManagers.js
@@ -83,6 +83,7 @@ export class IntegrationManagers {
}
async _setupHomeserverManagers() {
+ if (!MatrixClientPeg.get()) return;
try {
console.log("Updating homeserver-configured integration managers...");
const homeserverDomain = MatrixClientPeg.getHomeserverName();
From 9b64686041b9ef4c28fc76bbf3ab54cc795ce5f1 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Fri, 17 Jan 2020 13:50:24 +0000
Subject: [PATCH 25/26] Add missing import
---
src/KeyRequestHandler.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/KeyRequestHandler.js b/src/KeyRequestHandler.js
index 0aca6529e4..30f3b7d50e 100644
--- a/src/KeyRequestHandler.js
+++ b/src/KeyRequestHandler.js
@@ -17,6 +17,7 @@ limitations under the License.
import * as sdk from './index';
import Modal from './Modal';
+import SettingsStore from './settings/SettingsStore';
// TODO: We can remove this once cross-signing is the only way.
// https://github.com/vector-im/riot-web/issues/11908
From 42fe69aec9777d868da6504f3981e6023959c550 Mon Sep 17 00:00:00 2001
From: David Baker
Date: Fri, 17 Jan 2020 14:08:37 +0000
Subject: [PATCH 26/26] Don't check devices if crypto is disabled
---
src/DeviceListener.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/DeviceListener.js b/src/DeviceListener.js
index 4b779377e8..15ca931fc8 100644
--- a/src/DeviceListener.js
+++ b/src/DeviceListener.js
@@ -69,6 +69,8 @@ export default class DeviceListener {
async recheck() {
const cli = MatrixClientPeg.get();
+ if (!cli.isCryptoEnabled()) return false;
+
const devices = await cli.getStoredDevicesForUser(cli.getUserId());
for (const device of devices) {
if (device.deviceId == cli.deviceId) continue;