Improve loading of JSON files to avoid implicit behaviours of Node require (#1519)

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
Michael Telatynski 2024-02-19 15:22:40 +00:00 committed by GitHub
parent 742aeb32a3
commit 760099e226
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 24 additions and 5 deletions

View file

@ -41,6 +41,7 @@ import { getProfileFromDeeplink, protocolInit } from "./protocol";
import { _t, AppLocalization } from "./language-helper";
import { setDisplayMediaCallback } from "./displayMediaCallback";
import { setupMacosTitleBar } from "./macos-titlebar";
import { loadJsonFile } from "./utils";
const argv = minimist(process.argv, {
alias: { help: "h" },
@ -143,8 +144,7 @@ async function loadConfig(): Promise<void> {
const asarPath = await getAsarPath();
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
global.vectorConfig = require(asarPath + "config.json");
global.vectorConfig = loadJsonFile(asarPath, "config.json");
} catch (e) {
// it would be nice to check the error code here and bail if the config
// is unparsable, but we get MODULE_NOT_FOUND in the case of a missing
@ -155,8 +155,7 @@ async function loadConfig(): Promise<void> {
try {
// Load local config and use it to override values from the one baked with the build
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localConfig = require(path.join(app.getPath("userData"), "config.json"));
const localConfig = loadJsonFile(app.getPath("userData"), "config.json");
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers

View file

@ -19,6 +19,7 @@ import { TranslationKey as TKey } from "matrix-web-i18n";
import type Store from "electron-store";
import type EN from "./i18n/strings/en_EN.json";
import { loadJsonFile } from "./utils";
const FALLBACK_LOCALE = "en";
@ -105,7 +106,7 @@ export class AppLocalization {
public fetchTranslationJson(locale: string): Record<string, string> {
try {
console.log("Fetching translation json for locale: " + locale);
return require(`./i18n/strings/${this.denormalize(locale)}.json`);
return loadJsonFile(`./i18n/strings/${this.denormalize(locale)}.json`);
} catch (e) {
console.log(`Could not fetch translation json for locale: '${locale}'`, e);
return {};

View file

@ -15,6 +15,8 @@ limitations under the License.
*/
import crypto from "crypto";
import fs from "node:fs";
import path from "node:path";
export async function randomArray(size: number): Promise<string> {
return new Promise((resolve, reject) => {
@ -27,3 +29,20 @@ export async function randomArray(size: number): Promise<string> {
});
});
}
type JsonValue = null | string | number;
type JsonArray = Array<JsonValue | JsonObject | JsonArray>;
interface JsonObject {
[key: string]: JsonObject | JsonArray | JsonValue;
}
type Json = JsonArray | JsonObject;
/**
* Synchronously load a JSON file from the local filesystem.
* Unlike `require`, will never execute any javascript in a loaded file.
* @param paths - An array of path segments which will be joined using the system's path delimiter.
*/
export function loadJsonFile<T extends Json>(...paths: string[]): T {
const file = fs.readFileSync(path.join(...paths), { encoding: "utf-8" });
return JSON.parse(file);
}