Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QuickCSS improvements #557

Closed
wants to merge 31 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
243ae14
remove blip from reloading
12944qwerty Aug 31, 2023
a1380df
redesign scrollbar
12944qwerty Aug 31, 2023
1437d03
popout
12944qwerty Sep 20, 2023
268c0c1
use icon files
12944qwerty Sep 20, 2023
609468b
sticky popout
12944qwerty Sep 20, 2023
a1a96b9
lint
12944qwerty Sep 20, 2023
389d6fd
fix css
12944qwerty Sep 22, 2023
512aea3
fix most changes
12944qwerty Sep 26, 2023
213d62c
lint
12944qwerty Sep 26, 2023
1abd0c4
i18n: update translations from weblate
weblate Sep 22, 2023
8568845
New i18n strings
asportnoy Sep 23, 2023
aba34cc
i18n: update translations from weblate
weblate Sep 23, 2023
1e0c9fe
i18n: update translations from weblate
weblate Sep 24, 2023
fff3b61
i18n: update translations from weblate
weblate Sep 24, 2023
9019fe4
i18n: update translations from weblate
weblate Sep 24, 2023
95e26f4
i18n: update translations from weblate
weblate Sep 25, 2023
9d68216
i18n: update translations from weblate
weblate Sep 25, 2023
933d085
i18n: update translations from weblate
weblate Sep 25, 2023
11c646e
Improve various logs (#561)
EastArctica Sep 25, 2023
12f9209
i18n: update translations from weblate
weblate Sep 26, 2023
7001f41
i18n: update translations from weblate
weblate Sep 26, 2023
7556fbf
i18n: update translations from weblate
weblate Sep 26, 2023
c88cf1a
Package updates (#549)
asportnoy Sep 26, 2023
8f90fff
Fix Discord crash (#562)
asportnoy Sep 27, 2023
0f52589
Security patch (Closes #556)
asportnoy Sep 27, 2023
e815318
4.6.4
asportnoy Sep 27, 2023
7eb26b6
Remove polyfill plugin
asportnoy Sep 27, 2023
0cb58ed
Remove package
asportnoy Sep 27, 2023
21b3f09
4.6.5
asportnoy Sep 27, 2023
cb06d92
Create SECURITY.md
asportnoy Sep 27, 2023
4212258
Update SECURITY.md (#563)
asportnoy Sep 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Security patch (Closes #556)
asportnoy authored and 12944qwerty committed Oct 22, 2024
commit 0f525891926f06461adebd1bb31df3406087809d
2 changes: 1 addition & 1 deletion scripts/build.mts
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ Promise.all([
platform: "node",
target: `node${NODE_VERSION}`,
outfile: "dist/main.js",
external: ["electron"],
external: ["electron", "original-fs"],
}),
// Preload
esbuild.build({
29 changes: 26 additions & 3 deletions src/main/ipc/installer.ts
Original file line number Diff line number Diff line change
@@ -9,11 +9,15 @@ import {
} from "../../types";
import { Octokit } from "@octokit/rest";
import { CONFIG_PATH, CONFIG_PATHS } from "../../util.mjs";
import { readFile, writeFile } from "fs/promises";
import { readFile } from "fs/promises";
import { writeFile as originalWriteFile } from "original-fs";
import fetch from "node-fetch";
import { join } from "path";
import { join, resolve, sep } from "path";
import { AnyAddonManifestOrReplugged, anyAddonOrReplugged } from "src/types/addon";
import { getSetting } from "./settings";
import { promisify } from "util";

const writeFile = promisify(originalWriteFile);

const octokit = new Octokit();

@@ -170,6 +174,13 @@ ipcMain.handle(
query.set("type", update ? "update" : "install");
if (version) query.set("version", version);

if (type === "replugged") {
// Manually set Path and URL for security purposes
path = "replugged.asar";
const apiUrl = await getSetting("dev.replugged.Settings", "apiUrl", "https://replugged.dev");
url = `${apiUrl}/api/v1/store/dev.replugged.Replugged.asar`;
}

let res;
try {
res = await fetch(`${url}?${query}`);
@@ -191,8 +202,20 @@ ipcMain.handle(

const buf = Buffer.from(file);

const base = getBaseName(type);
const filePath = resolve(base, path);
if (!filePath.startsWith(`${base}${sep}`)) {
// Ensure file changes are restricted to the base path
return {
success: false,
error: "Invalid path",
};
}

console.log(url, filePath);

try {
await writeFile(join(getBaseName(type), path), buf);
await writeFile(filePath, buf);
} catch (err) {
return {
success: false,
18 changes: 15 additions & 3 deletions src/main/ipc/plugins.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ IPC events:
*/

import { readFile, readdir, readlink, rm, stat } from "fs/promises";
import { extname, join } from "path";
import { extname, join, sep } from "path";
import { ipcMain, shell } from "electron";
import { RepluggedIpcChannels, type RepluggedPlugin } from "../../types";
import { plugin } from "../../types/addon";
@@ -19,8 +19,14 @@ export const isFileAPlugin = (f: Dirent | Stats, name: string): boolean => {
};

async function getPlugin(pluginName: string): Promise<RepluggedPlugin> {
const manifestPath = join(PLUGINS_DIR, pluginName, "manifest.json");
if (!manifestPath.startsWith(`${PLUGINS_DIR}${sep}`)) {
// Ensure file changes are restricted to the base path
throw new Error("Invalid plugin name");
}

const manifest: unknown = JSON.parse(
await readFile(join(PLUGINS_DIR, pluginName, "manifest.json"), {
await readFile(manifestPath, {
encoding: "utf-8",
}),
);
@@ -85,7 +91,13 @@ ipcMain.handle(RepluggedIpcChannels.LIST_PLUGINS, async (): Promise<RepluggedPlu
});

ipcMain.handle(RepluggedIpcChannels.UNINSTALL_PLUGIN, async (_, pluginName: string) => {
await rm(join(PLUGINS_DIR, pluginName), {
const pluginPath = join(PLUGINS_DIR, pluginName);
if (!pluginPath.startsWith(`${PLUGINS_DIR}${sep}`)) {
// Ensure file changes are restricted to the base path
throw new Error("Invalid plugin name");
}

await rm(pluginPath, {
recursive: true,
force: true,
});
36 changes: 33 additions & 3 deletions src/main/ipc/settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { readFile, writeFile } from "fs/promises";
import { join } from "path";
import { resolve, sep } from "path";
import { ipcMain, shell } from "electron";
import { RepluggedIpcChannels } from "../../types";
import type {
@@ -11,9 +11,20 @@ import { CONFIG_PATHS } from "src/util.mjs";

const SETTINGS_DIR = CONFIG_PATHS.settings;

export function getSettingsPath(namespace: string): string {
const resolved = resolve(SETTINGS_DIR, `${namespace}.json`);
console.log(resolved, SETTINGS_DIR, resolved.startsWith(SETTINGS_DIR));
if (!resolved.startsWith(`${SETTINGS_DIR}${sep}`)) {
// Ensure file changes are restricted to the base path
throw new Error("Invalid namespace");
}
return resolved;
}

async function readSettings(namespace: string): Promise<Map<string, unknown>> {
const path = getSettingsPath(namespace);
try {
const data = await readFile(join(SETTINGS_DIR, `${namespace}.json`), "utf8");
const data = await readFile(path, "utf8");
return new Map(Object.entries(JSON.parse(data)));
} catch {
return new Map();
@@ -22,7 +33,7 @@ async function readSettings(namespace: string): Promise<Map<string, unknown>> {

function writeSettings(namespace: string, settings: SettingsMap): Promise<void> {
return writeFile(
join(SETTINGS_DIR, `${namespace}.json`),
getSettingsPath(namespace),
JSON.stringify(Object.fromEntries(settings.entries()), null, 2),
"utf8",
);
@@ -54,8 +65,27 @@ export async function writeTransaction<T>(
handler: SettingsTransactionHandler<T>,
): Promise<T> {
return transaction(namespace, async () => {
const postHandlerTransform: Array<(settings: SettingsMap) => void | Promise<void>> = [];

const settings = await readSettings(namespace);
if (namespace.toLowerCase() === "dev.replugged.settings") {
// Prevent the "apiUrl" setting from changing
const originalValue = settings.get("apiUrl");
postHandlerTransform.push((settings) => {
if (originalValue) {
settings.set("apiUrl", originalValue);
} else {
settings.delete("apiUrl");
}
});
}

const res = await handler(settings);

for (const transform of postHandlerTransform) {
await transform(settings);
}

await writeSettings(namespace, settings);
return res;
});
18 changes: 15 additions & 3 deletions src/main/ipc/themes.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ IPC events:
*/

import { readFile, readdir, readlink, rm, stat } from "fs/promises";
import { extname, join } from "path";
import { extname, join, sep } from "path";
import { ipcMain, shell } from "electron";
import { RepluggedIpcChannels, type RepluggedTheme } from "../../types";
import { theme } from "../../types/addon";
@@ -19,8 +19,14 @@ export const isFileATheme = (f: Dirent | Stats, name: string): boolean => {
};

async function getTheme(path: string): Promise<RepluggedTheme> {
const manifestPath = join(THEMES_DIR, path, "manifest.json");
if (!manifestPath.startsWith(`${THEMES_DIR}${sep}`)) {
// Ensure file changes are restricted to the base path
throw new Error("Invalid plugin name");
}

const manifest: unknown = JSON.parse(
await readFile(join(THEMES_DIR, path, "manifest.json"), {
await readFile(manifestPath, {
encoding: "utf-8",
}),
);
@@ -72,7 +78,13 @@ ipcMain.handle(RepluggedIpcChannels.LIST_THEMES, async (): Promise<RepluggedThem
});

ipcMain.handle(RepluggedIpcChannels.UNINSTALL_THEME, async (_, themeName: string) => {
await rm(join(THEMES_DIR, themeName), {
const themePath = join(THEMES_DIR, themeName);
if (!themePath.startsWith(`${THEMES_DIR}${sep}`)) {
// Ensure file changes are restricted to the base path
throw new Error("Invalid theme name");
}

await rm(themePath, {
recursive: true,
force: true,
});
1 change: 1 addition & 0 deletions src/renderer/coremods/settings/pages/General.tsx
Original file line number Diff line number Diff line change
@@ -125,6 +125,7 @@ export const General = (): React.ReactElement => {
<TextInput
{...util.useSetting(generalSettings, "apiUrl")}
placeholder="https://replugged.dev"
disabled
/>
</FormItem>