公開済みのソース
ソースの ZIP をダウンロード
CH-J Tools
特定のアプリケーションリリースのディレクトリとファイルを閲覧できます。
CH-J / Server Manager
406 ファイル
core-20261024T135205Z-7c487d719de2
追加日時: · ビルド日時:
1
"use strict";3
const { compareVersions } = require("../../shared/version");5
class 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
checked: Boolean(this.lastCheck),28
currentVersion: this.appVersion,29
currentBuildId: this.buildId,30
updateAvailable: Boolean(release && releaseRelation !== "sameVersionCurrentRelease"),31
release,32
releases: this.releases,33
selectedReleaseId: this.selectedReleaseId,34
releaseRelation,35
downloaded: this.lastVerifiedDownload ? {36
releaseId: this.lastVerifiedDownload.releaseId,37
filename: this.lastVerifiedDownload.filename,38
size: this.lastVerifiedDownload.size,39
sha512: this.lastVerifiedDownload.sha512,40
signatureVerified: this.lastVerifiedDownload.signatureVerified === true,41
primaryFingerprint: this.lastVerifiedDownload.primaryFingerprint,42
signingFingerprints: this.lastVerifiedDownload.signingFingerprints43
} : null44
};45
}47
async check() {48
if (this.operation) throw new Error("Another update operation is already running.");49
this.operation = "checking";50
try {51
const config = this.configStore.get();52
const provider = this.providerFactory(config.updates);53
const catalog = await provider.listReleases({54
currentVersion: this.appVersion,55
platform: this.platform,56
arch: this.arch,57
channel: config.updates.channel58
});59
this.releases = catalog.releases;60
const preferred = this.releases.find((release) => compareVersions(release.version, this.appVersion) > 0)61
|| this.releases[0]62
|| null;63
this.selectedReleaseId = preferred?.id || null;64
this.lastCheck = {65
updateAvailable: Boolean(preferred),66
currentVersion: this.appVersion,67
release: preferred,68
sourceBaseUrl: catalog.sourceBaseUrl69
};70
this.lastVerifiedDownload = null;71
this.installerLaunchAuthorized = false;72
this.logger?.info("Update check completed.", {73
channel: config.updates.channel,74
updateAvailable: this.lastCheck.updateAvailable,75
version: this.lastCheck.release?.version || null,76
sourceBaseUrl: this.lastCheck.sourceBaseUrl77
});78
} finally {79
this.operation = null;80
}81
// Reported after the operation is cleared, so the result never claims "checking".82
return this.getState();83
}85
select(releaseId) {86
if (this.operation) throw new Error("Another update operation is already running.");87
const release = this.releases.find((item) => item.id === String(releaseId || ""));88
if (!release) throw new Error("Selected release is not available in the current catalog.");89
this.selectedReleaseId = release.id;90
this.lastCheck = {91
...(this.lastCheck || { currentVersion: this.appVersion }),92
updateAvailable: true,93
release94
};95
this.lastVerifiedDownload = null;96
this.installerLaunchAuthorized = false;97
return this.getState();98
}100
async download() {101
if (this.operation) throw new Error("Another update operation is already running.");102
if (!this.lastCheck?.release) throw new Error("No update release is selected.");103
this.operation = "downloading";104
this.lastVerifiedDownload = null;105
this.installerLaunchAuthorized = false;106
try {107
const provider = this.providerFactory(this.configStore.get().updates);108
this.lastVerifiedDownload = await provider.downloadAndVerify(this.lastCheck.release);109
if (this.lastVerifiedDownload.signatureVerified !== true) {110
this.lastVerifiedDownload = null;111
throw new Error("The update did not pass mandatory OpenPGP verification.");112
}113
this.lastVerifiedDownload.releaseId = this.lastCheck.release.id;114
this.installerLaunchAuthorized = false;115
this.logger?.info("Update downloaded and verified with SHA-512 and OpenPGP.", {116
filename: this.lastVerifiedDownload.filename,117
size: this.lastVerifiedDownload.size,118
reused: this.lastVerifiedDownload.reused,119
primaryFingerprint: this.lastVerifiedDownload.primaryFingerprint,120
signingFingerprints: this.lastVerifiedDownload.signingFingerprints121
});122
} finally {123
this.operation = null;124
}125
return this.getState();126
}128
getVerifiedDownloadPath() {129
return this.lastVerifiedDownload?.signatureVerified === true130
? this.lastVerifiedDownload.path131
: null;132
}134
async prepareInstallerLaunch() {135
if (this.operation) throw new Error("Another update operation is already running.");136
const release = this.lastCheck?.release;137
if (!release || !this.lastVerifiedDownload || this.lastVerifiedDownload.releaseId !== release.id) {138
throw new Error("No verified update release is ready to install.");139
}140
this.operation = "verifying-signature";141
this.installerLaunchAuthorized = false;142
try {143
const provider = this.providerFactory(this.configStore.get().updates);144
const filePath = await provider.reverifyForInstall(this.lastVerifiedDownload, release);145
this.installerLaunchAuthorized = true;146
return filePath;147
} catch (error) {148
this.lastVerifiedDownload = null;149
throw error;150
} finally {151
this.operation = null;152
}153
}155
cleanupDownloads() {156
const provider = this.providerFactory(this.configStore.get().updates);157
const result = provider.cleanupDownloads?.() || { cleaned: false };158
this.lastVerifiedDownload = null;159
this.installerLaunchAuthorized = false;160
return result;161
}163
markInstallerLaunched() {164
const release = this.lastCheck?.release;165
if (!release || !this.lastVerifiedDownload || this.lastVerifiedDownload.releaseId !== release.id166
|| this.lastVerifiedDownload.signatureVerified !== true || !this.installerLaunchAuthorized) {167
throw new Error("No verified update release is ready to install.");168
}169
this.configStore.recordLaunchedRelease({170
id: release.id,171
version: release.version,172
publishedAt: release.publishedAt,173
sha512: release.sha512174
});175
this.installerLaunchAuthorized = false;176
return this.getState();177
}179
_relation(release) {180
const comparison = compareVersions(release.version, this.appVersion);181
if (comparison > 0) return "newerVersion";182
if (comparison < 0) return "olderVersion";183
if (this.buildId && release.buildId === this.buildId) return "sameVersionCurrentRelease";185
const lastLaunched = this.configStore.get().updates.lastLaunchedRelease;186
if (lastLaunched && compareVersions(lastLaunched.version, release.version) === 0) {187
if (lastLaunched.id === release.id || lastLaunched.sha512 === release.sha512) {188
return "sameVersionCurrentRelease";189
}190
const releaseTime = Date.parse(release.publishedAt);191
const launchedTime = Date.parse(lastLaunched.publishedAt);192
if (Number.isFinite(releaseTime) && Number.isFinite(launchedTime)) {193
return releaseTime > launchedTime ? "sameVersionNewerRelease" : "sameVersionOlderRelease";194
}195
}197
const newestSameVersion = this.releases.find((item) => compareVersions(item.version, this.appVersion) === 0);198
return newestSameVersion?.id === release.id199
? "sameVersionNewerRelease"200
: "sameVersionOlderRelease";201
}202
}204
module.exports = { UpdateService };SHA-256
bd86b28272c1e13cf989401c767c9126efe689f556a4b7b098f545b34b7dd825CH-J Proprietary Software License 1.14 · ソースは CH-J Proprietary Software License 1.14 に基づいて提供されています。公開されていても、ライセンス条項が変わったり、追加の権利が付与されたりすることはありません。
アーカイブの SHA-256
476ed8aef0f1e96a5acdf223127b6692acdf4492eeaf5d0816b6e2a634fbbda6