fix: Invalid JSON in Custom Translations setting crashes the UI (#28600)

Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com>
pull/28849/head
Matheus Barbosa Silva 3 years ago committed by GitHub
parent 2eb690e68e
commit bc22cfa4c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      apps/meteor/app/lib/server/methods/saveSettings.ts
  2. 1
      apps/meteor/app/lib/server/startup/settings.ts
  3. 10
      apps/meteor/client/lib/utils/applyCustomTranslations.ts
  4. 11
      apps/meteor/client/providers/TranslationProvider.tsx
  5. 4
      apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json

@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { Settings } from '@rocket.chat/models';
import type { ISetting } from '@rocket.chat/core-typings';
import { isSettingCode } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
@ -20,6 +21,15 @@ declare module '@rocket.chat/ui-contexts' {
}
}
const validJSON = Match.Where((value: string) => {
try {
value === '' || JSON.parse(value);
return true;
} catch (_) {
throw new Meteor.Error('Invalid JSON provided');
}
});
Meteor.methods<ServerMethods>({
saveSettings: twoFactorRequired(async function (
params: {
@ -60,6 +70,12 @@ Meteor.methods<ServerMethods>({
case 'multiSelect':
check(value, Array);
break;
case 'code':
check(value, String);
if (isSettingCode(setting) && setting.code === 'application/json') {
check(value, validJSON);
}
break;
default:
check(value, String);
break;

@ -1110,6 +1110,7 @@ void settingsRegistry.addGroup('General', function () {
this.section('Translations', function () {
return this.add('Custom_Translations', '', {
type: 'code',
code: 'application/json',
public: true,
});
});

@ -2,10 +2,18 @@ import { TAPi18n, TAPi18next } from 'meteor/rocketchat:tap-i18n';
import { settings } from '../../../app/settings/client';
const parseToJSON = (customTranslations: string) => {
try {
return JSON.parse(customTranslations);
} catch (e) {
return false;
}
};
export const applyCustomTranslations = (): void => {
const customTranslations: string | undefined = settings.get('Custom_Translations');
if (!customTranslations) {
if (!customTranslations || !parseToJSON(customTranslations)) {
return;
}

@ -19,7 +19,7 @@ type TranslationNamespace = Extract<TranslationKey, `${string}.${string}`> exten
const namespacesDefault = ['core', 'onboarding', 'registration', 'cloud'] as TranslationNamespace[];
const parseToJSON = (customTranslations: string) => {
const parseToJSON = (customTranslations: string): Record<string, Record<string, string>> | false => {
try {
return JSON.parse(customTranslations);
} catch (e) {
@ -98,9 +98,16 @@ const useI18next = (lng: string): typeof i18next => {
return;
}
const parsedCustomTranslations: Record<string, Record<string, string>> = JSON.parse(customTranslations);
const parsedCustomTranslations = parseToJSON(customTranslations);
if (!parsedCustomTranslations) {
return;
}
for (const [ln, translations] of Object.entries(parsedCustomTranslations)) {
if (!translations) {
continue;
}
const namespaces = Object.entries(translations).reduce((acc, [key, value]): Record<string, Record<string, string>> => {
const namespace = key.split('.')[0];

@ -686,7 +686,7 @@
"AutoTranslate_Change_Language_Description": "Changing the auto-translate language does not translate previous messages.",
"AutoTranslate_DeepL": "DeepL",
"AutoTranslate_Enabled": "Enable Auto-Translate",
"AutoTranslate_Enabled_Description": "Enabling auto-translation will allow people with the <code class=\"inline\">auto-translate</code> permission to have all messages automatically translated into their selected language. Fees may apply.",
"AutoTranslate_Enabled_Description": "Enabling auto-translation will allow people with the `auto-translate` permission to have all messages automatically translated into their selected language. Fees may apply.",
"AutoTranslate_Google": "Google",
"AutoTranslate_Microsoft": "Microsoft",
"AutoTranslate_Microsoft_API_Key": "Ocp-Apim-Subscription-Key",
@ -1439,7 +1439,7 @@
"Custom_Sounds": "Custom Sounds",
"Custom_Status": "Custom Status",
"Custom_Translations": "Custom Translations",
"Custom_Translations_Description": "Should be a valid JSON where keys are languages containing a dictionary of key and translations. Example:<br/><code>{\n \"en\": {\n \"Channels\": \"Rooms\"\n },\n \"pt\": {\n \"Channels\": \"Salas\"\n }\n}</code> ",
"Custom_Translations_Description": "Should be a valid JSON where keys are languages containing a dictionary of key and translations. Example: `{\n \"en\": {\n \"Channels\": \"Rooms\"\n },\n \"pt\": {\n \"Channels\": \"Salas\"\n }\n}`",
"Custom_User_Status": "Custom User Status",
"Custom_User_Status_Add": "Add Custom User Status",
"Custom_User_Status_Added_Successfully": "Custom User Status Added Successfully",

Loading…
Cancel
Save