Публикуемый источник
Загрузка источника ZIP
CH-J Server Manager
Просмотр каталогов и файлов для конкретного выпуска приложения.
CH-J / Server Manager
377 файлы
core-20261019T111616Z-160a00bfcddc
Добавлено: · Построено:
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 and4
// 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_FINGERPRINT6
// Run: npx electron scripts/smokeUsersUiWindows.js [screenshot-dir]7
const { app, BrowserWindow, ipcMain, protocol } = require("electron");8
const assert = require("node:assert/strict");9
const fs = require("node:fs");10
const os = require("node:os");11
const path = require("node:path");12
const { hardenSession } = require("../src/main/bootstrap/createMainWindow");13
const { PluginRegistry } = require("../src/main/plugins/pluginRegistry");14
const { PluginRuntime } = require("../src/main/plugins/pluginRuntime");15
const { SessionManager } = require("../src/main/sessions/sessionManager");16
const { PrivilegedExecutor } = require("../src/main/sessions/privilegedExec");17
const { UserAdminService, createUserAdminApi } = require("../src/main/users/userAdminService");18
const { WindowsUserAdminService } = require("../src/main/users/windowsUserAdminService");19
const { WindowsExecutor } = require("../src/main/sessions/windowsPrivilegedExec");20
const { detectPlatform } = require("../src/main/sessions/platformDetect");21
const { KeyGeneratorService } = require("../src/main/keys/keyGeneratorService");23
const env = process.env;24
const root = fs.mkdtempSync(path.join(os.tmpdir(), "chj-users-ui-win-"));25
const shots = process.argv.find((arg, index) => index > 1 && !arg.startsWith("-") && !arg.endsWith(".js")) || null;26
app.setPath("userData", root);27
protocol.registerSchemesAsPrivileged([{ scheme: "chj-plugin", privileges: { standard: true, secure: true, supportFetchAPI: true } }]);28
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));29
const errors = [];30
let window;31
const js = (source) => window.webContents.executeJavaScript(source);32
async 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")}`);36
}37
async 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());41
}42
async function confirm() { await until("document.querySelector('#confirmDialog').open"); await js("document.querySelector('#confirmForm').requestSubmit()"); }43
async 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")`);47
}49
async 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");125
}127
run().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-256
b4ea9366a4e1c2f41c31d409017e7d2b384e2307e6463ddc020539407fb62b1fCH-J Proprietary Software License 1.14 · Источник представлен в CH-J Proprietary Software License 1.14. Его наличие не изменяет лицензионных условий и не предоставляет дополнительных прав.
Архив SHA-256
a9605c0870a223b6a8542bb0705edd51d8b04f3069582653417a8397fabcc09a