Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cb4a1dc54
|
||
|
|
9ea469dbd7
|
||
|
|
011bc26a1a | ||
|
|
c697099eeb | ||
|
|
4a90995589 | ||
|
|
6a98e18a38 | ||
|
|
fd859d839d | ||
|
|
6085ffbcd3 | ||
|
|
53bb8c938b | ||
|
|
b771bcb095 | ||
|
|
fdb1b65159 | ||
|
|
bf0de0a879 | ||
|
|
6bdb2edb66 | ||
|
|
4a89704de6 | ||
|
|
999c9cd849 | ||
|
|
f41f0e6fef | ||
|
|
a3a73d9466 | ||
|
|
ed1e368aae | ||
|
|
4df84efdcd | ||
|
|
95fc2368a5 | ||
|
|
9d69da2dab | ||
|
|
65007e248e | ||
|
|
f1f564d67a | ||
|
|
f80de12ae2 | ||
|
|
acb19a520a | ||
|
|
9c27071213 | ||
|
|
0f6020818d | ||
|
|
fcf6c93404 | ||
|
|
3d0f255ab4 | ||
|
|
ede5cae333 | ||
|
|
b8f9cb937a | ||
|
|
1fae11c0ff | ||
|
|
41eb6327e6 | ||
|
|
c723fc7eac | ||
|
|
7812823367 | ||
|
|
2d5c2c78d2 | ||
|
|
6e64890c04 | ||
|
|
d269e9da6b |
No files matched your search
@@ -0,0 +1 @@
|
||||
.gitea/CODEOWNERS linguist-detectable=false
|
||||
@@ -0,0 +1,3 @@
|
||||
# Pull requests request review from the eligible staff team(s).
|
||||
# One approval from either an Admin or Developer satisfies branch protection.
|
||||
* @trueog/Admins @trueog/Developers
|
||||
@@ -1 +0,0 @@
|
||||
custom: https://www.paypal.me/ibj
|
||||
@@ -1,73 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for submitting an issue for NuVotifier. We appreciate
|
||||
any and all bug reports.
|
||||
|
||||
Before you continue, please ensure you are reporting
|
||||
a real bug and are not suffering from a configuration issue
|
||||
or a plugin problem. Once NuVotifier has received and
|
||||
called your vote listeners, it's not our issue any more.
|
||||
|
||||
If you are having difficulty setting up NuVotifier to receive
|
||||
votes, you are in the wrong place. Please view our wiki
|
||||
at https://github.com/NuVotifier/NuVotifier/wiki for a
|
||||
comprehensive set of instructions for configuring and
|
||||
diagnosing common problems with NuVotifier.
|
||||
|
||||
If you are certain that there is a problem with
|
||||
NuVotifier, please continue filling the form below.
|
||||
Make sure to follow these instructions:
|
||||
|
||||
1. Tell the exact NuVotifier version you're using.
|
||||
If you just say "latest" your issue will get closed.
|
||||
2. Please include all relevant logs and configuration
|
||||
files. Make sure to redact any tokens in the config
|
||||
file.
|
||||
3. Don't write anything between these arrows.
|
||||
We won't see it otherwise.
|
||||
4. Before you create your issue, delete this block of
|
||||
text and the code block at the very bottom. -->
|
||||
|
||||
### Information
|
||||
|
||||
**Platform on which you run NuVotifier**: <!-- Either Bukkit, Sponge, BungeeCord, or Velocity. -->
|
||||
|
||||
**Version of NuVotifier**:
|
||||
|
||||
```
|
||||
<!--
|
||||
Getting this depends on your platform:
|
||||
|
||||
Bukkit: Use /version Votifier
|
||||
|
||||
Sponge: Use /sponge plugins and find NuVotifier
|
||||
|
||||
BungeeCord: No such command exists.
|
||||
|
||||
Velocity: Use /velocity plugins from in-game and hover over "nuvotifier"
|
||||
-->
|
||||
```
|
||||
|
||||
**Relevant log**: <!-- Paste the log on https://gist.github.com/, replace this with link -->
|
||||
### Details
|
||||
|
||||
**Description**
|
||||
<!-- Replace this with a brief summary of the bug. -->
|
||||
|
||||
**Steps to reproduce**
|
||||
<!-- Replace this with exactly what you did to cause the bug. -->
|
||||
|
||||
**Expected behavior**
|
||||
<!-- Replace this with what you expected to happen. -->
|
||||
|
||||
```
|
||||
Please make sure to delete this line of text and the three ``` characters surrounding it, or your issue will be closed.
|
||||
```
|
||||
+17
@@ -7,6 +7,20 @@
|
||||
# netbeans
|
||||
/nbproject
|
||||
|
||||
# eclipse
|
||||
api/.classpath
|
||||
api/.project
|
||||
api/.settings/
|
||||
bukkit/.classpath
|
||||
bukkit/.project
|
||||
bukkit/.settings/
|
||||
common/.classpath
|
||||
common/.project
|
||||
common/.settings/
|
||||
universal/.classpath
|
||||
universal/.project
|
||||
universal/.settings/
|
||||
|
||||
# we use maven!
|
||||
/build.xml
|
||||
|
||||
@@ -47,3 +61,6 @@ debug.txt
|
||||
# gradle stuff
|
||||
.gradle/
|
||||
.gradletasknamecache
|
||||
|
||||
# fabric
|
||||
fabric/run/
|
||||
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
pipeline {
|
||||
agent {
|
||||
docker { image 'openjdk:12-jdk' }
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './gradlew build --no-daemon'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './gradlew test --no-daemon'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Publish') {
|
||||
when {
|
||||
branch "master"
|
||||
}
|
||||
environment {
|
||||
SNAPSHOT_REPO = credentials('ibj-nexus-snapshot-repo')
|
||||
RELEASE_REPO = credentials('ibj-nexus-release-repo')
|
||||
RAW_UPLOAD_PATH = credentials('ibj-nexus-raw-path')
|
||||
REPO = credentials('ibj-nexus-access')
|
||||
PUBLISH = 'true'
|
||||
LATEST_BUILD = 'true'
|
||||
}
|
||||
steps {
|
||||
sh './gradlew publishVersionedPublicationToIbjRepository'
|
||||
sh './gradlew publishLatestToIbjBlockRaw'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,10 @@
|
||||
# NuVotifier
|
||||
# Votifier-OG
|
||||
|
||||
NuVotifier is a secure alternative to using the original Votifier project.
|
||||
NuVotifier will work in place of Votifier - any vote listener that supports
|
||||
Votifier will also support NuVotifier.
|
||||
Votifier-OG is a 1.19.4 fork of NuVotifier, which is a secure alternative to using the original Votifier project.
|
||||
Votifier-OG will work in place of NuVotifier, and will work in place of Votifier - any vote listener that supports
|
||||
Votifier will also support NuVotifier and Votifier-OG.
|
||||
|
||||
NuVotifier supports many different platforms using the same universal JAR:
|
||||
|
||||
+ Bukkit / Spigot / Paper >=1.7.10
|
||||
+ Sponge 7
|
||||
+ BungeeCord / Waterfall
|
||||
+ Velocity
|
||||
|
||||
NuVotifier also adds forwarding and listener test commands not present in the
|
||||
original version.
|
||||
|
||||
[Setup Guide](https://github.com/NuVotifier/NuVotifier/wiki/Setup-Guide)
|
||||
|
||||
[Troubleshooting Guide](https://github.com/NuVotifier/NuVotifier/wiki/Troubleshooting-Guide)
|
||||
|
||||
[Developer Information](https://github.com/NuVotifier/NuVotifier/wiki/Developer-Documentation)
|
||||
Votifier-OG supports Purpur 1.19.4. It is maintained by [TrueOG Network](https://trueog.net/)
|
||||
|
||||
# License
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
dependencies {
|
||||
implementation 'com.google.code.gson:gson:2.8.0'
|
||||
}
|
||||
@@ -20,7 +20,6 @@ package com.vexsoftware.votifier.model;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
@@ -54,8 +53,7 @@ public class Vote {
|
||||
private byte[] additionalData;
|
||||
|
||||
@Deprecated
|
||||
public Vote() {
|
||||
}
|
||||
public Vote() {}
|
||||
|
||||
public Vote(String serviceName, String username, String address, String timeStamp) {
|
||||
this.serviceName = serviceName;
|
||||
@@ -74,8 +72,14 @@ public class Vote {
|
||||
}
|
||||
|
||||
public Vote(Vote vote) {
|
||||
this(vote.getServiceName(), vote.getUsername(), vote.getAddress(), vote.getTimeStamp(),
|
||||
vote.getAdditionalData() == null ? null : vote.getAdditionalData().clone());
|
||||
this(
|
||||
vote.getServiceName(),
|
||||
vote.getUsername(),
|
||||
vote.getAddress(),
|
||||
vote.getTimeStamp(),
|
||||
vote.getAdditionalData() == null
|
||||
? null
|
||||
: vote.getAdditionalData().clone());
|
||||
}
|
||||
|
||||
private static String getTimestamp(JsonElement object) {
|
||||
@@ -87,21 +91,21 @@ public class Vote {
|
||||
}
|
||||
|
||||
public Vote(JsonObject jsonObject) {
|
||||
this(jsonObject.get("serviceName").getAsString(),
|
||||
this(
|
||||
jsonObject.get("serviceName").getAsString(),
|
||||
jsonObject.get("username").getAsString(),
|
||||
jsonObject.get("address").getAsString(),
|
||||
getTimestamp(jsonObject.get("timestamp")));
|
||||
if (jsonObject.has("additionalData"))
|
||||
additionalData = Base64.getDecoder().decode(jsonObject.get("additionalData").getAsString());
|
||||
additionalData =
|
||||
Base64.getDecoder().decode(jsonObject.get("additionalData").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String data;
|
||||
if (additionalData == null)
|
||||
data = "null";
|
||||
else
|
||||
data = Base64.getEncoder().encodeToString(additionalData);
|
||||
if (additionalData == null) data = "null";
|
||||
else data = Base64.getEncoder().encodeToString(additionalData);
|
||||
|
||||
return "Vote (from:" + serviceName + " username:" + username
|
||||
+ " address:" + address + " timeStamp:" + timeStamp
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.vexsoftware.votifier.model;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VoteTest {
|
||||
@Test
|
||||
public void testVoteConstructFromJsonObject() {
|
||||
|
||||
String serviceName = "serviceNameA";
|
||||
String username = "usernameA";
|
||||
String address = "home";
|
||||
String timestamp = "1234";
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
o.addProperty("serviceName", serviceName);
|
||||
o.addProperty("username", username);
|
||||
o.addProperty("address", address);
|
||||
o.addProperty("timestamp", timestamp);
|
||||
|
||||
Vote v = new Vote(o);
|
||||
|
||||
assertEquals(serviceName, v.getServiceName());
|
||||
assertEquals(username, v.getUsername());
|
||||
assertEquals(address, v.getAddress());
|
||||
assertEquals(timestamp, v.getTimeStamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteConstructFromJsonObjectLongTS() {
|
||||
|
||||
String serviceName = "serviceNameA";
|
||||
String username = "usernameA";
|
||||
String address = "home";
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
o.addProperty("serviceName", serviceName);
|
||||
o.addProperty("username", username);
|
||||
o.addProperty("address", address);
|
||||
o.addProperty("timestamp", 1234);
|
||||
|
||||
Vote v = new Vote(o);
|
||||
|
||||
assertEquals(serviceName, v.getServiceName());
|
||||
assertEquals(username, v.getUsername());
|
||||
assertEquals(address, v.getAddress());
|
||||
assertEquals("1234", v.getTimeStamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteSerialize() {
|
||||
Vote v = new Vote("service", "username", "address", "1234");
|
||||
JsonObject o = v.serialize();
|
||||
|
||||
assertEquals(4, o.size());
|
||||
assertEquals("service", o.get("serviceName").getAsString());
|
||||
assertEquals("username", o.get("username").getAsString());
|
||||
assertEquals("address", o.get("address").getAsString());
|
||||
assertEquals("1234", o.get("timestamp").getAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteEquals() {
|
||||
Vote v1 = new Vote("service", "username", "address", "1234");
|
||||
assertEquals(v1, v1);
|
||||
assertEquals(v1.hashCode(), new Vote("service", "username", "address", "1234").hashCode());
|
||||
assertEquals(v1, new Vote("service", "username", "address", "1234"));
|
||||
assertNotEquals(v1, new Object());
|
||||
assertNotEquals(v1, null);
|
||||
assertNotEquals(v1, new Vote("service2", "username", "address", "1234"));
|
||||
assertNotEquals(v1, new Vote("service", "username1", "address", "1234"));
|
||||
assertNotEquals(v1, new Vote("service", "username", "address1", "1234"));
|
||||
assertNotEquals(v1, new Vote("service", "username", "address", "12345"));
|
||||
}
|
||||
}
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Fetch all submodule content.
|
||||
git submodule update --force --recursive --init
|
||||
@@ -1,60 +0,0 @@
|
||||
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id "com.github.spotbugs" version "4.7.1" apply false
|
||||
id "net.kyori.blossom" version "1.3.0" apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group 'com.vexsoftware'
|
||||
version '2.7.3'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: "com.github.spotbugs"
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://hub.spigotmc.org/nexus/content/repositories/snapshots"
|
||||
}
|
||||
maven {
|
||||
url "https://oss.sonatype.org/content/repositories/snapshots"
|
||||
}
|
||||
maven {
|
||||
url "https://repo.spongepowered.org/maven"
|
||||
}
|
||||
maven {
|
||||
url "https://repo.velocitypowered.com/snapshots/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.2"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params:5.4.2"
|
||||
testImplementation "org.mockito:mockito-core:2.+"
|
||||
}
|
||||
|
||||
processResources {
|
||||
filter(ReplaceTokens, tokens: ["app.version": this.project.version])
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
|
||||
reports {
|
||||
html {
|
||||
enabled = true
|
||||
destination = file("$buildDir/reports/spotbugs/main/spotbugs.html")
|
||||
stylesheet = 'fancy-hist.xsl'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
import org.gradle.kotlin.dsl.provideDelegate
|
||||
|
||||
/* ------------------------------ Plugins ------------------------------ */
|
||||
plugins {
|
||||
id("java") // Import Java plugin.
|
||||
id("java-library") // Import Java Library plugin.
|
||||
id("com.diffplug.spotless") version "8.1.0" // Import Spotless plugin.
|
||||
id("com.gradleup.shadow") version "8.3.9" // Import Shadow plugin.
|
||||
id("checkstyle") // Import Checkstyle plugin.
|
||||
eclipse // Import Eclipse plugin.
|
||||
kotlin("jvm") version "2.1.21" // Import Kotlin JVM plugin.
|
||||
}
|
||||
|
||||
extra["kotlinAttribute"] = Attribute.of("kotlin-tag", Boolean::class.javaObjectType)
|
||||
|
||||
val kotlinAttribute: Attribute<Boolean> by rootProject.extra
|
||||
|
||||
/* --------------------------- JDK / Kotlin ---------------------------- */
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17 // Compile with JDK 17 compatibility.
|
||||
toolchain { // Select Java toolchain.
|
||||
languageVersion.set(JavaLanguageVersion.of(17)) // Use JDK 17.
|
||||
vendor.set(JvmVendorSpec.GRAAL_VM) // Use GraalVM CE.
|
||||
}
|
||||
}
|
||||
|
||||
kotlin { jvmToolchain(17) }
|
||||
|
||||
/* ----------------------------- Metadata ------------------------------ */
|
||||
group = "net.trueog.votifier-og" // Declare bundle identifier.
|
||||
|
||||
version = "1.0.2" // Declare plugin version (will be in .jar).
|
||||
|
||||
val apiVersion = "1.19" // Declare minecraft server target version.
|
||||
|
||||
/* ----------------------------- Resources ----------------------------- */
|
||||
tasks.named<ProcessResources>("processResources") {
|
||||
val props = mapOf("version" to version, "apiVersion" to apiVersion)
|
||||
inputs.properties(props) // Indicates to rerun if version changes.
|
||||
filesMatching("plugin.yml") { expand(props) }
|
||||
from("LICENSE") { into("/") } // Bundle licenses into jarfiles.
|
||||
}
|
||||
|
||||
/* ---------------------------- Repos ---------------------------------- */
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral() // Import the Maven Central Maven Repository.
|
||||
gradlePluginPortal() // Import the Gradle Plugin Portal Maven Repository.
|
||||
maven { url = uri("https://repo.purpurmc.org/snapshots") } // Import the PurpurMC Maven Repository.
|
||||
maven { url = uri("file://${System.getProperty("user.home")}/.m2/repository") }
|
||||
System.getProperty("SELF_MAVEN_LOCAL_REPO")?.let { // TrueOG Bootstrap mavenLocal().
|
||||
val dir = file(it)
|
||||
if (dir.isDirectory) {
|
||||
println("Using SELF_MAVEN_LOCAL_REPO at: $it")
|
||||
maven { url = uri("file://${dir.absolutePath}") }
|
||||
} else {
|
||||
logger.error("TrueOG Bootstrap not found, defaulting to ~/.m2 for mavenLocal()")
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
?: run {
|
||||
logger.error("TrueOG Bootstrap not found, defaulting to ~/.m2 for mavenLocal()")
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------- Java project deps ---------------------------- */
|
||||
configurations.create("shadeOnly")
|
||||
|
||||
dependencies { implementation(project(":nuvotifier-bukkit")) }
|
||||
|
||||
apply(from = "eclipse.gradle.kts") // Import eclipse classpath support script.
|
||||
|
||||
/* ---------------------- Reproducible jars ---------------------------- */
|
||||
allprojects {
|
||||
tasks.withType<AbstractArchiveTask>().configureEach { // Ensure reproducible .jars
|
||||
isPreserveFileTimestamps = false
|
||||
isReproducibleFileOrder = true
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------- Shadow -------------------------------- */
|
||||
tasks.shadowJar {
|
||||
exclude("io.github.miniplaceholders.*") // Exclude the MiniPlaceholders package from being shadowed.
|
||||
isEnableRelocation = true
|
||||
relocationPrefix = "${project.group}.shadow"
|
||||
archiveClassifier.set("") // Use empty string instead of null.
|
||||
}
|
||||
|
||||
tasks.jar { archiveClassifier.set("part") } // Applies to root jarfile only.
|
||||
|
||||
val copyBukkitJarToRoot by tasks.registering(Copy::class)
|
||||
|
||||
project(":nuvotifier-bukkit").pluginManager.withPlugin("com.gradleup.shadow") {
|
||||
val bukkitShadowJarProvider = project(":nuvotifier-bukkit").tasks.named<Jar>("shadowJar")
|
||||
copyBukkitJarToRoot.configure {
|
||||
dependsOn(bukkitShadowJarProvider)
|
||||
from(bukkitShadowJarProvider.flatMap { it.archiveFile })
|
||||
into(layout.buildDirectory.dir("libs"))
|
||||
rename { "Votifier-OG-${project.version}.jar" }
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.spotlessApply, tasks.shadowJar, copyBukkitJarToRoot)
|
||||
} // Build depends on spotless and shadow.
|
||||
|
||||
tasks.shadowJar { finalizedBy(copyBukkitJarToRoot) }
|
||||
|
||||
/* --------------------------- Javac opts ------------------------------- */
|
||||
allprojects {
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.compilerArgs.add("-parameters") // Enable reflection for java code.
|
||||
options.isFork = true // Run javac in its own process.
|
||||
options.compilerArgs.add("-Xlint:deprecation") // Trigger deprecation warning messages.
|
||||
options.encoding = "UTF-8" // Use UTF-8 file encoding.
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------- Auto Formatting ------------------------ */
|
||||
spotless {
|
||||
java {
|
||||
eclipse().configFile("config/formatter/eclipse-java-formatter.xml") // Eclipse java formatting.
|
||||
leadingTabsToSpaces() // Convert leftover leading tabs to spaces.
|
||||
removeUnusedImports() // Remove imports that aren't being called.
|
||||
}
|
||||
kotlinGradle {
|
||||
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } // JetBrains Kotlin formatting.
|
||||
target("build.gradle.kts", "settings.gradle.kts") // Gradle files to format.
|
||||
}
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "10.18.1" // Declare checkstyle version to use.
|
||||
configFile = file("config/checkstyle/checkstyle.xml") // Point checkstyle to config file.
|
||||
isIgnoreFailures = true // Don't fail the build if checkstyle does not pass.
|
||||
isShowViolations = true // Show the violations in any IDE with the checkstyle plugin.
|
||||
}
|
||||
|
||||
tasks.named("compileJava") {
|
||||
dependsOn("spotlessApply") // Run spotless before compiling with the JDK.
|
||||
}
|
||||
|
||||
tasks.named("spotlessCheck") {
|
||||
dependsOn("spotlessApply") // Run spotless before checking if spotless ran.
|
||||
}
|
||||
|
||||
/* ------------------------------ Eclipse SHIM ------------------------- */
|
||||
|
||||
// This can't be put in eclipse.gradle.kts because Gradle is weird.
|
||||
subprojects {
|
||||
apply(plugin = "java-library")
|
||||
apply(plugin = "eclipse")
|
||||
eclipse.project.name = "${project.name}-${rootProject.name}"
|
||||
tasks.withType<Jar>().configureEach { archiveBaseName.set("${project.name}-${rootProject.name}") }
|
||||
}
|
||||
|
||||
/* ----------------------- Subproject configuration -------------------- */
|
||||
|
||||
subprojects {
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
vendor.set(JvmVendorSpec.GRAAL_VM)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project(":nuvotifier-api") {
|
||||
dependencies {
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
}
|
||||
tasks.test { useJUnit() }
|
||||
}
|
||||
|
||||
project(":nuvotifier-common") {
|
||||
dependencies {
|
||||
api(project(":nuvotifier-api"))
|
||||
implementation(platform("io.netty:netty-bom:4.1.110.Final"))
|
||||
implementation("io.netty:netty-handler")
|
||||
implementation("io.netty:netty-transport-native-epoll:4.1.110.Final:linux-x86_64")
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
}
|
||||
}
|
||||
|
||||
project(":nuvotifier-bukkit") {
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT")
|
||||
implementation(project(":nuvotifier-api"))
|
||||
implementation(project(":nuvotifier-common"))
|
||||
}
|
||||
|
||||
tasks.named<ProcessResources>("processResources") {
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
val props =
|
||||
mapOf(
|
||||
"version" to rootProject.version,
|
||||
"apiVersion" to apiVersion,
|
||||
"internalVersion" to rootProject.version,
|
||||
)
|
||||
inputs.properties(props)
|
||||
filesMatching("plugin.yml") { expand(props) }
|
||||
from(rootProject.file("LICENSE")) { into("/") }
|
||||
}
|
||||
|
||||
tasks.named<Jar>("jar") { manifest { attributes("Implementation-Version" to project.version) } }
|
||||
|
||||
tasks.named<Jar>("shadowJar") {
|
||||
archiveBaseName.set("Votifier-OG")
|
||||
archiveVersion.set(rootProject.version.toString())
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.publish.PublishingExtension
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention
|
||||
import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask
|
||||
|
||||
private const val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl"
|
||||
private const val ARTIFACTORY_USER = "artifactory_user"
|
||||
private const val ARTIFACTORY_PASSWORD = "artifactory_password"
|
||||
|
||||
fun Project.applyRootArtifactoryConfig() {
|
||||
if (!project.hasProperty(ARTIFACTORY_CONTEXT_URL)) ext[ARTIFACTORY_CONTEXT_URL] = "http://localhost"
|
||||
if (!project.hasProperty(ARTIFACTORY_USER)) ext[ARTIFACTORY_USER] = "guest"
|
||||
if (!project.hasProperty(ARTIFACTORY_PASSWORD)) ext[ARTIFACTORY_PASSWORD] = ""
|
||||
|
||||
apply(plugin = "com.jfrog.artifactory")
|
||||
configure<ArtifactoryPluginConvention> {
|
||||
setContextUrl("${project.property(ARTIFACTORY_CONTEXT_URL)}")
|
||||
clientConfig.publisher.run {
|
||||
repoKey = when {
|
||||
"${project.version}".contains("SNAPSHOT") -> "private"
|
||||
else -> "public"
|
||||
}
|
||||
username = "${project.property(ARTIFACTORY_USER)}"
|
||||
password = "${project.property(ARTIFACTORY_PASSWORD)}"
|
||||
isMaven = true
|
||||
isIvy = false
|
||||
}
|
||||
}
|
||||
tasks.named<ArtifactoryTask>("artifactoryPublish") {
|
||||
isSkip = true
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.applyCommonArtifactoryConfig() {
|
||||
configure<PublishingExtension> {
|
||||
publications {
|
||||
register<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
versionMapping {
|
||||
usage("java-api") {
|
||||
fromResolutionOf("runtimeClasspath")
|
||||
}
|
||||
usage("java-runtime") {
|
||||
fromResolutionResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<ArtifactoryTask>("artifactoryPublish") {
|
||||
publications("maven")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.repositories
|
||||
import org.gradle.kotlin.dsl.the
|
||||
|
||||
fun Project.applyCommonConfiguration() {
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
|
||||
maven {
|
||||
name = "Fabric"
|
||||
url = uri("https://maven.fabricmc.net/")
|
||||
}
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
cacheChangingModulesFor(5, "MINUTES")
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withId("java") {
|
||||
the<JavaPluginExtension>().toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.external.javadoc.StandardJavadocDocletOptions
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
|
||||
fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, javaRelease: Int = 8, banSlf4j: Boolean = true) {
|
||||
applyCommonConfiguration()
|
||||
apply(plugin = "eclipse")
|
||||
apply(plugin = "idea")
|
||||
|
||||
tasks
|
||||
.withType<JavaCompile>()
|
||||
.matching { it.name == "compileJava" || it.name == "compileTestJava" }
|
||||
.configureEach {
|
||||
val disabledLint = listOf(
|
||||
"processing", "path", "fallthrough", "serial"
|
||||
)
|
||||
options.release.set(javaRelease)
|
||||
options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" })
|
||||
options.isDeprecation = true
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add("-parameters")
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"compileOnly"("com.google.code.findbugs:jsr305:${Versions.FINDBUGS}")
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}")
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-params:${Versions.JUNIT}")
|
||||
"testImplementation"("org.mockito:mockito-core:${Versions.MOCKITO}")
|
||||
"testImplementation"("org.mockito:mockito-junit-jupiter:${Versions.MOCKITO}")
|
||||
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT}")
|
||||
}
|
||||
|
||||
// Java 8 turns on doclint which we fail
|
||||
tasks.withType<Javadoc>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
(options as StandardJavadocDocletOptions).apply {
|
||||
addStringOption("Xdoclint:none", "-quiet")
|
||||
tags(
|
||||
"apiNote:a:API Note:",
|
||||
"implSpec:a:Implementation Requirements:",
|
||||
"implNote:a:Implementation Note:"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
configure<JavaPluginExtension> {
|
||||
disableAutoTargetJvm()
|
||||
withJavadocJar()
|
||||
if (sourcesJar) {
|
||||
withSourcesJar()
|
||||
}
|
||||
}
|
||||
|
||||
if (banSlf4j) {
|
||||
configurations["compileClasspath"].apply {
|
||||
resolutionStrategy.componentSelection {
|
||||
withModule("org.slf4j:slf4j-api") {
|
||||
reject("No SLF4J allowed on compile classpath")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.SourceSetContainer
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import org.gradle.kotlin.dsl.the
|
||||
|
||||
val Project.ext: ExtraPropertiesExtension
|
||||
get() = extensions.getByType()
|
||||
|
||||
val Project.sourceSets: SourceSetContainer
|
||||
get() = the<JavaPluginExtension>().sourceSets
|
||||
@@ -0,0 +1,42 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.component.AdhocComponentWithVariants
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.named
|
||||
|
||||
fun Project.applyPlatformAndCoreConfiguration(javaRelease: Int = 8) {
|
||||
applyCommonConfiguration()
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "maven-publish")
|
||||
apply(plugin = "com.jfrog.artifactory")
|
||||
applyCommonJavaConfiguration(
|
||||
sourcesJar = true,
|
||||
javaRelease = javaRelease,
|
||||
banSlf4j = false
|
||||
)
|
||||
|
||||
ext["internalVersion"] = "$version+${rootProject.ext["gitCommitHash"]}"
|
||||
}
|
||||
|
||||
fun Project.applyShadowConfiguration() {
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
archiveClassifier.set("dist")
|
||||
dependencies {
|
||||
include(project(":nuvotifier-api"))
|
||||
include(project(":nuvotifier-common"))
|
||||
|
||||
exclude("com.google.code.findbugs:jsr305")
|
||||
}
|
||||
exclude("GradleStart**")
|
||||
exclude(".cache")
|
||||
exclude("LICENSE*")
|
||||
exclude("META-INF/maven/**")
|
||||
}
|
||||
val javaComponent = components["java"] as AdhocComponentWithVariants
|
||||
// I don't think we want this published (it's the shadow jar)
|
||||
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
object Versions {
|
||||
const val JUNIT = "5.8.1"
|
||||
const val MOCKITO = "4.3.1"
|
||||
const val FINDBUGS = "3.0.2"
|
||||
const val NETTYIO = "4.1.72.Final"
|
||||
const val GSON = "2.9.0"
|
||||
const val VELOCITY = "3.1.0"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/bin/
|
||||
@@ -1,6 +0,0 @@
|
||||
dependencies {
|
||||
compileOnly group: "org.spigotmc", name: "spigot-api", version: "1.8.8-R0.1-SNAPSHOT"
|
||||
implementation project(":nuvotifier-api")
|
||||
implementation project(":nuvotifier-common")
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ package com.vexsoftware.votifier;
|
||||
|
||||
import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
class BukkitScheduler implements VotifierScheduler {
|
||||
private final NuVotifierBukkit plugin;
|
||||
@@ -17,29 +16,17 @@ class BukkitScheduler implements VotifierScheduler {
|
||||
return (int) (unit.toMillis(time) / 50);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask sync(Runnable runnable) {
|
||||
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTask(plugin, runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask onPool(Runnable runnable) {
|
||||
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskAsynchronously(plugin, runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask delayedSync(Runnable runnable, int delay, TimeUnit unit) {
|
||||
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskLater(plugin, runnable, toTicks(delay, unit)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit) {
|
||||
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, runnable, toTicks(delay, unit)));
|
||||
return new BukkitTaskWrapper(
|
||||
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, runnable, toTicks(delay, unit)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask repeatOnPool(Runnable runnable, int delay, int repeat, TimeUnit unit) {
|
||||
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, toTicks(delay, unit), toTicks(repeat, unit)));
|
||||
return new BukkitTaskWrapper(plugin.getServer()
|
||||
.getScheduler()
|
||||
.runTaskTimerAsynchronously(plugin, runnable, toTicks(delay, unit), toTicks(repeat, unit)));
|
||||
}
|
||||
|
||||
private static class BukkitTaskWrapper implements ScheduledVotifierTask {
|
||||
|
||||
@@ -21,8 +21,6 @@ package com.vexsoftware.votifier;
|
||||
import com.vexsoftware.votifier.cmd.NVReloadCmd;
|
||||
import com.vexsoftware.votifier.cmd.TestVoteCmd;
|
||||
import com.vexsoftware.votifier.forwarding.BukkitPluginMessagingForwardingSink;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardedVoteListener;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardingVoteSink;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.model.VotifierEvent;
|
||||
import com.vexsoftware.votifier.net.VotifierServerBootstrap;
|
||||
@@ -33,14 +31,11 @@ import com.vexsoftware.votifier.platform.JavaUtilLogger;
|
||||
import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardedVoteListener;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardingVoteSink;
|
||||
import com.vexsoftware.votifier.util.IOUtil;
|
||||
import com.vexsoftware.votifier.util.KeyCreator;
|
||||
import com.vexsoftware.votifier.util.TokenUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -52,6 +47,10 @@ import java.security.KeyPair;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* The main Votifier plugin class.
|
||||
@@ -84,8 +83,18 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
private ForwardingVoteSink forwardingMethod;
|
||||
private VotifierScheduler scheduler;
|
||||
private LoggingAdapter pluginLogger;
|
||||
private boolean isFolia;
|
||||
|
||||
private boolean loadAndBind() {
|
||||
try {
|
||||
Class.forName("io.papermc.paper.threadedregions.scheduler.AsyncScheduler");
|
||||
isFolia = true;
|
||||
|
||||
getLogger().info("Using Folia; VotifierEvent will be fired asynchronously.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
isFolia = false;
|
||||
}
|
||||
|
||||
scheduler = new BukkitScheduler(this);
|
||||
pluginLogger = new JavaUtilLogger(getLogger());
|
||||
if (!getDataFolder().exists()) {
|
||||
@@ -104,8 +113,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
* assigned to the server.
|
||||
*/
|
||||
String hostAddr = Bukkit.getServer().getIp();
|
||||
if (hostAddr == null || hostAddr.length() == 0)
|
||||
hostAddr = "0.0.0.0";
|
||||
if (hostAddr == null || hostAddr.length() == 0) hostAddr = "0.0.0.0";
|
||||
|
||||
/*
|
||||
* Create configuration file if it does not exists; otherwise, load it
|
||||
@@ -121,10 +129,14 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
}
|
||||
|
||||
// Load and manually replace variables in the configuration.
|
||||
String cfgStr = new String(IOUtil.readAllBytes(getResource("bukkitConfig.yml")), StandardCharsets.UTF_8);
|
||||
String cfgStr =
|
||||
new String(IOUtil.readAllBytes(getResource("bukkitConfig.yml")), StandardCharsets.UTF_8);
|
||||
String token = TokenUtil.newToken();
|
||||
cfgStr = cfgStr.replace("%default_token%", token).replace("%ip%", hostAddr);
|
||||
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), config.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
Files.copy(
|
||||
new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)),
|
||||
config.toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
/*
|
||||
* Remind hosted server admins to be sure they have the right
|
||||
@@ -167,8 +179,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
keyPair = RSAIO.load(rsaDirectory);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
getLogger().log(Level.SEVERE,
|
||||
"Error reading configuration file or RSA tokens", ex);
|
||||
getLogger().log(Level.SEVERE, "Error reading configuration file or RSA tokens", ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -186,7 +197,9 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
if (tokenSection != null) {
|
||||
Map<String, Object> websites = tokenSection.getValues(false);
|
||||
for (Map.Entry<String, Object> website : websites.entrySet()) {
|
||||
tokens.put(website.getKey(), KeyCreator.createKeyFrom(website.getValue().toString()));
|
||||
tokens.put(
|
||||
website.getKey(),
|
||||
KeyCreator.createKeyFrom(website.getValue().toString()));
|
||||
getLogger().info("Loaded token for website: " + website.getKey());
|
||||
}
|
||||
} else {
|
||||
@@ -197,8 +210,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
try {
|
||||
cfg.save(config);
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.SEVERE,
|
||||
"Error generating Votifier token", e);
|
||||
getLogger().log(Level.SEVERE, "Error generating Votifier token", e);
|
||||
return false;
|
||||
}
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
@@ -212,8 +224,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
// Initialize the receiver.
|
||||
final String host = cfg.getString("host", hostAddr);
|
||||
final int port = cfg.getInt("port", 8192);
|
||||
if (!debug)
|
||||
getLogger().info("QUIET mode enabled!");
|
||||
if (!debug) getLogger().info("QUIET mode enabled!");
|
||||
|
||||
if (port >= 0) {
|
||||
final boolean disablev1 = cfg.getBoolean("disable-v1-protocol");
|
||||
@@ -236,19 +247,24 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
|
||||
ConfigurationSection forwardingConfig = cfg.getConfigurationSection("forwarding");
|
||||
if (forwardingConfig != null) {
|
||||
String method = forwardingConfig.getString("method", "none").toLowerCase(); //Default to lower case for case-insensitive searches
|
||||
String method = forwardingConfig
|
||||
.getString("method", "none")
|
||||
.toLowerCase(); // Default to lower case for case-insensitive searches
|
||||
if ("none".equals(method)) {
|
||||
getLogger().info("Method none selected for vote forwarding: Votes will not be received from a forwarder.");
|
||||
getLogger()
|
||||
.info("Method none selected for vote forwarding: Votes will not be received from a forwarder.");
|
||||
} else if ("pluginmessaging".equals(method)) {
|
||||
String channel = forwardingConfig.getString("pluginMessaging.channel", "NuVotifier");
|
||||
try {
|
||||
forwardingMethod = new BukkitPluginMessagingForwardingSink(this, channel, this);
|
||||
getLogger().info("Receiving votes over PluginMessaging channel '" + channel + "'.");
|
||||
} catch (RuntimeException e) {
|
||||
getLogger().log(Level.SEVERE, "NuVotifier could not set up PluginMessaging for vote forwarding!", e);
|
||||
getLogger()
|
||||
.log(Level.SEVERE, "NuVotifier could not set up PluginMessaging for vote forwarding!", e);
|
||||
}
|
||||
} else {
|
||||
getLogger().severe("No vote forwarding method '" + method + "' known. Defaulting to noop implementation.");
|
||||
getLogger()
|
||||
.severe("No vote forwarding method '" + method + "' known. Defaulting to noop implementation.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -297,9 +313,16 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
} else {
|
||||
try {
|
||||
halt();
|
||||
getLogger().log(Level.SEVERE, "On reload, there was a problem with the configuration. Votifier currently does nothing!");
|
||||
getLogger()
|
||||
.log(
|
||||
Level.SEVERE,
|
||||
"On reload, there was a problem with the configuration. Votifier currently does nothing!");
|
||||
} catch (Exception ex) {
|
||||
getLogger().log(Level.SEVERE, "On reload, there was a problem loading, and we could not re-halt the server. Votifier is in an unstable state!", ex);
|
||||
getLogger()
|
||||
.log(
|
||||
Level.SEVERE,
|
||||
"On reload, there was a problem loading, and we could not re-halt the server. Votifier is in an unstable state!",
|
||||
ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -336,22 +359,27 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
@Override
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) {
|
||||
if (debug) {
|
||||
getLogger().info("Got a " + protocolVersion.humanReadable + " vote record from " + remoteAddress + " -> " + vote);
|
||||
getLogger()
|
||||
.info("Got a " + protocolVersion.humanReadable + " vote record from " + remoteAddress + " -> "
|
||||
+ vote);
|
||||
}
|
||||
Bukkit.getScheduler().runTask(this, () -> fireVotifierEvent(vote));
|
||||
fireVotifierEvent(vote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable, boolean alreadyHandledVote, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Vote processed, however an exception " +
|
||||
"occurred with a vote from " + remoteAddress, throwable);
|
||||
getLogger()
|
||||
.log(
|
||||
Level.WARNING,
|
||||
"Vote processed, however an exception " + "occurred with a vote from " + remoteAddress,
|
||||
throwable);
|
||||
} else {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress, throwable);
|
||||
getLogger().log(Level.WARNING, "Unable to process vote from " + remoteAddress, throwable);
|
||||
}
|
||||
} else if (!alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress);
|
||||
getLogger().log(Level.WARNING, "Unable to process vote from " + remoteAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,15 +388,30 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
if (debug) {
|
||||
getLogger().info("Got a forwarded vote -> " + v);
|
||||
}
|
||||
Bukkit.getScheduler().runTask(this, () -> fireVotifierEvent(v));
|
||||
fireVotifierEvent(v);
|
||||
}
|
||||
|
||||
private void fireVotifierEvent(Vote vote) {
|
||||
if (VotifierEvent.getHandlerList().getRegisteredListeners().length == 0) {
|
||||
getLogger().log(Level.SEVERE, "A vote was received, but you don't have any listeners available to listen for it.");
|
||||
getLogger().log(Level.SEVERE, "See https://github.com/NuVotifier/NuVotifier/wiki/Setup-Guide#vote-listeners for");
|
||||
getLogger()
|
||||
.log(
|
||||
Level.SEVERE,
|
||||
"A vote was received, but you don't have any listeners available to listen for it.");
|
||||
getLogger()
|
||||
.log(
|
||||
Level.SEVERE,
|
||||
"See https://github.com/NuVotifier/NuVotifier/wiki/Setup-Guide#vote-listeners for");
|
||||
getLogger().log(Level.SEVERE, "a list of listeners you can configure.");
|
||||
}
|
||||
Bukkit.getPluginManager().callEvent(new VotifierEvent(vote));
|
||||
|
||||
if (!isFolia) {
|
||||
getServer()
|
||||
.getScheduler()
|
||||
.runTask(this, () -> getServer().getPluginManager().callEvent(new VotifierEvent(vote)));
|
||||
} else {
|
||||
getServer().getScheduler().runTaskAsynchronously(this, () -> getServer()
|
||||
.getPluginManager()
|
||||
.callEvent(new VotifierEvent(vote, true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.vexsoftware.votifier.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.NuVotifierBukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -17,14 +18,18 @@ public class NVReloadCmd implements CommandExecutor {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.reload")) {
|
||||
sender.sendMessage(ChatColor.GRAY + "Reloading NuVotifier...");
|
||||
sender.sendMessage(Component.text("Reloading NuVotifier...").color(NamedTextColor.GRAY));
|
||||
if (plugin.reload()) {
|
||||
sender.sendMessage(ChatColor.DARK_GREEN + "NuVotifier has been reloaded!");
|
||||
sender.sendMessage(
|
||||
Component.text("NuVotifier has been reloaded!").color(NamedTextColor.DARK_GREEN));
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "Looks like there was a problem reloading NuVotifier, check the console!");
|
||||
sender.sendMessage(
|
||||
Component.text("Looks like there was a problem reloading NuVotifier, check the console!")
|
||||
.color(NamedTextColor.DARK_RED));
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "You do not have permission to do this!");
|
||||
sender.sendMessage(
|
||||
Component.text("You do not have permission to do this!").color(NamedTextColor.DARK_RED));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import com.vexsoftware.votifier.NuVotifierBukkit;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.util.ArgsToVote;
|
||||
import org.bukkit.ChatColor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -24,17 +25,22 @@ public class TestVoteCmd implements CommandExecutor {
|
||||
try {
|
||||
v = ArgsToVote.parse(args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "Error while parsing arguments to create test vote: " + e.getMessage());
|
||||
sender.sendMessage(ChatColor.GRAY + "Usage hint: /testvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]");
|
||||
sender.sendMessage(
|
||||
Component.text("Error while parsing arguments to create test vote: " + e.getMessage())
|
||||
.color(NamedTextColor.DARK_RED));
|
||||
sender.sendMessage(Component.text(
|
||||
"Usage hint: /testvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]")
|
||||
.color(NamedTextColor.GRAY));
|
||||
return true;
|
||||
}
|
||||
|
||||
plugin.onVoteReceived(v, VotifierSession.ProtocolVersion.TEST, "localhost.test");
|
||||
sender.sendMessage(ChatColor.GREEN + "Test vote executed: " + v.toString());
|
||||
sender.sendMessage(
|
||||
Component.text("Test vote executed: " + v.toString()).color(NamedTextColor.GREEN));
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "You do not have permission to do this!");
|
||||
sender.sendMessage(
|
||||
Component.text("You do not have permission to do this!").color(NamedTextColor.DARK_RED));
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
+5
-9
@@ -1,24 +1,20 @@
|
||||
package com.vexsoftware.votifier.forwarding;
|
||||
|
||||
import com.vexsoftware.votifier.NuVotifierBukkit;
|
||||
import com.vexsoftware.votifier.support.forwarding.AbstractPluginMessagingForwardingSink;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardedVoteListener;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Created by Joe Hirschfeld on 10/20/2015.
|
||||
*/
|
||||
public class BukkitPluginMessagingForwardingSink extends AbstractPluginMessagingForwardingSink implements PluginMessageListener {
|
||||
public class BukkitPluginMessagingForwardingSink extends AbstractPluginMessagingForwardingSink
|
||||
implements PluginMessageListener {
|
||||
|
||||
public BukkitPluginMessagingForwardingSink(Plugin p, String channel, ForwardedVoteListener listener) {
|
||||
super(listener);
|
||||
Validate.notNull(channel, "Channel cannot be null.");
|
||||
Objects.requireNonNull(channel, "Channel cannot be null."); // Replaced Validate.notNull
|
||||
this.channel = channel;
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(p, channel, this);
|
||||
this.p = p;
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.bukkit.event.HandlerList;
|
||||
|
||||
/**
|
||||
* {@code VotifierEvent} is a custom Bukkit event class that is sent
|
||||
* synchronously to CraftBukkit's main thread allowing other plugins to listener
|
||||
* synchronously to CraftBukkit's main thread allowing other plugins to listen
|
||||
* for votes.
|
||||
*
|
||||
* @author frelling
|
||||
@@ -30,6 +30,17 @@ public class VotifierEvent extends Event {
|
||||
this.vote = vote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a vote event that encapsulated the given vote record.
|
||||
*
|
||||
* @param vote vote record
|
||||
* @param async whether the event will be fired asynchronously
|
||||
*/
|
||||
public VotifierEvent(final Vote vote, final boolean async) {
|
||||
super(async);
|
||||
this.vote = vote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encapsulated vote record.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The IP to listen to. Use 0.0.0.0 if you wish to listen to all interfaces on your server. (All IP addresses)
|
||||
# This defaults to the IP you have configured your server to listen on, or 0.0.0.0 if you have not configured this.
|
||||
host: %ip%
|
||||
host: 0.0.0.0
|
||||
|
||||
# Port to listen for new votes on
|
||||
port: 8192
|
||||
@@ -13,7 +13,7 @@ disable-v1-protocol: false
|
||||
# All tokens, labeled by the serviceName of each server list.
|
||||
tokens:
|
||||
# Default token for all server lists, if another isn't supplied.
|
||||
default: %default_token%
|
||||
default: "^{VOTIFIER_OG_TOKEN}"
|
||||
|
||||
# Configuration section for all vote forwarding to NuVotifier
|
||||
forwarding:
|
||||
@@ -22,4 +22,4 @@ forwarding:
|
||||
# - pluginMessaging - Sets up plugin messaging
|
||||
method: none
|
||||
pluginMessaging:
|
||||
channel: nuvotifier:votes
|
||||
channel: nuvotifier:votes
|
||||
@@ -1,9 +1,9 @@
|
||||
name: Votifier
|
||||
name: Votifier-OG
|
||||
main: com.vexsoftware.votifier.NuVotifierBukkit
|
||||
version: @app.version@
|
||||
version: "${version}"
|
||||
description: A plugin that gets notified when votes are made for the server on toplists.
|
||||
authors: [Ichbinjoe, blakeman8192, Kramer, tuxed]
|
||||
api-version: 1.13
|
||||
authors: [Ichbinjoe, blakeman8192, Kramer, tuxed, NotAlexNoyle]
|
||||
api-version: 1.19
|
||||
|
||||
commands:
|
||||
nvreload:
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
dependencies {
|
||||
compileOnly group: "net.md-5", name: "bungeecord-api", version: "1.8-SNAPSHOT"
|
||||
implementation project(":nuvotifier-api")
|
||||
implementation project(":nuvotifier-common")
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee;
|
||||
|
||||
import com.vexsoftware.votifier.platform.BackendServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class BungeeBackendServer implements BackendServer {
|
||||
private final ServerInfo info;
|
||||
|
||||
public BungeeBackendServer(ServerInfo info) {
|
||||
this.info = Objects.requireNonNull(info, "info");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return info.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendPluginMessage(String channel, byte[] data) {
|
||||
return info.sendData(channel, data, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return info.getName();
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee;
|
||||
|
||||
import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class BungeeScheduler implements VotifierScheduler {
|
||||
private final NuVotifier plugin;
|
||||
|
||||
public BungeeScheduler(NuVotifier plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask sync(Runnable runnable) {
|
||||
return onPool(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask onPool(Runnable runnable) {
|
||||
return new BungeeTaskWrapper(plugin.getProxy().getScheduler().runAsync(plugin, runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask delayedSync(Runnable runnable, int delay, TimeUnit unit) {
|
||||
return delayedOnPool(runnable, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit) {
|
||||
return new BungeeTaskWrapper(plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, unit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask repeatOnPool(Runnable runnable, int delay, int repeat, TimeUnit unit) {
|
||||
return new BungeeTaskWrapper(plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, unit));
|
||||
}
|
||||
|
||||
private static class BungeeTaskWrapper implements ScheduledVotifierTask {
|
||||
private final ScheduledTask task;
|
||||
|
||||
private BungeeTaskWrapper(ScheduledTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,424 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.vexsoftware.votifier.VoteHandler;
|
||||
import com.vexsoftware.votifier.bungee.cmd.NVReloadCmd;
|
||||
import com.vexsoftware.votifier.bungee.cmd.TestVoteCmd;
|
||||
import com.vexsoftware.votifier.net.VotifierServerBootstrap;
|
||||
import com.vexsoftware.votifier.platform.BackendServer;
|
||||
import com.vexsoftware.votifier.platform.JavaUtilLogger;
|
||||
import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.ProxyVotifierPlugin;
|
||||
import com.vexsoftware.votifier.bungee.events.VotifierEvent;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardingVoteSource;
|
||||
import com.vexsoftware.votifier.support.forwarding.ServerFilter;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.FileVoteCache;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.MemoryVoteCache;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
|
||||
import com.vexsoftware.votifier.support.forwarding.proxy.ProxyForwardingVoteSource;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAIO;
|
||||
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAKeygen;
|
||||
import com.vexsoftware.votifier.util.IOUtil;
|
||||
import com.vexsoftware.votifier.util.KeyCreator;
|
||||
import com.vexsoftware.votifier.util.TokenUtil;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.plugin.PluginManager;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import net.md_5.bungee.config.ConfigurationProvider;
|
||||
import net.md_5.bungee.config.YamlConfiguration;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlugin {
|
||||
|
||||
/**
|
||||
* The server channel.
|
||||
*/
|
||||
private VotifierServerBootstrap bootstrap;
|
||||
|
||||
/**
|
||||
* The RSA key pair.
|
||||
*/
|
||||
private KeyPair keyPair;
|
||||
|
||||
/**
|
||||
* Debug mode flag
|
||||
*/
|
||||
private boolean debug;
|
||||
|
||||
/**
|
||||
* Keys used for websites.
|
||||
*/
|
||||
private Map<String, Key> tokens = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Method used to forward votes to downstream servers
|
||||
*/
|
||||
private ForwardingVoteSource forwardingMethod;
|
||||
|
||||
private VotifierScheduler scheduler;
|
||||
private LoggingAdapter pluginLogger;
|
||||
|
||||
private void loadAndBind() {
|
||||
if (!getDataFolder().exists()) {
|
||||
if (!getDataFolder().mkdir()) {
|
||||
throw new RuntimeException("Unable to create the plugin data folder " + getDataFolder());
|
||||
}
|
||||
}
|
||||
|
||||
// Handle configuration.
|
||||
File config = new File(getDataFolder() , "config.yml");
|
||||
File rsaDirectory = new File(getDataFolder() , "rsa");
|
||||
Configuration configuration;
|
||||
|
||||
if (!config.exists()) {
|
||||
try {
|
||||
// First time run - do some initialization.
|
||||
getLogger().info("Configuring Votifier for the first time...");
|
||||
|
||||
// Initialize the configuration file.
|
||||
if (!config.createNewFile()) {
|
||||
throw new IOException("Unable to create the config file at " + config);
|
||||
}
|
||||
|
||||
String cfgStr = new String(IOUtil.readAllBytes(getResourceAsStream("bungeeConfig.yml")), StandardCharsets.UTF_8);
|
||||
String token = TokenUtil.newToken();
|
||||
cfgStr = cfgStr.replace("%default_token%", token);
|
||||
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), config.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
/*
|
||||
* Remind hosted server admins to be sure they have the right
|
||||
* port number.
|
||||
*/
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("Assigning NuVotifier to listen on port 8192. If you are hosting BungeeCord on a");
|
||||
getLogger().info("shared server please check with your hosting provider to verify that this port");
|
||||
getLogger().info("is available for your use. Chances are that your hosting provider will assign");
|
||||
getLogger().info("a different port, which you need to specify in config.yml");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("Assigning NuVotifier to listen to interface 0.0.0.0. This is usually alright,");
|
||||
getLogger().info("however, if you want NuVotifier to only listen to one interface for security ");
|
||||
getLogger().info("reasons (or you use a shared host), you may change this in the config.yml.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("Your default Votifier token is " + token + ".");
|
||||
getLogger().info("You will need to provide this token when you submit your server to a voting");
|
||||
getLogger().info("list.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Unable to create configuration file", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the configuration.
|
||||
try {
|
||||
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(config);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to load configuration", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create RSA directory and keys if it does not exist; otherwise, read
|
||||
* keys.
|
||||
*/
|
||||
try {
|
||||
if (!rsaDirectory.exists()) {
|
||||
if (!rsaDirectory.mkdir()) {
|
||||
throw new RuntimeException("Unable to create the RSA key folder " + rsaDirectory);
|
||||
}
|
||||
keyPair = RSAKeygen.generate(2048);
|
||||
RSAIO.save(rsaDirectory, keyPair);
|
||||
} else {
|
||||
keyPair = RSAIO.load(rsaDirectory);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error reading RSA tokens", ex);
|
||||
}
|
||||
|
||||
// Load Votifier tokens.
|
||||
Configuration tokenSection = configuration.getSection("tokens");
|
||||
|
||||
if (configuration.get("tokens") != null) {
|
||||
for (String s : tokenSection.getKeys()) {
|
||||
tokens.put(s, KeyCreator.createKeyFrom(tokenSection.getString(s)));
|
||||
getLogger().info("Loaded token for website: " + s);
|
||||
}
|
||||
} else {
|
||||
String token = TokenUtil.newToken();
|
||||
configuration.set("tokens", Collections.singletonMap("default", token));
|
||||
tokens.put("default", KeyCreator.createKeyFrom(token));
|
||||
try {
|
||||
ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, config);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error generating Votifier token", e);
|
||||
}
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("No tokens were found in your configuration, so we've generated one for you.");
|
||||
getLogger().info("Your default Votifier token is " + token + ".");
|
||||
getLogger().info("You will need to provide this token when you submit your server to a voting");
|
||||
getLogger().info("list.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
// Initialize the receiver.
|
||||
final String host = configuration.getString("host", "0.0.0.0");
|
||||
final int port = configuration.getInt("port", 8192);
|
||||
|
||||
if (configuration.get("quiet") != null)
|
||||
debug = !configuration.getBoolean("quiet");
|
||||
else
|
||||
debug = configuration.getBoolean("debug", true);
|
||||
|
||||
if (!debug)
|
||||
getLogger().info("QUIET mode enabled!");
|
||||
|
||||
final boolean disablev1 = configuration.getBoolean("disable-v1-protocol");
|
||||
if (disablev1) {
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("Votifier protocol v1 parsing has been disabled. Most voting websites do not");
|
||||
getLogger().info("currently support the modern Votifier protocol in NuVotifier.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
// Must set up server asynchronously due to BungeeCord goofiness.
|
||||
FutureTask<?> initTask = new FutureTask<>(Executors.callable(() -> {
|
||||
this.bootstrap = new VotifierServerBootstrap(host, port, NuVotifier.this, disablev1);
|
||||
this.bootstrap.start(err -> {});
|
||||
}));
|
||||
getProxy().getScheduler().runAsync(this, initTask);
|
||||
try {
|
||||
initTask.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException("Unable to start server", e);
|
||||
}
|
||||
|
||||
Configuration fwdCfg = configuration.getSection("forwarding");
|
||||
String fwdMethod = fwdCfg.getString("method", "none").toLowerCase();
|
||||
if ("none".equals(fwdMethod)) {
|
||||
getLogger().info("Method none selected for vote forwarding: Votes will not be forwarded to backend servers.");
|
||||
} else if ("pluginmessaging".equals(fwdMethod)) {
|
||||
String channel = fwdCfg.getString("pluginMessaging.channel", "NuVotifier");
|
||||
String cacheMethod = fwdCfg.getString("pluginMessaging.cache", "file").toLowerCase();
|
||||
VoteCache voteCache = null;
|
||||
if ("none".equals(cacheMethod)) {
|
||||
getLogger().info("Vote cache none selected for caching: votes that cannot be immediately delivered will be lost.");
|
||||
} else if ("memory".equals(cacheMethod)) {
|
||||
voteCache = new MemoryVoteCache(
|
||||
this,
|
||||
fwdCfg.getInt("pluginMessaging.memory.cacheTime", -1));
|
||||
getLogger().info("Using in-memory cache for votes that are not able to be delivered.");
|
||||
} else if ("file".equals(cacheMethod)) {
|
||||
try {
|
||||
voteCache = new FileVoteCache(
|
||||
this,
|
||||
new File(getDataFolder(), fwdCfg.getString("pluginMessaging.file.name")),
|
||||
fwdCfg.getInt("pluginMessaging.file.cacheTime", -1));
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.SEVERE, "Unload to load file cache. Votes will be lost!", e);
|
||||
}
|
||||
}
|
||||
|
||||
int dumpRate = fwdCfg.getInt("pluginMessaging.dumpRate", 5);
|
||||
|
||||
ServerFilter filter = new ServerFilter(
|
||||
fwdCfg.getStringList("pluginMessaging.excludedServers"),
|
||||
fwdCfg.getBoolean("pluginMessaging.whitelist", false)
|
||||
);
|
||||
|
||||
if (!fwdCfg.getBoolean("pluginMessaging.onlySendToJoinedServer")) {
|
||||
try {
|
||||
forwardingMethod = new PluginMessagingForwardingSource(channel, filter, this, voteCache, dumpRate);
|
||||
getLogger().info("Forwarding votes over PluginMessaging channel '" + channel + "' for vote forwarding!");
|
||||
} catch (RuntimeException e) {
|
||||
getLogger().log(Level.SEVERE, "NuVotifier could not set up PluginMessaging for vote forwarding!", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
String fallbackServer = fwdCfg.getString("pluginMessaging.joinedServerFallback", null);
|
||||
if (fallbackServer != null && fallbackServer.isEmpty()) fallbackServer = null;
|
||||
forwardingMethod = new OnlineForwardPluginMessagingForwardingSource(channel, this, filter, voteCache, fallbackServer, dumpRate);
|
||||
getLogger().info("Forwarding votes over PluginMessaging channel '" + channel + "' for vote forwarding for online players!");
|
||||
} catch (RuntimeException e) {
|
||||
getLogger().log(Level.SEVERE, "NuVotifier could not set up PluginMessaging for vote forwarding!", e);
|
||||
}
|
||||
}
|
||||
} else if ("proxy".equals(fwdMethod)) {
|
||||
Configuration serverSection = fwdCfg.getSection("proxy");
|
||||
List<ProxyForwardingVoteSource.BackendServer> serverList = new ArrayList<>();
|
||||
for (String s : serverSection.getKeys()) {
|
||||
Configuration section = serverSection.getSection(s);
|
||||
InetAddress address;
|
||||
try {
|
||||
address = InetAddress.getByName(section.getString("address"));
|
||||
} catch (UnknownHostException e) {
|
||||
getLogger().info("Address " + section.getString("address") + " couldn't be looked up. Ignoring!");
|
||||
continue;
|
||||
}
|
||||
|
||||
Key token = null;
|
||||
try {
|
||||
token = KeyCreator.createKeyFrom(section.getString("token", section.getString("key")));
|
||||
} catch (IllegalArgumentException e) {
|
||||
getLogger().log(Level.SEVERE,
|
||||
"An exception occurred while attempting to add proxy target '" + s + "' - maybe your token is wrong? " +
|
||||
"Votes will not be forwarded to this server!", e);
|
||||
}
|
||||
|
||||
if (token != null) {
|
||||
ProxyForwardingVoteSource.BackendServer server = new ProxyForwardingVoteSource.BackendServer(s,
|
||||
new InetSocketAddress(address, section.getInt("port")),
|
||||
token);
|
||||
serverList.add(server);
|
||||
}
|
||||
}
|
||||
|
||||
forwardingMethod = bootstrap.createForwardingSource(serverList, null);
|
||||
getLogger().info("Forwarding votes from this NuVotifier instance to another NuVotifier server.");
|
||||
} else {
|
||||
getLogger().severe("No vote forwarding method '" + fwdMethod + "' known. Defaulting to noop implementation.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
scheduler = new BungeeScheduler(this);
|
||||
pluginLogger = new JavaUtilLogger(getLogger());
|
||||
|
||||
PluginManager pm = ProxyServer.getInstance().getPluginManager();
|
||||
pm.registerCommand(this, new NVReloadCmd(this));
|
||||
pm.registerCommand(this, new TestVoteCmd(this));
|
||||
pm.registerListener(this, new ReloadListener(this));
|
||||
|
||||
loadAndBind();
|
||||
}
|
||||
|
||||
private void halt() {
|
||||
// Shut down the network handlers.
|
||||
if (bootstrap != null) {
|
||||
bootstrap.shutdown();
|
||||
bootstrap = null;
|
||||
}
|
||||
|
||||
if (forwardingMethod != null) {
|
||||
forwardingMethod.halt();
|
||||
forwardingMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean reload() {
|
||||
try {
|
||||
halt();
|
||||
} catch (Exception ex) {
|
||||
getLogger().log(Level.SEVERE, "On halt, an exception was thrown. This may be fine!", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
loadAndBind();
|
||||
getLogger().info("Reload was successful.");
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
halt();
|
||||
getLogger().log(Level.SEVERE, "On reload, there was a problem with the configuration. Votifier currently does nothing!", ex);
|
||||
} catch (Exception ex2) {
|
||||
getLogger().log(Level.SEVERE, "On reload, there was a problem loading, and we could not re-halt the server. Votifier is in an unstable state!", ex);
|
||||
getLogger().log(Level.SEVERE, "(halt exception)", ex2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
halt();
|
||||
getLogger().info("Votifier disabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (protocolVersion == VotifierSession.ProtocolVersion.ONE) {
|
||||
getLogger().info("Got a protocol v1 vote record from " + remoteAddress + " -> " + vote);
|
||||
} else {
|
||||
getLogger().info("Got a protocol v2 vote record from " + remoteAddress + " -> " + vote);
|
||||
}
|
||||
}
|
||||
|
||||
getProxy().getScheduler().runAsync(this, () -> getProxy().getPluginManager().callEvent(new VotifierEvent(vote)));
|
||||
|
||||
if (forwardingMethod != null) {
|
||||
getProxy().getScheduler().runAsync(this, () -> forwardingMethod.forward(vote));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable, boolean alreadyHandledVote, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Vote processed, however an exception " +
|
||||
"occurred with a vote from " + remoteAddress, throwable);
|
||||
} else {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress, throwable);
|
||||
}
|
||||
} else if (!alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Key> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair getProtocolV1Key() {
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggingAdapter getPluginLogger() {
|
||||
return pluginLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VotifierScheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BackendServer> getAllBackendServers() {
|
||||
return getProxy().getServers().values().stream()
|
||||
.map(BungeeBackendServer::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BackendServer> getServer(String name) {
|
||||
ServerInfo info = getProxy().getServerInfo(name);
|
||||
return Optional.ofNullable(info).map(BungeeBackendServer::new);
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.platform.BackendServer;
|
||||
import com.vexsoftware.votifier.support.forwarding.AbstractPluginMessagingForwardingSource;
|
||||
import com.vexsoftware.votifier.support.forwarding.ServerFilter;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
/**
|
||||
* @author Joseph Hirschfeld
|
||||
* @date 12/31/2015
|
||||
*/
|
||||
public final class OnlineForwardPluginMessagingForwardingSource extends AbstractPluginMessagingForwardingSource implements Listener {
|
||||
public OnlineForwardPluginMessagingForwardingSource(String channel, NuVotifier nuVotifier, ServerFilter serverFilter,
|
||||
VoteCache cache, String fallbackServer, int dumpRate) {
|
||||
super(channel, serverFilter, nuVotifier, cache, dumpRate);
|
||||
this.fallbackServer = fallbackServer;
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(nuVotifier, this);
|
||||
}
|
||||
|
||||
private final String fallbackServer;
|
||||
|
||||
@Override
|
||||
public void forward(Vote v) {
|
||||
ProxiedPlayer p = ProxyServer.getInstance().getPlayer(v.getUsername());
|
||||
if (p != null && p.getServer() != null &&
|
||||
serverFilter.isAllowed(p.getServer().getInfo().getName())) {
|
||||
if (forwardSpecific(new BungeeBackendServer(p.getServer().getInfo()), v)) {
|
||||
if (plugin.isDebug()) {
|
||||
plugin.getPluginLogger().info("Successfully forwarded vote " + v + " to server " + p.getServer().getInfo().getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ServerInfo serverInfo = ProxyServer.getInstance().getServers().get(fallbackServer);
|
||||
|
||||
// nowhere to fall back to, yet still not online. lets save this vote yet!
|
||||
if (serverInfo == null)
|
||||
attemptToAddToPlayerCache(v, v.getUsername());
|
||||
else if (!forwardSpecific(new BungeeBackendServer(serverInfo), v))
|
||||
attemptToAddToCache(v, fallbackServer);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessage(PluginMessageEvent e) {
|
||||
if (e.getTag().equals(channel)) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerConnected(final ServerConnectedEvent e) { //Attempt to resend any votes that were previously cached.
|
||||
BackendServer server = new BungeeBackendServer(e.getServer().getInfo());
|
||||
handlePlayerSwitch(server, e.getPlayer().getName());
|
||||
onServerConnect(server);
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee;
|
||||
|
||||
import com.vexsoftware.votifier.support.forwarding.AbstractPluginMessagingForwardingSource;
|
||||
import com.vexsoftware.votifier.support.forwarding.ServerFilter;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class PluginMessagingForwardingSource extends AbstractPluginMessagingForwardingSource implements Listener {
|
||||
|
||||
public PluginMessagingForwardingSource(String channel, ServerFilter serverFilter, NuVotifier nuVotifier, VoteCache cache, int dumpRate) {
|
||||
super(channel, serverFilter, nuVotifier, cache, dumpRate);
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(nuVotifier, this);
|
||||
}
|
||||
|
||||
protected PluginMessagingForwardingSource(String channel, NuVotifier nuVotifier, VoteCache voteCache, int dumpRate) {
|
||||
super(channel, nuVotifier, voteCache, dumpRate);
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(nuVotifier, this);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessage(PluginMessageEvent e) {
|
||||
if (e.getTag().equals(channel)) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerConnected(final ServerConnectedEvent e) { //Attempt to resend any votes that were previously cached.
|
||||
onServerConnect(new BungeeBackendServer(e.getServer().getInfo()));
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee;
|
||||
|
||||
import net.md_5.bungee.api.event.ProxyReloadEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class ReloadListener implements Listener {
|
||||
private final NuVotifier nuVotifier;
|
||||
|
||||
public ReloadListener(NuVotifier nuVotifier) {
|
||||
this.nuVotifier = nuVotifier;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onProxyReload(ProxyReloadEvent event) {
|
||||
this.nuVotifier.reload();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.bungee.NuVotifier;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class NVReloadCmd extends Command {
|
||||
|
||||
private final NuVotifier plugin;
|
||||
|
||||
private static final BaseComponent reloadingNuVotifier = new TextComponent("Reloading NuVotifier...");
|
||||
private static final BaseComponent nuvotifierHasBeenReloaded = new TextComponent("NuVotifier has been reloaded!");
|
||||
private static final BaseComponent problem = new TextComponent("Looks like there was a problem reloading NuVotifier, check the console!");
|
||||
private static final BaseComponent permission = new TextComponent("You do not have permission to do this!");
|
||||
|
||||
static {
|
||||
reloadingNuVotifier.setColor(ChatColor.GRAY);
|
||||
nuvotifierHasBeenReloaded.setColor(ChatColor.DARK_GREEN);
|
||||
problem.setColor(ChatColor.DARK_RED);
|
||||
permission.setColor(ChatColor.DARK_RED);
|
||||
}
|
||||
|
||||
public NVReloadCmd(NuVotifier plugin) {
|
||||
super("pnvreload", "nuvotifier.reload");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.reload")) {
|
||||
sender.sendMessage(reloadingNuVotifier);
|
||||
if (plugin.reload()) {
|
||||
sender.sendMessage(nuvotifierHasBeenReloaded);
|
||||
} else {
|
||||
sender.sendMessage(problem);
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.bungee.NuVotifier;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.util.ArgsToVote;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class TestVoteCmd extends Command {
|
||||
|
||||
private final NuVotifier plugin;
|
||||
|
||||
private static final BaseComponent permission = new TextComponent("You do not have permission to do this!");
|
||||
private static final BaseComponent usage = new TextComponent("Usage hint: /ptestvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]");
|
||||
|
||||
static {
|
||||
usage.setColor(ChatColor.GRAY);
|
||||
}
|
||||
|
||||
public TestVoteCmd(NuVotifier plugin) {
|
||||
super("ptestvote", "nuvotifier.testvote");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.testvote")) {
|
||||
Vote v;
|
||||
try {
|
||||
v = ArgsToVote.parse(args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
TextComponent c = new TextComponent("Error while parsing arguments to create test vote: " + e.getMessage());
|
||||
c.setColor(ChatColor.DARK_RED);
|
||||
sender.sendMessage(c);
|
||||
sender.sendMessage(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.onVoteReceived(v, VotifierSession.ProtocolVersion.TEST, "localhost.test");
|
||||
TextComponent c = new TextComponent("Test vote executed: " + v.toString());
|
||||
c.setColor(ChatColor.GREEN);
|
||||
sender.sendMessage(c);
|
||||
} else {
|
||||
sender.sendMessage(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.vexsoftware.votifier.bungee.events;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* {@code VotifierEvent} is a custom BungeeCord event class that is sent
|
||||
* asynchronously allowing other plugins to listen for votes.
|
||||
*/
|
||||
public class VotifierEvent extends Event {
|
||||
/**
|
||||
* The vote.
|
||||
**/
|
||||
private final Vote vote;
|
||||
|
||||
public VotifierEvent(Vote vote) {
|
||||
this.vote = vote;
|
||||
}
|
||||
|
||||
public Vote getVote() {
|
||||
return vote;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
name: NuVotifier
|
||||
main: com.vexsoftware.votifier.bungee.NuVotifier
|
||||
version: @app.version@
|
||||
author: Ichbinjoe, blakeman8192, Kramer, tuxed
|
||||
@@ -1,70 +0,0 @@
|
||||
# The IP to listen to. Use 0.0.0.0 if you wish to listen to all interfaces on your server. (All IP addresses)
|
||||
# This defaults to the IP you have configured your server to listen on, or 0.0.0.0 if you have not configured this.
|
||||
host: 0.0.0.0
|
||||
|
||||
# Port to listen for new votes on
|
||||
port: 8192
|
||||
|
||||
# All tokens, labeled by the serviceName of each server list.
|
||||
tokens:
|
||||
# Default token for all server lists, if another isn't supplied.
|
||||
default: %default_token%
|
||||
|
||||
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
|
||||
# option is currently not recommended as most voting sites only support the old protocol at present.
|
||||
disable-v1-protocol: false
|
||||
|
||||
# Configuration section for all vote forwarding to NuVotifier
|
||||
forwarding:
|
||||
# Sets whether to set up a remote method for fowarding. Supported methods:
|
||||
# - none - Does not set up a forwarding method.
|
||||
# - pluginMessaging - Sets up plugin messaging.
|
||||
# - proxy - Proxies votes to other NuVotifier servers from this server.
|
||||
method: none
|
||||
pluginMessaging:
|
||||
channel: nuvotifier:votes
|
||||
|
||||
#Only send votes to certain servers. If a server is present on excludedServers, then votes will NOT be forwarded
|
||||
#to them. If excludedServers is not present, votes will be sent to all servers.
|
||||
# If onlySendToJoinedServer is true and a player is on one of these servers, NuVotifier will process the vote as if the
|
||||
# player was not on the network at all.
|
||||
#excludedServers:
|
||||
#- server1
|
||||
#- server2
|
||||
|
||||
# If uncommented, turns excludedServers into an includedServers, where only servers on the list will be used.
|
||||
#whitelist: true
|
||||
|
||||
# Sets which cache to use if there are no players on the server that the vote is being sent to. Supported caches:
|
||||
# - none - Votes will simply be lost when no players are present on the server.
|
||||
# - memory - Votes will be cached in memory when no players are present. When Bungee is restarted, the votes will be lost.
|
||||
# - file - Votes will be saved to a local file every 3 minutes and on shutdown and reloaded when Bungee is restarted. This is suitable for
|
||||
# most set ups.
|
||||
cache: file
|
||||
# Only sends the vote to the server in which the player is currently joined.
|
||||
onlySendToJoinedServer: false
|
||||
#Sets which server to send the vote in the event the player is not online when the vote is cast
|
||||
#If you do not want the vote forwarded to a fallback, set this value to empty ('')
|
||||
#ONLY USED IF onlySendToJoinedServer is true!!
|
||||
joinedServerFallback: 'Hub'
|
||||
# Defines how quickly to dump votes over a player's connection when offloading a cache in votes per second
|
||||
dumpRate: 5
|
||||
# Options for file caching.
|
||||
file:
|
||||
name: cached-votes.json
|
||||
# days before a vote is considered 'dead' - removed from cache with a console warning
|
||||
cacheTime: 10
|
||||
# Options for memory caching.
|
||||
memory:
|
||||
# days before a vote is considered 'dead' and removed from memory. All votes are removed when the server restarts. -1 signifies no TTL
|
||||
cacheTime: -1
|
||||
# Specify servers to proxy votes for.
|
||||
proxy:
|
||||
Hub:
|
||||
address: 127.0.0.1
|
||||
port: 8193
|
||||
token: MyKeyHere
|
||||
Hub2:
|
||||
address: 127.0.0.1
|
||||
port: 8194
|
||||
token: AnotherKeyHere
|
||||
@@ -0,0 +1 @@
|
||||
/bin/
|
||||
@@ -1,8 +0,0 @@
|
||||
dependencies {
|
||||
implementation project(":nuvotifier-api")
|
||||
implementation group: "io.netty", name: "netty-handler", version: "4.1.49.Final"
|
||||
implementation group: "io.netty", name: "netty-transport-native-epoll", version: "4.1.49.Final", classifier: "linux-x86_64"
|
||||
implementation 'com.google.code.gson:gson:2.8.0'
|
||||
testImplementation group: "org.json", name: "json", version: "20180130" // retain this for testing reasons
|
||||
testImplementation 'com.google.guava:guava:28.1-jre'
|
||||
}
|
||||
@@ -2,14 +2,13 @@ package com.vexsoftware.votifier;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
public interface VoteHandler {
|
||||
|
||||
void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) throws Exception;
|
||||
void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress)
|
||||
throws Exception;
|
||||
|
||||
default void onError(Throwable throwable, boolean voteAlreadyCompleted, String remoteAddress) {
|
||||
throw new RuntimeException("Unimplemented onError handler");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,8 +21,6 @@ import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.List;
|
||||
@@ -81,7 +79,10 @@ public class VotifierServerBootstrap {
|
||||
channel.attr(VotifierSession.KEY).set(new VotifierSession());
|
||||
channel.attr(VotifierPlugin.KEY).set(plugin);
|
||||
channel.pipeline().addLast("greetingHandler", VotifierGreetingHandler.INSTANCE);
|
||||
channel.pipeline().addLast("protocolDifferentiator", new VotifierProtocolDifferentiator(false, !v1Disable));
|
||||
channel.pipeline()
|
||||
.addLast(
|
||||
"protocolDifferentiator",
|
||||
new VotifierProtocolDifferentiator(false, !v1Disable));
|
||||
channel.pipeline().addLast("voteHandler", voteInboundHandler);
|
||||
}
|
||||
})
|
||||
@@ -89,14 +90,16 @@ public class VotifierServerBootstrap {
|
||||
.addListener((ChannelFutureListener) future -> {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
plugin.getPluginLogger().info("Votifier enabled on socket " + serverChannel.localAddress() + ".");
|
||||
plugin.getPluginLogger()
|
||||
.info("Votifier enabled on socket " + serverChannel.localAddress() + ".");
|
||||
error.accept(null);
|
||||
} else {
|
||||
SocketAddress socketAddress = future.channel().localAddress();
|
||||
if (socketAddress == null) {
|
||||
socketAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
plugin.getPluginLogger().error("Votifier was not able to bind to " + socketAddress.toString(), future.cause());
|
||||
plugin.getPluginLogger()
|
||||
.error("Votifier was not able to bind to " + socketAddress.toString(), future.cause());
|
||||
error.accept(future.cause());
|
||||
}
|
||||
});
|
||||
@@ -108,8 +111,8 @@ public class VotifierServerBootstrap {
|
||||
.group(eventLoopGroup);
|
||||
}
|
||||
|
||||
public ProxyForwardingVoteSource createForwardingSource(List<ProxyForwardingVoteSource.BackendServer> backendServers,
|
||||
VoteCache voteCache) {
|
||||
public ProxyForwardingVoteSource createForwardingSource(
|
||||
List<ProxyForwardingVoteSource.BackendServer> backendServers, VoteCache voteCache) {
|
||||
return new ProxyForwardingVoteSource(plugin, this::client, backendServers, voteCache);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@ public class VotifierSession {
|
||||
}
|
||||
|
||||
public void completeVote() {
|
||||
if (hasCompletedVote)
|
||||
throw new IllegalStateException("Protocol completed vote twice!");
|
||||
if (hasCompletedVote) throw new IllegalStateException("Protocol completed vote twice!");
|
||||
|
||||
hasCompletedVote = true;
|
||||
}
|
||||
@@ -46,6 +45,7 @@ public class VotifierSession {
|
||||
TEST("test");
|
||||
|
||||
public final String humanReadable;
|
||||
|
||||
ProtocolVersion(String hr) {
|
||||
this.humanReadable = hr;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
@@ -28,7 +27,8 @@ public class VoteInboundHandler extends SimpleChannelInboundHandler<Vote> {
|
||||
protected void channelRead0(ChannelHandlerContext ctx, final Vote vote) throws Exception {
|
||||
VotifierSession session = ctx.channel().attr(VotifierSession.KEY).get();
|
||||
|
||||
handler.onVoteReceived(vote, session.getVersion(), ctx.channel().remoteAddress().toString());
|
||||
handler.onVoteReceived(
|
||||
vote, session.getVersion(), ctx.channel().remoteAddress().toString());
|
||||
session.completeVote();
|
||||
|
||||
if (session.getVersion() == VotifierSession.ProtocolVersion.ONE) {
|
||||
|
||||
-1
@@ -6,7 +6,6 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
|
||||
+15
-8
@@ -1,15 +1,14 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.protocol.v1crypto.RSA;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.util.QuietException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
@@ -30,8 +29,10 @@ public class VotifierProtocol1Decoder extends ByteToMessageDecoder {
|
||||
}
|
||||
|
||||
if (buf.readableBytes() > 256) {
|
||||
// They sent too much data.
|
||||
throw new QuietException("Could not decrypt data from " + ctx.channel().remoteAddress() + " as it is too long. Attack?");
|
||||
// They sent too much data - silently drop the connection.
|
||||
buf.skipBytes(buf.readableBytes());
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] block = ByteBufUtil.getBytes(buf);
|
||||
@@ -43,9 +44,13 @@ public class VotifierProtocol1Decoder extends ByteToMessageDecoder {
|
||||
block = RSA.decrypt(block, plugin.getProtocolV1Key().getPrivate());
|
||||
} catch (Exception e) {
|
||||
if (plugin.isDebug()) {
|
||||
throw new CorruptedFrameException("Could not decrypt data from " + ctx.channel().remoteAddress() + ". Make sure the public key on the list is correct.", e);
|
||||
throw new CorruptedFrameException(
|
||||
"Could not decrypt data from " + ctx.channel().remoteAddress()
|
||||
+ ". Make sure the public key on the list is correct.",
|
||||
e);
|
||||
} else {
|
||||
throw new QuietException("Could not decrypt data from " + ctx.channel().remoteAddress() + ". Make sure the public key on the list is correct.");
|
||||
throw new QuietException("Could not decrypt data from "
|
||||
+ ctx.channel().remoteAddress() + ". Make sure the public key on the list is correct.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,11 +58,13 @@ public class VotifierProtocol1Decoder extends ByteToMessageDecoder {
|
||||
String all = new String(block, StandardCharsets.US_ASCII);
|
||||
String[] split = all.split("\n");
|
||||
if (split.length < 5) {
|
||||
throw new QuietException("Not enough fields specified in vote. This is not a NuVotifier issue. Got " + split.length + " fields, but needed 5.");
|
||||
throw new QuietException("Not enough fields specified in vote. This is not a NuVotifier issue. Got "
|
||||
+ split.length + " fields, but needed 5.");
|
||||
}
|
||||
|
||||
if (!split[0].equals("VOTE")) {
|
||||
throw new QuietException("The VOTE opcode was not present. This is not a NuVotifier issue, but a bug with the server list.");
|
||||
throw new QuietException(
|
||||
"The VOTE opcode was not present. This is not a NuVotifier issue, but a bug with the server list.");
|
||||
}
|
||||
|
||||
// Create the vote.
|
||||
|
||||
+7
-6
@@ -1,21 +1,20 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.util.GsonInst;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Decodes protocol 2 JSON votes.
|
||||
@@ -44,7 +43,8 @@ public class VotifierProtocol2Decoder extends MessageToMessageDecoder<String> {
|
||||
if (key == null) {
|
||||
key = plugin.getTokens().get("default");
|
||||
if (key == null) {
|
||||
throw new RuntimeException("Unknown service '" + votePayload.get("serviceName").getAsString() + "'");
|
||||
throw new RuntimeException(
|
||||
"Unknown service '" + votePayload.get("serviceName").getAsString() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ public class VotifierProtocol2Decoder extends MessageToMessageDecoder<String> {
|
||||
ctx.pipeline().remove(this);
|
||||
}
|
||||
|
||||
private boolean hmacEqual(byte[] sig, byte[] message, Key key) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
private boolean hmacEqual(byte[] sig, byte[] message, Key key)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
// See https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
|
||||
// This randomizes the byte order to make timing attacks more difficult.
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
|
||||
+19
-6
@@ -8,7 +8,6 @@ import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
@@ -16,7 +15,8 @@ import java.util.List;
|
||||
* Attempts to determine if original protocol or protocol v2 is being used.
|
||||
*/
|
||||
public class VotifierProtocolDifferentiator extends ByteToMessageDecoder {
|
||||
private static final QuietException V2_ONLY = new QuietException("This server only accepts well-formed Votifier v2 packets.");
|
||||
private static final QuietException V2_ONLY =
|
||||
new QuietException("This server only accepts well-formed Votifier v2 packets.");
|
||||
|
||||
private static final short PROTOCOL_2_MAGIC = 0x733A;
|
||||
private final boolean testMode;
|
||||
@@ -45,10 +45,23 @@ public class VotifierProtocolDifferentiator extends ByteToMessageDecoder {
|
||||
session.setVersion(VotifierSession.ProtocolVersion.TWO);
|
||||
|
||||
if (!testMode) {
|
||||
ctx.pipeline().addAfter("protocolDifferentiator", "protocol2LengthDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2, 0, 4));
|
||||
ctx.pipeline().addAfter("protocol2LengthDecoder", "protocol2StringDecoder", new StringDecoder(StandardCharsets.UTF_8));
|
||||
ctx.pipeline().addAfter("protocol2StringDecoder", "protocol2VoteDecoder", new VotifierProtocol2Decoder());
|
||||
ctx.pipeline().addAfter("protocol2VoteDecoder", "protocol2StringEncoder", new StringEncoder(StandardCharsets.UTF_8));
|
||||
ctx.pipeline()
|
||||
.addAfter(
|
||||
"protocolDifferentiator",
|
||||
"protocol2LengthDecoder",
|
||||
new LengthFieldBasedFrameDecoder(1024, 2, 2, 0, 4));
|
||||
ctx.pipeline()
|
||||
.addAfter(
|
||||
"protocol2LengthDecoder",
|
||||
"protocol2StringDecoder",
|
||||
new StringDecoder(StandardCharsets.UTF_8));
|
||||
ctx.pipeline()
|
||||
.addAfter("protocol2StringDecoder", "protocol2VoteDecoder", new VotifierProtocol2Decoder());
|
||||
ctx.pipeline()
|
||||
.addAfter(
|
||||
"protocol2VoteDecoder",
|
||||
"protocol2StringEncoder",
|
||||
new StringEncoder(StandardCharsets.UTF_8));
|
||||
ctx.pipeline().remove(this);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Vex Software LLC
|
||||
* This file is part of Votifier.
|
||||
*
|
||||
*
|
||||
* Votifier is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* Votifier is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Votifier. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.vexsoftware.votifier.net.protocol.v1crypto;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
/**
|
||||
* Static RSA utility methods for encrypting and decrypting blocks of
|
||||
@@ -57,5 +57,4 @@ public class RSA {
|
||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Vex Software LLC
|
||||
* This file is part of Votifier.
|
||||
*
|
||||
*
|
||||
* Votifier is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* Votifier is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Votifier. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.vexsoftware.votifier.net.protocol.v1crypto;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyFactory;
|
||||
@@ -30,6 +29,7 @@ import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* Static utility methods for saving and loading RSA key pairs.
|
||||
@@ -48,12 +48,10 @@ public class RSAIO {
|
||||
PublicKey publicKey = keyPair.getPublic();
|
||||
|
||||
// Store the public and private keys.
|
||||
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(
|
||||
publicKey.getEncoded());
|
||||
PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(
|
||||
privateKey.getEncoded());
|
||||
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(publicKey.getEncoded());
|
||||
PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
|
||||
try (FileOutputStream publicOut = new FileOutputStream(directory + "/public.key");
|
||||
FileOutputStream privateOut = new FileOutputStream(directory + "/private.key")) {
|
||||
FileOutputStream privateOut = new FileOutputStream(directory + "/private.key")) {
|
||||
|
||||
publicOut.write(Base64.getEncoder().encode(publicSpec.getEncoded()));
|
||||
privateOut.write(Base64.getEncoder().encode(privateSpec.getEncoded()));
|
||||
@@ -68,8 +66,11 @@ public class RSAIO {
|
||||
try {
|
||||
return Base64.getDecoder().decode(strContents);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Base64 decoding exception: This is probably due to a corrupted file, " +
|
||||
"but in case it isn't, here is a b64 representation of what we read: " + new String(Base64.getEncoder().encode(contents), StandardCharsets.UTF_8), e);
|
||||
throw new IllegalArgumentException(
|
||||
"Base64 decoding exception: This is probably due to a corrupted file, "
|
||||
+ "but in case it isn't, here is a b64 representation of what we read: "
|
||||
+ new String(Base64.getEncoder().encode(contents), StandardCharsets.UTF_8),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,13 +91,10 @@ public class RSAIO {
|
||||
|
||||
// Instantiate and return the key pair.
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
|
||||
encodedPublicKey);
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
|
||||
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
|
||||
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
|
||||
encodedPrivateKey);
|
||||
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
|
||||
return new KeyPair(publicKey, privateKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Vex Software LLC
|
||||
* This file is part of Votifier.
|
||||
*
|
||||
*
|
||||
* Votifier is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* Votifier is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Votifier. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@@ -36,10 +36,8 @@ public class RSAKeygen {
|
||||
*/
|
||||
public static KeyPair generate(int bits) throws Exception {
|
||||
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
|
||||
RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(bits,
|
||||
RSAKeyGenParameterSpec.F4);
|
||||
RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(bits, RSAKeyGenParameterSpec.F4);
|
||||
keygen.initialize(spec);
|
||||
return keygen.generateKeyPair();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,13 +2,16 @@ package com.vexsoftware.votifier.platform;
|
||||
|
||||
public interface LoggingAdapter {
|
||||
void error(String s);
|
||||
|
||||
void error(String s, Object... o);
|
||||
|
||||
void error(String s, Throwable e, Object... o);
|
||||
|
||||
void warn(String s);
|
||||
|
||||
void warn(String s, Object... o);
|
||||
|
||||
void info(String s);
|
||||
|
||||
void info(String s, Object... o);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.vexsoftware.votifier.platform;
|
||||
import com.vexsoftware.votifier.VoteHandler;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Map;
|
||||
|
||||
-15
@@ -12,21 +12,6 @@ public class ScheduledExecutorServiceVotifierScheduler implements VotifierSchedu
|
||||
this.service = Objects.requireNonNull(service, "service");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask sync(Runnable runnable) {
|
||||
return new ScheduledVotifierTaskWrapper(service.submit(runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask onPool(Runnable runnable) {
|
||||
return new ScheduledVotifierTaskWrapper(service.submit(runnable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask delayedSync(Runnable runnable, int delay, TimeUnit unit) {
|
||||
return new ScheduledVotifierTaskWrapper(service.schedule(runnable, delay, unit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit) {
|
||||
return new ScheduledVotifierTaskWrapper(service.schedule(runnable, delay, unit));
|
||||
|
||||
-5
@@ -3,11 +3,6 @@ package com.vexsoftware.votifier.platform.scheduler;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public interface VotifierScheduler {
|
||||
ScheduledVotifierTask sync(Runnable runnable);
|
||||
|
||||
ScheduledVotifierTask onPool(Runnable runnable);
|
||||
|
||||
ScheduledVotifierTask delayedSync(Runnable runnable, int delay, TimeUnit unit);
|
||||
|
||||
ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit);
|
||||
|
||||
|
||||
+2
-5
@@ -5,7 +5,6 @@ import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
import java.io.CharArrayReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -29,10 +28,8 @@ public abstract class AbstractPluginMessagingForwardingSink implements Forwardin
|
||||
|
||||
while (r.hasNext()) {
|
||||
String name = r.nextName();
|
||||
if (r.peek() == JsonToken.NUMBER)
|
||||
o.add(name, new JsonPrimitive(r.nextLong()));
|
||||
else
|
||||
o.add(name, new JsonPrimitive(r.nextString()));
|
||||
if (r.peek() == JsonToken.NUMBER) o.add(name, new JsonPrimitive(r.nextLong()));
|
||||
else o.add(name, new JsonPrimitive(r.nextString()));
|
||||
}
|
||||
r.endObject();
|
||||
|
||||
|
||||
+56
-42
@@ -5,7 +5,6 @@ import com.vexsoftware.votifier.platform.BackendServer;
|
||||
import com.vexsoftware.votifier.platform.ProxyVotifierPlugin;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.FileVoteCache;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
@@ -16,7 +15,8 @@ import java.util.function.Consumer;
|
||||
|
||||
public abstract class AbstractPluginMessagingForwardingSource implements ForwardingVoteSource {
|
||||
|
||||
public AbstractPluginMessagingForwardingSource(String channel, ServerFilter serverFilter, ProxyVotifierPlugin plugin, VoteCache cache, int dumpRate) {
|
||||
public AbstractPluginMessagingForwardingSource(
|
||||
String channel, ServerFilter serverFilter, ProxyVotifierPlugin plugin, VoteCache cache, int dumpRate) {
|
||||
this.channel = channel;
|
||||
this.plugin = plugin;
|
||||
this.cache = cache;
|
||||
@@ -24,7 +24,8 @@ public abstract class AbstractPluginMessagingForwardingSource implements Forward
|
||||
this.dumpRate = dumpRate;
|
||||
}
|
||||
|
||||
protected AbstractPluginMessagingForwardingSource(String channel, ProxyVotifierPlugin plugin, VoteCache voteCache, int dumpRate) {
|
||||
protected AbstractPluginMessagingForwardingSource(
|
||||
String channel, ProxyVotifierPlugin plugin, VoteCache voteCache, int dumpRate) {
|
||||
this(channel, null, plugin, voteCache, dumpRate);
|
||||
}
|
||||
|
||||
@@ -80,18 +81,17 @@ public abstract class AbstractPluginMessagingForwardingSource implements Forward
|
||||
if (cache == null) return;
|
||||
final Collection<Vote> cachedVotes = cache.evict(server.getName());
|
||||
dumpVotesToServer(cachedVotes, server, "server '" + server + "'", failedVotes -> {
|
||||
for (Vote v : failedVotes)
|
||||
cache.addToCache(v, server.getName());
|
||||
for (Vote v : failedVotes) cache.addToCache(v, server.getName());
|
||||
});
|
||||
}
|
||||
|
||||
protected void attemptToAddToCache(Vote v, String server) {
|
||||
if (cache != null) {
|
||||
cache.addToCache(v, server);
|
||||
if (plugin.isDebug())
|
||||
plugin.getPluginLogger().info("Added to forwarding cache: " + v + " -> " + server);
|
||||
if (plugin.isDebug()) plugin.getPluginLogger().info("Added to forwarding cache: " + v + " -> " + server);
|
||||
} else if (plugin.isDebug())
|
||||
plugin.getPluginLogger().error("Could not immediately send vote to backend, vote lost! " + v + " -> " + server);
|
||||
plugin.getPluginLogger()
|
||||
.error("Could not immediately send vote to backend, vote lost! " + v + " -> " + server);
|
||||
}
|
||||
|
||||
protected void attemptToAddToPlayerCache(Vote v, String player) {
|
||||
@@ -100,48 +100,63 @@ public abstract class AbstractPluginMessagingForwardingSource implements Forward
|
||||
if (plugin.isDebug())
|
||||
plugin.getPluginLogger().info("Added to forwarding cache: " + v + " -> (player) " + player);
|
||||
} else if (plugin.isDebug())
|
||||
plugin.getPluginLogger().error("Could not immediately send vote to backend, vote lost! " + v + " -> (player) " + player);
|
||||
|
||||
plugin.getPluginLogger()
|
||||
.error("Could not immediately send vote to backend, vote lost! " + v + " -> (player) " + player);
|
||||
}
|
||||
|
||||
// returns a collection of failed votes
|
||||
private void dumpVotesToServer(Collection<Vote> cachedVotes, BackendServer target, String identifier, Consumer<Collection<Vote>> cb) {
|
||||
private void dumpVotesToServer(
|
||||
Collection<Vote> cachedVotes, BackendServer target, String identifier, Consumer<Collection<Vote>> cb) {
|
||||
dumpVotesToServer(cachedVotes, target, identifier, 0, cb);
|
||||
}
|
||||
private void dumpVotesToServer(Collection<Vote> cachedVotes, BackendServer target, String identifier, int evictedAlready, Consumer<Collection<Vote>> cb) {
|
||||
|
||||
private void dumpVotesToServer(
|
||||
Collection<Vote> cachedVotes,
|
||||
BackendServer target,
|
||||
String identifier,
|
||||
int evictedAlready,
|
||||
Consumer<Collection<Vote>> cb) {
|
||||
if (!cachedVotes.isEmpty()) {
|
||||
plugin.getScheduler().delayedOnPool(() -> {
|
||||
int evicted = 0;
|
||||
Iterator<Vote> vi = cachedVotes.iterator();
|
||||
Collection<Vote> chunk = new ArrayList<>(dumpRate);
|
||||
while (vi.hasNext() && evicted < dumpRate) {
|
||||
chunk.add(vi.next());
|
||||
vi.remove();
|
||||
}
|
||||
plugin.getScheduler()
|
||||
.delayedOnPool(
|
||||
() -> {
|
||||
int evicted = 0;
|
||||
Iterator<Vote> vi = cachedVotes.iterator();
|
||||
Collection<Vote> chunk = new ArrayList<>(dumpRate);
|
||||
while (vi.hasNext() && evicted < dumpRate) {
|
||||
chunk.add(vi.next());
|
||||
vi.remove();
|
||||
}
|
||||
|
||||
if (forwardSpecific(target, chunk)) {
|
||||
evicted += chunk.size();
|
||||
if (forwardSpecific(target, chunk)) {
|
||||
evicted += chunk.size();
|
||||
|
||||
if (evicted >= dumpRate && !cachedVotes.isEmpty()) {
|
||||
// if we evicted everything we could but still need to evict more
|
||||
dumpVotesToServer(cachedVotes, target, identifier, evictedAlready + evicted, cb);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// so since our forwarding failed, break like we are done
|
||||
cachedVotes.addAll(chunk);
|
||||
}
|
||||
if (evicted >= dumpRate && !cachedVotes.isEmpty()) {
|
||||
// if we evicted everything we could but still need to evict more
|
||||
dumpVotesToServer(
|
||||
cachedVotes, target, identifier, evictedAlready + evicted, cb);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// so since our forwarding failed, break like we are done
|
||||
cachedVotes.addAll(chunk);
|
||||
}
|
||||
|
||||
if (plugin.isDebug()) {
|
||||
plugin.getPluginLogger().info("Successfully evicted " + (evictedAlready + evicted) + " votes to " + identifier + ".");
|
||||
if (!cachedVotes.isEmpty()) {
|
||||
plugin.getPluginLogger().info("Held " + cachedVotes.size() + " votes for " + identifier + ".");
|
||||
}
|
||||
}
|
||||
if (plugin.isDebug()) {
|
||||
plugin.getPluginLogger()
|
||||
.info("Successfully evicted " + (evictedAlready + evicted) + " votes to "
|
||||
+ identifier + ".");
|
||||
if (!cachedVotes.isEmpty()) {
|
||||
plugin.getPluginLogger()
|
||||
.info("Held " + cachedVotes.size() + " votes for " + identifier + ".");
|
||||
}
|
||||
}
|
||||
|
||||
// cachedVotes contains any votes which have yet to be evicted
|
||||
cb.accept(cachedVotes);
|
||||
}, evictedAlready == 0 ? 3 : 1, TimeUnit.SECONDS);
|
||||
// cachedVotes contains any votes which have yet to be evicted
|
||||
cb.accept(cachedVotes);
|
||||
},
|
||||
evictedAlready == 0 ? 3 : 1,
|
||||
TimeUnit.SECONDS);
|
||||
} else {
|
||||
cb.accept(cachedVotes);
|
||||
}
|
||||
@@ -153,8 +168,7 @@ public abstract class AbstractPluginMessagingForwardingSource implements Forward
|
||||
|
||||
final Collection<Vote> cachedVotes = cache.evictPlayer(playerName);
|
||||
dumpVotesToServer(cachedVotes, server, "player '" + playerName + "'", failedVotes -> {
|
||||
for (Vote v : failedVotes)
|
||||
cache.addToCachePlayer(v, playerName);
|
||||
for (Vote v : failedVotes) cache.addToCachePlayer(v, playerName);
|
||||
});
|
||||
}
|
||||
}
|
||||
-1
@@ -13,5 +13,4 @@ public interface ForwardedVoteListener {
|
||||
* @param v Vote that was forwarded
|
||||
*/
|
||||
void onForward(Vote v);
|
||||
|
||||
}
|
||||
-1
@@ -9,5 +9,4 @@ public interface ForwardingVoteSink {
|
||||
* Stop or close any oustanding network interfaces. Occurs on the onDisable method of a plugin.
|
||||
*/
|
||||
void halt();
|
||||
|
||||
}
|
||||
-1
@@ -18,5 +18,4 @@ public interface ForwardingVoteSource {
|
||||
* Stop or close any oustanding network interfaces. Occurs on the onDisable method of a plugin.
|
||||
*/
|
||||
void halt();
|
||||
|
||||
}
|
||||
+20
-20
@@ -7,7 +7,6 @@ import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask;
|
||||
import com.vexsoftware.votifier.util.GsonInst;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@@ -28,13 +27,18 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
|
||||
load();
|
||||
|
||||
saveTask = plugin.getScheduler().repeatOnPool(() -> {
|
||||
try {
|
||||
save();
|
||||
} catch (IOException e) {
|
||||
l.error("Unable to save cached votes, votes will be lost if you restart.", e);
|
||||
}
|
||||
}, 3, 3, TimeUnit.MINUTES);
|
||||
saveTask = plugin.getScheduler()
|
||||
.repeatOnPool(
|
||||
() -> {
|
||||
try {
|
||||
save();
|
||||
} catch (IOException e) {
|
||||
l.error("Unable to save cached votes, votes will be lost if you restart.", e);
|
||||
}
|
||||
},
|
||||
3,
|
||||
3,
|
||||
TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private static Set<String> keySet(JsonObject object) {
|
||||
@@ -71,7 +75,8 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
}
|
||||
|
||||
if (object.get("version").getAsInt() != 2)
|
||||
throw new IllegalStateException("Could not read cache file! Unknown version '" + object.get("version").getAsInt() + "' read.");
|
||||
throw new IllegalStateException("Could not read cache file! Unknown version '"
|
||||
+ object.get("version").getAsInt() + "' read.");
|
||||
|
||||
JsonObject players = object.getAsJsonObject("players");
|
||||
JsonObject servers = object.getAsJsonObject("servers");
|
||||
@@ -88,8 +93,7 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
File replacementFile;
|
||||
for (int i = 0; ; i++) {
|
||||
replacementFile = new File(cacheFile.getParentFile(), cacheFile.getName() + ".bak." + i);
|
||||
if (!replacementFile.exists())
|
||||
break;
|
||||
if (!replacementFile.exists()) break;
|
||||
}
|
||||
|
||||
if (!cacheFile.renameTo(replacementFile)) {
|
||||
@@ -107,10 +111,8 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
for (int i = 0; i < voteArray.size(); i++) {
|
||||
JsonObject voteObject = voteArray.get(i).getAsJsonObject();
|
||||
VoteWithRecordedTimestamp v = new VoteWithRecordedTimestamp(voteObject);
|
||||
if (hasTimedOut(v))
|
||||
l.warn("Purging out of date vote.", v);
|
||||
else
|
||||
votes.add(v);
|
||||
if (hasTimedOut(v)) l.warn("Purging out of date vote.", v);
|
||||
else votes.add(v);
|
||||
}
|
||||
return votes;
|
||||
}
|
||||
@@ -135,7 +137,8 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
public JsonObject serializeMap(Map<String, Collection<VoteWithRecordedTimestamp>> map) {
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
Iterator<Map.Entry<String, Collection<VoteWithRecordedTimestamp>>> entryItr = map.entrySet().iterator();
|
||||
Iterator<Map.Entry<String, Collection<VoteWithRecordedTimestamp>>> entryItr =
|
||||
map.entrySet().iterator();
|
||||
while (entryItr.hasNext()) {
|
||||
Map.Entry<String, Collection<VoteWithRecordedTimestamp>> entry = entryItr.next();
|
||||
JsonArray array = new JsonArray();
|
||||
@@ -150,18 +153,15 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
} else {
|
||||
array.add(vote.serialize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if, during our iteration, we TTL invalidated all of the votes
|
||||
if (entry.getValue().isEmpty())
|
||||
entryItr.remove();
|
||||
if (entry.getValue().isEmpty()) entryItr.remove();
|
||||
o.add(entry.getKey(), array);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
public void halt() throws IOException {
|
||||
saveTask.cancel();
|
||||
save();
|
||||
|
||||
Vendored
-1
@@ -5,7 +5,6 @@ import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
+2
-4
@@ -1,7 +1,6 @@
|
||||
package com.vexsoftware.votifier.support.forwarding.cache;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -32,8 +31,7 @@ public interface VoteCache {
|
||||
* @param v Vote to add to the cache
|
||||
* @param player Server to add vote under
|
||||
*/
|
||||
default void addToCachePlayer(Vote v, String player) {
|
||||
}
|
||||
default void addToCachePlayer(Vote v, String player) {}
|
||||
|
||||
/**
|
||||
* Evicts all votes from the vote cache and returns a collection of vote objects
|
||||
@@ -51,6 +49,6 @@ public interface VoteCache {
|
||||
* @return A collection of all votes which were previously in the cache under the player
|
||||
*/
|
||||
default Collection<Vote> evictPlayer(String player) {
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+29
-20
@@ -1,12 +1,12 @@
|
||||
package com.vexsoftware.votifier.support.forwarding.proxy;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardingVoteSource;
|
||||
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
|
||||
import com.vexsoftware.votifier.support.forwarding.proxy.client.VotifierProtocol2Encoder;
|
||||
import com.vexsoftware.votifier.support.forwarding.proxy.client.VotifierProtocol2HandshakeHandler;
|
||||
import com.vexsoftware.votifier.support.forwarding.proxy.client.VotifierResponseHandler;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
@@ -15,7 +15,6 @@ import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
@@ -32,7 +31,11 @@ public class ProxyForwardingVoteSource implements ForwardingVoteSource {
|
||||
|
||||
private static final StringDecoder STRING_DECODER = new StringDecoder(StandardCharsets.US_ASCII);
|
||||
|
||||
public ProxyForwardingVoteSource(VotifierPlugin plugin, Supplier<Bootstrap> nettyBootstrap, List<BackendServer> backendServers, VoteCache voteCache) {
|
||||
public ProxyForwardingVoteSource(
|
||||
VotifierPlugin plugin,
|
||||
Supplier<Bootstrap> nettyBootstrap,
|
||||
List<BackendServer> backendServers,
|
||||
VoteCache voteCache) {
|
||||
this.plugin = plugin;
|
||||
this.nettyBootstrap = nettyBootstrap;
|
||||
this.backendServers = backendServers;
|
||||
@@ -52,27 +55,35 @@ public class ProxyForwardingVoteSource implements ForwardingVoteSource {
|
||||
}
|
||||
|
||||
private void forwardVote(final BackendServer server, final Vote v, final int tries) {
|
||||
nettyBootstrap.get()
|
||||
nettyBootstrap
|
||||
.get()
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel) {
|
||||
channel.pipeline().addLast(new DelimiterBasedFrameDecoder(256, true, Delimiters.lineDelimiter()));
|
||||
channel.pipeline()
|
||||
.addLast(new DelimiterBasedFrameDecoder(256, true, Delimiters.lineDelimiter()));
|
||||
channel.pipeline().addLast(new ReadTimeoutHandler(5, TimeUnit.SECONDS));
|
||||
channel.pipeline().addLast(STRING_DECODER);
|
||||
channel.pipeline().addLast(new VotifierProtocol2Encoder(server.key));
|
||||
channel.pipeline().addLast(new VotifierProtocol2HandshakeHandler(v, new VotifierResponseHandler() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
if (plugin.isDebug()) {
|
||||
plugin.getPluginLogger().info("Successfully forwarded vote " + v + " to " + server.address + ".");
|
||||
}
|
||||
}
|
||||
channel.pipeline()
|
||||
.addLast(new VotifierProtocol2HandshakeHandler(
|
||||
v,
|
||||
new VotifierResponseHandler() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
if (plugin.isDebug()) {
|
||||
plugin.getPluginLogger()
|
||||
.info("Successfully forwarded vote " + v + " to "
|
||||
+ server.address + ".");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable error) {
|
||||
handleFailure(server, v, error, tries);
|
||||
}
|
||||
}, plugin));
|
||||
@Override
|
||||
public void onFailure(Throwable error) {
|
||||
handleFailure(server, v, error, tries);
|
||||
}
|
||||
},
|
||||
plugin));
|
||||
}
|
||||
})
|
||||
.connect(server.address)
|
||||
@@ -110,9 +121,7 @@ public class ProxyForwardingVoteSource implements ForwardingVoteSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void halt() {
|
||||
|
||||
}
|
||||
public void halt() {}
|
||||
|
||||
public static class BackendServer {
|
||||
private final String name;
|
||||
|
||||
+1
-4
@@ -21,9 +21,6 @@ public class VoteRequest {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VoteRequest{" +
|
||||
"challenge='" + challenge + '\'' +
|
||||
", vote=" + vote +
|
||||
'}';
|
||||
return "VoteRequest{" + "challenge='" + challenge + '\'' + ", vote=" + vote + '}';
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -5,11 +5,10 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.util.Base64;
|
||||
import javax.crypto.Mac;
|
||||
|
||||
public class VotifierProtocol2Encoder extends MessageToByteEncoder<VoteRequest> {
|
||||
private static final short MAGIC = 0x733A;
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package com.vexsoftware.votifier.support.forwarding.proxy.client;
|
||||
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
@@ -11,7 +11,8 @@ public class VotifierProtocol2HandshakeHandler extends SimpleChannelInboundHandl
|
||||
private final VotifierResponseHandler responseHandler;
|
||||
private final VotifierPlugin nuVotifier;
|
||||
|
||||
public VotifierProtocol2HandshakeHandler(Vote toSend, VotifierResponseHandler responseHandler, VotifierPlugin nuVotifier) {
|
||||
public VotifierProtocol2HandshakeHandler(
|
||||
Vote toSend, VotifierResponseHandler responseHandler, VotifierPlugin nuVotifier) {
|
||||
this.toSend = toSend;
|
||||
this.responseHandler = responseHandler;
|
||||
this.nuVotifier = nuVotifier;
|
||||
@@ -33,7 +34,6 @@ public class VotifierProtocol2HandshakeHandler extends SimpleChannelInboundHandl
|
||||
ctx.pipeline().remove(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
responseHandler.onFailure(cause);
|
||||
|
||||
+3
-2
@@ -19,8 +19,9 @@ public class VotifierProtocol2ResponseHandler extends SimpleChannelInboundHandle
|
||||
if (status.equals("ok")) {
|
||||
responseHandler.onSuccess();
|
||||
} else {
|
||||
responseHandler.onFailure(new Exception("Remote server error: " + object.get("cause").getAsString() +
|
||||
": " + object.get("error").getAsString()));
|
||||
responseHandler.onFailure(
|
||||
new Exception("Remote server error: " + object.get("cause").getAsString() + ": "
|
||||
+ object.get("error").getAsString()));
|
||||
}
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.vexsoftware.votifier.util;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -10,7 +9,7 @@ public class ArgsToVote {
|
||||
|
||||
private static final Pattern argumentPattern = Pattern.compile("([a-zA-Z]+)=(\\S*)");
|
||||
|
||||
public static Vote parse(String[] arguments) {
|
||||
public static Vote parse(String[] arguments) {
|
||||
return parse(arguments, null);
|
||||
}
|
||||
|
||||
@@ -32,7 +31,8 @@ public class ArgsToVote {
|
||||
break;
|
||||
case "username":
|
||||
if (v.length() > 16)
|
||||
throw new IllegalArgumentException("Illegal username - must be less than 16 characters long.");
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal username - must be less than 16 characters long.");
|
||||
username = v;
|
||||
break;
|
||||
case "address":
|
||||
@@ -42,8 +42,7 @@ public class ArgsToVote {
|
||||
timestamp = v;
|
||||
break;
|
||||
default:
|
||||
if (additionalArgs != null)
|
||||
additionalArgs.put(key, v);
|
||||
if (additionalArgs != null) additionalArgs.put(key, v);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -54,8 +53,7 @@ public class ArgsToVote {
|
||||
}
|
||||
}
|
||||
|
||||
if (username == null)
|
||||
throw new IllegalArgumentException("Username not specified!");
|
||||
if (username == null) throw new IllegalArgumentException("Username not specified!");
|
||||
|
||||
return new Vote(serviceName, username, address, timestamp);
|
||||
}
|
||||
|
||||
@@ -6,5 +6,4 @@ import com.google.gson.GsonBuilder;
|
||||
public class GsonInst {
|
||||
|
||||
public static final Gson gson = new GsonBuilder().create();
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.vexsoftware.votifier.util;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class KeyCreator {
|
||||
public static Key createKeyFrom(String token) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.vexsoftware.votifier.util;
|
||||
|
||||
public class QuietException extends Exception {
|
||||
public QuietException() {
|
||||
}
|
||||
public QuietException() {}
|
||||
|
||||
public QuietException(String s) {
|
||||
super(s);
|
||||
|
||||
@@ -4,9 +4,7 @@ import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class TokenUtil {
|
||||
private TokenUtil() {
|
||||
|
||||
}
|
||||
private TokenUtil() {}
|
||||
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
|
||||
+4
-3
@@ -8,7 +8,6 @@ import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.platform.scheduler.ScheduledExecutorServiceVotifierScheduler;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
@@ -27,7 +26,8 @@ public class StandaloneVotifierPlugin implements VotifierPlugin {
|
||||
private final VotifierScheduler scheduler;
|
||||
private VotifierServerBootstrap bootstrap;
|
||||
|
||||
public StandaloneVotifierPlugin(Map<String, Key> tokens, VoteReceiver receiver, KeyPair v1Key, InetSocketAddress bind) {
|
||||
public StandaloneVotifierPlugin(
|
||||
Map<String, Key> tokens, VoteReceiver receiver, KeyPair v1Key, InetSocketAddress bind) {
|
||||
this.receiver = receiver;
|
||||
this.bind = bind;
|
||||
this.tokens = Collections.unmodifiableMap(new HashMap<>(tokens));
|
||||
@@ -68,7 +68,8 @@ public class StandaloneVotifierPlugin implements VotifierPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) throws Exception {
|
||||
public void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress)
|
||||
throws Exception {
|
||||
receiver.onVote(vote);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,5 +4,6 @@ import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
public interface VoteReceiver {
|
||||
void onVote(Vote vote) throws Exception;
|
||||
|
||||
void onException(Throwable throwable);
|
||||
}
|
||||
-1
@@ -2,7 +2,6 @@ package com.vexsoftware.votifier.util.standalone;
|
||||
|
||||
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAIO;
|
||||
import com.vexsoftware.votifier.util.KeyCreator;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.Key;
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import com.vexsoftware.votifier.util.KeyCreator;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestVotifierPlugin implements VotifierPlugin {
|
||||
private static final byte[] PUBLIC_KEY;
|
||||
private static final byte[] PRIVATE_KEY;
|
||||
|
||||
static byte[] r(String u) throws Exception {
|
||||
URL resourceUrl = TestVotifierPlugin.class.getResource(u);
|
||||
Path resourcePath = Paths.get(resourceUrl.toURI());
|
||||
|
||||
return Base64.getDecoder().decode(new String(Files.readAllBytes(resourcePath), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
PUBLIC_KEY = r("/public.key");
|
||||
PRIVATE_KEY = r("/private.key");
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final TestVotifierPlugin I = new TestVotifierPlugin();
|
||||
|
||||
public static TestVotifierPlugin getI() {
|
||||
return I;
|
||||
}
|
||||
|
||||
private final Map<String, Key> keyMap = new HashMap<>();
|
||||
private final KeyPair keyPair;
|
||||
|
||||
public TestVotifierPlugin() {
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
|
||||
PUBLIC_KEY);
|
||||
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
|
||||
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
|
||||
PRIVATE_KEY);
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
|
||||
keyPair = new KeyPair(publicKey, privateKey);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
keyMap.put("default", KeyCreator.createKeyFrom("test"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Key> getTokens() {
|
||||
return keyMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair getProtocolV1Key() {
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggingAdapter getPluginLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VotifierScheduler getScheduler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebug() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void specificKeysOnly() {
|
||||
keyMap.clear();
|
||||
keyMap.put("Test", KeyCreator.createKeyFrom("test"));
|
||||
}
|
||||
|
||||
public void restoreDefault() {
|
||||
keyMap.clear();
|
||||
keyMap.put("default", KeyCreator.createKeyFrom("test"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.protocol.v1crypto.RSA;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VoteUtil {
|
||||
public static byte[] encodePOJOv1(Vote vote) throws Exception {
|
||||
return encodePOJOv1(vote, TestVotifierPlugin.getI().getProtocolV1Key().getPublic());
|
||||
}
|
||||
|
||||
public static byte[] encodePOJOv1(Vote vote, PublicKey key) throws Exception {
|
||||
List<String> ordered = new ArrayList<>();
|
||||
ordered.add("VOTE");
|
||||
ordered.add(vote.getServiceName());
|
||||
ordered.add(vote.getUsername());
|
||||
ordered.add(vote.getAddress());
|
||||
ordered.add(vote.getTimeStamp());
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String s : ordered) {
|
||||
builder.append(s).append('\n'); // naive join needed!
|
||||
}
|
||||
|
||||
return RSA.encrypt(builder.toString().getBytes(StandardCharsets.US_ASCII), key);
|
||||
}
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.net.protocol.v1crypto.RSA;
|
||||
import com.vexsoftware.votifier.util.QuietException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VotifierProtocol1DecoderTest {
|
||||
private static final VotifierSession SESSION = new VotifierSession();
|
||||
|
||||
private EmbeddedChannel createChannel() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocol1Decoder());
|
||||
channel.attr(VotifierSession.KEY).set(SESSION);
|
||||
channel.attr(VotifierPlugin.KEY).set(TestVotifierPlugin.getI());
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulDecode() throws Exception {
|
||||
Vote votePojo = new Vote("Test", "test", "test", "test");
|
||||
|
||||
// Send the vote
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
byte[] encrypted = VoteUtil.encodePOJOv1(votePojo);
|
||||
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
|
||||
|
||||
assertTrue(channel.writeInbound(encryptedByteBuf));
|
||||
Object presumedVote = channel.readInbound();
|
||||
assertEquals(votePojo, presumedVote);
|
||||
assertFalse(channel.finish());
|
||||
}
|
||||
|
||||
private void verifyFailure(String bad) throws Exception {
|
||||
// Send the bad vote
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
byte[] encrypted = RSA.encrypt(bad.getBytes(StandardCharsets.UTF_8), TestVotifierPlugin.getI().getProtocolV1Key().getPublic());
|
||||
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
|
||||
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(encryptedByteBuf));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeMissingField() throws Exception {
|
||||
verifyFailure("VOTE\nTest\ntest\ntest"); // missing field
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeBadOpcode() throws Exception {
|
||||
verifyFailure("TEST\nTest\ntest\ntest\ntest\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeBadRsa() throws Exception {
|
||||
// Decode our bad RSA key
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(TestVotifierPlugin.r("/bad_public.key"));
|
||||
PublicKey badPublicKey = keyFactory.generatePublic(publicKeySpec);
|
||||
|
||||
// Send the bad vote
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
byte[] encrypted = VoteUtil.encodePOJOv1(new Vote("Test", "test", "test", "test"), badPublicKey);
|
||||
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
|
||||
|
||||
assertThrows(DecoderException.class, ()->channel.writeInbound(encryptedByteBuf));
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.util.GsonInst;
|
||||
import com.vexsoftware.votifier.util.KeyCreator;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VotifierProtocol2DecoderTest {
|
||||
private static final VotifierSession SESSION = new VotifierSession();
|
||||
|
||||
private EmbeddedChannel createChannel() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocol2Decoder());
|
||||
channel.attr(VotifierSession.KEY).set(SESSION);
|
||||
channel.attr(VotifierPlugin.KEY).set(TestVotifierPlugin.getI());
|
||||
return channel;
|
||||
}
|
||||
|
||||
private void sendVote(Vote vote, Key key, boolean expectSuccess) throws Exception {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
JsonObject payload = vote.serialize();
|
||||
payload.addProperty("challenge", SESSION.getChallenge());
|
||||
String payloadEncoded = GsonInst.gson.toJson(payload);
|
||||
object.put("payload", payloadEncoded);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(key);
|
||||
object.put("signature",
|
||||
Base64.getEncoder().encodeToString(mac.doFinal(payloadEncoded.getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
if (expectSuccess) {
|
||||
assertTrue(channel.writeInbound(object.toString()));
|
||||
assertEquals(vote, channel.readInbound());
|
||||
assertFalse(channel.finish());
|
||||
} else {
|
||||
try {
|
||||
channel.writeInbound(object.toString());
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulDecode() throws Exception {
|
||||
sendVote(new Vote("Test", "test", "test", "0"), TestVotifierPlugin.getI().getTokens().get("default"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeBadPacket() {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
Vote vote = new Vote("Test", "test", "test", "0");
|
||||
JSONObject object = new JSONObject();
|
||||
JsonObject payload = vote.serialize();
|
||||
payload.addProperty("challenge", SESSION.getChallenge());
|
||||
object.put("payload", GsonInst.gson.toJson(payload));
|
||||
// We "forget" the signature.
|
||||
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(object.toString()));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeBadVoteField() throws Exception {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
Vote vote = new Vote("Test", "test", "test", "0");
|
||||
JSONObject object = new JSONObject();
|
||||
JsonObject payload = vote.serialize();
|
||||
String payloadEncoded = GsonInst.gson.toJson(payload);
|
||||
// We "forget" the challenge.
|
||||
object.put("payload", payloadEncoded);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(TestVotifierPlugin.getI().getTokens().get("default"));
|
||||
object.put("signature",
|
||||
Base64.getEncoder().encodeToString(mac.doFinal(payloadEncoded.getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(object.toString()));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeBadChallenge() throws Exception {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
|
||||
Vote vote = new Vote("Test", "test", "test", "0");
|
||||
JSONObject object = new JSONObject();
|
||||
JsonObject payload = vote.serialize();
|
||||
// We provide the wrong challenge.
|
||||
payload.addProperty("challenge", "not a challenge for me");
|
||||
object.put("payload", payload.toString());
|
||||
String payloadEncoded = GsonInst.gson.toJson(payload);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(TestVotifierPlugin.getI().getTokens().get("default"));
|
||||
object.put("signature",
|
||||
Base64.getEncoder().encode(mac.doFinal(payloadEncoded.getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(object.toString()));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeNonExistentKey() throws Exception {
|
||||
TestVotifierPlugin.getI().specificKeysOnly();
|
||||
|
||||
Vote vote = new Vote("Bad Service", "test", "test", "0");
|
||||
|
||||
assertThrows(DecoderException.class, () -> sendVote(vote, TestVotifierPlugin.getI().getTokens().get("Test"), false));
|
||||
|
||||
TestVotifierPlugin.getI().restoreDefault();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureDecodeBadSignature() {
|
||||
Vote vote = new Vote("Bad Service", "test", "test", "0");
|
||||
assertThrows(CorruptedFrameException.class, () -> sendVote(vote, KeyCreator.createKeyFrom("BadKey"), false));
|
||||
}
|
||||
}
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
package com.vexsoftware.votifier.net.protocol;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.util.QuietException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class VotifierProtocolDifferentiatorTest {
|
||||
@Test
|
||||
public void v1Test() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, true));
|
||||
|
||||
VotifierSession session = new VotifierSession();
|
||||
channel.attr(VotifierSession.KEY).set(session);
|
||||
|
||||
ByteBuf test = Unpooled.buffer(256);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
test.writeByte(0);
|
||||
}
|
||||
channel.writeInbound(test);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.ONE, session.getVersion());
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v2Test() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, false));
|
||||
|
||||
VotifierSession session = new VotifierSession();
|
||||
channel.attr(VotifierSession.KEY).set(session);
|
||||
|
||||
ByteBuf test = Unpooled.buffer();
|
||||
test.writeShort(0x733A);
|
||||
channel.writeInbound(test);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.TWO, session.getVersion());
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failIfv1NotSupported() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, false));
|
||||
|
||||
VotifierSession session = new VotifierSession();
|
||||
channel.attr(VotifierSession.KEY).set(session);
|
||||
|
||||
ByteBuf test = Unpooled.buffer(256);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
test.writeByte(0);
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(test));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failOnBadPacketTest() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, false));
|
||||
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
buf.writeByte(0);
|
||||
}
|
||||
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(buf));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryIdentifyRealVotev1() throws Exception {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, true));
|
||||
|
||||
VotifierSession session = new VotifierSession();
|
||||
channel.attr(VotifierSession.KEY).set(session);
|
||||
|
||||
Vote votePojo = new Vote("Test", "test", "test", "test");
|
||||
byte[] encrypted = VoteUtil.encodePOJOv1(votePojo);
|
||||
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
|
||||
|
||||
channel.writeInbound(encryptedByteBuf);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.ONE, session.getVersion());
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package com.vexsoftware.votifier.support.forwarding;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class PMForwardingSinkTest {
|
||||
|
||||
@Test
|
||||
public void testSuccessfulMultiDecode() throws Exception {
|
||||
List<Vote> receivedVotes = new ArrayList<>();
|
||||
ForwardedVoteListener vl = receivedVotes::add;
|
||||
|
||||
List<Vote> sentVotes = new ArrayList<>(Arrays.asList(
|
||||
new Vote("serviceA", "usernameA", "1.1.1.1", "1546300800"),
|
||||
new Vote("serviceB", "usernameBBBBBBB", "1.2.23.4", "1514764800")
|
||||
));
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
for (Vote v : sentVotes) {
|
||||
message.append(v.serialize());
|
||||
}
|
||||
|
||||
byte[] messageBytes = message.toString().getBytes(StandardCharsets.UTF_8);
|
||||
System.out.println(message.toString());
|
||||
|
||||
AbstractPluginMessagingForwardingSink sink = new AbstractPluginMessagingForwardingSink(vl) {
|
||||
@Override
|
||||
public void halt() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
sink.handlePluginMessage(messageBytes);
|
||||
|
||||
assertEquals(sentVotes.size(), receivedVotes.size());
|
||||
|
||||
for (int i = 0; i < receivedVotes.size(); i++) {
|
||||
assertEquals(sentVotes.get(i), receivedVotes.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.vexsoftware.votifier.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ArgsToVoteTest {
|
||||
@Test
|
||||
void handlesInvalidRequest() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
ArgsToVote.parse(new String[0]);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesSingleUsername() {
|
||||
Vote vote = ArgsToVote.parse(new String[] { "dummy_user" });
|
||||
assertEquals("dummy_user", vote.getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesSingleUsernameTooLong() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
ArgsToVote.parse(new String[] { "AVeryVeryVeryLongUsername" });
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "servicename", "address", "timestamp" })
|
||||
void handlesAdditionalKeywordArguments(String key) throws Exception {
|
||||
Vote vote = ArgsToVote.parse(new String[] { "username=abc123", key + "=dummy" });
|
||||
|
||||
// Find the getter on the Vote object
|
||||
for (Method method : Vote.class.getDeclaredMethods()) {
|
||||
if (method.getName().toLowerCase(Locale.ENGLISH).equals("get" + key) && method.getParameterCount() == 0) {
|
||||
assertEquals("dummy", method.invoke(vote));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fail("Unable to find appropriate getter - this is a bug");
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesUsernameKeywordArgument() {
|
||||
Vote vote = ArgsToVote.parse(new String[] { "username=dummy_user" });
|
||||
assertEquals("dummy_user", vote.getUsername());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "servicename", "address", "timestamp" })
|
||||
void handlesMixedUsernameAndKeywordArgument(String key) throws Exception {
|
||||
Vote vote = ArgsToVote.parse(new String[] { "abc123", key + "=dummy" });
|
||||
|
||||
assertEquals("abc123", vote.getUsername());
|
||||
|
||||
// Find the getter on the Vote object
|
||||
for (Method method : Vote.class.getDeclaredMethods()) {
|
||||
if (method.getName().toLowerCase(Locale.ENGLISH).equals("get" + key) && method.getParameterCount() == 0) {
|
||||
assertEquals("dummy", method.invoke(vote));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fail("Unable to find appropriate getter - this is a bug");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("powerSetArgs")
|
||||
void handlesMixedKeywordArguments(Set<String> keys) throws Exception {
|
||||
String[] args = new String[keys.size() + 1];
|
||||
args[0] = "abc123";
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
args[i + 1] = ImmutableList.copyOf(keys).get(i) + "=dummy";
|
||||
}
|
||||
Vote vote = ArgsToVote.parse(args);
|
||||
|
||||
assertEquals("abc123", vote.getUsername());
|
||||
|
||||
// Find the getters on the Vote object
|
||||
outer: for (String key : keys) {
|
||||
for (Method method : Vote.class.getDeclaredMethods()) {
|
||||
if (method.getName().toLowerCase(Locale.ENGLISH).equals("get" + key) && method.getParameterCount() == 0) {
|
||||
assertEquals("dummy", method.invoke(vote));
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
fail("Unable to find appropriate getter - this is a bug");
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream<Set<String>> powerSetArgs() {
|
||||
return Sets.powerSet(ImmutableSet.of("servicename", "address", "timestamp")).stream();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArrOsFuGPoHDZEFRHXriZRqrUXXjUOhVabC0Xu+WPtVbQrvNngN0igo0ZJIZELflhsFNBUJAnREo+wColfDg1rk2juEUYDt+gRzrN3WiqgzZolF3E4Dg4LrXh6cPuu4AeOZW9CtjXt2JwPBhlWLZb2RFhA6FziFLeMBa42/5VLFCQAmiuuU3OCiBskR3Jz/E5zqc7V/j247OMm+WRJ/k8OFTEFB+zFINOZY1ud3ltwkzQIPi1luGNW8Yt8+CEg/6hDiVlpFwgsazt4uKI/UfU5oP0kAKjQUfFGvNaBtJ0RlsBeJ7VDpOfIG6dDb8pe4IaA9aJLVcXWEn30pHsyYl2NwIDAQAB
|
||||
@@ -1 +0,0 @@
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCd5osoNvoLM52pN8U15QkRXpGVxk0WaoNLWgN24pnW30FIAO3bp8qD2FXJzX2hvw43LIwudVEbwmdzeytVWDNuigLqEsJJsXCHh9ORKjGVHvS240r6idfxJ139Jz2d3oSZG8acHdHgs/H/M98O8lz9Zb2KHtm+rxpiwsV2SdhMtfMDJmRx4p0JklgJ8TV1ZApoypbGtRKXHOirVSs6zfgaYaeglUNITAgsZZNZk+j9Pp572FxyYryxkUaWVn09RAD07XvWKJc3f7NBElA2LpuZXTYJh3BXaI/N05tdgPej5o99PXaA2UMhdqo778zoQoeWzOvbNMUqZROqGW5WDwhdAgMBAAECggEAM8xcXB3k2uXc05UrCaoP1nXadnKt+SuJ1J87wbVGWDm21aMQZF1fzu6Z/fB+RSBCzpC7j8YGjH+ypiyCo6WigaGeoSD0QW6HBr7lBZr81vlnt9NKVnP/tel/KLvFt9M2Vm/JMI+LuRXuzhQ7GVEidjH5AqVqMuaIVlukoVBKN6d20KihcHeCjOZLAoL727QYGrHNr0eH9wQpgMzj3A51ubi5ma3bDvnSvN4ZoP3BhmDTRVnHEh4hx/XFYELi3RDGN2SDjegNXlZ+e03BHCGRryOCuwY1eua78gkrWN8sr3QAdWhEN/Pdwq0BpVsdsbyPzmgoamAMmBbKyBnEJxuvlQKBgQDtLQIhFVYA7vNtpwnXV3ahyEPCNf+tLJYsLYjKWRpoTw6bI3FfgMAEPGbDXLsmLi37mvRmCJpoU9j4nfRd/umoEIW6xuaYDdGRpyaiOlkEXyJd0n3uv/3mF7VtyltrPK3Mt2Gb7kGaZqe07B4a5UC02CCvpKqpbFfC0XxHP32GkwKBgQCqbs2D/pNcdA9iHm+AhX/oylK+BfiruTvLx/c2wOFleQOiNZUZCC6zELIDzuQXPlk9mlNshnciIItcjnyLGkDr2lvJpt6Bi65Jx5hYhlWrms883/hRUSjgKtJ9PFWl8wUVTJJsrOg0fm2ZM+YXpO9AvziRTEPj2MeibQjjlfsbTwKBgHc1ZBiUzMFzWM8IYh3mTC5MpiH7WiMEggZ6bIKn/mnnMoQvcFB8OgbnBQ+0kCxEkcAgxi5yrIk7e5aabbTA51gd1dlnF4fdijQXO4fWo99aob9eiQVzYn4/9GTWjNR9jy2SDnF9c2PTrP92njsOd1NuPh+KOG0nk4TMHhcBhmoZAoGAF4ZPy8ZZ5MsITIzS6zSCIUm7/gqo9lsNC+XAE8iv0+fOPpeSyu+8Mm89gxUNmr+6Zaxlk3dD/mvrkI0CV9j52RQ80yq7T7pOBlUMjDuOm680p7xqdB71u2ttvmeTkuJmczgshd+f9Y715c2qFt1nQNKkJjoWrN6BP8Q5E+Dh1jUCgYEApBuFGwmcSob6rIzinM4nJRyMLXqIy6nKCy8bBLkWCFPGztjIxhKBA/pErADhkLaLyM5reeMPNBbxruAFJ3mzfOneKf9lt0oHq2/jq0vJvYUj9tZjD2Sw6dhj0JqQhKIkhux1rU1xAAedY21JGTS+Be0dFfSv5uDrErPJiN+Qyt0=
|
||||
@@ -1 +0,0 @@
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAneaLKDb6CzOdqTfFNeUJEV6RlcZNFmqDS1oDduKZ1t9BSADt26fKg9hVyc19ob8ONyyMLnVRG8Jnc3srVVgzbooC6hLCSbFwh4fTkSoxlR70tuNK+onX8Sdd/Sc9nd6EmRvGnB3R4LPx/zPfDvJc/WW9ih7Zvq8aYsLFdknYTLXzAyZkceKdCZJYCfE1dWQKaMqWxrUSlxzoq1UrOs34GmGnoJVDSEwILGWTWZPo/T6ee9hccmK8sZFGllZ9PUQA9O171iiXN3+zQRJQNi6bmV02CYdwV2iPzdObXYD3o+aPfT12gNlDIXaqO+/M6EKHlszr2zTFKmUTqhluVg8IXQIDAQAB
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
<module name="Checker">
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<module name="FinalLocalVariable"/>
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="Indentation">
|
||||
<property name="severity" value="ignore"/>
|
||||
</module>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\borg\.junit\.jupiter\.api\.Assertions\.fail\s*\(\s*"Not yet implemented"\s*\)\s*;"/>
|
||||
<property name="message" value="Remove placeholder fail() and implement the test."/>
|
||||
<property name="ignoreCase" value="true"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="(?<!\w)fail\s*\(\s*"Not yet implemented"\s*\)\s*;"/>
|
||||
<property name="message" value="Remove placeholder fail() and implement the test."/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="23">
|
||||
<profile kind="CodeFormatterProfile" name="TrueOG Network Formatting" version="23">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case_after_arrow" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="20"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line_on_wrap"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
@@ -1 +0,0 @@
|
||||
resources/
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
.PHONY: clean all run
|
||||
|
||||
all : resources/paper.jar resources/waterfall.jar resources/velocity.jar resources/sponge.jar resources/viaversion.jar
|
||||
|
||||
resources :
|
||||
mkdir resources
|
||||
|
||||
resources/paper.jar : resources
|
||||
wget -O resources/paper.jar https://papermc.io/api/v1/paper/1.16.2/182/download
|
||||
|
||||
resources/waterfall.jar : resources
|
||||
wget -O resources/waterfall.jar https://papermc.io/ci/job/Waterfall/lastSuccessfulBuild/artifact/Waterfall-Proxy/bootstrap/target/Waterfall.jar
|
||||
|
||||
resources/velocity.jar : resources
|
||||
wget -O resources/velocity.jar https://ci.velocitypowered.com/job/velocity-1.1.0/lastSuccessfulBuild/artifact/proxy/build/libs/velocity-proxy-1.1.0-SNAPSHOT-all.jar
|
||||
|
||||
resources/sponge.jar : resources
|
||||
wget -O resources/sponge.jar https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/1.12.2-7.3.0/spongevanilla-1.12.2-7.3.0.jar
|
||||
|
||||
resources/viaversion.jar : resources
|
||||
wget -O resources/viaversion.jar https://ci.viaversion.com/job/ViaVersion/459/artifact/jar/target/ViaVersion-3.1.1-SNAPSHOT.jar
|
||||
|
||||
clean :
|
||||
rm -r resources/
|
||||
|
||||
run :
|
||||
tmux new-session './p1/run.sh' \; \
|
||||
split-window -h './p2/run.sh' \; \
|
||||
split-window -h './s1/run.sh' \; \
|
||||
split-window -h './s2/run.sh' \; \
|
||||
select-layout even-horizontal
|
||||
@@ -1,29 +0,0 @@
|
||||
## Using this testbed
|
||||
|
||||
This testbed runs two proxies, labeled p1 and p2, as well as two servers behind it,
|
||||
labeled s1 and s2. Ports for where everything is bound is listed below.
|
||||
|
||||
First, download required sources using the following command:
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
Then, each time you want to launch a session, run:
|
||||
|
||||
```
|
||||
make run
|
||||
```
|
||||
|
||||
FYI, this only works in Linux afaik because thats what I do my development on.
|
||||
|
||||
# Ports
|
||||
|
||||
| Server | Server Software | MC Port | Votifier Port |
|
||||
| ------ | ---------------------- | ------- | ------------- |
|
||||
| p1 | Waterfall/BungeeCord | 25577 | 8192 |
|
||||
| p2 | Velocity | 25578 | 8193 |
|
||||
| s1 | Paper (1.16.1) | 25565 | 8194 |
|
||||
| s2 | SpongeVanilla (1.12.2) | 25566 | 8195 |
|
||||
|
||||
For compatibility with 1.16.1, s2 includes ViaVersion.
|
||||
@@ -1,4 +0,0 @@
|
||||
logs/
|
||||
modules/
|
||||
locations.yml
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
server_connect_timeout: 5000
|
||||
listeners:
|
||||
- query_port: 25577
|
||||
motd: '&4its a bungee cord surbur'
|
||||
tab_list: GLOBAL_PING
|
||||
query_enabled: false
|
||||
proxy_protocol: false
|
||||
forced_hosts: {}
|
||||
ping_passthrough: false
|
||||
priorities:
|
||||
- s1
|
||||
bind_local_address: true
|
||||
host: 0.0.0.0:25577
|
||||
max_players: 1
|
||||
tab_size: 60
|
||||
force_default_server: false
|
||||
remote_ping_cache: -1
|
||||
network_compression_threshold: 256
|
||||
permissions:
|
||||
default:
|
||||
- bungeecord.command.server
|
||||
- bungeecord.command.list
|
||||
admin:
|
||||
- bungeecord.command.alert
|
||||
- bungeecord.command.end
|
||||
- bungeecord.command.ip
|
||||
- bungeecord.command.reload
|
||||
log_pings: true
|
||||
connection_throttle_limit: 3
|
||||
prevent_proxy_connections: true
|
||||
timeout: 30000
|
||||
player_limit: -1
|
||||
ip_forward: true
|
||||
groups:
|
||||
md_5:
|
||||
- admin
|
||||
remote_ping_timeout: 5000
|
||||
connection_throttle: 1
|
||||
log_commands: false
|
||||
stats: bf8a54ea-2917-4b9e-b463-2c05bd7f1ac6
|
||||
online_mode: true
|
||||
forge_support: true
|
||||
disabled_commands: []
|
||||
servers:
|
||||
s1:
|
||||
motd: SERVER 1
|
||||
address: localhost:25565
|
||||
restricted: false
|
||||
s2:
|
||||
motd: SERVER 2
|
||||
address: localhost:25566
|
||||
restricted: false
|
||||
@@ -1,8 +0,0 @@
|
||||
version: 2
|
||||
modules:
|
||||
- jenkins://cmd_alert
|
||||
- jenkins://cmd_find
|
||||
- jenkins://cmd_list
|
||||
- jenkins://cmd_send
|
||||
- jenkins://cmd_server
|
||||
- jenkins://reconnect_yaml
|
||||
@@ -1,2 +0,0 @@
|
||||
rsa/
|
||||
cached-votes.json
|
||||
@@ -1,74 +0,0 @@
|
||||
# The IP to listen to. Use 0.0.0.0 if you wish to listen to all interfaces on your server. (All IP addresses)
|
||||
# This defaults to the IP you have configured your server to listen on, or 0.0.0.0 if you have not configured this.
|
||||
host: 0.0.0.0
|
||||
|
||||
# Port to listen for new votes on
|
||||
port: 8192
|
||||
|
||||
# Whether or not to print debug messages. In a production system, this should be set to false.
|
||||
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
|
||||
debug: true
|
||||
|
||||
# All tokens, labeled by the serviceName of each server list.
|
||||
tokens:
|
||||
# Default token for all server lists, if another isn't supplied.
|
||||
default: proxy1token
|
||||
|
||||
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
|
||||
# option is currently not recommended as most voting sites only support the old protocol at present.
|
||||
disable-v1-protocol: false
|
||||
|
||||
# Configuration section for all vote forwarding to NuVotifier
|
||||
forwarding:
|
||||
# Sets whether to set up a remote method for fowarding. Supported methods:
|
||||
# - none - Does not set up a forwarding method.
|
||||
# - pluginMessaging - Sets up plugin messaging.
|
||||
# - proxy - Proxies votes to other NuVotifier servers from this server.
|
||||
method: pluginMessaging
|
||||
pluginMessaging:
|
||||
channel: nuvotifier:votes
|
||||
|
||||
#Only send votes to certain servers. If a server is present on excludedServers, then votes will NOT be forwarded
|
||||
#to them. If excludedServers is not present, votes will be sent to all servers.
|
||||
# If onlySendToJoinedServer is true and a player is on one of these servers, NuVotifier will process the vote as if the
|
||||
# player was not on the network at all.
|
||||
#excludedServers:
|
||||
#- server1
|
||||
#- server2
|
||||
|
||||
# If uncommented, turns excludedServers into an includedServers, where only servers on the list will be used.
|
||||
#whitelist: true
|
||||
|
||||
# Sets which cache to use if there are no players on the server that the vote is being sent to. Supported caches:
|
||||
# - none - Votes will simply be lost when no players are present on the server.
|
||||
# - memory - Votes will be cached in memory when no players are present. When Bungee is restarted, the votes will be lost.
|
||||
# - file - Votes will be saved to a local file every 3 minutes and on shutdown and reloaded when Bungee is restarted. This is suitable for
|
||||
# most set ups.
|
||||
cache: file
|
||||
# Only sends the vote to the server in which the player is currently joined.
|
||||
onlySendToJoinedServer: true
|
||||
#Sets which server to send the vote in the event the player is not online when the vote is cast
|
||||
#If you do not want the vote forwarded to a fallback, set this value to empty ('')
|
||||
#ONLY USED IF onlySendToJoinedServer is true!!
|
||||
joinedServerFallback: 's1'
|
||||
# Defines how quickly to dump votes over a player's connection when offloading a cache in votes per second
|
||||
dumpRate: 5
|
||||
# Options for file caching.
|
||||
file:
|
||||
name: cached-votes.json
|
||||
# days before a vote is considered 'dead' - removed from cache with a console warning
|
||||
cacheTime: 10
|
||||
# Options for memory caching.
|
||||
memory:
|
||||
# days before a vote is considered 'dead' and removed from memory. All votes are removed when the server restarts. -1 signifies no TTL
|
||||
cacheTime: -1
|
||||
# Specify servers to proxy votes for.
|
||||
proxy:
|
||||
Hub:
|
||||
address: 127.0.0.1
|
||||
port: 8194
|
||||
token: server1token
|
||||
Hub2:
|
||||
address: 127.0.0.1
|
||||
port: 8195
|
||||
token: server2token
|
||||
@@ -1 +0,0 @@
|
||||
../../../universal/build/libs/nuvotifier.jar
|
||||
Loaded 100 of 175 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user