Compare commits
72 Commits
Author | SHA1 | Date |
---|---|---|
Taah | 2e40ddc6bc | |
Telesphoreo | ff9cf12acc | |
Telesphoreo | 94528860f2 | |
Telesphoreo | c83f8f1d8e | |
Focusvity | 31cd561b92 | |
Telesphoreo | f0582e03e6 | |
Telesphoreo | 4e593e1b5e | |
Telesphoreo | 026b29a98c | |
Telesphoreo | 266a8d6384 | |
Telesphoreo | 21ee54cf98 | |
Telesphoreo | 492c6bd8eb | |
Telesphoreo | a7c76e6089 | |
Telesphoreo | 7a996004f0 | |
Telesphoreo | 46ff09bf58 | |
Telesphoreo | 4426c4b4b7 | |
Telesphoreo | fc8811d453 | |
Telesphoreo | 459f62e0d3 | |
Telesphoreo | 4918cf55f3 | |
Telesphoreo | e9395e193a | |
Telesphoreo | a257fb2f9c | |
Telesphoreo | fc9924754a | |
Telesphoreo | 867e3ff79b | |
Telesphoreo | 8bef589b7a | |
Allink | 5a0ae8746c | |
Telesphoreo | 41a2475e3d | |
Telesphoreo | 0bcbc7e79c | |
Telesphoreo | 95043a33db | |
Telesphoreo | 93619dd05e | |
Taah | 244d027e5d | |
Telesphoreo | ceea975729 | |
Telesphoreo | 32f17a23f3 | |
Telesphoreo | 1148ff5da9 | |
Telesphoreo | a0ae4a9720 | |
Telesphoreo | 82238fa3ed | |
Telesphoreo | 6e152417b7 | |
Telesphoreo | 22bb27af24 | |
Telesphoreo | 2b24f0ee4c | |
Telesphoreo | 7769f34f74 | |
Telesphoreo | 8337e0dfca | |
Taah | 41459ad404 | |
Telesphoreo | 7760eb6ff2 | |
Telesphoreo | cbc7907aea | |
ayunami2000 | 1f91e9c684 | |
ayunami2000 | f8bd688fa5 | |
ayunami2000 | 2117cf7041 | |
ayunami2000 | 16ee5378ad | |
Telesphoreo | 391e146d60 | |
Telesphoreo | 4bca726338 | |
Telesphoreo | 820eb57a0a | |
ayunami2000 | 139374ba55 | |
ayunami2000 | 822bc5b483 | |
Telesphoreo | 3dde5f7007 | |
ayunami2000 | 6e79310ef8 | |
Telesphoreo | 1802d91fad | |
Telesphoreo | 3fa54cec72 | |
Telesphoreo | e1dd36a0fb | |
Telesphoreo | 33a72983d2 | |
ayunami2000 | b980ea837b | |
ayunami2000 | c7658647fc | |
ayunami2000 | 5823b0c790 | |
ayunami2000 | 7163042f1b | |
Telesphoreo | 0b3c6ddbec | |
Telesphoreo | 1ec17ce7e7 | |
Telesphoreo | 1a139034b5 | |
ayunami2000 | b6b5a7f227 | |
Telesphoreo | 01d2cf44ea | |
Telesphoreo | ef5ff6b540 | |
Telesphoreo | 2ce0a1e698 | |
Telesphoreo | e6e8439a72 | |
Telesphoreo | 7550db5fb0 | |
Telesphoreo | b4ab3b609a | |
Telesphoreo | c4ad009a34 |
|
@ -0,0 +1,18 @@
|
||||||
|
name: Gradle
|
||||||
|
|
||||||
|
on: [ push ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 17
|
||||||
|
cache: gradle
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: chmod a+x gradlew && ./gradlew build --no-daemon
|
|
@ -0,0 +1,49 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Plexus Code Style" version="1">
|
||||||
|
<JavaCodeStyleSettings>
|
||||||
|
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="20" />
|
||||||
|
<option name="IMPORT_LAYOUT_TABLE">
|
||||||
|
<value>
|
||||||
|
<package name="" withSubpackages="true" static="false" />
|
||||||
|
<package name="" withSubpackages="true" static="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</JavaCodeStyleSettings>
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
|
<value>
|
||||||
|
<package name="java.util" alias="false" withSubpackages="false" />
|
||||||
|
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||||
|
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||||
|
<value>
|
||||||
|
<package name="" alias="false" withSubpackages="true" />
|
||||||
|
<package name="java" alias="false" withSubpackages="true" />
|
||||||
|
<package name="javax" alias="false" withSubpackages="true" />
|
||||||
|
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||||
|
<package name="" alias="true" withSubpackages="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</JetCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="JAVA">
|
||||||
|
<option name="BRACE_STYLE" value="2" />
|
||||||
|
<option name="CLASS_BRACE_STYLE" value="2" />
|
||||||
|
<option name="METHOD_BRACE_STYLE" value="2" />
|
||||||
|
<option name="LAMBDA_BRACE_STYLE" value="2" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="WHILE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="SPACE_AFTER_TYPE_CAST" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="0" />
|
||||||
|
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
||||||
|
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Plexus Code Style" />
|
||||||
|
</state>
|
||||||
|
</component>
|
|
@ -0,0 +1,24 @@
|
||||||
|
For those who are wanting to contribute, we fully encourage doing so. There are a few rules we require following when contributing however.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. Make an issue and get feedback. It's important to know if your idea will be accepted before writing any code.
|
||||||
|
- If it is a feature request, describe the feature and be extremely specific.
|
||||||
|
- If it is a bug report, ensure you include how to reproduce the bug and the expected outcome
|
||||||
|
- If it is an enhancement, describe your proposed changes. Ensure you are extremely specific.
|
||||||
|
2. Fork this project
|
||||||
|
3. Create a new branch that describes the new feature, enhancement, or bug fix. For example, this is good: `feature/add-xyz`. This is bad: `fix-this-lol`.
|
||||||
|
4. Write the code that addresses your change.
|
||||||
|
- Keep in mind that it **must** be formatted correctly. If you are using IntelliJ, there is a `codeStyle.xml` file that tells IntelliJ how to format your code. Check this link for information on how to use the file: https://www.jetbrains.com/help/idea/configuring-code-style.html#import-export-schemes
|
||||||
|
- If you are not using IntelliJ, that is fine. We use the Plexus Code Style (which is almost the same as Allman) so please format your code accordingly.
|
||||||
|
6. Push your changes to your new branch and make a PR based off of that branch.
|
||||||
|
|
||||||
|
## Requirements for a PR
|
||||||
|
- The issue must be marked as approved
|
||||||
|
- It must only address each specific issue. Don't make one PR for multiple issues.
|
||||||
|
- Your PR must compile and work. If it does not compile or work, your PR will most likely be rejected.
|
||||||
|
|
||||||
|
## Code requirements
|
||||||
|
- Most importantly, your code must be efficient. Your pull request may be rejected if your code is deemed inefficient or sloppy.
|
||||||
|
- Do not repeat yourself. Create functions as needed if you're using large blocks of code over and over again.
|
||||||
|
- Do not use an excessive amount of commits when making your PR. It makes the master branch look messy.
|
||||||
|
- Your code must be consistent with Plex's codebase. If a function already exists, use it.
|
|
@ -1,2 +1,2 @@
|
||||||
# Module-HTTPD
|
# Module-HTTPD [![Build Status](https://ci.plex.us.org/job/Module-HTTPD/badge/icon)](https://ci.plex.us.org/job/Module-HTTPD/)
|
||||||
The HTTPD module for Plex
|
The HTTPD module for Plex
|
||||||
|
|
|
@ -5,91 +5,75 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "dev.plex"
|
group = "dev.plex"
|
||||||
version = "1.0.1"
|
version = "1.4-SNAPSHOT"
|
||||||
description = "Module-HTTPD"
|
description = "Module-HTTPD"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://papermc.io/repo/repository/maven-public/")
|
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||||
}
|
}
|
||||||
|
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://nexus.telesphoreo.me/repository/plex/")
|
url = uri("https://nexus.telesphoreo.me/repository/plex/")
|
||||||
}
|
}
|
||||||
|
|
||||||
maven {
|
|
||||||
url = uri("https://nexus.telesphoreo.me/repository/totalfreedom/")
|
|
||||||
}
|
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://jitpack.io")
|
url = uri("https://jitpack.io")
|
||||||
|
content {
|
||||||
|
includeGroup("com.github.MilkBowl")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.projectlombok:lombok:1.18.22")
|
implementation("org.projectlombok:lombok:1.18.30")
|
||||||
annotationProcessor("org.projectlombok:lombok:1.18.22")
|
annotationProcessor("org.projectlombok:lombok:1.18.30")
|
||||||
implementation("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
|
implementation("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
|
||||||
implementation("dev.plex:Plex:1.0")
|
implementation("dev.plex:server:1.4-SNAPSHOT")
|
||||||
implementation("org.json:json:20220320")
|
implementation("org.json:json:20231013")
|
||||||
implementation("org.reflections:reflections:0.10.2")
|
implementation("org.reflections:reflections:0.10.2")
|
||||||
implementation("org.eclipse.jetty:jetty-server:11.0.8")
|
implementation("org.eclipse.jetty:jetty-server:11.0.19")
|
||||||
implementation("org.eclipse.jetty:jetty-servlet:11.0.8")
|
implementation("org.eclipse.jetty:jetty-servlet:11.0.19")
|
||||||
implementation("org.eclipse.jetty:jetty-proxy:11.0.8")
|
implementation("org.eclipse.jetty:jetty-proxy:11.0.19")
|
||||||
implementation("com.github.MilkBowl:VaultAPI:1.7")
|
implementation("com.github.MilkBowl:VaultAPI:1.7.1") {
|
||||||
|
exclude("org.bukkit", "bukkit")
|
||||||
|
}
|
||||||
|
implementation(platform("com.intellectualsites.bom:bom-newest:1.40")) // Ref: https://github.com/IntellectualSites/bom
|
||||||
|
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core")
|
||||||
|
implementation("commons-io:commons-io:2.15.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.getByName<Jar>("jar") {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
archiveBaseName.set("Module-HTTPD")
|
||||||
|
archiveVersion.set("")
|
||||||
|
from("src/main/resources") {
|
||||||
|
exclude("dev/**")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
compileJava {
|
compileJava {
|
||||||
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
|
||||||
// Set the release flag. This configures what version bytecode the compiler will emit, as well as what JDK APIs are usable.
|
|
||||||
// See https://openjdk.java.net/jeps/247 for more information.
|
|
||||||
options.release.set(17)
|
|
||||||
}
|
}
|
||||||
javadoc {
|
javadoc {
|
||||||
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
options.encoding = Charsets.UTF_8.name()
|
||||||
}
|
}
|
||||||
processResources {
|
processResources {
|
||||||
filteringCharset = Charsets.UTF_8.name() // We want UTF-8 for everything
|
filteringCharset = Charsets.UTF_8.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("maven") {
|
create<MavenPublication>("maven") {
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.getByName<Jar>("jar") {
|
|
||||||
// duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
archiveBaseName.set("Plex-HTTPD")
|
|
||||||
archiveVersion.set("")
|
|
||||||
// from("src/main/resources") {
|
|
||||||
// include("**/**")
|
|
||||||
// }
|
|
||||||
// from("src/main/java") {
|
|
||||||
// include("**/**")
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
resources {
|
|
||||||
srcDirs("src/main/java", "src/main/resources")
|
|
||||||
include("**/**")
|
|
||||||
exclude("**/**.java")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.getByName<Copy>("processResources") {
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
}
|
|
||||||
|
|
Binary file not shown.
|
@ -1,5 +1,7 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
@ -80,13 +80,11 @@ do
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
@ -133,22 +131,29 @@ location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
|
@ -193,6 +198,10 @@ if "$cygwin" || "$msys" ; then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# Collect all arguments for the java command;
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
@ -205,6 +214,12 @@ set -- \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
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.
|
# Use "xargs" to parse quoted args.
|
||||||
#
|
#
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
|
@ -25,7 +25,8 @@
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
exit /b 1
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
package dev.plex;
|
package dev.plex;
|
||||||
|
|
||||||
|
import dev.plex.authentication.AuthenticationManager;
|
||||||
|
import dev.plex.cache.FileCache;
|
||||||
import dev.plex.config.ModuleConfig;
|
import dev.plex.config.ModuleConfig;
|
||||||
import dev.plex.module.PlexModule;
|
import dev.plex.module.PlexModule;
|
||||||
import dev.plex.request.impl.AdminsEndpoint;
|
import dev.plex.request.AbstractServlet;
|
||||||
import dev.plex.request.impl.IndefBansEndpoint;
|
import dev.plex.request.SchematicUploadServlet;
|
||||||
import dev.plex.request.impl.ListEndpoint;
|
import dev.plex.request.impl.*;
|
||||||
import dev.plex.request.impl.PunishmentsEndpoint;
|
|
||||||
import dev.plex.util.PlexLog;
|
import dev.plex.util.PlexLog;
|
||||||
import java.io.File;
|
import jakarta.servlet.MultipartConfigElement;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.milkbowl.vault.permission.Permission;
|
import net.milkbowl.vault.permission.Permission;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.*;
|
||||||
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
|
|
||||||
import org.eclipse.jetty.server.HttpConfiguration;
|
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHandler;
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public class HTTPDModule extends PlexModule
|
public class HTTPDModule extends PlexModule
|
||||||
{
|
{
|
||||||
|
@ -34,10 +32,17 @@ public class HTTPDModule extends PlexModule
|
||||||
|
|
||||||
public static ModuleConfig moduleConfig;
|
public static ModuleConfig moduleConfig;
|
||||||
|
|
||||||
|
public static final FileCache fileCache = new FileCache();
|
||||||
|
|
||||||
|
public static final String template = AbstractServlet.readFileReal(HTTPDModule.class.getResourceAsStream("/httpd/template.html"));
|
||||||
|
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load()
|
public void load()
|
||||||
{
|
{
|
||||||
moduleConfig = new ModuleConfig(this, "settings.yml");
|
// Move it from /httpd/config.yml to /plugins/Plex/modules/Plex-HTTPD/config.yml
|
||||||
|
moduleConfig = new ModuleConfig(this, "httpd/config.yml", "config.yml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -45,10 +50,22 @@ public class HTTPDModule extends PlexModule
|
||||||
{
|
{
|
||||||
moduleConfig.load();
|
moduleConfig.load();
|
||||||
PlexLog.debug("HTTPD Module Port: {0}", moduleConfig.getInt("server.port"));
|
PlexLog.debug("HTTPD Module Port: {0}", moduleConfig.getInt("server.port"));
|
||||||
if (!setupPermissions() && getPlex().getSystem().equalsIgnoreCase("permissions") && !Bukkit.getPluginManager().isPluginEnabled("Vault"))
|
if ((!Bukkit.getPluginManager().isPluginEnabled("Vault") || !setupPermissions()))
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Plex-HTTPD requires the 'Vault' plugin as well as a Permissions plugin that hooks into 'Vault'. We recommend LuckPerms!");
|
throw new RuntimeException("Plex-HTTPD requires the 'Vault' plugin as well as a Permissions plugin that hooks into 'Vault'. We recommend LuckPerms!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.authenticationManager = new AuthenticationManager();
|
||||||
|
if (this.authenticationManager.provider() != null)
|
||||||
|
{
|
||||||
|
PlexLog.debug(this.authenticationManager.provider().generateLogin());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlexLog.debug("Provider was not found for Authentication so disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
serverThread = new Thread(() ->
|
serverThread = new Thread(() ->
|
||||||
{
|
{
|
||||||
Server server = new Server();
|
Server server = new Server();
|
||||||
|
@ -62,10 +79,22 @@ public class HTTPDModule extends PlexModule
|
||||||
connector.setHost(moduleConfig.getString("server.bind-address"));
|
connector.setHost(moduleConfig.getString("server.bind-address"));
|
||||||
connector.setPort(moduleConfig.getInt("server.port"));
|
connector.setPort(moduleConfig.getInt("server.port"));
|
||||||
|
|
||||||
new AdminsEndpoint();
|
|
||||||
new IndefBansEndpoint();
|
new IndefBansEndpoint();
|
||||||
|
new IndexEndpoint();
|
||||||
new ListEndpoint();
|
new ListEndpoint();
|
||||||
new PunishmentsEndpoint();
|
new PunishmentsEndpoint();
|
||||||
|
new CommandsEndpoint();
|
||||||
|
new SchematicDownloadEndpoint();
|
||||||
|
new SchematicUploadEndpoint();
|
||||||
|
|
||||||
|
ServletHolder uploadHolder = HTTPDModule.context.addServlet(SchematicUploadServlet.class, "/api/schematics/uploading");
|
||||||
|
|
||||||
|
File uploadLoc = new File(System.getProperty("java.io.tmpdir"), "schematic-temp-dir");
|
||||||
|
if (!uploadLoc.exists())
|
||||||
|
{
|
||||||
|
uploadLoc.mkdirs();
|
||||||
|
}
|
||||||
|
uploadHolder.getRegistration().setMultipartConfig(new MultipartConfigElement(uploadLoc.getAbsolutePath(), 1024 * 1024 * 5, 1024 * 1024 * 25, 1024 * 1024));
|
||||||
|
|
||||||
server.setConnectors(new Connector[]{connector});
|
server.setConnectors(new Connector[]{connector});
|
||||||
server.setHandler(context);
|
server.setHandler(context);
|
||||||
|
@ -106,4 +135,34 @@ public class HTTPDModule extends PlexModule
|
||||||
permissions = rsp.getProvider();
|
permissions = rsp.getProvider();
|
||||||
return permissions != null;
|
return permissions != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File getWorldeditFolder()
|
||||||
|
{
|
||||||
|
if (Bukkit.getPluginManager().isPluginEnabled("WorldEdit"))
|
||||||
|
{
|
||||||
|
return new File(Bukkit.getPluginManager().getPlugin("WorldEdit").getDataFolder() + "/schematics/");
|
||||||
|
}
|
||||||
|
else if (Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit"))
|
||||||
|
{
|
||||||
|
return new File(Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit").getDataFolder() + "/schematics/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFileSystemCaseSensitive = !new File("a").equals(new File("A"));
|
||||||
|
|
||||||
|
public static boolean fileNameEquals(String filename1, String filename2)
|
||||||
|
{
|
||||||
|
if (isFileSystemCaseSensitive)
|
||||||
|
{
|
||||||
|
return filename1.equals(filename2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return filename1.equalsIgnoreCase(filename2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package dev.plex.authentication;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Taah
|
||||||
|
* @since 6:37 PM [03-05-2024]
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(fluent = true)
|
||||||
|
public class AuthenticatedUser
|
||||||
|
{
|
||||||
|
private final String ip;
|
||||||
|
private final ZonedDateTime lastAuthenticated;
|
||||||
|
private final LinkedList<String> roles = Lists.newLinkedList();
|
||||||
|
private final UserType userType = UserType.UNKNOWN;
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package dev.plex.authentication;
|
||||||
|
|
||||||
|
import dev.plex.HTTPDModule;
|
||||||
|
import dev.plex.authentication.impl.DiscordOAuth2Provider;
|
||||||
|
import dev.plex.util.PlexLog;
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Taah
|
||||||
|
* @since 7:08 PM [03-05-2024]
|
||||||
|
*/
|
||||||
|
public class AuthenticationManager
|
||||||
|
{
|
||||||
|
private final OAuth2Provider provider;
|
||||||
|
|
||||||
|
public AuthenticationManager()
|
||||||
|
{
|
||||||
|
final boolean enabled = HTTPDModule.moduleConfig.getBoolean("authentication.enabled", false);
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
provider = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlexLog.debug("[HTTPD] Auth is enabled");
|
||||||
|
|
||||||
|
final String providerName = HTTPDModule.moduleConfig.getString("authentication.provider.name", "");
|
||||||
|
if (providerName.isEmpty())
|
||||||
|
{
|
||||||
|
PlexLog.error("OAuth2 Authentication is enabled but no provider was given!");
|
||||||
|
provider = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlexLog.debug("[HTTPD] Provider name is {0}", providerName);
|
||||||
|
|
||||||
|
switch (providerName.toLowerCase())
|
||||||
|
{
|
||||||
|
case "discord" -> {
|
||||||
|
provider = new DiscordOAuth2Provider();
|
||||||
|
}
|
||||||
|
case "xenforo" -> {
|
||||||
|
throw new NotImplementedException("XenForo OAuth2 is not implemented yet!");
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
provider = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlexLog.log("Using {0} provider for authentication", providerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OAuth2Provider provider()
|
||||||
|
{
|
||||||
|
return this.provider;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package dev.plex.authentication;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Response;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Taah
|
||||||
|
* @since 6:36 PM [03-05-2024]
|
||||||
|
*/
|
||||||
|
public interface OAuth2Provider
|
||||||
|
{
|
||||||
|
HashMap<String, AuthenticatedUser> sessions();
|
||||||
|
|
||||||
|
AuthenticatedUser login(Response response, UserType type);
|
||||||
|
|
||||||
|
String[] roles(AuthenticatedUser user);
|
||||||
|
|
||||||
|
String generateLogin();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package dev.plex.authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Taah
|
||||||
|
* @since 6:37 PM [03-05-2024]
|
||||||
|
*/
|
||||||
|
public enum UserType
|
||||||
|
{
|
||||||
|
DISCORD, UNKNOWN
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package dev.plex.authentication.impl;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import dev.plex.HTTPDModule;
|
||||||
|
import dev.plex.authentication.AuthenticatedUser;
|
||||||
|
import dev.plex.authentication.OAuth2Provider;
|
||||||
|
import dev.plex.authentication.UserType;
|
||||||
|
import dev.plex.util.PlexLog;
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.server.Response;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Taah
|
||||||
|
* @since 6:41 PM [03-05-2024]
|
||||||
|
*/
|
||||||
|
public class DiscordOAuth2Provider implements OAuth2Provider
|
||||||
|
{
|
||||||
|
private final HashMap<String, AuthenticatedUser> sessions = Maps.newHashMap();
|
||||||
|
|
||||||
|
private final String token;
|
||||||
|
private final String clientId;
|
||||||
|
private final String redirectUri;
|
||||||
|
|
||||||
|
public DiscordOAuth2Provider()
|
||||||
|
{
|
||||||
|
token = System.getenv("BOT_TOKEN").isEmpty() ? HTTPDModule.moduleConfig.getString("authentication.provider.discord.token", System.getProperty("BOT_TOKEN", "")) : System.getenv("BOT_TOKEN");
|
||||||
|
clientId = HTTPDModule.moduleConfig.getString("authentication.provider.discord.clientId", "");
|
||||||
|
redirectUri = URLEncoder.encode(HTTPDModule.moduleConfig.getString("authentication.provider.redirectUri", ""), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
PlexLog.debug("[HTTPD] Client ID: {0}, Redirect URL: {1}", clientId, redirectUri);
|
||||||
|
|
||||||
|
if (redirectUri.isEmpty())
|
||||||
|
{
|
||||||
|
PlexLog.error("Provided authentication redirect url was empty for HTTPD!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.isEmpty())
|
||||||
|
{
|
||||||
|
PlexLog.error("Provided discord authentication token was empty for HTTPD!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientId.isEmpty())
|
||||||
|
{
|
||||||
|
PlexLog.error("Provided discord client ID was empty for HTTPD!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashMap<String, AuthenticatedUser> sessions()
|
||||||
|
{
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticatedUser login(Response response, UserType type)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] roles(AuthenticatedUser user)
|
||||||
|
{
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateLogin()
|
||||||
|
{
|
||||||
|
return String.format("https://discord.com/oauth2/authorize?client_id=%s&scope=%s&redirect_uri=%s",
|
||||||
|
clientId,
|
||||||
|
"identify%20guilds%20guilds.members.read",
|
||||||
|
redirectUri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package dev.plex.cache;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
public class CacheItem
|
||||||
|
{
|
||||||
|
public String path;
|
||||||
|
public byte[] file;
|
||||||
|
public long timestamp;
|
||||||
|
|
||||||
|
public CacheItem(File f) throws IOException
|
||||||
|
{
|
||||||
|
this.path = f.getPath();
|
||||||
|
this.file = Files.readAllBytes(f.toPath());
|
||||||
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package dev.plex.cache;
|
||||||
|
|
||||||
|
import com.google.common.collect.EvictingQueue;
|
||||||
|
import dev.plex.HTTPDModule;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
public class FileCache
|
||||||
|
{
|
||||||
|
private final Queue<CacheItem> cache = EvictingQueue.create(15);
|
||||||
|
|
||||||
|
public byte[] getFile(File file) throws IOException
|
||||||
|
{
|
||||||
|
return getFile(file.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getFile(String path) throws IOException
|
||||||
|
{
|
||||||
|
CacheItem theItem = cache.stream().filter(cacheItem -> HTTPDModule.fileNameEquals(cacheItem.path, path)).findFirst().orElse(null);
|
||||||
|
if (theItem == null)
|
||||||
|
{
|
||||||
|
theItem = new CacheItem(new File(path));
|
||||||
|
if (theItem.file.length < 1048576) cache.add(theItem);
|
||||||
|
}
|
||||||
|
if (System.currentTimeMillis() - theItem.timestamp > 3 * 60 * 1000) // 3 minutes
|
||||||
|
{
|
||||||
|
cache.remove(theItem);
|
||||||
|
theItem = new CacheItem(new File(path));
|
||||||
|
if (theItem.file.length < 1048576) cache.add(theItem);
|
||||||
|
}
|
||||||
|
return theItem.file;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import dev.plex.HTTPDModule;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
|
||||||
public class Log
|
public class Log
|
||||||
{
|
{
|
||||||
public static void log(String message, Object... strings)
|
public static void log(String message, Object... strings)
|
||||||
|
|
|
@ -3,15 +3,20 @@ package dev.plex.request;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import dev.plex.HTTPDModule;
|
import dev.plex.HTTPDModule;
|
||||||
import dev.plex.logging.Log;
|
import dev.plex.logging.Log;
|
||||||
import jakarta.servlet.AsyncContext;
|
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServlet;
|
import jakarta.servlet.http.HttpServlet;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.text.CharacterIterator;
|
||||||
|
import java.text.StringCharacterIterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
|
||||||
|
@ -43,7 +48,7 @@ public class AbstractServlet extends HttpServlet
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
String ipAddress = req.getRemoteAddr();
|
String ipAddress = req.getRemoteAddr();
|
||||||
if (ipAddress == null)
|
if (ipAddress.equals("127.0.0.1"))
|
||||||
{
|
{
|
||||||
ipAddress = req.getHeader("X-FORWARDED-FOR");
|
ipAddress = req.getHeader("X-FORWARDED-FOR");
|
||||||
}
|
}
|
||||||
|
@ -69,8 +74,11 @@ public class AbstractServlet extends HttpServlet
|
||||||
resp.setStatus(HttpServletResponse.SC_OK);
|
resp.setStatus(HttpServletResponse.SC_OK);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Object object = mapping.method.invoke(this, req);
|
Object object = mapping.method.invoke(this, req, resp);
|
||||||
resp.getWriter().println(object.toString());
|
if (object != null)
|
||||||
|
{
|
||||||
|
resp.getWriter().println(object.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException | IllegalAccessException | InvocationTargetException e)
|
catch (IOException | IllegalAccessException | InvocationTargetException e)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +87,62 @@ public class AbstractServlet extends HttpServlet
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String readFile(InputStream filename)
|
||||||
|
{
|
||||||
|
String base = HTTPDModule.template;
|
||||||
|
String page = readFileReal(filename);
|
||||||
|
String[] info = page.split("\n", 3);
|
||||||
|
base = base.replace("${TITLE}", info[0]);
|
||||||
|
base = base.replace("${ACTIVE_" + info[1] + "}", "active\" aria-current=\"page");
|
||||||
|
base = base.replace("${ACTIVE_HOME}", "");
|
||||||
|
base = base.replace("${ACTIVE_ADMINS}", "");
|
||||||
|
base = base.replace("${ACTIVE_INDEFBANS}", "");
|
||||||
|
base = base.replace("${ACTIVE_LIST}", "");
|
||||||
|
base = base.replace("${ACTIVE_COMMANDS}", "");
|
||||||
|
base = base.replace("${ACTIVE_PUNISHMENTS}", "");
|
||||||
|
base = base.replace("${ACTIVE_SCHEMATICS}", "");
|
||||||
|
base = base.replace("${CONTENT}", info[2]);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readFileReal(InputStream filename)
|
||||||
|
{
|
||||||
|
StringBuilder contentBuilder = new StringBuilder();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(Objects.requireNonNull(filename)));
|
||||||
|
String str;
|
||||||
|
while ((str = in.readLine()) != null)
|
||||||
|
{
|
||||||
|
contentBuilder.append(str).append("\n");
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
catch (IOException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return contentBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code from https://programming.guide/java/formatting-byte-size-to-human-readable-format.html
|
||||||
|
public static String formattedSize(long bytes)
|
||||||
|
{
|
||||||
|
long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
|
||||||
|
if (absB < 1024)
|
||||||
|
{
|
||||||
|
return bytes + " B";
|
||||||
|
}
|
||||||
|
long value = absB;
|
||||||
|
CharacterIterator ci = new StringCharacterIterator("KMGTPE");
|
||||||
|
for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10)
|
||||||
|
{
|
||||||
|
value >>= 10;
|
||||||
|
ci.next();
|
||||||
|
}
|
||||||
|
value *= Long.signum(bytes);
|
||||||
|
return String.format("%.1f %ciB", value / 1024.0, ci.current());
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class Mapping
|
public static class Mapping
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
package dev.plex.request;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
||||||
|
import dev.plex.HTTPDModule;
|
||||||
|
import dev.plex.cache.DataUtils;
|
||||||
|
import dev.plex.player.PlexPlayer;
|
||||||
|
import dev.plex.util.PlexLog;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.Part;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class SchematicUploadServlet extends HttpServlet
|
||||||
|
{
|
||||||
|
private static final Pattern schemNameMatcher = Pattern.compile("^[a-z0-9'!,_ -]{1,30}\\.schem(atic)?$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
if (request.getRemoteAddr() == null)
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("Your IP address could not be detected. Please ensure you are using IPv4."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlexPlayer plexPlayer = DataUtils.getPlayerByIP(request.getRemoteAddr());
|
||||||
|
if (plexPlayer == null)
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("Couldn't load your IP Address: " + request.getRemoteAddr() + ". Have you joined the server before?"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlexLog.debug("Plex-HTTPD using permissions check");
|
||||||
|
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(plexPlayer.getUuid());
|
||||||
|
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.schematics.upload"))
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("You do not have permission to upload schematics."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File worldeditFolder = HTTPDModule.getWorldeditFolder();
|
||||||
|
if (worldeditFolder == null)
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("Worldedit is not installed!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File[] schematics = worldeditFolder.listFiles();
|
||||||
|
Part uploadPart;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
uploadPart = request.getPart("file");
|
||||||
|
}
|
||||||
|
catch (IllegalStateException e)
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("That schematic is too large!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String filename = uploadPart.getSubmittedFileName().replaceAll("[^a-zA-Z0-9'!,_ .-]", "_");
|
||||||
|
if (!schemNameMatcher.matcher(filename).matches())
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("That is not a valid schematic filename!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean alreadyExists = schematics != null && Arrays.stream(schematics).anyMatch(file -> HTTPDModule.fileNameEquals(file.getName(), filename));
|
||||||
|
if (alreadyExists)
|
||||||
|
{
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("A schematic with the name <b>" + filename + "</b> already exists!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InputStream inputStream = uploadPart.getInputStream();
|
||||||
|
File schematicFile = new File(worldeditFolder, filename);
|
||||||
|
FileUtils.copyInputStreamToFile(inputStream, schematicFile);
|
||||||
|
ClipboardFormat schematicFormat = ClipboardFormats.findByFile(schematicFile);
|
||||||
|
if (schematicFormat == null)
|
||||||
|
{
|
||||||
|
PlexLog.log("IP Address: " + request.getRemoteAddr() + " FAILED to upload schematic with filename: " + filename);
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("Schematic is not a valid format."));
|
||||||
|
FileUtils.deleteQuietly(schematicFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
schematicFormat.getReader(new FileInputStream(schematicFile));
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
PlexLog.log("IP Address: " + request.getRemoteAddr() + " FAILED to upload schematic with filename: " + filename);
|
||||||
|
response.getWriter().println(schematicUploadBadHTML("Schematic is not a valid format."));
|
||||||
|
FileUtils.deleteQuietly(schematicFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Files.copy(inputStream, schematic.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
inputStream.close();
|
||||||
|
response.getWriter().println(schematicUploadGoodHTML("Successfully uploaded <b>" + filename + "</b>."));
|
||||||
|
PlexLog.log("IP Address: " + request.getRemoteAddr() + " uploaded schematic with filename: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String schematicUploadBadHTML(String message)
|
||||||
|
{
|
||||||
|
String file = AbstractServlet.readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload_bad.html"));
|
||||||
|
file = file.replace("${MESSAGE}", message);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String schematicUploadGoodHTML(String message)
|
||||||
|
{
|
||||||
|
String file = AbstractServlet.readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload_good.html"));
|
||||||
|
file = file.replace("${MESSAGE}", message);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
package dev.plex.request.impl;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import dev.plex.HTTPDModule;
|
|
||||||
import dev.plex.Plex;
|
|
||||||
import dev.plex.cache.DataUtils;
|
|
||||||
import dev.plex.player.PlexPlayer;
|
|
||||||
import dev.plex.rank.enums.Rank;
|
|
||||||
import dev.plex.request.AbstractServlet;
|
|
||||||
import dev.plex.request.GetMapping;
|
|
||||||
import dev.plex.util.PlexLog;
|
|
||||||
import dev.plex.util.adapter.LocalDateTimeSerializer;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
|
|
||||||
public class AdminsEndpoint extends AbstractServlet
|
|
||||||
{
|
|
||||||
@GetMapping(endpoint = "/api/admins/")
|
|
||||||
public String getAdmins(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
String ipAddress = request.getRemoteAddr();
|
|
||||||
if (ipAddress == null)
|
|
||||||
{
|
|
||||||
return "An IP address could not be detected. Please ensure you are connecting using IPv4.";
|
|
||||||
}
|
|
||||||
final PlexPlayer player = DataUtils.getPlayerByIP(ipAddress);
|
|
||||||
if (player == null)
|
|
||||||
{
|
|
||||||
// This likely means they've never joined the server before. That's okay. We can just not return IPs.
|
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(Plex.get().getAdminList().getAllAdminPlayers().stream().peek(plexPlayer -> plexPlayer.setIps(Lists.newArrayList())).peek(plexPlayer -> plexPlayer.setPunishments(Lists.newArrayList())).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
if (Plex.get().getSystem().equalsIgnoreCase("ranks"))
|
|
||||||
{
|
|
||||||
PlexLog.debug("Plex-HTTPD using ranks check");
|
|
||||||
if (!player.getRankFromString().isAtLeast(Rank.ADMIN))
|
|
||||||
{
|
|
||||||
// Don't return IPs either if the person is not an Admin or above.
|
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(Plex.get().getAdminList().getAllAdminPlayers().stream().peek(plexPlayer -> plexPlayer.setIps(Lists.newArrayList())).peek(plexPlayer -> plexPlayer.setPunishments(Lists.newArrayList())).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Plex.get().getSystem().equalsIgnoreCase("permissions"))
|
|
||||||
{
|
|
||||||
PlexLog.debug("Plex-HTTPD using permissions check");
|
|
||||||
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.getUuid());
|
|
||||||
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.admins.access"))
|
|
||||||
{
|
|
||||||
// If the person doesn't have permission, don't return IPs
|
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(Plex.get().getAdminList().getAllAdminPlayers().stream().peek(plexPlayer -> plexPlayer.setIps(Lists.newArrayList())).peek(plexPlayer -> plexPlayer.setPunishments(Lists.newArrayList())).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(Plex.get().getAdminList().getAllAdminPlayers());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package dev.plex.request.impl;
|
||||||
|
|
||||||
|
import dev.plex.command.PlexCommand;
|
||||||
|
import dev.plex.command.annotation.CommandPermissions;
|
||||||
|
import dev.plex.request.AbstractServlet;
|
||||||
|
import dev.plex.request.GetMapping;
|
||||||
|
import dev.plex.util.PlexLog;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandMap;
|
||||||
|
import org.bukkit.command.PluginIdentifiableCommand;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class AuthenticationEndpoint extends AbstractServlet
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping(endpoint = "/oauth2")
|
||||||
|
public String login(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
// TODO: Nuh uh
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
package dev.plex.request.impl;
|
||||||
|
|
||||||
|
import dev.plex.command.PlexCommand;
|
||||||
|
import dev.plex.command.annotation.CommandPermissions;
|
||||||
|
import dev.plex.request.AbstractServlet;
|
||||||
|
import dev.plex.request.GetMapping;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandMap;
|
||||||
|
import org.bukkit.command.PluginIdentifiableCommand;
|
||||||
|
|
||||||
|
public class CommandsEndpoint extends AbstractServlet
|
||||||
|
{
|
||||||
|
|
||||||
|
private final StringBuilder list = new StringBuilder();
|
||||||
|
private boolean loadedCommands = false;
|
||||||
|
|
||||||
|
@GetMapping(endpoint = "/api/commands/")
|
||||||
|
public String getCommands(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
if (!loadedCommands)
|
||||||
|
{
|
||||||
|
final SortedMap<String, List<Command>> commandMap = new TreeMap<>();
|
||||||
|
final CommandMap map = Bukkit.getCommandMap();
|
||||||
|
for (Command command : map.getKnownCommands().values())
|
||||||
|
{
|
||||||
|
String plugin = "Bukkit";
|
||||||
|
if (command instanceof PluginIdentifiableCommand)
|
||||||
|
{
|
||||||
|
plugin = ((PluginIdentifiableCommand) command).getPlugin().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Command> pluginCommands = commandMap.computeIfAbsent(plugin, k -> new ArrayList<>());
|
||||||
|
if (!pluginCommands.contains(command))
|
||||||
|
{
|
||||||
|
pluginCommands.add(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String key : commandMap.keySet())
|
||||||
|
{
|
||||||
|
commandMap.get(key).sort(Comparator.comparing(Command::getName));
|
||||||
|
StringBuilder rows = new StringBuilder();
|
||||||
|
for (Command command : commandMap.get(key))
|
||||||
|
{
|
||||||
|
String permission = command.getPermission();
|
||||||
|
if (command instanceof PlexCommand plexCmd)
|
||||||
|
{
|
||||||
|
CommandPermissions perms = plexCmd.getClass().getAnnotation(CommandPermissions.class);
|
||||||
|
if (perms != null)
|
||||||
|
{
|
||||||
|
permission = (perms.permission().isBlank() ? "N/A" : perms.permission());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.append(createRow(command.getName(), command.getAliases(), command.getDescription(), command.getUsage(), permission));
|
||||||
|
}
|
||||||
|
|
||||||
|
list.append(createTable(key, rows.toString())).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedCommands = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return commandsHTML(list.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String commandsHTML(String commandsList)
|
||||||
|
{
|
||||||
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/commands.html"));
|
||||||
|
file = file.replace("${commands}", commandsList);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createTable(String pluginName, String commandRows)
|
||||||
|
{
|
||||||
|
return "<details id=\"" + pluginName + "\"><summary>" + pluginName + "</summary>\n"
|
||||||
|
+ "<table id=\"" + pluginName + "Table\" class=\"table table-striped table-bordered\">\n"
|
||||||
|
+ " <thead>\n <tr>\n <th scope=\"col\">Name (Aliases)</th>\n "
|
||||||
|
+ "<th scope=\"col\">Description</th>\n "
|
||||||
|
+ "<th scope=\"col\">Usage</th>\n "
|
||||||
|
+ "<th scope=\"col\">Permission</th>\n </tr>\n</thead>\n"
|
||||||
|
+ "<tbody>\n " + commandRows + "\n</tbody>\n</table>\n</details>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createRow(String name, List<String> aliases, String description, String usage, String permission)
|
||||||
|
{
|
||||||
|
return " <tr>\n <th scope=\"row\">" + name
|
||||||
|
+ (aliases.isEmpty() || aliases.toString().equals("[]") ? "" : " (" + String.join(", ", aliases) + ")") + "</th>\n"
|
||||||
|
+ " <th scope=\"row\">" + description + "</th>\n"
|
||||||
|
+ " <th scope=\"row\"><code>" + cleanUsage(usage) + "</code></th>\n"
|
||||||
|
+ " <th scope=\"row\">" + (permission != null ? permission.replaceAll(";", "<br>") : "N/A") + "</th>\n </tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cleanUsage(String usage)
|
||||||
|
{
|
||||||
|
usage = usage.replaceAll("<", "<").replaceAll(">", ">");
|
||||||
|
if (usage.isBlank())
|
||||||
|
{
|
||||||
|
usage = "Not Provided";
|
||||||
|
}
|
||||||
|
return usage.startsWith("/") || usage.equals("Not Provided") ? usage : "/" + usage;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,47 +5,46 @@ import dev.plex.HTTPDModule;
|
||||||
import dev.plex.Plex;
|
import dev.plex.Plex;
|
||||||
import dev.plex.cache.DataUtils;
|
import dev.plex.cache.DataUtils;
|
||||||
import dev.plex.player.PlexPlayer;
|
import dev.plex.player.PlexPlayer;
|
||||||
import dev.plex.rank.enums.Rank;
|
|
||||||
import dev.plex.request.AbstractServlet;
|
import dev.plex.request.AbstractServlet;
|
||||||
import dev.plex.request.GetMapping;
|
import dev.plex.request.GetMapping;
|
||||||
import dev.plex.util.PlexLog;
|
import dev.plex.util.PlexLog;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.UUID;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
|
|
||||||
public class IndefBansEndpoint extends AbstractServlet
|
public class IndefBansEndpoint extends AbstractServlet
|
||||||
{
|
{
|
||||||
|
private static final String TITLE = "Indefinite Bans - Plex HTTPD";
|
||||||
|
|
||||||
@GetMapping(endpoint = "/api/indefbans/")
|
@GetMapping(endpoint = "/api/indefbans/")
|
||||||
public String getBans(HttpServletRequest request)
|
public String getBans(HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
String ipAddress = request.getRemoteAddr();
|
String ipAddress = request.getRemoteAddr();
|
||||||
if (ipAddress == null)
|
if (ipAddress == null)
|
||||||
{
|
{
|
||||||
return "An IP address could not be detected. Please ensure you are connecting using IPv4.";
|
return indefbansHTML("An IP address could not be detected. Please ensure you are connecting using IPv4.");
|
||||||
}
|
}
|
||||||
final PlexPlayer player = DataUtils.getPlayerByIP(ipAddress);
|
final PlexPlayer player = DataUtils.getPlayerByIP(ipAddress);
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
return "Couldn't load your IP Address: " + ipAddress + ". Have you joined the server before?";
|
return indefbansHTML("Couldn't load your IP Address: " + ipAddress + ". Have you joined the server before?");
|
||||||
}
|
}
|
||||||
if (Plex.get().getSystem().equalsIgnoreCase("ranks"))
|
PlexLog.debug("Plex-HTTPD using permissions check");
|
||||||
|
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.getUuid());
|
||||||
|
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.indefbans.access"))
|
||||||
{
|
{
|
||||||
PlexLog.debug("Plex-HTTPD using ranks check");
|
return indefbansHTML("Not enough permissions to view this page.");
|
||||||
if (!player.getRankFromString().isAtLeast(Rank.ADMIN))
|
|
||||||
{
|
|
||||||
return "Not a high enough rank to view this page.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Plex.get().getSystem().equalsIgnoreCase("permissions"))
|
|
||||||
{
|
|
||||||
PlexLog.debug("Plex-HTTPD using permissions check");
|
|
||||||
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.getUuid());
|
|
||||||
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.indefbans.access"))
|
|
||||||
{
|
|
||||||
return "Not enough permissions to view this page.";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.setHeader("content-type", "application/json");
|
||||||
return new GsonBuilder().setPrettyPrinting().create().toJson(Plex.get().getPunishmentManager().getIndefiniteBans().stream().toList());
|
return new GsonBuilder().setPrettyPrinting().create().toJson(Plex.get().getPunishmentManager().getIndefiniteBans().stream().toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String indefbansHTML(String message)
|
||||||
|
{
|
||||||
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/indefbans.html"));
|
||||||
|
file = file.replace("${MESSAGE}", message);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package dev.plex.request.impl;
|
||||||
|
|
||||||
|
import dev.plex.request.AbstractServlet;
|
||||||
|
import dev.plex.request.GetMapping;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
public class IndexEndpoint extends AbstractServlet
|
||||||
|
{
|
||||||
|
@GetMapping(endpoint = "//")
|
||||||
|
public String getIndex(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
return indexHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(endpoint = "/api/")
|
||||||
|
public String getAPI(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
return indexHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String indexHTML()
|
||||||
|
{
|
||||||
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/index.html"));
|
||||||
|
String isAre = Bukkit.getOnlinePlayers().size() == 1 ? " is " : " are ";
|
||||||
|
String pluralOnline = Bukkit.getOnlinePlayers().size() == 1 ? " player " : " players ";
|
||||||
|
String pluralMax = Bukkit.getMaxPlayers() == 1 ? " player " : " players ";
|
||||||
|
file = file.replace("${is_are}", isAre);
|
||||||
|
file = file.replace("${server_online_players}", Bukkit.getOnlinePlayers().size() + pluralOnline);
|
||||||
|
file = file.replace("${server_total_players}", Bukkit.getMaxPlayers() + pluralMax);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,19 +3,22 @@ package dev.plex.request.impl;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import dev.plex.request.AbstractServlet;
|
import dev.plex.request.AbstractServlet;
|
||||||
import dev.plex.request.GetMapping;
|
import dev.plex.request.GetMapping;
|
||||||
|
import dev.plex.request.MappingHeaders;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class ListEndpoint extends AbstractServlet
|
public class ListEndpoint extends AbstractServlet
|
||||||
{
|
{
|
||||||
List<String> players = new ArrayList<>();
|
|
||||||
|
|
||||||
@GetMapping(endpoint = "/api/list/")
|
@GetMapping(endpoint = "/api/list/")
|
||||||
public String getOnlinePlayers(HttpServletRequest request)
|
@MappingHeaders(headers = "content-type;application/json")
|
||||||
|
public String getOnlinePlayers(HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
|
List<String> players = new ArrayList<>();
|
||||||
for (Player player : Bukkit.getOnlinePlayers())
|
for (Player player : Bukkit.getOnlinePlayers())
|
||||||
{
|
{
|
||||||
players.add(player.getName());
|
players.add(player.getName());
|
||||||
|
|
|
@ -2,69 +2,31 @@ package dev.plex.request.impl;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import dev.plex.HTTPDModule;
|
import dev.plex.HTTPDModule;
|
||||||
import dev.plex.Plex;
|
|
||||||
import dev.plex.cache.DataUtils;
|
import dev.plex.cache.DataUtils;
|
||||||
import dev.plex.player.PlexPlayer;
|
import dev.plex.player.PlexPlayer;
|
||||||
import dev.plex.rank.enums.Rank;
|
|
||||||
import dev.plex.request.AbstractServlet;
|
import dev.plex.request.AbstractServlet;
|
||||||
import dev.plex.request.GetMapping;
|
import dev.plex.request.GetMapping;
|
||||||
import dev.plex.util.PlexLog;
|
import dev.plex.util.adapter.ZonedDateTimeAdapter;
|
||||||
import dev.plex.util.adapter.LocalDateTimeSerializer;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.io.BufferedReader;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.FileReader;
|
import java.time.ZonedDateTime;
|
||||||
import java.io.IOException;
|
import java.util.UUID;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class PunishmentsEndpoint extends AbstractServlet
|
public class PunishmentsEndpoint extends AbstractServlet
|
||||||
{
|
{
|
||||||
@GetMapping(endpoint = "/api/punishments/")
|
@GetMapping(endpoint = "/api/punishments/")
|
||||||
public String getPunishments(HttpServletRequest request)
|
public String getPunishments(HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
String ipAddress = request.getRemoteAddr();
|
String ipAddress = request.getRemoteAddr();
|
||||||
if (ipAddress == null)
|
if (ipAddress == null)
|
||||||
{
|
{
|
||||||
return "An IP address could not be detected. Please ensure you are connecting using IPv4.";
|
return punishmentsHTML("An IP address could not be detected. Please ensure you are connecting using IPv4.");
|
||||||
}
|
}
|
||||||
if (request.getPathInfo() == null)
|
if (request.getPathInfo() == null || request.getPathInfo().equals("/"))
|
||||||
{
|
{
|
||||||
/*StringBuilder contentBuilder = new StringBuilder();
|
return readFile(this.getClass().getResourceAsStream("/httpd/punishments.html"));
|
||||||
PlexLog.log(this.getClass().getClassLoader().getResource("punishments.html").getPath());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
BufferedReader in = new BufferedReader(new FileReader(this.getClass().getClassLoader().getResource("punishments.html").getFile().replace("!", "")));
|
|
||||||
String str;
|
|
||||||
while ((str = in.readLine()) != null)
|
|
||||||
{
|
|
||||||
contentBuilder.append(str);
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
catch (IOException ignored)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return contentBuilder.toString();*/
|
|
||||||
return """
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<body>
|
|
||||||
<div style="text-align: center;">
|
|
||||||
<h2 style="font-family:Helvetica">Enter the UUID or username of the player you want to check</h2>
|
|
||||||
<input id="test" type="text" autofocus>
|
|
||||||
<button type="button" onclick="redirect()">Submit</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function redirect() {
|
|
||||||
var url = document.getElementById('test').value
|
|
||||||
window.location = "punishments/" + url
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>""";
|
|
||||||
}
|
}
|
||||||
UUID pathUUID;
|
UUID pathUUID;
|
||||||
String pathPlexPlayer;
|
String pathPlexPlayer;
|
||||||
|
@ -83,36 +45,39 @@ public class PunishmentsEndpoint extends AbstractServlet
|
||||||
final PlexPlayer player = DataUtils.getPlayerByIP(ipAddress);
|
final PlexPlayer player = DataUtils.getPlayerByIP(ipAddress);
|
||||||
if (punishedPlayer == null)
|
if (punishedPlayer == null)
|
||||||
{
|
{
|
||||||
return "This player has never joined the server before.";
|
return punishmentsHTML("This player has never joined the server before.");
|
||||||
}
|
}
|
||||||
if (punishedPlayer.getPunishments().isEmpty())
|
if (punishedPlayer.getPunishments().isEmpty())
|
||||||
{
|
{
|
||||||
return "This player has been a good boy. They have no punishments!";
|
return punishmentsGoodHTML("This player has been a good boy. They have no punishments!");
|
||||||
}
|
}
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
// If the player is null, give it to them without the IPs
|
// If the player is null, give it to them without the IPs
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
|
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
|
||||||
}
|
}
|
||||||
if (Plex.get().getSystem().equalsIgnoreCase("ranks"))
|
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.getUuid());
|
||||||
|
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.punishments.access"))
|
||||||
{
|
{
|
||||||
PlexLog.debug("Plex-HTTPD using ranks check");
|
// If the person doesn't have permission, don't return IPs
|
||||||
if (!player.getRankFromString().isAtLeast(Rank.ADMIN))
|
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
|
||||||
{
|
|
||||||
// Don't return IPs either if the person is not an Admin or above.
|
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (Plex.get().getSystem().equalsIgnoreCase("permissions"))
|
|
||||||
{
|
response.setHeader("content-type", "application/json");
|
||||||
PlexLog.debug("Plex-HTTPD using permissions check");
|
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().toList());
|
||||||
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.getUuid());
|
}
|
||||||
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.punishments.access"))
|
|
||||||
{
|
private String punishmentsHTML(String message)
|
||||||
// If the person doesn't have permission, don't return IPs
|
{
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/punishments_error.html"));
|
||||||
}
|
file = file.replace("${MESSAGE}", message);
|
||||||
}
|
return file;
|
||||||
return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().toList());
|
}
|
||||||
|
|
||||||
|
private String punishmentsGoodHTML(String message)
|
||||||
|
{
|
||||||
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/punishments_good.html"));
|
||||||
|
file = file.replace("${MESSAGE}", message);
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package dev.plex.request.impl;
|
||||||
|
|
||||||
|
import dev.plex.HTTPDModule;
|
||||||
|
import dev.plex.request.AbstractServlet;
|
||||||
|
import dev.plex.request.GetMapping;
|
||||||
|
import dev.plex.util.PlexLog;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SchematicDownloadEndpoint extends AbstractServlet
|
||||||
|
{
|
||||||
|
List<File> files = new ArrayList<>();
|
||||||
|
|
||||||
|
@GetMapping(endpoint = "/api/schematics/download/")
|
||||||
|
public String downloadSchematic(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
if (request.getPathInfo() == null || request.getPathInfo().equals("/"))
|
||||||
|
{
|
||||||
|
return schematicHTML();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutputStream outputStream;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
outputStream = response.getOutputStream();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
schematicServe(request.getPathInfo().replace("/", ""), outputStream);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void schematicServe(String requestedSchematic, OutputStream outputStream)
|
||||||
|
{
|
||||||
|
File worldeditFolder = HTTPDModule.getWorldeditFolder();
|
||||||
|
if (worldeditFolder == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File[] schems = worldeditFolder.listFiles();
|
||||||
|
if (schems != null)
|
||||||
|
{
|
||||||
|
File schemFile = Arrays.stream(schems).filter(file -> file.getName().equals(requestedSchematic)).findFirst().orElse(null);
|
||||||
|
if (schemFile != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] schemData = HTTPDModule.fileCache.getFile(schemFile);
|
||||||
|
if (schemData != null)
|
||||||
|
{
|
||||||
|
outputStream.write(schemData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String schematicHTML()
|
||||||
|
{
|
||||||
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/schematic_download.html"));
|
||||||
|
File worldeditFolder = HTTPDModule.getWorldeditFolder();
|
||||||
|
if (worldeditFolder == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (File worldeditFile : listFilesForFolder(worldeditFolder))
|
||||||
|
{
|
||||||
|
String fixedPath = worldeditFile.getPath().replace("plugins/FastAsyncWorldEdit/schematics/", "");
|
||||||
|
fixedPath = fixedPath.replace("plugins/WorldEdit/schematics/", "");
|
||||||
|
String sanitizedName = fixedPath.replaceAll("<", "<").replaceAll(">", ">");
|
||||||
|
sb.append(" <tr>\n" +
|
||||||
|
" <th scope=\"row\">\n <a href=\"" + fixedPath + "\" download>" + sanitizedName + "</a>\n </th>\n" +
|
||||||
|
" <td>\n " + formattedSize(worldeditFile.length()) + "\n </td>\n" +
|
||||||
|
" </tr>\n");
|
||||||
|
}
|
||||||
|
file = file.replace("${schematics}", sb.toString());
|
||||||
|
files.clear();
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<File> listFilesForFolder(final File folder)
|
||||||
|
{
|
||||||
|
for (File fileEntry : folder.listFiles())
|
||||||
|
{
|
||||||
|
if (fileEntry.isDirectory())
|
||||||
|
{
|
||||||
|
PlexLog.debug("Found directory");
|
||||||
|
listFilesForFolder(fileEntry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files.add(fileEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package dev.plex.request.impl;
|
||||||
|
|
||||||
|
import dev.plex.HTTPDModule;
|
||||||
|
import dev.plex.cache.DataUtils;
|
||||||
|
import dev.plex.player.PlexPlayer;
|
||||||
|
import dev.plex.request.AbstractServlet;
|
||||||
|
import dev.plex.request.GetMapping;
|
||||||
|
import dev.plex.util.PlexLog;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
|
||||||
|
public class SchematicUploadEndpoint extends AbstractServlet
|
||||||
|
{
|
||||||
|
@GetMapping(endpoint = "/api/schematics/upload/")
|
||||||
|
public String uploadSchematic(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
{
|
||||||
|
String ipAddress = request.getRemoteAddr();
|
||||||
|
if (ipAddress == null)
|
||||||
|
{
|
||||||
|
return schematicsHTML("An IP address could not be detected. Please ensure you are connecting using IPv4.");
|
||||||
|
}
|
||||||
|
final PlexPlayer player = DataUtils.getPlayerByIP(ipAddress);
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return schematicsHTML("Couldn't load your IP Address: " + ipAddress + ". Have you joined the server before?");
|
||||||
|
}
|
||||||
|
PlexLog.debug("Plex-HTTPD using permissions check");
|
||||||
|
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.getUuid());
|
||||||
|
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.schematics.upload"))
|
||||||
|
{
|
||||||
|
return schematicsHTML("You do not have permission to upload schematics.");
|
||||||
|
}
|
||||||
|
return readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String schematicsHTML(String message)
|
||||||
|
{
|
||||||
|
String file = readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload_bad.html"));
|
||||||
|
file = file.replace("${MESSAGE}", message);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/gh/Telesphoreo/bootstrap-color-switcher@master/script.js"></script>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@200;400&display=swap" rel="stylesheet">
|
||||||
|
<title>${TITLE} - Plex HTTPD</title>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: 'IBM Plex Sans', sans-serif;">
|
||||||
|
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="/" style="font-weight:200;">Plex HTTPD</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
|
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_HOME}" href="/">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_INDEFBANS}" href="/api/indefbans/">Indefinite Bans</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_LIST}" href="/api/list/">List</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_PUNISHMENTS}" href="/api/punishments/">Punishments</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle ${ACTIVE_SCHEMATICS}" id="navbarDropdownMenuLink" role="button"
|
||||||
|
data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
Schematics
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
|
||||||
|
<li><a class="dropdown-item" href="/api/schematics/download/">Download</a></li>
|
||||||
|
<li><a class="dropdown-item" href="/api/schematics/upload/">Upload</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div style="text-align: center;" class="col-auto m-0 row justify-content-center p-4">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,12 @@
|
||||||
|
Commands
|
||||||
|
COMMANDS
|
||||||
|
<style>
|
||||||
|
summary {
|
||||||
|
font-size: 24px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h2>Commands List</h2>
|
||||||
|
<h5>A list of commands is below.</h5>
|
||||||
|
<br><br>
|
||||||
|
${commands}
|
|
@ -0,0 +1,15 @@
|
||||||
|
server:
|
||||||
|
bind-address: 0.0.0.0
|
||||||
|
port: 27192
|
||||||
|
logging: false
|
||||||
|
|
||||||
|
authentication:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Providers: discord
|
||||||
|
provider:
|
||||||
|
name: discord
|
||||||
|
redirectUri: ""
|
||||||
|
discord: # Fill if using discord provider
|
||||||
|
clientId: ""
|
||||||
|
token: "" # Can also use environment variable or system property BOT_TOKEN
|
|
@ -0,0 +1,4 @@
|
||||||
|
Indefinite Bans
|
||||||
|
INDEFBANS
|
||||||
|
<h2>Indefinite Bans</h2>
|
||||||
|
<h5 class="alert alert-danger mb-3 w-auto p-3" role="alert"><b>Error:</b> ${MESSAGE}</h5>
|
|
@ -0,0 +1,5 @@
|
||||||
|
Home
|
||||||
|
HOME
|
||||||
|
<h2>Welcome to the Plex HTTPD!</h2>
|
||||||
|
<h4>Use the sidebar to navigate the available pages.</h4>
|
||||||
|
<h4><br>There ${is_are} currently ${server_online_players} online out of ${server_total_players} total.</h4>
|
|
@ -0,0 +1,23 @@
|
||||||
|
Punishments
|
||||||
|
PUNISHMENTS
|
||||||
|
<h2>Punishment Search</h2>
|
||||||
|
<label for="uuid"><h5>Enter the UUID or username of the player you want to lookup</h5></label>
|
||||||
|
<div class="input-group mb-3 w-75 p-3">
|
||||||
|
<input id="uuid" type="text" autocomplete="off" autofocus class="form-control">
|
||||||
|
<button class="btn btn-outline-primary" type="submit"
|
||||||
|
onclick="redirect();">Submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function redirect() {
|
||||||
|
const url = document.getElementById('uuid').value;
|
||||||
|
window.location = "/api/punishments/" + url
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
document.getElementById('uuid').addEventListener('keypress', function (event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
redirect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,4 @@
|
||||||
|
Punishments
|
||||||
|
PUNISHMENTS
|
||||||
|
<h2>Punishment Search</h2>
|
||||||
|
<h5 class="alert alert-danger mb-3 w-auto p-3" role="alert"><b>Error:</b> ${MESSAGE}</h5>
|
|
@ -0,0 +1,4 @@
|
||||||
|
Punishments
|
||||||
|
PUNISHMENTS
|
||||||
|
<h2>Punishment Search</h2>
|
||||||
|
<h5 class="alert alert-success mb-3 w-auto p-3" role="alert">${MESSAGE}</h5>
|
|
@ -0,0 +1,35 @@
|
||||||
|
Schematics
|
||||||
|
SCHEMATICS
|
||||||
|
<h2>Schematic Download</h2>
|
||||||
|
<label for="schemList"><h5>A list of schematics is below. You can click on the schematic name to download it.</h5>
|
||||||
|
</label>
|
||||||
|
<div class="input-group mb-3 w-75 p-3">
|
||||||
|
<input type="text" autocomplete="off" autofocus class="form-control" oninput="filterTable(this.value)"
|
||||||
|
placeholder="Search for a schematic...">
|
||||||
|
</div>
|
||||||
|
<table id="schemList" class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Size</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${schematics}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<script>
|
||||||
|
let schemList = document.getElementById("schemList").getElementsByTagName("tbody")[0].getElementsByTagName("tr");
|
||||||
|
|
||||||
|
function filterTable(query) {
|
||||||
|
for (let i = 0; i < schemList.length; i++) {
|
||||||
|
let th = schemList[i].getElementsByTagName("th")[0];
|
||||||
|
let schemName = th.textContent || th.innerText;
|
||||||
|
if (schemName.toLowerCase().includes(query.toLowerCase())) {
|
||||||
|
schemList[i].style.display = "";
|
||||||
|
} else {
|
||||||
|
schemList[i].style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,13 @@
|
||||||
|
Schematics
|
||||||
|
SCHEMATICS
|
||||||
|
<h2>Schematic Upload</h2>
|
||||||
|
<div class="cos-xs-8 col-lg-5">
|
||||||
|
<label for="formFile" class="form-label"><h5>Please select a schematic file to upload.</h5></label>
|
||||||
|
<form class="input-group justify-content-center" enctype="multipart/form-data" method="post"
|
||||||
|
action="/api/schematics/uploading">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="file" class="form-control" id="formFile" name="file" aria-describedby="formFile" aria-label="Upload">
|
||||||
|
<button class="btn btn-outline-primary" type="submit">Upload</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
Schematics
|
||||||
|
SCHEMATICS
|
||||||
|
<h2>Schematic Upload</h2>
|
||||||
|
<h5 class="alert alert-danger mb-3 w-auto p-3" role="alert"><b>Error:</b> ${MESSAGE}</h5>
|
|
@ -0,0 +1,4 @@
|
||||||
|
Schematics
|
||||||
|
SCHEMATICS
|
||||||
|
<h2>Schematic Upload</h2>
|
||||||
|
<h5 class="alert alert-success mb-3 w-auto p-3" role="alert">${MESSAGE}</h5>
|
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/gh/Telesphoreo/bootstrap-color-switcher@master/script.js"></script>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@200;400&display=swap" rel="stylesheet">
|
||||||
|
<title>${TITLE} - Plex HTTPD</title>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: 'IBM Plex Sans', sans-serif;">
|
||||||
|
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="/" style="font-weight:200;">Plex HTTPD</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
|
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_HOME}" href="/">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_INDEFBANS}" href="/api/indefbans/">Indefinite Bans</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_LIST}" href="/api/list/">List</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link ${ACTIVE_PUNISHMENTS}" href="/api/punishments/">Punishments</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="nav-link ${ACTIVE_COMMANDS}" href="/api/commands/">Commands</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle ${ACTIVE_SCHEMATICS}" id="navbarDropdownMenuLink" role="button"
|
||||||
|
data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
Schematics
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
|
||||||
|
<li><a class="dropdown-item" href="/api/schematics/download/">Download</a></li>
|
||||||
|
<li><a class="dropdown-item" href="/api/schematics/upload/">Upload</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div style="text-align: center;" class="col-auto m-0 row justify-content-center p-4">
|
||||||
|
${CONTENT}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,4 +1,4 @@
|
||||||
name: Plex-HTTPD
|
name: Module-HTTPD
|
||||||
version: 1.0.1
|
version: 1.4-SNAPSHOT
|
||||||
description: HTTPD server for Plex
|
description: HTTPD server for Plex
|
||||||
main: dev.plex.HTTPDModule
|
main: dev.plex.HTTPDModule
|
|
@ -1,16 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<body>
|
|
||||||
<div style="text-align: center;">
|
|
||||||
<h2 style="font-family:Helvetica">Enter the UUID or username of the player you want to check</h2>
|
|
||||||
<input id="test" type="text" autofocus>
|
|
||||||
<button type="button" onclick="redirect()">Submit</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function redirect() {
|
|
||||||
var url = document.getElementById('test').value
|
|
||||||
window.location = "punishments/" + url
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,4 +0,0 @@
|
||||||
server:
|
|
||||||
bind-address: 0.0.0.0
|
|
||||||
port: 27192
|
|
||||||
logging: false
|
|
Loading…
Reference in New Issue