Skip to content

Commit 5b126d7

Browse files
committed
fix(version-manager): avoid false unobfuscated detection on legacy versions
1 parent e0c3bb6 commit 5b126d7

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

__tests__/core/version-manager.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ describe('Version Management', () => {
4545
expect(result).toBe(false);
4646
}, 30000);
4747

48+
it('should return false for legacy obfuscated versions without client_mappings metadata', async () => {
49+
const versionManager = getVersionManager();
50+
// Early 1.14.x versions can omit client_mappings while still being obfuscated.
51+
const result = await versionManager.isVersionUnobfuscated('1.14.3');
52+
expect(result).toBe(false);
53+
}, 30000);
54+
4855
it('should return true for unobfuscated versions (26.1+)', async () => {
4956
const versionManager = getVersionManager();
5057
// 26.1 snapshots ship without obfuscation - no client_mappings in version JSON

src/services/version-manager.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import { logger } from '../utils/logger.js';
88
* Manages Minecraft versions - downloading, caching, and metadata
99
*/
1010
export class VersionManager {
11+
/**
12+
* First known unobfuscated Minecraft build.
13+
* 26.1-snapshot-1 released at this timestamp and removed client obfuscation.
14+
*/
15+
private static readonly UNOBFUSCATED_CUTOFF_MS = Date.parse('2025-12-16T12:42:29+00:00');
16+
1117
private downloader = getMojangDownloader();
1218
private cache = getCacheManager();
1319

@@ -148,10 +154,27 @@ export class VersionManager {
148154
* Starting with Minecraft 26.1 snapshots, Mojang stopped obfuscating the
149155
* client JAR. These versions have no `client_mappings` entry in their
150156
* version JSON because there is nothing to reverse-map.
157+
*
158+
* Important: some older obfuscated versions (e.g. early 1.14.x) also lack
159+
* `client_mappings` metadata, so missing metadata alone is not sufficient.
151160
*/
152161
async isVersionUnobfuscated(version: string): Promise<boolean> {
153162
const versionJson = await this.downloader.getVersionJson(version);
154-
return !versionJson.downloads.client_mappings;
163+
if (versionJson.downloads.client_mappings) {
164+
return false;
165+
}
166+
167+
// Early 1.14.x releases can be missing client_mappings metadata while still obfuscated.
168+
// Treat versions as unobfuscated only after the known 26.1 cutover and only for modern ids.
169+
const releaseTimeMs = Date.parse(versionJson.releaseTime);
170+
const isAfterUnobfuscatedCutover =
171+
Number.isFinite(releaseTimeMs) && releaseTimeMs >= VersionManager.UNOBFUSCATED_CUTOFF_MS;
172+
173+
const modernVersionId = /^(\d+)\.(\d+)(?:\.\d+)?(?:-snapshot-\d+)?$/.exec(versionJson.id);
174+
const modernMajor = modernVersionId ? Number.parseInt(modernVersionId[1], 10) : Number.NaN;
175+
const isModernUnobfuscatedSeries = Number.isFinite(modernMajor) && modernMajor >= 26;
176+
177+
return isAfterUnobfuscatedCutover && isModernUnobfuscatedSeries;
155178
}
156179

157180
/**

0 commit comments

Comments
 (0)