mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 15:45:23 +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";
|
} from "./repositories/factory.js";
|
||||||
import { withCurrentSqliteForeignKeysDisabled } from "./repositories/sqlite-foreign-keys.js";
|
import { withCurrentSqliteForeignKeysDisabled } from "./repositories/sqlite-foreign-keys.js";
|
||||||
import { applyPluginHostImportSettings } from "./routes/host-plugin-settings.js";
|
import { applyPluginHostImportSettings } from "./routes/host-plugin-settings.js";
|
||||||
|
import {
|
||||||
|
selectExportableSettings,
|
||||||
|
type SettingData,
|
||||||
|
} from "../utils/export-settings.js";
|
||||||
import {
|
import {
|
||||||
keepUsableProtocolCredentials,
|
keepUsableProtocolCredentials,
|
||||||
listProtocolLogins,
|
listProtocolLogins,
|
||||||
@@ -107,19 +111,9 @@ const requireAdmin = authManager.createAdminMiddleware();
|
|||||||
app.use(createCompressionMiddleware());
|
app.use(createCompressionMiddleware());
|
||||||
app.use(createCorsMiddleware());
|
app.use(createCorsMiddleware());
|
||||||
|
|
||||||
type SettingData = {
|
async function getExportableSettings(isAdmin: boolean): Promise<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[]> {
|
|
||||||
const settingsRows = await createCurrentSettingsRepository().listAll();
|
const settingsRows = await createCurrentSettingsRepository().listAll();
|
||||||
|
return selectExportableSettings(settingsRows, isAdmin);
|
||||||
return settingsRows.filter((setting) => shouldExportSetting(setting.key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeSettingsToExportDatabase(
|
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);
|
await writeHostDefaultsToExport(exportDb, userId);
|
||||||
} finally {
|
} finally {
|
||||||
exportDb.close();
|
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