Compare commits

...

38 Commits

Author SHA1 Message Date
Taah 2e40ddc6bc begin oauth2 setup 2024-03-05 19:41:08 -08:00
Telesphoreo ff9cf12acc Add schematic validation to the HTTPD 2024-01-25 15:59:27 -06:00
Telesphoreo 94528860f2
Update CommandsEndpoint.java 2023-12-13 21:28:54 -06:00
Telesphoreo c83f8f1d8e
Merge pull request #12 from plexusorg/commands-route
Add commands route
2023-12-13 21:25:41 -06:00
Focusvity 31cd561b92
Add commands route 2023-12-10 15:35:30 +11:00
Telesphoreo f0582e03e6 Update dependencies 2023-11-26 00:03:16 -06:00
Telesphoreo 4e593e1b5e Update dependencies 2023-10-29 22:59:33 -05:00
Telesphoreo 026b29a98c make module name consistent 2023-09-05 18:14:43 -05:00
Telesphoreo 266a8d6384 Remove admin link 2023-09-05 17:49:50 -05:00
Telesphoreo 21ee54cf98
Update for latest version of Plex 2023-08-28 19:02:46 -05:00
Telesphoreo 492c6bd8eb
Release 1.3 2023-07-22 22:51:42 -05:00
Telesphoreo a7c76e6089 Update Gradle and dependencies 2023-04-29 15:10:24 -05:00
Telesphoreo 7a996004f0 HTTPD now supports dark mode 2023-04-03 15:39:22 -05:00
Telesphoreo 46ff09bf58 Update compatibility with Plex and Gradle 2023-03-08 13:21:31 -06:00
Telesphoreo 4426c4b4b7 Update dependencies and Gradle 2023-03-02 23:09:54 -06:00
Telesphoreo fc8811d453
Update Gradle 2022-11-27 22:18:55 -06:00
Telesphoreo 459f62e0d3
Update dependencies 2022-11-27 22:15:00 -06:00
Telesphoreo 4918cf55f3 Update Gradle + remove API 2022-08-02 20:24:27 -05:00
Telesphoreo e9395e193a
B R U H 2022-08-02 00:09:46 -05:00
Telesphoreo a257fb2f9c Update to 1.19 2022-06-13 23:00:38 -05:00
Telesphoreo fc9924754a Update for 1.2 2022-06-05 22:13:20 -05:00
Telesphoreo 867e3ff79b Closes #8 2022-05-30 20:55:28 -05:00
Telesphoreo 8bef589b7a
Merge pull request #7 from plexusorg/content-type
Set Content-Type header to application/json for JSON endpoints (closes #6)
2022-05-30 02:44:29 -05:00
Allink 5a0ae8746c
Set Content-Type header to application/json for JSON endpoints (closes #6) 2022-05-30 03:55:03 +01:00
Telesphoreo 41a2475e3d Update version 2022-05-28 22:04:07 -05:00
Telesphoreo 0bcbc7e79c Update repo 2022-05-21 21:05:38 -05:00
Telesphoreo 95043a33db
Create CONTRIBUTING.md 2022-05-17 14:58:30 -05:00
Telesphoreo 93619dd05e
Update Bootstrap 2022-05-16 23:21:50 -05:00
Taah 244d027e5d fix this condition 2022-05-10 22:34:39 -07:00
Telesphoreo ceea975729
Add GitHub workflow 2022-05-08 14:00:41 -05:00
Telesphoreo 32f17a23f3
Update dependencies 2022-05-08 13:59:50 -05:00
Telesphoreo 1148ff5da9
Update README.md 2022-05-05 22:33:52 -05:00
Telesphoreo a0ae4a9720
i hate this 2022-04-24 17:24:38 -05:00
Telesphoreo 82238fa3ed
switch to server/api 2022-04-24 16:21:36 -05:00
Telesphoreo 6e152417b7 This needs to be changed 2022-04-21 20:24:43 -05:00
Telesphoreo 22bb27af24 Make it look nicer if you decide to view the source for some reason
Yes I know this is useless
2022-04-21 19:28:12 -05:00
Telesphoreo 2b24f0ee4c Absolutely based 2022-04-21 18:24:15 -05:00
Telesphoreo 7769f34f74 Back to snapshot 2022-04-20 22:01:54 -05:00
33 changed files with 671 additions and 259 deletions

18
.github/workflows/gradle.yml vendored Normal file
View File

@ -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

View File

@ -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>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Plexus Code Style" />
</state>
</component>

24
CONTRIBUTING.md Normal file
View File

@ -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.

View File

@ -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

View File

@ -5,71 +5,75 @@ plugins {
}
group = "dev.plex"
version = "1.0.2"
version = "1.4-SNAPSHOT"
description = "Module-HTTPD"
repositories {
mavenCentral()
maven {
url = uri("https://papermc.io/repo/repository/maven-public/")
url = uri("https://repo.papermc.io/repository/maven-public/")
}
maven {
url = uri("https://nexus.telesphoreo.me/repository/plex/")
}
maven {
url = uri("https://nexus.telesphoreo.me/repository/totalfreedom/")
}
maven {
url = uri("https://jitpack.io")
content {
includeGroup("com.github.MilkBowl")
}
}
}
dependencies {
implementation("org.projectlombok:lombok:1.18.22")
annotationProcessor("org.projectlombok:lombok:1.18.22")
implementation("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
implementation("dev.plex:Plex:1.0.2-SNAPSHOT")
implementation("org.json:json:20220320")
implementation("org.projectlombok:lombok:1.18.30")
annotationProcessor("org.projectlombok:lombok:1.18.30")
implementation("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
implementation("dev.plex:server:1.4-SNAPSHOT")
implementation("org.json:json:20231013")
implementation("org.reflections:reflections:0.10.2")
implementation("org.eclipse.jetty:jetty-server:11.0.9")
implementation("org.eclipse.jetty:jetty-servlet:11.0.9")
implementation("org.eclipse.jetty:jetty-proxy:11.0.9")
implementation("com.github.MilkBowl:VaultAPI:1.7")
implementation("org.eclipse.jetty:jetty-server:11.0.19")
implementation("org.eclipse.jetty:jetty-servlet:11.0.19")
implementation("org.eclipse.jetty:jetty-proxy:11.0.19")
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 {
compileJava {
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
// 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)
options.encoding = Charsets.UTF_8.name()
}
javadoc {
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
options.encoding = Charsets.UTF_8.name()
}
processResources {
filteringCharset = Charsets.UTF_8.name() // We want UTF-8 for everything
filteringCharset = Charsets.UTF_8.name()
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}
tasks.getByName<Jar>("jar") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveBaseName.set("Plex-HTTPD")
archiveVersion.set("")
from("src/main/resources") {
exclude("dev/**")
}
}

Binary file not shown.

View File

@ -1,5 +1,7 @@
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-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

31
gradlew vendored
View File

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (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.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -80,13 +80,11 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# 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"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -133,22 +131,29 @@ location of your Java installation."
fi
else
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
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
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 ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | 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" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -193,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
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;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
@ -205,6 +214,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.

15
gradlew.bat vendored
View File

@ -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,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,7 +41,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 +76,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

View File

@ -1,5 +1,6 @@
package dev.plex;
import dev.plex.authentication.AuthenticationManager;
import dev.plex.cache.FileCache;
import dev.plex.config.ModuleConfig;
import dev.plex.module.PlexModule;
@ -7,25 +8,19 @@ import dev.plex.request.AbstractServlet;
import dev.plex.request.SchematicUploadServlet;
import dev.plex.request.impl.*;
import dev.plex.util.PlexLog;
import java.io.File;
import java.util.concurrent.atomic.AtomicReference;
import jakarta.servlet.MultipartConfigElement;
import lombok.Getter;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.eclipse.jetty.server.Connector;
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.server.*;
import org.eclipse.jetty.servlet.ServletContextHandler;
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 static ServletContextHandler context;
@ -41,6 +36,8 @@ public class HTTPDModule extends PlexModule
public static final String template = AbstractServlet.readFileReal(HTTPDModule.class.getResourceAsStream("/httpd/template.html"));
private AuthenticationManager authenticationManager;
@Override
public void load()
{
@ -53,10 +50,22 @@ public class HTTPDModule extends PlexModule
{
moduleConfig.load();
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!");
}
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(() ->
{
Server server = new Server();
@ -70,18 +79,21 @@ public class HTTPDModule extends PlexModule
connector.setHost(moduleConfig.getString("server.bind-address"));
connector.setPort(moduleConfig.getInt("server.port"));
new AdminsEndpoint();
new IndefBansEndpoint();
new IndexEndpoint();
new ListEndpoint();
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();
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});
@ -140,7 +152,7 @@ public class HTTPDModule extends PlexModule
}
}
private static boolean isFileSystemCaseSensitive = !new File( "a" ).equals( new File( "A" ) );
private static boolean isFileSystemCaseSensitive = !new File("a").equals(new File("A"));
public static boolean fileNameEquals(String filename1, String filename2)
{

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -0,0 +1,10 @@
package dev.plex.authentication;
/**
* @author Taah
* @since 6:37 PM [03-05-2024]
*/
public enum UserType
{
DISCORD, UNKNOWN
}

View File

@ -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);
}
}

View File

@ -98,6 +98,7 @@ public class AbstractServlet extends HttpServlet
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]);

View File

@ -1,26 +1,27 @@
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.Plex;
import dev.plex.cache.DataUtils;
import dev.plex.player.PlexPlayer;
import dev.plex.rank.enums.Rank;
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 java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.regex.Pattern;
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);
@ -39,24 +40,12 @@ public class SchematicUploadServlet extends HttpServlet
response.getWriter().println(schematicUploadBadHTML("Couldn't load your IP Address: " + request.getRemoteAddr() + ". Have you joined the server before?"));
return;
}
if (Plex.get().getSystem().equalsIgnoreCase("ranks"))
PlexLog.debug("Plex-HTTPD using permissions check");
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(plexPlayer.getUuid());
if (!HTTPDModule.getPermissions().playerHas(null, offlinePlayer, "plex.httpd.schematics.upload"))
{
PlexLog.debug("Plex-HTTPD using ranks check");
if (!plexPlayer.getRankFromString().isAtLeast(Rank.ADMIN))
{
response.getWriter().println(schematicUploadBadHTML("You must be an admin or above to upload schematics."));
return;
}
}
else if (Plex.get().getSystem().equalsIgnoreCase("permissions"))
{
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;
}
response.getWriter().println(schematicUploadBadHTML("You do not have permission to upload schematics."));
return;
}
File worldeditFolder = HTTPDModule.getWorldeditFolder();
if (worldeditFolder == null)
@ -88,9 +77,31 @@ public class SchematicUploadServlet extends HttpServlet
return;
}
InputStream inputStream = uploadPart.getInputStream();
Files.copy(inputStream, new File(worldeditFolder, filename).toPath(), StandardCopyOption.REPLACE_EXISTING);
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 + "."));
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)

View File

@ -1,69 +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.ZonedDateTimeSerializer;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletResponse;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
public class AdminsEndpoint extends AbstractServlet
{
private static final String TITLE = "Admins - Plex HTTPD";
@GetMapping(endpoint = "/api/admins/")
public String getAdmins(HttpServletRequest request, HttpServletResponse response)
{
String ipAddress = request.getRemoteAddr();
if (ipAddress == null)
{
return adminsHTML("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(ZonedDateTime.class, new ZonedDateTimeSerializer()).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(ZonedDateTime.class, new ZonedDateTimeSerializer()).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(ZonedDateTime.class, new ZonedDateTimeSerializer()).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(ZonedDateTime.class, new ZonedDateTimeSerializer()).setPrettyPrinting().create().toJson(Plex.get().getAdminList().getAllAdminPlayers());
}
private String adminsHTML(String message)
{
String file = readFile(this.getClass().getResourceAsStream("/httpd/admins.html"));
file = file.replace("${MESSAGE}", message);
return file;
}
}

View File

@ -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 "";
}
}

View File

@ -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("<", "&lt;").replaceAll(">", "&gt;");
if (usage.isBlank())
{
usage = "Not Provided";
}
return usage.startsWith("/") || usage.equals("Not Provided") ? usage : "/" + usage;
}
}

View File

@ -5,7 +5,6 @@ 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;
@ -31,23 +30,14 @@ public class IndefBansEndpoint extends AbstractServlet
{
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");
if (!player.getRankFromString().isAtLeast(Rank.ADMIN))
{
return indefbansHTML("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 indefbansHTML("Not enough permissions to view this page.");
}
return indefbansHTML("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());
}

View File

@ -3,6 +3,7 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import dev.plex.request.MappingHeaders;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
@ -14,6 +15,7 @@ import org.bukkit.entity.Player;
public class ListEndpoint extends AbstractServlet
{
@GetMapping(endpoint = "/api/list/")
@MappingHeaders(headers = "content-type;application/json")
public String getOnlinePlayers(HttpServletRequest request, HttpServletResponse response)
{
List<String> players = new ArrayList<>();

View File

@ -2,20 +2,15 @@ package dev.plex.request.impl;
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.ZonedDateTimeSerializer;
import dev.plex.util.adapter.ZonedDateTimeAdapter;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import jakarta.servlet.http.HttpServletResponse;
import java.time.ZonedDateTime;
import java.util.UUID;
import jakarta.servlet.http.HttpServletResponse;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@ -59,28 +54,17 @@ public class PunishmentsEndpoint extends AbstractServlet
if (player == null)
{
// If the player is null, give it to them without the IPs
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer()).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 (!player.getRankFromString().isAtLeast(Rank.ADMIN))
{
// Don't return IPs either if the person is not an Admin or above.
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
}
// If the person doesn't have permission, don't return IPs
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).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.punishments.access"))
{
// If the person doesn't have permission, don't return IPs
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
}
}
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().toList());
response.setHeader("content-type", "application/json");
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().toList());
}
private String punishmentsHTML(String message)

View File

@ -3,15 +3,21 @@ 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)
{
@ -72,20 +78,35 @@ public class SchematicDownloadEndpoint extends AbstractServlet
return null;
}
StringBuilder sb = new StringBuilder();
File[] alphabetical = worldeditFolder.listFiles();
if (alphabetical != null)
for (File worldeditFile : listFilesForFolder(worldeditFolder))
{
Arrays.sort(alphabetical);
for (File worldeditFile : alphabetical)
{
String sanitizedName = worldeditFile.getName().replaceAll("<","&lt;").replaceAll(">","&gt;");
sb.append("<tr>" +
"<th scope=\"row\"><a href=\"" + worldeditFile.getName() + "\" download>" + sanitizedName + "</a></th>" +
"<td>" + formattedSize(worldeditFile.length()) + "</td>" +
"</tr>");
}
file = file.replace("${schematics}", sb.toString());
String fixedPath = worldeditFile.getPath().replace("plugins/FastAsyncWorldEdit/schematics/", "");
fixedPath = fixedPath.replace("plugins/WorldEdit/schematics/", "");
String sanitizedName = fixedPath.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
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;
}
}

View File

@ -1,10 +1,8 @@
package dev.plex.request.impl;
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;
@ -28,22 +26,11 @@ public class SchematicUploadEndpoint extends AbstractServlet
{
return schematicsHTML("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.schematics.upload"))
{
PlexLog.debug("Plex-HTTPD using ranks check");
if (!player.getRankFromString().isAtLeast(Rank.ADMIN))
{
return schematicsHTML("You must be an admin or above to upload schematics.");
}
}
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.schematics.upload"))
{
return schematicsHTML("You do not have permission to upload schematics.");
}
return schematicsHTML("You do not have permission to upload schematics.");
}
return readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload.html"));
}

View File

@ -2,18 +2,21 @@
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
<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>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<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="/">Plex HTTPD</a>
<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>
@ -23,9 +26,6 @@
<li class="nav-item">
<a class="nav-link ${ACTIVE_HOME}" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link ${ACTIVE_ADMINS}" href="/api/admins/">Admins</a>
</li>
<li class="nav-item">
<a class="nav-link ${ACTIVE_INDEFBANS}" href="/api/indefbans/">Indefinite Bans</a>
</li>

View File

@ -1,4 +0,0 @@
Admins
ADMINS
<h2>Admins</h2>
<h5 class="alert alert-danger mb-3 w-auto p-3" role="alert"><b>Error:</b> ${MESSAGE}</h5>

View File

@ -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}

View File

@ -1,4 +1,15 @@
server:
bind-address: 0.0.0.0
port: 27192
logging: false
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

View File

@ -15,7 +15,7 @@ SCHEMATICS
</tr>
</thead>
<tbody>
${schematics}
${schematics}
</tbody>
</table>
<script>

View File

@ -2,18 +2,21 @@
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
<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>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<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="/">Plex HTTPD</a>
<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>
@ -23,9 +26,6 @@
<li class="nav-item">
<a class="nav-link ${ACTIVE_HOME}" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link ${ACTIVE_ADMINS}" href="/api/admins/">Admins</a>
</li>
<li class="nav-item">
<a class="nav-link ${ACTIVE_INDEFBANS}" href="/api/indefbans/">Indefinite Bans</a>
</li>
@ -35,6 +35,9 @@
<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">

View File

@ -1,4 +1,4 @@
name: Plex-HTTPD
version: 1.0.2
name: Module-HTTPD
version: 1.4-SNAPSHOT
description: HTTPD server for Plex
main: dev.plex.HTTPDModule