mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
fix: keep global settings out of non-admin data exports (GHSA-v3vp-ffww-q7pw)
This commit is contained in:
1 parent
8a45d952fd
commit
740d2adaf3
3 files changed
+59
-13
No files matched your search
@@ -81,6 +81,10 @@ import {
|
||||
} from "./repositories/factory.js";
|
||||
import { withCurrentSqliteForeignKeysDisabled } from "./repositories/sqlite-foreign-keys.js";
|
||||
import { applyPluginHostImportSettings } from "./routes/host-plugin-settings.js";
|
||||
import {
|
||||
selectExportableSettings,
|
||||
type SettingData,
|
||||
} from "../utils/export-settings.js";
|
||||
import {
|
||||
keepUsableProtocolCredentials,
|
||||
listProtocolLogins,
|
||||
@@ -107,19 +111,9 @@ const requireAdmin = authManager.createAdminMiddleware();
|
||||
app.use(createCompressionMiddleware());
|
||||
app.use(createCorsMiddleware());
|
||||
|
||||
type SettingData = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
function shouldExportSetting(key: string): boolean {
|
||||
return !key.startsWith("reset_code_") && !key.startsWith("temp_reset_token_");
|
||||
}
|
||||
|
||||
async function getExportableSettings(): Promise<SettingData[]> {
|
||||
async function getExportableSettings(isAdmin: boolean): Promise<SettingData[]> {
|
||||
const settingsRows = await createCurrentSettingsRepository().listAll();
|
||||
|
||||
return settingsRows.filter((setting) => shouldExportSetting(setting.key));
|
||||
return selectExportableSettings(settingsRows, isAdmin);
|
||||
}
|
||||
|
||||
function writeSettingsToExportDatabase(
|
||||
@@ -1047,7 +1041,10 @@ app.post("/database/export", authenticateJWT, async (req, res) => {
|
||||
);
|
||||
}
|
||||
|
||||
writeSettingsToExportDatabase(exportDb, await getExportableSettings());
|
||||
writeSettingsToExportDatabase(
|
||||
exportDb,
|
||||
await getExportableSettings(!!user.isAdmin),
|
||||
);
|
||||
await writeHostDefaultsToExport(exportDb, userId);
|
||||
} finally {
|
||||
exportDb.close();
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { selectExportableSettings } from "../../utils/export-settings.js";
|
||||
|
||||
const rows = [
|
||||
{ key: "allow_registration", value: "true" },
|
||||
{ key: "audit_log_forward_token", value: "secret" },
|
||||
{ key: "reset_code_alice", value: "123456" },
|
||||
{ key: "temp_reset_token_alice", value: "abc" },
|
||||
{ key: "user_dek_v3_u1", value: "{}" },
|
||||
];
|
||||
|
||||
describe("selectExportableSettings", () => {
|
||||
it("gives a non-admin export no global settings", () => {
|
||||
expect(selectExportableSettings(rows, false)).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps instance config for admins but drops secrets", () => {
|
||||
expect(selectExportableSettings(rows, true).map((r) => r.key)).toEqual([
|
||||
"allow_registration",
|
||||
"user_dek_v3_u1",
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
export type SettingData = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
const SECRET_SETTING_PREFIXES = [
|
||||
"reset_code_",
|
||||
"temp_reset_token_",
|
||||
"audit_log_forward_token",
|
||||
];
|
||||
|
||||
/**
|
||||
* Global settings are instance config, not user data: only an admin's export
|
||||
* carries them (import only applies them for admins anyway), and never the
|
||||
* one-time reset codes or the audit forwarding token.
|
||||
*/
|
||||
export function selectExportableSettings(
|
||||
rows: SettingData[],
|
||||
isAdmin: boolean,
|
||||
): SettingData[] {
|
||||
if (!isAdmin) return [];
|
||||
return rows.filter(
|
||||
(row) =>
|
||||
!SECRET_SETTING_PREFIXES.some((prefix) => row.key.startsWith(prefix)),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user