Skip to content

Commit

Permalink
feat: Show E2EI Verification system message (#16224)
Browse files Browse the repository at this point in the history
* feat: Show E2EI Verification system message

* Add second line message

* render e2ei verification system message

* remove unused code

* show system message

* fix for display verification message

* fix for displaying cell state description

* suggestion fix
  • Loading branch information
phoenixhdd authored Nov 21, 2023
1 parent 1351a5d commit 3943102
Show file tree
Hide file tree
Showing 16 changed files with 127 additions and 5 deletions.
1 change: 1 addition & 0 deletions server/config/client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export function generateConfig(params: ConfigGeneratorParams, env: Env) {
OAUTH_LEARN_MORE: env.URL_SUPPORT_OAUTH_LEARN_MORE,
OFFLINE_BACKEND: env.URL_SUPPORT_OFFLINE_BACKEND,
FEDERATION_STOP: env.URL_SUPPORT_FEDERATION_STOP,
E2EI_VERIFICATION: env.URL_SUPPORT_E2EI_VERIFICATION,
},
TEAMS_BASE: env.URL_TEAMS_BASE,
TEAMS_CREATE: env.URL_TEAMS_CREATE,
Expand Down
1 change: 1 addition & 0 deletions server/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export type Env = {
URL_SUPPORT_OFFLINE_BACKEND: string;

URL_SUPPORT_FEDERATION_STOP: string;
URL_SUPPORT_E2EI_VERIFICATION: string;

URL_WHATS_NEW: string;

Expand Down
5 changes: 4 additions & 1 deletion src/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,10 @@
"timedMessageDisclaimer": "Self-deleting messages will be turned on for all the participants in this conversation.",
"timedMessagesTitle": "Self-deleting messages",
"tooltipConversationAddImage": "Add picture",
"tooltipConversationAllVerified": "All fingerprints are verified",
"tooltipConversationAllVerified": "All fingerprints are verified (Proteus)",
"tooltipConversationAllDevicesVerified": "All device fingerprints verified (Proteus)",
"tooltipConversationAllE2EIVerified": "All devices are verified (end-to-end identity). [link]Learn more[/link]",
"tooltipConversationAllE2EIVerifiedShort": "All devices verified (end-to-end identity)",
"tooltipConversationCall": "Call",
"tooltipConversationDetailsAddPeople": "Add participants to conversation ({{shortcut}})",
"tooltipConversationDetailsRename": "Change conversation name",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@

import React from 'react';

import {MLSVerified} from '@wireapp/react-ui-kit';

import {Icon} from 'Components/Icon';
import {E2EIVerificationMessage} from 'src/script/entity/message/E2EIVerificationMessage';
import {MessageTimerUpdateMessage} from 'src/script/entity/message/MessageTimerUpdateMessage';
import {MLSConversationRecoveredMessage} from 'src/script/entity/message/MLSConversationRecoveredMessage';
import {ReceiptModeUpdateMessage} from 'src/script/entity/message/ReceiptModeUpdateMessage';
Expand Down Expand Up @@ -54,5 +57,9 @@ export const SystemMessage: React.FC<SystemMessageProps> = ({message}) => {
return <SystemMessageBase message={message} icon={<Icon.Info />} />;
}

if (message instanceof E2EIVerificationMessage) {
return <SystemMessageBase message={message} icon={<MLSVerified className="filled" />} />;
}

return <SystemMessageBase message={message} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const SystemMessageBase: React.FC<SystemMessageProps> = ({message, isSend
<p className="message-header-label">
<span className="message-header-label__multiline">
{isSenderNameVisible && <span className="message-header-sender-name">{unsafeSenderName}</span>}
{message.caption && <span className="ellipsis">{message.caption}</span>}
{message.caption && <span className="ellipsis" dangerouslySetInnerHTML={{__html: message.caption}} />}
</span>
</p>
<div className="message-body-actions">
Expand Down
6 changes: 6 additions & 0 deletions src/script/conversation/ConversationCellState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type {MemberMessage} from '../entity/message/MemberMessage';
import type {SystemMessage} from '../entity/message/SystemMessage';
import type {Text} from '../entity/message/Text';
import {ConversationError} from '../error/ConversationError';
import {ClientEvent} from '../event/Client';

enum ACTIVITY_TYPE {
CALL = 'ConversationCellState.ACTIVITY_TYPE.CALL',
Expand Down Expand Up @@ -334,6 +335,10 @@ const _getStateUnreadMessage = {
string = t('notificationSharedLocation');
} else if (messageEntity.hasAssetImage()) {
string = t('notificationAssetAdd');
} else if (messageEntity?.type === ClientEvent.CONVERSATION.E2EI_VERIFICATION) {
string = t('tooltipConversationAllDevicesVerified');
} else if (messageEntity.isVerification()) {
string = t('tooltipConversationAllDevicesVerified');
}

if (!!string) {
Expand Down Expand Up @@ -388,6 +393,7 @@ export const generateCellState = (
_getStateUnreadMessage,
_getStateUserName,
];

const matchingState = states.find(state => state.match(conversationEntity)) || _getStateDefault;

return {
Expand Down
1 change: 1 addition & 0 deletions src/script/conversation/ConversationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,7 @@ export class ConversationRepository {
case ClientEvent.CONVERSATION.VERIFICATION:
case ClientEvent.CONVERSATION.VOICE_CHANNEL_ACTIVATE:
case ClientEvent.CONVERSATION.VOICE_CHANNEL_DEACTIVATE:
case ClientEvent.CONVERSATION.E2EI_VERIFICATION:
return this.addEventToConversation(conversationEntity, eventJson);
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/script/conversation/EventBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,12 @@ export interface ErrorEvent
id: string;
}

// E2EI Verified Events
export type AllE2EIVerifiedEvent = ConversationEvent<CONVERSATION.E2EI_VERIFICATION>;

export type ClientConversationEvent =
| AllVerifiedEvent
| AllE2EIVerifiedEvent
| AssetAddEvent
| ErrorEvent
| CompositeMessageAddEvent
Expand Down Expand Up @@ -309,6 +313,17 @@ export const EventBuilder = {
};
},

buildAllE2EIVerified(conversationEntity: Conversation): AllE2EIVerifiedEvent {
return {
...buildQualifiedId(conversationEntity),
data: undefined,
from: '',
id: createUuid(),
time: conversationEntity.getNextIsoDate(),
type: ClientEvent.CONVERSATION.E2EI_VERIFICATION,
};
},

buildCallingTimeoutEvent(
reason: AVS_REASON.NOONE_JOINED | AVS_REASON.EVERYONE_LEFT,
conversation: Conversation,
Expand Down
13 changes: 13 additions & 0 deletions src/script/conversation/EventMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {CompositeMessage} from '../entity/message/CompositeMessage';
import {ContentMessage} from '../entity/message/ContentMessage';
import {DecryptErrorMessage} from '../entity/message/DecryptErrorMessage';
import {DeleteMessage} from '../entity/message/DeleteMessage';
import {E2EIVerificationMessage} from '../entity/message/E2EIVerificationMessage';
import {FailedToAddUsersMessage} from '../entity/message/FailedToAddUsersMessage';
import {FederationStopMessage} from '../entity/message/FederationStopMessage';
import {FileAsset} from '../entity/message/FileAsset';
Expand Down Expand Up @@ -331,6 +332,11 @@ export class EventMapper {
break;
}

case ClientEvent.CONVERSATION.E2EI_VERIFICATION: {
messageEntity = this._mapEventE2EIVerificationMessage();
break;
}

case ClientEvent.CONVERSATION.ONE2ONE_CREATION: {
messageEntity = this._mapEvent1to1Creation(event);
break;
Expand Down Expand Up @@ -643,6 +649,13 @@ export class EventMapper {
return new MLSConversationRecoveredMessage();
}

/**
* Maps JSON data of E2E Identity verification message event to message entity.
*/
private _mapEventE2EIVerificationMessage(): MissedMessage {
return new E2EIVerificationMessage();
}

/**
* Maps JSON data of `conversation.knock` message into message entity.
*/
Expand Down
11 changes: 10 additions & 1 deletion src/script/entity/Conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {CallMessage} from './message/CallMessage';
import type {ContentMessage} from './message/ContentMessage';
import type {Message} from './message/Message';
import {PingMessage} from './message/PingMessage';
import {SystemMessage} from './message/SystemMessage';
import type {User} from './User';

import type {Call} from '../calling/Call';
Expand All @@ -57,6 +58,7 @@ import {ConversationStatus} from '../conversation/ConversationStatus';
import {ConversationVerificationState} from '../conversation/ConversationVerificationState';
import {NOTIFICATION_STATE} from '../conversation/NotificationSetting';
import {ConversationError} from '../error/ConversationError';
import {ClientEvent} from '../event/Client';
import {isContentMessage, isDeleteMessage} from '../guards/Message';
import {StatusType} from '../message/StatusType';
import {ConversationRecord} from '../storage/record/ConversationRecord';
Expand All @@ -70,6 +72,7 @@ interface UnreadState {
pings: PingMessage[];
selfMentions: ContentMessage[];
selfReplies: ContentMessage[];
systemMessages: SystemMessage[];
}

enum TIMESTAMP_TYPE {
Expand Down Expand Up @@ -431,8 +434,10 @@ export class Conversation {
pings: [],
selfMentions: [],
selfReplies: [],
systemMessages: [],
};
const messages = [...this.messages(), ...this.incomingMessages()];

for (let index = messages.length - 1; index >= 0; index--) {
const messageEntity = messages[index];
if (messageEntity.visible()) {
Expand All @@ -451,7 +456,11 @@ export class Conversation {
const isSelfQuoted =
isMessage && this.selfUser() && (messageEntity as ContentMessage).isUserQuoted(this.selfUser().id);

if (isMissedCall || isPing || isMessage) {
const isMLSProtocol = this.protocol === ConversationProtocol.MLS;
const isE2EIVerification =
isMLSProtocol && messageEntity?.type === ClientEvent.CONVERSATION.E2EI_VERIFICATION;

if (isMissedCall || isPing || isMessage || isE2EIVerification) {
unreadState.allMessages.push(messageEntity as ContentMessage);
}

Expand Down
37 changes: 37 additions & 0 deletions src/script/entity/message/E2EIVerificationMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Wire
* Copyright (C) 2023 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {replaceLink, t} from 'Util/LocalizerUtil';

import {SystemMessage} from './SystemMessage';

import {Config} from '../../Config';
import {SystemMessageType} from '../../message/SystemMessageType';

export class E2EIVerificationMessage extends SystemMessage {
constructor() {
super();
this.system_message_type = SystemMessageType.E2EI_VERIFIED;
this.caption = t(
'tooltipConversationAllE2EIVerified',
{},
replaceLink(Config.getConfig().URL.SUPPORT.E2EI_VERIFICATION),
);
}
}
1 change: 1 addition & 0 deletions src/script/event/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export enum CONVERSATION {
FEDERATION_STOP = 'conversation.federation-stop',
VOICE_CHANNEL_ACTIVATE = 'conversation.voice-channel-activate',
VOICE_CHANNEL_DEACTIVATE = 'conversation.voice-channel-deactivate',
E2EI_VERIFICATION = 'conversation.e2ei-verification',
}

export enum USER {
Expand Down
1 change: 1 addition & 0 deletions src/script/event/EventTypeHandling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ export const EventTypeHandling = {
ClientEvent.CONVERSATION.VERIFICATION,
ClientEvent.CONVERSATION.VOICE_CHANNEL_ACTIVATE,
ClientEvent.CONVERSATION.VOICE_CHANNEL_DEACTIVATE,
ClientEvent.CONVERSATION.E2EI_VERIFICATION,
],
};
20 changes: 19 additions & 1 deletion src/script/main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ import {ConnectionRepository} from '../connection/ConnectionRepository';
import {ConnectionService} from '../connection/ConnectionService';
import {ConversationRepository} from '../conversation/ConversationRepository';
import {ConversationService} from '../conversation/ConversationService';
import {ConversationVerificationState} from '../conversation/ConversationVerificationState';
import {registerMLSConversationVerificationStateHandler} from '../conversation/ConversationVerificationStateHandler';
import {OnConversationVerificationStateChange} from '../conversation/ConversationVerificationStateHandler/shared';
import {EventBuilder} from '../conversation/EventBuilder';
import {MessageRepository} from '../conversation/MessageRepository';
import {CryptographyRepository} from '../cryptography/CryptographyRepository';
import {User} from '../entity/User';
Expand Down Expand Up @@ -371,8 +374,9 @@ export class App {
if (!localClient) {
throw new ClientError(CLIENT_ERROR_TYPE.NO_VALID_CLIENT, 'Client has been deleted on backend');
}

if (supportsMLS()) {
registerMLSConversationVerificationStateHandler();
registerMLSConversationVerificationStateHandler(this.updateConversationVerificationState);
}

this.core.on(CoreEvents.NEW_SESSION, ({userId, clientId}) => {
Expand Down Expand Up @@ -802,4 +806,18 @@ export class App {

doRedirect(signOutReason);
}

private updateConversationVerificationState: OnConversationVerificationStateChange = async ({
conversationEntity,
conversationVerificationState,
}) => {
switch (conversationVerificationState) {
case ConversationVerificationState.VERIFIED:
const allVerifiedEvent = EventBuilder.buildAllE2EIVerified(conversationEntity);
await this.repository.event.injectEvent(allVerifiedEvent);
break;
default:
break;
}
};
}
1 change: 1 addition & 0 deletions src/script/message/SystemMessageType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ export enum SystemMessageType {
MEMBER_LEAVE = 'leave',
NORMAL = 'normal',
MLS_CONVERSATION_RECOVERED = 'mls-conversation-recovered',
E2EI_VERIFIED = 'e2ei-verified',
}
10 changes: 9 additions & 1 deletion src/style/content/conversation/message-list.less
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
&--svg {
line-height: 0;

svg path {
svg:not(.filled) path {
fill: var(--foreground);
}
}
Expand Down Expand Up @@ -864,3 +864,11 @@
background-color: var(--message-actions-background-hover);
}
}

.system-message-caption {
& > a {
color: inherit;
font-weight: @font-weight-bold;
text-decoration: underline;
}
}

0 comments on commit 3943102

Please sign in to comment.