Compare commits

...

42 Commits

Author SHA1 Message Date
Colbster937
b0fcff588b start on subscriptions 2026-02-17 17:21:34 -06:00
Colbster937
9b6bc94def Merge branch 'main' of https://github.com/WebMCDevelopment/originblacklist 2026-02-17 09:56:21 -06:00
Colbster937
4dd81995d5 disable auto updater 2026-02-17 09:56:14 -06:00
dependabot[bot]
41ce550089 Bump me.clip:placeholderapi from 2.12.1 to 2.12.2 (#18)
Bumps me.clip:placeholderapi from 2.12.1 to 2.12.2.

---
updated-dependencies:
- dependency-name: me.clip:placeholderapi
  dependency-version: 2.12.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-12 15:58:08 +00:00
Colbster937
745622fa36 update build.gradle.kts 2026-02-11 07:38:31 -06:00
Colbster937
e7343b557d Merge pull request #17 from Cirsius/main
fix NullPointerException when geyser dispatches ProxyPingEvent with a null virtual host
2026-02-11 07:34:52 -06:00
cirsius
47d451362b fix NullPointerException when geyser dispatches ProxyPingEvent with a null virtual host 2026-02-11 05:33:20 -06:00
Colbster937
f4261e0d6c update 2026-02-05 17:36:05 -06:00
Colbster937
b91b4f93e5 Merge branch 'main' of https://github.com/WebMCDevelopment/originblacklist 2026-02-05 13:36:28 -06:00
Colbster937
2e05fb6031 remove debug code 2026-02-05 13:36:23 -06:00
dependabot[bot]
a7ea336158 Bump com.github.seancfoley:ipaddress from 5.5.1 to 5.6.1 (#16)
Bumps [com.github.seancfoley:ipaddress](https://github.com/seancfoley/IPAddress) from 5.5.1 to 5.6.1.
- [Release notes](https://github.com/seancfoley/IPAddress/releases)
- [Commits](https://github.com/seancfoley/IPAddress/compare/v5.5.1...v5.6.1)

---
updated-dependencies:
- dependency-name: com.github.seancfoley:ipaddress
  dependency-version: 5.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-05 15:58:11 +00:00
dependabot[bot]
0a2c39fbd4 Bump me.clip:placeholderapi from 2.11.7 to 2.12.1 (#15)
Bumps me.clip:placeholderapi from 2.11.7 to 2.12.1.

---
updated-dependencies:
- dependency-name: me.clip:placeholderapi
  dependency-version: 2.12.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-05 15:57:56 +00:00
Colbster937
df17431df0 thing 2026-02-03 19:58:52 -06:00
Colbster937
2c0f084bb4 2.0.9 2026-01-30 12:28:51 -06:00
dependabot[bot]
c391ec3ad6 Bump com.velocitypowered:velocity-api (#14)
Bumps com.velocitypowered:velocity-api from 3.4.0-SNAPSHOT to 3.5.0-SNAPSHOT.

---
updated-dependencies:
- dependency-name: com.velocitypowered:velocity-api
  dependency-version: 3.5.0-SNAPSHOT
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-29 23:14:46 +00:00
Colbster937
ce7685367f update 2026-01-29 17:12:58 -06:00
Colbster937
bc16324342 Merge branch 'main' of https://github.com/WebMCDevelopment/originblacklist 2026-01-29 17:10:40 -06:00
Colbster937
f6cf685d1c update 2026-01-29 17:10:27 -06:00
dependabot[bot]
9b955ea77d Bump dependabot/fetch-metadata from 2.3.0 to 2.5.0 (#13)
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2.3.0 to 2.5.0.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](d7267f607e...21025c705c)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-29 23:05:54 +00:00
Colbster937
f1fe503357 update 2026-01-29 17:03:00 -06:00
Colbster937
e315eeab24 update 2026-01-29 16:59:38 -06:00
Colbster937
c4dbe81de0 test dependabot 2026-01-29 16:52:03 -06:00
Colbster937
2883adc928 configure dependabot 2026-01-29 16:49:04 -06:00
Colbster937
00b1c99dc4 add more motd customization 2026-01-24 23:01:12 -06:00
Colbster937
1cd60a4dba update bstats for platform types 2026-01-24 21:47:30 -06:00
Colbster937
ebcae682aa . 2026-01-21 19:32:30 -06:00
Colbster937
f22e800439 share plugin commit in http api 2026-01-21 10:43:47 -06:00
Colbster937
f0274ff4d4 only unregister routes fi enabled 2026-01-21 10:21:05 -06:00
Colbster937
12f9d669b4 make it register an eaglerxserver route 2026-01-20 22:03:34 -06:00
Colbster937
c43de8a1c9 accept eula 2026-01-19 15:40:40 -06:00
Colbster937
d8fa2b10c1 fix auto update invalid jar err 2026-01-17 10:38:56 -06:00
Colbster937
89311ee6de eagler 2026-01-16 18:06:31 -06:00
Colbster937
14ffd4eb08 relocate deps 2026-01-16 16:09:04 -06:00
Colbster937
50fdbb0c28 add http blacklist sharing 2026-01-14 16:44:44 -06:00
Colbster937
bb71befe78 update readme 2026-01-14 14:55:22 -06:00
Colbster937
49f4e249e5 bump version 2026-01-14 14:54:56 -06:00
Colbster937
5491efa79a management cmds 2026-01-14 14:54:30 -06:00
Colbster937
5e29f7f74a add manual update command 2026-01-13 20:32:08 -06:00
Colbster937
ffdbcfa3b4 fix version sorting 2026-01-12 16:27:50 -06:00
Colbster937
58123dddd7 eagler 2026-01-12 16:20:41 -06:00
Colbster937
91adbd5526 use commit sha in snapshot file names 2026-01-12 13:35:21 -06:00
Colbster937
2b1ccd018d auto update plugin 2026-01-12 12:34:17 -06:00
53 changed files with 2223 additions and 1046 deletions

19
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
version: 2
updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]

22
.github/workflows/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
on:
pull_request:
permissions:
contents: write
pull-requests: write
jobs:
dependabot:
runs-on: ubuntu-latest
if: github.event.pull_request.user.login == 'dependabot[bot]'
steps:
- id: metadata
uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- if: steps.metadata.outputs.update-type != 'version-update:semver-major'
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,5 +1,3 @@
name: Build Plugin
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
@@ -58,22 +56,23 @@ jobs:
run: | run: |
echo "TAG_NAME=${{ format('v{0}{1}', steps.vars.outputs.VERS, steps.ghck.outputs.EXISTS == 'true' && format('+{0}', steps.vars.outputs.COMMIT_HASH) || '') }}" >> "$GITHUB_OUTPUT" echo "TAG_NAME=${{ format('v{0}{1}', steps.vars.outputs.VERS, steps.ghck.outputs.EXISTS == 'true' && format('+{0}', steps.vars.outputs.COMMIT_HASH) || '') }}" >> "$GITHUB_OUTPUT"
echo "REL_NAME=${{ format('{0}{1}', steps.ghck.outputs.EXISTS == 'true' && 'Snapshot ' || 'v', steps.ghck.outputs.EXISTS == 'true' && steps.vars.outputs.COMMIT_HASH || steps.vars.outputs.VERS) }}" >> "$GITHUB_OUTPUT" echo "REL_NAME=${{ format('{0}{1}', steps.ghck.outputs.EXISTS == 'true' && 'Snapshot ' || 'v', steps.ghck.outputs.EXISTS == 'true' && steps.vars.outputs.COMMIT_HASH || steps.vars.outputs.VERS) }}" >> "$GITHUB_OUTPUT"
echo "ART_NAME=${{ format('{0}{1}.jar', steps.vars.outputs.AFCT, steps.ghck.outputs.EXISTS == 'true' && format('+{0}', steps.vars.outputs.COMMIT_HASH) || '') }}" >> "$GITHUB_OUTPUT"
- run: | - run: |
mkdir -p dist mkdir -p dist
cp "./build/libs/${{ steps.vars.outputs.AFCT }}" ./dist cp "./build/libs/${{ steps.vars.outputs.AFCT }}.jar" ./dist/${{ steps.dist.outputs.ART_NAME }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
path: dist/${{ steps.vars.outputs.AFCT }} path: dist/${{ steps.dist.outputs.ART_NAME }}
name: ${{ steps.vars.outputs.AFCT }} name: ${{ steps.dist.outputs.ART_NAME }}
- if: github.event_name == 'push' && github.ref == 'refs/heads/main' - if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
tag_name: ${{ steps.dist.outputs.TAG_NAME }} tag_name: ${{ steps.dist.outputs.TAG_NAME }}
name: ${{ steps.dist.outputs.REL_NAME }} name: ${{ steps.dist.outputs.REL_NAME }}
files: dist/${{ steps.vars.outputs.AFCT }} files: dist/${{ steps.dist.outputs.ART_NAME }}
prerelease: ${{ steps.ghck.outputs.EXISTS == 'true' }} prerelease: ${{ steps.ghck.outputs.EXISTS == 'true' }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -86,8 +85,8 @@ jobs:
version: ${{ steps.dist.outputs.TAG_NAME }} version: ${{ steps.dist.outputs.TAG_NAME }}
loaders: '["bukkit", "bungeecord", "paper", "purpur", "spigot", "velocity", "waterfall"]' loaders: '["bukkit", "bungeecord", "paper", "purpur", "spigot", "velocity", "waterfall"]'
game-versions: '["1.8.x", "1.9.x", "1.10.x", "1.11.x", "1.12.x", "1.13.x", "1.14.x", "1.15.x", "1.16.x", "1.17.x", "1.18.x", "1.19.x", "1.20.x", "1.21.x"]' game-versions: '["1.8.x", "1.9.x", "1.10.x", "1.11.x", "1.12.x", "1.13.x", "1.14.x", "1.15.x", "1.16.x", "1.17.x", "1.18.x", "1.19.x", "1.20.x", "1.21.x"]'
files: dist/${{ steps.vars.outputs.AFCT }} files: dist/${{ steps.dist.outputs.ART_NAME }}
primary-file: ${{ steps.vars.outputs.AFCT }} primary-file: ${{ steps.dist.outputs.ART_NAME }}
name: ${{ steps.dist.outputs.REL_NAME }} name: ${{ steps.dist.outputs.REL_NAME }}
channel: ${{ steps.ghck.outputs.EXISTS == 'true' && 'beta' || 'release' }} channel: ${{ steps.ghck.outputs.EXISTS == 'true' && 'beta' || 'release' }}
dependencies: |- dependencies: |-

4
.gitignore vendored
View File

@@ -1,8 +1,10 @@
/.gradle/ /.gradle/
/.vscode/ /.vscode/
/gradle/ /gradle/**
/build/ /build/
/bin/ /bin/
/run/ /run/
/gradlew /gradlew
/gradlew.bat /gradlew.bat
!/gradle/wrapper/
!/gradle/wrapper/*.properties

View File

@@ -9,16 +9,25 @@
- [x] Client brand based blacklisting - [x] Client brand based blacklisting
- [x] Username based blacklisting - [x] Username based blacklisting
- [x] IP based blacklisting - [x] IP based blacklisting
- [x] Modular multi-platform support
- [x] JSON5 based configuration
- [x] Kick message customization - [x] Kick message customization
- [x] Blacklist MOTD customization - [x] Blacklist MOTD customization
- [x] MiniMessage and legacy formattings supported - [x] MiniMessage and legacy formattings supported
- [x] Plugin update checker - [x] Plugin update checker
- [x] Send blacklist logs to a webhook - [x] Send blacklist logs to a webhook
- [ ] Ingame blacklist management command - [x] Ingame blacklist management commands
- [x] Blacklist sharing via EaglerXServer routes
- [x] Reverse blacklist (whitelist)
- [ ] Subscribe to an auto-updating blacklist - [ ] Subscribe to an auto-updating blacklist
- [ ] Reverse blacklist (whitelist)
<h2>Changes from v1</h2>
- [x] Modular multi-platform support
- [x] JSON5 based configuration
<h2>Requirements</h2>
- Eagler(craft)XServer v1.0.2 or newer
- JDK 21 or newer
<h2>Download</h2> <h2>Download</h2>
The latest release can be found at <b><a href="https://github.com/WebMCDevelopment/originblacklist/releases/latest/">https://github.com/WebMCDevelopment/originblacklist/releases/latest/</a></b> The latest release can be found at <b><a href="https://github.com/WebMCDevelopment/originblacklist/releases/latest/">https://github.com/WebMCDevelopment/originblacklist/releases/latest/</a></b>

View File

@@ -1,3 +1,6 @@
import groovy.lang.Closure
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.palantir.gradle.gitversion.VersionDetails
import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.language.jvm.tasks.ProcessResources import org.gradle.language.jvm.tasks.ProcessResources
import xyz.jpenilla.runpaper.task.RunServer import xyz.jpenilla.runpaper.task.RunServer
@@ -9,9 +12,9 @@ import xyz.jpenilla.runvelocity.task.RunVelocity
val PLUGIN_NAME = "OriginBlacklist" val PLUGIN_NAME = "OriginBlacklist"
val PLUGIN_IDEN = "originblacklist" val PLUGIN_IDEN = "originblacklist"
val PLUGIN_DOMN = "xyz.webmc" val PLUGIN_DOMN = "xyz.webmc.$PLUGIN_IDEN"
val PLUGIN_DESC = "An eaglercraft client blacklist plugin." val PLUGIN_DESC = "An eaglercraft client blacklist plugin."
val PLUGIN_VERS = "2.0.2" val PLUGIN_VERS = "2.0.9"
val PLUGIN_SITE = "https://github.com/WebMCDevelopment/$PLUGIN_IDEN" val PLUGIN_SITE = "https://github.com/WebMCDevelopment/$PLUGIN_IDEN"
val PLUGIN_DEPA = listOf("EaglercraftXServer") val PLUGIN_DEPA = listOf("EaglercraftXServer")
val PLUGIN_DEPB = listOf("EaglercraftXServer") val PLUGIN_DEPB = listOf("EaglercraftXServer")
@@ -26,23 +29,29 @@ val PLUGIN_CTBR = emptyList<String>()
val PLUGIN_DEPA_J = getJSONObj(PLUGIN_DEPA) val PLUGIN_DEPA_J = getBukkitBungeeDeps(PLUGIN_DEPA)
val PLUGIN_DEPB_J = getJSONObj(PLUGIN_DEPB) val PLUGIN_DEPB_J = getBukkitBungeeDeps(PLUGIN_DEPB)
val PLUGIN_DEPC_J = getJSONObjMerge(PLUGIN_DEPC, PLUGIN_SDPC) val PLUGIN_DEPC_J = getVelocityDeps(PLUGIN_DEPC, PLUGIN_SDPC)
val PLUGIN_SDPA_J = getJSONObj(PLUGIN_SDPA) val PLUGIN_SDPA_J = getBukkitBungeeDeps(PLUGIN_SDPA)
val PLUGIN_SDPB_J = getJSONObj(PLUGIN_SDPB) val PLUGIN_SDPB_J = getBukkitBungeeDeps(PLUGIN_SDPB)
val PLUGIN_PROV_J = getJSONObj(PLUGIN_PROV) val PLUGIN_PROV_J = getBukkitBungeeDeps(PLUGIN_PROV)
val PLUGIN_ATHR_J = getJSONObj(PLUGIN_ATHR) val PLUGIN_ATHR_J = getBukkitBungeeDeps(PLUGIN_ATHR)
val PLUGIN_CTBR_J = getJSONObj(PLUGIN_CTBR) val PLUGIN_CTBR_J = getBukkitBungeeDeps(PLUGIN_CTBR)
val EAGXS_VER = "1.0.8"
plugins { plugins {
id("java") id("java")
id("com.gradleup.shadow") version "9.3.0" id("com.gradleup.shadow") version "9.3.0"
id("com.palantir.git-version") version "4.2.0"
id("xyz.jpenilla.run-paper") version "3.0.2" id("xyz.jpenilla.run-paper") version "3.0.2"
id("xyz.jpenilla.run-waterfall") version "3.0.2" id("xyz.jpenilla.run-waterfall") version "3.0.2"
id("xyz.jpenilla.run-velocity") version "3.0.2" id("xyz.jpenilla.run-velocity") version "3.0.2"
} }
@Suppress("UNCHECKED_CAST")
val GIT_INFO = (extra["versionDetails"] as Closure<VersionDetails>)()
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.papermc.io/repository/maven-public/")
@@ -56,19 +65,19 @@ repositories {
} }
dependencies { dependencies {
compileOnly("com.velocitypowered:velocity-api:3.4.0-SNAPSHOT") compileOnly("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
compileOnly("org.bukkit:bukkit:1.8-R0.1-SNAPSHOT") compileOnly("org.bukkit:bukkit:1.8-R0.1-SNAPSHOT")
compileOnly("net.md-5:bungeecord-api:1.21-R0.5-SNAPSHOT") compileOnly("net.md-5:bungeecord-api:1.21-R0.5-SNAPSHOT")
compileOnly("net.lax1dude.eaglercraft.backend:api-velocity:1.0.0") compileOnly("net.lax1dude.eaglercraft.backend:api-velocity:1.0.0")
compileOnly("net.lax1dude.eaglercraft.backend:api-bungee:1.0.0") compileOnly("net.lax1dude.eaglercraft.backend:api-bungee:1.0.0")
compileOnly("net.lax1dude.eaglercraft.backend:api-bukkit:1.0.0") compileOnly("net.lax1dude.eaglercraft.backend:api-bukkit:1.0.0")
compileOnly("me.clip:placeholderapi:2.11.7") compileOnly("me.clip:placeholderapi:2.12.2")
compileOnly("net.william278:papiproxybridge:1.8.4") compileOnly("net.william278:papiproxybridge:1.8.4")
implementation("org.semver4j:semver4j:6.0.0") implementation("org.semver4j:semver4j:6.0.0")
implementation("de.marhali:json5-java:3.0.0") implementation("de.marhali:json5-java:3.0.0")
implementation("net.kyori:adventure-text-minimessage:4.26.1") implementation("net.kyori:adventure-text-minimessage:4.26.1")
implementation("net.kyori:adventure-text-serializer-legacy:4.26.1") implementation("net.kyori:adventure-text-serializer-legacy:4.26.1")
implementation("com.github.seancfoley:ipaddress:5.5.1") implementation("com.github.seancfoley:ipaddress:5.6.1")
implementation("org.bstats:bstats-bukkit:3.1.0") implementation("org.bstats:bstats-bukkit:3.1.0")
implementation("org.bstats:bstats-bungeecord:3.1.0") implementation("org.bstats:bstats-bungeecord:3.1.0")
implementation("org.bstats:bstats-velocity:3.1.0") implementation("org.bstats:bstats-velocity:3.1.0")
@@ -82,20 +91,10 @@ sourceSets {
} }
java { java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17)) toolchain.languageVersion.set(JavaLanguageVersion.of(21))
} }
tasks.withType<JavaCompile>().configureEach { val BUILD_PROPS = mapOf(
options.encoding = "UTF-8"
options.release.set(17)
}
tasks.withType<ProcessResources>() {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
outputs.upToDateWhen { false }
doFirst {
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) {
expand(mapOf(
"plugin_name" to PLUGIN_NAME, "plugin_name" to PLUGIN_NAME,
"plugin_iden" to PLUGIN_IDEN, "plugin_iden" to PLUGIN_IDEN,
"plugin_desc" to PLUGIN_DESC, "plugin_desc" to PLUGIN_DESC,
@@ -109,73 +108,103 @@ tasks.withType<ProcessResources>() {
"plugin_prov" to PLUGIN_PROV_J, "plugin_prov" to PLUGIN_PROV_J,
"plugin_athr" to PLUGIN_ATHR_J, "plugin_athr" to PLUGIN_ATHR_J,
"plugin_ctbr" to PLUGIN_CTBR_J, "plugin_ctbr" to PLUGIN_CTBR_J,
)) "git_cm_hash" to GIT_INFO.gitHashFull,
)
tasks.named<JavaCompile>("compileJava") {
options.encoding = "UTF-8"
options.release.set(21)
} }
tasks.named<ProcessResources>("processResources") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
outputs.upToDateWhen { false }
doFirst {
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) {
expand(BUILD_PROPS)
}
}
doLast {
val file = destinationDir.resolve("build.properties")
file.parentFile.mkdirs()
file.writeText(
BUILD_PROPS.entries.joinToString("\n") { (k, v) ->
"$k = $v"
}
)
} }
inputs.files(tasks.named<JavaCompile>("compileJava").map { it.outputs.files }) inputs.files(tasks.named<JavaCompile>("compileJava").map { it.outputs.files })
} }
tasks.withType<RunServer>() { tasks.named<Jar>("jar") {
minecraftVersion("1.12.2") enabled = false
runDirectory.set(layout.projectDirectory.dir("run/paper"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v1.0.8", "EaglerXServer.jar")
modrinth("placeholderapi", "2.11.7")
}
} }
tasks.withType<RunWaterfall>() { tasks.named<ShadowJar>("shadowJar") {
waterfallVersion("1.21") enabled = true
runDirectory.set(layout.projectDirectory.dir("run/waterfall")) doFirst {
downloadPlugins { delete(layout.buildDirectory.dir("libs"))
github("lax1dude", "eaglerxserver", "v1.0.8", "EaglerXServer.jar") mkdir(layout.buildDirectory.dir("libs"))
} }
} relocate("inet.ipaddr", "$PLUGIN_DOMN.shaded.ipaddress")
relocate("de.marhali.json5", "$PLUGIN_DOMN.shaded.json5")
tasks.withType<RunVelocity>() { relocate("org.bstats", "$PLUGIN_DOMN.shaded.bstats")
velocityVersion("3.4.0-SNAPSHOT") relocate("org.semver4j.semver4j", "$PLUGIN_DOMN.shaded.semver4j")
runDirectory.set(layout.projectDirectory.dir("run/velocity")) // relocate("net.kyori.adventure", "$PLUGIN_DOMN.shaded.adventure")
downloadPlugins {
github("lax1dude", "eaglerxserver", "v1.0.8", "EaglerXServer.jar")
modrinth("miniplaceholders", "3.1.0")
}
}
tasks.jar {
archiveFileName.set("$PLUGIN_NAME-$PLUGIN_VERS.jar") archiveFileName.set("$PLUGIN_NAME-$PLUGIN_VERS.jar")
} }
tasks.shadowJar { tasks.named("build") {
relocate("org.bstats", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.bstats") dependsOn(tasks.named("shadowJar"))
relocate("de.marhali.json5", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.json5")
relocate("org.semver4j.semver4j", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.semver4j")
// relocate("net.kyori.adventure", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.adventure")
archiveFileName.set("$PLUGIN_NAME-$PLUGIN_VERS.jar")
} }
tasks.register("printVars") { tasks.register("printVars") {
group = "help" group = "help"
doLast { doLast {
println("VERS = " + PLUGIN_VERS) println("VERS = " + PLUGIN_VERS)
println("AFCT = " + tasks.named("shadowJar").get().outputs.files.singleFile.name) println("AFCT = " + tasks.named("shadowJar").get().outputs.files.singleFile.name.removeSuffix(".jar"))
} }
} }
fun getJSONObj(list: List<String>): String { tasks.named<RunServer>("runServer") {
return if (list.isNotEmpty()) { minecraftVersion("1.12.2")
list.joinToString( runDirectory.set(layout.projectDirectory.dir("run/paper"))
separator = "\", \"", jvmArgs("-Dcom.mojang.eula.agree=true")
prefix = "\"", downloadPlugins {
postfix = "\"" github("lax1dude", "eaglerxserver", "v" + EAGXS_VER, "EaglerXServer.jar")
) modrinth("placeholderapi", "2.12.2")
} else {
""
} }
} }
fun getJSONObjMerge(a: List<String>, b: List<String>): String { tasks.named<RunWaterfall>("runWaterfall") {
waterfallVersion("1.21")
runDirectory.set(layout.projectDirectory.dir("run/waterfall"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v" + EAGXS_VER, "EaglerXServer.jar")
}
}
tasks.named<RunVelocity>("runVelocity") {
velocityVersion("3.5.0-SNAPSHOT")
runDirectory.set(layout.projectDirectory.dir("run/velocity"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v" + EAGXS_VER, "EaglerXServer.jar")
modrinth("miniplaceholders", "3.1.0")
}
}
fun getBukkitBungeeDeps(list: List<String>): String {
return list.joinToString(
prefix = "[",
postfix = "]"
) { "\"$it\"" }
}
fun getVelocityDeps(a: List<String>, b: List<String>): String {
val c = a.joinToString(", ") { "{\"id\":\"$it\",\"optional\":false}" } val c = a.joinToString(", ") { "{\"id\":\"$it\",\"optional\":false}" }
val d = b.joinToString(", ") { "{\"id\":\"$it\",\"optional\":true}" } val d = b.joinToString(", ") { "{\"id\":\"$it\",\"optional\":true}" }
return listOf(c, d).filter { it.isNotEmpty() }.joinToString(",") return "[" + listOf(c, d).filter { it.isNotEmpty() }.joinToString(",") + "]"
} }

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,309 +0,0 @@
package xyz.webmc.originblacklist.base;
import xyz.webmc.originblacklist.base.config.OriginBlacklistConfig;
import xyz.webmc.originblacklist.base.enums.EnumBlacklistType;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.enums.EnumLogLevel;
import xyz.webmc.originblacklist.base.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.base.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.base.util.OPlayer;
import xyz.webmc.originblacklist.base.util.UpdateChecker;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import inet.ipaddr.AddressStringException;
import inet.ipaddr.IPAddressString;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.lax1dude.eaglercraft.backend.server.api.EnumWebSocketHeader;
import net.lax1dude.eaglercraft.backend.server.api.IEaglerLoginConnection;
import net.lax1dude.eaglercraft.backend.server.api.query.IMOTDConnection;
import org.semver4j.Semver;
public final class OriginBlacklist {
public static final Semver REQUIRED_API_VER = new Semver("1.0.2");
public static final String GENERIC_STR = "GENERIC";
public static final String UNKNOWN_STR = "UNKNOWN";
public static final String PLUGIN_REPO = "WebMCDevelopment/originblacklist";
public static final int BSTATS_ID = 28776;
private final IOriginBlacklistPlugin plugin;
private final OriginBlacklistConfig config;
private boolean updateAvailable;
public OriginBlacklist(final IOriginBlacklistPlugin plugin) {
this.plugin = plugin;
this.config = new OriginBlacklistConfig(plugin);
this.checkForUpdate();
plugin.scheduleRepeat(() -> {
this.checkForUpdate();
}, 60, TimeUnit.MINUTES);
}
public final void handleLogin(final OriginBlacklistLoginEvent event) {
final OPlayer player = event.getPlayer();
final EnumBlacklistType blacklisted = this.testBlacklist(player);
if (blacklisted != EnumBlacklistType.NONE) {
final String blacklisted_value;
if (blacklisted == EnumBlacklistType.ORIGIN) {
blacklisted_value = player.getOrigin();
} else if (blacklisted == EnumBlacklistType.BRAND) {
blacklisted_value = player.getBrand();
} else if (blacklisted == EnumBlacklistType.NAME) {
blacklisted_value = player.getName();
} else if (blacklisted == EnumBlacklistType.ADDR) {
blacklisted_value = player.getAddr();
} else {
blacklisted_value = UNKNOWN_STR;
}
this.plugin.kickPlayer(this.getBlacklistedComponent("kick", blacklisted.getArrayString(),
blacklisted.getAltString(), blacklisted.getString(), "not allowed", "not allowed on the server",
blacklisted_value, blacklisted.getActionString()), event);
this.sendWebhooks(event, blacklisted);
final String name = player.getName();
if (isNonNull(name)) {
this.plugin.log(EnumLogLevel.INFO, "Prevented blacklisted player " + name + " from joining.");
}
}
}
public final void handleMOTD(final OriginBlacklistMOTDEvent event) {
final OPlayer player = event.getPlayer();
final EnumBlacklistType blacklisted = this.testBlacklist(player);
if (blacklisted != EnumBlacklistType.NONE) {
final String blacklisted_value;
if (blacklisted == EnumBlacklistType.ORIGIN) {
blacklisted_value = player.getOrigin();
} else if (blacklisted == EnumBlacklistType.ADDR) {
blacklisted_value = player.getAddr();
} else {
blacklisted_value = UNKNOWN_STR;
}
this.plugin.setMOTD(this.getBlacklistedComponent("motd", blacklisted.getArrayString(), blacklisted.getAltString(),
blacklisted.getString(), "blacklisted", "blacklisted from the server", blacklisted_value,
blacklisted.getActionString()), event);
}
}
public final boolean isDebugEnabled() {
return this.config.get("debug").getAsBoolean();
}
public final boolean isMetricsEnabled() {
return this.config.get("bStats").getAsBoolean();
}
public final OriginBlacklistConfig getConfig() {
return this.config;
}
public final void setEaglerMOTD(final Component comp, final OriginBlacklistMOTDEvent event) {
final IMOTDConnection conn = event.getEaglerEvent().getMOTDConnection();
final List<String> lst = new ArrayList<>();
for (String ln : getComponentString(comp).split("\n")) {
lst.add(ln);
}
conn.setServerMOTD(lst);
conn.setPlayerTotal(0);
conn.setPlayerUnlimited();
conn.setPlayerList(List.of());
conn.setServerIcon(this.config.getIconBytes());
conn.sendToUser();
conn.disconnect();
}
private final EnumBlacklistType testBlacklist(final OPlayer player) {
final String name = player.getName();
final String addr = player.getAddr();
final String origin = player.getOrigin();
final String brand = player.getBrand();
if (isNonNull(origin)) {
for (final Json5Element element : this.config.get("blacklist.origins").getAsJson5Array()) {
if (origin.matches(element.getAsString())) {
return EnumBlacklistType.ORIGIN;
}
}
}
if (isNonNull(brand)) {
for (final Json5Element element : this.config.get("blacklist.brands").getAsJson5Array()) {
if (brand.matches(element.getAsString())) {
return EnumBlacklistType.BRAND;
}
}
}
if (isNonNull(name)) {
for (final Json5Element element : this.config.get("blacklist.player_names").getAsJson5Array()) {
this.plugin.log(EnumLogLevel.DEBUG, element.getAsString());
if (name.matches(element.getAsString())) {
return EnumBlacklistType.NAME;
}
}
}
if (isNonNull(addr)) {
for (final Json5Element element : this.config.get("blacklist.ip_addresses").getAsJson5Array()) {
try {
if ((new IPAddressString(element.getAsString()).toAddress())
.contains((new IPAddressString(addr)).toAddress())) {
return EnumBlacklistType.ADDR;
}
} catch (final AddressStringException exception) {
exception.printStackTrace();
}
}
}
return EnumBlacklistType.NONE;
}
private final Component getBlacklistedComponent(final String type, final String id, final String blockType,
final String blockTypeAlt, final String notAllowed, final String notAllowedAlt, final String blockValue,
final String action) {
final Json5Array arr = this.config.get("messages." + type).getAsJson5Array();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.size(); i++) {
if (i > 0)
sb.append("\n");
sb.append(arr.get(i).getAsString());
}
final String str = sb.toString()
.replaceAll("%action%", this.config.get("messages.actions." + action).getAsString())
.replaceAll("%block_type%", blockType)
.replaceAll("%block_type%", blockType)
.replaceAll("%not_allowed%", notAllowed)
.replaceAll("%not_allowed_alt%", notAllowedAlt)
.replaceAll("%blocked_value%", blockValue);
return MiniMessage.miniMessage().deserialize(str);
}
private final void sendWebhooks(final OriginBlacklistLoginEvent event, final EnumBlacklistType type) {
Json5Element element = this.config.get("discord.enabled");
if (element.getAsBoolean()) {
final OPlayer player = event.getPlayer();
final EnumConnectionType connType = event.getConnectionType();
final String userAgent;
if (connType == EnumConnectionType.EAGLER) {
final IEaglerLoginConnection loginConn = event.getEaglerEvent().getLoginConnection();
userAgent = loginConn.getWebSocketHeader(EnumWebSocketHeader.HEADER_USER_AGENT);
} else {
userAgent = UNKNOWN_STR;
}
final byte[] payload = String.format(
"""
{
"content": "Blocked a blacklisted %s from joining",
"embeds": [
{
"title": "-------- Player Information --------",
"description": "**→ Name:** %s\\n**→ Origin:** %s\\n**→ Brand:** %s\\n**→ IP Address:** %s\\n**→ Protocol Version:** %s\\n**→ User Agent:** %s\\n**→ Rewind:** %s\\n**→ Player Type:** %s",
"color": 15801922,
"fields": [],
"footer": {
"text": "OriginBlacklist v%s",
"icon_url": "https://raw.githubusercontent.com/%s/refs/heads/main/img/icon.png"
}
}
],
"components": [
{
"type": 1,
"components": [
{
"type": 2,
"style": 5,
"label": "Get the Plugin",
"url": "https://github.com/%s",
"emoji": {
"name": "🌐"
}
}
]
}
]
}
""",
type.getAltString(),
player.getName().replaceAll("_", "\\_"),
player.getOrigin(),
player.getBrand(),
this.config.get("discord.send_ips").getAsBoolean() ? player.getAddr() : "*\\*CENSORED\\**",
player.getPVN(),
userAgent,
player.isRewind() ? "YES" : "NO",
connType.toString(),
this.plugin.getPluginVersion(),
PLUGIN_REPO,
PLUGIN_REPO
).getBytes();
element = this.config.get("discord.webhook_urls");
if (element instanceof Json5Array) {
for (final Json5Element _element : element.getAsJson5Array()) {
CompletableFuture.runAsync(() -> {
try {
final URL url = new URL(_element.getAsString());
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.connect();
final OutputStream os = conn.getOutputStream();
os.write(payload);
os.close();
final int code = conn.getResponseCode();
if (code < 200 || code >= 300) {
this.plugin.log(EnumLogLevel.WARN, "Webhook failed (HTTP " + code + ")");
}
conn.disconnect();
} catch (Throwable t) {
t.printStackTrace();
}
});
}
}
}
}
private final void checkForUpdate() {
CompletableFuture.runAsync(() -> {
this.updateAvailable = UpdateChecker.checkForUpdate(PLUGIN_REPO, this.plugin.getPluginVersion(),
this.config.get("update_checker.allow_snapshots").getAsBoolean());
if (this.updateAvailable) {
this.plugin.log(EnumLogLevel.INFO, "An update is available! Download it at https://github.com/" + PLUGIN_REPO + ".git");
}
});
}
public static final String getComponentString(final Component comp) {
return LegacyComponentSerializer.legacySection().serialize(comp);
}
public static final String getLegacyFromMiniMessage(final String str) {
return getComponentString(MiniMessage.miniMessage().deserialize(str));
}
public static final String getPNGBase64FromBytes(final byte[] bytes) {
return "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
}
public static final boolean isNonNull(final String str) {
return str != null && !str.isEmpty() && !str.isBlank() && !str.equals("null");
}
}

View File

@@ -1,8 +0,0 @@
package xyz.webmc.originblacklist.base.command;
public interface CommandContext {
String getPlayerName();
void reply(final String message);
boolean hasPermission(final String permission);
String[] getArgs();
}

View File

@@ -1,10 +0,0 @@
package xyz.webmc.originblacklist.base.command;
import java.util.List;
public interface ICommand {
static final String NO_PERMISSION = "<red>You don't have permission to use this command.</red>";
boolean execute(final CommandContext ctx);
List<String> suggest(final CommandContext ctx);
void usage(final CommandContext ctx);
}

View File

@@ -1,76 +0,0 @@
package xyz.webmc.originblacklist.base.command;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import java.util.List;
import de.marhali.json5.Json5Element;
public class OriginBlacklistCommand implements ICommand {
private final OriginBlacklist plugin;
public OriginBlacklistCommand(OriginBlacklist plugin) {
this.plugin = plugin;
}
@Override
public boolean execute(final CommandContext ctx) {
final String[] args = ctx.getArgs();
if (ctx.hasPermission("originblacklist.command")) {
if (args.length > 0) {
final String command = args[0].toLowerCase();
if ("reload".equals(command)) {
if (ctx.hasPermission("originblacklist.command.reload")) {
this.plugin.getConfig().reloadConfig();
ctx.reply("<green>Configuration Reloaded</green>");
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("list".equals(command)) {
if (ctx.hasPermission("originblacklist.command.reload")) {
ctx.reply("<aqua>Blacklist:</aqua>");
ctx.reply("<gold> - Origins:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.origins").getAsJson5Array()) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - Brands:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.brands").getAsJson5Array()) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - Players:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.player_names").getAsJson5Array()) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - IPs:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.ip_addresses").getAsJson5Array()) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
} else {
ctx.reply(NO_PERMISSION);
}
} else {
this.usage(ctx);
}
} else {
this.usage(ctx);
}
} else {
ctx.reply("");
}
return true;
}
@Override
public List<String> suggest(final CommandContext ctx) {
return List.of();
}
@Override
public void usage(CommandContext ctx) {
ctx.reply("<aqua>Commands:</aqua>");
ctx.reply("<gray> - /originblacklist reload</gray>");
// ctx.reply("<gray> - /originblacklist add <brand/origin/name/ip> <value></gray>");
// ctx.reply("<gray> - /originblacklist remove <brand/origin/name/ip> <value></gray>");
ctx.reply("<gray> - /originblacklist list</gray>");
}
}

View File

@@ -1,258 +0,0 @@
package xyz.webmc.originblacklist.base.config;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import javax.imageio.ImageIO;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import de.marhali.json5.Json5Primitive;
public final class OriginBlacklistConfig {
private final Json5 json5;
private final File file;
private final Path filePath;
private final File iconFile;
private final Path iconPath;
private Json5Object config;
private byte[] icon;
private String icon64;
public OriginBlacklistConfig(IOriginBlacklistPlugin plugin) {
this.json5 = Json5.builder(builder -> builder
.quoteless()
.quoteSingle()
.parseComments()
.writeComments()
.prettyPrinting()
.build());
final String dir = "plugins/" + plugin.getPluginId();
this.file = new File(dir + "/config.json5");
this.filePath = file.toPath();
this.iconFile = new File(dir + "/blacklisted.png");
this.iconPath = iconFile.toPath();
this.loadConfig();
}
private final void loadConfig() {
try {
this.reloadConfigUnsafe();
} catch (final IOException exception) {
throw new RuntimeException("Failed to load config.", exception);
}
this.reloadIconImage();
}
public final void reloadConfig() {
try {
this.reloadConfigUnsafe();
} catch (final IOException exception) {
exception.printStackTrace();
}
this.reloadIconImage();
}
private final void reloadConfigUnsafe() throws IOException {
if (this.file.exists()) {
String text = Files.readString(this.file.toPath(), StandardCharsets.UTF_8);
Json5Element parsed = this.json5.parse(text);
if (parsed instanceof Json5Object) {
this.config = (Json5Object) parsed;
if (merge(this.config, getDefaultConfig())) {
this.saveConfig();
}
} else {
throw new IOException("Config must be an object!");
}
} else {
this.config = getDefaultConfig();
this.saveConfig();
}
}
private final void reloadIconImage() {
try {
if (!this.iconFile.exists()) {
this.iconFile.getParentFile().mkdirs();
final InputStream in = OriginBlacklist.class.getResourceAsStream("/blacklisted.png");
Files.copy(in, iconPath, StandardCopyOption.REPLACE_EXISTING);
in.close();
}
final BufferedImage img = ImageIO.read(iconFile);
if (img.getWidth() == 64 && img.getHeight() == 64) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
this.icon64 = OriginBlacklist.getPNGBase64FromBytes(baos.toByteArray());
byte[] bytes = new byte[64 * 64 * 4];
for (int y = 0; y < 64; y++) {
for (int x = 0; x < 64; x++) {
int pixel = img.getRGB(x, y);
int i = (y * 64 + x) * 4;
bytes[i] = (byte) ((pixel >> 16) & 0xFF);
bytes[i + 1] = (byte) ((pixel >> 8) & 0xFF);
bytes[i + 2] = (byte) (pixel & 0xFF);
bytes[i + 3] = (byte) ((pixel >> 24) & 0xFF);
}
this.icon = bytes;
}
} else {
throw new IOException("Icon must be 64x64!");
}
} catch (final IOException exception) {
exception.printStackTrace();
}
}
public final void saveConfig() {
try {
this.file.getParentFile().mkdirs();
Files.write(this.filePath, this.json5.serialize(this.config).getBytes(StandardCharsets.UTF_8));
} catch (final IOException exception) {
exception.printStackTrace();
}
}
public final Json5Element get(final String key) {
Json5Element element = null;
if (this.config != null && OriginBlacklist.isNonNull(key)) {
element = this.config;
final String[] parts = key.split("\\.");
for (final String part : parts) {
if (element instanceof Json5Object) {
final Json5Object obj = (Json5Object) element;
if (obj.has(part)) {
element = obj.get(part);
} else {
element = null;
}
} else {
element = null;
}
if (element == null) {
break;
}
}
}
return element;
}
public final byte[] getIconBytes() {
return this.icon;
}
public final String getIconBase64URI() {
return this.icon64;
}
private static final Json5Object getDefaultConfig() {
final Json5Object obj = new Json5Object();
addJSONObj(obj, "debug", Json5Primitive.fromBoolean(false), null);
final Json5Object mobj = new Json5Object();
final Json5Array kick = new Json5Array();
kick.add("<red>This %block_type% is %not_allowed_alt%!</red>");
kick.add("<dark_gray>»</dark_gray> <gray>%blocked_value%</gray> <dark_gray>«</dark_gray>");
kick.add("");
kick.add("%action%");
kick.add("");
kick.add("<aqua>Think this is a mistake? Join our discord:</aqua>");
kick.add("<blue>discord.gg/changethisintheconfig</blue>");
addJSONObj(mobj, "kick", kick, null);
final Json5Array motd = new Json5Array();
motd.add("<red>This %block_type% is %not_allowed%!</red>");
motd.add("<dark_gray>»</dark_gray> <gray>%blocked_value%</gray>");
addJSONObj(mobj, "motd", motd, null);
final Json5Object actions = new Json5Object();
actions.add("generic", Json5Primitive.fromString("<gold>Please switch to a different %block_type%.</gold>"));
actions.add("player_name", Json5Primitive.fromString("<gold>Please change your %block_type%.</gold>"));
actions.add("ip_address", Json5Primitive.fromString("<gold>Please contact staff for assistance.</gold>"));
addJSONObj(mobj, "actions", actions, null);
addJSONObj(obj, "messages", mobj, null);
final Json5Object bobj = new Json5Object();
final Json5Array origins = new Json5Array();
origins.add(".*eaglerhackedclients\\.vercel\\.app.*");
origins.add(".*eaglerhacks\\.github\\.io.*");
origins.add(".*mcproject\\.vercel\\.app.*");
origins.add(".*wurst-b2\\.vercel\\.app.*");
origins.add(".*flqmedev\\.github\\.io.*");
origins.add(".*wurst2\\.vercel\\.app.*");
origins.add(".*dhyeybg7\\.vercel\\.app.*");
origins.add(".*uec\\.vercel\\.app.*");
origins.add(".*valux-game\\.github\\.io.*");
origins.add(".*project516\\.dev.*");
addJSONObj(bobj, "origins", origins, null);
final Json5Array brands = new Json5Array();
brands.add(".*dragonx.*");
brands.add(".*piclient.*");
brands.add(".*justin.*");
brands.add(".*wurstx.*");
brands.add(".*moonlight.*");
addJSONObj(bobj, "brands", brands, null);
final Json5Array players = new Json5Array();
players.add("Admin");
addJSONObj(bobj, "player_names", players, null);
final Json5Array ips = new Json5Array();
ips.add("192.0.2.0/24");
addJSONObj(bobj, "ip_addresses", ips, null);
addJSONObj(obj, "blacklist", bobj, null);
final Json5Object dobj = new Json5Object();
addJSONObj(dobj, "enabled", Json5Primitive.fromBoolean(false), null);
addJSONObj(dobj, "webhook_urls", new Json5Array(), null);
addJSONObj(dobj, "send_ips", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "discord", dobj, null);
final Json5Object uobj = new Json5Object();
addJSONObj(uobj, "enabled", Json5Primitive.fromBoolean(true), null);
addJSONObj(uobj, "allow_snapshots", Json5Primitive.fromBoolean(false), null);
addJSONObj(uobj, "auto_update", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "update_checker", uobj, null);
addJSONObj(obj, "bStats", Json5Primitive.fromBoolean(true), null);
return obj;
}
private static final boolean merge(final Json5Object a, final Json5Object b) {
boolean changed = false;
for (String key : b.keySet()) {
Json5Element element = b.get(key);
if (!a.has(key)) {
a.add(key, element.deepCopy());
changed = true;
} else {
final Json5Element _element = a.get(key);
if (_element instanceof Json5Object objA && element instanceof Json5Object objB) {
if (merge(objA, objB)) {
changed = true;
}
}
}
}
return changed;
}
private static final void addJSONObj(final Json5Object obj, final String key, final Json5Element value,
final String comment) {
if (OriginBlacklist.isNonNull(comment)) {
value.setComment(comment);
}
obj.add(key, value);
}
}

View File

@@ -1,8 +0,0 @@
package xyz.webmc.originblacklist.base.enums;
public enum EnumLogLevel {
INFO,
WARN,
ERROR,
DEBUG
}

View File

@@ -1,21 +0,0 @@
package xyz.webmc.originblacklist.base.util;
import xyz.webmc.originblacklist.base.enums.EnumLogLevel;
import xyz.webmc.originblacklist.base.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.base.events.OriginBlacklistMOTDEvent;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.text.Component;
import org.semver4j.Semver;
public interface IOriginBlacklistPlugin {
public String getPluginId();
public Semver getPluginVersion();
public void log(final EnumLogLevel level, final String txt);
public void kickPlayer(final Component txt, final OriginBlacklistLoginEvent event);
public void setMOTD(final Component txt, final OriginBlacklistMOTDEvent event);
public String parsePlaceholders(final OPlayer player, final String str);
public void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit);
public void shutdown();
}

View File

@@ -1,49 +0,0 @@
package xyz.webmc.originblacklist.base.util;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import org.semver4j.Semver;
import org.semver4j.Semver.VersionDiff;
public class UpdateChecker {
private static final Json5 json5 = Json5.builder(builder -> builder.build());
public static final boolean checkForUpdate(final String repo, final Semver currentVersion, final boolean allowPreRelease) {
try {
final URL url = new URL("https://api.github.com/repos/" + repo + "/releases");
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.connect();
final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Json5Element element = json5.parse(reader);
if (element instanceof Json5Array) {
final Json5Array arr = element.getAsJson5Array();
if (arr.size() > 0) {
element = arr.get(0);
if (element instanceof Json5Object) {
final Json5Object obj = element.getAsJson5Object();
final String tag = obj.get("tag_name").getAsString();
final Semver ver = new Semver(tag.substring(1));
if (ver.isGreaterThan(currentVersion) && (allowPreRelease || currentVersion.diff(ver) != VersionDiff.BUILD)) {
return true;
}
}
}
}
conn.disconnect();
return false;
} catch (final Throwable t) {
t.printStackTrace();
return false;
}
}
}

View File

@@ -0,0 +1,36 @@
package xyz.webmc.originblacklist.bukkit;
import org.bstats.charts.CustomChart;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.metrics.GenericMetricsAdapter;
import org.bstats.bukkit.Metrics;
public final class BukkitMetricsAdapter extends GenericMetricsAdapter {
private final OriginBlacklistBukkitPlugin plugin;
private Metrics metrics;
public BukkitMetricsAdapter(final OriginBlacklistBukkitPlugin plugin) {
super();
this.plugin = plugin;
}
@Override
public void start() {
if (this.metrics == null) {
this.metrics = new Metrics(this.plugin, OriginBlacklist.BSTATS.BUKKIT);
for (final CustomChart chart : this.charts) {
this.metrics.addCustomChart(chart);
}
}
}
@Override
public void shutdown() {
if (this.metrics != null) {
this.metrics.shutdown();
this.metrics = null;
}
}
}

View File

@@ -1,17 +1,19 @@
package xyz.webmc.originblacklist.bukkit; package xyz.webmc.originblacklist.bukkit;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.enums.EnumLogLevel;
import xyz.webmc.originblacklist.base.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.base.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.base.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.base.util.OPlayer;
import xyz.webmc.originblacklist.bukkit.command.OriginBlacklistCommandBukkit; import xyz.webmc.originblacklist.bukkit.command.OriginBlacklistCommandBukkit;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.core.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.core.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.core.logger.JavaLogger;
import xyz.webmc.originblacklist.core.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.core.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.core.util.OPlayer;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64; import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -39,11 +41,11 @@ import org.bukkit.util.CachedServerIcon;
import org.semver4j.Semver; import org.semver4j.Semver;
@SuppressWarnings({ "rawtypes" }) @SuppressWarnings({ "rawtypes" })
public final class OriginBlacklistBukkit extends JavaPlugin implements Listener, IOriginBlacklistPlugin { public final class OriginBlacklistBukkitPlugin extends JavaPlugin implements Listener, IOriginBlacklistPlugin {
private boolean papiPlaceholdersEnabled; private boolean papiPlaceholdersEnabled;
private Object papi; private Object papi;
private OriginBlacklist blacklist; private OriginBlacklist blacklist;
private IEaglerXServerAPI eaglerAPI; private JavaLogger logger;
private Metrics metrics; private Metrics metrics;
private CachedServerIcon iconCache; private CachedServerIcon iconCache;
@@ -70,18 +72,18 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
} else { } else {
this.papi = null; this.papi = null;
} }
this.logger = new JavaLogger(this.getLogger());
this.blacklist = new OriginBlacklist(this); this.blacklist = new OriginBlacklist(this);
this.eaglerAPI = EaglerXServerAPI.instance();
this.getCommand("originblacklist").setExecutor(new OriginBlacklistCommandBukkit(this.blacklist)); this.getCommand("originblacklist").setExecutor(new OriginBlacklistCommandBukkit(this.blacklist));
this.getServer().getPluginManager().registerEvents(this, this); this.getServer().getPluginManager().registerEvents(this, this);
this.log(EnumLogLevel.INFO, "Initialized Plugin"); this.blacklist.init();
if (this.blacklist.isMetricsEnabled()) { if (this.blacklist.isMetricsEnabled()) {
this.metrics = new Metrics(this, OriginBlacklist.BSTATS_ID); this.metrics = new Metrics(this, OriginBlacklist.BSTATS.BUKKIT);
this.metrics.addCustomChart(new AdvancedPie("player_types", () -> { this.metrics.addCustomChart(new AdvancedPie("player_types", () -> {
final Map<String, Integer> playerMap = new HashMap<>(); final Map<String, Integer> playerMap = new HashMap<>();
for (final Player player : Bukkit.getOnlinePlayers()) { for (final Player player : Bukkit.getOnlinePlayers()) {
final boolean eagler = eaglerAPI.isEaglerPlayerByUUID(player.getUniqueId()); final boolean eagler = this.getEaglerAPI().isEaglerPlayerByUUID(player.getUniqueId());
final String key = eagler ? "Eagler" : "Java"; final String key = eagler ? "Eagler" : "Java";
playerMap.put(key, playerMap.getOrDefault(key, 0) + 1); playerMap.put(key, playerMap.getOrDefault(key, 0) + 1);
} }
@@ -91,6 +93,11 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
} }
} }
@Override
public void onDisable() {
this.blacklist.shutdown();
}
@EventHandler(priority = EventPriority.NORMAL) @EventHandler(priority = EventPriority.NORMAL)
public final void onEaglerLogin(final EaglercraftLoginEvent event) { public final void onEaglerLogin(final EaglercraftLoginEvent event) {
final OPlayer player = new OPlayer(event.getLoginConnection(), event.getProfileUsername(), event.getProfileUUID()); final OPlayer player = new OPlayer(event.getLoginConnection(), event.getProfileUsername(), event.getProfileUUID());
@@ -105,15 +112,14 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public final void onJavaLogin(final AsyncPlayerPreLoginEvent event) { public final void onJavaLogin(final AsyncPlayerPreLoginEvent event) {
final OPlayer player = new OPlayer(null, event.getName(), event.getUniqueId(), final OPlayer player = new OPlayer(null, event.getName(), event.getUniqueId(), event.getAddress().toString(),
event.getAddress() != null ? event.getAddress().toString() : null, OriginBlacklist.UNKNOWN_STR, -1); OriginBlacklist.UNKNOWN_STR, OriginBlacklist.UNKNOWN_STR, -1);
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player));
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public final void onJavaMOTD(final ServerListPingEvent event) { public final void onJavaMOTD(final ServerListPingEvent event) {
final OPlayer player = new OPlayer(null, null, null, final OPlayer player = new OPlayer(null, null, null, event.getAddress().toString(), null, null, -1);
event.getAddress() != null ? event.getAddress().toString() : null, null, -1);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player)); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player));
} }
@@ -128,18 +134,23 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
} }
@Override @Override
public final void log(final EnumLogLevel level, final String txt) { public final Path getPluginJarPath() {
if (level == EnumLogLevel.WARN) { return Paths.get(this.getFile().getAbsolutePath());
this.getLogger().warning(txt);
} else if (level == EnumLogLevel.ERROR) {
this.getLogger().severe(txt);
} else if (level == EnumLogLevel.DEBUG) {
if (this.blacklist != null && this.blacklist.isDebugEnabled()) {
this.getLogger().info(txt);
} }
} else {
this.getLogger().info(txt); @Override
public final BukkitMetricsAdapter getMetrics() {
return new BukkitMetricsAdapter(this);
} }
@Override
public final IEaglerXServerAPI getEaglerAPI() {
return EaglerXServerAPI.instance();
}
@Override
public final JavaLogger getTheLogger() {
return this.logger;
} }
@Override @Override
@@ -224,12 +235,16 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
public final void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit) { public final void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit) {
long ms = unit.toMillis((long) period); long ms = unit.toMillis((long) period);
long ticks = Math.max(1L, ms / 50L); long ticks = Math.max(1L, ms / 50L);
Bukkit.getScheduler().runTaskTimer(this, task, ticks, ticks); Bukkit.getScheduler().runTaskTimer(this, task, 0, ticks);
}
@Override
public final void runAsync(final Runnable task) {
Bukkit.getScheduler().runTaskAsynchronously(this, task);
} }
@Override @Override
public final void shutdown() { public final void shutdown() {
this.metrics.shutdown();
Bukkit.getScheduler().cancelTasks(this); Bukkit.getScheduler().cancelTasks(this);
} }
} }

View File

@@ -1,36 +1,43 @@
package xyz.webmc.originblacklist.bukkit.command; package xyz.webmc.originblacklist.bukkit.command;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.base.command.CommandContext; import xyz.webmc.originblacklist.core.command.CommandContext;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
public class BKTCommandContext implements CommandContext { public final class BKTCommandContext implements CommandContext {
private final OriginBlacklist plugin;
private final CommandSender sender; private final CommandSender sender;
private final String[] args; private final String[] args;
public BKTCommandContext(final CommandSender sender, final String[] args) { public BKTCommandContext(final OriginBlacklist plugin, final CommandSender sender, final String[] args) {
this.plugin = plugin;
this.sender = sender; this.sender = sender;
this.args = args; this.args = args;
} }
@Override @Override
public String getPlayerName() { public final OriginBlacklist getPlugin() {
return this.plugin;
}
@Override
public final String getPlayerName() {
return this.sender.getName(); return this.sender.getName();
} }
@Override @Override
public void reply(final String message) { public final void reply(final String message) {
this.sender.sendMessage(OriginBlacklist.getLegacyFromMiniMessage(message)); this.sender.sendMessage(OriginBlacklist.getLegacyFromMiniMessage(message));
} }
@Override @Override
public boolean hasPermission(final String permission) { public final boolean hasPermission(final String permission) {
return this.sender.hasPermission(permission); return this.sender.hasPermission(permission);
} }
@Override @Override
public String[] getArgs() { public final String[] getArgs() {
return this.args; return this.args;
} }
} }

View File

@@ -1,7 +1,7 @@
package xyz.webmc.originblacklist.bukkit.command; package xyz.webmc.originblacklist.bukkit.command;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.base.command.OriginBlacklistCommand; import xyz.webmc.originblacklist.core.command.OriginBlacklistCommand;
import java.util.List; import java.util.List;
@@ -9,18 +9,22 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
public class OriginBlacklistCommandBukkit extends OriginBlacklistCommand implements TabExecutor { public final class OriginBlacklistCommandBukkit extends OriginBlacklistCommand implements TabExecutor {
private final OriginBlacklist plugin;
public OriginBlacklistCommandBukkit(OriginBlacklist plugin) { public OriginBlacklistCommandBukkit(OriginBlacklist plugin) {
super(plugin); super(plugin);
this.plugin = plugin;
} }
@Override @Override
public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) {
return super.execute(new BKTCommandContext(sender, args)); return super.execute(new BKTCommandContext(this.plugin, sender, args));
} }
@Override @Override
public List<String> onTabComplete(final CommandSender sender, final Command command, final String label, final String[] args) { public List<String> onTabComplete(final CommandSender sender, final Command command, final String label,
return super.suggest(new BKTCommandContext(sender, args)); final String[] args) {
return super.suggest(new BKTCommandContext(this.plugin, sender, args));
} }
} }

View File

@@ -0,0 +1,36 @@
package xyz.webmc.originblacklist.bungee;
import org.bstats.charts.CustomChart;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.metrics.GenericMetricsAdapter;
import org.bstats.bungeecord.Metrics;
public final class BungeeMetricsAdapter extends GenericMetricsAdapter {
private final OriginBlacklistBungeePlugin plugin;
private Metrics metrics;
public BungeeMetricsAdapter(final OriginBlacklistBungeePlugin plugin) {
super();
this.plugin = plugin;
}
@Override
public void start() {
if (this.metrics == null) {
this.metrics = new Metrics(this.plugin, OriginBlacklist.BSTATS.BUNGEE);
for (final CustomChart chart : this.charts) {
this.metrics.addCustomChart(chart);
}
}
}
@Override
public void shutdown() {
if (this.metrics != null) {
this.metrics.shutdown();
this.metrics = null;
}
}
}

View File

@@ -1,17 +1,19 @@
package xyz.webmc.originblacklist.bungee; package xyz.webmc.originblacklist.bungee;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.enums.EnumLogLevel;
import xyz.webmc.originblacklist.base.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.base.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.base.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.base.util.OPlayer;
import xyz.webmc.originblacklist.bungee.command.OriginBlacklistCommandBungee; import xyz.webmc.originblacklist.bungee.command.OriginBlacklistCommandBungee;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.core.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.core.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.core.logger.JavaLogger;
import xyz.webmc.originblacklist.core.util.EaglerEventPriority;
import xyz.webmc.originblacklist.core.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.core.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.core.util.OPlayer;
import java.util.HashMap; import java.net.InetSocketAddress;
import java.util.Map; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@@ -21,6 +23,7 @@ import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftLogin
import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftMOTDEvent;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.api.event.PreLoginEvent;
@@ -29,18 +32,15 @@ import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority; import net.md_5.bungee.event.EventPriority;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.AdvancedPie;
import org.semver4j.Semver; import org.semver4j.Semver;
@SuppressWarnings({ "deprecation", "rawtypes" }) @SuppressWarnings({ "deprecation", "rawtypes" })
public final class OriginBlacklistBungee extends Plugin implements Listener, IOriginBlacklistPlugin { public final class OriginBlacklistBungeePlugin extends Plugin implements Listener, IOriginBlacklistPlugin {
private ProxyServer proxy; private ProxyServer proxy;
private boolean papiPlaceholdersEnabled; private boolean papiPlaceholdersEnabled;
private Object papi; private Object papi;
private OriginBlacklist blacklist; private OriginBlacklist blacklist;
private IEaglerXServerAPI eaglerAPI; private JavaLogger logger;
private Metrics metrics;
@Override @Override
public final void onEnable() { public final void onEnable() {
@@ -66,25 +66,17 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
} else { } else {
this.papi = null; this.papi = null;
} }
this.logger = new JavaLogger(this.getLogger());
this.blacklist = new OriginBlacklist(this); this.blacklist = new OriginBlacklist(this);
this.eaglerAPI = EaglerXServerAPI.instance(); this.getProxy().getPluginManager().registerCommand(this,
this.getProxy().getPluginManager().registerCommand(this, new OriginBlacklistCommandBungee(this, this.blacklist, "originblacklist")); new OriginBlacklistCommandBungee(this, this.blacklist, "originblacklist"));
this.getProxy().getPluginManager().registerListener(this, this); this.getProxy().getPluginManager().registerListener(this, this);
this.log(EnumLogLevel.INFO, "Initialized Plugin"); this.blacklist.init();
if (this.blacklist.isMetricsEnabled()) {
this.metrics = new Metrics(this, OriginBlacklist.BSTATS_ID);
this.metrics.addCustomChart(new AdvancedPie("player_types", () -> {
final Map<String, Integer> playerMap = new HashMap<>();
for (final ProxiedPlayer player : this.proxy.getPlayers()) {
final boolean eagler = eaglerAPI.isEaglerPlayerByUUID(player.getUniqueId());
final String key = eagler ? "Eagler" : "Java";
playerMap.put(key, playerMap.getOrDefault(key, 0) + 1);
} }
return playerMap; @Override
})); public void onDisable() {
} this.blacklist.shutdown();
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
@@ -93,7 +85,7 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(event, null, EnumConnectionType.EAGLER, player)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(event, null, EnumConnectionType.EAGLER, player));
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EaglerEventPriority.EAGLER_MOTD_EVENT)
public final void onEaglerMOTD(final EaglercraftMOTDEvent event) { public final void onEaglerMOTD(final EaglercraftMOTDEvent event) {
final OPlayer player = new OPlayer(event.getMOTDConnection(), null, null); final OPlayer player = new OPlayer(event.getMOTDConnection(), null, null);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(event, null, EnumConnectionType.EAGLER, player)); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(event, null, EnumConnectionType.EAGLER, player));
@@ -101,21 +93,33 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public final void onJavaLogin(final PostLoginEvent event) { public final void onJavaLogin(final PostLoginEvent event) {
final PendingConnection conn = event.getPlayer().getPendingConnection();
final InetSocketAddress vhost = conn.getVirtualHost();
final ProxiedPlayer aPlayer = event.getPlayer(); final ProxiedPlayer aPlayer = event.getPlayer();
final String origin = vhost != null ? vhost.getHostString() + vhost.getPort() : OriginBlacklist.UNKNOWN_STR;
final OPlayer bPlayer = new OPlayer(null, aPlayer.getName(), aPlayer.getUniqueId(), final OPlayer bPlayer = new OPlayer(null, aPlayer.getName(), aPlayer.getUniqueId(),
aPlayer.getAddress().toString(), aPlayer.getClientBrand(), event.getPlayer().getPendingConnection().getVersion()); aPlayer.getAddress().toString(), aPlayer.getClientBrand(), origin,
conn.getVersion());
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, bPlayer)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, bPlayer));
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public final void onJavaHandshake(final PreLoginEvent event) { public final void onJavaHandshake(final PreLoginEvent event) {
final OPlayer player = new OPlayer(null, null, null, event.getConnection().getAddress().toString(), OriginBlacklist.UNKNOWN_STR, event.getConnection().getVersion()); final PendingConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost();
final String origin = vhost != null ? vhost.getHostString() + vhost.getPort() : OriginBlacklist.UNKNOWN_STR;
final OPlayer player = new OPlayer(null, null, null, conn.getAddress().toString(), OriginBlacklist.UNKNOWN_STR,
origin, conn.getVersion());
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player));
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public final void onJavaMOTD(final ProxyPingEvent event) { public final void onJavaMOTD(final ProxyPingEvent event) {
final OPlayer player = new OPlayer(null, null, null, event.getConnection().getAddress().toString(), null, -1); final PendingConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost();
final String origin = vhost != null ? vhost.getHostString() + vhost.getPort() : OriginBlacklist.UNKNOWN_STR;
final OPlayer player = new OPlayer(null, null, null, conn.getAddress().toString(), null,
origin, -1);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player)); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player));
} }
@@ -130,18 +134,23 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
} }
@Override @Override
public final void log(final EnumLogLevel level, final String txt) { public final Path getPluginJarPath() {
if (level == EnumLogLevel.WARN) { return Paths.get(this.getFile().getAbsolutePath());
this.getLogger().warning(txt);
} else if (level == EnumLogLevel.ERROR) {
this.getLogger().severe(txt);
} else if (level == EnumLogLevel.DEBUG) {
if (this.blacklist != null && this.blacklist.isDebugEnabled()) {
this.getLogger().info(txt);
} }
} else {
this.getLogger().info(txt); @Override
public final BungeeMetricsAdapter getMetrics() {
return new BungeeMetricsAdapter(this);
} }
@Override
public final IEaglerXServerAPI getEaglerAPI() {
return EaglerXServerAPI.instance();
}
@Override
public final JavaLogger getTheLogger() {
return this.logger;
} }
@Override @Override
@@ -188,12 +197,16 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
@Override @Override
public final void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit) { public final void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit) {
this.proxy.getScheduler().schedule(this, task, period, period, unit); this.proxy.getScheduler().schedule(this, task, 0, period, unit);
}
@Override
public final void runAsync(final Runnable task) {
this.proxy.getScheduler().runAsync(this, task);
} }
@Override @Override
public final void shutdown() { public final void shutdown() {
this.metrics.shutdown();
this.proxy.getScheduler().cancel(this); this.proxy.getScheduler().cancel(this);
} }
} }

View File

@@ -1,37 +1,44 @@
package xyz.webmc.originblacklist.bungee.command; package xyz.webmc.originblacklist.bungee.command;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.base.command.CommandContext; import xyz.webmc.originblacklist.core.command.CommandContext;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
public class BNGCommandContext implements CommandContext { public final class BNGCommandContext implements CommandContext {
private final OriginBlacklist plugin;
private final CommandSender sender; private final CommandSender sender;
private final String[] args; private final String[] args;
public BNGCommandContext(final CommandSender sender, final String[] args) { public BNGCommandContext(final OriginBlacklist plugin, final CommandSender sender, final String[] args) {
this.plugin = plugin;
this.sender = sender; this.sender = sender;
this.args = args; this.args = args;
} }
@Override @Override
public String getPlayerName() { public final OriginBlacklist getPlugin() {
return this.plugin;
}
@Override
public final String getPlayerName() {
return this.sender.getName(); return this.sender.getName();
} }
@Override @Override
public void reply(final String message) { public final void reply(final String message) {
this.sender.sendMessage(TextComponent.fromLegacy(OriginBlacklist.getLegacyFromMiniMessage(message))); this.sender.sendMessage(TextComponent.fromLegacy(OriginBlacklist.getLegacyFromMiniMessage(message)));
} }
@Override @Override
public boolean hasPermission(final String permission) { public final boolean hasPermission(final String permission) {
return this.sender.hasPermission(permission); return this.sender.hasPermission(permission);
} }
@Override @Override
public String[] getArgs() { public final String[] getArgs() {
return this.args; return this.args;
} }
} }

View File

@@ -1,8 +1,8 @@
package xyz.webmc.originblacklist.bungee.command; package xyz.webmc.originblacklist.bungee.command;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.bungee.OriginBlacklistBungeePlugin;
import xyz.webmc.originblacklist.base.command.OriginBlacklistCommand; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.bungee.OriginBlacklistBungee; import xyz.webmc.originblacklist.core.command.OriginBlacklistCommand;
import java.util.List; import java.util.List;
@@ -10,21 +10,24 @@ import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor; import net.md_5.bungee.api.plugin.TabExecutor;
public class OriginBlacklistCommandBungee extends Command implements TabExecutor { public final class OriginBlacklistCommandBungee extends Command implements TabExecutor {
private final OriginBlacklistCommand cmd; private final OriginBlacklistCommand cmd;
private final OriginBlacklist blacklist;
public OriginBlacklistCommandBungee(final OriginBlacklistBungee plugin, final OriginBlacklist blacklist, final String command) { public OriginBlacklistCommandBungee(final OriginBlacklistBungeePlugin plugin, final OriginBlacklist blacklist,
final String command) {
super(command); super(command);
this.cmd = new OriginBlacklistCommand(blacklist); this.cmd = new OriginBlacklistCommand(blacklist);
this.blacklist = blacklist;
} }
@Override @Override
public void execute(final CommandSender sender, final String[] args) { public final void execute(final CommandSender sender, final String[] args) {
this.cmd.execute(new BNGCommandContext(sender, args)); this.cmd.execute(new BNGCommandContext(this.blacklist, sender, args));
} }
@Override @Override
public List<String> onTabComplete(final CommandSender sender, final String[] args) { public final List<String> onTabComplete(final CommandSender sender, final String[] args) {
return this.cmd.suggest(new BNGCommandContext(sender, args)); return this.cmd.suggest(new BNGCommandContext(this.blacklist, sender, args));
} }
} }

View File

@@ -0,0 +1,589 @@
package xyz.webmc.originblacklist.core;
import xyz.webmc.originblacklist.core.config.OriginBlacklistConfig;
import xyz.webmc.originblacklist.core.enums.EnumBlacklistType;
import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.core.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.core.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.core.http.OriginBlacklistRequestHandler;
import xyz.webmc.originblacklist.core.logger.AbstractLogger;
import xyz.webmc.originblacklist.core.metrics.GenericMetricsAdapter;
import xyz.webmc.originblacklist.core.util.BuildInfo;
import xyz.webmc.originblacklist.core.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.core.util.OPlayer;
import xyz.webmc.originblacklist.core.util.UpdateChecker;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import inet.ipaddr.AddressStringException;
import inet.ipaddr.IPAddressString;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.lax1dude.eaglercraft.backend.server.api.IBasePlayer;
import net.lax1dude.eaglercraft.backend.server.api.IEaglerPlayer;
import net.lax1dude.eaglercraft.backend.server.api.IEaglerXServerAPI;
import net.lax1dude.eaglercraft.backend.server.api.query.IMOTDConnection;
import org.bstats.charts.AdvancedPie;
import org.semver4j.Semver;
@SuppressWarnings({ "rawtypes", "unused" })
public final class OriginBlacklist {
private static final String COMMIT_L = BuildInfo.get("git_cm_hash");
private static final String COMMIT_S = COMMIT_L.substring(0, 8);
public static final Semver REQUIRED_API_VER = new Semver("1.0.2");
public static final String GENERIC_STR = "GENERIC";
public static final String UNKNOWN_STR = "UNKNOWN";
public static final String CENSORED_STR = "CENSORED";
public static final String PLUGIN_REPO = "WebMCDevelopment/originblacklist";
private final IOriginBlacklistPlugin plugin;
private final OriginBlacklistConfig config;
private final GenericMetricsAdapter metrics;
private final AbstractLogger logger;
private final Json5 json5;
private String updateURL;
private Path jarFile;
public OriginBlacklist(final IOriginBlacklistPlugin plugin) {
this.plugin = plugin;
this.config = new OriginBlacklistConfig(this);
this.metrics = plugin.getMetrics();
this.logger = plugin.getTheLogger().setPlugin(this);
;
this.json5 = Json5.builder(builder -> builder.prettyPrinting().indentFactor(0).build());
}
public final void init() {
this.jarFile = this.plugin.getPluginJarPath();
this.plugin.scheduleRepeat(this::repeatTick, 3600, TimeUnit.SECONDS);
if (this.isBlacklistAPIEnabled()) {
OriginBlacklistRequestHandler.register(this);
}
this.metrics.addCustomChart(new AdvancedPie("player_types", () -> {
final Map<String, Integer> playerMap = new HashMap<>();
for (final Object player : this.getEaglerAPI().getAllPlayers()) {
if (player instanceof IBasePlayer bPlayer) {
final String key = (bPlayer instanceof IEaglerPlayer) ? "Eagler" : "Java";
playerMap.put(key, playerMap.getOrDefault(key, 0) + 1);
}
}
return playerMap;
}));
this.logger.info("Initialized Plugin");
this.logger.debug("Commit " + COMMIT_L);
if (this.isMetricsEnabled()) {
this.metrics.start();
}
}
public final void shutdown() {
this.logger.info("Shutting down...");
if (this.isBlacklistAPIEnabled()) {
OriginBlacklistRequestHandler.unRegister(this);
}
if (this.isMetricsEnabled()) {
this.metrics.shutdown();
}
this.plugin.shutdown();
}
public final void handleReload() {
try {
if (this.isBlacklistAPIEnabled()) {
OriginBlacklistRequestHandler.register(this);
} else {
OriginBlacklistRequestHandler.unRegister(this);
}
} catch (final Throwable t) {
}
try {
if (this.isMetricsEnabled()) {
this.metrics.start();
} else {
this.metrics.shutdown();
}
} catch (final Throwable t) {
}
}
public final void handleLogin(final OriginBlacklistLoginEvent event) {
final OPlayer player = event.getPlayer();
final EnumBlacklistType blacklisted = this.testBlacklist(player);
if (blacklisted != EnumBlacklistType.NONE) {
final String blacklisted_value;
if (blacklisted == EnumBlacklistType.ORIGIN) {
blacklisted_value = player.getOrigin();
} else if (blacklisted == EnumBlacklistType.BRAND) {
blacklisted_value = player.getBrand();
} else if (blacklisted == EnumBlacklistType.NAME) {
blacklisted_value = player.getName();
} else if (blacklisted == EnumBlacklistType.ADDR) {
blacklisted_value = player.getAddr();
} else {
blacklisted_value = UNKNOWN_STR;
}
this.plugin.kickPlayer(this.getBlacklistedComponent("kick", blacklisted.getArrayString(),
blacklisted.getAltString(), blacklisted.getString(), "not allowed", "not allowed on the server",
blacklisted_value, blacklisted.getActionString(), false), event);
this.sendWebhooks(event, blacklisted);
final String name = player.getName();
if (isNonNullStr(name)) {
this.logger.info("Prevented blacklisted player " + name + " from joining.");
this.updateLogFile(event, blacklisted);
}
}
}
public final void handleMOTD(final OriginBlacklistMOTDEvent event) {
final OPlayer player = event.getPlayer();
final EnumBlacklistType blacklisted = this.testBlacklist(player);
if (blacklisted != EnumBlacklistType.NONE) {
final String blacklisted_value;
if (blacklisted == EnumBlacklistType.ORIGIN) {
blacklisted_value = player.getOrigin();
} else if (blacklisted == EnumBlacklistType.ADDR) {
blacklisted_value = player.getAddr();
} else {
blacklisted_value = UNKNOWN_STR;
}
if (this.isMOTDEnabled()) {
this.plugin
.setMOTD(this.getBlacklistedComponent("motd", blacklisted.getArrayString(), blacklisted.getAltString(),
blacklisted.getString(), "blacklisted", "blacklisted from the server", blacklisted_value,
blacklisted.getActionString(), true), event);
}
}
}
public final boolean isDebugEnabled() {
return this.config.getBoolean("debug");
}
public final boolean isMetricsEnabled() {
return this.config.getBoolean("bStats");
}
public final boolean isMOTDEnabled() {
return this.config.getBoolean("motd.enabled");
}
public final boolean isWebhooksEnabled() {
return this.config.getBoolean("discord.webhook.enabled");
}
public final boolean isLogFileEnabled() {
return this.config.getBoolean("logFile");
}
public final boolean isBlacklistAPIEnabled() {
return this.config.getBoolean("blacklist_http_api");
}
public final OriginBlacklistConfig getConfig() {
return this.config;
}
public final void setEaglerMOTD(final Component comp, final OriginBlacklistMOTDEvent event) {
final IMOTDConnection conn = event.getEaglerEvent().getMOTDConnection();
final List<String> lst = new ArrayList<>();
for (final String ln : getComponentString(comp).split("\n")) {
lst.add(ln);
}
final List<String> pLst = new ArrayList<>();
for (final Json5Element ln : this.config.getArray("motd.players.hover").getAsJson5Array()) {
pLst.add(getLegacyFromMiniMessage(
ln.getAsString().replaceAll("%discord_invite%", this.config.getString("discord.invite"))));
}
conn.setServerMOTD(lst);
conn.setPlayerTotal(this.config.getInteger("motd.players.online"));
conn.setPlayerMax(this.config.getInteger("motd.players.max"));
conn.setPlayerList(pLst);
conn.setServerIcon(this.config.getIconBytes());
conn.sendToUser();
conn.disconnect();
}
public final void checkForUpdates(final Runnable action1, final Runnable action2) {
if (this.config.getBoolean("update_checker.enabled")) {
this.plugin.runAsync(() -> {
this.updateURL = UpdateChecker.checkForUpdates(PLUGIN_REPO, this.plugin.getPluginVersion(),
this.config.getBoolean("update_checker.allow_snapshots"));
if (isNonNullStr((this.updateURL))) {
action1.run();
} else {
action2.run();
}
});
} else {
action2.run();
}
}
public final void updatePlugin(final Runnable action1, final Runnable action2) {
try {
final URL url = (new URI(this.updateURL)).toURL();
final Path jar = this.jarFile;
final Path bak = jar.resolveSibling(jar.getFileName().toString() + ".bak");
final Path upd = jar
.resolveSibling(Paths.get(URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8)).getFileName());
try {
Files.copy(jar, bak, StandardCopyOption.REPLACE_EXISTING);
} catch (final Throwable t) {
t.printStackTrace();
}
try {
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(15000);
conn.setReadTimeout(15000);
conn.setRequestProperty("User-Agent", OriginBlacklist.getUserAgent());
conn.connect();
try (final InputStream in = conn.getInputStream()) {
Files.copy(in, upd, StandardCopyOption.REPLACE_EXISTING);
} finally {
conn.disconnect();
}
if (Files.exists(upd)) {
Files.delete(jar);
Files.delete(bak);
this.jarFile = upd;
action1.run();
return;
}
} catch (final Throwable t) {
Files.move(bak, jar, StandardCopyOption.REPLACE_EXISTING);
throw t;
}
} catch (final Throwable t) {
t.printStackTrace();
}
action2.run();
}
public final void updatePlugin() {
this.updatePlugin(() -> {
}, () -> {
});
}
public final EnumBlacklistType testBlacklist(final OPlayer player) {
final String name = player.getName();
final String addr = player.getAddr();
final String origin = player.getOrigin();
final String brand = player.getBrand();
final boolean whitelist = this.config.getBoolean("blacklist_to_whitelist");
EnumBlacklistType type = EnumBlacklistType.NONE;
if (isNonNullStr(origin)) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.ORIGIN;
for (final Json5Element element : this.config.getArray("blacklist.origins").getAsJson5Array()) {
if (origin.matches(element.getAsString())) {
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.ORIGIN;
break;
}
}
} else if (this.config.getBoolean("block_undefined_origin")) {
return whitelist ? EnumBlacklistType.NONE : EnumBlacklistType.ORIGIN;
}
if (isNonNullStr(brand)) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.BRAND;
for (final Json5Element element : this.config.getArray("blacklist.brands")) {
if (brand.matches(element.getAsString())) {
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.BRAND;
break;
}
}
}
if (isNonNullStr(name)) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.NAME;
for (final Json5Element element : this.config.getArray("blacklist.player_names")) {
if (name.matches(element.getAsString())) {
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.NAME;
break;
}
}
}
if (isNonNullStr(addr)) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.ADDR;
for (final Json5Element element : this.config.getArray("blacklist.ip_addresses")) {
try {
if ((new IPAddressString(element.getAsString()).toAddress())
.contains((new IPAddressString(addr)).toAddress())) {
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.ADDR;
break;
}
} catch (final AddressStringException exception) {
if (this.isDebugEnabled())
exception.printStackTrace();
}
}
}
return type;
}
public final String getBlacklistShare() {
try {
final Json5Object obj = new Json5Object();
obj.addProperty("plugin_version", this.plugin.getPluginVersion().getVersion() + "+" + COMMIT_S);
obj.addProperty("blacklist_to_whitelist", this.config.getBoolean("blacklist_to_whitelist"));
obj.addProperty("block_undefined_origin", this.config.getBoolean("block_undefined_origin"));
final Json5Object bObj = new Json5Object();
final String[] types = new String[] { "origins", "brands", "player_names", "ip_addresses" };
for (final String type : types) {
bObj.add(type, this.config.getArray("blacklist." + type));
}
obj.add("blacklist", bObj);
return this.json5.serialize(obj);
} catch (final Throwable t) {
return null;
}
}
public final String getDataDir() {
return "plugins/" + this.plugin.getPluginId();
}
public final IEaglerXServerAPI getEaglerAPI() {
return this.plugin.getEaglerAPI();
}
private final Component getBlacklistedComponent(final String type, final String id, final String blockType,
final String blockTypeAlt, final String notAllowed, final String notAllowedAlt, final String blockValue,
final String action, final boolean isMOTD) {
final Json5Array arr = this.config.getArray(isMOTD ? (type + ".text") : ("messages." + type));
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.size(); i++) {
if (i > 0)
sb.append("\n");
sb.append(arr.get(i).getAsString());
}
final String str = sb.toString()
.replaceAll("%action%", this.config.getString("messages.actions." + action))
.replaceAll("%block_type%", blockType)
.replaceAll("%block_type%", blockType)
.replaceAll("%not_allowed%", notAllowed)
.replaceAll("%not_allowed_alt%", notAllowedAlt)
.replaceAll("%blocked_value%", blockValue)
.replaceAll("%discord_invite%", this.config.getString("discord.invite"));
return MiniMessage.miniMessage().deserialize(str);
}
private final void sendWebhooks(final OriginBlacklistLoginEvent event, final EnumBlacklistType type) {
if (this.isWebhooksEnabled()) {
final OPlayer player = event.getPlayer();
final EnumConnectionType connType = event.getConnectionType();
/*
* final String userAgent;
* if (connType == EnumConnectionType.EAGLER) {
* final IEaglerLoginConnection loginConn =
* event.getEaglerEvent().getLoginConnection();
* userAgent =
* loginConn.getWebSocketHeader(EnumWebSocketHeader.HEADER_USER_AGENT);
* } else {
* userAgent = UNKNOWN_STR;
* }
*/
final byte[] payload = String.format(
"""
{
"content": "Blocked a blacklisted %s from joining",
"embeds": [
{
"title": "-------- Player Information --------",
"description": "**→ Name:** %s\\n**→ Origin:** %s\\n**→ Brand:** %s\\n**→ IP Address:** %s\\n**→ Protocol Version:** %s\\n**→ Host:** %s\\n**→ Rewind:** %s\\n**→ Player Type:** %s",
"color": 15801922,
"fields": [],
"footer": {
"text": "%s v%s",
"icon_url": "https://raw.githubusercontent.com/%s/refs/heads/main/img/icon.png"
}
}
],
"components": [
{
"type": 1,
"components": [
{
"type": 2,
"style": 5,
"label": "Get the Plugin",
"url": "https://github.com/%s",
"emoji": {
"name": "🌐"
}
}
]
}
]
}
""",
type.getAltString(),
player.getName().replaceAll("_", "\\_"),
player.getOrigin(),
player.getBrand(),
this.config.getBoolean("discord.send_ips") ? player.getAddr() : CENSORED_STR,
player.getPVN(),
player.getVHost(),
// userAgent,
player.isRewind() ? "YES" : "NO",
connType.toString(),
BuildInfo.get("plugin_name"),
this.plugin.getPluginVersion() + "" + COMMIT_S,
PLUGIN_REPO,
PLUGIN_REPO).getBytes();
final Json5Array arr = this.config.get("discord.webhook_urls").getAsJson5Array();
for (final Json5Element element : arr) {
this.plugin.runAsync(() -> {
try {
final URL url = (new URI(element.getAsString())).toURL();
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.connect();
final OutputStream os = conn.getOutputStream();
os.write(payload);
os.close();
final int code = conn.getResponseCode();
if (code < 200 || code >= 300) {
this.logger.warn("Webhook failed (HTTP " + code + ")");
}
conn.disconnect();
} catch (final Throwable t) {
t.printStackTrace();
}
});
}
}
}
private final void repeatTick() {
this.checkForUpdates();
}
private final void checkForUpdates() {
this.checkForUpdates(() -> {
// if (!this.config.getBoolean("update_checker.auto_update")) {
if (true) {
this.logger.info("An update is available! Download it at " + this.updateURL);
} else {
this.updatePlugin();
}
}, () -> {
});
}
private final void updateLogFile(final OriginBlacklistLoginEvent event, final EnumBlacklistType type) {
if (this.isLogFileEnabled()) {
final OPlayer player = event.getPlayer();
final String txt = Instant.now() + " - [player=" + player.getName() + "," + "blacklist_reason=" + type.toString()
+ "]";
final Path dir = Paths.get(this.getDataDir());
try {
Files.createDirectories(dir);
Files.writeString(
dir.resolve("blacklist.log"),
txt + "\n",
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.APPEND);
} catch (final Throwable t) {
t.printStackTrace();
}
}
}
public static final String getComponentString(final Component comp) {
return LegacyComponentSerializer.legacySection().serialize(comp);
}
public static final String getLegacyFromMiniMessage(final String str) {
return getComponentString(MiniMessage.miniMessage().deserialize(str));
}
public static final String getPNGBase64FromBytes(final byte[] bytes) {
return "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
}
public static final String getUserAgent() {
return BuildInfo.get("plugin_name") + "/" + BuildInfo.get("plugin_vers") + "+" + BuildInfo.get("git_cm_hash");
}
public static final boolean isNonNullStr(final String str) {
return str != null && !str.isEmpty() && !str.isBlank() && !str.equals("null");
}
public static final String sha256(String input) {
try {
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
final StringBuilder sb = new StringBuilder();
for (final byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (final Throwable t) {
throw new RuntimeException(t);
}
}
public static final class BSTATS {
public static final int VELOCITY = 29033;
public static final int BUNGEE = 29034;
public static final int BUKKIT = 29035;
}
}

View File

@@ -0,0 +1,15 @@
package xyz.webmc.originblacklist.core.command;
import xyz.webmc.originblacklist.core.OriginBlacklist;
public interface CommandContext {
public OriginBlacklist getPlugin();
public String getPlayerName();
public void reply(final String message);
public boolean hasPermission(final String permission);
public String[] getArgs();
}

View File

@@ -0,0 +1,13 @@
package xyz.webmc.originblacklist.core.command;
import java.util.List;
public interface ICommand {
public static final String NO_PERMISSION = "<red>You don't have permission to use this command.</red>";
public boolean execute(final CommandContext ctx);
public List<String> suggest(final CommandContext ctx);
public void usage(final CommandContext ctx);
}

View File

@@ -0,0 +1,162 @@
package xyz.webmc.originblacklist.core.command;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.config.OriginBlacklistConfig;
import xyz.webmc.originblacklist.core.enums.EnumBlacklistType;
import xyz.webmc.originblacklist.core.util.OPlayer;
import java.util.List;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Primitive;
public class OriginBlacklistCommand implements ICommand {
private final OriginBlacklist plugin;
public OriginBlacklistCommand(OriginBlacklist plugin) {
this.plugin = plugin;
}
@Override
public boolean execute(final CommandContext ctx) {
final String[] args = ctx.getArgs();
if (ctx.hasPermission("originblacklist.command")) {
if (args.length > 0) {
final OriginBlacklistConfig config = this.plugin.getConfig();
final String command = args[0];
final String argA = args.length > 1 ? args[1] : null;
;
final String argB = args.length > 2 ? args[2] : null;
final boolean add = "add".equalsIgnoreCase(command);
final boolean remove = "remove".equalsIgnoreCase(command);
if ("reload".equalsIgnoreCase(command)) {
if (ctx.hasPermission("originblacklist.command.reload")) {
config.reloadConfig();
this.plugin.handleReload();
ctx.reply("<green>Configuration Reloaded</green>");
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("update".equalsIgnoreCase(command)) {
if (ctx.hasPermission("originblacklist.command.update")) {
ctx.reply("<aqua>Checking for updates...</aqua>");
this.plugin.checkForUpdates(() -> {
ctx.reply("<yellow>Updating plugin...</yellow>");
this.plugin.updatePlugin(() -> {
ctx.reply("<green>Successfully updated plugin.</green>");
}, () -> {
ctx.reply("<red>Failed to update plugin.</red>");
});
}, () -> {
ctx.reply("<green>Plugin is up to date.</green>");
});
} else {
ctx.reply(NO_PERMISSION);
}
} else if ((add || remove) && OriginBlacklist.isNonNullStr(argB)) {
if ((add && ctx.hasPermission("originblacklist.command.add"))
|| (remove && ctx.hasPermission("originblacklist.command.add"))) {
final String arrName;
if ("origin".equalsIgnoreCase(argA)) {
arrName = "origins";
} else if ("brand".equalsIgnoreCase(argA)) {
arrName = "brands";
} else if ("name".equalsIgnoreCase(argA)) {
arrName = "player_names";
} else if ("ip".equalsIgnoreCase(argA)) {
arrName = "ip_addresses";
} else {
arrName = null;
}
if (OriginBlacklist.isNonNullStr(arrName)) {
final String arrPath = "blacklist." + arrName;
final Json5Array arr = config.getArray(arrPath);
if (add) {
if (!arr.contains(Json5Primitive.fromString(argB))) {
arr.add(argB);
config.set(arrPath, arr);
ctx.reply("<green>Added " + argB + " to the " + argA + " blacklist</green>");
} else {
ctx.reply("<red>" + argB + " is already on the " + argA + " blacklist</red>");
}
} else if (remove) {
if (arr.contains(Json5Primitive.fromString(argB))) {
arr.remove(Json5Primitive.fromString(argB));
config.set(arrPath, arr);
ctx.reply("<green>Removed " + argB + " from the " + argA + " blacklist</green>");
} else {
ctx.reply("<red>" + argB + " not on the " + argA + " blacklist</red>");
}
}
} else {
this.usage(ctx);
}
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("test".equalsIgnoreCase(command) && OriginBlacklist.isNonNullStr(argA)) {
if (ctx.hasPermission("originblacklist.command.test")) {
if (this.isBlacklisted(argA)) {
ctx.reply("<green>" + argA + " is on the blacklist.</green>");
} else {
ctx.reply("<red>" + argA + " is not on the blacklist.</red>");
}
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("list".equalsIgnoreCase(command)) {
if (ctx.hasPermission("originblacklist.command.list")) {
ctx.reply("<aqua>Blacklist:</aqua>");
ctx.reply("<gold> - Origins:</gold>");
for (final Json5Element element : config.getArray("blacklist.origins")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - Brands:</gold>");
for (final Json5Element element : config.getArray("blacklist.brands")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - Players:</gold>");
for (final Json5Element element : config.getArray("blacklist.player_names")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - IPs:</gold>");
for (final Json5Element element : config.getArray("blacklist.ip_addresses")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
} else {
ctx.reply(NO_PERMISSION);
}
} else {
this.usage(ctx);
}
} else {
this.usage(ctx);
}
} else {
ctx.reply("");
}
return true;
}
@Override
public final List<String> suggest(final CommandContext ctx) {
return List.of();
}
@Override
public final void usage(CommandContext ctx) {
ctx.reply("<aqua>Commands:</aqua>");
ctx.reply("<gray> - /originblacklist reload</gray>");
ctx.reply("<gray> - /originblacklist update</gray>");
ctx.reply("<gray> - /originblacklist add <origin/brand/name/ip> <arg></gray>");
ctx.reply("<gray> - /originblacklist remove <origin/brand/name/ip> <arg></gray>");
ctx.reply("<gray> - /originblacklist test <arg></gray>");
ctx.reply("<gray> - /originblacklist list</gray>");
}
private final boolean isBlacklisted(final String str) {
final OPlayer player = new OPlayer(null, str, null, str, str, null, -1);
return this.plugin.testBlacklist(player) != EnumBlacklistType.NONE;
}
}

View File

@@ -0,0 +1,515 @@
package xyz.webmc.originblacklist.core.config;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import de.marhali.json5.Json5Primitive;
public final class OriginBlacklistConfig {
public static final Json5Object DEFAULT_CONFIG = getDefaultConfig();
public static final int LATEST_CONFIG_VERSION = 2;
private final Json5 json5;
private final File file;
private final Path filePath;
private final File iconFile;
private final Path iconPath;
private Json5Object config;
private byte[] icon;
private String icon64;
public OriginBlacklistConfig(final OriginBlacklist plugin) {
this.json5 = Json5.builder(builder -> builder
.quoteless()
.quoteSingle()
.parseComments()
.writeComments()
.prettyPrinting()
.build());
this.file = new File(plugin.getDataDir() + "/config.json5");
this.filePath = file.toPath();
this.iconFile = new File(plugin.getDataDir() + "/blacklisted.png");
this.iconPath = iconFile.toPath();
this.loadConfig();
}
private final void loadConfig() {
try {
this.reloadConfigUnsafe();
this.reloadIconImage();
} catch (final IOException exception) {
throw new RuntimeException("Failed to load config.", exception);
}
}
public final void reloadConfig() {
try {
this.reloadConfigUnsafe();
this.reloadIconImage();
} catch (final IOException exception) {
exception.printStackTrace();
}
}
private final void reloadConfigUnsafe() throws IOException {
if (this.file.exists()) {
String text = Files.readString(this.file.toPath(), StandardCharsets.UTF_8);
Json5Element parsed = this.json5.parse(text);
if (parsed instanceof Json5Object) {
this.config = (Json5Object) parsed;
this.config = OriginBlacklistConfigTransformer.transformConfig(this.config);
merge(this.config, DEFAULT_CONFIG);
} else {
throw new IOException("Config must be an object!");
}
} else {
this.config = DEFAULT_CONFIG;
}
this.saveConfig();
}
private final void reloadIconImage() {
try {
if (!this.iconFile.exists()) {
this.iconFile.getParentFile().mkdirs();
final InputStream in = OriginBlacklist.class.getResourceAsStream("/blacklisted.png");
Files.copy(in, iconPath, StandardCopyOption.REPLACE_EXISTING);
in.close();
}
final BufferedImage img = ImageIO.read(iconFile);
if (img.getWidth() == 64 && img.getHeight() == 64) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
this.icon64 = OriginBlacklist.getPNGBase64FromBytes(baos.toByteArray());
final byte[] bytes = new byte[64 * 64 * 4];
for (int y = 0; y < 64; y++) {
for (int x = 0; x < 64; x++) {
int pixel = img.getRGB(x, y);
int i = (y * 64 + x) * 4;
bytes[i] = (byte) ((pixel >> 16) & 0xFF);
bytes[i + 1] = (byte) ((pixel >> 8) & 0xFF);
bytes[i + 2] = (byte) (pixel & 0xFF);
bytes[i + 3] = (byte) ((pixel >> 24) & 0xFF);
}
this.icon = bytes;
}
} else {
throw new IOException("Icon must be 64x64!");
}
} catch (final IOException exception) {
exception.printStackTrace();
}
}
public final void saveConfig() {
try {
this.file.getParentFile().mkdirs();
Files.write(this.filePath, this.json5.serialize(this.config).getBytes(StandardCharsets.UTF_8));
} catch (final IOException exception) {
exception.printStackTrace();
}
}
public final Json5Element get(final String key) {
Json5Element element = null;
if (this.config != null && OriginBlacklist.isNonNullStr(key)) {
element = this.config;
final String[] parts = splitPath(key);
for (final String part : parts) {
if (element instanceof Json5Object) {
final Json5Object obj = (Json5Object) element;
if (obj.has(part)) {
element = obj.get(part);
} else {
element = null;
}
} else {
element = null;
}
if (element == null) {
break;
}
}
}
return element;
}
public final boolean set(final String key, final Json5Element value) {
boolean ret = false;
if (this.config != null && value != null) {
final String[] parts = splitPath(key);
if (parts.length > 0) {
Json5Object obj = this.config;
for (int i = 0; i < parts.length - 1; i++) {
final String part = parts[i];
final Json5Element cur = obj.has(part) ? obj.get(part) : null;
if (cur instanceof Json5Object next) {
obj = next;
} else {
final Json5Object next = new Json5Object();
obj.add(part, next);
obj = next;
}
}
obj.add(parts[parts.length - 1], value.deepCopy());
this.saveConfig();
ret = true;
}
}
return ret;
}
public final boolean remove(final String key) {
boolean ret = false;
if (this.config != null) {
final String[] parts = splitPath(key);
if (parts.length > 0) {
Json5Object obj = this.config;
Json5Element element = obj;
for (int i = 0; i < parts.length - 1; i++) {
if (element instanceof Json5Object cur && cur.has(parts[i])) {
element = cur.get(parts[i]);
if (element instanceof Json5Object) {
obj = (Json5Object) element;
} else {
element = null;
}
} else {
element = null;
}
if (element == null) {
break;
}
}
if (element != null && obj.has(parts[parts.length - 1])) {
obj.remove(parts[parts.length - 1]);
this.saveConfig();
ret = true;
}
}
}
return ret;
}
public final String getString(final String key) {
return this.get(key).getAsString();
}
public final boolean getBoolean(final String key) {
return this.get(key).getAsBoolean();
}
public final int getInteger(final String key) {
return this.get(key).getAsInt();
}
public final Json5Array getArray(final String key) {
return this.get(key).getAsJson5Array();
}
public final Json5Object getObject(final String key) {
return this.get(key).getAsJson5Object();
}
public final byte[] getIconBytes() {
return this.icon;
}
public final String getIconBase64URI() {
return this.icon64;
}
private static final Json5Object getDefaultConfig() {
final Json5Object obj = new Json5Object();
addJSONObj(obj, "debug", Json5Primitive.fromBoolean(false), null);
final Json5Object mObj = new Json5Object();
final Json5Array kick = new Json5Array();
kick.add("<red>This %block_type% is %not_allowed_alt%!</red>");
kick.add("<dark_gray>»</dark_gray> <gray>%blocked_value%</gray> <dark_gray>«</dark_gray>");
kick.add("");
kick.add("%action%");
kick.add("");
kick.add("<aqua>Think this is a mistake? Join our discord:</aqua>");
kick.add("<blue>%discord_invite%</blue>");
addJSONObj(mObj, "kick", kick, null);
final Json5Object actions = new Json5Object();
actions.add("generic", Json5Primitive.fromString("<gold>Please switch to a different %block_type%.</gold>"));
actions.add("player_name", Json5Primitive.fromString("<gold>Please change your %block_type%.</gold>"));
actions.add("ip_address", Json5Primitive.fromString("<gold>Please contact staff for assistance.</gold>"));
addJSONObj(mObj, "actions", actions, null);
addJSONObj(obj, "messages", mObj, null);
final Json5Object nObj = new Json5Object();
addJSONObj(nObj, "enabled", Json5Primitive.fromBoolean(true), null);
final Json5Array mArr = new Json5Array();
mArr.add("<red>This %block_type% is %not_allowed%!</red>");
mArr.add("<dark_gray>»</dark_gray> <gray>%blocked_value%</gray>");
addJSONObj(nObj, "text", mArr, null);
final Json5Object mPlayers = new Json5Object();
addJSONObj(mPlayers, "online", Json5Primitive.fromNumber(0), null);
addJSONObj(mPlayers, "max", Json5Primitive.fromNumber(0), null);
final Json5Array hArr = new Json5Array();
hArr.add("<blue>Join our discord</blue>");
hArr.add("<blue>%discord_invite%</blue>");
addJSONObj(mPlayers, "hover", hArr, null);
addJSONObj(nObj, "players", mPlayers, null);
addJSONObj(obj, "motd", nObj, null);
final Json5Object bObj = new Json5Object();
final Json5Array origins = new Json5Array();
origins.add(".*eaglerhackedclients\\.vercel\\.app.*");
origins.add(".*eaglerhacks\\.github\\.io.*");
origins.add(".*mcproject\\.vercel\\.app.*");
origins.add(".*wurst-b2\\.vercel\\.app.*");
origins.add(".*flqmedev\\.github\\.io.*");
origins.add(".*wurst2\\.vercel\\.app.*");
origins.add(".*dhyeybg7\\.vercel\\.app.*");
origins.add(".*uec\\.vercel\\.app.*");
origins.add(".*valux-game\\.github\\.io.*");
origins.add(".*project516\\.dev.*");
addJSONObj(bObj, "origins", origins, null);
final Json5Array brands = new Json5Array();
brands.add(".*dragonx.*");
brands.add(".*piclient.*");
brands.add(".*justin.*");
brands.add(".*wurstx.*");
brands.add(".*moonlight.*");
addJSONObj(bObj, "brands", brands, null);
final Json5Array players = new Json5Array();
players.add("Admin");
addJSONObj(bObj, "player_names", players, null);
final Json5Array ips = new Json5Array();
ips.add("192.0.2.0/24");
addJSONObj(bObj, "ip_addresses", ips, null);
final Json5Array sub = new Json5Array();
addJSONObj(bObj, "subscriptions", sub, null);
addJSONObj(obj, "blacklist", bObj, null);
final Json5Object dObj = new Json5Object();
addJSONObj(dObj, "invite", Json5Primitive.fromString("discord.gg/changeme"), null);
final Json5Object webhook = new Json5Object();
addJSONObj(webhook, "enabled", Json5Primitive.fromBoolean(false), null);
addJSONObj(webhook, "webhook_urls", new Json5Array(), null);
addJSONObj(webhook, "send_ips", Json5Primitive.fromBoolean(true), null);
addJSONObj(dObj, "webhook", webhook, null);
addJSONObj(obj, "discord", dObj, null);
final Json5Object uObj = new Json5Object();
addJSONObj(uObj, "enabled", Json5Primitive.fromBoolean(true), null);
addJSONObj(uObj, "allow_snapshots", Json5Primitive.fromBoolean(false), null);
// addJSONObj(uObj, "check_timer", Json5Primitive.fromNumber(3600), null);
addJSONObj(uObj, "auto_update", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "update_checker", uObj, null);
addJSONObj(obj, "blacklist_http_api", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "blacklist_to_whitelist", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "block_undefined_origin", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "bStats", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "logFile", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "config_version", Json5Primitive.fromNumber(LATEST_CONFIG_VERSION), "DO NOT CHANGE");
return obj;
}
private static final boolean merge(final Json5Object aObj, final Json5Object bObj) {
final Json5Object ret = new Json5Object();
boolean changed = false;
for (final String key : bObj.keySet()) {
final Json5Element dv = bObj.get(key);
if (aObj.has(key)) {
final Json5Element v = aObj.get(key);
if (dv instanceof Json5Object) {
if (v instanceof Json5Object) {
final boolean c = merge((Json5Object) v, (Json5Object) dv);
ret.add(key, (Json5Object) v);
if (c) {
changed = true;
}
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else if (dv instanceof Json5Array) {
if (v instanceof Json5Array) {
final Json5Array vArr = (Json5Array) v;
final Json5Array dArr = (Json5Array) dv;
if (dArr.size() == 0) {
ret.add(key, vArr.deepCopy());
} else {
final Json5Element d0 = dArr.get(0);
if (d0 instanceof Json5Primitive && ((Json5Primitive) d0).isString()) {
final Json5Array out = new Json5Array();
for (final Json5Element e : vArr) {
if (e instanceof Json5Primitive && ((Json5Primitive) e).isString()) {
out.add(e.deepCopy());
}
}
if (out.size() > 0) {
if (out.size() != vArr.size()) {
changed = true;
}
ret.add(key, out);
} else {
ret.add(key, dArr.deepCopy());
changed = true;
}
} else {
boolean a = true;
for (final Json5Element e : vArr) {
if (e == null) {
a = false;
} else if (d0 instanceof Json5Object) {
if (!(e instanceof Json5Object)) {
a = false;
}
} else if (d0 instanceof Json5Array) {
if (!(e instanceof Json5Array)) {
a = false;
}
} else if (d0 instanceof Json5Primitive && e instanceof Json5Primitive) {
final Json5Primitive bp = (Json5Primitive) d0;
final Json5Primitive ap = (Json5Primitive) e;
if (bp.isBoolean()) {
if (!ap.isBoolean()) {
a = false;
}
} else if (bp.isNumber()) {
if (!ap.isNumber()) {
a = false;
}
} else if (bp.isString()) {
if (!ap.isString()) {
a = false;
}
}
} else {
a = false;
}
if (!a) {
break;
}
}
if (a) {
ret.add(key, vArr.deepCopy());
} else {
ret.add(key, dArr.deepCopy());
changed = true;
}
}
}
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else if (dv instanceof Json5Primitive) {
if (v instanceof Json5Primitive) {
final Json5Primitive dp = (Json5Primitive) dv;
final Json5Primitive vp = (Json5Primitive) v;
if (dp.isBoolean()) {
if (vp.isBoolean()) {
ret.add(key, vp.deepCopy());
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else if (dp.isNumber()) {
if (vp.isNumber()) {
ret.add(key, vp.deepCopy());
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else if (dp.isString()) {
if (vp.isString()) {
ret.add(key, vp.deepCopy());
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
} else {
ret.add(key, dv.deepCopy());
changed = true;
}
}
for (final String key : aObj.keySet()) {
if (!bObj.has(key)) {
ret.add(key, aObj.get(key).deepCopy());
}
}
for (final String key : aObj.keySet()) {
if (!bObj.has(key)) {
ret.add(key, aObj.get(key).deepCopy());
}
}
for (final String k : new ArrayList<>(aObj.keySet())) {
aObj.remove(k);
}
for (final String k : ret.keySet()) {
aObj.add(k, ret.get(k));
}
for (final String key : ret.keySet()) {
aObj.add(key, ret.get(key));
}
return changed;
}
private static final void addJSONObj(final Json5Object obj, final String key, final Json5Element value,
final String comment) {
if (OriginBlacklist.isNonNullStr(comment)) {
value.setComment(comment);
}
obj.add(key, value);
}
private static final String[] splitPath(final String key) {
final String[] ret;
if (OriginBlacklist.isNonNullStr(key)) {
ret = key.split("\\.");
} else {
ret = new String[0];
}
return ret;
}
}

View File

@@ -0,0 +1,39 @@
package xyz.webmc.originblacklist.core.config;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Object;
import de.marhali.json5.Json5Primitive;
public final class OriginBlacklistConfigTransformer {
public static final Json5Object transformConfig(final Json5Object config) {
final Json5Object obj = config.deepCopy();
final int ver = obj.get("config_version").getAsInt();
if (ver <= 1) {
final Json5Object mObj = obj.get("messages").getAsJson5Object().deepCopy();
final Json5Array motd = mObj.get("motd").getAsJson5Array().deepCopy();
mObj.remove("motd");
final Json5Object nObj = new Json5Object();
nObj.add("text", motd);
obj.remove("messages");
obj.add("messages", mObj);
obj.add("motd", nObj);
final Json5Object dObj = obj.get("discord").getAsJson5Object().deepCopy();
final Json5Primitive wEnabled = dObj.get("enabled").getAsJson5Primitive();
final Json5Array wURLS = dObj.get("webhook_urls").getAsJson5Array().deepCopy();
final Json5Primitive wAddrs = dObj.get("send_ips").getAsJson5Primitive();
dObj.remove("enabled");
dObj.remove("webhook_urls");
dObj.remove("send_ips");
final Json5Object oObj = new Json5Object();
oObj.add("enabled", wEnabled);
oObj.add("webhook_urls", wURLS);
oObj.add("send_ips", wAddrs);
dObj.add("webhook", oObj);
obj.remove("discord");
obj.add("discord", dObj);
}
obj.remove("config_version");
obj.add("config_version", Json5Primitive.fromNumber(OriginBlacklistConfig.LATEST_CONFIG_VERSION));
return obj;
}
}

View File

@@ -1,6 +1,6 @@
package xyz.webmc.originblacklist.base.enums; package xyz.webmc.originblacklist.core.enums;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
public enum EnumBlacklistType { public enum EnumBlacklistType {
ORIGIN("origin", "website", "origins", null), ORIGIN("origin", "website", "origins", null),
@@ -18,7 +18,7 @@ public enum EnumBlacklistType {
this.str = str; this.str = str;
this.alt = alt; this.alt = alt;
this.arr = arr; this.arr = arr;
this.act = OriginBlacklist.isNonNull(act) ? act : OriginBlacklist.GENERIC_STR.toLowerCase(); this.act = OriginBlacklist.isNonNullStr(act) ? act : OriginBlacklist.GENERIC_STR.toLowerCase();
} }
public final String getString() { public final String getString() {
@@ -36,4 +36,8 @@ public enum EnumBlacklistType {
public final String getActionString() { public final String getActionString() {
return this.act; return this.act;
} }
public final boolean isBlacklisted() {
return this != NONE;
}
} }

View File

@@ -1,4 +1,4 @@
package xyz.webmc.originblacklist.base.enums; package xyz.webmc.originblacklist.core.enums;
public enum EnumConnectionType { public enum EnumConnectionType {
JAVA, JAVA,

View File

@@ -1,7 +1,7 @@
package xyz.webmc.originblacklist.base.events; package xyz.webmc.originblacklist.core.events;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType; import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.util.OPlayer; import xyz.webmc.originblacklist.core.util.OPlayer;
import net.lax1dude.eaglercraft.backend.server.api.event.IBaseServerEvent; import net.lax1dude.eaglercraft.backend.server.api.event.IBaseServerEvent;

View File

@@ -1,7 +1,7 @@
package xyz.webmc.originblacklist.base.events; package xyz.webmc.originblacklist.core.events;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType; import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.util.OPlayer; import xyz.webmc.originblacklist.core.util.OPlayer;
import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftLoginEvent; import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftLoginEvent;

View File

@@ -1,7 +1,7 @@
package xyz.webmc.originblacklist.base.events; package xyz.webmc.originblacklist.core.events;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType; import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.util.OPlayer; import xyz.webmc.originblacklist.core.util.OPlayer;
import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftMOTDEvent;

View File

@@ -0,0 +1,40 @@
package xyz.webmc.originblacklist.core.http;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import java.nio.charset.StandardCharsets;
import net.lax1dude.eaglercraft.backend.server.api.webserver.IRequestContext;
import net.lax1dude.eaglercraft.backend.server.api.webserver.IRequestHandler;
import net.lax1dude.eaglercraft.backend.server.api.webserver.RouteDesc;
public final class OriginBlacklistRequestHandler implements IRequestHandler {
private static final RouteDesc route = RouteDesc.create("/originblacklist/v2/");
private final OriginBlacklist plugin;
public OriginBlacklistRequestHandler(final OriginBlacklist plugin) {
this.plugin = plugin;
}
@Override
public final void handleRequest(final IRequestContext ctx) {
final String path = ctx.getPath();
if (route.getPattern().equals(path)) {
final byte[] bytes = this.plugin.getBlacklistShare().getBytes(StandardCharsets.UTF_8);
ctx.addResponseHeader("Content-Type", "application/json; charset=utf-8");
ctx.setResponseCode(200);
ctx.setResponseBody(bytes);
} else {
ctx.getServer().get404Handler().handleRequest(ctx);
}
}
public static final void register(final OriginBlacklist plugin) {
plugin.getEaglerAPI().getWebServer().registerRoute(plugin, route, new OriginBlacklistRequestHandler(plugin));
}
public static final void unRegister(final OriginBlacklist plugin) {
plugin.getEaglerAPI().getWebServer().unregisterRoute(plugin, route);
}
}

View File

@@ -0,0 +1,19 @@
package xyz.webmc.originblacklist.core.logger;
import xyz.webmc.originblacklist.core.OriginBlacklist;
public abstract class AbstractLogger {
private OriginBlacklist plugin = null;
public abstract void info(final String txt, final Object ...args);
public abstract void warn(final String txt, final Object ...args);
public abstract void error(final String txt, final Object ...args);
public final AbstractLogger setPlugin(final OriginBlacklist plugin) {
this.plugin = plugin;
return this;
}
public final void debug(final String txt, final Object ...args) {
if (this.plugin.isDebugEnabled()) {
this.info(txt, args);
}
}
}

View File

@@ -0,0 +1,27 @@
package xyz.webmc.originblacklist.core.logger;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class JavaLogger extends AbstractLogger {
private final Logger logger;
public JavaLogger(final Logger logger) {
this.logger = logger;
}
@Override
public final void info(final String txt, final Object ...args) {
this.logger.log(Level.INFO, txt, args);
}
@Override
public final void warn(final String txt, final Object ...args) {
this.logger.log(Level.WARNING, txt, args);
}
@Override
public final void error(final String txt, final Object ...args) {
this.logger.log(Level.SEVERE, txt, args);
}
}

View File

@@ -0,0 +1,26 @@
package xyz.webmc.originblacklist.core.logger;
import org.slf4j.Logger;
public final class SLF4JLogger extends AbstractLogger {
private final Logger logger;
public SLF4JLogger(final Logger logger) {
this.logger = logger;
}
@Override
public final void info(final String txt, final Object ...args) {
this.logger.info(txt, args);
}
@Override
public final void warn(final String txt, final Object ...args) {
this.logger.warn(txt, args);
}
@Override
public final void error(final String txt, final Object ...args) {
this.logger.error(txt, args);
}
}

View File

@@ -0,0 +1,21 @@
package xyz.webmc.originblacklist.core.metrics;
import java.util.ArrayList;
import java.util.List;
import org.bstats.charts.CustomChart;
public abstract class GenericMetricsAdapter {
protected final List<CustomChart> charts;
protected GenericMetricsAdapter() {
this.charts = new ArrayList<>();
}
public final void addCustomChart(final CustomChart chart) {
this.charts.add(chart);
}
public abstract void start();
public abstract void shutdown();
}

View File

@@ -0,0 +1,20 @@
package xyz.webmc.originblacklist.core.util;
import java.io.InputStream;
import java.util.Properties;
public final class BuildInfo {
private static final Properties properties;
public static final String get(final String key) {
return properties.getProperty(key).trim();
}
static {
properties = new Properties();
try (final InputStream in = BuildInfo.class.getClassLoader().getResourceAsStream("build.properties")) {
properties.load(in);
} catch (final Throwable t) {
}
}
}

View File

@@ -1,4 +1,4 @@
package xyz.webmc.originblacklist.base.util; package xyz.webmc.originblacklist.core.util;
public final class ChatFormat { public final class ChatFormat {
private static final String SYMBOL = "§"; private static final String SYMBOL = "§";

View File

@@ -0,0 +1,5 @@
package xyz.webmc.originblacklist.core.util;
public final class EaglerEventPriority {
public static final int EAGLER_MOTD_EVENT = 100;
}

View File

@@ -0,0 +1,40 @@
package xyz.webmc.originblacklist.core.util;
import xyz.webmc.originblacklist.core.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.core.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.core.logger.AbstractLogger;
import xyz.webmc.originblacklist.core.metrics.GenericMetricsAdapter;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.text.Component;
import net.lax1dude.eaglercraft.backend.server.api.IEaglerXServerAPI;
import org.semver4j.Semver;
@SuppressWarnings({ "rawtypes" })
public interface IOriginBlacklistPlugin {
public String getPluginId();
public Semver getPluginVersion();
public Path getPluginJarPath();
public GenericMetricsAdapter getMetrics();
public AbstractLogger getTheLogger();
public IEaglerXServerAPI getEaglerAPI();
public void kickPlayer(final Component txt, final OriginBlacklistLoginEvent event);
public void setMOTD(final Component txt, final OriginBlacklistMOTDEvent event);
public String parsePlaceholders(final OPlayer player, final String str);
public void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit);
public void runAsync(final Runnable task);
public void shutdown();
}

View File

@@ -1,4 +1,4 @@
package xyz.webmc.originblacklist.base.util; package xyz.webmc.originblacklist.core.util;
import org.semver4j.Semver; import org.semver4j.Semver;

View File

@@ -1,6 +1,6 @@
package xyz.webmc.originblacklist.base.util; package xyz.webmc.originblacklist.core.util;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
@@ -16,16 +16,18 @@ public final class OPlayer {
private final String name; private final String name;
private final UUID uuid; private final UUID uuid;
private final String brand; private final String brand;
private final String vhost;
private final boolean rewind; private final boolean rewind;
private final int pvn; private final int pvn;
public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid, final String addr, public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid, final String addr,
final String brand, final int pvn) { final String brand, final String vhost, final int pvn) {
this.name = name; this.name = name;
this.uuid = uuid; this.uuid = uuid;
if (conn != null) { if (conn != null) {
this.origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN); this.origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN);
this.addr = formatSocketAddress(conn.getSocketAddress()); this.addr = formatSocketAddress(conn.getSocketAddress());
this.vhost = conn.isWebSocketSecure() ? "wss://" : "ws://" + conn.getWebSocketHost();
if (conn instanceof IEaglerLoginConnection) { if (conn instanceof IEaglerLoginConnection) {
final IEaglerLoginConnection loginConn = (IEaglerLoginConnection) conn; final IEaglerLoginConnection loginConn = (IEaglerLoginConnection) conn;
this.brand = loginConn.getEaglerBrandString(); this.brand = loginConn.getEaglerBrandString();
@@ -40,13 +42,14 @@ public final class OPlayer {
this.origin = OriginBlacklist.UNKNOWN_STR; this.origin = OriginBlacklist.UNKNOWN_STR;
this.addr = formatIPAddress(addr); this.addr = formatIPAddress(addr);
this.brand = brand; this.brand = brand;
this.vhost = vhost;
this.rewind = false; this.rewind = false;
this.pvn = pvn; this.pvn = pvn;
} }
} }
public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid) { public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid) {
this(conn, name, uuid, null, null, -1); this(conn, name, uuid, null, null, null, -1);
} }
public final String getOrigin() { public final String getOrigin() {
@@ -69,6 +72,10 @@ public final class OPlayer {
return this.brand; return this.brand;
} }
public final String getVHost() {
return this.vhost;
}
public final boolean isRewind() { public final boolean isRewind() {
return this.rewind; return this.rewind;
} }
@@ -78,9 +85,7 @@ public final class OPlayer {
} }
private static final String formatIPAddress(String addr) { private static final String formatIPAddress(String addr) {
if (addr == null) { if (OriginBlacklist.isNonNullStr(addr)) {
addr = OriginBlacklist.UNKNOWN_STR;
} else {
if (addr.startsWith("/")) { if (addr.startsWith("/")) {
addr = addr.substring(1); addr = addr.substring(1);
} }
@@ -132,6 +137,8 @@ public final class OPlayer {
if (hex && c == 6 && addr.indexOf("::") == -1) { if (hex && c == 6 && addr.indexOf("::") == -1) {
addr = addr + "::"; addr = addr + "::";
} }
} else {
addr = OriginBlacklist.UNKNOWN_STR;
} }
return addr; return addr;

View File

@@ -0,0 +1,102 @@
package xyz.webmc.originblacklist.core.util;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import org.semver4j.Semver;
import org.semver4j.Semver.VersionDiff;
public final class UpdateChecker {
private static final Json5 json5 = Json5.builder(builder -> builder.build());
public static final String checkForUpdates(final String repo, final Semver currentVersion,
final boolean allowSnapshots) {
try {
final URL url = (new URI("https://api.github.com/repos/" + repo + "/releases")).toURL();
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestProperty("User-Agent", OriginBlacklist.getUserAgent());
conn.setRequestProperty("Accept", "application/vnd.github+json");
conn.connect();
final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String ret = null;
Json5Element element = json5.parse(reader);
reader.close();
Json5Object rel = null;
Json5Object snap = null;
if (element instanceof Json5Array) {
final Json5Array arr = element.getAsJson5Array();
for (int i = 0; i < arr.size(); i++) {
element = arr.get(i);
if (element instanceof Json5Object) {
final Json5Object obj = element.getAsJson5Object();
if (!obj.has("published_at")) {
continue;
}
final boolean pre = obj.get("prerelease").getAsBoolean();
if (!pre) {
if (rel == null
|| obj.get("published_at").getAsString().compareTo(rel.get("published_at").getAsString()) > 0) {
rel = obj;
}
} else {
if (snap == null
|| obj.get("published_at").getAsString().compareTo(snap.get("published_at").getAsString()) > 0) {
snap = obj;
}
}
}
continue;
}
for (int i = 0; i < 2; i++) {
final Json5Object obj = i == 0 ? rel : snap;
if (obj == null || (i == 1 && !allowSnapshots)) {
continue;
}
final String tag = obj.get("tag_name").getAsString();
final Semver ver = new Semver(tag.startsWith("v") ? tag.substring(1) : tag);
String comm;
try {
comm = ver.getBuild().get(0).trim();
} catch (final Throwable t) {
comm = "";
}
if (ver.isGreaterThan(currentVersion) || (allowSnapshots && currentVersion.diff(ver) == VersionDiff.BUILD
&& OriginBlacklist.isNonNullStr(comm) && !BuildInfo.get("git_cm_hash").startsWith(comm))) {
element = obj.get("assets");
if (element instanceof Json5Array) {
final Json5Array aArr = element.getAsJson5Array();
if (aArr.size() > 0) {
element = aArr.get(0);
if (element instanceof Json5Object) {
ret = element.getAsJson5Object().get("browser_download_url").getAsString();
break;
}
}
}
}
}
}
conn.disconnect();
return ret;
} catch (final Throwable t) {
t.printStackTrace();
return null;
}
}
}

View File

@@ -1,18 +1,20 @@
package xyz.webmc.originblacklist.velocity; package xyz.webmc.originblacklist.velocity;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.base.enums.EnumConnectionType; import xyz.webmc.originblacklist.core.enums.EnumConnectionType;
import xyz.webmc.originblacklist.base.enums.EnumLogLevel; import xyz.webmc.originblacklist.core.events.OriginBlacklistLoginEvent;
import xyz.webmc.originblacklist.base.events.OriginBlacklistLoginEvent; import xyz.webmc.originblacklist.core.events.OriginBlacklistMOTDEvent;
import xyz.webmc.originblacklist.base.events.OriginBlacklistMOTDEvent; import xyz.webmc.originblacklist.core.logger.SLF4JLogger;
import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin; import xyz.webmc.originblacklist.core.util.EaglerEventPriority;
import xyz.webmc.originblacklist.base.util.IncompatibleDependencyException; import xyz.webmc.originblacklist.core.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.base.util.OPlayer; import xyz.webmc.originblacklist.core.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.core.util.OPlayer;
import xyz.webmc.originblacklist.velocity.command.OriginBlacklistCommandVelocity; import xyz.webmc.originblacklist.velocity.command.OriginBlacklistCommandVelocity;
import java.util.HashMap; import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -22,7 +24,9 @@ import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.event.player.PlayerClientBrandEvent; import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyPingEvent; import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.api.proxy.server.ServerPing;
@@ -33,36 +37,32 @@ import net.lax1dude.eaglercraft.backend.server.api.IEaglerXServerAPI;
import net.lax1dude.eaglercraft.backend.server.api.velocity.EaglerXServerAPI; import net.lax1dude.eaglercraft.backend.server.api.velocity.EaglerXServerAPI;
import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftLoginEvent; import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftLoginEvent;
import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftMOTDEvent;
import org.bstats.charts.AdvancedPie;
import org.bstats.velocity.Metrics;
import org.bstats.velocity.Metrics.Factory; import org.bstats.velocity.Metrics.Factory;
import org.semver4j.Semver; import org.semver4j.Semver;
import org.slf4j.Logger; import org.slf4j.Logger;
@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" }) @SuppressWarnings({ "deprecation", "rawtypes" })
public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin { public final class OriginBlacklistVelocityPlugin implements IOriginBlacklistPlugin {
private final PluginContainer plugin; private final PluginContainer plugin;
private final Factory metricsFactory; private final Factory metricsFactory;
private final ProxyServer proxy; private final ProxyServer proxy;
private final Logger logger; private final SLF4JLogger logger;
private boolean papiPlaceholdersEnabled; private boolean papiPlaceholdersEnabled;
private Object papi; private Object papi;
private OriginBlacklist blacklist; private OriginBlacklist blacklist;
private IEaglerXServerAPI eaglerAPI;
private Metrics metrics;
@Inject @Inject
public OriginBlacklistVelocity(final PluginContainer plugin, Factory metricsFactory, final ProxyServer proxy, public OriginBlacklistVelocityPlugin(final PluginContainer plugin, Factory metricsFactory, final ProxyServer proxy,
final Logger logger) { final Logger logger) {
this.plugin = plugin; this.plugin = plugin;
this.metricsFactory = metricsFactory; this.metricsFactory = metricsFactory;
this.proxy = proxy; this.proxy = proxy;
this.logger = logger; this.logger = new SLF4JLogger(logger);
} }
@Subscribe @Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) { public final void onProxyInitialization(final ProxyInitializeEvent event) {
this.proxy.getPluginManager().getPlugin("eaglerxserver").ifPresentOrElse(plugin -> { this.proxy.getPluginManager().getPlugin("eaglerxserver").ifPresentOrElse(plugin -> {
final Semver version = new Semver(plugin.getDescription().getVersion().orElse("1.0.0")); final Semver version = new Semver(plugin.getDescription().getVersion().orElse("1.0.0"));
if (version.isLowerThan(OriginBlacklist.REQUIRED_API_VER)) { if (version.isLowerThan(OriginBlacklist.REQUIRED_API_VER)) {
@@ -84,23 +84,13 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
this.papi = null; this.papi = null;
} }
this.blacklist = new OriginBlacklist(this); this.blacklist = new OriginBlacklist(this);
this.eaglerAPI = EaglerXServerAPI.instance();
this.proxy.getCommandManager().register("originblacklist", new OriginBlacklistCommandVelocity(this.blacklist)); this.proxy.getCommandManager().register("originblacklist", new OriginBlacklistCommandVelocity(this.blacklist));
this.log(EnumLogLevel.INFO, "Initialized Plugin"); this.blacklist.init();
if (this.blacklist.isMetricsEnabled()) {
this.metrics = this.metricsFactory.make(this, OriginBlacklist.BSTATS_ID);
this.metrics.addCustomChart(new AdvancedPie("player_types", () -> {
final Map<String, Integer> playerMap = new HashMap<>();
for (final Player player : this.proxy.getAllPlayers()) {
final boolean eagler = eaglerAPI.isEaglerPlayerByUUID(player.getUniqueId());
final String key = eagler ? "Eagler" : "Java";
playerMap.put(key, playerMap.getOrDefault(key, 0) + 1);
} }
return playerMap; @Subscribe
})); public final void onProxyShutdown(final ProxyShutdownEvent e) {
} this.blacklist.shutdown();
} }
@Subscribe(order = PostOrder.FIRST) @Subscribe(order = PostOrder.FIRST)
@@ -109,7 +99,7 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(event, null, EnumConnectionType.EAGLER, player)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(event, null, EnumConnectionType.EAGLER, player));
} }
@Subscribe(order = PostOrder.LAST) @Subscribe(priority = EaglerEventPriority.EAGLER_MOTD_EVENT, order = PostOrder.LAST)
public final void onEaglerMOTD(final EaglercraftMOTDEvent event) { public final void onEaglerMOTD(final EaglercraftMOTDEvent event) {
final OPlayer player = new OPlayer(event.getMOTDConnection(), null, null); final OPlayer player = new OPlayer(event.getMOTDConnection(), null, null);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(event, null, EnumConnectionType.EAGLER, player)); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(event, null, EnumConnectionType.EAGLER, player));
@@ -117,23 +107,33 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
@Subscribe(order = PostOrder.FIRST) @Subscribe(order = PostOrder.FIRST)
public final void onJavaLogin(final PreLoginEvent event) { public final void onJavaLogin(final PreLoginEvent event) {
final InboundConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost().orElse(null);
final String origin = vhost != null ? vhost.getHostString() + vhost.getPort() : OriginBlacklist.UNKNOWN_STR;
final OPlayer player = new OPlayer(null, event.getUsername(), event.getUniqueId(), final OPlayer player = new OPlayer(null, event.getUsername(), event.getUniqueId(),
event.getConnection().getRemoteAddress().toString(), OriginBlacklist.UNKNOWN_STR, event.getConnection().getProtocolVersion().getProtocol()); conn.getRemoteAddress().toString(), OriginBlacklist.UNKNOWN_STR, origin,
conn.getProtocolVersion().getProtocol());
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player));
} }
@Subscribe(order = PostOrder.FIRST) @Subscribe(order = PostOrder.FIRST)
public final void onJavaHandshake(final PlayerClientBrandEvent event) { public final void onJavaHandshake(final PlayerClientBrandEvent event) {
final Player aPlayer = (Player) event.getPlayer(); final InetSocketAddress vhost = event.getPlayer().getVirtualHost().orElse(null);
final String origin = vhost != null ? vhost.getHostString() + vhost.getPort() : OriginBlacklist.UNKNOWN_STR;
final Player aPlayer = event.getPlayer();
final OPlayer bPlayer = new OPlayer(null, aPlayer.getUsername(), aPlayer.getUniqueId(), final OPlayer bPlayer = new OPlayer(null, aPlayer.getUsername(), aPlayer.getUniqueId(),
aPlayer.getRemoteAddress().getAddress().toString(), event.getBrand(), event.getPlayer().getProtocolVersion().getProtocol()); aPlayer.getRemoteAddress().getAddress().toString(), event.getBrand(), origin,
event.getPlayer().getProtocolVersion().getProtocol());
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, bPlayer)); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, bPlayer));
} }
@Subscribe(order = PostOrder.LAST) @Subscribe(order = PostOrder.LAST)
public final void onJavaMOTD(final ProxyPingEvent event) { public final void onJavaMOTD(final ProxyPingEvent event) {
final OPlayer player = new OPlayer(null, null, null, event.getConnection().getRemoteAddress().getHostString(), final InboundConnection conn = event.getConnection();
null, -1); final InetSocketAddress vhost = conn.getVirtualHost().orElse(null);
final String origin = vhost != null ? vhost.getHostString() + vhost.getPort() : OriginBlacklist.UNKNOWN_STR;
final OPlayer player = new OPlayer(null, null, null, conn.getRemoteAddress().getHostString(),
null, origin, -1);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player)); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player));
} }
@@ -148,18 +148,27 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
} }
@Override @Override
public final void log(final EnumLogLevel level, final String txt) { public final Path getPluginJarPath() {
if (level == EnumLogLevel.WARN) { try {
this.logger.warn(txt); return Paths.get(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).toAbsolutePath();
} else if (level == EnumLogLevel.ERROR) { } catch (final Throwable t) {
this.logger.error(txt); throw new RuntimeException("Unable to determine plugin JAR path");
} else if (level == EnumLogLevel.DEBUG) {
if (this.blacklist.isDebugEnabled()) {
this.logger.debug(txt);
} }
} else {
this.logger.info(txt);
} }
@Override
public final VelocityMetricsAdapter getMetrics() {
return new VelocityMetricsAdapter(this, this.metricsFactory);
}
@Override
public final IEaglerXServerAPI getEaglerAPI() {
return EaglerXServerAPI.instance();
}
@Override
public final SLF4JLogger getTheLogger() {
return this.logger;
} }
@Override @Override
@@ -214,10 +223,16 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
.schedule(); .schedule();
} }
@Override
public final void runAsync(final Runnable task) {
this.proxy.getScheduler()
.buildTask(this, task)
.schedule();
}
@Override @Override
public final void shutdown() { public final void shutdown() {
this.metrics.shutdown(); for (final ScheduledTask task : this.proxy.getScheduler().tasksByPlugin(this.plugin)) {
for (ScheduledTask task : this.proxy.getScheduler().tasksByPlugin(this.plugin)) {
task.cancel(); task.cancel();
} }
} }

View File

@@ -0,0 +1,38 @@
package xyz.webmc.originblacklist.velocity;
import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.metrics.GenericMetricsAdapter;
import org.bstats.charts.CustomChart;
import org.bstats.velocity.Metrics;
import org.bstats.velocity.Metrics.Factory;
public final class VelocityMetricsAdapter extends GenericMetricsAdapter {
private final OriginBlacklistVelocityPlugin plugin;
private final Factory factory;
private Metrics metrics;
public VelocityMetricsAdapter(final OriginBlacklistVelocityPlugin plugin, final Factory factory) {
super();
this.plugin = plugin;
this.factory = factory;
}
@Override
public void start() {
if (this.metrics == null) {
this.metrics = this.factory.make(this.plugin, OriginBlacklist.BSTATS.VELOCITY);
for (final CustomChart chart : this.charts) {
this.metrics.addCustomChart(chart);
}
}
}
@Override
public void shutdown() {
if (this.metrics != null) {
this.metrics.shutdown();
this.metrics = null;
}
}
}

View File

@@ -1,24 +1,27 @@
package xyz.webmc.originblacklist.velocity.command; package xyz.webmc.originblacklist.velocity.command;
import xyz.webmc.originblacklist.base.OriginBlacklist; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.base.command.OriginBlacklistCommand; import xyz.webmc.originblacklist.core.command.OriginBlacklistCommand;
import java.util.List; import java.util.List;
import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.api.command.SimpleCommand;
public class OriginBlacklistCommandVelocity extends OriginBlacklistCommand implements SimpleCommand { public final class OriginBlacklistCommandVelocity extends OriginBlacklistCommand implements SimpleCommand {
private final OriginBlacklist plugin;
public OriginBlacklistCommandVelocity(OriginBlacklist plugin) { public OriginBlacklistCommandVelocity(OriginBlacklist plugin) {
super(plugin); super(plugin);
this.plugin = plugin;
} }
@Override @Override
public void execute(final Invocation invocation) { public final void execute(final Invocation invocation) {
super.execute(new VCommandContext(invocation)); super.execute(new VCommandContext(this.plugin, invocation));
} }
@Override @Override
public List<String> suggest(final Invocation invocation) { public final List<String> suggest(final Invocation invocation) {
return super.suggest(new VCommandContext(invocation)); return super.suggest(new VCommandContext(this.plugin, invocation));
} }
} }

View File

@@ -1,34 +1,42 @@
package xyz.webmc.originblacklist.velocity.command; package xyz.webmc.originblacklist.velocity.command;
import xyz.webmc.originblacklist.base.command.CommandContext; import xyz.webmc.originblacklist.core.OriginBlacklist;
import xyz.webmc.originblacklist.core.command.CommandContext;
import com.velocitypowered.api.command.SimpleCommand.Invocation; import com.velocitypowered.api.command.SimpleCommand.Invocation;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
public class VCommandContext implements CommandContext { public final class VCommandContext implements CommandContext {
private final OriginBlacklist plugin;
private final Invocation invocation; private final Invocation invocation;
public VCommandContext(final Invocation invocation) { public VCommandContext(final OriginBlacklist plugin, final Invocation invocation) {
this.plugin = plugin;
this.invocation = invocation; this.invocation = invocation;
} }
@Override @Override
public String getPlayerName() { public final OriginBlacklist getPlugin() {
return this.plugin;
}
@Override
public final String getPlayerName() {
return this.invocation.source().toString(); return this.invocation.source().toString();
} }
@Override @Override
public void reply(final String message) { public final void reply(final String message) {
this.invocation.source().sendMessage(MiniMessage.miniMessage().deserialize(message)); this.invocation.source().sendMessage(MiniMessage.miniMessage().deserialize(message));
} }
@Override @Override
public boolean hasPermission(final String permission) { public final boolean hasPermission(final String permission) {
return this.invocation.source().hasPermission(permission); return this.invocation.source().hasPermission(permission);
} }
@Override @Override
public String[] getArgs() { public final String[] getArgs() {
return this.invocation.arguments(); return this.invocation.arguments();
} }
} }

View File

@@ -1,10 +1,10 @@
name: ${plugin_name} name: ${plugin_name}
version: ${plugin_vers} version: ${plugin_vers}
main: xyz.webmc.${plugin_iden}.bungee.${plugin_name}Bungee main: xyz.webmc.${plugin_iden}.bungee.${plugin_name}BungeePlugin
description: ${plugin_desc} description: ${plugin_desc}
website: ${plugin_site} website: ${plugin_site}
author: [${plugin_athr}] author: ${plugin_athr}
contributors: [${plugin_ctbr}] contributors: ${plugin_ctbr}
depends: [${plugin_depb}] depends: ${plugin_depb}
provides: [${plugin_prov}] provides: ${plugin_prov}
softdepend: [${plugin_sdpb}] softdepend: ${plugin_sdpb}

View File

@@ -1,12 +1,12 @@
name: ${plugin_name} name: ${plugin_name}
version: ${plugin_vers} version: ${plugin_vers}
main: xyz.webmc.${plugin_iden}.bukkit.${plugin_name}Bukkit main: xyz.webmc.${plugin_iden}.bukkit.${plugin_name}BukkitPlugin
description: ${plugin_desc} description: ${plugin_desc}
website: ${plugin_site} website: ${plugin_site}
authors: [${plugin_athr}] authors: ${plugin_athr}
contributors: [${plugin_ctbr}] contributors: ${plugin_ctbr}
depend: [${plugin_depa}] depend: ${plugin_depa}
provides: [${plugin_prov}] provides: ${plugin_prov}
softdepend: [${plugin_sdpa}] softdepend: ${plugin_sdpa}
commands: commands:
originblacklist: ${plugin_iden}:

View File

@@ -4,7 +4,7 @@
"version": "${plugin_vers}", "version": "${plugin_vers}",
"description": "${plugin_desc}", "description": "${plugin_desc}",
"website": "${plugin_site}", "website": "${plugin_site}",
"main": "xyz.webmc.${plugin_iden}.velocity.${plugin_name}Velocity", "main": "xyz.webmc.${plugin_iden}.velocity.${plugin_name}VelocityPlugin",
"authors": [${plugin_athr}], "authors": ${plugin_athr},
"dependencies": [${plugin_depc}] "dependencies": ${plugin_depc}
} }