Prevent savedata corruption and denial-of-service by adding four layers
of protection to the save pipeline:
- Bounded decompression (nullcomp.DecompressWithLimit): caps output size
to prevent OOM from crafted payloads that expand to exhaust memory
- Bounds-checked delta patching (deltacomp.ApplyDataDiffWithLimit):
validates offsets before writing, returns errors for negative offsets,
truncated patches, and oversized output; ApplyDataDiff now returns
original data on error instead of partial corruption
- Size limits on save handlers: rejects compressed payloads >512KB and
decompressed data >1MB before processing; applied to main savedata,
platedata, and platebox diff paths
- Rotating savedata backups: 3 slots per character with 30-minute
interval, snapshots the previous state before overwriting, backed by
new savedata_backups table (migration 0007)
The userBinary and minidata maps with their locks were spread across
Server as raw fields with manual lock management. Cross-channel session
searches also required acquiring nested locks (server lock + binary
lock). Encapsulating in dedicated types eliminates the nested locking
and reduces Server's field count by 4.
Add 18 new typed methods to CharacterRepository (ReadTime, SaveTime,
SaveInt, SaveBool, SaveString, ReadBool, ReadString, LoadColumnWithDefault,
SetDeleted, UpdateDailyCafe, ResetDailyQuests, ReadEtcPoints, ResetCafeTime,
UpdateGuildPostChecked, ReadGuildPostChecked, SaveMercenary, UpdateGCPAndPact,
FindByRastaID) and migrate ~56 inline SQL queries across 13 handler files.
Pure refactor — zero behavior change. Each handler produces identical SQL
with identical parameters. Cross-table JOINs and bulk CharacterSaveData
operations are intentionally left out of scope.
Add readCharacterInt/adjustCharacterInt helpers for single-column
integer operations on the characters table. Eliminates fmt.Sprintf
SQL construction in handlers_misc.go and replaces inline queries
across cafe, kouryou, and mercenary handlers.
Second round of protocol constant extraction: adds constants_time.go
(secsPerDay, secsPerWeek), constants_raviente.go (register IDs,
semaphore constants), and named constants across 14 handler files
replacing raw hex/numeric literals. Updates anti-patterns doc to
mark #4 (magic numbers) as substantially fixed.
A malicious or buggy client could send arbitrarily large payloads
that get written directly to PostgreSQL, wasting disk and memory.
Each save handler now rejects payloads exceeding a generous upper
bound derived from the known data format sizes.
Covers all remaining items from #158: partner, hunternavi,
savemercenary, scenariodata, platedata, platebox, platemyset,
rengokudata, mezfes, savefavoritequest, house_furniture, mission.
Closes#158