Közzétett forrás
Letöltés forrás ZIP
CH-J Server Manager
Könyvtárak és fájlok böngészése egy adott alkalmazás kiadásához.
CH-J / Server Manager
339 fájlok
core-20261014T184258Z-3fbed0b93fdf
Hozzáadva: Nem rögzített dátum · Beépített:
1
"use strict";2
// Offline integration check: production renderer, preload, IPC, vault and bundled plugin runtime.3
const { app, BrowserWindow, ipcMain, protocol, clipboard } = require("electron");4
const assert = require("node:assert/strict");5
const fs = require("node:fs");6
const os = require("node:os");7
const path = require("node:path");8
const { createMainWindow, hardenSession } = require("../src/main/bootstrap/createMainWindow");9
const { registerCoreIpc } = require("../src/main/ipc/registerCoreIpc");10
const { ConfigStore } = require("../src/main/config/configStore");11
const { VaultStore } = require("../src/main/security/vaultStore");12
const { ProfileService } = require("../src/main/profiles/profileService");13
const { PluginRegistry } = require("../src/main/plugins/pluginRegistry");14
const { PluginRuntime } = require("../src/main/plugins/pluginRuntime");15
const { PluginService } = require("../src/main/plugins/pluginService");16
const { LocalHashService } = require("../src/main/hashing/localHashService");17
const { DiagnosticsService } = require("../src/main/diagnostics/diagnosticsService");19
const root = fs.mkdtempSync(path.join(os.tmpdir(), "chj-workspace-ui-"));20
app.setPath("userData", root);21
protocol.registerSchemesAsPrivileged([{ scheme: "chj-plugin", privileges: { standard: true, secure: true, supportFetchAPI: true } }]);22
let window, runtime, diagnostics, config, profiles;23
let nextImport, nextExport;24
const errors = [];25
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));26
const js = (source) => window.webContents.executeJavaScript(source);27
async function until(source, timeout = 10000) {28
const started = Date.now();29
while (Date.now() - started < timeout) { if (await js(`(() => { try { return (${source}); } catch { return false; } })()`)) return; await delay(40); }30
throw new Error(`UI condition timed out: ${source}`);31
}32
async function run() {33
await app.whenReady(); hardenSession();34
config = new ConfigStore(root); config.load(); config.update({ updates: { autoCheck: false } });35
const vault = new VaultStore(root); await vault.create("ui-smoke-password"); profiles = new ProfileService(vault);36
const first = profiles.save({ label: "NGINX", host: "NGINX.lan", username: "nginx", storePassword: true, password: "must-stay-in-vault" });37
profiles.save({ label: "IPv6", host: "2001:db8::10", username: "admin", port: 2222 });38
const registry = new PluginRegistry(root, null, { bundledRoot: path.join(__dirname, "../src/main/firstPartyPlugins") });39
window = createMainWindow();40
const watchErrors = (webContents) => webContents.on("console-message", (event) => { if (event.level === "error") { errors.push(event.message); console.error(event.message); } });41
watchErrors(window.webContents);42
runtime = new PluginRuntime({ BrowserWindow, registry, sessionManager: { list: () => [] }, localHashService: new LocalHashService(),43
logService: { readTail: () => ({ text: "", size: 0, readAt: new Date().toISOString(), truncated: false }) },44
preload: path.join(__dirname, "../src/preload/pluginPreload.js"), getMainWindow: () => window,45
getLanguage: () => config.get().ui.language, isVaultUnlocked: () => vault.status().unlocked });46
runtime.registerIpc(ipcMain);47
const pluginService = new PluginService({ registry, runtime, configStore: config });48
diagnostics = new DiagnosticsService({ storageRoot: root });49
registerCoreIpc({ ipcMain, app, clipboard, configStore: config, vaultStore: vault, profileService: profiles,50
pluginRegistry: registry, pluginService, pluginRuntime: runtime, diagnosticsService: diagnostics,51
biometricService: { requireSensitiveAction: async () => {}, getStatus: () => ({ available: false, enabled: false, code: "BIOMETRIC_UNAVAILABLE" }) },52
updateService: { getState: () => ({ currentVersion: "0.0.1", status: "idle", releases: [] }) }, getMainWindow: () => window,53
dialog: { showOpenDialog: async () => nextImport ? { canceled: false, filePaths: [nextImport] } : { canceled: true, filePaths: [] },54
showSaveDialog: async () => nextExport ? { canceled: false, filePath: nextExport } : { canceled: true } } });55
await until('state.profiles.length === 2 && document.querySelectorAll("#pluginRows .plugin-row").length === 7');56
assert.equal(await js('document.querySelector("#navigationEditToggle").checked'), false);57
assert.equal(await js('document.querySelectorAll(".navigation-controls").length'), 0);58
assert.equal(await js('[...document.querySelectorAll(".navigation-row")].some(row => row.draggable)'), false);59
const dropTerminal = '{ const dataTransfer = new DataTransfer(); dataTransfer.setData("text/chj-navigation", "terminal"); document.querySelector("[data-nav-key=overview]").dispatchEvent(new DragEvent("drop", { dataTransfer, bubbles: true })); }';60
await js(dropTerminal);61
assert.deepEqual(config.get().ui.navigationOrder, []);62
await js('document.querySelector("#navigationEditToggle").click();');63
assert.equal(await js('[...document.querySelectorAll(".navigation-row")].every(row => row.draggable)'), true);64
await js('{ const dataTransfer = new DataTransfer(); document.querySelector("[data-nav-key=terminal]").dispatchEvent(new DragEvent("dragstart", { dataTransfer, bubbles: true })); if (dataTransfer.getData("text/chj-navigation") !== "terminal") throw new Error("Missing drag payload"); document.querySelector("[data-nav-key=overview]").dispatchEvent(new DragEvent("drop", { dataTransfer, bubbles: true })); }');65
await until('document.querySelector("#mainNavigation").firstElementChild.dataset.navKey === "terminal"');66
assert.equal(new ConfigStore(root).load().ui.navigationOrder[0], "terminal");67
await js(`showView('plugins'); document.querySelector('[data-plugin-id="chj.system-monitor"] .plugin-pin').click();`);68
await until(`Boolean(document.querySelector('[data-nav-key="plugin:chj.system-monitor"]'))`);69
await js('{ const dataTransfer = new DataTransfer(); dataTransfer.setData("text/chj-navigation", "plugin:chj.system-monitor"); document.querySelector("[data-nav-key=terminal]").dispatchEvent(new DragEvent("drop", { dataTransfer, bubbles: true })); }');70
await until('document.querySelector("#mainNavigation").firstElementChild.dataset.navKey === "plugin:chj.system-monitor"');71
await js('document.querySelector("#navigationEditToggle").click();');72
await js(dropTerminal);73
assert.equal(await js('document.querySelector("#mainNavigation").firstElementChild.dataset.navKey'), "plugin:chj.system-monitor");74
await js(`document.querySelector('[data-plugin-id="chj.hash-checksum"] .plugin-visibility').click();`);75
await until('!document.querySelector("#hashToolButton") && document.querySelector("#pluginRows .plugin-hidden .button").disabled');76
assert.equal(await js('document.querySelector("#pluginRows .plugin-hidden .plugin-pin").disabled'), true);77
await js(`document.querySelector('[data-plugin-id="chj.hash-checksum"] .plugin-visibility').click();`);78
await until('document.querySelectorAll("#pluginRows .plugin-hidden").length === 0');79
assert.equal(await js('document.querySelectorAll("#pluginRows select").length'), 0);80
assert.equal(await js('document.querySelectorAll("#pluginRows details[open]").length'), 0);81
assert.equal(await js('document.querySelector(".plugin-catalog-disclosure").open'), false);82
await js('document.querySelector("#pluginRows details summary").click();');83
assert.equal(await js('document.querySelector("#pluginRows details").open'), true);84
await js('document.querySelector("#pluginRows details summary").click();');85
// Open every packaged tool through the real sandboxed runtime, without SSH/network access.86
for (const plugin of registry.listInstalled()) {87
runtime.open(plugin.id);88
const pluginWindow = runtime.windows.get(plugin.id); watchErrors(pluginWindow.webContents);89
await new Promise((resolve, reject) => { pluginWindow.webContents.once("did-finish-load", resolve); pluginWindow.webContents.once("did-fail-load", (_e, code, description) => reject(new Error(`${plugin.id}: ${code} ${description}`))); });90
await delay(180);91
assert.equal(pluginWindow.webContents.getLastWebPreferences().nodeIntegration, false);92
assert.equal(pluginWindow.webContents.getLastWebPreferences().sandbox, true);93
assert.equal(await pluginWindow.webContents.executeJavaScript('typeof window.process'), "undefined");94
assert.ok(await pluginWindow.webContents.executeJavaScript('Boolean(window.chjPlugin && document.body.textContent.length > 50)'));95
runtime.close(plugin.id);96
}97
nextImport = path.join(root, "import.json");98
fs.writeFileSync(nextImport, JSON.stringify({ format: "chj-server-profiles", version: 1, servers: [99
{ name: "NGINX import", host: "NGINX.lan", username: "nginx", port: 22, password: "never-import" },100
{ name: "Nový server", host: "192.168.10.100", username: "root", port: 22 }101
] }));102
await js('showView("profiles"); document.querySelector("#importProfilesButton").click();');103
await until('document.querySelector("#profileImportDialog").open');104
assert.equal(profiles.list().length, 2);105
assert.equal(await js('document.querySelectorAll("#profileImportRows tr").length'), 2);106
await js('document.querySelector("#cancelProfileImport").click();');107
assert.equal(profiles.list().length, 2);108
await js('document.querySelector("#importProfilesButton").click();');109
await until('document.querySelector("#profileImportDialog").open');110
await js('document.querySelector("#profileDuplicatePolicy").value = "update"; document.querySelector("#confirmProfileImport").click();');111
await until('!document.querySelector("#profileImportDialog").open && state.profiles.length === 3');112
assert.equal(profiles.getStoredPassword(first.id), null);113
for (const format of ["json", "csv"]) {114
nextExport = path.join(root, `export.${format}`);115
await js(`document.querySelector('#profileExportFormat').value = '${format}'; document.querySelector('#exportProfilesButton').click();`);116
await until('!document.querySelector("#exportProfilesButton").disabled');117
assert.doesNotMatch(fs.readFileSync(nextExport, "utf8"), /must-stay-in-vault|never-import|privateKey|token|password/i);118
assert.match(fs.readFileSync(nextExport, "utf8"), /NGINX\.lan/);119
}120
nextExport = path.join(root, "selected.json");121
await js('document.querySelector("#profileRows input").click(); document.querySelector("#exportSelectedProfiles").checked = true; document.querySelector("#profileExportFormat").value = "json"; document.querySelector("#exportProfilesButton").click();');122
await until('!document.querySelector("#exportProfilesButton").disabled');123
assert.equal(JSON.parse(fs.readFileSync(nextExport, "utf8")).servers.length, 1);124
nextImport = path.join(root, "export.csv");125
await js('document.querySelector("#importProfilesButton").click();');126
await until('document.querySelector("#profileImportDialog").open');127
assert.equal(await js('document.querySelectorAll("#profileImportRows tr").length'), 3);128
await js('document.querySelector("#confirmProfileImport").click();');129
await until('!document.querySelector("#profileImportDialog").open');130
assert.equal(profiles.list().length, 3); // Default skip preserves existing profiles.131
for (const language of ["cs", "de", "en"]) {132
await js(`applyLanguage('${language}')`);133
assert.equal(await js('document.querySelector("#profileImportTitle").textContent.includes("transfer.")'), false);134
}135
await window.webContents.reload();136
await until('document.querySelector("#mainNavigation").firstElementChild.dataset.navKey === "plugin:chj.system-monitor" && state.profiles.length === 3');137
assert.equal(await js('document.querySelector("#navigationEditToggle").checked'), false);138
window.setSize(960, 720);139
for (const view of ["plugins", "profiles"]) {140
await js(`showView('${view}')`); await delay(80);141
assert.equal(await js('document.documentElement.scrollWidth <= window.innerWidth'), true, `${view} must fit the minimum window width`);142
}143
const artifacts = process.env.CHJ_WORKSPACE_SMOKE_ARTIFACT_DIR;144
if (artifacts) {145
fs.mkdirSync(artifacts, { recursive: true }); window.setSize(1240, 900);146
for (const view of ["plugins", "profiles"]) { await js(`showView('${view}')`); await delay(350); fs.writeFileSync(path.join(artifacts, `${view}.png`), (await window.webContents.capturePage()).toPNG()); }147
}148
assert.deepEqual(errors, []);149
console.log("CHJ_WORKSPACE_UI_OK: locked/unlocked mouse reorder/persistence, compact plugin checkboxes, seven bundled sandboxed plugins, hide/show/pin, import preview/cancel/update, secret-free JSON/CSV, selected export, CZ/DE/EN, minimum window width");150
}151
function finish(code) { runtime?.closeAll(); diagnostics?.stopAll(); window?.destroy(); try { fs.rmSync(root, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch {} app.exit(code); }152
run().then(() => finish(0), (error) => { console.error(error); finish(1); });153
setTimeout(() => { console.error("Workspace UI smoke exceeded 60s"); finish(1); }, 60000).unref();SHA-256
b40356a0e29a0033b030f17a50998088823597cbd4bd8c4f419a9554ef67ccc2CH-J Proprietary Software License 1.14 · A forrás a CH-J Proprietary Software License 1.14 alatt található. Rendelkezése nem változtatja meg a licenc feltételeit, és nem ad további jogokat.
Archive SHA-256
3df08cf5e899262a6ce92d7ec2caf5c42b683f1f2b57055662b845ff7dde67a8