Commit Graph

55 Commits

Author SHA1 Message Date
Houmgaor
b40217c7fe feat(savedata): add tier 1 data integrity protections
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)
2026-03-17 19:03:43 +01:00
Houmgaor
4e8c4b4e92 fix(channelserver): handle silently discarded errors across handlers
Replace ~17 instances of '_ =' / '_ :=' with proper error checks that
log warnings or send fail ACKs. Affected handlers: cafe, distitem, data,
guild, guild_board, guild_cooking, guild_scout, house, mercenary, misc,
and rengoku. Also resolves all pre-existing lint issues: unchecked
bf.Seek in tests, unused filtered slice in svc_festa, unused mock
fields, and unused signserver test helper.
2026-02-27 11:33:25 +01:00
Houmgaor
74798fc8b3 fix(channelserver): return error from Save() to prevent misleading success logs
CharacterSaveData.Save() silently returned on failure (nil decompressed
data, compression error, DB error) while the caller unconditionally
logged "Saved character data successfully". This made diagnosing save
failures difficult (ref #163).

Save() now returns an error, and all six call sites check it. The
success log in saveAllCharacterData only fires when the save actually
persisted.
2026-02-27 11:21:37 +01:00
Houmgaor
f640cfee27 fix: log SJIS decoding errors instead of silently discarding them
Add SJISToUTF8Lossy() that wraps SJISToUTF8() and logs decode errors at
slog.Debug level. Replace all 31 call sites across 17 files that previously
discarded the error with `_, _ =`. This makes garbled text from malformed
SJIS client data debuggable without adding noise at default log levels.
2026-02-22 17:01:22 +01:00
Houmgaor
1d507b3d11 fix: replace fmt.Sprintf in logger calls with structured fields and add LoopDelay default
fmt.Sprintf inside zap logger calls defeats structured logging,
making log aggregation and filtering harder. All 6 sites now use
proper zap fields (zap.Uint32, zap.Uint8, zap.String).

LoopDelay had no viper.SetDefault, so omitting it from config.json
caused a zero-value (0 ms) busy-loop in the recv loop. Default is
now 50 ms, matching config.example.json.
2026-02-22 16:32:43 +01:00
Houmgaor
c04fa504cc refactor(channelserver): extract UserBinaryStore and MinidataStore
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.
2026-02-21 13:39:44 +01:00
Houmgaor
f17cb96b52 refactor(config): rename package _config to config with cfg alias
The config package used `package _config` with a leading underscore,
which is unconventional in Go. Rename to `package config` (matching the
directory name) and use `cfg` as the standard import alias across all
93 importing files.
2026-02-21 13:20:15 +01:00
Houmgaor
a02251e486 fix(channelserver): mitigate house theme corruption on save (#92)
The game client sometimes writes -1 (0xFF bytes) into the house_tier
field during save, which causes the house theme to vanish on next
login. Snapshot the house tier before applying the save delta and
restore it if the incoming value is corrupted.
2026-02-20 22:57:40 +01:00
Houmgaor
d642cbef24 refactor(channelserver): migrate remaining character queries to CharacterRepository
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.
2026-02-20 21:57:24 +01:00
Houmgaor
d5c44b5557 docs: mark binary I/O and copy-paste anti-patterns as resolved
Binary I/O (#5): all 12 remaining encoding/binary calls are
legitimate (zero-alloc spot-reads, random-access into game blobs).
Copy-paste handlers (#8): loadCharacterData/saveCharacterData helpers
now cover standard blob patterns.

Also upgrades saveCharacterData to send doAckSimpleFail on oversize
payloads and DB errors, and migrates handleMsgMhfSaveScenarioData
to the improved helper.
2026-02-20 20:55:06 +01:00
Houmgaor
24ccc167fe fix(channelserver): add fail ACKs to silent error paths to prevent client softlocks
Handlers that log errors and return without sending a MsgSysAck leave
the client waiting indefinitely. Add doAckSimpleFail/doAckBufFail to
14 error paths across 4 files, matching the pattern already used in
~70 other error paths across the codebase.

Affected handlers:
- handleMsgMhfGetCafeDuration (1 path)
- handleMsgMhfSavedata (1 path)
- handleMsgMhfArrangeGuildMember (3 paths)
- handleMsgMhfEnumerateGuildMember (5 paths)
- handleMsgSysLogin (4 paths)
- handleMsgSysIssueLogkey (1 path)
2026-02-20 19:35:25 +01:00
Houmgaor
d32e77efba refactor: replace panic calls with structured error handling
Replace ~25 panic() calls in non-fatal code paths with proper
s.logger.Error + return patterns. Panics in handler code crashed
goroutines (caught by defer/recover but still disruptive) instead
of failing gracefully.

Key changes:
- SJISToUTF8 now returns (string, error); all 30+ callers updated
- Handler DB/IO panics replaced with log + return/ack fail
- Unhandled switch-case panics replaced with logger.Error
- Sign server Accept() panic replaced with log + continue
- Dead unreachable panic in guild_model.go removed
- deltacomp patch error logs and returns partial data

Panics intentionally kept: ByteFrame sentinel, unimplemented
packet stubs, os.Exit in main.go.
2026-02-20 19:11:41 +01:00
Houmgaor
5f3c843082 refactor(config): eliminate ErupeConfig global variable
Replace the mutable global `_config.ErupeConfig` with dependency
injection across 79 files. Config is now threaded through existing
paths: `ClientContext.RealClientMode` for packet encoding, `s.server.
erupeConfig` for channel handlers, and explicit parameters for utility
functions. This removes hidden coupling, enables test parallelism
without global save/restore, and prevents low-level packages from
reaching up to the config layer.

Key changes:
- Enrich ClientContext with RealClientMode for packet files
- Add mode parameter to CryptConn, mhfitem, mhfcourse functions
- Convert handlers_commands init() to lazy sync.Once initialization
- Delete global var, init(), and helper functions from config.go
- Update all tests to pass config explicitly
2026-02-20 17:07:42 +01:00
Houmgaor
c2eba51b29 fix(channelserver): add max-size guards to binary blob save handlers
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
2026-02-19 00:28:28 +01:00
Houmgaor
e353906e1c refactor(channelserver): split handlers_data.go into sub-files
Separate the 1,580-line handlers_data.go into three focused files:
- handlers_data.go (~210 lines): character save/load handlers
- handlers_data_paper.go (~616 lines): tower/paper types and handler
- handlers_data_paper_tables.go (~765 lines): paperGiftData reward map

Mirrors the earlier handlers_guild.go split pattern.
2026-02-18 00:47:14 +01:00
Houmgaor
c64dabc3ba fix: check all Close() return values for errcheck lint
Add explicit error discards (_ =) for Close() calls on network
connections, SQL rows, and file handles across 28 files. Also add
.golangci.yml with standard linter defaults to match CI configuration.
2026-02-17 23:57:14 +01:00
Houmgaor
47f7a1f636 fix(channelserver): handle bare Exec errors and filter expected ErrNoRows
138 bare db.Exec calls across 22 handler files silently dropped write
errors. Each is now wrapped with error check and zap logging.

4 QueryRow sites that legitimately return sql.ErrNoRows during normal
operation (new player mezfes, festa rankings, empty guild item box)
now filter it out to reduce log noise.
2026-02-17 23:33:44 +01:00
Houmgaor
46bbb6adf9 fix: resolve all remaining lint errors (errcheck) across 49 files
Fix unchecked error returns on bf.Seek(), db.Exec(), QueryRow().Scan(),
pkt.Build(), logger.Sync(), and binary.Write() calls. The linter now
passes with 0 errors, build compiles, and all tests pass with -race.
2026-02-17 18:07:38 +01:00
Houmgaor
18592c5ded fix(handlers): trying to fix issues with incomplete saves. 2025-10-31 13:10:17 +01:00
Houmgaor
1398383a8d fix(lint): automated linting, with simple formatter. 2025-10-19 22:43:05 +02:00
Houmgaor
8a92a7957e fix(crashes): trying to investigate the causes of crash.
New unit tests to that end.
2025-10-19 19:02:29 +02:00
wish
4eed6a9738 add playtime chat command 2024-11-09 18:20:49 +11:00
wish
0b3e1f520f use Monster enum on GetPaperData 2024-02-19 17:34:08 +11:00
wish
377ff14a22 use Monster enum on GetPaperData 2024-02-19 17:34:01 +11:00
wish
0ea0dc217b simplify config 2023-12-31 12:51:24 +11:00
wish
5662564842 add option to dump raw saves 2023-12-03 17:57:23 +11:00
wish
e75a77e6b8 optimise grpToGR 2023-10-28 11:55:06 +11:00
wish
8abefd7441 fix null LoadScenarioData response 2023-10-28 11:53:53 +11:00
wish
d0431fbc1c ignore name-checker if using Season modes 2023-10-02 23:13:19 +11:00
wish
872459e7bd fix dumpSaveData not recursively creating folders 2023-07-30 22:39:31 +10:00
wish
1169684e5b remove test PaperMission data 2023-07-01 12:53:17 +10:00
wish
586ae8b388 add comment descriptions for PaperData 2023-06-25 21:44:59 +10:00
wish
0929592110 rework PaperData 2023-06-19 22:43:07 +10:00
wish
7d884da938 replace deprecated code 2023-03-31 00:04:51 +11:00
wish
c718e9a5a7 fix various packet responses 2023-02-12 14:04:16 +11:00
Yarg-mirror
3afaba5193 Update handlers_data.go
Under Windows: no change
Under Linux: Fix directory creation with no read/write permissions that failed the creation of save data dump
2023-02-04 14:32:10 +11:00
wish
e6845d74d0 make various handlers not error fatally 2023-02-04 14:29:28 +11:00
wish
218693ef40 clean up various save handlers 2023-02-02 21:08:09 +11:00
wish
d5e69aa83c fix handling new characters 2023-01-05 01:20:54 +11:00
wish
0774518eeb handle unnamed new characters 2023-01-04 10:47:24 +11:00
wish
9234d82110 add option to flag corruption attempted saves as deleted 2022-12-23 23:18:00 +11:00
wish
7676f2e7d5 terminate session on save corruption 2022-12-23 23:12:01 +11:00
wish
4a7cde77ea fix nil StrConv on save 2022-11-01 10:49:28 +11:00
wish
6ee9234745 fix various savedata bugs 2022-10-08 13:59:48 +11:00
wish
d9541a6d1a rewrite dumpSaveData 2022-10-05 13:33:14 +11:00
wish
128f375cd2 dump savedata without name 2022-09-10 22:43:23 +10:00
wish
616d58e70e dump other savedata types 2022-09-05 15:29:24 +10:00
wish
6c9e39a5cd fix savedata bugs 2022-09-04 15:52:50 +10:00
wish
90314fa411 rework savedata 2022-09-04 03:19:32 +10:00
wish
6e7259a068 dump more save data types to backup 2022-08-19 19:46:55 +10:00