
OPShield
Protects your server from OP/admin abuse with console-only OP (via password) and optional admin command restriction.
193
1
Список изменений
[1.9.1] - 2026-05-23 — Bug Fix Release
This is a patch release that resolves six bugs identified through code review.
No configuration keys were added, removed, or renamed. Existing data.yml and
config.yml files are fully compatible — no migration needed.
🐛 Bug Fixes
FIX [Critical] — Double timestamp in every audit log entry
- Root cause:
OPShield.audit()manually prepended a formatted timestamp to the message string before passing it toAuditLogger.log(). However,AuditLogger.buildLine()also wraps every line with its own timestamp, resulting in output like:
This affected every audit entry since v1.6.0.[2026-05-23 10:00:00] 2026-05-23 10:00:00 | Configuration reloaded. - Fix: Removed the manual timestamp construction from
OPShield.audit(). Timestamp formatting is now owned exclusively byAuditLogger.buildLine(). Audit lines now read correctly:[2026-05-23 10:00:00] Configuration reloaded. - Impact: Existing rotated log files (
audit.log.1etc.) retain the old double-timestamp format. New entries written after the upgrade are clean. No action required on existing files.
FIX [High] — auth_session_granted and auth_session_active messages were never sent
- Root cause: The language key
auth_session_grantedwas introduced in v1.9.0 but the correspondingsend()call was absent from bothcompletePrivilegeCommand()(session grant path) andhandlePrivilegeCommand()(session reuse path). Players had no way to know a session existed or how much time remained. - Fix:
completePrivilegeCommand()now callssendReplaced(player, "auth_session_granted", "minutes", …)immediately after the session is stored inauthenticatedSessions.handlePrivilegeCommand()now callssendReplaced(player, "auth_session_active", "minutes", …)(with the remaining minutes) on the session-reuse fast-path.
- New language key:
auth_session_activeadded toen.yml,vn.yml, andru.yml.
FIX [Medium] — Shadow-ban decoy messages lost all colour formatting
- Root cause: The fake-success message pipeline was:
PlainTextComponentSerializer.plainText().serialize(colorize(fakeMsg))colorize()correctly parsed&a,&c, etc. into an AdventureComponentwith colour, butPlainTextComponentSerializer.plainText().serialize()then stripped every colour code before wrapping the result in a hard-codedNamedTextColor.YELLOW. Language-file formatting was silently discarded. - Fix: Removed the unnecessary serialise/re-wrap chain. The
Componentreturned bycolorize(fakeMsg)is now sent directly:
Server owners can now apply any Adventure-compatible colour codes (player.sendMessage(colorize(fakeMsg));&a,&c,&l, etc.) in their language files and have them rendered correctly. - Cleanup: Removed now-unused imports
NamedTextColor,PlainTextComponentSerializer, andComponentfromOPShield.java.
FIX [Medium] — LockoutManager.cleanupExpired() discarded backoff count earlier than count_decay_hours intended
- Root cause:
cleanupExpired()removed any record whoseexpiryMs <= nowANDattempts == 0. When a lockout expired naturally,isLockedOut()setexpiryMs = 0andattempts = 0(intentionally preservingcountfor exponential backoff). On the very next cleanup tick (≤ 60 s later), the cleanup predicate matched and deleted the entire record, includingcount. Thesecurity.lockout.count_decay_hoursconfig key had no practical effect: the backoff counter was always reset within one cleanup cycle after each lockout expired. - Fix:
cleanupExpired()now accepts adecayMsparameter (derived fromlockoutDecayHoursinOPShield). A record is only removed when both conditions are true:- No active lockout and no in-progress attempts.
- The time elapsed since
lastLockoutAtMsexceedsdecayMs. Exponential backoff now behaves as documented.
- API change (internal):
LockoutManager.cleanupExpired()→cleanupExpired(long decayMs). No external callers; internal call site updated inOPShield.cleanupRuntimeState().
FIX [Medium] — /opshield reload blocked by allow_op_reload: false even for players with explicit opshield.reload permission
- Root cause: In
handleManagementCommand(), theallow_op_reloadflag was evaluated before the permission check. A player with an explicitopshield.reloadgrant from a permissions plugin was still denied whenallow_op_reload: false, making the permission effectively meaningless. - Fix: The permission check (
opshield.reload) now runs first. Theallow_op_reloadflag is applied only as a secondary restriction after the caller is confirmed to hold the permission. Console senders are unaffected.
FIX [Low] — IP tracking unreliable behind BungeeCord / Velocity (documentation + debug warning)
- Root cause:
getPlayerIpRaw()usesplayer.getAddress().getAddress().getHostAddress(). Behind a proxy, this resolves to the proxy's own address (commonly127.0.0.1or a private RFC-1918 range), not the connecting client's real IP. IP-based lockout mirroring andip_limittracking silently group all players under the same key. - Fix (partial): Full proxy-IP forwarding requires server-side configuration
outside the plugin's scope (Paper IP forwarding,
BungeeGuard, etc.). This release adds a debug-mode warning logged whendebug: trueand the resolved address is a loopback or private-range address, so administrators are alerted during setup. The warning is suppressed in production (debug: false) to avoid console spam on legitimate LAN servers.
🌍 Language File Changes
| Key | Files | Change |
|---|---|---|
auth_session_active | en.yml, vn.yml, ru.yml | Added — shown when an existing valid session is reused |
All other keys are unchanged and backwards-compatible.
🔧 Internal / Code Quality
- Removed four now-unused imports from
OPShield.java:LocalDateTime,ZoneId,Instant,DateTimeFormatter(timestamp moved toAuditLogger),Component,NamedTextColor,PlainTextComponentSerializer(shadow-ban message fix). LockoutManager.cleanupExpired()signature updated (internal only).- Added inline
FIX[…]comments at every corrected site for audit trail.
✅ Compatibility
| Item | Status |
|---|---|
config.yml (v1.9.0) | ✅ No changes required |
data.yml (v1.9.0) | ✅ No changes required |
| Language files (v1.9.0) | ⚠️ auth_session_active key added; old files work but players will see [Missing Message: auth_session_active] until updated |
| Paper API | ✅ 1.21+ (unchanged) |
Метаданные
Канал релиза
Release
Номер версии
1.9.1
Загрузчики
BukkitPaperPurpurSpigot
Версии игры
1.21–1.21.11
Загрузок
25
Дата публикации
3 нед. назад
