Hash mods' flattened folder content instead of a rebuilt zip - #50
Open
12problems wants to merge 1 commit into
Open
Hash mods' flattened folder content instead of a rebuilt zip#5012problems wants to merge 1 commit into
12problems wants to merge 1 commit into
Conversation
The launcher no longer deploys mods as zips - Steamodded mounting a .zip via NFS.mount() didn't behave correctly for every mod in practice, so it now deploys real extracted folders instead (see the companion launcher-repo PR). The "approved hash" this server computes has to match what the launcher actually verifies against, so it switches too: hash a mod's flattened content directly instead of assembling and hashing a deterministic zip of it. - New mod-folder-hash.ts: computeModFolderHash() is a byte-for-byte Node port of the launcher's ModFileHash::hashDirectory() - sorted relative POSIX paths + file bytes, fed into one running SHA-256. Verified against the launcher side with a real cross-language parity check (not just each side's own unit tests): a standalone build of the actual modfilehash.cpp and a Node script calling this file produced identical digests for the same sample mod tree, both before and after renaming the tree's own root folder (which deliberately doesn't factor into the hash on either side, unlike the old zip-based scheme where the two had to agree on folder naming for the resulting hash to match at all). - mods-sync.service.ts: computePreparedZipHash() -> renamed computeModFolderHashForRelease(), now calls computeModFolderHash() on the flattened extracted directory directly instead of shelling out to modzip and hashing the assembled archive's bytes. - Deleted native/modzip/ and its Dockerfile build step entirely - no native C binary/libzip to compile or ship anymore. - mod-archive-flatten.ts/backfill-mod-hashes.ts doc comments updated to match; relocateModRoot() itself is unchanged (still needed to produce the same flattened layout the launcher's own extraction step would). - New mod-folder-hash.test.ts: hash-vs-hand-computed-SHA-256, root-name independence, enumeration-order independence, content/rename sensitivity. All passing. No DB schema change - modRegistry.latestSha256/modRegistryVersions.sha256 stay hex-sha256 columns, just fed different input bytes now. Every hash stored under the old algorithm is wrong under this one - `pnpm backfill-mod-hashes` needs to run once after this deploys (see backfill-mod-hashes.ts, unchanged, already idempotent). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Companion PR to Balatro-Multiplayer/new-launcher's folder-based mod
deployment change (targets
mainthere). The launcher no longerdeploys mods as zips -
NFS.mount()-mounting a.zipdidn't behavecorrectly for every mod in practice - so it now deploys real extracted
folders instead. This server's "approved hash" has to match what the
launcher actually verifies against, so it switches too: hash a mod's
flattened content directly instead of assembling and hashing a
deterministic zip of it.
mod-folder-hash.ts:computeModFolderHash(), a byte-for-byteNode port of the launcher's
ModFileHash::hashDirectory()mods-sync.service.tscalls it directly on the flattened extracteddirectory instead of shelling out to
modzipnative/modzip/and its Dockerfile build step entirely - nonative C binary/libzip dependency left in this repo at all
mod-folder-hash.test.tscovering the algorithm's correctnessVerified with a real cross-language parity check, not just each
side's own unit tests: built a standalone copy of the launcher's
actual
modfilehash.cppand ran it side-by-side with this repo'smod-folder-hash.tsagainst the same sample mod tree - both producedthe identical SHA-256 digest, both before and after renaming the
tree's own root folder (deliberately irrelevant to the hash on either
side now, unlike the old zip-based scheme).
No DB schema change -
sha256columns stay hex-sha256, just feddifferent input bytes. Every hash stored under the old algorithm is
wrong under this one -
pnpm backfill-mod-hashesneeds to run onceafter this deploys (already idempotent, unchanged).
Test plan
pnpm test(mod-folder-hash.test.ts + mod-archive-flatten.test.ts) - all passingtsc --noEmit- no new errors introducedpnpm backfill-mod-hashesagainst a real deploy after merging🤖 Generated with Claude Code