diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index 2c05f231e7..9d07628093 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -236,12 +236,20 @@ export default class CreateSecretStorageDialog extends React.PureComponent { try { if (force) { + console.log("Forcing secret storage reset"); // log something so we can debug this later await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, createSecretStorageKey: async () => this._recoveryKey, - setupNewKeyBackup: true, + setupNewKeyBackup: this.state.useKeyBackup, setupNewSecretStorage: true, }); + if (!this.state.useKeyBackup && this.state.backupInfo) { + // If the user is resetting their cross-signing keys and doesn't want + // key backup (but had it enabled before), delete the key backup as it's + // no longer valid. + console.log("Deleting invalid key backup (secrets have been reset; key backup not requested)"); + await cli.deleteKeyBackupVersion(this.state.backupInfo.version); + } } else { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 69a2e54a2c..f53929df4a 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1717,8 +1717,11 @@ export default createReactClass({ } else { const myUserId = this.context.credentials.userId; const myMember = this.state.room.getMember(myUserId); - const inviteEvent = myMember.events.member; - var inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender(); + const inviteEvent = myMember ? myMember.events.member : null; + let inviterName = _t("Unknown"); + if (inviteEvent) { + inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender(); + } // We deliberately don't try to peek into invites, even if we have permission to peek // as they could be a spam vector. diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index c74f6ed6e3..7818496e71 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -267,6 +267,7 @@ export default createReactClass({ dis.dispatch({action: 'start_login'}); } else { this.setState({ + serverErrorIsFatal: true, // fatal because user cannot continue on this server errorText: _t("Registration has been disabled on this homeserver."), // add empty flows array to get rid of spinner flows: [], diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 452489aa65..70ab80e6cc 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -130,22 +130,24 @@ export default createReactClass({ }, onViewSourceClick: function() { + const ev = this.props.mxEvent.replacingEvent() || this.props.mxEvent; const ViewSource = sdk.getComponent('structures.ViewSource'); Modal.createTrackedDialog('View Event Source', '', ViewSource, { - roomId: this.props.mxEvent.getRoomId(), - eventId: this.props.mxEvent.getId(), - content: this.props.mxEvent.event, + roomId: ev.getRoomId(), + eventId: ev.getId(), + content: ev.event, }, 'mx_Dialog_viewsource'); this.closeMenu(); }, onViewClearSourceClick: function() { + const ev = this.props.mxEvent.replacingEvent() || this.props.mxEvent; const ViewSource = sdk.getComponent('structures.ViewSource'); Modal.createTrackedDialog('View Clear Event Source', '', ViewSource, { - roomId: this.props.mxEvent.getRoomId(), - eventId: this.props.mxEvent.getId(), + roomId: ev.getRoomId(), + eventId: ev.getId(), // FIXME: _clearEvent is private - content: this.props.mxEvent._clearEvent, + content: ev._clearEvent, }, 'mx_Dialog_viewsource'); this.closeMenu(); }, diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index f1008dfcb0..7e51e76f6c 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -23,6 +23,7 @@ import { MatrixClient } from 'matrix-js-sdk'; import Modal from '../../../../Modal'; import { _t } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../CrossSigningManager'; +import SettingsStore from "../../../../settings/SettingsStore"; const RESTORE_TYPE_PASSPHRASE = 0; const RESTORE_TYPE_RECOVERYKEY = 1; @@ -89,14 +90,21 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { _onResetRecoveryClick = () => { this.props.onFinished(false); - Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', - import('../../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'), - { - onFinished: () => { - this._loadBackupStatus(); - }, - }, null, /* priority = */ false, /* static = */ true, - ); + + if (SettingsStore.getValue("feature_cross_signing")) { + // If cross-signing is enabled, we reset the SSSS recovery passphrase (and cross-signing keys) + this.props.onFinished(false); + accessSecretStorage(() => {}, /* forceReset = */ true); + } else { + Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', + import('../../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'), + { + onFinished: () => { + this._loadBackupStatus(); + }, + }, null, /* priority = */ false, /* static = */ true, + ); + } } _onRecoveryKeyChange = (e) => { diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index 61f5a8161a..478dc90418 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -557,7 +557,7 @@ const RedactMessagesButton = ({member}) => { let eventsToRedact = []; while (timeline) { eventsToRedact = timeline.getEvents().reduce((events, event) => { - if (event.getSender() === userId && !event.isRedacted()) { + if (event.getSender() === userId && !event.isRedacted() && !event.isRedaction()) { return events.concat(event); } else { return events; diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index be3e8cf971..6b03000961 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -364,7 +364,7 @@ export default createReactClass({ let eventsToRedact = []; for (const timeline of timelineSet.getTimelines()) { eventsToRedact = timeline.getEvents().reduce((events, event) => { - if (event.getSender() === userId && !event.isRedacted()) { + if (event.getSender() === userId && !event.isRedacted() && !event.isRedaction()) { return events.concat(event); } else { return events; diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index cb04d2a018..c07f1c25dd 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -131,8 +131,8 @@ export default class CrossSigningPanel extends React.PureComponent { } _destroySecureSecretStorage = () => { - const ConfirmDestoryCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog"); - Modal.createDialog(ConfirmDestoryCrossSigningDialog, { + const ConfirmDestroyCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog"); + Modal.createDialog(ConfirmDestroyCrossSigningDialog, { onFinished: this.onDestroyStorage, }); } diff --git a/src/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts index d01fa66655..e5027e0d37 100644 --- a/src/rageshake/submit-rageshake.ts +++ b/src/rageshake/submit-rageshake.ts @@ -101,37 +101,40 @@ export default async function sendBugReport(bugReportEndpoint: string, opts: IOp if (client) { body.append('user_id', client.credentials.userId); body.append('device_id', client.deviceId); - } - if (client.isCryptoEnabled()) { - const keys = [`ed25519:${client.getDeviceEd25519Key()}`]; - if (client.getDeviceCurve25519Key) { - keys.push(`curve25519:${client.getDeviceCurve25519Key()}`); + if (client.isCryptoEnabled()) { + const keys = [`ed25519:${client.getDeviceEd25519Key()}`]; + if (client.getDeviceCurve25519Key) { + keys.push(`curve25519:${client.getDeviceCurve25519Key()}`); + } + body.append('device_keys', keys.join(', ')); + body.append('cross_signing_key', client.getCrossSigningId()); + + body.append('device_keys', keys.join(', ')); + + // add cross-signing status information + const crossSigning = client._crypto._crossSigningInfo; + const secretStorage = client._crypto._secretStorage; + + body.append("cross_signing_key", crossSigning.getId()); + body.append("cross_signing_pk_in_ssss", + String(!!(await crossSigning.isStoredInSecretStorage(secretStorage)))); + body.append("ssss_key_in_account", String(!!(await secretStorage.hasKey()))); + + const pkCache = client.getCrossSigningCacheCallbacks(); + body.append("self_signing_pk_cached", + String(!!(pkCache && await pkCache.getCrossSigningKeyCache("self_signing")))); + body.append("user_signing_pk_cached", + String(!!(pkCache && await pkCache.getCrossSigningKeyCache("user_signing")))); + + const sessionBackupKeyFromCache = await client._crypto.getSessionBackupPrivateKey(); + body.append("session_backup_key_cached", String(!!sessionBackupKeyFromCache)); + body.append("session_backup_key_well_formed", String(sessionBackupKeyFromCache instanceof Uint8Array)); + body.append("cross_signing_supported_by_hs", + String(await client.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing"))); + body.append("cross_signing_ready", String(await client.isCrossSigningReady())); + body.append("ssss_key_needs_upgrade", String(await client.secretStorageKeyNeedsUpgrade())); } - body.append('device_keys', keys.join(', ')); - - // add cross-signing status information - const crossSigning = client._crypto._crossSigningInfo; - const secretStorage = client._crypto._secretStorage; - - body.append("cross_signing_key", crossSigning.getId()); - body.append("cross_signing_pk_in_ssss", - String(!!(await crossSigning.isStoredInSecretStorage(secretStorage)))); - body.append("ssss_key_in_account", String(!!(await secretStorage.hasKey()))); - - const pkCache = client.getCrossSigningCacheCallbacks(); - body.append("self_signing_pk_cached", - String(!!(pkCache && await pkCache.getCrossSigningKeyCache("self_signing")))); - body.append("user_signing_pk_cached", - String(!!(pkCache && await pkCache.getCrossSigningKeyCache("user_signing")))); - - const sessionBackupKeyFromCache = await client._crypto.getSessionBackupPrivateKey(); - body.append("session_backup_key_cached", String(!!sessionBackupKeyFromCache)); - body.append("session_backup_key_well_formed", String(sessionBackupKeyFromCache instanceof Uint8Array)); - body.append("cross_signing_supported_by_hs", - String(await client.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing"))); - body.append("cross_signing_ready", String(await client.isCrossSigningReady())); - body.append("ssss_key_needs_upgrade", String(await client.secretStorageKeyNeedsUpgrade())); } if (opts.label) {