[IMPROVE] OTR Message (#24297)

Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com>
pull/26673/head^2
Fábio Albuquerque 3 years ago committed by GitHub
parent 02d5f70e1c
commit 7acbb2a320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      apps/meteor/app/lib/server/functions/sendMessage.js
  2. 24
      apps/meteor/app/otr/client/OTRRoom.ts
  3. 2
      apps/meteor/app/otr/lib/IOTR.ts
  4. 2
      apps/meteor/app/otr/server/index.ts
  5. 8
      apps/meteor/app/otr/server/methods/updateOTRAck.ts
  6. 2
      apps/meteor/app/ui-utils/client/lib/RoomManager.ts
  7. 34
      apps/meteor/client/startup/otr.ts
  8. 10
      apps/meteor/server/modules/notifications/notifications.module.ts
  9. 3
      packages/core-typings/src/IMessage/IMessage.ts

@ -10,6 +10,7 @@ import { hasPermission } from '../../../authorization/server';
import { SystemLogger } from '../../../../server/lib/logger/system';
import { parseUrlsInMessage } from './parseUrlsInMessage';
import { isRelativeURL } from '../../../../lib/utils/isRelativeURL';
import notifications from '../../../notifications/server/lib/Notifications';
/**
* IMPORTANT
@ -244,7 +245,10 @@ export const sendMessage = function (user, message, room, upsert = false) {
message = callbacks.run('beforeSaveMessage', message, room);
if (message) {
if (message._id && upsert) {
if (message.t === 'otr') {
const otrStreamer = notifications.streamRoomMessage;
otrStreamer.emit(message.rid, message, user, room);
} else if (message._id && upsert) {
const { _id } = message;
delete message._id;
Messages.upsert(

@ -66,8 +66,7 @@ export class OTRRoom implements IOTRRoom {
}
setState(nextState: OtrRoomState): void {
const currentState = this.state.get();
if (currentState === nextState) {
if (this.getState() === nextState) {
return;
}
@ -141,7 +140,7 @@ export class OTRRoom implements IOTRRoom {
this._userOnlineComputation = Tracker.autorun(() => {
const $room = $(`#chat-window-${this._roomId}`);
const $title = $('.rc-header__title', $room);
if (this.state.get() === OtrRoomState.ESTABLISHED) {
if (this.getState() === OtrRoomState.ESTABLISHED) {
if ($room.length && $title.length && !$('.otr-icon', $title).length) {
$title.prepend("<i class='otr-icon icon-key'></i>");
}
@ -252,8 +251,8 @@ export class OTRRoom implements IOTRRoom {
const establishConnection = async (): Promise<void> => {
this.setState(OtrRoomState.ESTABLISHING);
Meteor.clearTimeout(timeout);
try {
if (!data.publicKey) throw new Error('Public key is not generated');
await this.generateKeyPair();
await this.importPublicKey(data.publicKey);
await goToRoomById(data.roomId);
@ -283,11 +282,11 @@ export class OTRRoom implements IOTRRoom {
throw new Meteor.Error('user-not-defined', 'User not defined.');
}
if (data.refresh && this.state.get() === OtrRoomState.ESTABLISHED) {
if (data.refresh && this.getState() === OtrRoomState.ESTABLISHED) {
this.reset();
await establishConnection();
} else {
if (this.state.get() === OtrRoomState.ESTABLISHED) {
if (this.getState() === OtrRoomState.ESTABLISHED) {
this.reset();
}
imperativeModal.open({
@ -308,11 +307,11 @@ export class OTRRoom implements IOTRRoom {
},
},
});
timeout = Meteor.setTimeout(() => {
this.setState(OtrRoomState.TIMEOUT);
imperativeModal.close();
}, 10000);
}
timeout = Meteor.setTimeout(() => {
this.setState(OtrRoomState.TIMEOUT);
imperativeModal.close();
}, 10000);
} catch (e) {
dispatchToastMessage({ type: 'error', message: e });
}
@ -320,6 +319,7 @@ export class OTRRoom implements IOTRRoom {
case 'acknowledge':
try {
if (!data.publicKey) throw new Error('Public key is not generated');
await this.importPublicKey(data.publicKey);
this.setState(OtrRoomState.ESTABLISHED);
@ -334,7 +334,7 @@ export class OTRRoom implements IOTRRoom {
break;
case 'deny':
if (this.state.get() === OtrRoomState.ESTABLISHING) {
if (this.getState() === OtrRoomState.ESTABLISHING) {
this.reset();
this.setState(OtrRoomState.DECLINED);
}
@ -347,7 +347,7 @@ export class OTRRoom implements IOTRRoom {
throw new Meteor.Error('user-not-defined', 'User not defined.');
}
if (this.state.get() === OtrRoomState.ESTABLISHED) {
if (this.getState() === OtrRoomState.ESTABLISHED) {
this.reset();
this.setState(OtrRoomState.NOT_STARTED);
imperativeModal.open({

@ -5,8 +5,8 @@ import type { OTRRoom } from '../client/OTRRoom';
export interface IOnUserStreamData {
roomId: IRoom['_id'];
publicKey: string;
userId: IUser['_id'];
publicKey?: string;
refresh?: boolean;
}

@ -1,4 +1,4 @@
import './settings';
import './methods/deleteOldOTRMessages';
import './methods/updateOTRAck';
import './methods/sendSystemMessages';
import './methods/deleteOldOTRMessages';

@ -1,13 +1,13 @@
import type { IMessage } from '@rocket.chat/core-typings';
import { Meteor } from 'meteor/meteor';
import { Messages } from '../../../models/server';
import notifications from '../../../notifications/server/lib/Notifications';
Meteor.methods({
updateOTRAck(_id: IMessage['_id'], ack: IMessage['otrAck']): void {
updateOTRAck({ message, ack }) {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'updateOTRAck' });
}
Messages.updateOTRAck(_id, ack);
const otrStreamer = notifications.streamRoomMessage;
otrStreamer.emit(message.rid, { ...message, otr: { ack } });
},
});

@ -193,7 +193,7 @@ const computation = Tracker.autorun(() => {
}
}
msg.name = room.name;
msg.name = room.name || '';
handleTrackSettingsChange(msg);

@ -1,23 +1,32 @@
import { AtLeast, IMessage } from '@rocket.chat/core-typings';
import { IMessage, IRoom, IUser, AtLeast } from '@rocket.chat/core-typings';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { Notifications } from '../../app/notifications/client';
import OTR from '../../app/otr/client/OTR';
import { IOnUserStreamData, IOTRDecrypt } from '../../app/otr/lib/IOTR';
import { OtrRoomState } from '../../app/otr/lib/OtrRoomState';
import { t } from '../../app/utils/client';
import { onClientBeforeSendMessage } from '../lib/onClientBeforeSendMessage';
import { onClientMessageReceived } from '../lib/onClientMessageReceived';
type NotifyUserData = {
roomId: IRoom['_id'];
userId: IUser['_id'];
};
Meteor.startup(() => {
Tracker.autorun(() => {
if (Meteor.userId()) {
Notifications.onUser('otr', (type: string, data: IOnUserStreamData) => {
Notifications.onUser('otr', (type: string, data: NotifyUserData) => {
if (!data.roomId || !data.userId || data.userId === Meteor.userId()) {
return;
}
const instanceByRoomId = OTR.getInstanceByRoomId(data.roomId);
if (!data.roomId || !data.userId || data.userId === Meteor.userId() || !instanceByRoomId) {
if (!instanceByRoomId) {
return;
}
instanceByRoomId.onUserStream(type, data);
});
}
@ -37,33 +46,32 @@ Meteor.startup(() => {
const instanceByRoomId = OTR.getInstanceByRoomId(message.rid);
if (message.rid && instanceByRoomId && instanceByRoomId.getState() === OtrRoomState.ESTABLISHED) {
if (message.notification) {
if (message?.notification) {
message.msg = t('Encrypted_message');
return message;
}
if (message?.t !== 'otr') {
if (message.t !== 'otr') {
return message;
}
const otrRoom = instanceByRoomId;
const decrypted = await otrRoom.decrypt(message.msg);
const decrypted = await instanceByRoomId.decrypt(message.msg);
if (typeof decrypted === 'string') {
return { ...message, msg: decrypted };
}
const { _id, text: msg, ack, ts, userId }: IOTRDecrypt = decrypted;
const { _id, text: msg, ack, ts, userId } = decrypted;
if (ts) message.ts = ts;
if (message.otrAck) {
const otrAck = await otrRoom.decrypt(message.otrAck);
const otrAck = await instanceByRoomId.decrypt(message.otrAck);
if (typeof otrAck === 'string') {
return { ...message, msg: otrAck };
}
if (ack === otrAck.text) message.t = 'otr-ack';
} else if (userId !== Meteor.userId()) {
const encryptedAck = await otrRoom.encryptText(ack);
const encryptedAck = await instanceByRoomId.encryptText(ack);
Meteor.call('updateOTRAck', _id, encryptedAck);
Meteor.call('updateOTRAck', { message, ack: encryptedAck });
}
return { ...message, _id, msg };

@ -282,6 +282,10 @@ export class NotificationsModule {
this.streamUser.allowWrite(async function (eventName: string, data: unknown) {
const [, e] = eventName.split('/');
if (e === 'otr' && (data === 'handshake' || data === 'acknowledge')) {
const isEnable = await Settings.getValueById('OTR_Enable');
return Boolean(this.userId) && (isEnable === 'true' || isEnable === true);
}
if (e === 'webrtc') {
return true;
}
@ -308,11 +312,15 @@ export class NotificationsModule {
this.streamUser.allowRead(async function (eventName) {
const [userId, e] = eventName.split('/');
if (e === 'otr') {
const isEnable = await Settings.getValueById('OTR_Enable');
return Boolean(this.userId) && this.userId === userId && (isEnable === 'true' || isEnable === true);
}
if (e === 'webrtc') {
return true;
}
return this.userId != null && this.userId === userId;
return Boolean(this.userId) && this.userId === userId;
});
this.streamImporters.allowRead('all');

@ -57,12 +57,11 @@ type OmnichannelTypesValues =
| 'omnichannel_on_hold_chat_resumed';
type OtrMessageTypeValues = 'otr' | 'otr-ack';
type OtrSystemMessages = 'user_joined_otr' | 'user_requested_otr_key_refresh' | 'user_key_refreshed_successfully';
export type MessageTypesValues =
| 'e2e'
| 'otr'
| 'otr-ack'
| 'uj'
| 'ul'
| 'ru'

Loading…
Cancel
Save