diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 1bf30b3..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,45 +0,0 @@
-.gradle
-build/
-!gradle/wrapper/gradle-wrapper.jar
-!**/src/main/**/build/
-!**/src/test/**/build/
-
-### IntelliJ IDEA ###
-.idea/modules.xml
-.idea/jarRepositories.xml
-.idea/compiler.xml
-.idea/libraries/
-*.iws
-*.iml
-*.ipr
-out/
-!**/src/main/**/out/
-!**/src/test/**/out/
-
-### Eclipse ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
-.sts4-cache
-bin/
-!**/src/main/**/bin/
-!**/src/test/**/bin/
-
-### NetBeans ###
-/nbproject/private/
-/nbbuild/
-/dist/
-/nbdist/
-/.nb-gradle/
-
-### VS Code ###
-.vscode/
-
-### Mac OS ###
-.DS_Store
-
-### Idea ###
-.idea
\ No newline at end of file
diff --git a/.gradle/7.5.1/checksums/checksums.lock b/.gradle/7.5.1/checksums/checksums.lock
new file mode 100644
index 0000000..6aed38d
Binary files /dev/null and b/.gradle/7.5.1/checksums/checksums.lock differ
diff --git a/.gradle/7.5.1/checksums/md5-checksums.bin b/.gradle/7.5.1/checksums/md5-checksums.bin
new file mode 100644
index 0000000..4fad43f
Binary files /dev/null and b/.gradle/7.5.1/checksums/md5-checksums.bin differ
diff --git a/.gradle/7.5.1/checksums/sha1-checksums.bin b/.gradle/7.5.1/checksums/sha1-checksums.bin
new file mode 100644
index 0000000..3e42c84
Binary files /dev/null and b/.gradle/7.5.1/checksums/sha1-checksums.bin differ
diff --git a/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock b/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock
new file mode 100644
index 0000000..8e1b9a0
Binary files /dev/null and b/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock differ
diff --git a/.gradle/7.5.1/dependencies-accessors/gc.properties b/.gradle/7.5.1/dependencies-accessors/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/7.5.1/executionHistory/executionHistory.bin b/.gradle/7.5.1/executionHistory/executionHistory.bin
new file mode 100644
index 0000000..da9486f
Binary files /dev/null and b/.gradle/7.5.1/executionHistory/executionHistory.bin differ
diff --git a/.gradle/7.5.1/executionHistory/executionHistory.lock b/.gradle/7.5.1/executionHistory/executionHistory.lock
new file mode 100644
index 0000000..ffd7142
Binary files /dev/null and b/.gradle/7.5.1/executionHistory/executionHistory.lock differ
diff --git a/.gradle/7.5.1/fileChanges/last-build.bin b/.gradle/7.5.1/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/.gradle/7.5.1/fileChanges/last-build.bin differ
diff --git a/.gradle/7.5.1/fileHashes/fileHashes.bin b/.gradle/7.5.1/fileHashes/fileHashes.bin
new file mode 100644
index 0000000..127f007
Binary files /dev/null and b/.gradle/7.5.1/fileHashes/fileHashes.bin differ
diff --git a/.gradle/7.5.1/fileHashes/fileHashes.lock b/.gradle/7.5.1/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..ab25736
Binary files /dev/null and b/.gradle/7.5.1/fileHashes/fileHashes.lock differ
diff --git a/.gradle/7.5.1/fileHashes/resourceHashesCache.bin b/.gradle/7.5.1/fileHashes/resourceHashesCache.bin
new file mode 100644
index 0000000..cca3e20
Binary files /dev/null and b/.gradle/7.5.1/fileHashes/resourceHashesCache.bin differ
diff --git a/.gradle/7.5.1/gc.properties b/.gradle/7.5.1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..bbe0e22
Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..7b397cd
--- /dev/null
+++ b/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Mon Jan 22 14:15:34 ICT 2024
+gradle.version=7.5.1
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000..b684a37
Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe
new file mode 100644
index 0000000..4367e53
Binary files /dev/null and b/.gradle/file-system.probe differ
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..b4d14b6
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+tudubucket
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b0bead3
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
new file mode 100644
index 0000000..8cf359d
--- /dev/null
+++ b/.idea/discord.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..592fdc7
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..df543e3
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..a33a07b
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..7e340a7
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..715593d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/tudubucket.main.iml b/.idea/modules/tudubucket.main.iml
new file mode 100644
index 0000000..a589521
--- /dev/null
+++ b/.idea/modules/tudubucket.main.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ SPIGOT
+
+ 1
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..2c9deb1
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index ce18c15..261eeb9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,13 +1,201 @@
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- Version 2, December 2004
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
- Copyright (C) 2023 LangDuaMC developers
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
- Everyone is permitted to copy and distribute verbatim or modified
- copies of this license document, and changing it is allowed as long
- as the name is changed.
+ 1. Definitions.
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
- 0. You just DO WHAT THE FUCK YOU WANT TO.
\ No newline at end of file
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.MD b/README.MD
index 72c9d2d..caa45da 100644
--- a/README.MD
+++ b/README.MD
@@ -1,10 +1,2 @@
-# WhitelistedAdmins - Protect from OP brute.
-[![CodeQL](https://github.com/LangDuaMC/WhitelistedAdmin/actions/workflows/codeql.yml/badge.svg)](https://github.com/LangDuaMC/WhitelistedAdmin/actions/workflows/codeql.yml)
-
-- ### [Download](https://github.com/LangDuaMC/WhitelistedAdmin/actions/workflows/gradle.yml)
-
-## Function
-
-Basically force users with administrator permissions to whitelist their IP address.
-
-### Have fun!
+# WhitelistedAdmin
+hallo
diff --git a/WhitelistedAdmin.iml b/WhitelistedAdmin.iml
new file mode 100644
index 0000000..2e86d14
--- /dev/null
+++ b/WhitelistedAdmin.iml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ SPIGOT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..d521ce4
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,49 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ */
+
+plugins {
+ id 'java'
+ id 'maven-publish'
+}
+
+repositories {
+ mavenLocal()
+ maven {
+ url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/')
+ }
+
+ maven {
+ url = uri('https://oss.sonatype.org/content/groups/public/')
+ }
+
+ maven {
+ url = uri('https://repo.extendedclip.com/content/repositories/placeholderapi/')
+ }
+
+ maven {
+ url = uri('https://repo.maven.apache.org/maven2/')
+ }
+}
+
+dependencies {
+ compileOnly 'org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT'
+ compileOnly 'me.clip:placeholderapi:2.11.2'
+}
+
+group = 'ankita'
+version = '1'
+description = 'WhitelistedAdmin'
+java.sourceCompatibility = JavaVersion.VERSION_1_8
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ from(components.java)
+ }
+ }
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
diff --git a/build.gradle.kts b/build.gradle.kts
deleted file mode 100644
index 16685a3..0000000
--- a/build.gradle.kts
+++ /dev/null
@@ -1,91 +0,0 @@
-import org.apache.tools.ant.filters.FixCrLfFilter
-import org.apache.tools.ant.filters.ReplaceTokens
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-import java.io.ByteArrayOutputStream
-
-plugins {
- kotlin("jvm") version "1.8.21"
- id("com.github.johnrengelman.shadow") version "7.0.0"
- id("com.github.gmazzo.buildconfig") version "3.0.0"
- id("org.jlleitschuh.gradle.ktlint") version "11.3.2"
-}
-
-group = "net.langdua"
-version = "1.0.0"
-
-repositories {
- maven(url = "https://papermc.io/repo/repository/maven-public/")
- maven(url = "https://repo.extendedclip.com/content/repositories/placeholderapi/")
- maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
- name = "sonatype-oss-snapshots1"
- }
- mavenCentral()
-}
-
-val minecraftVersion: String = project.extra["minecraftVersion"].toString()
-val bstatsID: String = project.extra["bstatsID"].toString()
-
-dependencies {
- // PaperMC Dependency
- compileOnly("com.destroystokyo.paper", "paper-api", "$minecraftVersion-R0.1-SNAPSHOT")
- compileOnly("me.clip", "placeholderapi", "2.11.3")
- implementation("org.bstats", "bstats-bukkit", "3.0.2")
- implementation("net.kyori", "adventure-text-minimessage", "4.13.1")
-
- // Add your dependencies here
- // Examples
- // implementation("io.ktor", "ktor-client", "1.4.0") // Would be shaded into the final jar
- // compileOnly("io.ktor", "ktor-client", "1.4.0") // Only used on compile time
- implementation(kotlin("stdlib"))
-}
-
-buildConfig {
- className("BuildConfig")
- packageName("$group.$name")
- val commit = getGitHash()
- val branch = getGitBranch()
- buildConfigField("String", "GIT_COMMIT", "\"$commit\"")
- buildConfigField("String", "GIT_BRANCH", "\"$branch\"")
- buildConfigField("Int", "BSTATS_ID", bstatsID)
-}
-
-fun getGitHash(): String {
- val stdout = ByteArrayOutputStream()
- exec {
- commandLine("git", "rev-parse", "--short", "HEAD")
- standardOutput = stdout
- }
- return stdout.toString("UTF-8").trim()
-}
-
-fun getGitBranch(): String {
- val stdout = ByteArrayOutputStream()
- exec {
- commandLine("git", "rev-parse", "--abbrev-ref", "HEAD")
- standardOutput = stdout
- }
- return stdout.toString("UTF-8").trim()
-}
-
-tasks {
- processResources {
- filter(FixCrLfFilter::class)
- filter(ReplaceTokens::class, "tokens" to mapOf("version" to project.version))
- filteringCharset = "UTF-8"
- }
- jar {
- // Disabled, because we use the shadowJar task for building our jar
- enabled = false
- }
- shadowJar {
- relocate("org.bstats", "net.langdua.reflected.wladmin.org.bstats")
- }
- build {
- dependsOn(shadowJar)
- }
- withType {
- kotlinOptions {
- jvmTarget = "17"
- }
- }
-}
diff --git a/build/classes/java/main/ankita/tudubucket/DiscordIntegration.class b/build/classes/java/main/ankita/tudubucket/DiscordIntegration.class
new file mode 100644
index 0000000..a630831
Binary files /dev/null and b/build/classes/java/main/ankita/tudubucket/DiscordIntegration.class differ
diff --git a/build/classes/java/main/ankita/tudubucket/SendMessage.class b/build/classes/java/main/ankita/tudubucket/SendMessage.class
new file mode 100644
index 0000000..edb136c
Binary files /dev/null and b/build/classes/java/main/ankita/tudubucket/SendMessage.class differ
diff --git a/build/classes/java/main/ankita/tudubucket/commands/WhitelistAdminCommand.class b/build/classes/java/main/ankita/tudubucket/commands/WhitelistAdminCommand.class
new file mode 100644
index 0000000..a4b3308
Binary files /dev/null and b/build/classes/java/main/ankita/tudubucket/commands/WhitelistAdminCommand.class differ
diff --git a/build/classes/java/main/ankita/tudubucket/main.class b/build/classes/java/main/ankita/tudubucket/main.class
new file mode 100644
index 0000000..b18e7c0
Binary files /dev/null and b/build/classes/java/main/ankita/tudubucket/main.class differ
diff --git a/build/libs/tudubucket-1.jar b/build/libs/tudubucket-1.jar
new file mode 100644
index 0000000..cd4fdcf
Binary files /dev/null and b/build/libs/tudubucket-1.jar differ
diff --git a/build/resources/main/config.yml b/build/resources/main/config.yml
new file mode 100644
index 0000000..737e68e
--- /dev/null
+++ b/build/resources/main/config.yml
@@ -0,0 +1,65 @@
+# WhitelistedAdmin configuration
+
+# Placeholders list:
+# {player}: Player name
+# {address}: Player IP Address when joined
+# {current_address}: Player IP Address in the configuration
+
+# Date format for messages
+date-format: "yyyy-MM-dd HH:MM:SS"
+
+# List of permissions to check whether the joined player is an admin or not (only if they are not whitelisted)
+# Wildcards (e.g. "bukkit.*") are supported, it will check if the player has any permission starting with "bukkit.", for example.
+admin-permissions:
+ - "bukkit.plugin"
+ - "bukkit.?"
+ - "idk"
+
+# Discord Integration support
+integrations:
+ discord:
+ enable: true
+ # Method: "webhook" or "bot"
+ method: "bot"
+
+ bot:
+ token: "insert-your-bot-token-here"
+ # For more information about getting a Channel ID, refer to https://support.discord.com/hc/en-us/articles/206346498
+ alert-channel-id: "0123456789123456789"
+
+ webhook:
+ url: "https://discord.com/api/webhooks/0123456789123456789/webhook-token"
+
+# Hide the plugin
+plugin:
+ hide: true
+ message-unknown-command: 'Unknown command. Type "/help" for help.'
+
+# Messages to announce to integrations, placeholder, and color code supported
+messages:
+ logging:
+ unknown-admin: "{time} {player} have matched administrator permissions but not have whitelisted!"
+ invalid-address: "{time} {player} have different IP address with whitelisted! Currently whitelisted address: {current_address}"
+ success-whitelisted-ip: "{time} {player} have been whitelisted with IP address {current_address}"
+ success-removed-admin: "{time} {player} have been removed from administrator list"
+ console:
+ configuration-reloaded: 'Configuration reloaded!'
+ invalid-command: 'Invalid command argument!'
+ unknown-admin: "{time} {player} have matched administrator permissions but not have whitelisted!"
+ invalid-address: "{time} {player} have different IP address with whitelisted! Current whitelisted address: {current_address}"
+ success-whitelisted-ip: "{time} {player} have been whitelisted with IP address {current_address}"
+ success-removed-admin: "{time} {player} have been removed from administrator list"
+ integration:
+ unknown-admin: "{time} {player} have matched administrator permissions but not have whitelisted!"
+ invalid-address: "{time} {player} have different IP address with whitelisted! Current whitelisted address: {current_address}"
+ success-whitelisted-ip: "{time} {player} have been whitelisted with IP address {current_address}"
+ success-removed-admin: "{time} {player} have been removed from administrator list"
+ kick:
+ unknown-admin: "You have matched administrator permissions but not have whitelisted!"
+ invalid-address: "You have a different IP address than the whitelisted one!"
+
+
+# List of whitelisted administrators and their IP address
+whitelisted-admins:
+ admin1: "127.0.0.1"
+ admin2: "127.0.0.1"
diff --git a/build/resources/main/plugin.yml b/build/resources/main/plugin.yml
new file mode 100644
index 0000000..1dfd91e
--- /dev/null
+++ b/build/resources/main/plugin.yml
@@ -0,0 +1,17 @@
+name: WhitelistedAdmin
+version: '${project.version}'
+main: ankita.tudubucket.main
+api-version: 1.18
+authors: [tudubucket]
+description: A Minecraft plugin for Server Administrator safety purposes
+website: https://tudubucket.dev
+prefix: WhitelistedAdmin
+softdepend: [PlaceholderAPI]
+commands:
+ whitelist-admin:
+ description: Main command for WhitelistedAdmin plugin
+ aliases:
+ - wla
+ - wladmin
+ permission: whitelistedadmin.wladmin
+
diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin
new file mode 100644
index 0000000..136a5ac
Binary files /dev/null and b/build/tmp/compileJava/previous-compilation-data.bin differ
diff --git a/build/tmp/jar/MANIFEST.MF b/build/tmp/jar/MANIFEST.MF
new file mode 100644
index 0000000..59499bc
--- /dev/null
+++ b/build/tmp/jar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/gradle.properties b/gradle.properties
deleted file mode 100644
index 0ae7e88..0000000
--- a/gradle.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-kotlin.code.style=official
-minecraftVersion=1.16.5
-bstatsID=18465
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 60c76b3..ae04661 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
\ No newline at end of file
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
old mode 100755
new mode 100644
index 1b6c787..a69d9cb
--- a/gradlew
+++ b/gradlew
@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd3..f127cfd 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0b378fb
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,85 @@
+
+
+ 4.0.0
+
+ ankita
+ tudubucket
+ 1
+ jar
+
+ WhitelistedAdmin
+
+ A Minecraft plugin for Server Administrator safety purposes
+
+ 1.8
+ UTF-8
+
+ https://tudubucket.dev
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+ false
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+ spigotmc-repo
+ https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+
+ sonatype
+ https://oss.sonatype.org/content/groups/public/
+
+
+ placeholderapi
+ https://repo.extendedclip.com/content/repositories/placeholderapi/
+
+
+
+
+
+ org.spigotmc
+ spigot-api
+ 1.18.2-R0.1-SNAPSHOT
+ provided
+
+
+ me.clip
+ placeholderapi
+ 2.11.2
+ provided
+
+
+
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..3c51985
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,5 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ */
+
+rootProject.name = 'tudubucket'
diff --git a/settings.gradle.kts b/settings.gradle.kts
deleted file mode 100644
index 6344474..0000000
--- a/settings.gradle.kts
+++ /dev/null
@@ -1,2 +0,0 @@
-
-rootProject.name = "WhitelistedAdmin"
diff --git a/src/main/java/ankita/tudubucket/DiscordIntegration.java b/src/main/java/ankita/tudubucket/DiscordIntegration.java
new file mode 100644
index 0000000..af9c515
--- /dev/null
+++ b/src/main/java/ankita/tudubucket/DiscordIntegration.java
@@ -0,0 +1,72 @@
+package ankita.tudubucket;
+
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import javax.sql.rowset.spi.SyncFactoryException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Logger;
+
+import static org.bukkit.Bukkit.getLogger;
+
+public class DiscordIntegration {
+
+ private final String sendMethod;
+ private final String botToken;
+ private final String webhookUrl;
+ private final String alertChannelId;
+
+ public DiscordIntegration(FileConfiguration config) {
+ ConfigurationSection discordConfig = config.getConfigurationSection("integrations.discord");
+ assert discordConfig != null;
+ sendMethod = discordConfig.getString("method");
+ botToken = discordConfig.getString("bot-token");
+ webhookUrl = discordConfig.getString("webhook-url");
+ alertChannelId = discordConfig.getString("alert-channel-id");
+ }
+
+ public void sendMessage(String message) throws IOException, SyncFactoryException {
+ try {
+ String payload = "{\"content\":\"" + message + "\"}";
+ if (!sendMethod.equals("webhook") && !sendMethod.equals("bot")) {
+ throw new IllegalStateException("Invalid sending message method! Please check your configuration file again.");
+ } else if (sendMethod.equals("bot") && (botToken != null)) {
+ // Sending message using a bot
+ String url = "https://discord.com/api/channels/" + alertChannelId + "/messages";
+ HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Authorization", "Bot " + botToken);
+ connection.setRequestProperty("Content-Type", "application/json");
+ connection.setDoOutput(true);
+ OutputStream outputStream = connection.getOutputStream();
+ outputStream.write(payload.getBytes(StandardCharsets.UTF_8));
+ outputStream.flush();
+ outputStream.close();
+ connection.getInputStream().close();
+ connection.disconnect();
+ } else if (sendMethod.equals("webhook") && (webhookUrl != null)) {
+ // Sending message using a webhook
+ HttpURLConnection connection = (HttpURLConnection) new URL(webhookUrl).openConnection();
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", "application/json");
+ connection.setDoOutput(true);
+ OutputStream outputStream = connection.getOutputStream();
+ outputStream.write(payload.getBytes(StandardCharsets.UTF_8));
+ outputStream.flush();
+ outputStream.close();
+ connection.getInputStream().close();
+ connection.disconnect();
+ } else {
+ // Both bot token and webhook url are not defined
+ throw new IllegalStateException("Neither bot token nor webhook url is defined for Discord integration");
+ }
+ } catch (IOException e) {
+ Logger logger = getLogger();
+ logger.severe("Failed to send message to Discord: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/ankita/tudubucket/SendMessage.java b/src/main/java/ankita/tudubucket/SendMessage.java
new file mode 100644
index 0000000..5ba3431
--- /dev/null
+++ b/src/main/java/ankita/tudubucket/SendMessage.java
@@ -0,0 +1,21 @@
+package ankita.tudubucket;
+
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class SendMessage {
+
+ public static void send(CommandSender sender, String message) {
+ if (sender instanceof Player) {
+ Player player = (Player) sender;
+ String msg = PlaceholderAPI.setPlaceholders(player, message);
+ player.sendMessage(ChatColor.translateAlternateColorCodes('&', msg));
+ } else {
+ String msg = PlaceholderAPI.setPlaceholders(null, message);
+ Bukkit.getServer().getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&', msg));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ankita/tudubucket/commands/WhitelistAdminCommand.java b/src/main/java/ankita/tudubucket/commands/WhitelistAdminCommand.java
new file mode 100644
index 0000000..5f6fd8e
--- /dev/null
+++ b/src/main/java/ankita/tudubucket/commands/WhitelistAdminCommand.java
@@ -0,0 +1,179 @@
+package ankita.tudubucket.commands;
+
+import ankita.tudubucket.SendMessage;
+import ankita.tudubucket.DiscordIntegration;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
+import org.bukkit.event.player.PlayerLoginEvent;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.NotNull;
+
+import javax.sql.rowset.spi.SyncFactoryException;
+import java.io.File;
+import java.io.IOException;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Objects;
+
+public class WhitelistAdminCommand implements CommandExecutor, Listener {
+
+ public WhitelistAdminCommand(JavaPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public String getConfigMessage(String path, String player, String ipAddress) {
+ FileConfiguration config = plugin.getConfig();
+
+ String pattern = Objects.requireNonNull(config.getString("date-format"));
+
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
+
+ return Objects.requireNonNull(config.getString(path))
+ .replace("{time}", formatter.toString())
+ .replace("{player}", player)
+ .replace("{current_address}", ipAddress);
+ }
+
+ private final JavaPlugin plugin;
+
+
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+
+
+ if (args.length == 0) {
+ SendMessage.send(sender, "&c&oWhitelistedAdmin &r&eby &6tudubucket");
+ SendMessage.send(sender, "&6For help, type &e/help");
+ return false;
+ }
+
+ if (args[0].equals("reload")) {
+ // Reload the config
+ plugin.reloadConfig();
+ SendMessage.send(sender, "Configuration reloaded.");
+ return true;
+ }
+ if (args[0].equals("+") && args.length != 3) {
+ if (args.length < 3) {
+ SendMessage.send(sender, "&cToo few arguments.");
+ }
+ else {
+ SendMessage.send(sender, "&cToo many arguments.");
+ }
+ SendMessage.send(sender, "&cUsage: /whitelist-admin + playerName ipAddress");
+ return false;
+ }
+ if (args[0].equals("+")) {
+ // Add player to the whitelist
+ String playerName = args[1];
+ String ip = args[2];
+ FileConfiguration config = plugin.getConfig();
+ config.set("whitelisted." + playerName, ip);
+ try {
+ config.save(new File(plugin.getDataFolder(), "config.yml"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ DiscordIntegration Discord = new DiscordIntegration(plugin.getConfig());
+ SendMessage.send(sender, playerName + " has been added to the whitelist.");
+ if(Objects.equals(config.getBoolean("integrations.discord.enabled"), true)) {
+ try {
+ Discord.sendMessage(getConfigMessage("messages.integration.success-whitelisted-admin", args[1], args[2]));
+ } catch (IOException | SyncFactoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ plugin.reloadConfig();
+ return true;
+ }
+ if (args[0].equals("-") && args.length != 2) {
+ if (args.length < 2) {
+ SendMessage.send(sender, "&cToo few arguments.");
+ }
+ else {
+ SendMessage.send(sender, "&cToo many arguments.");
+ }
+ SendMessage.send(sender, "&cUsage: /whitelist-admin - playerName");
+ }
+ if (args[0].equals("-") && args.length == 2) {
+ // Remove player from the whitelist
+ String playerName = args[1];
+ FileConfiguration config = plugin.getConfig();
+ if (config.contains("whitelisted." + playerName)) {
+ config.set("whitelisted." + playerName, null);
+ try {
+ config.save(new File(plugin.getDataFolder(), "config.yml"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ DiscordIntegration Discord = new DiscordIntegration(plugin.getConfig());
+ SendMessage.send(sender, playerName + " has been removed from the whitelist.");
+ if(Objects.equals(config.getBoolean("integrations.discord.enabled"), true)) {
+ try {
+ Discord.sendMessage(getConfigMessage("messages.integration.success-removed-admin", args[1], "null"));
+ } catch (IOException | SyncFactoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ plugin.reloadConfig();
+ } else {
+ SendMessage.send(sender, playerName + " does not in the whitelist.");
+ plugin.reloadConfig();
+ }
+ return true;
+ }
+
+ SendMessage.send(sender, "&cInvalid command name!");
+ return false;
+ }
+
+ @EventHandler
+ public void onPlayerPreLogin(AsyncPlayerPreLoginEvent event) throws SyncFactoryException, IOException {
+ FileConfiguration config = plugin.getConfig();
+
+ String player = event.getName();
+ String playerIP = event.getAddress().toString();
+ String storedIP = config.getString("whitelisted." + playerIP);
+
+ if (storedIP != null && !storedIP.equals(playerIP)) {
+ event.disallow(
+ AsyncPlayerPreLoginEvent.Result.KICK_OTHER,
+ getConfigMessage("messages.kick.invalid-address", player, playerIP)
+ );
+
+ if(Objects.equals(config.getBoolean("integrations.discord.enabled"), true)) {
+ DiscordIntegration Discord = new DiscordIntegration(plugin.getConfig());
+ Discord.sendMessage(getConfigMessage("messages.integration.invalid-address", player, playerIP));
+ }
+ }
+ }
+ @EventHandler
+ public void onPlayerJoin(PlayerLoginEvent event) {
+ FileConfiguration config = plugin.getConfig();
+
+ List permissions = config.getStringList("admin-permissions");
+ Player player = event.getPlayer();
+ if (config.getString("whitelisted." + player) == null) {
+ for (String permission: permissions) {
+ if (player.hasPermission(permission)) {
+ player.kickPlayer(getConfigMessage("messages.kick.unknown-admin", player.getName(), Objects.toString(player.getAddress())));
+ if(Objects.equals(config.getBoolean("integrations.discord.enabled"), true)) {
+ try {
+ DiscordIntegration Discord = new DiscordIntegration(plugin.getConfig());
+ Discord.sendMessage(getConfigMessage("messages.integration.unknown-admin", player.getName(), Objects.toString(player.getAddress())));
+ } catch (IOException | SyncFactoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/ankita/tudubucket/main.java b/src/main/java/ankita/tudubucket/main.java
new file mode 100644
index 0000000..1862444
--- /dev/null
+++ b/src/main/java/ankita/tudubucket/main.java
@@ -0,0 +1,48 @@
+package ankita.tudubucket;
+
+import ankita.tudubucket.commands.WhitelistAdminCommand;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.event.Listener;
+import org.bukkit.plugin.java.JavaPlugin;
+import java.io.File;
+import java.util.Objects;
+import java.util.logging.Logger;
+
+public final class main extends JavaPlugin implements Listener {
+
+ @Override
+ public void onEnable() {
+ Logger logger = getLogger();
+ File whitelistFolder = new File(getDataFolder(), "WhitelistedAdmin");
+ File configFile = new File(getDataFolder(), "config.yml");
+ if (!configFile.exists()) saveDefaultConfig();
+ getConfig().options().copyDefaults(true);
+ saveDefaultConfig();
+ FileConfiguration config = YamlConfiguration.loadConfiguration(configFile);
+ Objects.requireNonNull(getCommand("whitelist-admin")).setExecutor(new WhitelistAdminCommand(this));
+
+ // Register the listener
+ Bukkit.getPluginManager().registerEvents(new WhitelistAdminCommand(this), this);
+
+ if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
+ /*
+ * We register the EventListener here, when PlaceholderAPI is installed.
+ * Since all events are in the main class (this class), we simply use "this"
+ */
+ Bukkit.getPluginManager().registerEvents(this, this);
+ } else {
+ /*
+ * We inform about the fact that PlaceholderAPI isn't installed and then
+ * disable this plugin to prevent issues.
+ */
+ System.out.print("Could not find PlaceholderAPI! This plugin is required.");
+ Bukkit.getPluginManager().disablePlugin(this);
+ }
+ }
+ @Override
+ public void onDisable() {
+ // Plugin shutdown logic
+ }
+}
diff --git a/src/main/kotlin/net/langdua/bootstrap/PluginBootstrap.kt b/src/main/kotlin/net/langdua/bootstrap/PluginBootstrap.kt
deleted file mode 100644
index e1548c2..0000000
--- a/src/main/kotlin/net/langdua/bootstrap/PluginBootstrap.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.langdua.bootstrap
-
-import net.kyori.adventure.text.minimessage.MiniMessage
-import org.bukkit.event.Listener
-import org.bukkit.plugin.java.JavaPlugin
-
-abstract class PluginBootstrap : JavaPlugin(), Listener {
- val mm = MiniMessage.miniMessage()
-}
diff --git a/src/main/kotlin/net/langdua/bootstrap/Utility.kt b/src/main/kotlin/net/langdua/bootstrap/Utility.kt
deleted file mode 100644
index 774a496..0000000
--- a/src/main/kotlin/net/langdua/bootstrap/Utility.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.langdua.bootstrap
-
-import net.kyori.adventure.text.Component
-
-class Utility(private val plugin: PluginBootstrap) {
- fun getAdventureComponent(name: String): Component? {
- return plugin.config.getString(name)?.let { plugin.mm.deserialize(it) }
- }
-}
diff --git a/src/main/kotlin/net/langdua/wladmin/DiscordIntegration.kt b/src/main/kotlin/net/langdua/wladmin/DiscordIntegration.kt
deleted file mode 100644
index 3978bdd..0000000
--- a/src/main/kotlin/net/langdua/wladmin/DiscordIntegration.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-package net.langdua.wladmin
-
-import org.bukkit.Bukkit
-import org.bukkit.configuration.ConfigurationSection
-import org.bukkit.configuration.file.FileConfiguration
-import java.io.IOException
-import java.net.HttpURLConnection
-import java.net.URL
-import java.nio.charset.StandardCharsets
-import javax.sql.rowset.spi.SyncFactoryException
-
-class DiscordIntegration(pluginConfig: FileConfiguration) {
- private val config = pluginConfig.getConfigurationSection("integrations.discord")?.let { Config.fromConfig(it) }
-
- class Config(
- val method: String?,
- val token: String?,
- val url: String?,
- val channelId: String?
- ) {
- companion object {
- fun fromConfig(config: ConfigurationSection): Config {
- return Config(
- config.getString("method"),
- config.getString("bot-token"),
- config.getString("webhook-url"),
- config.getString("alert-channel-id")
- )
- }
- }
- }
-
- @Throws(IOException::class, SyncFactoryException::class)
- fun sendMessage(message: String) {
- if (config == null) {
- throw IllegalStateException("Improper Discord hook configuration")
- }
- try {
- if ((config.method == "webhook" || config.method == "bot") &&
- (config.method == "bot" && !config.token.isNullOrBlank()) ||
- (config.method == "webhook" && !config.url.isNullOrBlank())
- ) {
- val connection =
- URL(if (config.method == "bot") "https://discord.com/api/channels/${config.channelId}/messages" else config.url).openConnection() as HttpURLConnection
- if (config.method == "bot") {
- config.token?.let {
- connection.setRequestProperty("Authorization", "Bot $it")
- }
- }
- connection.requestMethod = "POST"
- connection.setRequestProperty("Content-Type", "application/json")
- connection.doOutput = true
- val outputStream = connection.outputStream
- val payload =
- "{\"content\":\"$message\"}" // Both bot token and webhook url are not defined// Sending message using a webhook
- outputStream.write(payload.toByteArray(StandardCharsets.UTF_8))
- outputStream.flush()
- outputStream.close()
- connection.inputStream.close()
- connection.disconnect()
- } else {
- throw IllegalStateException("Neither bot token nor webhook url is defined for Discord integration")
- }
- } catch (e: IOException) {
- val logger = Bukkit.getLogger()
- logger.severe("Failed to send message to Discord: " + e.message)
- }
- }
-}
diff --git a/src/main/kotlin/net/langdua/wladmin/Plugin.kt b/src/main/kotlin/net/langdua/wladmin/Plugin.kt
deleted file mode 100644
index e83e81e..0000000
--- a/src/main/kotlin/net/langdua/wladmin/Plugin.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.langdua.wladmin
-
-import net.langdua.bootstrap.PluginBootstrap
-import net.langdua.bootstrap.Utility
-import net.langdua.main.BuildConfig
-import net.langdua.wladmin.commands.WhitelistAdminCommand
-import org.bstats.bukkit.Metrics
-import org.bukkit.Bukkit
-import org.bukkit.configuration.file.YamlConfiguration
-import java.io.File
-import java.util.*
-
-class Plugin : PluginBootstrap() {
- val whitelistFolder = File(dataFolder, "WhitelistedAdmin")
- private val configFile = File(dataFolder, "config.yml")
- var utility = Utility(this)
- override fun onEnable() {
- Metrics(this, BuildConfig.BSTATS_ID)
- if (!configFile.exists()) saveDefaultConfig()
- config.options().copyDefaults(true)
- saveDefaultConfig()
- YamlConfiguration.loadConfiguration(configFile)
- Objects.requireNonNull(getCommand("whitelist-admin"))?.setExecutor(WhitelistAdminCommand(this))
- // Register the listener
- Bukkit.getPluginManager().registerEvents(WhitelistAdminCommand(this), this)
- }
-
- override fun onDisable() {
- // Plugin shutdown logic
- }
-}
diff --git a/src/main/kotlin/net/langdua/wladmin/SendMessage.kt b/src/main/kotlin/net/langdua/wladmin/SendMessage.kt
deleted file mode 100644
index 659f0a6..0000000
--- a/src/main/kotlin/net/langdua/wladmin/SendMessage.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.langdua.wladmin
-
-import me.clip.placeholderapi.PlaceholderAPI
-import org.bukkit.Bukkit
-import org.bukkit.ChatColor
-import org.bukkit.command.CommandSender
-import org.bukkit.command.ConsoleCommandSender
-import org.bukkit.entity.Player
-
-class SendMessage {
- companion object {
- fun send(sender: CommandSender?, message: String) {
- val msg =
- ChatColor.translateAlternateColorCodes(
- '&',
- PlaceholderAPI.setPlaceholders(
- if (sender is Player && sender !is ConsoleCommandSender) sender else null,
- message
- )
- )
- if (sender != null) {
- sender.sendMessage(msg)
- } else {
- Bukkit.getServer().consoleSender.sendMessage(msg)
- }
- }
- }
-}
diff --git a/src/main/kotlin/net/langdua/wladmin/commands/WhitelistAdminCommand.kt b/src/main/kotlin/net/langdua/wladmin/commands/WhitelistAdminCommand.kt
deleted file mode 100644
index db03c6c..0000000
--- a/src/main/kotlin/net/langdua/wladmin/commands/WhitelistAdminCommand.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package net.langdua.wladmin.commands
-
-import net.langdua.wladmin.DiscordIntegration
-import net.langdua.wladmin.Plugin
-import net.langdua.wladmin.SendMessage
-import org.bukkit.command.Command
-import org.bukkit.command.CommandExecutor
-import org.bukkit.command.CommandSender
-import org.bukkit.event.EventHandler
-import org.bukkit.event.Listener
-import org.bukkit.event.player.PlayerJoinEvent
-import java.io.File
-import java.io.IOException
-import java.util.*
-import javax.sql.rowset.spi.SyncFactoryException
-
-class WhitelistAdminCommand(private val plugin: Plugin) : CommandExecutor, Listener {
- private val config = plugin.config
- private val discord = DiscordIntegration(config)
- override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
- if (args.isEmpty()) {
- SendMessage.send(sender, "&c&oWhitelistedAdmin &r&eby &6LangDuaMC developers [tudubucket, hUwUtao]")
- SendMessage.send(sender, "&6For help, type &e/help")
- return false
- } else if (args[0] == "reload") {
- // Reload the config
- plugin.reloadConfig()
- SendMessage.send(sender, "Configuration reloaded.")
- return true
- } else if (args[0] == "+" && args.size == 3) {
- // Add player to the whitelist
- val playerName = args[1]
- val ip = args[2]
- config["whitelisted.$playerName"] = ip
- try {
- config.save(File(plugin.dataFolder, "config.yml"))
- } catch (e: IOException) {
- e.printStackTrace()
- }
- SendMessage.send(sender, "$playerName has been added to the whitelist.")
- if (config.getBoolean("integrations.discord.enabled")) {
- try {
- discord.sendMessage(config.getString("messages.integration.success-whitelisted-admin")!!)
- } catch (e: IOException) {
- throw RuntimeException(e)
- } catch (e: SyncFactoryException) {
- throw RuntimeException(e)
- }
- }
- plugin.reloadConfig()
- return true
- } else if (args[0] == "-" && args.size == 2) {
- // Remove player from the whitelist
- val playerName = args[1]
-
- if (config.contains("whitelisted.$playerName")) {
- config["whitelisted.$playerName"] = null
- try {
- config.save(File(plugin.dataFolder, "config.yml"))
- } catch (e: IOException) {
- e.printStackTrace()
- }
- SendMessage.send(sender, "$playerName has been removed from the whitelist.")
- if (config.getBoolean("integrations.discord.enabled")) {
- try {
- discord.sendMessage(config.getString("messages.integration.success-removed-admin")!!)
- } catch (e: IOException) {
- throw RuntimeException(e)
- } catch (e: SyncFactoryException) {
- throw RuntimeException(e)
- }
- }
- plugin.reloadConfig()
- } else {
- SendMessage.send(sender, "$playerName is not in the whitelist.")
- plugin.reloadConfig()
- }
- return true
- }
- SendMessage.send(sender, "&cInvalid command!")
- return false
- }
-
- @EventHandler
- @Throws(SyncFactoryException::class, IOException::class)
- fun onPlayerJoin(event: PlayerJoinEvent) {
- // Get the configuration
-
- // Check if the player has any forbidden permissions
- val permissions = config.getStringList("permissions")
- val player = event.player
- val checkValid = config.getString("whitelisted.$player")
- for (permission in permissions) {
- if (player.hasPermission(permission!!) && checkValid == null) {
- player.kick(plugin.utility.getAdventureComponent("messages.kick.unknown-admin"))
- if (config.getBoolean("integrations.discord.enabled")) {
- try {
- discord.sendMessage(config.getString("messages.integration.unknown-admin")!!)
- } catch (e: IOException) {
- throw RuntimeException(e)
- } catch (e: SyncFactoryException) {
- throw RuntimeException(e)
- }
- }
- return
- }
- }
-
- // Check if the player is whitelisted
- val playerName = player.name
- val playerIP = Objects.requireNonNull(player.address).hostString
- val storedIP = config.getString("whitelisted.$playerName")
- if (storedIP != null && storedIP != playerIP) {
- player.kick(plugin.utility.getAdventureComponent("messages.kick.invalid-address"))
- if (config.getBoolean("integrations.discord.enabled")) {
- discord.sendMessage(config.getString("messages.integration.invalid-address")!!)
- }
- }
- }
-}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 856236d..8dff0cd 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,61 +1,65 @@
# WhitelistedAdmin configuration
-# Placeholder list:
+# Placeholders list:
# {player}: Player name
-# {address}: Player IP Address in PlayerJoinEvent
+# {address}: Player IP Address when joined
# {current_address}: Player IP Address in the configuration
-# List of permissions to check
-# Wildcard (e.g. "bukkit.*") are supported, it will check if the player have any permission starting with "bukkit.", for example.
-permissions:
+# Date format for messages
+date-format: "yyyy-MM-dd HH:MM:SS"
+
+# List of permissions to check whether the joined player is an admin or not (only if they are not whitelisted)
+# Wildcards (e.g. "bukkit.*") are supported, it will check if the player has any permission starting with "bukkit.", for example.
+admin-permissions:
- "bukkit.plugin"
- "bukkit.?"
- "idk"
-# List of whitelisted administrator and their IP address
-whitelisted:
- remember-to-replace-this-to-your-admin-name: "127.0.0.1"
- you-can-add: "127.0.0.2"
- as-much-player-as-you-want: "172.0.0.3"
-
-
# Discord Integration support
-
integrations:
discord:
- enabled: true
+ enable: true
# Method: "webhook" or "bot"
method: "bot"
- bot-token: "insert-your-bot-token-here"
- webhook-url: "https://discord.com/api/webhooks/0123456789123456789/webhook-token"
- # This setting required only if you are using Discord bot instead of Webhook. Remember, this is Channel ID, not the Channel name.
- # For more information about getting Channel ID, refer to https://support.discord.com/hc/en-us/articles/206346498
- alert-channel-id: "0123456789123456789"
+
+ bot:
+ token: "insert-your-bot-token-here"
+ # For more information about getting a Channel ID, refer to https://support.discord.com/hc/en-us/articles/206346498
+ alert-channel-id: "0123456789123456789"
+
+ webhook:
+ url: "https://discord.com/api/webhooks/0123456789123456789/webhook-token"
# Hide the plugin
plugin:
hide: true
message-unknown-command: 'Unknown command. Type "/help" for help.'
-# Messages to announce to integrations, placeholder and color code supported
+# Messages to announce to integrations, placeholder, and color code supported
messages:
logging:
unknown-admin: "{time} {player} have matched administrator permissions but not have whitelisted!"
- invalid-address: "{time} {player} have different IP address with whitelisted! Currently whitelisted address: %old_address%"
- success-whitelisted-ip: "{time} {player} have been whitelisted with IP address %ip_address%"
+ invalid-address: "{time} {player} have different IP address with whitelisted! Currently whitelisted address: {current_address}"
+ success-whitelisted-ip: "{time} {player} have been whitelisted with IP address {current_address}"
success-removed-admin: "{time} {player} have been removed from administrator list"
console:
configuration-reloaded: 'Configuration reloaded!'
invalid-command: 'Invalid command argument!'
unknown-admin: "{time} {player} have matched administrator permissions but not have whitelisted!"
- invalid-address: "{time} {player} have different IP address with whitelisted! Currently whitelisted address: %old_address%"
- success-whitelisted-ip: "{time} {player} have been whitelisted with IP address %ip_address%"
+ invalid-address: "{time} {player} have different IP address with whitelisted! Current whitelisted address: {current_address}"
+ success-whitelisted-ip: "{time} {player} have been whitelisted with IP address {current_address}"
success-removed-admin: "{time} {player} have been removed from administrator list"
integration:
unknown-admin: "{time} {player} have matched administrator permissions but not have whitelisted!"
- invalid-address: "{time} {player} have different IP address with whitelisted! Currently whitelisted address: %old_address%"
- success-whitelisted-ip: "{time} {player} have been whitelisted with IP address %ip_address%"
+ invalid-address: "{time} {player} have different IP address with whitelisted! Current whitelisted address: {current_address}"
+ success-whitelisted-ip: "{time} {player} have been whitelisted with IP address {current_address}"
success-removed-admin: "{time} {player} have been removed from administrator list"
kick:
unknown-admin: "You have matched administrator permissions but not have whitelisted!"
- invalid-address: "You have different IP address with whitelisted!"
\ No newline at end of file
+ invalid-address: "You have a different IP address than the whitelisted one!"
+
+
+# List of whitelisted administrators and their IP address
+whitelisted-admins:
+ admin1: "127.0.0.1"
+ admin2: "127.0.0.1"
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 7a16f2b..1dfd91e 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,16 +1,17 @@
name: WhitelistedAdmin
-version: '1.0.0'
-main: net.langdua.wladmin.Plugin
-api-version: 1.16
-authors: [tudubucket, hUwUtao]
+version: '${project.version}'
+main: ankita.tudubucket.main
+api-version: 1.18
+authors: [tudubucket]
description: A Minecraft plugin for Server Administrator safety purposes
-website: https://github.com/LangDuaMC/WhitelistedAdmin
-prefix: WLAdmin
-depend: [PlaceholderAPI]
+website: https://tudubucket.dev
+prefix: WhitelistedAdmin
+softdepend: [PlaceholderAPI]
commands:
whitelist-admin:
description: Main command for WhitelistedAdmin plugin
aliases:
- wla
+ - wladmin
permission: whitelistedadmin.wladmin