diff --git a/res/css/_components.scss b/res/css/_components.scss index 22c9b73dca..bc636eb3c6 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -128,7 +128,6 @@ @import "./views/messages/_MEmoteBody.scss"; @import "./views/messages/_MFileBody.scss"; @import "./views/messages/_MImageBody.scss"; -@import "./views/messages/_MKeyVerificationRequest.scss"; @import "./views/messages/_MNoticeBody.scss"; @import "./views/messages/_MStickerBody.scss"; @import "./views/messages/_MTextBody.scss"; @@ -143,6 +142,7 @@ @import "./views/messages/_TextualEvent.scss"; @import "./views/messages/_UnknownBody.scss"; @import "./views/messages/_ViewSourceEvent.scss"; +@import "./views/messages/_common_CryptoEvent.scss"; @import "./views/right_panel/_EncryptionInfo.scss"; @import "./views/right_panel/_UserInfo.scss"; @import "./views/right_panel/_VerificationPanel.scss"; diff --git a/res/css/views/messages/_MKeyVerificationRequest.scss b/res/css/views/messages/_common_CryptoEvent.scss similarity index 61% rename from res/css/views/messages/_MKeyVerificationRequest.scss rename to res/css/views/messages/_common_CryptoEvent.scss index ee20751083..98e1e97e39 100644 --- a/res/css/views/messages/_MKeyVerificationRequest.scss +++ b/res/css/views/messages/_common_CryptoEvent.scss @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +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. @@ -14,60 +14,62 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_KeyVerification { +.mx_cryptoEvent { display: grid; grid-template-columns: 24px minmax(0, 1fr) min-content; - &.mx_KeyVerification_icon::after { + &.mx_cryptoEvent_icon::after { grid-column: 1; grid-row: 1 / 3; - width: 12px; + width: 16px; height: 16px; content: ""; - mask-image: url("$(res)/img/e2e/normal.svg"); - mask-repeat: no-repeat; - mask-size: 100%; + background-image: url("$(res)/img/e2e/normal.svg"); + background-repeat: no-repeat; + background-size: 100%; margin-top: 4px; - background-color: $primary-fg-color; } - &.mx_KeyVerification_icon_verified::after { - mask-image: url("$(res)/img/e2e/verified.svg"); - background-color: $accent-color; + &.mx_cryptoEvent_icon_verified::after { + background-image: url("$(res)/img/e2e/verified.svg"); } - .mx_KeyVerification_title, .mx_KeyVerification_subtitle, .mx_KeyVerification_state { + &.mx_cryptoEvent_icon_warning::after { + background-image: url("$(res)/img/e2e/warning.svg"); + } + + .mx_cryptoEvent_title, .mx_cryptoEvent_subtitle, .mx_cryptoEvent_state { overflow-wrap: break-word; } - .mx_KeyVerification_title { + .mx_cryptoEvent_title { font-weight: 600; font-size: 15px; grid-column: 2; grid-row: 1; } - .mx_KeyVerification_subtitle { + .mx_cryptoEvent_subtitle { grid-column: 2; grid-row: 2; } - .mx_KeyVerification_state, .mx_KeyVerification_subtitle { + .mx_cryptoEvent_state, .mx_cryptoEvent_subtitle { font-size: 12px; } - .mx_KeyVerification_state, .mx_KeyVerification_buttons { + .mx_cryptoEvent_state, .mx_cryptoEvent_buttons { grid-column: 3; grid-row: 1 / 3; } - .mx_KeyVerification_buttons { + .mx_cryptoEvent_buttons { align-items: center; display: flex; } - .mx_KeyVerification_state { + .mx_cryptoEvent_state { width: 130px; padding: 10px 20px; margin: auto 0; diff --git a/src/TextForEvent.js b/src/TextForEvent.js index cdfea45ad7..d4003058c8 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -442,23 +442,6 @@ function textForHistoryVisibilityEvent(event) { } } -function textForEncryptionEvent(event) { - const senderName = event.sender ? event.sender.name : event.getSender(); - if (event.getContent().algorithm === "m.megolm.v1.aes-sha2") { - return _t('%(senderName)s turned on end-to-end encryption.', { - senderName, - }); - } - return _t( - '%(senderName)s turned on end-to-end encryption ' + - '(unrecognised algorithm %(algorithm)s).', - { - senderName, - algorithm: event.getContent().algorithm, - }, - ); -} - // Currently will only display a change if a user's power level is changed function textForPowerEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); @@ -636,7 +619,6 @@ const stateHandlers = { 'm.room.member': textForMemberEvent, 'm.room.third_party_invite': textForThreePidInviteEvent, 'm.room.history_visibility': textForHistoryVisibilityEvent, - 'm.room.encryption': textForEncryptionEvent, 'm.room.power_levels': textForPowerEvent, 'm.room.pinned_events': textForPinnedEvent, 'm.room.server_acl': textForServerACLEvent, diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 4ad75eb700..a13278cf68 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -465,6 +465,12 @@ export default class MessagePanel extends React.Component { } return false; }; + // events that we include in the group but then eject out and place + // above the group. + const shouldEject = (ev) => { + if (ev.getType() === "m.room.encryption") return true; + return false; + }; if (mxEv.getType() === "m.room.create") { let summaryReadMarker = null; const ts1 = mxEv.getTs(); @@ -484,6 +490,7 @@ export default class MessagePanel extends React.Component { } const summarisedEvents = []; // Don't add m.room.create here as we don't want it inside the summary + const ejectedEvents = []; for (;i + 1 < this.props.events.length; i++) { const collapsedMxEv = this.props.events[i + 1]; @@ -501,7 +508,11 @@ export default class MessagePanel extends React.Component { // If RM event is in the summary, mark it as such and the RM will be appended after the summary. summaryReadMarker = summaryReadMarker || this._readMarkerForEvent(collapsedMxEv.getId()); - summarisedEvents.push(collapsedMxEv); + if (shouldEject(collapsedMxEv)) { + ejectedEvents.push(collapsedMxEv); + } else { + summarisedEvents.push(collapsedMxEv); + } } // At this point, i = the index of the last event in the summary sequence @@ -513,6 +524,10 @@ export default class MessagePanel extends React.Component { return this._getTilesForEvent(e, e, e === lastShownEvent); }).reduce((a, b) => a.concat(b), []); + for (const ejected of ejectedEvents) { + ret.push(...this._getTilesForEvent(mxEv, ejected, last)); + } + // Get sender profile from the latest event in the summary as the m.room.create doesn't contain one const ev = this.props.events[i]; ret.push( +
{_t("Encryption enabled")}
+
+ {_t( + "Messages in this room are end-to-end encrypted. " + + "Learn more & verify this user in their user profile.", + )} +
+ ; + } else { + body =
+
{_t("Encryption not enabled")}
+
{_t("The encryption used by this room isn't supported.")}
+
; + classes += " mx_cryptoEvent_icon_warning"; + } + + return (
+ {body} +
); + } +} + +EncryptionEvent.propTypes = { + /* the MatrixEvent to show */ + mxEvent: PropTypes.object.isRequired, +}; diff --git a/src/components/views/messages/MKeyVerificationConclusion.js b/src/components/views/messages/MKeyVerificationConclusion.js index a17dcd8ab0..c410c7fdff 100644 --- a/src/components/views/messages/MKeyVerificationConclusion.js +++ b/src/components/views/messages/MKeyVerificationConclusion.js @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +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. @@ -94,12 +94,12 @@ export default class MKeyVerificationConclusion extends React.Component { if (title) { const subtitle = userLabelForEventRoom(request.otherUserId, mxEvent.getRoomId()); - const classes = classNames("mx_EventTile_bubble", "mx_KeyVerification", "mx_KeyVerification_icon", { - mx_KeyVerification_icon_verified: request.done, + const classes = classNames("mx_EventTile_bubble", "mx_cryptoEvent", "mx_cryptoEvent_icon", { + mx_cryptoEvent_icon_verified: request.done, }); return (
-
{title}
-
{subtitle}
+
{title}
+
{subtitle}
); } diff --git a/src/components/views/messages/MKeyVerificationRequest.js b/src/components/views/messages/MKeyVerificationRequest.js index ebe5c9adf7..ab02b2e5ad 100644 --- a/src/components/views/messages/MKeyVerificationRequest.js +++ b/src/components/views/messages/MKeyVerificationRequest.js @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +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. @@ -125,30 +125,30 @@ export default class MKeyVerificationRequest extends React.Component { } else { stateLabel = this._cancelledLabel(request.cancellingUserId); } - stateNode = (
{stateLabel}
); + stateNode = (
{stateLabel}
); } if (!request.initiatedByMe) { const name = getNameForEventRoom(request.requestingUserId, mxEvent.getRoomId()); - title = (
{ + title = (
{ _t("%(name)s wants to verify", {name})}
); - subtitle = (
{ + subtitle = (
{ userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId())}
); if (request.requested && !request.observeOnly) { - stateNode = (
+ stateNode = (
); } } else { // request sent by us - title = (
{ + title = (
{ _t("You sent a verification request")}
); - subtitle = (
{ + subtitle = (
{ userLabelForEventRoom(request.receivingUserId, mxEvent.getRoomId())}
); } if (title) { - return (
+ return (
{title} {subtitle} {stateNode} diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index a8e9c7bf81..bba2310281 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -40,12 +40,14 @@ const eventTileTypes = { 'm.sticker': 'messages.MessageEvent', 'm.key.verification.cancel': 'messages.MKeyVerificationConclusion', 'm.key.verification.done': 'messages.MKeyVerificationConclusion', + 'm.room.encryption': 'messages.EncryptionEvent', 'm.call.invite': 'messages.TextualEvent', 'm.call.answer': 'messages.TextualEvent', 'm.call.hangup': 'messages.TextualEvent', }; const stateEventTileTypes = { + 'm.room.encryption': 'messages.EncryptionEvent', 'm.room.aliases': 'messages.TextualEvent', // 'm.room.aliases': 'messages.RoomAliasesEvent', // too complex 'm.room.canonical_alias': 'messages.TextualEvent', @@ -55,7 +57,6 @@ const stateEventTileTypes = { 'm.room.avatar': 'messages.RoomAvatarEvent', 'm.room.third_party_invite': 'messages.TextualEvent', 'm.room.history_visibility': 'messages.TextualEvent', - 'm.room.encryption': 'messages.TextualEvent', 'm.room.topic': 'messages.TextualEvent', 'm.room.power_levels': 'messages.TextualEvent', 'm.room.pinned_events': 'messages.TextualEvent', @@ -600,7 +601,8 @@ export default createReactClass({ // Info messages are basically information about commands processed on a room const isBubbleMessage = eventType.startsWith("m.key.verification") || - (eventType === "m.room.message" && msgtype && msgtype.startsWith("m.key.verification")); + (eventType === "m.room.message" && msgtype && msgtype.startsWith("m.key.verification")) || + (eventType === "m.room.encryption"); let isInfoMessage = ( !isBubbleMessage && eventType !== 'm.room.message' && eventType !== 'm.sticker' && eventType !== 'm.room.create' diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8901f85cb9..3c7b515833 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -259,8 +259,6 @@ "%(senderName)s made future room history visible to all room members.": "%(senderName)s made future room history visible to all room members.", "%(senderName)s made future room history visible to anyone.": "%(senderName)s made future room history visible to anyone.", "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s made future room history visible to unknown (%(visibility)s).", - "%(senderName)s turned on end-to-end encryption.": "%(senderName)s turned on end-to-end encryption.", - "%(senderName)s turned on end-to-end encryption (unrecognised algorithm %(algorithm)s).": "%(senderName)s turned on end-to-end encryption (unrecognised algorithm %(algorithm)s).", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.", "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.", @@ -1196,6 +1194,10 @@ "Today": "Today", "Yesterday": "Yesterday", "View Source": "View Source", + "Encryption enabled": "Encryption enabled", + "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.", + "Encryption not enabled": "Encryption not enabled", + "The encryption used by this room isn't supported.": "The encryption used by this room isn't supported.", "Error decrypting audio": "Error decrypting audio", "React": "React", "Reply": "Reply",