Objavljen izvor
Preuzmi ZIP izvora
CH-J Server Manager
Pregledaj direktorije i datoteke za određeni programski izdanje.
CH-J / Server Manager
377 datoteke
core-20261019T111616Z-160a00bfcddc
Dodano: · Izgrađeno:
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"]);10
const DEFAULT_CONFIG = Object.freeze({11
schemaVersion: 1,12
ui: {13
language: "cs",14
theme: "dark",15
navigationOrder: []16
},17
updates: {18
channel: "alpha",19
autoCheck: true,20
lastLaunchedRelease: null,21
baseUrls: [22
"https://sm.ch-j.de/"23
]24
},25
plugins: {26
channel: "alpha",27
display: {}28
},29
security: { autoLockMinutes: 0, lockOnBlur: false, requireSystemAuthentication: false }30
});32
function clone(value) {33
return JSON.parse(JSON.stringify(value));34
}36
function normalizeReleaseMarker(value) {37
if (!value || typeof value !== "object" || Array.isArray(value)) return null;38
const id = String(value.id || "").trim();39
const version = String(value.version || "").trim();40
const publishedAt = String(value.publishedAt || "").trim();41
const sha512 = String(value.sha512 || "").trim().toLowerCase();42
if (!id || !version || Number.isNaN(Date.parse(publishedAt)) || !/^[a-f0-9]{128}$/.test(sha512)) return null;43
return { id, version, publishedAt, sha512 };44
}46
function normalizeConfig(input = {}) {47
const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};48
const channel = CATALOG_CHANNELS.includes(source.updates?.channel)49
? source.updates.channel50
: DEFAULT_CONFIG.updates.channel;51
const pluginChannel = CATALOG_CHANNELS.includes(source.plugins?.channel)52
? source.plugins.channel53
: DEFAULT_CONFIG.plugins.channel;54
const theme = ["system", "dark", "light"].includes(source.ui?.theme)55
? source.ui.theme56
: DEFAULT_CONFIG.ui.theme;57
const language = SUPPORTED_LANGUAGES.includes(String(source.ui?.language || ""))58
? String(source.ui.language)59
: DEFAULT_CONFIG.ui.language;61
return {62
schemaVersion: 1,63
ui: { language, theme, 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) : [] },64
updates: {65
channel,66
autoCheck: source.updates?.autoCheck !== false,67
lastLaunchedRelease: normalizeReleaseMarker(source.updates?.lastLaunchedRelease),68
baseUrls: clone(DEFAULT_CONFIG.updates.baseUrls)69
},70
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))) },71
security: {72
autoLockMinutes: [0, 1, 5, 10, 15, 30, 60].includes(source.security?.autoLockMinutes) ? source.security.autoLockMinutes : 0,73
lockOnBlur: source.security?.lockOnBlur === true,74
requireSystemAuthentication: source.security?.requireSystemAuthentication === true75
}76
};77
}79
class ConfigStore {80
constructor(rootDir) {81
this.rootDir = rootDir;82
this.filePath = path.join(rootDir, "config", "config.json");83
this.value = clone(DEFAULT_CONFIG);84
}86
load() {87
try {88
const raw = fs.readFileSync(this.filePath, "utf8");89
this.value = normalizeConfig(JSON.parse(raw));90
} catch (error) {91
if (error?.code !== "ENOENT") {92
const backup = `${this.filePath}.invalid-${Date.now()}`;93
try { fs.renameSync(this.filePath, backup); } catch {}94
}95
this.value = clone(DEFAULT_CONFIG);96
this.save();97
}98
return this.get();99
}101
get() {102
return clone(this.value);103
}105
update(patch = {}) {106
const updatePatch = patch.updates && typeof patch.updates === "object" ? patch.updates : {};107
const next = {108
...this.value,109
ui: { ...this.value.ui, ...(patch.ui || {}) },110
updates: {111
...this.value.updates,112
channel: updatePatch.channel ?? this.value.updates.channel,113
autoCheck: updatePatch.autoCheck ?? this.value.updates.autoCheck114
},115
plugins: { ...this.value.plugins, ...(patch.plugins || {}) },116
security: { ...this.value.security, ...(patch.security || {}) }117
};118
this.value = normalizeConfig(next);119
this.save();120
return this.get();121
}123
recordLaunchedRelease(release) {124
const marker = normalizeReleaseMarker(release);125
if (!marker) throw new Error("Invalid launched update release metadata.");126
this.value = normalizeConfig({127
...this.value,128
updates: { ...this.value.updates, lastLaunchedRelease: marker }129
});130
this.save();131
return clone(marker);132
}134
save() {135
atomicWriteJson(this.filePath, this.value);136
}137
}139
module.exports = {140
ConfigStore,141
CATALOG_CHANNELS,142
DEFAULT_CONFIG,143
SUPPORTED_LANGUAGES,144
normalizeReleaseMarker,145
normalizeConfig146
};SHA-256
c5b49d76b57f817af19928a45c27facb98282e5e606429b1a616ec0b5c0f3090CH-J Proprietary Software License 1.14 · Izvor je osiguran pod CH-J Proprietary Software License 1.14. Njena dostupnost ne mijenja uvjete licenciranja niti daje dodatna prava.
Arhiv SHA-256
a9605c0870a223b6a8542bb0705edd51d8b04f3069582653417a8397fabcc09a