CH-J Server Managerمدیریت سرور از طریق SSH
منو
منبع منتشرشده

CH-J Server Manager

پوشه‌ها و فایل‌های یک نسخهٔ مشخص از برنامه را مرور کنید.

دانلود ZIP منبع
CH-J / Server Manager 368 فایل
core-20261017T201717Z-057348c4a70f افزوده‌شده: تاریخ ثبت نشده است · ساخته‌شده:
smokeUsersUiWindows.js افزوده‌شده: تاریخ ثبت نشده است ۹٫۶ KB · 127 خط
کد دانلود فایل
1"use strict";
2// End-to-end UI check of chj.users against an ISOLATED Windows test machine (Windows OpenSSH).
3// Creates and deletes the temporary account "chjui1" and changes sshd_config through CH-J (with restart and
4// rollback guard), then restores the inherited policy. Credentials only from the environment:
5// CHJ_USERS_WINDOWS_HOST, CHJ_USERS_WINDOWS_USER, CHJ_USERS_WINDOWS_PASSWORD, CHJ_USERS_WINDOWS_FINGERPRINT
6// Run: npx electron scripts/smokeUsersUiWindows.js [screenshot-dir]
7const { app, BrowserWindow, ipcMain, protocol } = require("electron");
8const assert = require("node:assert/strict");
9const fs = require("node:fs");
10const os = require("node:os");
11const path = require("node:path");
12const { hardenSession } = require("../src/main/bootstrap/createMainWindow");
13const { PluginRegistry } = require("../src/main/plugins/pluginRegistry");
14const { PluginRuntime } = require("../src/main/plugins/pluginRuntime");
15const { SessionManager } = require("../src/main/sessions/sessionManager");
16const { PrivilegedExecutor } = require("../src/main/sessions/privilegedExec");
17const { UserAdminService, createUserAdminApi } = require("../src/main/users/userAdminService");
18const { WindowsUserAdminService } = require("../src/main/users/windowsUserAdminService");
19const { WindowsExecutor } = require("../src/main/sessions/windowsPrivilegedExec");
20const { detectPlatform } = require("../src/main/sessions/platformDetect");
21const { KeyGeneratorService } = require("../src/main/keys/keyGeneratorService");
23const env = process.env;
24const root = fs.mkdtempSync(path.join(os.tmpdir(), "chj-users-ui-win-"));
25const shots = process.argv.find((arg, index) => index > 1 && !arg.startsWith("-") && !arg.endsWith(".js")) || null;
26app.setPath("userData", root);
27protocol.registerSchemesAsPrivileged([{ scheme: "chj-plugin", privileges: { standard: true, secure: true, supportFetchAPI: true } }]);
28const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
29const errors = [];
30let window;
31const js = (source) => window.webContents.executeJavaScript(source);
32async function until(source, timeout = 60000) {
33 const started = Date.now();
34 while (Date.now() - started < timeout) { if (await js(`(() => { try { return (${source}); } catch { return false; } })()`)) return; await delay(100); }
35 throw new Error(`UI condition timed out: ${source}\nstatus: ${await js("document.querySelector('#status').textContent")}`);
37async function shot(name) {
38 if (!shots) return;
39 fs.mkdirSync(shots, { recursive: true });
40 fs.writeFileSync(path.join(shots, `${name}.png`), (await window.webContents.capturePage()).toPNG());
42async function confirm() { await until("document.querySelector('#confirmDialog').open"); await js("document.querySelector('#confirmForm').requestSubmit()"); }
43async function selectUser(name) {
44 await until(`document.querySelector('button[data-username="${name}"]')`);
45 await js(`document.querySelector('button[data-username="${name}"]').click()`);
46 await until(`document.querySelector('#detailTitle').textContent === "${name}" && !document.querySelector('#detailSubtitle').textContent.includes("Načítám")`);
49async function run() {
50 assert.ok(env.CHJ_USERS_WINDOWS_HOST && env.CHJ_USERS_WINDOWS_PASSWORD && env.CHJ_USERS_WINDOWS_FINGERPRINT, "CHJ_USERS_WINDOWS_* not set");
51 await app.whenReady(); hardenSession();
52 const fingerprint = Buffer.from(`${env.CHJ_USERS_WINDOWS_FINGERPRINT}=`, "base64").toString("hex");
53 const profileService = {
54 get: () => ({ id: "win", label: "Windows test", host: env.CHJ_USERS_WINDOWS_HOST, port: 22, username: env.CHJ_USERS_WINDOWS_USER || "codex", authMethod: "password" }),
55 getHostKey: () => fingerprint, trustHostKey() {}, getStoredPassword: () => env.CHJ_USERS_WINDOWS_PASSWORD, markUsed() {}
56 };
57 const sessionManager = new SessionManager({ profileService, latencyMonitor: { start: () => () => {} } });
58 await sessionManager.connect({ sessionId: "ui", profileId: "win" });
59 const windowsService = new WindowsUserAdminService({ sessionManager, windowsExecutor: new WindowsExecutor({ sessionManager }) });
60 const userAdmin = createUserAdminApi(new UserAdminService({ sessionManager, privilegedExecutor: new PrivilegedExecutor({ sessionManager }), windowsService, detectPlatform }));
61 const registry = new PluginRegistry(root, null, { bundledRoot: path.join(__dirname, "../src/main/firstPartyPlugins") });
62 const runtime = new PluginRuntime({ BrowserWindow, registry, sessionManager, userAdmin, keyGeneratorService: new KeyGeneratorService(),
63 preload: path.join(__dirname, "../src/preload/pluginPreload.js"), getMainWindow: () => null, isVaultUnlocked: () => true });
64 runtime.registerIpc(ipcMain);
65 runtime.open("chj.users");
66 window = runtime.windows.get("chj.users");
67 window.webContents.on("console-message", (event) => { if (event.level === "error") errors.push(event.message); });
68 window.setSize(1320, 900);
69 await until("document.querySelectorAll('#usersBody button[data-username]').length > 0");
70 assert.match(await js("document.querySelector('#privilegeBadge').textContent"), /správce Windows \(zvýšený token\)/);
71 assert.equal(await js("document.querySelector('#elevatedButton').hidden"), true, "no sudo button on Windows");
72 assert.equal(await js("Array.from(document.querySelectorAll('thead th')).map(n => n.textContent).join('|')"), "Účet|SID (RID)|Stav|Administrators|SSH (CH-J)");
73 await shot("w01-list");
74 const inventory = await userAdmin.inventory("ui");
75 const leftover = inventory.users.find((user) => user.username === "chjui1");
76 if (leftover) await userAdmin.manage("ui", { action: "delete", sid: leftover.sid, username: "chjui1" });
77 await js("document.querySelector('#reloadButton').click()");
78 await until("!document.querySelector('button[data-username=\"chjui1\"]') && document.querySelector('#status').textContent.includes('Načteno')");
79 const allowGroups = /OpenSSH Users/i.test(inventory.groups.map((group) => group.name).join(",")) ? "S-1-5-32-585" : null;
81 await js("document.querySelector('#createButton').click()");
82 await until("document.querySelector('#createDialog').open");
83 assert.equal(await js("document.querySelector('#createShell').closest('label').hidden"), true, "no shell on Windows");
84 assert.equal(await js("document.querySelector('#createDescriptionLabel').hidden"), false);
85 await js(`document.querySelector('#createUsername').value = 'chjui1'; document.querySelector('#createComment').value = 'CH-J UI';
86 document.querySelector('#createDescription').value = 'UI smoke';
87 document.querySelector('#createPassword').value = 'Ui-Win-Pass-123!'; document.querySelector('#createPassword2').value = 'Ui-Win-Pass-123!';
88 ${allowGroups ? `Array.from(document.querySelector('#createGroups').options).forEach(o => { o.selected = o.value === '${allowGroups}'; });` : ""}`);
89 await shot("w02-create");
90 await js("document.querySelector('#createForm').requestSubmit()");
91 await until("document.querySelector('#detailTitle').textContent === 'chjui1' && document.querySelector('#detailSubtitle').textContent.includes('S-1-5-21-')", 90000);
92 await shot("w03-account");
93 await js("document.querySelector('#tab-groups').click()");
94 assert.equal(await js("document.querySelector('#tab-groups').textContent"), "Skupiny a správci");
95 assert.match(await js("document.querySelector('#panel-groups').textContent"), /Administrators[\s\S]*neznamená automaticky zvýšený token/);
96 await shot("w04-groups");
97 await js("document.querySelector('#tab-ssh').click()");
98 await until("document.querySelector('#panel-ssh').textContent.includes('Skutečně IPv4')");
99 await shot("w05-ssh");
100 await js(`document.querySelector('input[name="policy-password"][value="no"]').click(); document.querySelector('.policy-form').requestSubmit();`);
101 await confirm();
102 await until("document.querySelector('#status').textContent.includes('potvrdilo nové SSH přihlášení') || document.querySelector('#status').classList.contains('error')", 240000);
103 assert.match(await js("document.querySelector('#status').textContent"), /potvrdilo nové SSH přihlášení/);
104 await until("document.querySelector('button[data-username=\"chjui1\"]').closest('tr').textContent.includes('heslo ne')");
105 await shot("w06-ssh-applied");
106 await js(`document.querySelector('input[name="policy-password"][value="inherit"]').click(); document.querySelector('.policy-form').requestSubmit();`);
107 await confirm();
108 await until("document.querySelector('#status').textContent.includes('potvrdilo nové SSH přihlášení') || document.querySelector('#status').classList.contains('error')", 240000);
109 await js("document.querySelector('#tab-keys').click()");
110 await shot("w07-keys");
111 await js("document.querySelector('#tab-diagnostics').click()");
112 assert.match(await js("document.querySelector('#panel-diagnostics').textContent"), /Výchozí SSH shell/);
113 await shot("w08-diagnostics");
115 await selectUser("chjui1");
116 await js("document.querySelector('#tab-account').click()");
117 await js("Array.from(document.querySelectorAll('#panel-account button')).find(b => b.textContent.includes('Odstranit')).click()");
118 await until("document.querySelector('#confirmDialog').open");
119 await js("document.querySelector('#confirmTyped').value = 'chjui1'; document.querySelector('#confirmForm').requestSubmit();");
120 await until("!document.querySelector('button[data-username=\"chjui1\"]')", 120000);
121 await shot("w09-after-delete");
122 assert.deepEqual(errors, [], "no renderer errors");
123 await sessionManager.disconnectAll();
124 console.log("chj.users Windows UI smoke passed");
127run().then(() => { fs.rmSync(root, { recursive: true, force: true }); app.exit(0); }, (error) => { console.error(error); fs.rmSync(root, { recursive: true, force: true }); app.exit(1); });
SHA-256b4ea9366a4e1c2f41c31d409017e7d2b384e2307e6463ddc020539407fb62b1f

CH-J Proprietary Software License 1.14 · کد منبع تحت CH-J Proprietary Software License 1.14 ارائه می‌شود. در دسترس بودن آن شرایط مجوز را تغییر نمی‌دهد و حق اضافه‌ای اعطا نمی‌کند.

SHA-256 بایگانیcf4455b698f0f28e456a37b1834976a0194d8486acb7101052d59a838745cca3
فایل‌ها