CH-J Server ManagerSerververwaltung über SSH
Menü
Veröffentlichte Quellen

CH-J Server Manager

Durchsuchen Sie Verzeichnisse und Dateien einer bestimmten Anwendungsausgabe.

Quellen als ZIP herunterladen
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.

5,8 KB · 141 ZeilenDatei herunterladen
1"use strict";
3const fs = require("node:fs");
4const os = require("node:os");
5const path = require("node:path");
6const { execFileSync, spawn, spawnSync } = require("node:child_process");
7const { signAsync } = require("@electron/osx-sign");
9const projectRoot = path.resolve(__dirname, "..");
10const packageJson = require(path.join(projectRoot, "package.json"));
11const productName = packageJson.build?.productName || packageJson.productName;
12const distRoot = path.resolve(projectRoot, process.env.CHJ_DIST_DIR || "dist");
13const appPath = path.join(distRoot, "mac-arm64", `${productName}.app`);
14const outputPath = path.join(distRoot, `${productName}-${packageJson.version}-arm64.app.zip`);
16function run(command, args, options = {}) {
17 return execFileSync(command, args, { encoding: "utf8", stdio: options.capture ? "pipe" : "inherit" });
20function signatureIsValid(bundlePath) {
21 try {
22 run("codesign", ["--verify", "--deep", "--strict", "--verbose=2", bundlePath], { capture: true });
23 return true;
24 } catch (_) {
25 return false;
26 }
29function signatureDescription(bundlePath) {
30 const result = spawnSync("codesign", ["-dv", "--verbose=4", bundlePath], { encoding: "utf8" });
31 return `${result.stdout || ""}\n${result.stderr || ""}`;
34async function ensureValidSignature() {
35 if (signatureIsValid(appPath)) {
36 const description = signatureDescription(appPath);
37 if (description.includes("Authority=Developer ID Application")) return "developer-id";
38 if (description.includes("Signature=adhoc") && !description.includes("runtime)")) return "adhoc";
39 }
41 const identities = run("security", ["find-identity", "-v", "-p", "codesigning"], { capture: true });
42 const hasDeveloperId = identities.includes("Developer ID Application:");
43 const options = {
44 app: appPath,
45 platform: "darwin",
46 preAutoEntitlements: false,
47 preEmbedProvisioningProfile: false,
48 };
49 if (!hasDeveloperId) {
50 options.identity = "-";
51 options.identityValidation = false;
52 options.optionsForFile = () => ({
53 hardenedRuntime: false,
54 signatureFlags: [],
55 timestamp: "none",
56 });
57 }
58 await signAsync(options);
59 if (!signatureIsValid(appPath)) throw new Error("Kontrola codesign po podepsání .app selhala.");
60 return hasDeveloperId ? "developer-id" : "adhoc";
63async function smokeTestApp(bundlePath) {
64 const executable = path.join(bundlePath, "Contents", "MacOS", productName);
65 const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "chj-mac-smoke-data-"));
66 try {
67 // Fixture consent for this isolated packaging smoke test only. Production
68 // startup always checks the record; the environment does not bypass it.
69 const { LicenseAcceptance } = require("../src/main/legal/licenseAcceptance");
70 const acceptance = new LicenseAcceptance({ storageRoot: userDataDir,
71 licensePath: path.join(bundlePath, "Contents", "Resources", "licenses", "APPLICATION_LICENSE.txt"),
72 docsRoot: path.join(bundlePath, "Contents", "Resources", "docs"),
73 appVersion: packageJson.version, buildId: require("../src/shared/buildInfo.json").buildId });
74 acceptance.accept({ accepted: true, sha256: acceptance.identity.sha256, guidanceShown: true, guidanceSha256: acceptance.identity.guidanceSha256 });
75 await new Promise((resolve, reject) => {
76 let output = "";
77 const smokeEnvironment = {
78 ...process.env,
79 CHJ_BUILD_SMOKE_USER_DATA_DIR: userDataDir,
80 ELECTRON_ENABLE_LOGGING: "1",
81 };
82 delete smokeEnvironment.ELECTRON_RUN_AS_NODE;
83 delete smokeEnvironment.NODE_OPTIONS;
84 const child = spawn(executable, [], {
85 env: smokeEnvironment,
86 stdio: ["ignore", "pipe", "pipe"],
87 });
88 child.stdout.on("data", (chunk) => { output += chunk; });
89 child.stderr.on("data", (chunk) => { output += chunk; });
90 const timeout = setTimeout(() => {
91 child.kill("SIGTERM");
92 reject(new Error(`Aplikace nedokončila smoke test do 12 sekund.\n${output.trim()}`));
93 }, 12000);
94 child.once("error", (error) => {
95 clearTimeout(timeout);
96 reject(error);
97 });
98 child.once("exit", (code, signal) => {
99 clearTimeout(timeout);
100 if (code === 0 && output.includes("CHJ_BUILD_SMOKE_READY")) resolve();
101 else reject(new Error(`Aplikace nedokončila smoke test (code=${code}, signal=${signal}).\n${output.trim()}`));
102 });
103 });
104 } finally {
105 fs.rmSync(userDataDir, { recursive: true, force: true });
106 }
109async function main() {
110 if (process.platform !== "darwin") throw new Error("macOS instalační ZIP lze vytvářet pouze na macOS.");
111 if (!productName || !fs.statSync(appPath, { throwIfNoEntry: false })?.isDirectory()) {
112 throw new Error(`Chybí sestavená aplikace ${appPath}. Nejdřív spusťte macOS build.`);
113 }
115 const signature = await ensureValidSignature();
116 fs.rmSync(outputPath, { force: true });
117 run("ditto", ["-c", "-k", "--sequesterRsrc", "--keepParent", appPath, outputPath]);
119 const verifyRoot = fs.mkdtempSync(path.join(os.tmpdir(), "chj-mac-installer-"));
120 try {
121 run("ditto", ["-x", "-k", outputPath, verifyRoot]);
122 const extractedApp = path.join(verifyRoot, `${productName}.app`);
123 if (!fs.statSync(extractedApp, { throwIfNoEntry: false })?.isDirectory() || !signatureIsValid(extractedApp)) {
124 throw new Error("Výsledný ZIP neobsahuje kompletní aplikaci s platným podpisem bundle.");
125 }
126 await smokeTestApp(extractedApp);
127 } finally {
128 fs.rmSync(verifyRoot, { recursive: true, force: true });
129 }
131 console.log(`Instalační balíček: ${outputPath}`);
132 console.log(`Podpis: ${signature}`);
133 if (signature !== "developer-id") {
134 console.warn("VAROVÁNÍ: Jde o testovací ad-hoc sestavení. Pro bezobslužnou instalaci z webu je nutný Developer ID podpis a Apple notarizace.");
135 }
138main().catch((error) => {
139 console.error(error.message || error);
140 process.exitCode = 1;
141});

SHA-256: b48c92294b4b7c7bcbc7c2bcb5cd0f8c1a47ce5a828f5db6cba33465291d6197

SHA-256 des Archivs: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0