All versions
1.8.0
Release
OPShield 1.8.06 months ago 25
Compatibility
Minecraft: Java Edition
1.21.x
Platforms
Bukkit
Paper
Purpur
Spigot
Changes
[1.8.0] - 2026-04-28 — Manager Refactor, Security Hardening & Quality Improvements
🔒 Security Fixes
CRITICAL — Permission Default Changed
opshield.admindefault changed fromop→false(breaking if you relied on implicit OP grants)- Previously any player with OP status automatically received full OPShield admin rights
- Now all permissions must be explicitly granted via a permission plugin (e.g. LuckPerms)
- Migration: add
opshield.adminto your OP group in your permission plugin
- All child permissions (
opshield.reload,opshield.unlock,opshield.op,opshield.deop) default changed fromop→falsefor the same reason - Added
opshield.*wildcard permission for convenience
🏗️ Architecture Improvements
LockoutManager — Full Refactor
- Introduced
LockoutRecordinner class consolidating 5 separateConcurrentHashMaps (failedAttempts, lockoutTimestamps, lockoutCount, lastLockoutAt) into a single per-key object - Decay logic moved entirely into
LockoutManager.recordFailure()— no longer split between main class and manager - Added
mirrorLockout()for IP-mirrored lockouts (called by OPShield whentrack_ip=true) - Added
exportSnapshot()/importSnapshot()for clean persistence without raw map access - Backwards-compatible persistence: v1.8.0 reads legacy v1.7.0 data format and migrates automatically
LockoutManageris now the single source of truth for all lockout state
ShadowBanManager — Full Refactor
- Shadow-ban levels now owned by
ShadowBanManager(previously a rawConcurrentHashMapinOPShield.java) getFakeMessage()is no longer static; it accepts aMessageProviderfunctional interface so messages come from language files, not hard-coded strings- Added
shouldEscalate(key, threshold)method — clearly separates the "should I punish?" decision from execution - Added
exportLevels()/importLevels()for persistence - Extended command keyword → message-key mapping: now covers
op,deop,kick,stop,reload,pardon
OPShield.java — Reduced God Class Burden
- Replaced 5 raw state maps with delegation to
LockoutManager - Replaced
playerShadowBanLevelmap with delegation toShadowBanManager - Added
/opshield statuscommand for runtime diagnostics (shows active levels, flagged IPs, queue sizes) - Added
debugLog()helper — controlled bydebug: falseconfig key; never exposes sensitive info in production
✨ New Features
debugmode (debug: falsein config.yml) — enables verbose internal logging for troubleshooting without recompiling/opshield status— new sub-command withopshield.statuspermission; reports shadow-ban level count, flagged IPs, sensitive-history windows, auto-punishment statesecurity.password.auto_upgrade_legacy_hash: true— automatically re-hashes a legacy SHA-256 password to PBKDF2 the next time the correct password is provided; hash is saved to config.yml with no manual action required- Audit queue capacity (
audit.max_queue_size: 10000) — prevents unbounded memory growth if disk writes fail; oldest entries dropped with a console warning (rate-limited to once per flush cycle) - Audit JSON format (
audit.format: json) — emits one machine-readable JSON object per line for log aggregator ingestion;plainformat unchanged for backwards compatibility
🐛 Bug Fixes
ShadowBanManager.getFakeActionMessage()was never called — v1.7.0 added it but the main class still used hard-coded logic. Now the manager is the sole source of fake messagesLockoutManager.ipLimitMapwas unused —recordIpConnection()was called but the data was never read. Removed; IP limit tracking remains in OPShield.java pendingIpLimitManagerextractionPasswordHasher.upgradeHashIfNeeded()(NEW) —isLegacyHash()existed in 1.7.0 but there was no code path to actually upgrade the stored hash. Now the main class callsupgradeHashIfNeeded()after each successful login whenauto_upgrade_legacy_hash: trueHASH_FORMAT_VERSIONconstant (NEW) — the string"pbkdf2"was scattered as a magic literal acrossPasswordHasher; centralised to a named constant
🔧 Build Improvements
maven-compiler-plugin 3.13.0added with explicit<release>21</release>and<parameters>flagmaven-shade-plugin 3.6.0added (no relocations yet, but scaffold is ready for future bundled deps)maven-surefire-plugin 3.2.5added with JUnit 5 + Mockito test dependencies for unit testing managers- Centralised version properties —
java.version,paper.version, and plugin versions now all defined in<properties>for consistency
📝 Configuration
- Added
config-version: 2— allows future automatic migration detection - Added
debug: false— verbose diagnostic logging toggle - Added
security.password.auto_upgrade_legacy_hash: true - Added
audit.max_queue_size: 10000 - Added
audit.format: plain - Added
shadow_ban.auto_punish_leveldefault raised from3→5 - Added inline "Recommended values by server size" comments to
config.yml
🌍 Language Files
- Added 7 new shadow-fake message keys:
shadow_fake_op,shadow_fake_deop,shadow_fake_kick,shadow_fake_pardon,shadow_fake_stop,shadow_fake_reload(all three languages) - Fixed inconsistent Vietnamese translations in
vn.yml - All three language files now use natural-language fake messages that better blend in with real server output
📊 Code Quality Metrics
| Metric | v1.7.0 | v1.8.0 |
|---|---|---|
| Raw state maps in OPShield.java | 7 | 3 |
| Manager classes | 2 (stub) | 2 (fully active) |
Permissions with insecure default op |
6 | 0 |
| Hard-coded fake messages | 8 | 0 |
| Unused manager methods | 2 | 0 |
config-version |
❌ | ✅ |
| Debug mode | ❌ | ✅ |
| Audit queue cap | ❌ | ✅ |
| JSON audit format | ❌ | ✅ |
📝 Migration Notes
- Permission plugin setup required — add
opshield.adminto your OP group (see CRITICAL note above) - data.yml is auto-migrated from v1.7.0 format on first boot — no manual action needed
- All configuration keys are backwards-compatible; new keys use sensible defaults
- Old
lockout_timestamps/failed_attempts/lockout_count/last_lockout_atsections indata.ymlare read on upgrade and merged intolockout_records; old sections are replaced on next save
🔮 Planned for v1.9.0
- Extract
AutoPunishmentManager— move all ban/kick/firewall logic out ofOPShield.java - Extract
IpLimitManager— move IP tracking and flagging - Extract
CommandRestrictionManager— movematchesConfiguredCommandlogic - Add unit tests for
LockoutManagerandShadowBanManager - Consider Argon2id as an optional stronger hashing algorithm
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:Bv67n40d:ofhF9x1g"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:Bv67n40d:ofhF9x1g"
}

