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.

7,7 KB · 202 ZeilenDatei herunterladen
1"use strict";
3const { compareVersions } = require("../../shared/version");
5class UpdateService {
6 constructor(options) {
7 this.appVersion = options.appVersion;
8 this.buildId = options.buildId || null;
9 this.platform = options.platform;
10 this.arch = options.arch;
11 this.configStore = options.configStore;
12 this.providerFactory = options.providerFactory;
13 this.logger = options.logger;
14 this.lastCheck = null;
15 this.releases = [];
16 this.selectedReleaseId = null;
17 this.lastVerifiedDownload = null;
18 this.installerLaunchAuthorized = false;
19 this.operation = null;
20 }
22 getState() {
23 const release = this.lastCheck?.release || null;
24 const releaseRelation = release ? this._relation(release) : null;
25 return {
26 status: this.operation || "idle",
27 currentVersion: this.appVersion,
28 currentBuildId: this.buildId,
29 updateAvailable: Boolean(release && releaseRelation !== "sameVersionCurrentRelease"),
30 release,
31 releases: this.releases,
32 selectedReleaseId: this.selectedReleaseId,
33 releaseRelation,
34 downloaded: this.lastVerifiedDownload ? {
35 releaseId: this.lastVerifiedDownload.releaseId,
36 filename: this.lastVerifiedDownload.filename,
37 size: this.lastVerifiedDownload.size,
38 sha512: this.lastVerifiedDownload.sha512,
39 signatureVerified: this.lastVerifiedDownload.signatureVerified === true,
40 primaryFingerprint: this.lastVerifiedDownload.primaryFingerprint,
41 signingFingerprints: this.lastVerifiedDownload.signingFingerprints
42 } : null
43 };
44 }
46 async check() {
47 if (this.operation) throw new Error("Another update operation is already running.");
48 this.operation = "checking";
49 try {
50 const config = this.configStore.get();
51 const provider = this.providerFactory(config.updates);
52 const catalog = await provider.listReleases({
53 currentVersion: this.appVersion,
54 platform: this.platform,
55 arch: this.arch,
56 channel: config.updates.channel
57 });
58 this.releases = catalog.releases;
59 const preferred = this.releases.find((release) => compareVersions(release.version, this.appVersion) > 0)
60 || this.releases[0]
61 || null;
62 this.selectedReleaseId = preferred?.id || null;
63 this.lastCheck = {
64 updateAvailable: Boolean(preferred),
65 currentVersion: this.appVersion,
66 release: preferred,
67 sourceBaseUrl: catalog.sourceBaseUrl
68 };
69 this.lastVerifiedDownload = null;
70 this.installerLaunchAuthorized = false;
71 this.logger?.info("Update check completed.", {
72 channel: config.updates.channel,
73 updateAvailable: this.lastCheck.updateAvailable,
74 version: this.lastCheck.release?.version || null,
75 sourceBaseUrl: this.lastCheck.sourceBaseUrl
76 });
77 return this.getState();
78 } finally {
79 this.operation = null;
80 }
81 }
83 select(releaseId) {
84 if (this.operation) throw new Error("Another update operation is already running.");
85 const release = this.releases.find((item) => item.id === String(releaseId || ""));
86 if (!release) throw new Error("Selected release is not available in the current catalog.");
87 this.selectedReleaseId = release.id;
88 this.lastCheck = {
89 ...(this.lastCheck || { currentVersion: this.appVersion }),
90 updateAvailable: true,
91 release
92 };
93 this.lastVerifiedDownload = null;
94 this.installerLaunchAuthorized = false;
95 return this.getState();
96 }
98 async download() {
99 if (this.operation) throw new Error("Another update operation is already running.");
100 if (!this.lastCheck?.release) throw new Error("No update release is selected.");
101 this.operation = "downloading";
102 this.lastVerifiedDownload = null;
103 this.installerLaunchAuthorized = false;
104 try {
105 const provider = this.providerFactory(this.configStore.get().updates);
106 this.lastVerifiedDownload = await provider.downloadAndVerify(this.lastCheck.release);
107 if (this.lastVerifiedDownload.signatureVerified !== true) {
108 this.lastVerifiedDownload = null;
109 throw new Error("The update did not pass mandatory OpenPGP verification.");
110 }
111 this.lastVerifiedDownload.releaseId = this.lastCheck.release.id;
112 this.installerLaunchAuthorized = false;
113 this.logger?.info("Update downloaded and verified with SHA-512 and OpenPGP.", {
114 filename: this.lastVerifiedDownload.filename,
115 size: this.lastVerifiedDownload.size,
116 reused: this.lastVerifiedDownload.reused,
117 primaryFingerprint: this.lastVerifiedDownload.primaryFingerprint,
118 signingFingerprints: this.lastVerifiedDownload.signingFingerprints
119 });
120 return this.getState();
121 } finally {
122 this.operation = null;
123 }
124 }
126 getVerifiedDownloadPath() {
127 return this.lastVerifiedDownload?.signatureVerified === true
128 ? this.lastVerifiedDownload.path
129 : null;
130 }
132 async prepareInstallerLaunch() {
133 if (this.operation) throw new Error("Another update operation is already running.");
134 const release = this.lastCheck?.release;
135 if (!release || !this.lastVerifiedDownload || this.lastVerifiedDownload.releaseId !== release.id) {
136 throw new Error("No verified update release is ready to install.");
137 }
138 this.operation = "verifying-signature";
139 this.installerLaunchAuthorized = false;
140 try {
141 const provider = this.providerFactory(this.configStore.get().updates);
142 const filePath = await provider.reverifyForInstall(this.lastVerifiedDownload, release);
143 this.installerLaunchAuthorized = true;
144 return filePath;
145 } catch (error) {
146 this.lastVerifiedDownload = null;
147 throw error;
148 } finally {
149 this.operation = null;
150 }
151 }
153 cleanupDownloads() {
154 const provider = this.providerFactory(this.configStore.get().updates);
155 const result = provider.cleanupDownloads?.() || { cleaned: false };
156 this.lastVerifiedDownload = null;
157 this.installerLaunchAuthorized = false;
158 return result;
159 }
161 markInstallerLaunched() {
162 const release = this.lastCheck?.release;
163 if (!release || !this.lastVerifiedDownload || this.lastVerifiedDownload.releaseId !== release.id
164 || this.lastVerifiedDownload.signatureVerified !== true || !this.installerLaunchAuthorized) {
165 throw new Error("No verified update release is ready to install.");
166 }
167 this.configStore.recordLaunchedRelease({
168 id: release.id,
169 version: release.version,
170 publishedAt: release.publishedAt,
171 sha512: release.sha512
172 });
173 this.installerLaunchAuthorized = false;
174 return this.getState();
175 }
177 _relation(release) {
178 const comparison = compareVersions(release.version, this.appVersion);
179 if (comparison > 0) return "newerVersion";
180 if (comparison < 0) return "olderVersion";
181 if (this.buildId && release.buildId === this.buildId) return "sameVersionCurrentRelease";
183 const lastLaunched = this.configStore.get().updates.lastLaunchedRelease;
184 if (lastLaunched && compareVersions(lastLaunched.version, release.version) === 0) {
185 if (lastLaunched.id === release.id || lastLaunched.sha512 === release.sha512) {
186 return "sameVersionCurrentRelease";
187 }
188 const releaseTime = Date.parse(release.publishedAt);
189 const launchedTime = Date.parse(lastLaunched.publishedAt);
190 if (Number.isFinite(releaseTime) && Number.isFinite(launchedTime)) {
191 return releaseTime > launchedTime ? "sameVersionNewerRelease" : "sameVersionOlderRelease";
192 }
193 }
195 const newestSameVersion = this.releases.find((item) => compareVersions(item.version, this.appVersion) === 0);
196 return newestSameVersion?.id === release.id
197 ? "sameVersionNewerRelease"
198 : "sameVersionOlderRelease";
199 }
202module.exports = { UpdateService };

SHA-256: 10118684f925f713b6b6919552ba9c2de29ff1ffcd3a47c7962ce7b5604e7dfd

SHA-256 des Archivs: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0