CH-J Server Managergestione server su SSH
Menu
Sorgente pubblicata

CH-J Server Manager

Sfoglia directory e file per una specifica release di applicazioni.

Scarica sorgente ZIP
CH-J / Server Manager 196 file
core-20261013T133631Z-faa4ab45100e Aggiunto: Data non registrata · Costruito:
File
configStore.js Aggiunto: Data non registrata 4,4 KB · 145 righe
Scarica file
1"use strict";
3const fs = require("node:fs");
4const path = require("node:path");
5const { atomicWriteJson } = require("../storage/atomicFile");
7const SUPPORTED_LANGUAGES = Object.freeze(["cs", "de", "en"]);
8const CATALOG_CHANNELS = Object.freeze(["alpha", "beta", "stable", "all"]);
10const DEFAULT_CONFIG = Object.freeze({
11 schemaVersion: 1,
12 ui: {
13 language: "cs",
14 theme: "system"
15 },
16 updates: {
17 channel: "alpha",
18 autoCheck: true,
19 lastLaunchedRelease: null,
20 baseUrls: [
21 "https://www.sm.ch-j.de/",
22 "https://sm.ch-j.de/"
23 ]
24 },
25 plugins: {
26 channel: "alpha"
27 },
28 security: { autoLockMinutes: 0, lockOnBlur: false, requireSystemAuthentication: false }
29});
31function clone(value) {
32 return JSON.parse(JSON.stringify(value));
35function normalizeReleaseMarker(value) {
36 if (!value || typeof value !== "object" || Array.isArray(value)) return null;
37 const id = String(value.id || "").trim();
38 const version = String(value.version || "").trim();
39 const publishedAt = String(value.publishedAt || "").trim();
40 const sha512 = String(value.sha512 || "").trim().toLowerCase();
41 if (!id || !version || Number.isNaN(Date.parse(publishedAt)) || !/^[a-f0-9]{128}$/.test(sha512)) return null;
42 return { id, version, publishedAt, sha512 };
45function normalizeConfig(input = {}) {
46 const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};
47 const channel = CATALOG_CHANNELS.includes(source.updates?.channel)
48 ? source.updates.channel
49 : DEFAULT_CONFIG.updates.channel;
50 const pluginChannel = CATALOG_CHANNELS.includes(source.plugins?.channel)
51 ? source.plugins.channel
52 : DEFAULT_CONFIG.plugins.channel;
53 const theme = ["system", "dark", "light"].includes(source.ui?.theme)
54 ? source.ui.theme
55 : DEFAULT_CONFIG.ui.theme;
56 const language = SUPPORTED_LANGUAGES.includes(String(source.ui?.language || ""))
57 ? String(source.ui.language)
58 : DEFAULT_CONFIG.ui.language;
60 return {
61 schemaVersion: 1,
62 ui: { language, theme },
63 updates: {
64 channel,
65 autoCheck: source.updates?.autoCheck !== false,
66 lastLaunchedRelease: normalizeReleaseMarker(source.updates?.lastLaunchedRelease),
67 baseUrls: clone(DEFAULT_CONFIG.updates.baseUrls)
68 },
69 plugins: { channel: pluginChannel },
70 security: {
71 autoLockMinutes: [0, 1, 5, 10, 15, 30, 60].includes(source.security?.autoLockMinutes) ? source.security.autoLockMinutes : 0,
72 lockOnBlur: source.security?.lockOnBlur === true,
73 requireSystemAuthentication: source.security?.requireSystemAuthentication === true
74 }
75 };
78class ConfigStore {
79 constructor(rootDir) {
80 this.rootDir = rootDir;
81 this.filePath = path.join(rootDir, "config", "config.json");
82 this.value = clone(DEFAULT_CONFIG);
83 }
85 load() {
86 try {
87 const raw = fs.readFileSync(this.filePath, "utf8");
88 this.value = normalizeConfig(JSON.parse(raw));
89 } catch (error) {
90 if (error?.code !== "ENOENT") {
91 const backup = `${this.filePath}.invalid-${Date.now()}`;
92 try { fs.renameSync(this.filePath, backup); } catch {}
93 }
94 this.value = clone(DEFAULT_CONFIG);
95 this.save();
96 }
97 return this.get();
98 }
100 get() {
101 return clone(this.value);
102 }
104 update(patch = {}) {
105 const updatePatch = patch.updates && typeof patch.updates === "object" ? patch.updates : {};
106 const next = {
107 ...this.value,
108 ui: { ...this.value.ui, ...(patch.ui || {}) },
109 updates: {
110 ...this.value.updates,
111 channel: updatePatch.channel ?? this.value.updates.channel,
112 autoCheck: updatePatch.autoCheck ?? this.value.updates.autoCheck
113 },
114 plugins: { ...this.value.plugins, ...(patch.plugins || {}) },
115 security: { ...this.value.security, ...(patch.security || {}) }
116 };
117 this.value = normalizeConfig(next);
118 this.save();
119 return this.get();
120 }
122 recordLaunchedRelease(release) {
123 const marker = normalizeReleaseMarker(release);
124 if (!marker) throw new Error("Invalid launched update release metadata.");
125 this.value = normalizeConfig({
126 ...this.value,
127 updates: { ...this.value.updates, lastLaunchedRelease: marker }
128 });
129 this.save();
130 return clone(marker);
131 }
133 save() {
134 atomicWriteJson(this.filePath, this.value);
135 }
138module.exports = {
139 ConfigStore,
140 CATALOG_CHANNELS,
141 DEFAULT_CONFIG,
142 SUPPORTED_LANGUAGES,
143 normalizeReleaseMarker,
144 normalizeConfig
145};
SHA-256ef3ed13e02e6f67b19cdd3c7d417dcb17d779acad4ded7aec1b8d312349edc1e

CH-J Proprietary Software License 1.14 · La sorgente è fornita sotto CH-J Proprietary Software License 1.14. La sua disponibilità non modifica i termini di licenza o concede diritti aggiuntivi.

Archivio SHA-256de757268dbc4f0226549f8b4f41f9b7e585c856ee97fa0d43b17a0e95c281449