feat(config): add DisableSaveIntegrityCheck flag for save transfers

The SHA-256 integrity check introduced in migration 0007 blocks saves
when a character's savedata blob is imported from another server instance,
because the stored hash in the target DB no longer matches the new blob.

Adding DisableSaveIntegrityCheck (default: false) lets server operators
bypass the check to unblock cross-server save transfers. A warning is
logged each time the check is skipped so the flag's use is auditable.

Documents the per-character SQL alternative in CHANGELOG:
  UPDATE characters SET savedata_hash = NULL WHERE id = <id>

Closes #183.
This commit is contained in:
Houmgaor
2026-03-21 19:38:16 +01:00
parent 0911d15709
commit 0ea399f135
8 changed files with 83 additions and 5 deletions

View File

@@ -55,7 +55,8 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
// Verify integrity checksum if one was stored with this save.
// A nil hash means the character was saved before checksums were introduced,
// so we skip verification (the next save will compute and store the hash).
if storedHash != nil {
// DisableSaveIntegrityCheck bypasses this entirely for cross-server save transfers.
if storedHash != nil && !s.server.erupeConfig.DisableSaveIntegrityCheck {
computedHash := sha256.Sum256(saveData.decompSave)
if !bytes.Equal(storedHash, computedHash[:]) {
s.logger.Error("Savedata integrity check failed: hash mismatch",
@@ -66,6 +67,10 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
// TODO: attempt recovery from savedata_backups here
return nil, errors.New("savedata integrity check failed")
}
} else if storedHash != nil && s.server.erupeConfig.DisableSaveIntegrityCheck {
s.logger.Warn("Savedata integrity check skipped (DisableSaveIntegrityCheck=true)",
zap.Uint32("charID", charID),
)
}
saveData.updateStructWithSaveData()