From 0b7f23fa5491a97b598c4d94881108893520b030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 28 Jan 2020 15:06:43 +0100 Subject: [PATCH 01/18] EventIndex: Improve the documentation a bit. --- src/indexing/BaseEventIndexManager.js | 4 +- src/indexing/EventIndex.js | 131 +++++++++++++++++++++----- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/indexing/BaseEventIndexManager.js b/src/indexing/BaseEventIndexManager.js index 8ebaddc3ab..7a3b583088 100644 --- a/src/indexing/BaseEventIndexManager.js +++ b/src/indexing/BaseEventIndexManager.js @@ -153,8 +153,8 @@ export default class BaseEventIndexManager { /** * Search the event index using the given term for matching events. * - * @param {SearchArgs} searchArgs The search configuration sets what should - * be searched for and what should be contained in the search result. + * @param {SearchArgs} searchArgs The search configuration for the search, + * sets the search term and determines the search result contents. * * @return {Promise<[SearchResult]>} A promise that will resolve to an array * of search results once the search is done. diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 9628920cd7..5d40267fcd 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -51,6 +51,9 @@ export default class EventIndex extends EventEmitter { this.registerListeners(); } + /** + * Register event listeners that are necessary for the event index to work. + */ registerListeners() { const client = MatrixClientPeg.get(); @@ -60,6 +63,9 @@ export default class EventIndex extends EventEmitter { client.on('Room.timelineReset', this.onTimelineReset); } + /** + * Remove the event index specific event listeners. + */ removeListeners() { const client = MatrixClientPeg.get(); if (client === null) return; @@ -116,6 +122,15 @@ export default class EventIndex extends EventEmitter { })); } + /** + * The sync event listener. + * + * The listener has two cases: + * - First sync after start up, check if the index is empty, add + * initial checkpoints, if so. Start the crawler background task. + * - Every other sync, tell the event index to commit all the queued up + * live events + */ onSync = async (state, prevState, data) => { const indexManager = PlatformPeg.get().getEventIndexingManager(); @@ -139,6 +154,14 @@ export default class EventIndex extends EventEmitter { } } + /** + * The Room.timeline listener. + * + * This listener waits for live events in encrypted rooms, if they are + * decrypted or unencrypted we queue them to be added to the index, + * otherwise we save their event id and wait for them in the Event.decrypted + * listener. + */ onRoomTimeline = async (ev, room, toStartOfTimeline, removed, data) => { // We only index encrypted rooms locally. if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) return; @@ -162,6 +185,12 @@ export default class EventIndex extends EventEmitter { } } + /** + * The Event.decrypted listener. + * + * Checks if the event was marked for addition in the Room.timeline + * listener, if so queues it up to be added to the index. + */ onEventDecrypted = async (ev, err) => { const eventId = ev.getId(); @@ -171,6 +200,41 @@ export default class EventIndex extends EventEmitter { await this.addLiveEventToIndex(ev); } + /** + * The Room.timelineReset listener. + * + * Listens for timeline resets that are caused by a limited timeline to + * re-add checkpoints for rooms that need to be crawled again. + */ + onTimelineReset = async (room, timelineSet, resetAllTimelines) => { + if (room === null) return; + + const indexManager = PlatformPeg.get().getEventIndexingManager(); + if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) return; + + const timeline = room.getLiveTimeline(); + const token = timeline.getPaginationToken("b"); + + const backwardsCheckpoint = { + roomId: room.roomId, + token: token, + fullCrawl: false, + direction: "b", + }; + + console.log("EventIndex: Added checkpoint because of a limited timeline", + backwardsCheckpoint); + + await indexManager.addCrawlerCheckpoint(backwardsCheckpoint); + + this.crawlerCheckpoints.push(backwardsCheckpoint); + } + + /** + * Queue up live events to be added to the event index. + * + * @param {MatrixEvent} ev The event that should be added to the index. + */ async addLiveEventToIndex(ev) { const indexManager = PlatformPeg.get().getEventIndexingManager(); @@ -190,10 +254,24 @@ export default class EventIndex extends EventEmitter { indexManager.addEventToIndex(e, profile); } + /** + * Emmit that the crawler has changed the checkpoint that it's currently + * handling. + */ emitNewCheckpoint() { this.emit("changedCheckpoint", this.currentRoom()); } + /** + * The main crawler loop. + * + * Goes through crawlerCheckpoints and fetches events from the server to be + * added to the EventIndex. + * + * If a /room/{roomId}/messages request doesn't contain any events, stop the + * crawl, otherwise create a new checkpoint and push it to the + * crawlerCheckpoints queue so we go through them in a round-robin way. + */ async crawlerFunc() { let cancelled = false; @@ -328,8 +406,6 @@ export default class EventIndex extends EventEmitter { ].indexOf(value.getType()) >= 0 && !value.isRedacted() && !value.isDecryptionFailure() ); - // TODO do we need to check if the event has all the valid - // attributes? }; // TODO if there are no events at this point we're missing a lot @@ -394,40 +470,28 @@ export default class EventIndex extends EventEmitter { console.log("EventIndex: Stopping crawler function"); } - onTimelineReset = async (room, timelineSet, resetAllTimelines) => { - if (room === null) return; - - const indexManager = PlatformPeg.get().getEventIndexingManager(); - if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) return; - - const timeline = room.getLiveTimeline(); - const token = timeline.getPaginationToken("b"); - - const backwardsCheckpoint = { - roomId: room.roomId, - token: token, - fullCrawl: false, - direction: "b", - }; - - console.log("EventIndex: Added checkpoint because of a limited timeline", - backwardsCheckpoint); - - await indexManager.addCrawlerCheckpoint(backwardsCheckpoint); - - this.crawlerCheckpoints.push(backwardsCheckpoint); - } - + /** + * Start the crawler background task. + */ startCrawler() { if (this._crawler !== null) return; this.crawlerFunc(); } + /** + * Stop the crawler background task. + */ stopCrawler() { if (this._crawler === null) return; this._crawler.cancel(); } + /** + * Close the event index. + * + * This removes all the MatrixClient event listeners, stops the crawler + * task, and closes the index. + */ async close() { const indexManager = PlatformPeg.get().getEventIndexingManager(); this.removeListeners(); @@ -435,6 +499,15 @@ export default class EventIndex extends EventEmitter { return indexManager.closeEventIndex(); } + /** + * Search the event index using the given term for matching events. + * + * @param {SearchArgs} searchArgs The search configuration for the search, + * sets the search term and determines the search result contents. + * + * @return {Promise<[SearchResult]>} A promise that will resolve to an array + * of search results once the search is done. + */ async search(searchArgs) { const indexManager = PlatformPeg.get().getEventIndexingManager(); return indexManager.searchEventIndex(searchArgs); @@ -634,6 +707,12 @@ export default class EventIndex extends EventEmitter { return paginationPromise; } + /** + * Get statistical information of the index. + * + * @return {Promise} A promise that will resolve to the index + * statistics. + */ async getStats() { const indexManager = PlatformPeg.get().getEventIndexingManager(); return indexManager.getStats(); From 948ec203c63856863661256f0ea9bfa60455c4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 28 Jan 2020 15:07:29 +0100 Subject: [PATCH 02/18] BaseEventIndexManager: Fix the type hints for the empty promises. --- src/indexing/BaseEventIndexManager.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/indexing/BaseEventIndexManager.js b/src/indexing/BaseEventIndexManager.js index 7a3b583088..66904f9264 100644 --- a/src/indexing/BaseEventIndexManager.js +++ b/src/indexing/BaseEventIndexManager.js @@ -105,7 +105,7 @@ export default class BaseEventIndexManager { * @return {Promise} A promise that will resolve when the event index is * initialized. */ - async initEventIndex(): Promise<> { + async initEventIndex(): Promise { throw new Error("Unimplemented"); } @@ -146,7 +146,7 @@ export default class BaseEventIndexManager { * @return {Promise} A promise that will resolve once the queued up events * were added to the index. */ - async commitLiveEvents(): Promise<> { + async commitLiveEvents(): Promise { throw new Error("Unimplemented"); } @@ -197,7 +197,7 @@ export default class BaseEventIndexManager { * @return {Promise} A promise that will resolve once the checkpoint has * been stored. */ - async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<> { + async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise { throw new Error("Unimplemented"); } @@ -210,7 +210,7 @@ export default class BaseEventIndexManager { * @return {Promise} A promise that will resolve once the checkpoint has * been removed. */ - async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<> { + async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise { throw new Error("Unimplemented"); } @@ -250,7 +250,7 @@ export default class BaseEventIndexManager { * @return {Promise} A promise that will resolve once the event index has * been closed. */ - async closeEventIndex(): Promise<> { + async closeEventIndex(): Promise { throw new Error("Unimplemented"); } @@ -260,7 +260,7 @@ export default class BaseEventIndexManager { * @return {Promise} A promise that will resolve once the event index has * been deleted. */ - async deleteEventIndex(): Promise<> { + async deleteEventIndex(): Promise { throw new Error("Unimplemented"); } } From 5cabfb63a43a62e3a28c61f926bba32c312a8be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 28 Jan 2020 16:13:56 +0100 Subject: [PATCH 03/18] EventIndex: Don't mark the event listener method docs as jsdoc comments. --- src/indexing/EventIndex.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 5d40267fcd..e1ec0d1d1c 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -122,7 +122,7 @@ export default class EventIndex extends EventEmitter { })); } - /** + /* * The sync event listener. * * The listener has two cases: @@ -154,7 +154,7 @@ export default class EventIndex extends EventEmitter { } } - /** + /* * The Room.timeline listener. * * This listener waits for live events in encrypted rooms, if they are @@ -185,7 +185,7 @@ export default class EventIndex extends EventEmitter { } } - /** + /* * The Event.decrypted listener. * * Checks if the event was marked for addition in the Room.timeline @@ -200,7 +200,7 @@ export default class EventIndex extends EventEmitter { await this.addLiveEventToIndex(ev); } - /** + /* * The Room.timelineReset listener. * * Listens for timeline resets that are caused by a limited timeline to From 4a26a72684e47aa921a3e38965beeebd6c759d3f Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 28 Jan 2020 22:46:21 +0000 Subject: [PATCH 04/18] Restore key backup in Complete Security dialog Fixes https://github.com/vector-im/riot-web/issues/11889 --- .../structures/auth/CompleteSecurity.js | 36 +++++++++++++++---- src/i18n/strings/en_EN.json | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/components/structures/auth/CompleteSecurity.js b/src/components/structures/auth/CompleteSecurity.js index 29d8207d0a..0f30d9cf61 100644 --- a/src/components/structures/auth/CompleteSecurity.js +++ b/src/components/structures/auth/CompleteSecurity.js @@ -22,8 +22,9 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { accessSecretStorage } from '../../../CrossSigningManager'; const PHASE_INTRO = 0; -const PHASE_DONE = 1; -const PHASE_CONFIRM_SKIP = 2; +const PHASE_BUSY = 1; +const PHASE_DONE = 2; +const PHASE_CONFIRM_SKIP = 3; export default class CompleteSecurity extends React.Component { static propTypes = { @@ -39,6 +40,7 @@ export default class CompleteSecurity extends React.Component { // the presence of it insidicating that we're in 'verify mode'. // Because of the latter, it lives in the state. verificationRequest: null, + backupInfo: null, }; MatrixClientPeg.get().on("crypto.verification.request", this.onVerificationRequest); } @@ -53,10 +55,16 @@ export default class CompleteSecurity extends React.Component { } onStartClick = async () => { + this.setState({ + phase: PHASE_BUSY, + }); const cli = MatrixClientPeg.get(); + const backupInfo = await cli.getKeyBackupVersion(); + this.setState({backupInfo}); try { await accessSecretStorage(async () => { await cli.checkOwnCrossSigningTrust(); + if (backupInfo) await cli.restoreKeyBackupWithSecretStorage(backupInfo); }); if (cli.getCrossSigningId()) { @@ -66,6 +74,9 @@ export default class CompleteSecurity extends React.Component { } } catch (e) { // this will throw if the user hits cancel, so ignore + this.setState({ + phase: PHASE_INTRO, + }); } } @@ -155,13 +166,21 @@ export default class CompleteSecurity extends React.Component { } else if (phase === PHASE_DONE) { icon = ; title = _t("Session verified"); + let message; + if (this.state.backupInfo) { + message =

{_t( + "Your new session is now verified. It has access to your " + + "encrypted messages, and other users will see it as trusted.", + )}

; + } else { + message =

{_t( + "Your new session is now verified. Other users will see it as trusted.", + )}

; + } body = (
-

{_t( - "Your new session is now verified. It has access to your " + - "encrypted messages, and other users will see it as trusted.", - )}

+ {message}
); + } else if (phase === PHASE_BUSY) { + const Spinner = sdk.getComponent('views.elements.Spinner'); + icon = ; + title = ''; + body = ; } else { throw new Error(`Unknown phase ${phase}`); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b5a412e117..3ce31f69aa 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1894,6 +1894,7 @@ "Done": "Done", "Without completing security on this device, it won’t have access to encrypted messages.": "Without completing security on this device, it won’t have access to encrypted messages.", "Go Back": "Go Back", + "Restoring": "Restoring", "Failed to send email": "Failed to send email", "The email address linked to your account must be entered.": "The email address linked to your account must be entered.", "A new password must be entered.": "A new password must be entered.", From 2fbda42374d8f044cf6116364122bd94f45645ad Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 07:53:06 +0000 Subject: [PATCH 05/18] Fix buttons in right panel verif --- res/css/views/right_panel/_UserInfo.scss | 1 + src/components/views/verification/VerificationShowSas.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss index 9ce524c5ac..c275f42222 100644 --- a/res/css/views/right_panel/_UserInfo.scss +++ b/res/css/views/right_panel/_UserInfo.scss @@ -263,6 +263,7 @@ limitations under the License. .mx_UserInfo_verify { display: block; margin: 16px 0; + width: 100%; } } diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index 7b93f42983..ec222159ab 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -95,7 +95,7 @@ export default class VerificationShowSas extends React.Component { confirm = Date: Wed, 29 Jan 2020 07:53:23 +0000 Subject: [PATCH 06/18] Fix MemberInfo handling User objects without crashing --- src/components/views/rooms/MemberInfo.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 55855bbc9a..7c77c546b6 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -1113,7 +1113,8 @@ export default createReactClass({ } } - const avatarUrl = this.props.member.getMxcAvatarUrl(); + const {member} = this.props; + const avatarUrl = member.avatarUrl || (member.getMxcAvatarUrl && member.getMxcAvatarUrl()); let avatarElement; if (avatarUrl) { const httpUrl = this.context.mxcUrlToHttp(avatarUrl, 800, 800); From 3d47e259553d15c6e6d1b08b10a2070c42f7c4a6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 07:53:45 +0000 Subject: [PATCH 07/18] improve PropTypes for better rageshakes --- .../views/right_panel/VerificationPanel.js | 19 ++++++++++++++++++- .../views/verification/VerificationShowSas.js | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 3740c6e49d..46179183e1 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -14,7 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React from "react"; +import PropTypes from "prop-types"; import * as sdk from '../../../index'; import {verificationMethods} from 'matrix-js-sdk/src/crypto'; @@ -23,6 +24,8 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {_t} from "../../../languageHandler"; import E2EIcon from "../rooms/E2EIcon"; import { + PHASE_UNSENT, + PHASE_REQUESTED, PHASE_READY, PHASE_DONE, PHASE_STARTED, @@ -31,6 +34,20 @@ import { import Spinner from "../elements/Spinner"; export default class VerificationPanel extends React.PureComponent { + static propTypes = { + request: PropTypes.object.isRequired, + member: PropTypes.object.isRequired, + phase: PropTypes.oneOf([ + PHASE_UNSENT, + PHASE_REQUESTED, + PHASE_READY, + PHASE_STARTED, + PHASE_CANCELLED, + PHASE_DONE, + ]).isRequired, + onClose: PropTypes.func.isRequired, + }; + constructor(props) { super(props); this.state = {}; diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index ec222159ab..aee0f57cf8 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -27,7 +27,8 @@ function capFirst(s) { export default class VerificationShowSas extends React.Component { static propTypes = { - displayName: PropTypes.string.isRequired, + pending: PropTypes.bool, + displayName: PropTypes.string, // required if pending is true onDone: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired, sas: PropTypes.object.isRequired, From d824145638adba42a753bb1518b4335c0758b487 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 07:54:10 +0000 Subject: [PATCH 08/18] show as pending whilst in an empty state until told better to prevent a flash --- src/components/views/right_panel/EncryptionPanel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/right_panel/EncryptionPanel.js b/src/components/views/right_panel/EncryptionPanel.js index d45280e29c..4e147bd7a5 100644 --- a/src/components/views/right_panel/EncryptionPanel.js +++ b/src/components/views/right_panel/EncryptionPanel.js @@ -36,7 +36,7 @@ const EncryptionPanel = ({verificationRequest, member, onClose}) => { setRequest(verificationRequest); }, [verificationRequest]); - const [phase, setPhase] = useState(false); + const [phase, setPhase] = useState(undefined); const changeHandler = useCallback(() => { // handle transitions -> cancelled for mismatches which fire a modal instead of showing a card if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) { @@ -71,7 +71,7 @@ const EncryptionPanel = ({verificationRequest, member, onClose}) => { setRequest(verificationRequest); }, [member.userId]); - const requested = request && phase === PHASE_REQUESTED; + const requested = request && (phase === PHASE_REQUESTED || phase === undefined); if (!request || requested) { return ; } else { From 2aa21d9199396dca19f4b9e0867be298e48b9d35 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 07:54:28 +0000 Subject: [PATCH 09/18] reload on enabling cross-signing just to make things generally happier --- src/settings/Settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 37a211e905..6011f0499a 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -147,6 +147,7 @@ export const SETTINGS = { displayName: _td("Enable cross-signing to verify per-user instead of per-device (in development)"), supportedLevels: LEVELS_FEATURE, default: false, + controller: new ReloadOnChangeController(), }, "feature_event_indexing": { isFeature: true, From 61d0021c8eef4f7d558a596800e7d210510c7cea Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 07:58:43 +0000 Subject: [PATCH 10/18] Fix styling special case for DialogButtons --- res/css/views/right_panel/_UserInfo.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss index c275f42222..dc22de4713 100644 --- a/res/css/views/right_panel/_UserInfo.scss +++ b/res/css/views/right_panel/_UserInfo.scss @@ -263,7 +263,9 @@ limitations under the License. .mx_UserInfo_verify { display: block; margin: 16px 0; - width: 100%; + } + button.mx_UserInfo_verify { + width: 100%; // FIXME get rid of this once we get rid of DialogButtons here } } From 0bb423fd5ad9aecf3b6d408471fefb2699d008b3 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 08:00:32 +0000 Subject: [PATCH 11/18] Add console log on unhandled error to track down rageshake --- src/components/views/right_panel/VerificationPanel.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 46179183e1..2d3fdd3f40 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -164,11 +164,11 @@ export default class VerificationPanel extends React.PureComponent { } render() { - const {member} = this.props; + const {member, phase} = this.props; const displayName = member.displayName || member.name || member.userId; - switch (this.props.phase) { + switch (phase) { case PHASE_READY: return this.renderQRPhase(); case PHASE_STARTED: @@ -191,6 +191,7 @@ export default class VerificationPanel extends React.PureComponent { case PHASE_CANCELLED: return this.renderCancelledPhase(); } + console.error("VerificationPanel unhandled phase:", phase) return null; } From 37e568448d8a09dae730d1334c04794cca089899 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Jan 2020 08:08:52 +0000 Subject: [PATCH 12/18] delint --- src/components/views/right_panel/VerificationPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 2d3fdd3f40..18a9024310 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -191,7 +191,7 @@ export default class VerificationPanel extends React.PureComponent { case PHASE_CANCELLED: return this.renderCancelledPhase(); } - console.error("VerificationPanel unhandled phase:", phase) + console.error("VerificationPanel unhandled phase:", phase); return null; } From e9854f5e44c3f9fce735acfde0da551173493f76 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 29 Jan 2020 09:32:09 +0000 Subject: [PATCH 13/18] i18n --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3ce31f69aa..df163bbd56 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1891,10 +1891,10 @@ "Start": "Start", "Session verified": "Session verified", "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.", + "Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.", "Done": "Done", "Without completing security on this device, it won’t have access to encrypted messages.": "Without completing security on this device, it won’t have access to encrypted messages.", "Go Back": "Go Back", - "Restoring": "Restoring", "Failed to send email": "Failed to send email", "The email address linked to your account must be entered.": "The email address linked to your account must be entered.", "A new password must be entered.": "A new password must be entered.", From 610354220e074a457f0875bca83c23a781c6f0e7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 29 Jan 2020 11:01:00 +0000 Subject: [PATCH 14/18] Automatically focus on the invite dialog input Fixes https://github.com/vector-im/riot-web/issues/12070 --- src/components/views/dialogs/InviteDialog.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index de11dbf9fa..afa204af04 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -937,6 +937,7 @@ export default class InviteDialog extends React.PureComponent { value={this.state.filterText} ref={this._editorRef} onPaste={this._onPaste} + autoFocus={true} /> ); return ( From 8d1265748348d90d673ecd4c4f5cf6cfc3b07d63 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 29 Jan 2020 11:14:33 +0000 Subject: [PATCH 15/18] Filter event types when deciding on activity metrics for DM suggestions Fixes https://github.com/vector-im/riot-web/issues/12083 --- src/components/views/dialogs/InviteDialog.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index de11dbf9fa..a911abbf76 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -351,9 +351,19 @@ export default class InviteDialog extends React.PureComponent { continue; } - const lastEventTs = room.timeline && room.timeline.length - ? room.timeline[room.timeline.length - 1].getTs() - : 0; + // Find the last timestamp for a message event + const searchTypes = ["m.room.message", "m.room.encrypted", "m.sticker"]; + const maxSearchEvents = 20; // to prevent traversing history + let lastEventTs = 0; + if (room.timeline && room.timeline.length) { + for (let i = room.timeline.length - 1; i >= 0; i--) { + const ev = room.timeline[i]; + if (searchTypes.includes(ev.getType())) { + lastEventTs = ev.getTs(); + } + if (room.timeline.length - i > maxSearchEvents) break; + } + } if (!lastEventTs) { // something weird is going on with this room console.warn(`[Invite:Recents] ${userId} (${room.roomId}) has a weird last timestamp: ${lastEventTs}`); From a138a66e77528bcbd6fcd44c7e63d73d3abded3e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 29 Jan 2020 11:22:03 +0000 Subject: [PATCH 16/18] Let users paste text if they've already started filtering invite targets Fixes https://github.com/vector-im/riot-web/issues/11814 --- src/components/views/dialogs/InviteDialog.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index afa204af04..ee0d26c48d 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -747,6 +747,12 @@ export default class InviteDialog extends React.PureComponent { }; _onPaste = async (e) => { + if (this.state.filterText) { + // if the user has already typed something, just let them + // paste normally. + return; + } + // Prevent the text being pasted into the textarea e.preventDefault(); From 95a78538e0b7cbf3b7ca91f567d491571c7ab1f0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 29 Jan 2020 11:23:48 +0000 Subject: [PATCH 17/18] Break after getting timestamp --- src/components/views/dialogs/InviteDialog.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index a911abbf76..9d60610784 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -360,6 +360,7 @@ export default class InviteDialog extends React.PureComponent { const ev = room.timeline[i]; if (searchTypes.includes(ev.getType())) { lastEventTs = ev.getTs(); + break; } if (room.timeline.length - i > maxSearchEvents) break; } From 7d6981ba1adc4a4e023eef4a02a3d9b66f9bea2e Mon Sep 17 00:00:00 2001 From: Zoe Date: Wed, 29 Jan 2020 11:29:56 +0000 Subject: [PATCH 18/18] Revert "reload on enabling cross-signing just to make things generally happier" This reverts commit 2aa21d9199396dca19f4b9e0867be298e48b9d35. It was causing a login loop --- src/settings/Settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 6011f0499a..37a211e905 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -147,7 +147,6 @@ export const SETTINGS = { displayName: _td("Enable cross-signing to verify per-user instead of per-device (in development)"), supportedLevels: LEVELS_FEATURE, default: false, - controller: new ReloadOnChangeController(), }, "feature_event_indexing": { isFeature: true,