Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add version checker #15

Draft
wants to merge 6 commits into
base: ver/1.1.0
Choose a base branch
from
Draft
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
43 changes: 27 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ are commonly exploited on online servers.

- **Get Support / Contact Us**

Please join the [ArcanePlugins Discord](https://discord.gg/arcaneplugins-752310043214479462) and use the `#other-lokka30-plugins` channel.
Please join the [ArcanePlugins Discord](https://discord.gg/arcaneplugins-752310043214479462) and use
the `#other-lokka30-plugins` channel.

Alternatively, [please message lokka30](https://www.spigotmc.org/conversations/add?to=lokka30) on SpigotMC.

Expand All @@ -28,7 +29,8 @@ are commonly exploited on online servers.

- **Command Blocking**

Featuring a comprehensive command blocker, supporting blacklist/whitelisting, regex, powerful custom command rule chains, colon syntax blocking (`/plugin:command`), and more.
Featuring a comprehensive command blocker, supporting blacklist/whitelisting, regex, powerful custom command rule
chains, colon syntax blocking (`/plugin:command`), and more.

The default configuration blocks common commands used by players to check installed plugins and versions.

Expand All @@ -38,17 +40,21 @@ are commonly exploited on online servers.

- **Unit Testing**

Standard component logic, such as the Command Blocking logic, is unit-tested to ensure it is working correctly before any version can be shipped out.
Standard component logic, such as the Command Blocking logic, is unit-tested to ensure it is working correctly before
any version can be shipped out.

- **Simple & Reliable**

BlackWidow is built to be robust and lightweight, and doesn't mash half-baked features together to seem appealing (..only to break next update).
BlackWidow is built to be robust and lightweight, and doesn't mash half-baked features together to seem appealing (
..only to break next update).

- **Plenty more to come!**

There are a [variety of other features](https://github.com/orgs/ArcanePlugins/projects/5) planned, some major, such as command spying. It has the goal of being a pretty comprehensive security suite.
There are a [variety of other features](https://github.com/orgs/ArcanePlugins/projects/5) planned, some major, such as
command spying. It has the goal of being a pretty comprehensive security suite.

However, we currently have no plans for BlackWidow to become an 'anticheat' plugin in the usual sense, which seems to be fulfilled by existing solutions well enough.
However, we currently have no plans for BlackWidow to become an 'anticheat' plugin in the usual sense, which seems to
be fulfilled by existing solutions well enough.

Feel free to see a variety of screenshots below:

Expand Down Expand Up @@ -83,7 +89,8 @@ Feel free to see a variety of screenshots below:

Firstly, make sure your software setup is compatible with BlackWidow.

Please reference the [Requirements](https://github.com/ArcanePlugins/BlackWidow/wiki/Requirements) page for the most up-to-date and descriptive information on the requirements of running BlackWidow.
Please reference the [Requirements](https://github.com/ArcanePlugins/BlackWidow/wiki/Requirements) page for the most
up-to-date and descriptive information on the requirements of running BlackWidow.

The best-case scenario to run BlackWidow is:

Expand All @@ -95,11 +102,15 @@ Please be advised:

> We are considering adding future support for Velocity, BungeeCord, and Minestom. Let us know if you're interested!

> Derivatives of Spigot/Paper, such as Purpur or Pufferfish may work fine, but we don't support these setups. That being said, still give it a shot and see if everything works. :)
> Derivatives of Spigot/Paper, such as Purpur or Pufferfish may work fine, but we don't support these setups. That being
> said, still give it a shot and see if everything works. :)

> Please note that we are not interested in backporting BlackWidow to older versions of Minecraft/Java/etc. Please update your software, or feel free to fork BlackWidow and backport it.
> Please note that we are not interested in backporting BlackWidow to older versions of Minecraft/Java/etc. Please
> update your software, or feel free to fork BlackWidow and backport it.

> **We do NOT recommend** using any server software like Magma, Mohist, and Arclight which *try* to make Forge mods work with Bukkit plugins. Bukkit was *never* designed to work with Forge/Fabric/etc mods. Trying to mix the two often causes lots of unusual issues which burden server owners and plugin maintainers.
> **We do NOT recommend** using any server software like Magma, Mohist, and Arclight which *try* to make Forge mods work
> with Bukkit plugins. Bukkit was *never* designed to work with Forge/Fabric/etc mods. Trying to mix the two often causes
> lots of unusual issues which burden server owners and plugin maintainers.

## Projects Used

Expand Down Expand Up @@ -128,14 +139,14 @@ Thanks to all the other projects used, such as SpigotMC, IntelliJ, etc.
Copyright (C) 2024 lokka30 ([email](mailto:[email protected]))

> This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
>
> This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> GNU General Public License for more details.

You should have [received a copy](LICENSE.md) of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
7 changes: 7 additions & 0 deletions blackwidowlib/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>26.0.1</version>
<scope>provided</scope>
</dependency>

</dependencies>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ public class Chain {
* @since 1.0.0
*/
public Chain(
final String id,
final boolean enabled,
final Policy policy,
final Collection<String> rules,
final boolean isRegex,
final Collection<EvalCause> causeFilters
final String id,
final boolean enabled,
final Policy policy,
final Collection<String> rules,
final boolean isRegex,
final Collection<EvalCause> causeFilters
) {
this.id = Objects.requireNonNull(id, "id");
this.enabled = enabled;
Expand All @@ -86,12 +86,12 @@ public Chain(

if (!isRegex()) {
for (final String rule : rules()) {
if(rule.startsWith("/")) {
if (rule.startsWith("/")) {
continue;
}

throw new IllegalArgumentException("Rule string='" + rule + "' in chain id='" + id() + "' does" +
"not start with a slash (/); for a non-regex chain, all rules must start with a slash");
"not start with a slash (/); for a non-regex chain, all rules must start with a slash");
}
}

Expand Down Expand Up @@ -233,7 +233,7 @@ public final String id() {
* @since 1.0.0
*/
protected static String[] transformToArgs(
final String str
final String str
) {
if (str.isEmpty()) {
throw new IllegalArgumentException("str parameter must not be empty");
Expand All @@ -244,10 +244,10 @@ protected static String[] transformToArgs(
}

return str
.substring(1) // we don't want the starting slash.
.toLowerCase(Locale.ROOT) // let's use lowercase for case insensitivity.
.trim() // trim leading and trialing whitespace otherwise it can break String#split below.
.split("\\s+"); // finally, split by whitespace via regex.
.substring(1) // we don't want the starting slash.
.toLowerCase(Locale.ROOT) // let's use lowercase for case insensitivity.
.trim() // trim leading and trialing whitespace otherwise it can break String#split below.
.split("\\s+"); // finally, split by whitespace via regex.
}

/**
Expand All @@ -262,11 +262,11 @@ protected static String[] transformToArgs(
* @since 1.0.0
*/
private MatchResult matchRulePattern(
final String command,
final String rule,
final Pattern pattern,
final EvalCause cause,
final Consumer<Supplier<String>> debugger
final String command,
final String rule,
final Pattern pattern,
final EvalCause cause,
final Consumer<Supplier<String>> debugger
) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(rule, "rule");
Expand Down Expand Up @@ -298,9 +298,9 @@ private MatchResult matchRulePattern(
}

return new MatchResult(
pattern.matcher(command).find(),
rule,
"regex pattern match find result"
pattern.matcher(command).find(),
rule,
"regex pattern match find result"
);
}

Expand All @@ -315,12 +315,12 @@ private MatchResult matchRulePattern(
* @since 1.0.0
*/
private MatchResult matchRuleArgs(
final String cmd,
final String[] cmdArgs,
final String rule,
final String[] ruleArgs,
final EvalCause cause,
final Consumer<Supplier<String>> debugger
final String cmd,
final String[] cmdArgs,
final String rule,
final String[] ruleArgs,
final EvalCause cause,
final Consumer<Supplier<String>> debugger
) {
Objects.requireNonNull(cmd, "cmd");
Objects.requireNonNull(cmdArgs, "cmdArgs");
Expand All @@ -339,10 +339,10 @@ private MatchResult matchRuleArgs(
final int minLen = Math.min(cmdArgs.length, ruleArgs.length);

debugger.accept(() -> "matchRule: Checking cmd='" + cmd + "', " +
"rule='" + rule + "', " +
"minLen='" + minLen + "', " +
"cmdArgs='" + Arrays.toString(cmdArgs) + "' (len='" + cmdArgs.length + "'), " +
"ruleArgs='" + Arrays.toString(ruleArgs) + "' (len='" + ruleArgs.length + "').");
"rule='" + rule + "', " +
"minLen='" + minLen + "', " +
"cmdArgs='" + Arrays.toString(cmdArgs) + "' (len='" + cmdArgs.length + "'), " +
"ruleArgs='" + Arrays.toString(ruleArgs) + "' (len='" + ruleArgs.length + "').");

if (ruleArgs.length == 0 && cmdArgs.length == 0) {
debugger.accept(() -> "matchRule: Yes, because rule args and cmd args are both empty arrays.");
Expand All @@ -351,9 +351,9 @@ private MatchResult matchRuleArgs(

if (ruleArgs.length > cmdArgs.length) {
debugger.accept(() -> "matchRule: No, because it's impossible for this command to match this rule, " +
"because it doesn't have an equal or greater number args.");
"because it doesn't have an equal or greater number args.");
return new MatchResult(false, rule, "rule has more args than cmd, thus " +
"impossible to match");
"impossible to match");
}

for (int i = 0; i < minLen; i++) {
Expand All @@ -367,7 +367,7 @@ private MatchResult matchRuleArgs(
if (!cmdArg.equals(ruleArg) && !ruleArg.equals("*")) {
debugger.accept(() -> "matchRule: No, since args don't match and ruleArg is not a wildcard");
return new MatchResult(false, rule, "arg at index '" + i + "' didn't match, and " +
"ruleArg is not a wildcard");
"ruleArg is not a wildcard");
}

// if we're looking at the last arg of the rule, we've found a match.
Expand All @@ -394,9 +394,9 @@ private MatchResult matchRuleArgs(
* @since 1.0.0
*/
public final MatchResult matches(
final String command,
final EvalCause cause,
final Consumer<Supplier<String>> debugger
final String command,
final EvalCause cause,
final Consumer<Supplier<String>> debugger
) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(debugger, "debugger");
Expand All @@ -422,15 +422,15 @@ public final MatchResult matches(
debugger.accept(() -> "matches: Checking rule '" + rule + "'.");

final MatchResult res = isRegex() ?
matchRulePattern(command, rule, rulesRegexPatterns().get(rule), cause, debugger) :
matchRuleArgs(command, transformToArgs(command), rule, rulesAsArgs().get(rule), cause, debugger);
matchRulePattern(command, rule, rulesRegexPatterns().get(rule), cause, debugger) :
matchRuleArgs(command, transformToArgs(command), rule, rulesAsArgs().get(rule), cause, debugger);

if (res.matched()) {
debugger.accept(() -> "matches: Matched!");
return new MatchResult(
true,
res.rule(),
"in rule '" + rule + "'; " + res.description()
true,
res.rule(),
"in rule '" + rule + "'; " + res.description()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ public final class Evaluation {
* @since 1.0.0
*/
public Evaluation(
final String command,
final Policy policy,
final Chain chain,
final String rule,
final String description
final String command,
final Policy policy,
final Chain chain,
final String rule,
final String description
) {
this.command = Objects.requireNonNull(command, "command");
this.policy = Objects.requireNonNull(policy, "policy");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ public class Evaluator {
public static final AtomicBoolean SUPPRESS_EXCEPTION_MESSAGES = new AtomicBoolean(false);

public static Evaluation evaluate(
final String cmd,
final Collection<? extends Chain> chains,
final Policy defaultPolicy,
final boolean denyColonInFirstArg,
final EvalCause cause,
final Consumer<Supplier<String>> debugLogger,
final Consumer<Supplier<String>> warningLogger
final String cmd,
final Collection<? extends Chain> chains,
final Policy defaultPolicy,
final boolean denyColonInFirstArg,
final EvalCause cause,
final Consumer<Supplier<String>> debugLogger,
final Consumer<Supplier<String>> warningLogger
) {
try {
Objects.requireNonNull(cmd, "cmd");
Expand All @@ -57,45 +57,45 @@ public static Evaluation evaluate(
final MatchResult res = chain.matches(cmd, cause, debugLogger);
if (res.matched()) {
return new Evaluation(
cmd,
chain.policy(),
chain,
res.rule(),
"in chain #" + i + " (id='" + chain.id() + "'; " + res.description()
cmd,
chain.policy(),
chain,
res.rule(),
"in chain #" + i + " (id='" + chain.id() + "'; " + res.description()
);
}
i++;
}

if (denyColonInFirstArg && Chain.transformToArgs(cmd)[0].contains(":")) {
return new Evaluation(cmd, Policy.DENY, null, null, "colon found in first arg")
.withDueToColonInFirstArg(true);
.withDueToColonInFirstArg(true);
}
} catch (Exception ex) {
if (!SUPPRESS_EXCEPTION_MESSAGES.get()) {
warningLogger.accept(() ->
"An exception was caught whilst evaluating cmd '" + cmd + "': '" + ex.getClass().getSimpleName() +
"'. For best security practice, this cmd will be forcefully denied due to the error. " +
"Message: '" + ex.getMessage() + "'; Stack trace:\n"
"An exception was caught whilst evaluating cmd '" + cmd + "': '" + ex.getClass().getSimpleName() +
"'. For best security practice, this cmd will be forcefully denied due to the error. " +
"Message: '" + ex.getMessage() + "'; Stack trace:\n"
);
//noinspection CallToPrintStackTrace
ex.printStackTrace();
}
return new Evaluation(
cmd == null ? "/??? NULL COMMAND ???" : cmd,
Policy.DENY,
null,
null,
"exception caught, denying for security"
cmd == null ? "/??? NULL COMMAND ???" : cmd,
Policy.DENY,
null,
null,
"exception caught, denying for security"
).withDueToException(true);
}

return new Evaluation(
cmd,
defaultPolicy,
null,
null,
"default policy, no chains matched"
cmd,
defaultPolicy,
null,
null,
"default policy, no chains matched"
).withDueToDefaultPolicy(true);
}
}
Loading