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 339 file
core-20261014T184258Z-3fbed0b93fdf Aggiunto: Data non registrata · Costruito:
File
profileTransfer.test.js Aggiunto: Data non registrata 6,0 KB · 82 righe
Scarica file
1"use strict";
3const test = require("node:test");
4const assert = require("node:assert/strict");
5const fs = require("node:fs");
6const os = require("node:os");
7const path = require("node:path");
8const { ProfileService } = require("../src/main/profiles/profileService");
9const { VaultStore } = require("../src/main/security/vaultStore");
10const { ProfileTransfer, serializeProfiles, parseProfiles, identity, MAX_BYTES } = require("../src/main/profiles/profileTransfer");
12const document = (servers, version = 1) => JSON.stringify({ format: "chj-server-profiles", version, servers });
13const server = { name: 'Žluťoučký, "server"', host: "NGINX.lan", username: "root", port: 22 };
15async function setup(t) {
16 const root = fs.mkdtempSync(path.join(os.tmpdir(), "chj-transfer-"));
17 t.after(() => fs.rmSync(root, { recursive: true, force: true }));
18 const vault = new VaultStore(root); await vault.create("transfer-test-password");
19 const profiles = new ProfileService(vault);
20 return { vault, profiles, transfer: new ProfileTransfer(profiles) };
23test("JSON and CSV round trip UTF-8, original DNS/IPv4/IPv6 and never serialize secrets or paths", () => {
24 const servers = [server, { ...server, host: "192.168.1.10" }, { ...server, host: "2001:db8::10", port: 2222 }, { ...server, name: "=FORMULA()", username: "@user" }, { ...server, name: "'literal" }];
25 const profiles = servers.map((item) => ({ ...item, label: item.name, password: "do-not-export", privateKeyPath: "/secret/key", token: "secret-token", resolvedIp: "1.2.3.4", hasStoredPassword: true }));
26 for (const format of ["json", "csv"]) {
27 const exported = serializeProfiles(profiles, format);
28 assert.doesNotMatch(exported, /do-not-export|\/secret\/key|secret-token|1\.2\.3\.4|hasStoredPassword/);
29 assert.deepEqual(parseProfiles(exported).servers, servers);
30 }
31 assert.match(serializeProfiles(profiles, "csv"), /'=FORMULA/);
32 assert.deepEqual(Object.keys(JSON.parse(serializeProfiles(profiles)).servers[0]), ["name", "host", "username", "port"]);
33});
35test("import validates the entire document, version, fields, CSV structure and limits", () => {
36 for (const input of [document([server], 2), document([{ ...server, host: "bad host" }]), document([{ ...server, port: 0 }]), document([{ ...server, port: 65536 }]), document([{ ...server, port: null }]), document([{ ...server, username: "bad\nuser" }]), document([]), "name,ip,username,port\nx,1.2.3.4,root,22", 'name,host,username,port\n"bad,host,root,22', "name,host,username,port\nx,host,root,22,extra", "x".repeat(MAX_BYTES + 1)]) assert.throws(() => parseProfiles(input));
37 assert.deepEqual(parseProfiles('port,username,host,name\r\n22,root,nginx.lan,NGINX\r\n').servers[0], { name: "NGINX", host: "nginx.lan", username: "root", port: 22 });
38 assert.equal(parseProfiles(document([{ ...server, port: undefined }])).servers[0].port, 22);
39 assert.equal(identity({ ...server, host: "2001:db8::1" }), identity({ ...server, host: "2001:0db8:0:0:0:0:0:1" }));
40});
42test("preview is read-only; skip, update and create handle vault and file duplicates without importing authentication", async (t) => {
43 for (const policy of ["skip", "update", "create"]) {
44 const { profiles, vault, transfer } = await setup(t);
45 const saved = profiles.save({ label: "Old", host: "nginx.lan", username: "root", storePassword: true, password: "old-password" });
46 const preview = transfer.preview(document([{ ...server, password: "incoming-password", privateKeyPath: "/incoming/key" }, { ...server, name: "Second" }]));
47 assert.deepEqual(preview.servers.map((item) => item.duplicate), [true, true]);
48 assert.equal(profiles.get(saved.id).label, "Old");
49 assert.equal(profiles.getStoredPassword(saved.id), "old-password");
50 assert.deepEqual(transfer.commit(preview.token, policy), policy === "skip" ? { created: 0, updated: 0, skipped: 2 } : policy === "update" ? { created: 0, updated: 2, skipped: 0 } : { created: 2, updated: 0, skipped: 0 });
51 if (policy === "update") { assert.equal(profiles.getStoredPassword(saved.id), null); assert.equal(profiles.get(saved.id).label, "Second"); }
52 if (policy === "create") {
53 assert.equal(profiles.list().length, 3);
54 for (const profile of profiles.list().filter((item) => item.id !== saved.id)) { assert.equal(profile.hasStoredPassword, false); assert.equal(profile.privateKeyPath, ""); }
55 }
56 assert.doesNotMatch(JSON.stringify(vault.getData()), /incoming-password|\/incoming\/key/);
57 assert.throws(() => transfer.commit(preview.token, policy), /expired/);
58 }
59});
61test("updating a key-authenticated duplicate removes key paths and imported rows require new authentication", async (t) => {
62 const { profiles, transfer } = await setup(t);
63 const saved = profiles.save({ label: "Key server", host: server.host, username: server.username, tags: ["production"], authMethod: "privateKey", privateKeyPath: "/existing/key" });
64 const preview = transfer.preview(document([server, { ...server, host: "other.lan" }]));
65 assert.deepEqual(transfer.commit(preview.token, "update"), { created: 1, updated: 1, skipped: 0 });
66 assert.equal(profiles.get(saved.id).authMethod, "password");
67 assert.equal(profiles.get(saved.id).privateKeyPath, "");
68 assert.deepEqual(profiles.get(saved.id).tags, ["production"]);
69});
71test("cancel, lock and stale previews cannot be committed; invalid import leaves the vault intact", async (t) => {
72 const { profiles, vault, transfer } = await setup(t);
73 let preview = transfer.preview(document([server])); transfer.cancel();
74 assert.throws(() => transfer.commit(preview.token, "create"), /expired/);
75 preview = transfer.preview(document([server])); vault.lock(); await vault.unlock("transfer-test-password");
76 assert.throws(() => transfer.commit(preview.token, "create"), /expired/);
77 assert.throws(() => transfer.preview(document([server, { ...server, port: -1 }])));
78 assert.equal(profiles.list().length, 0);
79 preview = transfer.preview(document([server]));
80 assert.throws(() => transfer.commit(preview.token, "invalid"), /policy/);
81 assert.equal(profiles.list().length, 0);
82});
SHA-2566796f8af65b6aa706ade0a90daa466662eb60699053a6ff97b5c859a022c579c

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-2563df08cf5e899262a6ce92d7ec2caf5c42b683f1f2b57055662b845ff7dde67a8