Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Global owners
* @AleksandarHaralanov
35 changes: 27 additions & 8 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
# Contributing
ChatGuard has a devlog which you can visit [here](https://github.com/users/AleksandarHaralanov/projects/1).

Optionally, you can add your name [here](https://github.com/AleksandarHaralanov/ChatGuard/blob/5daf57b1412584b5b450a59c4ddead1585bcae2b/src/main/java/io/github/aleksandarharalanov/chatguard/command/ChatGuardCommand.java#L46) when you contribute code.
## Contribution Workflow
All contributions must be made to the `staging` branch via pull requests (PRs).

- **Write-access users** must create a **feature branch** from `staging`, push changes to it, and open a pull request to `staging`.
- **External contributors** must fork the repository, make changes in the `staging` branch of their fork, and open a pull request to `staging`.

Once reviewed and approved, changes from `staging` will be **squash merged** into `master` to maintain a clean history.

> ![NOTE]
> **Pull requests that do not follow these instructions will be rejected.**<br/>
> You will receive a comment explaining what was incorrect, so you can make the necessary changes and resubmit.

### Optional Contributor Recognition
You can add your name [here]() to be credited in the plugin's about command for your contribution.

## Coding Conventions
This is an open-source project. Keep in mind the people who will read your codemake it clean and easy to understand.
This is an open-source project. Keep in mind the people who will read and work with your codemake it clean and easy to understand.

When reading the code, you'll quickly get the hang of it. Focus on optimizing for readability:

- Do not leave zombie code behind.
- If you feel the need to add comments, don't hesitate; they are always appreciated.
- Use an indentation of four spaces whenever possible; however, two spaces are also acceptable if preferred.
- Always include spaces after list items and method parameters (e.g., `[1, 2, 3]`, not `[1,2,3]`), around operators (e.g., `x += 1`, not `x+=1`), around hash arrows, curly braces etc.
- Avoid utilizing algorithms with bad space and time complexity.
- You can read more about Big O notation [here](https://en.wikipedia.org/wiki/Big_O_notation).
- Clean and concise comments are encouraged if they improve understanding.
- Use an indentation of **four spaces** whenever possible; **two spaces are also acceptable** if preferred.
- Follow object-oriented principles such as SOLID to improve code maintainability.
- Prefer Java Streams and functional programming when applicable, as they improve code readability and performance.
- Use proper Java keywords and modifiers to ensure encapsulation and best practices:
- Always include spaces:
- After list items and method parameters (e.g., `[1, 2, 3]`, not `[1,2,3]`).
- Around operators (e.g., `x += 1`, not `x+=1`).
- Around hash arrows, curly braces, etc.
- If possible, please avoid algorithms with bad space and time complexity.
- Learn more about Big O notation [here](https://en.wikipedia.org/wiki/Big_O_notation).

Following general coding conventions is recommended as a best practice, no matter what you are working on.
Following these conventions will help maintain high-quality code and make contributions easier for everyone.
29 changes: 29 additions & 0 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: build-and-test
on:
pull_request:
branches:
- master
- staging

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up JDK 1.8
uses: actions/setup-java@v2
with:
java-version: 8
distribution: 'temurin'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v3

- name: Build with Gradle
run: ./gradlew build

- name: Test with Gradle
run: ./gradlew test
113 changes: 77 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
**ChatGuard** is a Minecraft plugin designed for servers running version b1.7.3.

- Cancels messages containing blocked terms or matching RegEx patterns.
- Censors signs containing blocked terms or matching RegEx patterns.
- Prevents players from joining with usernames containing blocked terms or matching RegEx patterns.
- Logs offenders (via Discord webhook, server console, or local file).
- Prevents chat message and command spam.
- Prompts captcha verification on suspected bot-like behavior.
- Issues temporary mutes (requires [Essentials v2.5.8](#requirements) as of ChatGuard `v4.1.1`).
- Implements chat and command rate limiter to decrease spam.
- Triggers captcha verification on repeated message spam.
- Issues temporary mutes (requires [Essentials v2.5.8](#Requirements & Optional) as of ChatGuard `v5.0.0`).
- Enforces escalating penalties via a six-strike tier system.
- Plays local sound cues for offending players upon detection.
- Plays local audio cues for offending players upon detection.

The plugin is entirely configurable.

---
## Contributing Code & Reporting Issues
## Contributions, Suggestions, and Issues
Consider helping ChatGuard become even more versatile and robust.

Visit the [CONTRIBUTING](https://github.com/AleksandarHaralanov/ChatGuard/blob/master/.github/CONTRIBUTING.md) guide for details on how to get started and where to focus your efforts.
It is **highly recommended** to visit the [CONTRIBUTING](https://github.com/AleksandarHaralanov/ChatGuard/blob/master/.github/CONTRIBUTING.md) guide for details on how to get started and where to focus your efforts.

For any issues with the plugin, or suggestions, please report them [here](https://github.com/AleksandarHaralanov/ChatGuard/issues).
For any issues with the plugin, or suggestions, please submit them [here](https://github.com/AleksandarHaralanov/ChatGuard/issues).

---
## Download
Expand All @@ -32,10 +33,10 @@ The plugin is fully open-source and transparent.<br/>
If you'd like additional peace of mind, you're welcome to scan the `.jar` file using [VirusTotal](https://www.virustotal.com/gui/home/upload).

---
## Requirements
## Requirements & Optional
Your server must be running one of the following APIs: CB1060-CB1092, [Project Poseidon](https://github.com/retromcorg/Project-Poseidon) or [UberBukkit](https://github.com/Moresteck/Project-Poseidon-Uberbukkit).

It also needs to be running **Essentials v2.5.8 or newer** (as of ChatGuard `v4.1.1`).<br/>You can download it from [here](https://github.com/AleksandarHaralanov/ChatGuard/raw/refs/heads/master/libs/Essentials.jar).
You can download **Essentials v2.5.8** from [here](https://github.com/AleksandarHaralanov/ChatGuard/raw/refs/heads/master/libs/Essentials.jar).

---
## Usage
Expand All @@ -61,26 +62,22 @@ Use PermissionsEx or similar plugins to grant groups the permission, enabling th

---
## Configurations
Generates `config.yml` and `strikes.yml` located at `plugins/ChatGuard`.
ChatGuard generates two configuration files using the default settings in the **config** directory.

> [!CAUTION]
> 🔖`v4.1.1`: If your server is not running **Essentials v2.5.8 or newer**, make sure to download and install it. Without it, the entire plugin will break, and in-game messages will fail to send properly.
>
> You can find the download [here](#requirements) in the requirements heading.
Additionally, it creates two data files, `captchas.yml` and `strikes.yml`, in the **data** directory.

### Config
This is the default `config.yml` configuration file:
#### Main Config `config.yml`:
```yaml
miscellaneous: # QoL Configurations
sound-cues: true # Offending player hears a local sound cue upon detection
miscellaneous: # Misc Configurations
audio-cues: true # Offending player hears a local audio cue upon detection

spam-prevention: # Spam Prevention Configuration
enabled: # Toggles spam prevention for chat messages and commands
message: true
chat: true
command: true
warn-player: true # Warns offending player upon detection
cooldown-ms: # Cooldown durations in milliseconds for strike tiers
message:
chat:
s0: 1000
s1: 2000
s2: 3000
Expand All @@ -101,24 +98,19 @@ captcha: # Captcha Configuration
code: # Captcha characters and length
characters: "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"
length: 5
log: # Logs captcha triggers to:
console: true # Server console
local-file: true # Local file
discord-webhook: # Discord webhook by an embed
enabled: false # Toggles Discord webhook
url: "" # Discord webhook URL
log-console: true # Log captcha trigger to server console
whitelist: [] # Allowed captcha bypass terms for sanitizing

filter: # Filter Configuration
enabled: true # Toggles filtering of chat messages and player usernames
enabled: # Toggles filtration for chat messages, player usernames, and signs
chat: true
sign: true
name: true
warn-player: true # Warns offending player upon detection
log: # Logs captcha triggers to:
log: # Log filter trigger to:
console: true # Server console
local-file: true # Local file
discord-webhook: # Discord webhook by an embed
enabled: false # Toggles Discord webhook
url: "" # Discord webhook URL
mute: # Mute Configuration
essentials-mute: # Essentials Mute Configuration
enabled: true # Toggles automatic mutes upon filter detection
duration: # Mute durations for strike tiers
s0: "30m"
Expand All @@ -133,9 +125,58 @@ filter: # Filter Configuration
whitelist: [] # Allowed chat message and player username bypass terms for sanitizing
blacklist: [] # Disallowed chat message and player username bypass terms
```
<br/>

### Strikes
The default `strikes.yml` configuration file is initially empty. When a player joins for the first time after ChatGuard is installed on the server, they are added to the configuration with 0 strikes. From there, the plugin manages their strikes, incrementing them up to a maximum of 5 as necessary. Read note below on how that works.
#### Discord Embed Config `discord.yml`:
```yaml
webhook-url: "" # Discord Webhook URL

embed-log: # Embed Configurations
type: # Logs to embed
chat: false
sign: false
name: false
captcha: false
optional:
censor: true # Censors sensitive data, such as IP addresses and the filter trigger in the embed
data:
ip-address: true # Includes player IP address in the embed
timestamp: true # Includes timestamp in the embed

customize: # Embed customization options
player-avatar: "https://minotar.net/avatar/%player%.png" # Place %player% where the player's username would usually go
type: # Various embed type log customizations
chat:
color: "#FF5555"
webhook:
name: "ChatGuard - Chat"
icon: "https://raw.githubusercontent.com/AleksandarHaralanov/ChatGuard/refs/heads/master/assets/ChatGuard-Logo.png"
sign:
color: "#FFAA00"
webhook:
name: "ChatGuard - Sign"
icon: "https://raw.githubusercontent.com/AleksandarHaralanov/ChatGuard/refs/heads/master/assets/ChatGuard-Logo-Gold.png"
name:
color: "#FFFF55"
webhook:
name: "ChatGuard - Name"
icon: "https://raw.githubusercontent.com/AleksandarHaralanov/ChatGuard/refs/heads/master/assets/ChatGuard-Logo-Yellow.png"
captcha:
color: "#AA00AA"
webhook:
name: "ChatGuard - Captcha"
icon: "https://raw.githubusercontent.com/AleksandarHaralanov/ChatGuard/refs/heads/master/assets/ChatGuard-Logo-Dark-Purple.png"
```

> [!CAUTION]
> If your server is not running **Essentials v2.5.8**, you must do one of the following:
> - **Disable Essentials mute support** by setting `filter.essentials-mute.enabled` to `false` in `config/config.yml`.
> - **Install Essentials** to use the temporary mute feature.
> - You can download **Essentials v2.5.8** from [here](#Requirements & Optional).
>
> Without one of the two, ChatGuard could break, and in-game messages might fail to send.

> [!NOTE]
> 🔖`v4.1.1`: Strike tiers will increment only when the filter is enabled, and a disallowed term or matching regex pattern is detected in a message. Otherwise, all strike tiers will default to 0 unless manually modified in the configuration file or through the included command.
> [!NOTE]
> Strike tiers increment only when the filter is enabled and a disallowed term or matching regex pattern is detected.
>
> Otherwise, all strike tiers default to `0` unless manually modified in `data/strikes.yml` or via the staff command.
40 changes: 27 additions & 13 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,45 @@ dependencies {

File ymlFile = file('src/main/resources/plugin.yml') as File

if (!ymlFile.exists()) throw new GradleException("The 'plugin.yml' file does not exist in 'src/main/resources'!")
if (!ymlFile.exists()) {
throw new GradleException("The 'plugin.yml' file does not exist in 'src/main/resources'.")
}

String pluginVersion
String pluginName
String ymlText = ymlFile.text

Matcher mainMatcher = (ymlText =~ /main:\s*(\S+)/)
Matcher versionMatcher = (ymlText =~ /version:\s*(\S+)/)
Matcher nameMatcher = (ymlText =~ /name:\s*(\S+)/)

if (!mainMatcher.find()) throw new GradleException("The 'main' attribute wasn't found in the 'plugin.yml' file!")
if (!mainMatcher.find()) {
throw new GradleException("The 'main' attribute wasn't found in the 'plugin.yml' file.")
}

if (versionMatcher.find()) {
version = versionMatcher.group(1)
} else {
throw new GradleException("The 'version' attribute wasn't found in the 'plugin.yml' file.")
}

if (!nameMatcher.find()) {
throw new GradleException("The 'name' attribute wasn't found in the 'plugin.yml' file.")
}

if (versionMatcher.find()) pluginVersion = versionMatcher.group(1)
else throw new GradleException("The 'version' attribute wasn't found in the 'plugin.yml' file!")
tasks.named('build') {
mustRunAfter 'clean'
}

if (nameMatcher.find()) pluginName = nameMatcher.group(1)
else throw new GradleException("The 'name' attribute wasn't found in the 'plugin.yml' file!")
tasks.register('cleanBuild') {
dependsOn 'clean', 'build'
group = 'custom'
}

jar {
manifest {
attributes(
'Implementation-Title': pluginName,
'Implementation-Version': pluginVersion
'Implementation-Title': "${project.name}",
'Implementation-Version': "${project.version}"
)
}
archiveVersion.set(pluginVersion)
archiveBaseName.set(pluginName)

archiveFileName = "${project.name}-${project.version}.jar"
}
Empty file modified gradlew
100644 → 100755
Empty file.
1 change: 0 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
rootProject.name = 'ChatGuard'

Loading