CH-J ToolsSerververwaltung über SSH
Menü
Veröffentlichte Quellen

CH-J Tools

Durchsuchen Sie Verzeichnisse und Dateien einer bestimmten Anwendungsausgabe.

Quellen als ZIP herunterladen
CH-J / Server Manager 406 Dateien
core-20261024T135205Z-7c487d719de2 Hinzugefügt: · Erstellt:
smokeUsersUiWindows.js Hinzugefügt: Datum nicht erfasst 9,6 KB · 128 Zeilen
Code Datei herunterladen
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 // The assertions below check the Czech UI texts.
63 const runtime = new PluginRuntime({ BrowserWindow, registry, getLanguage: () => "cs", sessionManager, userAdmin, keyGeneratorService: new KeyGeneratorService(),
64 preload: path.join(__dirname, "../src/preload/pluginPreload.js"), getMainWindow: () => null, isVaultUnlocked: () => true });
65 runtime.registerIpc(ipcMain);
66 runtime.open("chj.users");
67 window = runtime.windows.get("chj.users");
68 window.webContents.on("console-message", (event) => { if (event.level === "error") errors.push(event.message); });
69 window.setSize(1320, 900);
70 await until("document.querySelectorAll('#usersBody button[data-username]').length > 0");
71 assert.match(await js("document.querySelector('#privilegeBadge').textContent"), /správce Windows \(zvýšený token\)/);
72 assert.equal(await js("document.querySelector('#elevatedButton').hidden"), true, "no sudo button on Windows");
73 assert.equal(await js("Array.from(document.querySelectorAll('thead th')).map(n => n.textContent).join('|')"), "Účet|SID (RID)|Stav|Administrators|SSH (CH-J)");
74 await shot("w01-list");
75 const inventory = await userAdmin.inventory("ui");
76 const leftover = inventory.users.find((user) => user.username === "chjui1");
77 if (leftover) await userAdmin.manage("ui", { action: "delete", sid: leftover.sid, username: "chjui1" });
78 await js("document.querySelector('#reloadButton').click()");
79 await until("!document.querySelector('button[data-username=\"chjui1\"]') && document.querySelector('#status').textContent.includes('Načteno')");
80 const allowGroups = /OpenSSH Users/i.test(inventory.groups.map((group) => group.name).join(",")) ? "S-1-5-32-585" : null;
82 await js("document.querySelector('#createButton').click()");
83 await until("document.querySelector('#createDialog').open");
84 assert.equal(await js("document.querySelector('#createShell').closest('label').hidden"), true, "no shell on Windows");
85 assert.equal(await js("document.querySelector('#createDescriptionLabel').hidden"), false);
86 await js(`document.querySelector('#createUsername').value = 'chjui1'; document.querySelector('#createComment').value = 'CH-J UI';
87 document.querySelector('#createDescription').value = 'UI smoke';
88 document.querySelector('#createPassword').value = 'Ui-Win-Pass-123!'; document.querySelector('#createPassword2').value = 'Ui-Win-Pass-123!';
89 ${allowGroups ? `Array.from(document.querySelector('#createGroups').options).forEach(o => { o.selected = o.value === '${allowGroups}'; });` : ""}`);
90 await shot("w02-create");
91 await js("document.querySelector('#createForm').requestSubmit()");
92 await until("document.querySelector('#detailTitle').textContent === 'chjui1' && document.querySelector('#detailSubtitle').textContent.includes('S-1-5-21-')", 90000);
93 await shot("w03-account");
94 await js("document.querySelector('#tab-groups').click()");
95 assert.equal(await js("document.querySelector('#tab-groups').textContent"), "Skupiny a správci");
96 assert.match(await js("document.querySelector('#panel-groups').textContent"), /Administrators[\s\S]*neznamená automaticky zvýšený token/);
97 await shot("w04-groups");
98 await js("document.querySelector('#tab-ssh').click()");
99 await until("document.querySelector('#panel-ssh').textContent.includes('Skutečně IPv4')");
100 await shot("w05-ssh");
101 await js(`document.querySelector('input[name="policy-password"][value="no"]').click(); document.querySelector('.policy-form').requestSubmit();`);
102 await confirm();
103 await until("document.querySelector('#status').textContent.includes('potvrdilo nové SSH přihlášení') || document.querySelector('#status').classList.contains('error')", 240000);
104 assert.match(await js("document.querySelector('#status').textContent"), /potvrdilo nové SSH přihlášení/);
105 await until("document.querySelector('button[data-username=\"chjui1\"]').closest('tr').textContent.includes('heslo ne')");
106 await shot("w06-ssh-applied");
107 await js(`document.querySelector('input[name="policy-password"][value="inherit"]').click(); document.querySelector('.policy-form').requestSubmit();`);
108 await confirm();
109 await until("document.querySelector('#status').textContent.includes('potvrdilo nové SSH přihlášení') || document.querySelector('#status').classList.contains('error')", 240000);
110 await js("document.querySelector('#tab-keys').click()");
111 await shot("w07-keys");
112 await js("document.querySelector('#tab-diagnostics').click()");
113 assert.match(await js("document.querySelector('#panel-diagnostics').textContent"), /Výchozí SSH shell/);
114 await shot("w08-diagnostics");
116 await selectUser("chjui1");
117 await js("document.querySelector('#tab-account').click()");
118 await js("Array.from(document.querySelectorAll('#panel-account button')).find(b => b.textContent.includes('Odstranit')).click()");
119 await until("document.querySelector('#confirmDialog').open");
120 await js("document.querySelector('#confirmTyped').value = 'chjui1'; document.querySelector('#confirmForm').requestSubmit();");
121 await until("!document.querySelector('button[data-username=\"chjui1\"]')", 120000);
122 await shot("w09-after-delete");
123 assert.deepEqual(errors, [], "no renderer errors");
124 await sessionManager.disconnectAll();
125 console.log("chj.users Windows UI smoke passed");
128run().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-2566d4f1b7c51a3995de6e5eb1fdbc33266db490e5a3c8ad5828c0051dc0074570a

CH-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 Archivs476ed8aef0f1e96a5acdf223127b6692acdf4492eeaf5d0816b6e2a634fbbda6
Dateien