Skip to content

Commit

Permalink
Merge branch 'develop' into chore/app-metadata-typography-marketplace
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] committed Jan 16, 2023
2 parents 79fd6c9 + c420e99 commit 5189862
Show file tree
Hide file tree
Showing 61 changed files with 1,405 additions and 315 deletions.
7 changes: 1 addition & 6 deletions .vscode/settings.json
Expand Up @@ -14,10 +14,5 @@
}
],
"typescript.tsdk": "./node_modules/typescript/lib",
"cSpell.words": [
"livechat",
"omnichannel",
"photoswipe",
"tmid"
]
"cSpell.words": ["katex", "livechat", "omnichannel", "photoswipe", "tmid"]
}
35 changes: 35 additions & 0 deletions apps/meteor/app/api/server/v1/e2e.ts
Expand Up @@ -8,6 +8,7 @@ import {
import type { IUser } from '@rocket.chat/core-typings';

import { API } from '../api';
import { handleSuggestedGroupKey } from '../../../e2e/server/functions/handleSuggestedGroupKey';

API.v1.addRoute(
'e2e.fetchMyKeys',
Expand Down Expand Up @@ -195,3 +196,37 @@ API.v1.addRoute(
},
},
);

API.v1.addRoute(
'e2e.acceptSuggestedGroupKey',
{
authRequired: true,
validateParams: ise2eGetUsersOfRoomWithoutKeyParamsGET,
},
{
async post() {
const { rid } = this.bodyParams;

await handleSuggestedGroupKey('accept', rid, this.userId, 'e2e.acceptSuggestedGroupKey');

return API.v1.success();
},
},
);

API.v1.addRoute(
'e2e.rejectSuggestedGroupKey',
{
authRequired: true,
validateParams: ise2eGetUsersOfRoomWithoutKeyParamsGET,
},
{
async post() {
const { rid } = this.bodyParams;

await handleSuggestedGroupKey('reject', rid, this.userId, 'e2e.rejectSuggestedGroupKey');

return API.v1.success();
},
},
);
33 changes: 24 additions & 9 deletions apps/meteor/app/autotranslate/client/lib/actionButton.ts
@@ -1,13 +1,16 @@
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { isTranslatedMessage } from '@rocket.chat/core-typings';

import { AutoTranslate } from './autotranslate';
import { settings } from '../../../settings/client';
import { hasAtLeastOnePermission } from '../../../authorization/client';
import { MessageAction } from '../../../ui-utils/client/lib/MessageAction';
import { messageArgs } from '../../../../client/lib/utils/messageArgs';
import { Messages } from '../../../models/client';
import {
hasTranslationLanguageInAttachments,
hasTranslationLanguageInMessage,
} from '../../../../client/views/room/MessageList/lib/autoTranslate';

Meteor.startup(() => {
AutoTranslate.init();
Expand All @@ -22,21 +25,27 @@ Meteor.startup(() => {
action(_, props) {
const { message = messageArgs(this).msg } = props;
const language = AutoTranslate.getLanguage(message.rid);
if (!isTranslatedMessage(message) || !message.translations[language]) {
// } && !_.find(message.attachments, attachment => { return attachment.translations && attachment.translations[language]; })) {
if (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)) {
(AutoTranslate.messageIdsToWait as any)[message._id] = true;
Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } });
Meteor.call('autoTranslate.translateMessage', message, language);
}
const action = 'autoTranslateShowInverse' in message ? '$unset' : '$set';
Messages.update({ _id: message._id }, { [action]: { autoTranslateShowInverse: true } });
},
condition({ message, user }) {
condition({ message, subscription, user }) {
if (!user) {
return false;
}
const language = subscription?.autoTranslateLanguage || AutoTranslate.getLanguage(message.rid) || '';

return Boolean(message?.u && message.u._id !== user._id && isTranslatedMessage(message) && message.autoTranslateShowInverse);
return Boolean(
(message?.u &&
message.u._id !== user._id &&
subscription?.autoTranslate &&
(message as { autoTranslateShowInverse?: boolean }).autoTranslateShowInverse) ||
(!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)),
);
},
order: 90,
});
Expand All @@ -48,21 +57,27 @@ Meteor.startup(() => {
action(_, props) {
const { message = messageArgs(this).msg } = props;
const language = AutoTranslate.getLanguage(message.rid);
if (!isTranslatedMessage(message) || !message.translations[language]) {
// } && !_.find(message.attachments, attachment => { return attachment.translations && attachment.translations[language]; })) {
if (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)) {
(AutoTranslate.messageIdsToWait as any)[message._id] = true;
Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } });
Meteor.call('autoTranslate.translateMessage', message, language);
}
const action = 'autoTranslateShowInverse' in message ? '$unset' : '$set';
Messages.update({ _id: message._id }, { [action]: { autoTranslateShowInverse: true } });
},
condition({ message, user }) {
condition({ message, subscription, user }) {
const language = subscription?.autoTranslateLanguage || AutoTranslate.getLanguage(message.rid) || '';
if (!user) {
return false;
}

return Boolean(message?.u && message.u._id !== user._id && isTranslatedMessage(message) && !message.autoTranslateShowInverse);
return Boolean(
message?.u &&
message.u._id !== user._id &&
subscription?.autoTranslate &&
!(message as { autoTranslateShowInverse?: boolean }).autoTranslateShowInverse &&
(hasTranslationLanguageInMessage(message, language) || hasTranslationLanguageInAttachments(message.attachments, language)),
);
},
order: 90,
});
Expand Down
30 changes: 14 additions & 16 deletions apps/meteor/app/autotranslate/client/lib/autotranslate.ts
Expand Up @@ -9,10 +9,15 @@ import type {
IUser,
MessageAttachmentDefault,
} from '@rocket.chat/core-typings';
import { isTranslatedMessageAttachment } from '@rocket.chat/core-typings';

import { Subscriptions, Messages } from '../../../models/client';
import { hasPermission } from '../../../authorization/client';
import { call } from '../../../../client/lib/utils/call';
import {
hasTranslationLanguageInAttachments,
hasTranslationLanguageInMessage,
} from '../../../../client/views/room/MessageList/lib/autoTranslate';

let userLanguage = 'en';
let username = '';
Expand Down Expand Up @@ -55,6 +60,9 @@ export const AutoTranslate = {
language: string,
autoTranslateShowInverse: boolean,
): MessageAttachmentDefault[] {
if (!isTranslatedMessageAttachment(attachments)) {
return attachments;
}
for (const attachment of attachments) {
if (attachment.author_name !== username) {
if (attachment.text && attachment.translations && attachment.translations[language]) {
Expand Down Expand Up @@ -134,16 +142,11 @@ export const createAutoTranslateMessageRenderer = (): ((message: ITranslatedMess
message.translations = {};
}
if (!!subscription?.autoTranslate !== !!message.autoTranslateShowInverse) {
const hasAttachmentsTranslate =
message.attachments?.some(
(attachment) =>
'translations' in attachment &&
typeof attachment.translations === 'object' &&
autoTranslateLanguage in attachment.translations,
) ?? false;

message.translations.original = message.html;
if (message.translations[autoTranslateLanguage] && !hasAttachmentsTranslate) {
if (
message.translations[autoTranslateLanguage] &&
!hasTranslationLanguageInAttachments(message.attachments, autoTranslateLanguage)
) {
message.html = message.translations[autoTranslateLanguage];
}

Expand All @@ -155,12 +158,6 @@ export const createAutoTranslateMessageRenderer = (): ((message: ITranslatedMess
);
}
}
} else if (message.attachments && message.attachments.length > 0) {
message.attachments = AutoTranslate.translateAttachments(
message.attachments,
autoTranslateLanguage,
!!message.autoTranslateShowInverse,
);
}
return message;
};
Expand All @@ -177,7 +174,8 @@ export const createAutoTranslateMessageStreamHandler = (): ((message: ITranslate
subscription &&
subscription.autoTranslate === true &&
message.msg &&
(!message.translations || !message.translations[language])
(!message.translations ||
(!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)))
) {
// || (message.attachments && !_.find(message.attachments, attachment => { return attachment.translations && attachment.translations[language]; }))
Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } });
Expand Down
7 changes: 5 additions & 2 deletions apps/meteor/app/autotranslate/server/autotranslate.ts
Expand Up @@ -305,10 +305,13 @@ export abstract class AutoTranslate {
Meteor.defer(() => {
for (const [index, attachment] of message.attachments?.entries() ?? []) {
if (attachment.description || attachment.text) {
const translations = this._translateAttachmentDescriptions(attachment, targetLanguages);
// Removes the initial link `[ ](quoterl)` from quote message before translation
const translatedText = attachment?.text?.replace(/\[(.*?)\]\(.*?\)/g, '$1') || attachment?.text;
const attachmentMessage = { ...attachment, text: translatedText };
const translations = this._translateAttachmentDescriptions(attachmentMessage, targetLanguages);

if (!_.isEmpty(translations)) {
Messages.addAttachmentTranslations(message._id, index, translations);
Messages.addTranslations(message._id, translations, TranslationProviderRegistry[Provider]);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/app/autotranslate/server/googleTranslate.ts
Expand Up @@ -146,6 +146,7 @@ class GoogleAutoTranslate extends AutoTranslate {
params: {
key: this.apiKey,
target: language,
format: 'text',
},
query,
});
Expand Down Expand Up @@ -190,6 +191,7 @@ class GoogleAutoTranslate extends AutoTranslate {
params: {
key: this.apiKey,
target: language,
format: 'text',
},
query,
});
Expand Down
8 changes: 6 additions & 2 deletions apps/meteor/app/e2e/client/rocketchat.e2e.room.js
Expand Up @@ -264,7 +264,8 @@ export class E2ERoom extends Emitter {
const decryptedKey = await decryptRSA(e2e.privateKey, groupKey);
this.sessionKeyExportedString = toString(decryptedKey);
} catch (error) {
return this.error('Error decrypting group key: ', error);
this.error('Error decrypting group key: ', error);
return false;
}

this.keyID = Base64.encode(this.sessionKeyExportedString).slice(0, 12);
Expand All @@ -275,8 +276,11 @@ export class E2ERoom extends Emitter {
// Key has been obtained. E2E is now in session.
this.groupSessionKey = key;
} catch (error) {
return this.error('Error importing group key: ', error);
this.error('Error importing group key: ', error);
return false;
}

return true;
}

async createGroupKey() {
Expand Down
12 changes: 12 additions & 0 deletions apps/meteor/app/e2e/client/rocketchat.e2e.ts
Expand Up @@ -136,6 +136,18 @@ class E2E extends Emitter {
});
}

async acceptSuggestedKey(rid: string): Promise<void> {
await APIClient.post('/v1/e2e.acceptSuggestedGroupKey', {
rid,
});
}

async rejectSuggestedKey(rid: string): Promise<void> {
await APIClient.post('/v1/e2e.rejectSuggestedGroupKey', {
rid,
});
}

getKeysFromLocalStorage(): KeyPair {
return {
public_key: Meteor._localStorage.getItem('public_key'),
Expand Down
29 changes: 29 additions & 0 deletions apps/meteor/app/e2e/server/functions/handleSuggestedGroupKey.ts
@@ -0,0 +1,29 @@
import { Meteor } from 'meteor/meteor';
import { Subscriptions } from '@rocket.chat/models';

export async function handleSuggestedGroupKey(
handle: 'accept' | 'reject',
rid: string,
userId: string | null,
method: string,
): Promise<void> {
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method });
}

const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId);
if (!sub) {
throw new Meteor.Error('error-subscription-not-found', 'Subscription not found', { method });
}

const suggestedKey = String(sub.E2ESuggestedKey ?? '').trim();
if (!suggestedKey) {
throw new Meteor.Error('error-no-suggested-key-available', 'No suggested key available', { method });
}

if (handle === 'accept') {
await Subscriptions.setGroupE2EKey(sub._id, suggestedKey);
}

await Subscriptions.unsetGroupE2ESuggestedKey(sub._id);
}
17 changes: 0 additions & 17 deletions apps/meteor/app/e2e/server/methods/updateGroupKey.js

This file was deleted.

27 changes: 27 additions & 0 deletions apps/meteor/app/e2e/server/methods/updateGroupKey.ts
@@ -0,0 +1,27 @@
import { Meteor } from 'meteor/meteor';
import { Subscriptions } from '@rocket.chat/models';

Meteor.methods({
async 'e2e.updateGroupKey'(rid, uid, key) {
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'e2e.acceptSuggestedGroupKey' });
}

// I have a subscription to this room
const mySub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId);

if (mySub) {
// Setting the key to myself, can set directly to the final field
if (userId === uid) {
return Subscriptions.setGroupE2EKey(mySub._id, key);
}

// uid also has subscription to this room
const userSub = await Subscriptions.findOneByRoomIdAndUserId(rid, uid);
if (userSub) {
return Subscriptions.setGroupE2ESuggestedKey(userSub._id, key);
}
}
},
});
7 changes: 0 additions & 7 deletions apps/meteor/app/models/server/models/Subscriptions.js
Expand Up @@ -347,13 +347,6 @@ export class Subscriptions extends Base {
return this.find(query, options);
}

updateGroupE2EKey(_id, key) {
const query = { _id };
const update = { $set: { E2EKey: key } };
this.update(query, update);
return this.findOne({ _id });
}

/**
* @param {IRole['_id'][]} roles
* @param {string} scope the value for the role scope (room id)
Expand Down
1 change: 0 additions & 1 deletion apps/meteor/app/ui-message/client/message.html
Expand Up @@ -55,7 +55,6 @@
{{#if showTranslated}}
<span class="translated">
<i class="icon-language {{#if msg.autoTranslateFetching}}loading{{/if}}" title="{{_ "Translated"}}"></i>
<span class="translation-provider">{{ translationProvider }}</span>
</span>
{{/if}}
{{#if msg.sentByEmail}}
Expand Down

0 comments on commit 5189862

Please sign in to comment.