Veröffentlichte Quellen
Quellen als ZIP herunterladen
CH-J Tools
Durchsuchen Sie Verzeichnisse und Dateien einer bestimmten Anwendungsausgabe.
CH-J / Server Manager
406 Dateien
core-20261024T135205Z-7c487d719de2
Hinzugefügt: · Erstellt:
1
"use strict";3
const fs = require("node:fs");4
const path = require("node:path");5
const { atomicWriteJson } = require("../storage/atomicFile");7
const SUPPORTED_LANGUAGES = Object.freeze(["cs", "de", "en"]);8
const CATALOG_CHANNELS = Object.freeze(["alpha", "beta", "stable", "all"]);9
// Left navigation: mode (full = icon + text, compact = icons, split = icons in two columns), hidden flag kept10
// separately so the menu button restores the last mode, and the user-resized width of the full mode.11
const SIDEBAR_MODES = Object.freeze(["full", "compact", "split"]);12
const SIDEBAR_WIDTH = Object.freeze({ min: 220, max: 420, default: 248 });14
const DEFAULT_CONFIG = Object.freeze({15
schemaVersion: 1,16
ui: {17
language: "cs",18
theme: "dark",19
navigationOrder: [],20
sidebar: { mode: "full", hidden: false, width: SIDEBAR_WIDTH.default }21
},22
updates: {23
channel: "beta",24
autoCheck: true,25
lastLaunchedRelease: null,26
baseUrls: [27
"https://sm.ch-j.de/"28
]29
},30
plugins: {31
channel: "alpha",32
display: {}33
},34
security: { autoLockMinutes: 0, lockOnBlur: false, requireSystemAuthentication: false }35
});37
function clone(value) {38
return JSON.parse(JSON.stringify(value));39
}41
function normalizeReleaseMarker(value) {42
if (!value || typeof value !== "object" || Array.isArray(value)) return null;43
const id = String(value.id || "").trim();44
const version = String(value.version || "").trim();45
const publishedAt = String(value.publishedAt || "").trim();46
const sha512 = String(value.sha512 || "").trim().toLowerCase();47
if (!id || !version || Number.isNaN(Date.parse(publishedAt)) || !/^[a-f0-9]{128}$/.test(sha512)) return null;48
return { id, version, publishedAt, sha512 };49
}51
function normalizeSidebar(input) {52
const source = input && typeof input === "object" ? input : {};53
const width = Number(source.width);54
return {55
mode: SIDEBAR_MODES.includes(source.mode) ? source.mode : "full",56
hidden: source.hidden === true,57
width: Number.isFinite(width) ? Math.round(Math.min(SIDEBAR_WIDTH.max, Math.max(SIDEBAR_WIDTH.min, width))) : SIDEBAR_WIDTH.default58
};59
}61
function normalizeConfig(input = {}) {62
const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};63
const channel = CATALOG_CHANNELS.includes(source.updates?.channel)64
? source.updates.channel65
: DEFAULT_CONFIG.updates.channel;66
const pluginChannel = CATALOG_CHANNELS.includes(source.plugins?.channel)67
? source.plugins.channel68
: DEFAULT_CONFIG.plugins.channel;69
const theme = ["system", "dark", "light"].includes(source.ui?.theme)70
? source.ui.theme71
: DEFAULT_CONFIG.ui.theme;72
const language = SUPPORTED_LANGUAGES.includes(String(source.ui?.language || ""))73
? String(source.ui.language)74
: DEFAULT_CONFIG.ui.language;76
return {77
schemaVersion: 1,78
ui: { language, theme, sidebar: normalizeSidebar(source.ui?.sidebar), navigationOrder: Array.isArray(source.ui?.navigationOrder) ? [...new Set(source.ui.navigationOrder.filter((id) => typeof id === "string" && /^(overview|terminal|profiles|updates|plugins|diagnostics|settings|plugin:[a-z0-9][a-z0-9.-]{2,63})$/.test(id)))].slice(0, 200) : [] },79
updates: {80
channel,81
autoCheck: source.updates?.autoCheck !== false,82
lastLaunchedRelease: normalizeReleaseMarker(source.updates?.lastLaunchedRelease),83
baseUrls: clone(DEFAULT_CONFIG.updates.baseUrls)84
},85
plugins: { channel: pluginChannel, display: Object.fromEntries(Object.entries(source.plugins?.display && typeof source.plugins.display === "object" && !Array.isArray(source.plugins.display) ? source.plugins.display : {}).filter(([id, mode]) => /^[a-z0-9][a-z0-9.-]{2,63}$/.test(id) && ["hidden", "visible", "navigation"].includes(mode))) },86
security: {87
autoLockMinutes: [0, 1, 5, 10, 15, 30, 60].includes(source.security?.autoLockMinutes) ? source.security.autoLockMinutes : 0,88
lockOnBlur: source.security?.lockOnBlur === true,89
requireSystemAuthentication: source.security?.requireSystemAuthentication === true90
}91
};92
}94
class ConfigStore {95
constructor(rootDir) {96
this.rootDir = rootDir;97
this.filePath = path.join(rootDir, "config", "config.json");98
this.value = clone(DEFAULT_CONFIG);99
}101
load() {102
try {103
const raw = fs.readFileSync(this.filePath, "utf8");104
this.value = normalizeConfig(JSON.parse(raw));105
} catch (error) {106
if (error?.code !== "ENOENT") {107
const backup = `${this.filePath}.invalid-${Date.now()}`;108
try { fs.renameSync(this.filePath, backup); } catch {}109
}110
this.value = clone(DEFAULT_CONFIG);111
this.save();112
}113
return this.get();114
}116
get() {117
return clone(this.value);118
}120
update(patch = {}) {121
const updatePatch = patch.updates && typeof patch.updates === "object" ? patch.updates : {};122
const next = {123
...this.value,124
ui: { ...this.value.ui, ...(patch.ui || {}), sidebar: { ...this.value.ui.sidebar, ...(patch.ui?.sidebar || {}) } },125
updates: {126
...this.value.updates,127
channel: updatePatch.channel ?? this.value.updates.channel,128
autoCheck: updatePatch.autoCheck ?? this.value.updates.autoCheck129
},130
plugins: { ...this.value.plugins, ...(patch.plugins || {}) },131
security: { ...this.value.security, ...(patch.security || {}) }132
};133
this.value = normalizeConfig(next);134
this.save();135
return this.get();136
}138
recordLaunchedRelease(release) {139
const marker = normalizeReleaseMarker(release);140
if (!marker) throw new Error("Invalid launched update release metadata.");141
this.value = normalizeConfig({142
...this.value,143
updates: { ...this.value.updates, lastLaunchedRelease: marker }144
});145
this.save();146
return clone(marker);147
}149
save() {150
atomicWriteJson(this.filePath, this.value);151
}152
}154
module.exports = {155
SIDEBAR_MODES,156
SIDEBAR_WIDTH,157
ConfigStore,158
CATALOG_CHANNELS,159
DEFAULT_CONFIG,160
SUPPORTED_LANGUAGES,161
normalizeReleaseMarker,162
normalizeConfig163
};SHA-256
99e100e7d7459d0e8bad691c217d0ee46acd97e5765448edd3a5ec76feddb9f5CH-J Proprietary Software License 1.14 · Die Quellen werden unter der CH-J Proprietary Software License 1.14 bereitgestellt. Ihre Verfügbarkeit ändert die Lizenzbedingungen nicht und gewährt keine zusätzlichen Rechte.
SHA-256 des Archivs
476ed8aef0f1e96a5acdf223127b6692acdf4492eeaf5d0816b6e2a634fbbda6