├── .editorconfig
├── .gitattributes
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── README.md
├── SECURITY.md
├── dependabot.yml
└── workflows
│ └── gradle.yml
├── .gitignore
├── HEADER
├── LICENSE
├── api
├── build.gradle.kts
└── src
│ └── main
│ └── java
│ └── xyz
│ └── jonesdev
│ └── sonar
│ └── api
│ ├── Sonar.java
│ ├── SonarPlatform.java
│ ├── SonarSupplier.java
│ ├── SonarVersion.java
│ ├── command
│ ├── InvocationSource.java
│ ├── SonarCommand.java
│ └── subcommand
│ │ ├── Subcommand.java
│ │ ├── SubcommandInfo.java
│ │ └── SubcommandRegistry.java
│ ├── config
│ ├── Language.java
│ ├── SimpleYamlConfig.java
│ └── SonarConfiguration.java
│ ├── database
│ ├── controller
│ │ └── VerifiedPlayerController.java
│ ├── model
│ │ └── VerifiedPlayer.java
│ └── ormlite
│ │ ├── H2DatabaseTypeAdapter.java
│ │ ├── MariaDbDatabaseTypeAdapter.java
│ │ └── MysqlDatabaseTypeAdapter.java
│ ├── event
│ ├── SonarEvent.java
│ ├── SonarEventListener.java
│ ├── SonarEventManager.java
│ └── impl
│ │ ├── AttackDetectedEvent.java
│ │ ├── AttackMitigatedEvent.java
│ │ ├── CaptchaGenerationEndEvent.java
│ │ ├── CaptchaGenerationStartEvent.java
│ │ ├── UserBlacklistedEvent.java
│ │ ├── UserVerifyFailedEvent.java
│ │ ├── UserVerifyJoinEvent.java
│ │ └── UserVerifySuccessEvent.java
│ ├── fallback
│ ├── Fallback.java
│ ├── FallbackLoginQueue.java
│ ├── FallbackPipelines.java
│ ├── FallbackUser.java
│ ├── captcha
│ │ └── CaptchaGenerator.java
│ ├── protocol
│ │ └── ProtocolVersion.java
│ └── ratelimit
│ │ └── Ratelimiter.java
│ ├── fingerprint
│ └── FingerprintingUtil.java
│ ├── logger
│ └── LoggerWrapper.java
│ ├── notification
│ ├── ActionBarNotificationHandler.java
│ ├── ChatNotificationHandler.java
│ └── NotificationHandler.java
│ ├── profiler
│ └── SimpleProcessProfiler.java
│ ├── statistics
│ └── SonarStatistics.java
│ ├── timer
│ └── SystemTimer.java
│ ├── tracker
│ └── AttackTracker.java
│ ├── update
│ └── UpdateChecker.java
│ └── webhook
│ └── DiscordWebhook.java
├── build.gradle.kts
├── bukkit
├── build.gradle.kts
└── src
│ └── main
│ └── java
│ └── xyz
│ └── jonesdev
│ └── sonar
│ └── bukkit
│ ├── SonarBukkit.java
│ ├── SonarBukkitPlugin.java
│ ├── command
│ └── BukkitSonarCommand.java
│ ├── fallback
│ ├── BukkitServerVersion.java
│ ├── ChannelInactiveListener.java
│ ├── FallbackBukkitInboundHandler.java
│ └── FallbackBukkitInjector.java
│ └── listener
│ └── BukkitJoinListener.java
├── bungeecord
├── build.gradle.kts
└── src
│ └── main
│ └── java
│ └── xyz
│ └── jonesdev
│ └── sonar
│ └── bungee
│ ├── SonarBungee.java
│ ├── SonarBungeePlugin.java
│ ├── command
│ └── BungeeSonarCommand.java
│ └── fallback
│ ├── FallbackBungeeInboundHandler.java
│ └── FallbackBungeeInjector.java
├── captcha
├── build.gradle.kts
└── src
│ ├── main
│ ├── java
│ │ └── xyz
│ │ │ └── jonesdev
│ │ │ └── sonar
│ │ │ └── captcha
│ │ │ ├── StandardCaptchaGenerator.java
│ │ │ ├── StandardTTFFontProvider.java
│ │ │ ├── filters
│ │ │ ├── CircleInverseFilter.java
│ │ │ ├── CurvesOverlayFilter.java
│ │ │ ├── GridOverlayFilter.java
│ │ │ └── NoiseOverlayFilter.java
│ │ │ └── legacy
│ │ │ ├── LegacyCaptchaGenerator.java
│ │ │ ├── RippleFilter.java
│ │ │ └── ScratchFilter.java
│ └── resources
│ │ └── assets
│ │ └── fonts
│ │ └── Kingthings_Trypewriter_2.ttf
│ └── test
│ └── java
│ └── Main.java
├── common
├── build.gradle.kts
└── src
│ └── main
│ ├── java
│ └── xyz
│ │ └── jonesdev
│ │ └── sonar
│ │ └── common
│ │ ├── boot
│ │ ├── LibraryLoader.java
│ │ └── SonarBootstrap.java
│ │ ├── fallback
│ │ ├── FallbackBandwidthHandler.java
│ │ ├── FallbackInboundHandler.java
│ │ ├── FallbackInboundHandlerAdapter.java
│ │ ├── FallbackUserWrapper.java
│ │ ├── netty
│ │ │ ├── FallbackInjectedChannelInitializer.java
│ │ │ ├── FallbackTailExceptionsHandler.java
│ │ │ ├── FallbackTimeoutHandler.java
│ │ │ ├── FallbackVarInt21FrameDecoder.java
│ │ │ └── FallbackVarIntLengthEncoder.java
│ │ ├── protocol
│ │ │ ├── CaptchaPreparer.java
│ │ │ ├── FallbackPacket.java
│ │ │ ├── FallbackPacketDecoder.java
│ │ │ ├── FallbackPacketEncoder.java
│ │ │ ├── FallbackPacketListener.java
│ │ │ ├── FallbackPacketRegistry.java
│ │ │ ├── FallbackPacketSnapshot.java
│ │ │ ├── FallbackPreparer.java
│ │ │ ├── block
│ │ │ │ ├── BlockType.java
│ │ │ │ └── BlockUpdate.java
│ │ │ ├── dimension
│ │ │ │ ├── DimensionRegistry.java
│ │ │ │ └── DimensionType.java
│ │ │ ├── entity
│ │ │ │ └── EntityType.java
│ │ │ ├── item
│ │ │ │ └── ItemType.java
│ │ │ ├── map
│ │ │ │ ├── MapCaptchaInfo.java
│ │ │ │ └── MapColorPalette.java
│ │ │ └── packets
│ │ │ │ ├── configuration
│ │ │ │ ├── FinishConfigurationPacket.java
│ │ │ │ └── RegistryDataPacket.java
│ │ │ │ ├── handshake
│ │ │ │ └── HandshakePacket.java
│ │ │ │ ├── login
│ │ │ │ ├── LoginAcknowledgedPacket.java
│ │ │ │ ├── LoginStartPacket.java
│ │ │ │ └── LoginSuccessPacket.java
│ │ │ │ └── play
│ │ │ │ ├── AnimationPacket.java
│ │ │ │ ├── ChunkDataPacket.java
│ │ │ │ ├── ClientInformationPacket.java
│ │ │ │ ├── ClientTickEndPacket.java
│ │ │ │ ├── ConfirmTeleportationPacket.java
│ │ │ │ ├── DisconnectPacket.java
│ │ │ │ ├── EntityAnimationPacket.java
│ │ │ │ ├── GameEventPacket.java
│ │ │ │ ├── JoinGamePacket.java
│ │ │ │ ├── KeepAlivePacket.java
│ │ │ │ ├── MapDataPacket.java
│ │ │ │ ├── PaddleBoatPacket.java
│ │ │ │ ├── PlayerAbilitiesPacket.java
│ │ │ │ ├── PlayerInputPacket.java
│ │ │ │ ├── PluginMessagePacket.java
│ │ │ │ ├── RemoveEntitiesPacket.java
│ │ │ │ ├── SetContainerSlotPacket.java
│ │ │ │ ├── SetDefaultSpawnPositionPacket.java
│ │ │ │ ├── SetExperiencePacket.java
│ │ │ │ ├── SetHeldItemPacket.java
│ │ │ │ ├── SetPassengersPacket.java
│ │ │ │ ├── SetPlayerOnGround.java
│ │ │ │ ├── SetPlayerPositionPacket.java
│ │ │ │ ├── SetPlayerPositionRotationPacket.java
│ │ │ │ ├── SetPlayerRotationPacket.java
│ │ │ │ ├── SpawnEntityPacket.java
│ │ │ │ ├── SystemChatPacket.java
│ │ │ │ ├── TransactionPacket.java
│ │ │ │ ├── TransferPacket.java
│ │ │ │ ├── UpdateSectionBlocksPacket.java
│ │ │ │ ├── UpdateTimePacket.java
│ │ │ │ └── VehicleMovePacket.java
│ │ ├── ratelimit
│ │ │ ├── CaffeineCacheRatelimiter.java
│ │ │ └── NoopCacheRatelimiter.java
│ │ └── verification
│ │ │ ├── FallbackCaptchaHandler.java
│ │ │ ├── FallbackGravityHandler.java
│ │ │ ├── FallbackPreJoinHandler.java
│ │ │ ├── FallbackProtocolHandler.java
│ │ │ ├── FallbackVehicleHandler.java
│ │ │ └── FallbackVerificationHandler.java
│ │ ├── service
│ │ └── ScheduledServiceManager.java
│ │ ├── statistics
│ │ └── GlobalSonarStatistics.java
│ │ ├── subcommand
│ │ ├── BlacklistCommand.java
│ │ ├── DumpCommand.java
│ │ ├── NotifyCommand.java
│ │ ├── ReloadCommand.java
│ │ ├── StatisticsCommand.java
│ │ ├── VerboseCommand.java
│ │ └── VerifiedCommand.java
│ │ └── util
│ │ ├── ComponentHolder.java
│ │ ├── FakeChannelUtil.java
│ │ ├── FastUuidSansHyphens.java
│ │ ├── GeyserUtil.java
│ │ ├── ProtocolUtil.java
│ │ └── exception
│ │ ├── QuietDecoderException.java
│ │ └── ReflectiveOperationException.java
│ └── resources
│ └── assets
│ ├── codecs
│ ├── codec_1_16.nbt
│ ├── codec_1_16_2.nbt
│ ├── codec_1_18_2.nbt
│ ├── codec_1_19.nbt
│ ├── codec_1_19_1.nbt
│ ├── codec_1_19_4.nbt
│ ├── codec_1_20.nbt
│ ├── codec_1_20_5.nbt
│ ├── codec_1_21.nbt
│ ├── codec_1_21_2.nbt
│ ├── codec_1_21_4.nbt
│ └── codec_1_21_5.nbt
│ ├── config
│ ├── cs.yml
│ ├── de.yml
│ ├── en.yml
│ ├── fr.yml
│ ├── ka.yml
│ ├── nl.yml
│ ├── pl.yml
│ ├── pt-br.yml
│ ├── ru.yml
│ └── zh.yml
│ ├── language.properties
│ ├── messages
│ ├── cs.yml
│ ├── de.yml
│ ├── en.yml
│ ├── es.yml
│ ├── fr.yml
│ ├── id.yml
│ ├── ka.yml
│ ├── nl.yml
│ ├── pl.yml
│ ├── pt-br.yml
│ ├── ru.yml
│ ├── tr.yml
│ └── zh.yml
│ └── webhook
│ ├── cs.yml
│ ├── de.yml
│ ├── en.yml
│ ├── es.yml
│ ├── fr.yml
│ ├── id.yml
│ ├── ka.yml
│ ├── nl.yml
│ ├── pl.yml
│ ├── pt-br.yml
│ ├── ru.yml
│ └── zh.yml
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── lombok.config
├── settings.gradle.kts
└── velocity
├── build.gradle.kts
└── src
└── main
├── java
└── xyz
│ └── jonesdev
│ └── sonar
│ └── velocity
│ ├── SonarVelocity.java
│ ├── SonarVelocityPlugin.java
│ ├── command
│ └── VelocitySonarCommand.java
│ └── fallback
│ ├── FallbackVelocityInboundHandler.java
│ └── FallbackVelocityInjector.java
└── resources
└── velocity-plugin.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [**]
4 | charset = UTF-8
5 | indent_style = space
6 | indent_size = 2
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.java]
11 | ij_java_wrap_long_lines = true
12 |
13 | [{*.md,*.yml}]
14 | indent_style = unset
15 | insert_final_newline = unset
16 | trim_trailing_whitespace = unset
17 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Credits to https://github.com/alexkaratarakis/gitattributes/blob/master/Java.gitattributes
5 | # Java sources
6 | *.java text diff=java
7 | *.kt text diff=kotlin
8 | *.groovy text diff=java
9 | *.scala text diff=java
10 | *.gradle text diff=java
11 | *.gradle.kts text diff=kotlin
12 |
13 | # These files are binary and should be left untouched
14 | # (binary is a macro for -text -diff)
15 | *.class binary
16 | *.dll binary
17 | *.ear binary
18 | *.jar binary
19 | *.so binary
20 | *.war binary
21 | *.jks binary
22 |
23 | # Common build-tool wrapper scripts ('.cmd' versions are handled by 'Common.gitattributes')
24 | gradlew text eol=lf
25 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Before you start contributing, please take a moment to review our contributing guidelines.
2 | If you can't contribute but like the project, feel free to show your support by starring the project on GitHub or
3 | joining the [Discord](https://jonesdev.xyz/discord).
4 |
5 | ## Contributing Guidelines:
6 |
7 | 1. Fork the repository and create a new branch for your contribution.
8 | 2. Follow the coding guidelines for your code.
9 | 3. Test your code before committing and pushing it.
10 | 4. Use [semantic](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) commit messages for your commits.
11 |
12 | ## Coding Guidelines:
13 |
14 | - Use the same code style and formatting as the rest of the project.
15 | - Optional: Use an IDE that supports .editorconfig files.
16 | - Use meaningful names for variables, classes, and methods.
17 | - Write clear comments to explain complex parts of your code.
18 | - Ensure your code is easy to read and maintain.
19 |
20 | ## Bug Reports:
21 |
22 | 1. Check if someone has already reported the bug.
23 | 2. If not, open a new issue with a clear and detailed title.
24 | 3. Describe the bug, including the steps to reproduce it.
25 | 4. Include all logs related to the issue.
26 | 5. Provide the output of '/sonar dump'.
27 | 6. Feel free to provide any additional information.
28 |
29 | ## Feature Requests:
30 |
31 | 1. Check if someone has already made the same request.
32 | 2. If not, open a new issue with a clear and detailed title.
33 | 3. Explain the feature you want to see in Sonar and provide an example.
34 | 4. Explain why you want to see the feature in Sonar.
35 | 5. Feel free to provide any additional information.
36 |
37 | ## Pull Requests:
38 |
39 | - Use a clear and descriptive title for your pull request.
40 | - Provide a detailed description of the changes you made.
41 | - Reference related issues or pull requests.
42 | - Make sure everything is properly tested.
43 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: jonesdev
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Report bugs to improve security, stability and usability
3 | title: "Bug Report"
4 | labels: ["bug"]
5 |
6 | assignees: []
7 |
8 | body:
9 | - type: textarea
10 | id: info_and_expected_outcome
11 | attributes:
12 | label: "General information"
13 | description: |
14 | Describe the bug and the expected outcome.
15 | validations:
16 | required: true
17 |
18 | - type: textarea
19 | id: steps_to_reproduce
20 | attributes:
21 | label: "Steps to reproduce"
22 | description: |
23 | Please provide a short list of steps you need to do to reproduce the issue.
24 | placeholder: |
25 | 1. Join the server [...]
26 | 2. ...
27 | validations:
28 | required: true
29 |
30 | - type: textarea
31 | id: sonar_dump
32 | attributes:
33 | label: "Sonar dump"
34 | description: "Please provide the output of the command /sonar dump"
35 | validations:
36 | required: true
37 |
38 | - type: textarea
39 | id: additional_information
40 | attributes:
41 | label: "Additional information"
42 | description: |
43 | Is there any additional information you would like to provide?
44 | validations:
45 | required: false
46 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Documentation
4 | url: https://docs.jonesdev.xyz/
5 | about: Need help configuring Sonar or have questions regarding the installation and usage?
6 | - name: Discord
7 | url: https://jonesdev.xyz/discord/
8 | about: If you have any further questions, please feel free to join the Discord server and open a ticket.
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Suggest a feature to improve the plugin
3 | title: "Feature Request"
4 | labels: ["enhancement"]
5 |
6 | assignees: []
7 |
8 | body:
9 | - type: textarea
10 | id: general
11 | attributes:
12 | label: "Information"
13 | description: |
14 | Please provide some information about the feature you would like to be implemented.
15 | Is it related to an existing problem/bug/issue?
16 | Are there any screenshots or videos showcasing the feature to better understand your request?
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | id: reason
22 | attributes:
23 | label: "Reason"
24 | description: |
25 | Is there a specific reason why you would like this feature to be implemented?
26 | validations:
27 | required: true
28 |
29 | - type: textarea
30 | id: additional
31 | attributes:
32 | label: "Additional information"
33 | description: |
34 | Is there any additional information you would like to provide?
35 | validations:
36 | required: false
37 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | ## Reporting a security vulnerability
2 |
3 | If you encounter a bug, issue, or vulnerability that doesn't pose an immediate security risk, you can report it through the regular issue tracker.
4 |
5 | If you discover a security vulnerability within Sonar, please follow these steps to report it:
6 | 1. Do not disclose serious issues publicly before they are fixed.
7 | 2. Please provide as much detail as possible about the vulnerability.
8 | 3. Depending on the severity and complexity of the issue, the response time may vary.
9 | 4. Additional information might be requested.
10 | 5. Once the vulnerability is confirmed, an update with the fixes will roll out.
11 | 6. Users will be notified some time later to ensure safety for those who are using a vulnerable version.
12 | 7. You will be publicly acknowledged for your contribution if you choose to be credited.
13 |
14 | ## Contact
15 |
16 | If you have any questions or concerns regarding the security of this project, please open a ticket on Discord or contact me via email at contact@jonesdev.xyz.
17 |
18 | ## Acknowledgments
19 |
20 | - Special thanks to the [contributors of Sonar](https://github.com/jonesdevelopment/sonar/graphs/contributors),
21 | and also those who reported security issues or bugs.
22 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gradle" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
6 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
7 |
8 | name: Sonar CI
9 |
10 | on:
11 | push:
12 | branches: [ "main" ]
13 | pull_request:
14 | branches: [ "main" ]
15 |
16 | permissions:
17 | contents: read
18 |
19 | jobs:
20 | build:
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: actions/checkout@v4
25 |
26 | - name: Set up JDK 17
27 | uses: actions/setup-java@v3
28 | with:
29 | java-version: '17'
30 | distribution: 'temurin'
31 |
32 | - name: Setup Gradle
33 | uses: gradle/actions/setup-gradle@v4
34 |
35 | - name: Build with Gradle
36 | run: ./gradlew build-sonar
37 |
38 | - name: Upload Bukkit Artifact
39 | uses: actions/upload-artifact@v4
40 | with:
41 | name: Sonar-Bukkit
42 | path: bukkit/build/libs/Sonar-Bukkit.jar
43 | if-no-files-found: error
44 |
45 | - name: Upload BungeeCord Artifact
46 | uses: actions/upload-artifact@v4
47 | with:
48 | name: Sonar-Bungee
49 | path: bungeecord/build/libs/Sonar-Bungee.jar
50 | if-no-files-found: error
51 |
52 | - name: Upload Velocity Artifact
53 | uses: actions/upload-artifact@v4
54 | with:
55 | name: Sonar-Velocity
56 | path: velocity/build/libs/Sonar-Velocity.jar
57 | if-no-files-found: error
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # GitHub
2 | .github/
3 | HEADER
4 | LICENSE
5 | .*ignore
6 | .*config
7 | .*attributes
8 |
9 | # Editor configurations
10 | .idea/
11 | .gradle/
12 | vscode/
13 | .fleet/
14 |
15 | # Build directories
16 | target/
17 | out/
18 | gradle/
19 | build/
20 | gradlew*
21 |
22 | # Uncommon files
23 | *.bat
24 | *.cmd
25 | *.jar
26 | *.class
27 | *.iml
28 | *.exe
29 | *.png
30 | *.jpg
31 | *.jpeg
32 | *.log
33 | *.svg
34 | *.txt
35 |
--------------------------------------------------------------------------------
/HEADER:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 |
--------------------------------------------------------------------------------
/api/build.gradle.kts:
--------------------------------------------------------------------------------
1 | repositories {
2 | maven(url = "https://jitpack.io/") // simple-yaml
3 | }
4 |
5 | dependencies {
6 | compileOnly(rootProject.libs.simpleyaml) {
7 | exclude(group = "org.yaml")
8 | }
9 | compileOnly(rootProject.libs.annotations)
10 | }
11 |
12 | tasks {
13 | shadowJar {
14 | archiveFileName = "sonar-api-${rootProject.version}.jar"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/SonarPlatform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api;
19 |
20 | import io.netty.channel.ChannelPipeline;
21 | import lombok.Getter;
22 | import lombok.RequiredArgsConstructor;
23 |
24 | import java.util.function.Function;
25 |
26 | @Getter
27 | @RequiredArgsConstructor
28 | public enum SonarPlatform {
29 | BUKKIT("Bukkit", 19110, "packet_handler",
30 | pipeline -> pipeline.context("outbound_config") != null ? "outbound_config" : "encoder"),
31 | BUNGEE("BungeeCord", 19109, "inbound-boss",
32 | pipeline -> "packet-encoder"),
33 | VELOCITY("Velocity", 19107, "handler",
34 | pipeline -> "minecraft-encoder");
35 |
36 | private final String displayName;
37 | private final int metricsId;
38 | private final String connectionHandler;
39 | private final Function encoder;
40 | }
41 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/SonarSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api;
19 |
20 | import lombok.experimental.UtilityClass;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | @UtilityClass
24 | public class SonarSupplier {
25 | Sonar sonar;
26 |
27 | public void set(final @NotNull Sonar _sonar) {
28 | if (sonar != null) {
29 | throw new IllegalStateException("Sonar is already initialized");
30 | }
31 | sonar = _sonar;
32 | }
33 |
34 | public Sonar get() {
35 | if (sonar == null) {
36 | throw new IllegalStateException("Sonar is not initialized yet");
37 | }
38 | return sonar;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/SonarVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api;
19 |
20 | import lombok.Getter;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 | import java.net.URL;
26 | import java.util.jar.Manifest;
27 |
28 | @Getter
29 | public final class SonarVersion {
30 | static final SonarVersion INSTANCE = new SonarVersion();
31 |
32 | private final String version, formatted, gitBranch, gitCommit;
33 |
34 | SonarVersion() {
35 | // No need to null-check since we'll always just throw an exception if
36 | // we can't find the version information in this file.
37 | final Manifest manifest = getManifest();
38 |
39 | this.version = manifest.getMainAttributes().getValue("Implementation-Version");
40 | this.gitBranch = manifest.getMainAttributes().getValue("Git-Branch");
41 | this.gitCommit = manifest.getMainAttributes().getValue("Git-Commit");
42 | this.formatted = version + " (" + gitCommit + ")";
43 | }
44 |
45 | // https://github.com/PaperMC/Velocity/pull/1336/
46 | private static @NotNull Manifest getManifest() {
47 | final String classLocation = "/" + Sonar.class.getName().replace(".", "/") + ".class";
48 | final URL resource = Sonar.class.getResource(classLocation);
49 |
50 | if (resource == null) {
51 | throw new IllegalStateException("Could not find version information. Is the manifest missing?");
52 | }
53 |
54 | final String classFilePath = resource.toString().replace("\\", "/");
55 | final String archivePath = classFilePath.substring(0, classFilePath.length() - classLocation.length());
56 | final String manifestPath = archivePath + "/META-INF/MANIFEST.MF";
57 |
58 | try (final InputStream stream = new URL(manifestPath).openStream()) {
59 | return new Manifest(stream);
60 | } catch (IOException exception) {
61 | throw new IllegalStateException(exception);
62 | }
63 | }
64 |
65 | @Override
66 | public String toString() {
67 | return formatted;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/command/InvocationSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.command;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import net.kyori.adventure.audience.Audience;
23 | import net.kyori.adventure.text.Component;
24 |
25 | import java.util.UUID;
26 | import java.util.function.Predicate;
27 |
28 | @Getter
29 | @RequiredArgsConstructor
30 | public final class InvocationSource {
31 | private final UUID uuid;
32 | private final Audience audience;
33 | private final Predicate permissionFunction;
34 |
35 | /**
36 | * @return true if {@link InvocationSource#uuid} is not null
37 | */
38 | public boolean isPlayer() {
39 | return uuid != null;
40 | }
41 |
42 | /**
43 | * Sends a message to the command executor
44 | */
45 | public void sendMessage(final Component component) {
46 | audience.sendMessage(component);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/command/subcommand/SubcommandInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.command.subcommand;
19 |
20 | import java.lang.annotation.ElementType;
21 | import java.lang.annotation.Retention;
22 | import java.lang.annotation.RetentionPolicy;
23 | import java.lang.annotation.Target;
24 |
25 | @Retention(RetentionPolicy.RUNTIME)
26 | @Target(ElementType.TYPE)
27 | public @interface SubcommandInfo {
28 | String name();
29 |
30 | String[] aliases() default {};
31 |
32 | String[] arguments() default {};
33 |
34 | boolean argumentsRequired() default true;
35 |
36 | boolean onlyPlayers() default false;
37 |
38 | boolean onlyConsole() default false;
39 | }
40 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/command/subcommand/SubcommandRegistry.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.command.subcommand;
19 |
20 | import lombok.Getter;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | import java.util.Arrays;
24 | import java.util.List;
25 | import java.util.Vector;
26 |
27 | @Getter
28 | public final class SubcommandRegistry {
29 | private final List subcommands = new Vector<>();
30 |
31 | /**
32 | * Registers a single or multiple subcommand(s)
33 | *
34 | * @param subcommand Array of Subcommands to register
35 | */
36 | public void register(final Subcommand @NotNull ... subcommand) {
37 | subcommands.addAll(Arrays.asList(subcommand));
38 | }
39 |
40 | /**
41 | * Unregisters a single or multiple subcommand(s)
42 | *
43 | * @param subcommand Array of Subcommands to unregister
44 | */
45 | @SuppressWarnings("unused")
46 | public void unregister(final Subcommand @NotNull ... subcommand) {
47 | subcommands.removeAll(Arrays.asList(subcommand));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/database/model/VerifiedPlayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.database.model;
19 |
20 | import com.j256.ormlite.field.DatabaseField;
21 | import com.j256.ormlite.table.DatabaseTable;
22 | import lombok.AccessLevel;
23 | import lombok.Getter;
24 | import lombok.NoArgsConstructor;
25 | import lombok.ToString;
26 | import org.jetbrains.annotations.NotNull;
27 |
28 | import java.sql.Timestamp;
29 |
30 | @Getter
31 | @ToString
32 | @DatabaseTable(tableName = "sonar_fingerprints")
33 | @NoArgsConstructor(access = AccessLevel.PROTECTED)
34 | public final class VerifiedPlayer {
35 | @SuppressWarnings("unused")
36 | @DatabaseField(generatedId = true)
37 | private int id;
38 |
39 | @DatabaseField(
40 | columnName = "fingerprint",
41 | canBeNull = false,
42 | width = 48
43 | )
44 | private String fingerprint;
45 |
46 | @DatabaseField(
47 | columnName = "timestamp",
48 | canBeNull = false
49 | )
50 | private Timestamp timestamp;
51 |
52 | public VerifiedPlayer(final @NotNull String fingerprint,
53 | final long timestamp) {
54 | this.fingerprint = fingerprint;
55 | this.timestamp = new Timestamp(timestamp);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/database/ormlite/H2DatabaseTypeAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.database.ormlite;
19 |
20 | import com.j256.ormlite.jdbc.db.H2DatabaseType;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | public final class H2DatabaseTypeAdapter extends H2DatabaseType {
24 |
25 | // We need to override the default driver class name
26 | // to use the custom relocated H2 driver
27 | @Override
28 | protected String @NotNull [] getDriverClassNames() {
29 | return new String[]{"xyz.jonesdev.sonar.libs.h2.Driver"};
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/database/ormlite/MariaDbDatabaseTypeAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.database.ormlite;
19 |
20 | import com.j256.ormlite.jdbc.db.MariaDbDatabaseType;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | public final class MariaDbDatabaseTypeAdapter extends MariaDbDatabaseType {
24 |
25 | // We need to override the default driver class name
26 | // to use the custom relocated MariaDB driver
27 | @Override
28 | protected String @NotNull [] getDriverClassNames() {
29 | return new String[]{"xyz.jonesdev.sonar.libs.mariadb.jdbc.Driver"};
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/database/ormlite/MysqlDatabaseTypeAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.database.ormlite;
19 |
20 | import com.j256.ormlite.jdbc.db.MysqlDatabaseType;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | public final class MysqlDatabaseTypeAdapter extends MysqlDatabaseType {
24 |
25 | // We need to override the default driver class name
26 | // to use the custom relocated MySQL driver
27 | @Override
28 | protected String @NotNull [] getDriverClassNames() {
29 | return new String[]{"xyz.jonesdev.sonar.libs.mysql.cj.jdbc.Driver"};
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/SonarEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event;
19 |
20 | public interface SonarEvent {
21 | }
22 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/SonarEventListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event;
19 |
20 | import org.jetbrains.annotations.NotNull;
21 |
22 | @FunctionalInterface
23 | public interface SonarEventListener {
24 |
25 | /**
26 | * Handles the publishing of an event through Sonar's API
27 | */
28 | void handle(final @NotNull SonarEvent event);
29 | }
30 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/AttackDetectedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import xyz.jonesdev.sonar.api.event.SonarEvent;
21 |
22 | public final class AttackDetectedEvent implements SonarEvent {
23 | }
24 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/AttackMitigatedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.ToString;
23 | import xyz.jonesdev.sonar.api.event.SonarEvent;
24 | import xyz.jonesdev.sonar.api.tracker.AttackTracker;
25 |
26 | @Getter
27 | @ToString
28 | @RequiredArgsConstructor
29 | public final class AttackMitigatedEvent implements SonarEvent {
30 | private final AttackTracker.AttackStatistics attackStatistics;
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/CaptchaGenerationEndEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.ToString;
23 | import xyz.jonesdev.sonar.api.event.SonarEvent;
24 | import xyz.jonesdev.sonar.api.timer.SystemTimer;
25 |
26 | @Getter
27 | @ToString
28 | @RequiredArgsConstructor
29 | public final class CaptchaGenerationEndEvent implements SonarEvent {
30 | private final SystemTimer timer;
31 | private final int amountGenerated;
32 | }
33 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/CaptchaGenerationStartEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.AllArgsConstructor;
21 | import lombok.Getter;
22 | import lombok.Setter;
23 | import xyz.jonesdev.sonar.api.event.SonarEvent;
24 | import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator;
25 |
26 | @Getter
27 | @Setter
28 | @AllArgsConstructor
29 | public final class CaptchaGenerationStartEvent implements SonarEvent {
30 | private CaptchaGenerator captchaGenerator;
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserBlacklistedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.ToString;
23 | import xyz.jonesdev.sonar.api.event.SonarEvent;
24 | import xyz.jonesdev.sonar.api.fallback.FallbackUser;
25 |
26 | @Getter
27 | @ToString
28 | @RequiredArgsConstructor
29 | public final class UserBlacklistedEvent implements SonarEvent {
30 | private final FallbackUser user;
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserVerifyFailedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.ToString;
23 | import org.jetbrains.annotations.NotNull;
24 | import xyz.jonesdev.sonar.api.event.SonarEvent;
25 | import xyz.jonesdev.sonar.api.fallback.FallbackUser;
26 |
27 | @Getter
28 | @ToString
29 | @RequiredArgsConstructor
30 | public final class UserVerifyFailedEvent implements SonarEvent {
31 | private final @NotNull FallbackUser user;
32 | private final @NotNull String reason;
33 | }
34 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserVerifyJoinEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.ToString;
23 | import xyz.jonesdev.sonar.api.event.SonarEvent;
24 | import xyz.jonesdev.sonar.api.fallback.FallbackUser;
25 |
26 | @Getter
27 | @ToString
28 | @RequiredArgsConstructor
29 | public final class UserVerifyJoinEvent implements SonarEvent {
30 | private final FallbackUser user;
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserVerifySuccessEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.event.impl;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.ToString;
23 | import xyz.jonesdev.sonar.api.event.SonarEvent;
24 | import xyz.jonesdev.sonar.api.fallback.FallbackUser;
25 |
26 | @Getter
27 | @ToString
28 | @RequiredArgsConstructor
29 | public final class UserVerifySuccessEvent implements SonarEvent {
30 | private final FallbackUser user;
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fallback/Fallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fallback;
19 |
20 | import com.github.benmanes.caffeine.cache.Cache;
21 | import lombok.AccessLevel;
22 | import lombok.Getter;
23 | import lombok.NoArgsConstructor;
24 | import lombok.Setter;
25 | import xyz.jonesdev.sonar.api.Sonar;
26 | import xyz.jonesdev.sonar.api.config.SonarConfiguration;
27 | import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator;
28 | import xyz.jonesdev.sonar.api.fallback.ratelimit.Ratelimiter;
29 |
30 | import java.net.InetAddress;
31 | import java.util.concurrent.ConcurrentHashMap;
32 | import java.util.concurrent.ConcurrentMap;
33 |
34 | @Getter
35 | @NoArgsConstructor(access = AccessLevel.PRIVATE)
36 | public final class Fallback {
37 | public static final Fallback INSTANCE = new Fallback();
38 |
39 | private final ConcurrentMap online = new ConcurrentHashMap<>(128);
40 | private final ConcurrentMap connected = new ConcurrentHashMap<>(256);
41 | private final FallbackLoginQueue queue = new FallbackLoginQueue();
42 | @Setter
43 | private Cache blacklist;
44 | @Setter
45 | private long blacklistTime;
46 | @Setter
47 | private CaptchaGenerator captchaGenerator;
48 | @Setter
49 | private Ratelimiter ratelimiter;
50 |
51 | public boolean shouldVerifyNewPlayers() {
52 | return shouldPerform(Sonar.get0().getConfig().getVerification().getTiming());
53 | }
54 |
55 | public boolean shouldPerformCaptcha() {
56 | return shouldPerform(Sonar.get0().getConfig().getVerification().getMap().getTiming());
57 | }
58 |
59 | private static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) {
60 | return timing == SonarConfiguration.Verification.Timing.ALWAYS
61 | || (timing == SonarConfiguration.Verification.Timing.DURING_ATTACK
62 | && Sonar.get0().getAttackTracker().getCurrentAttack() != null);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fallback/FallbackLoginQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fallback;
19 |
20 | import lombok.AccessLevel;
21 | import lombok.Getter;
22 | import lombok.RequiredArgsConstructor;
23 | import xyz.jonesdev.sonar.api.Sonar;
24 |
25 | import java.net.InetAddress;
26 | import java.util.concurrent.ConcurrentHashMap;
27 | import java.util.concurrent.ConcurrentMap;
28 | import java.util.concurrent.ExecutorService;
29 | import java.util.concurrent.Executors;
30 |
31 | @Getter
32 | @RequiredArgsConstructor(access = AccessLevel.PROTECTED)
33 | public final class FallbackLoginQueue {
34 | // Fixed thread pool executor for all new verifications
35 | private static final int THREAD_POOL_SIZE = Math.min(0x7fff, Runtime.getRuntime().availableProcessors() * 2);
36 | private static final ExecutorService QUEUE_EXECUTOR = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
37 |
38 | private final ConcurrentMap players = new ConcurrentHashMap<>(512);
39 |
40 | public void poll() {
41 | final int maxQueuePolls = Math.min(players.size(), Sonar.get0().getConfig().getQueue().getMaxQueuePolls());
42 | // No need to initiate an executor service task if nobody is currently queued
43 | if (maxQueuePolls <= 0) return;
44 | // We need to be cautious here since we don't want any concurrency issues
45 | QUEUE_EXECUTOR.execute(() -> {
46 | final var iterator = players.entrySet().iterator();
47 | for (int index = 0; index < maxQueuePolls && iterator.hasNext(); index++) {
48 | iterator.next().getValue().run();
49 | iterator.remove();
50 | }
51 | });
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fallback/FallbackPipelines.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fallback;
19 |
20 | public interface FallbackPipelines {
21 | String FALLBACK_INACTIVE_LISTENER = "sonar-inactive-listener";
22 | String FALLBACK_INBOUND_HANDLER = "sonar-inbound-handler";
23 | String FALLBACK_FRAME_DECODER = "sonar-frame-decoder";
24 | String FALLBACK_FRAME_ENCODER = "sonar-frame-encoder";
25 | String FALLBACK_TIMEOUT = "sonar-timeout";
26 | String FALLBACK_PACKET_HANDLER = "sonar-packet-handler";
27 | String FALLBACK_PACKET_ENCODER = "sonar-packet-encoder";
28 | String FALLBACK_PACKET_DECODER = "sonar-packet-decoder";
29 | String FALLBACK_TAIL_EXCEPTIONS = "sonar-exception-tail";
30 | String FALLBACK_BANDWIDTH = "sonar-bandwidth-counter";
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fallback/FallbackUser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fallback;
19 |
20 | import io.netty.channel.Channel;
21 | import io.netty.util.ReferenceCountUtil;
22 | import net.kyori.adventure.text.Component;
23 | import org.jetbrains.annotations.NotNull;
24 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
25 | import xyz.jonesdev.sonar.api.timer.SystemTimer;
26 |
27 | import java.net.InetAddress;
28 |
29 | public interface FallbackUser {
30 | @NotNull Channel channel();
31 |
32 | @NotNull InetAddress getInetAddress();
33 |
34 | @NotNull ProtocolVersion getProtocolVersion();
35 |
36 | @NotNull SystemTimer getLoginTimer();
37 |
38 | @NotNull String getFingerprint();
39 |
40 | @NotNull String getUsername();
41 |
42 | boolean isForceCaptcha();
43 |
44 | void setForceCaptcha(final boolean isForceCaptcha);
45 |
46 | boolean isGeyser();
47 |
48 | /**
49 | * Disconnect the player during/after verification
50 | * using our custom Disconnect packet.
51 | *
52 | * @param reason Disconnect message component
53 | */
54 | void disconnect(final @NotNull Component reason);
55 |
56 | /**
57 | * Sends a packet/message to the player
58 | *
59 | * @param msg Message to send to the player
60 | */
61 | default void write(final @NotNull Object msg) {
62 | if (channel().isActive()) {
63 | channel().writeAndFlush(msg, channel().voidPromise());
64 | } else {
65 | ReferenceCountUtil.release(msg);
66 | }
67 | }
68 |
69 | /**
70 | * Queues a buffered message that will be
71 | * sent once all messages are flushed.
72 | */
73 | default void delayedWrite(final @NotNull Object msg) {
74 | if (channel().isActive()) {
75 | channel().write(msg, channel().voidPromise());
76 | } else {
77 | ReferenceCountUtil.release(msg);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fallback/captcha/CaptchaGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fallback.captcha;
19 |
20 | import org.jetbrains.annotations.NotNull;
21 |
22 | import java.awt.image.BufferedImage;
23 |
24 | @FunctionalInterface
25 | public interface CaptchaGenerator {
26 |
27 | /**
28 | * Generates a {@link java.awt.image.BufferedImage} that shows the answer to the CAPTCHA
29 | */
30 | @NotNull BufferedImage createImage(final char @NotNull [] answer);
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fallback/ratelimit/Ratelimiter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fallback.ratelimit;
19 |
20 | import org.jetbrains.annotations.NotNull;
21 |
22 | @FunctionalInterface
23 | public interface Ratelimiter {
24 | boolean attempt(final @NotNull T t);
25 | }
26 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/fingerprint/FingerprintingUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.fingerprint;
19 |
20 | import lombok.experimental.UtilityClass;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | @UtilityClass
24 | public class FingerprintingUtil {
25 |
26 | /**
27 | * Returns a hex string representing a hash of the username and IP address
28 | */
29 | public @NotNull String getFingerprint(final @NotNull String username,
30 | final @NotNull String hostAddress) {
31 | final int hash0 = username.hashCode();
32 | final int hash1 = hostAddress.hashCode();
33 | final int combined = hash0 + hash1;
34 | return Integer.toHexString(hash0 >> 4)
35 | + Integer.toHexString(combined << 2)
36 | + Integer.toHexString(hash1 >> 4);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/notification/NotificationHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.notification;
19 |
20 | import lombok.Getter;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | import java.util.Collection;
24 | import java.util.UUID;
25 | import java.util.Vector;
26 |
27 | @Getter
28 | public abstract class NotificationHandler {
29 | protected final @NotNull Collection subscribers = new Vector<>(0);
30 |
31 | public abstract void handleNotification();
32 |
33 | /**
34 | * @param uuid UUID of the player
35 | * @return Whether the audience is subscribed or not
36 | */
37 | public final boolean isSubscribed(final @NotNull UUID uuid) {
38 | return getSubscribers().contains(uuid);
39 | }
40 |
41 | /**
42 | * @param uuid UUID of the player
43 | */
44 | public final void subscribe(final UUID uuid) {
45 | getSubscribers().add(uuid);
46 | }
47 |
48 | /**
49 | * @param uuid UUID of the player
50 | */
51 | public final void unsubscribe(final UUID uuid) {
52 | getSubscribers().remove(uuid);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/statistics/SonarStatistics.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.statistics;
19 |
20 | @SuppressWarnings("unused")
21 | public interface SonarStatistics {
22 | long getConnectionsPerSecond();
23 |
24 | long getLoginsPerSecond();
25 |
26 | long getCurrentIncomingBandwidth();
27 |
28 | long getCurrentOutgoingBandwidth();
29 |
30 | long getTotalIncomingBandwidth();
31 |
32 | long getTotalOutgoingBandwidth();
33 |
34 | String getPerSecondIncomingBandwidthFormatted();
35 |
36 | String getPerSecondOutgoingBandwidthFormatted();
37 |
38 | int getTotalPlayersJoined();
39 |
40 | int getTotalPlayersVerified();
41 |
42 | int getTotalSuccessfulVerifications();
43 |
44 | int getTotalFailedVerifications();
45 |
46 | long getCurrentAttemptedVerifications();
47 |
48 | int getTotalAttemptedVerifications();
49 |
50 | long getCurrentBlacklistSize();
51 |
52 | long getTotalBlacklistSize();
53 | }
54 |
--------------------------------------------------------------------------------
/api/src/main/java/xyz/jonesdev/sonar/api/timer/SystemTimer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.api.timer;
19 |
20 | import lombok.Getter;
21 |
22 | import java.text.SimpleDateFormat;
23 |
24 | @Getter
25 | public final class SystemTimer {
26 | public static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("mm:ss");
27 |
28 | private long start = System.currentTimeMillis();
29 |
30 | public void reset() {
31 | start = System.currentTimeMillis();
32 | }
33 |
34 | /**
35 | * @return Time between the current timestamp and the start timestamp
36 | */
37 | public long delay() {
38 | return System.currentTimeMillis() - start;
39 | }
40 |
41 | /**
42 | * @apiNote Read more: {@link SystemTimer#delay}
43 | */
44 | public boolean elapsed(final long amount) {
45 | return delay() >= amount;
46 | }
47 |
48 | @Override
49 | public String toString() {
50 | return String.format("%.3f", delay() / 1000D);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/bukkit/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
2 |
3 | plugins {
4 | alias(libs.plugins.pluginyml.bukkit) apply true
5 | }
6 |
7 | bukkit {
8 | name = rootProject.name
9 | main = "xyz.jonesdev.sonar.bukkit.SonarBukkitPlugin"
10 | authors = listOf("Jones Development", "Sonar Contributors")
11 | website = "https://jonesdev.xyz/discord/"
12 | load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
13 | softDepend = listOf("Geyser-Spigot", "floodgate", "Protocolize", "ProtocolSupport",
14 | "ViaVersion", "packetevents", "ProtocolLib", "FastLogin")
15 | apiVersion = "1.13" // ignore legacy plugin warning
16 | foliaSupported = true
17 |
18 | commands {
19 | register("sonar") {
20 | // No permission checks here
21 | }
22 | }
23 | }
24 |
25 | repositories {
26 | maven(url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
27 | maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") // BungeeCord Chat API
28 | }
29 |
30 | dependencies {
31 | implementation(project(":api"))
32 | implementation(project(":common"))
33 |
34 | compileOnly(rootProject.libs.spigot)
35 | testCompileOnly(rootProject.libs.spigot)
36 |
37 | implementation(rootProject.libs.adventure.platform.bukkit) {
38 | exclude(module = "adventure-nbt")
39 | }
40 | implementation(rootProject.libs.bstats.bukkit)
41 | implementation(rootProject.libs.libby.bukkit)
42 | }
43 |
44 | tasks {
45 | shadowJar {
46 | relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori")
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/bukkit/src/main/java/xyz/jonesdev/sonar/bukkit/SonarBukkitPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.bukkit;
19 |
20 | import org.bukkit.plugin.java.JavaPlugin;
21 | import xyz.jonesdev.sonar.bukkit.fallback.FallbackBukkitInjector;
22 |
23 | public final class SonarBukkitPlugin extends JavaPlugin {
24 | private SonarBukkit bootstrap;
25 |
26 | @Override
27 | public void onLoad() {
28 | // Inject early if late-bind is disabled
29 | if (!FallbackBukkitInjector.isLateBindEnabled()) {
30 | FallbackBukkitInjector.inject();
31 | }
32 | }
33 |
34 | @Override
35 | public void onEnable() {
36 | bootstrap = new SonarBukkit(this);
37 | bootstrap.initialize();
38 | }
39 |
40 | @Override
41 | public void onDisable() {
42 | bootstrap.shutdown();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/bukkit/src/main/java/xyz/jonesdev/sonar/bukkit/command/BukkitSonarCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.bukkit.command;
19 |
20 | import org.bukkit.command.Command;
21 | import org.bukkit.command.CommandExecutor;
22 | import org.bukkit.command.CommandSender;
23 | import org.bukkit.command.TabExecutor;
24 | import org.bukkit.entity.Player;
25 | import org.jetbrains.annotations.NotNull;
26 | import xyz.jonesdev.sonar.api.Sonar;
27 | import xyz.jonesdev.sonar.api.command.InvocationSource;
28 | import xyz.jonesdev.sonar.api.command.SonarCommand;
29 |
30 | import java.util.Collections;
31 | import java.util.List;
32 |
33 | public final class BukkitSonarCommand implements CommandExecutor, TabExecutor, SonarCommand {
34 |
35 | @Override
36 | public boolean onCommand(final CommandSender sender,
37 | final Command command,
38 | final String label,
39 | final String[] args) {
40 | // Create our own invocation source wrapper to handle messages properly
41 | final InvocationSource invocationSource = new InvocationSource(
42 | sender instanceof Player ? ((Player) sender).getUniqueId() : null,
43 | Sonar.get0().sender(sender),
44 | sender::hasPermission);
45 | // Pass the invocation source and command arguments to our command handler
46 | handle(invocationSource, args);
47 | return true;
48 | }
49 |
50 | @Override
51 | public List onTabComplete(final @NotNull CommandSender sender,
52 | final Command command,
53 | final String commandAlias,
54 | final String @NotNull [] args) {
55 | // Do not allow tab completion if the player does not have the required permission
56 | return sender.hasPermission("sonar.command") ? getCachedTabSuggestions(args) : Collections.emptyList();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/bungeecord/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.pluginyml.bungee) apply true
3 | }
4 |
5 | bungee {
6 | name = rootProject.name
7 | main = "xyz.jonesdev.sonar.bungee.SonarBungeePlugin"
8 | author = "Jones Development, Sonar Contributors"
9 | softDepends = setOf("Geyser-BungeeCord", "floodgate", "Protocolize", "ViaVersion", "packetevents", "FastLogin")
10 | }
11 |
12 | dependencies {
13 | implementation(project(":api"))
14 | implementation(project(":common"))
15 |
16 | compileOnly(rootProject.libs.bungeecord)
17 | testCompileOnly(rootProject.libs.bungeecord)
18 |
19 | implementation(rootProject.libs.adventure.platform.bungee) {
20 | exclude(module = "adventure-nbt")
21 | }
22 | implementation(rootProject.libs.bstats.bungee)
23 | implementation(rootProject.libs.libby.bungee)
24 | }
25 |
26 | tasks {
27 | shadowJar {
28 | relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori")
29 |
30 | archiveFileName = "Sonar-Bungee.jar" // Hardcode a shortened version of the name
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/bungeecord/src/main/java/xyz/jonesdev/sonar/bungee/SonarBungeePlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.bungee;
19 |
20 | import lombok.Getter;
21 | import net.md_5.bungee.api.ProxyServer;
22 | import net.md_5.bungee.api.plugin.Plugin;
23 |
24 | @Getter
25 | public final class SonarBungeePlugin extends Plugin {
26 | private ProxyServer server;
27 | private SonarBungee bootstrap;
28 |
29 | @Override
30 | public void onEnable() {
31 | server = ProxyServer.getInstance();
32 |
33 | bootstrap = new SonarBungee(this);
34 | bootstrap.initialize();
35 | }
36 |
37 | @Override
38 | public void onDisable() {
39 | bootstrap.shutdown();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/bungeecord/src/main/java/xyz/jonesdev/sonar/bungee/command/BungeeSonarCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.bungee.command;
19 |
20 | import net.md_5.bungee.api.CommandSender;
21 | import net.md_5.bungee.api.connection.ProxiedPlayer;
22 | import net.md_5.bungee.api.plugin.Command;
23 | import net.md_5.bungee.api.plugin.TabExecutor;
24 | import org.jetbrains.annotations.NotNull;
25 | import xyz.jonesdev.sonar.api.Sonar;
26 | import xyz.jonesdev.sonar.api.command.InvocationSource;
27 | import xyz.jonesdev.sonar.api.command.SonarCommand;
28 |
29 | import java.util.Collections;
30 |
31 | public final class BungeeSonarCommand extends Command implements TabExecutor, SonarCommand {
32 | public BungeeSonarCommand() {
33 | super("sonar");
34 | }
35 |
36 | @Override
37 | public void execute(final @NotNull CommandSender sender, final String[] args) {
38 | // Create our own invocation source wrapper to handle messages properly
39 | final InvocationSource invocationSource = new InvocationSource(
40 | sender instanceof ProxiedPlayer ? ((ProxiedPlayer) sender).getUniqueId() : null,
41 | Sonar.get0().sender(sender),
42 | sender::hasPermission);
43 | // Pass the invocation source and command arguments to our command handler
44 | handle(invocationSource, args);
45 | }
46 |
47 | @Override
48 | public Iterable onTabComplete(final @NotNull CommandSender sender, final String @NotNull [] args) {
49 | // Do not allow tab completion if the player does not have the required permission
50 | return sender.hasPermission("sonar.command") ? getCachedTabSuggestions(args) : Collections.emptyList();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/captcha/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compileOnly(project(":api"))
3 | compileOnly(rootProject.libs.imagefilters)
4 |
5 | testImplementation(project(":api"))
6 | testImplementation(rootProject.libs.imagefilters)
7 | }
8 |
--------------------------------------------------------------------------------
/captcha/src/main/java/xyz/jonesdev/sonar/captcha/StandardTTFFontProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.captcha;
19 |
20 | import lombok.experimental.UtilityClass;
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | import java.awt.*;
24 | import java.io.InputStream;
25 | import java.util.Objects;
26 |
27 | @UtilityClass
28 | class StandardTTFFontProvider {
29 | private static final String[] FONT_NAMES = {"Kingthings_Trypewriter_2"};
30 | static final Font[] FONTS = new Font[FONT_NAMES.length];
31 | static final int STANDARD_FONT_SIZE = 25;
32 |
33 | static {
34 | for (int i = 0; i < FONT_NAMES.length; i++) {
35 | FONTS[i] = loadFont(String.format("/assets/fonts/%s.ttf", FONT_NAMES[i]));
36 | }
37 | }
38 |
39 | private static Font loadFont(final @NotNull String path) {
40 | try (final InputStream inputStream = StandardCaptchaGenerator.class.getResourceAsStream(path)) {
41 | // Load the font from the TTF file
42 | final Font customFont = Font.createFont(Font.TRUETYPE_FONT, Objects.requireNonNull(inputStream));
43 | // Set the font size and style
44 | return customFont.deriveFont(Font.PLAIN, STANDARD_FONT_SIZE);
45 | } catch (Exception exception) {
46 | throw new IllegalStateException(exception);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/captcha/src/main/java/xyz/jonesdev/sonar/captcha/filters/CurvesOverlayFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.captcha.filters;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import org.jetbrains.annotations.NotNull;
23 |
24 | import java.awt.*;
25 | import java.awt.geom.CubicCurve2D;
26 | import java.awt.image.BufferedImage;
27 | import java.util.Random;
28 |
29 | @Getter
30 | @RequiredArgsConstructor
31 | public final class CurvesOverlayFilter {
32 | private final int amount;
33 |
34 | private static final Random RANDOM = new Random();
35 |
36 | public void transform(final @NotNull BufferedImage image,
37 | final @NotNull Graphics2D graphics) {
38 | // Randomize the stroke width
39 | graphics.setStroke(new BasicStroke(1 + RANDOM.nextFloat()));
40 |
41 | final int halfWidth = image.getWidth() / 2;
42 |
43 | for (int i = 0; i < amount; ++i) {
44 | final float randomX = image.getWidth() * RANDOM.nextFloat();
45 | final float randomY = image.getHeight() * RANDOM.nextFloat();
46 | final float amplitude = 6.2831855f * (RANDOM.nextFloat() - 0.5f);
47 | final float sin = (float) Math.sin(amplitude) * halfWidth;
48 | final float cos = (float) Math.cos(amplitude) * halfWidth;
49 | final float x1 = randomX - cos;
50 | final float y1 = randomY - sin;
51 | final float x2 = randomX + cos;
52 | final float y2 = randomY + sin;
53 | // Control points for the cubic curve
54 | final float ctrlX1 = randomX + sin / 2;
55 | final float ctrlY1 = randomY - cos / 2;
56 | final float ctrlX2 = randomX - sin / 2;
57 | final float ctrlY2 = randomY + cos / 2;
58 | // Draw a cubic curve instead of a straight line
59 | graphics.draw(new CubicCurve2D.Float(x1, y1, ctrlX1, ctrlY1, ctrlX2, ctrlY2, x2, y2));
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/captcha/src/main/java/xyz/jonesdev/sonar/captcha/filters/GridOverlayFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.captcha.filters;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import org.jetbrains.annotations.NotNull;
23 |
24 | import java.awt.*;
25 | import java.awt.image.BufferedImage;
26 | import java.util.Random;
27 |
28 | @Getter
29 | @RequiredArgsConstructor
30 | public final class GridOverlayFilter {
31 | private final int amount, lineWidth, randomOffset;
32 |
33 | private static final Random RANDOM = new Random();
34 |
35 | public void transform(final @NotNull BufferedImage image,
36 | final @NotNull Graphics2D graphics) {
37 | final int spacingX = image.getWidth() / amount + lineWidth;
38 | final int spacingY = image.getHeight() / amount + lineWidth;
39 | int currentX = spacingX / 2;
40 | int currentY = spacingY / 2;
41 |
42 | for (int i = 0; i < amount; i++) {
43 | graphics.setStroke(new BasicStroke(lineWidth * 0.5f + lineWidth * RANDOM.nextFloat()));
44 | graphics.drawLine(currentX, 0, currentX + RANDOM.nextInt(randomOffset), image.getHeight());
45 | graphics.drawLine(0, currentY, image.getWidth(), currentY + RANDOM.nextInt(randomOffset));
46 |
47 | currentX += spacingX + lineWidth;
48 | currentY += spacingY + lineWidth;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/captcha/src/main/java/xyz/jonesdev/sonar/captcha/filters/NoiseOverlayFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.captcha.filters;
19 |
20 | import lombok.Getter;
21 | import lombok.RequiredArgsConstructor;
22 | import org.jetbrains.annotations.NotNull;
23 |
24 | import java.awt.image.BufferedImage;
25 | import java.util.Random;
26 |
27 | @Getter
28 | @RequiredArgsConstructor
29 | public final class NoiseOverlayFilter {
30 | private final float density, amount;
31 |
32 | private static final Random RANDOM = new Random();
33 |
34 | private int randomGaussian(int x) {
35 | x += (int) (RANDOM.nextGaussian() * amount);
36 | return Math.max(Math.min(x, 0xff), 0);
37 | }
38 |
39 | public void transform(final @NotNull BufferedImage image) {
40 | for (int x = 0; x < image.getWidth(); x++) {
41 | for (int y = 0; y < image.getHeight(); y++) {
42 | if (RANDOM.nextFloat() <= density) {
43 | final int rgb = image.getRGB(x, y);
44 | int r = (rgb >> 16) & 0xff;
45 | int g = (rgb >> 8) & 0xff;
46 | int b = rgb & 0xff;
47 | r = randomGaussian(r);
48 | g = randomGaussian(g);
49 | b = randomGaussian(b);
50 | image.setRGB(x, y, (r << 16) | (g << 8) | b);
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/captcha/src/main/java/xyz/jonesdev/sonar/captcha/legacy/RippleFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.captcha.legacy;
19 |
20 | import com.jhlabs.image.TransformFilter;
21 | import lombok.AllArgsConstructor;
22 | import lombok.Getter;
23 | import lombok.NoArgsConstructor;
24 | import lombok.Setter;
25 | import org.jetbrains.annotations.NotNull;
26 |
27 | @Getter
28 | @Setter
29 | @NoArgsConstructor
30 | @AllArgsConstructor
31 | public final class RippleFilter extends TransformFilter {
32 | private float xAmplitude, yAmplitude;
33 |
34 | @Override
35 | protected void transformInverse(final int x, final int y, final float @NotNull [] out) {
36 | final float nx = (float) y / 13f;
37 | final float ny = (float) x / 13f;
38 | final float fx = (float) Math.sin(nx);
39 | final float fy = (float) Math.sin(ny);
40 |
41 | out[0] = (float) x + xAmplitude * fx;
42 | out[1] = (float) y + yAmplitude * fy;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/captcha/src/main/java/xyz/jonesdev/sonar/captcha/legacy/ScratchFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.captcha.legacy;
19 |
20 | import com.jhlabs.image.AbstractBufferedImageOp;
21 | import lombok.RequiredArgsConstructor;
22 | import org.jetbrains.annotations.NotNull;
23 |
24 | import java.awt.*;
25 | import java.awt.image.BufferedImage;
26 | import java.util.Random;
27 |
28 | @RequiredArgsConstructor
29 | public final class ScratchFilter extends AbstractBufferedImageOp {
30 | private static final Random RANDOM = new Random();
31 |
32 | private final int amount;
33 |
34 | @Override
35 | public @NotNull BufferedImage filter(final @NotNull BufferedImage src, final BufferedImage dst) {
36 | final Graphics2D graphics = src.createGraphics();
37 |
38 | // Apply some gradient effect on them
39 | final Color color0 = Color.getHSBColor(RANDOM.nextFloat(), RANDOM.nextFloat(), 1);
40 | final Color color1 = new Color(~color0.getRGB());
41 | final GradientPaint gradient = new GradientPaint(0, 0, color0, src.getWidth(), src.getHeight(), color1);
42 | graphics.setPaint(gradient);
43 |
44 | final float halfWidth = src.getWidth() * 0.5f;
45 |
46 | for (int i = 0; i < amount; ++i) {
47 | final float randomX = src.getWidth() * RANDOM.nextFloat();
48 | final float randomY = src.getHeight() * RANDOM.nextFloat();
49 | final float amplitude = 6.2831855f * (RANDOM.nextFloat() - 0.5f);
50 | final float sin = (float) Math.sin(amplitude) * halfWidth;
51 | final float cos = (float) Math.cos(amplitude) * halfWidth;
52 | final float x1 = randomX - cos;
53 | final float y1 = randomY - sin;
54 | final float x2 = randomX + cos;
55 | final float y2 = randomY + sin;
56 | graphics.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
57 | }
58 |
59 | graphics.dispose();
60 | return src;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/captcha/src/main/resources/assets/fonts/Kingthings_Trypewriter_2.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/captcha/src/main/resources/assets/fonts/Kingthings_Trypewriter_2.ttf
--------------------------------------------------------------------------------
/captcha/src/test/java/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | import lombok.experimental.UtilityClass;
19 | import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator;
20 |
21 | import javax.imageio.ImageIO;
22 | import java.awt.image.BufferedImage;
23 | import java.io.File;
24 | import java.io.IOException;
25 | import java.util.Random;
26 |
27 | @UtilityClass
28 | public class Main {
29 | public void main(final String... args) throws IOException {
30 | final Random random = new Random();
31 | final StandardCaptchaGenerator standardCaptchaGenerator = new StandardCaptchaGenerator(null);
32 |
33 | final long start = System.currentTimeMillis();
34 | final char[] dictionary = {'a', 'b', 'c', 'd', 'e', 'f'/*, 'g'*/, 'h'/*, 'i'*/, 'j',
35 | 'k', 'm', 'n', 'o', 'p'/*, 'q'*/, 'r', 's', 't', 'u'/*, 'v', 'w'*/, 'x', 'y', 'z'};
36 |
37 | // Generate image
38 | final int amount = 1;
39 | for (int i = 0; i < amount; i++) {
40 | final char[] answer = new char[3 + random.nextInt(2)];
41 | for (int j = 0; j < answer.length; j++) {
42 | answer[j] = dictionary[random.nextInt(dictionary.length)];
43 | }
44 | final BufferedImage bufferedImage = standardCaptchaGenerator.createImage(answer);
45 |
46 | // Save image
47 | ImageIO.write(bufferedImage, "png", new File(i + ".png"));
48 | }
49 | System.out.println("Took " + (System.currentTimeMillis() - start) + "ms to generate " + amount + " image(s)");
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/common/build.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compileOnly(project(":api"))
3 | implementation(project(":captcha"))
4 | compileOnly(rootProject.libs.adventure.nbt)
5 | }
6 |
--------------------------------------------------------------------------------
/common/src/main/java/xyz/jonesdev/sonar/common/fallback/FallbackBandwidthHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.common.fallback;
19 |
20 | import io.netty.buffer.ByteBuf;
21 | import io.netty.channel.ChannelDuplexHandler;
22 | import io.netty.channel.ChannelHandler;
23 | import io.netty.channel.ChannelHandlerContext;
24 | import io.netty.channel.ChannelPromise;
25 | import lombok.AccessLevel;
26 | import lombok.NoArgsConstructor;
27 | import org.jetbrains.annotations.NotNull;
28 | import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
29 |
30 | @ChannelHandler.Sharable
31 | @NoArgsConstructor(access = AccessLevel.PRIVATE)
32 | public final class FallbackBandwidthHandler extends ChannelDuplexHandler {
33 | public static final ChannelHandler INSTANCE = new FallbackBandwidthHandler();
34 |
35 | @Override
36 | public void channelRead(final ChannelHandlerContext ctx, final @NotNull Object msg) throws Exception {
37 | if (msg instanceof ByteBuf) {
38 | // Increment the incoming traffic by the number of readable bytes
39 | final int readableBytes = ((ByteBuf) msg).readableBytes();
40 | GlobalSonarStatistics.perSecondIncomingTraffic += readableBytes;
41 | }
42 | ctx.fireChannelRead(msg);
43 | }
44 |
45 | @Override
46 | public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) throws Exception {
47 | if (msg instanceof ByteBuf) {
48 | // Increment the outgoing traffic by the number of readable bytes
49 | final int readableBytes = ((ByteBuf) msg).readableBytes();
50 | GlobalSonarStatistics.perSecondOutgoingTraffic += readableBytes;
51 | }
52 | ctx.write(msg, promise);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackTailExceptionsHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.common.fallback.netty;
19 |
20 | import io.netty.channel.ChannelDuplexHandler;
21 | import io.netty.channel.ChannelHandler;
22 | import io.netty.channel.ChannelHandlerContext;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | @ChannelHandler.Sharable
26 | public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler {
27 | public static final FallbackTailExceptionsHandler INSTANCE = new FallbackTailExceptionsHandler();
28 |
29 | // We can override the default exceptionCaught method since the server
30 | // does not have any other pipelines that could handle this error.
31 | // Additionally, this will also run after our custom decoder.
32 | @Override
33 | public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
34 | // Close the channel if we encounter any errors.
35 | ctx.close();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackTimeoutHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.common.fallback.netty;
19 |
20 | import io.netty.channel.ChannelHandlerContext;
21 | import io.netty.handler.timeout.IdleStateEvent;
22 | import io.netty.handler.timeout.IdleStateHandler;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | import java.util.concurrent.TimeUnit;
26 |
27 | public final class FallbackTimeoutHandler extends IdleStateHandler {
28 | public FallbackTimeoutHandler(final int readTimeout, final int writeTimeout, final TimeUnit timeUnit) {
29 | super(false, readTimeout, writeTimeout, 0L, timeUnit);
30 | }
31 |
32 | @Override
33 | protected void channelIdle(final @NotNull ChannelHandlerContext ctx,
34 | final IdleStateEvent idleStateEvent) throws Exception {
35 | // The netty (default) ReadTimeoutHandler would normally just throw an Exception
36 | // The default ReadTimeoutHandler does only check for the boolean 'closed' and
37 | // still throws the Exception even if the channel is closed
38 | if (ctx.channel().isActive()) {
39 | ctx.close();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackVarIntLengthEncoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2025 Sonar Contributors
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package xyz.jonesdev.sonar.common.fallback.netty;
19 |
20 | import io.netty.buffer.ByteBuf;
21 | import io.netty.channel.ChannelHandler;
22 | import io.netty.channel.ChannelHandlerContext;
23 | import io.netty.handler.codec.MessageToMessageEncoder;
24 | import org.jetbrains.annotations.NotNull;
25 | import xyz.jonesdev.sonar.common.util.ProtocolUtil;
26 |
27 | import java.util.List;
28 |
29 | // https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java
30 | @ChannelHandler.Sharable
31 | public final class FallbackVarIntLengthEncoder extends MessageToMessageEncoder {
32 | public static final FallbackVarIntLengthEncoder INSTANCE = new FallbackVarIntLengthEncoder();
33 |
34 | @Override
35 | protected void encode(final @NotNull ChannelHandlerContext ctx,
36 | final @NotNull ByteBuf byteBuf,
37 | final @NotNull List