aboutsummaryrefslogtreecommitdiff
path: root/src/main/ipcMain.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/ipcMain.ts')
-rw-r--r--src/main/ipcMain.ts45
1 files changed, 42 insertions, 3 deletions
diff --git a/src/main/ipcMain.ts b/src/main/ipcMain.ts
index d62888c..1dcb17c 100644
--- a/src/main/ipcMain.ts
+++ b/src/main/ipcMain.ts
@@ -24,19 +24,50 @@ import { IpcEvents } from "@utils/IpcEvents";
import { Queue } from "@utils/Queue";
import { BrowserWindow, ipcMain, shell } from "electron";
import { mkdirSync, readFileSync, watch } from "fs";
-import { open, readFile, writeFile } from "fs/promises";
-import { join } from "path";
+import { open, readdir, readFile, writeFile } from "fs/promises";
+import { join, normalize } from "path";
import monacoHtml from "~fileContent/../components/monacoWin.html;base64";
-import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, SETTINGS_DIR, SETTINGS_FILE } from "./utils/constants";
+import { getThemeInfo, stripBOM, UserThemeHeader } from "./themes";
+import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, SETTINGS_DIR, SETTINGS_FILE, THEMES_DIR } from "./utils/constants";
mkdirSync(SETTINGS_DIR, { recursive: true });
+mkdirSync(THEMES_DIR, { recursive: true });
+
+export function ensureSafePath(basePath: string, path: string) {
+ const normalizedBasePath = normalize(basePath);
+ const newPath = join(basePath, path);
+ const normalizedPath = normalize(newPath);
+ return normalizedPath.startsWith(normalizedBasePath) ? normalizedPath : null;
+}
function readCss() {
return readFile(QUICKCSS_PATH, "utf-8").catch(() => "");
}
+async function listThemes(): Promise<UserThemeHeader[]> {
+ const files = await readdir(THEMES_DIR).catch(() => []);
+
+ const themeInfo: UserThemeHeader[] = [];
+
+ for (const fileName of files) {
+ const data = await getThemeData(fileName).then(stripBOM).catch(() => null);
+ if (!data) continue;
+ const parsed = getThemeInfo(data, fileName);
+ themeInfo.push(parsed);
+ }
+
+ return themeInfo;
+}
+
+function getThemeData(fileName: string) {
+ fileName = fileName.replace(/\?v=\d+$/, "");
+ const safePath = ensureSafePath(THEMES_DIR, fileName);
+ if (!safePath) return Promise.reject(`Unsafe path ${fileName}`);
+ return readFile(safePath, "utf-8");
+}
+
export function readSettings() {
try {
return readFileSync(SETTINGS_FILE, "utf-8");
@@ -75,6 +106,10 @@ ipcMain.handle(IpcEvents.SET_QUICK_CSS, (_, css) =>
cssWriteQueue.push(() => writeFile(QUICKCSS_PATH, css))
);
+ipcMain.handle(IpcEvents.GET_THEMES_DIR, () => THEMES_DIR);
+ipcMain.handle(IpcEvents.GET_THEMES_LIST, () => listThemes());
+ipcMain.handle(IpcEvents.GET_THEME_DATA, (_, fileName) => getThemeData(fileName));
+
ipcMain.handle(IpcEvents.GET_SETTINGS_DIR, () => SETTINGS_DIR);
ipcMain.on(IpcEvents.GET_SETTINGS, e => e.returnValue = readSettings());
@@ -90,6 +125,10 @@ export function initIpc(mainWindow: BrowserWindow) {
mainWindow.webContents.postMessage(IpcEvents.QUICK_CSS_UPDATE, await readCss());
}, 50));
});
+
+ watch(THEMES_DIR, { persistent: false }, debounce(() => {
+ mainWindow.webContents.postMessage(IpcEvents.THEME_UPDATE, void 0);
+ }));
}
ipcMain.handle(IpcEvents.OPEN_MONACO_EDITOR, async () => {