Compare commits
10 Commits
4aa9ee7735
...
7cd3011e45
Author | SHA1 | Date | |
---|---|---|---|
7cd3011e45 | |||
|
371e686076 | ||
|
7392cd6574 | ||
|
71feb11b2e | ||
|
c0fdf20224 | ||
|
00b68859ff | ||
|
1db8c8c6ab | ||
|
af97ffffa5 | ||
|
39191957ea | ||
|
d77e508e9c |
7
.github/workflows/gradle.yml
vendored
7
.github/workflows/gradle.yml
vendored
@@ -10,13 +10,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Validate Gradle Wrapper
|
with:
|
||||||
uses: gradle/actions/wrapper-validation@v3
|
persist-credentials: false
|
||||||
|
- name: Set up Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
cache: 'gradle'
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
|
@@ -5,7 +5,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withJavadocJar()
|
// withJavadocJar()
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
|
|
||||||
sourceSets["main"].java {
|
sourceSets["main"].java {
|
||||||
|
@@ -12,6 +12,14 @@ package com.velocitypowered.api.event;
|
|||||||
*/
|
*/
|
||||||
public enum PostOrder {
|
public enum PostOrder {
|
||||||
|
|
||||||
FIRST, EARLY, NORMAL, LATE, LAST, CUSTOM
|
FIRST, EARLY, NORMAL, LATE, LAST,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previously used to specify that {@link Subscribe#priority()} should be used.
|
||||||
|
*
|
||||||
|
* @deprecated No longer required, you only need to specify {@link Subscribe#priority()}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
CUSTOM
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -32,12 +32,9 @@ public @interface Subscribe {
|
|||||||
* The priority of this event handler. Priorities are used to determine the order in which event
|
* The priority of this event handler. Priorities are used to determine the order in which event
|
||||||
* handlers are called. The higher the priority, the earlier the event handler will be called.
|
* handlers are called. The higher the priority, the earlier the event handler will be called.
|
||||||
*
|
*
|
||||||
* <p>Note that due to compatibility constraints, you must specify {@link PostOrder#CUSTOM}
|
|
||||||
* in order to use this field.</p>
|
|
||||||
*
|
|
||||||
* @return the priority
|
* @return the priority
|
||||||
*/
|
*/
|
||||||
short priority() default Short.MIN_VALUE;
|
short priority() default 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the handler must be called asynchronously. By default, all event handlers are called
|
* Whether the handler must be called asynchronously. By default, all event handlers are called
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.api.proxy;
|
package com.velocitypowered.api.proxy;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.HandshakeIntent;
|
||||||
import com.velocitypowered.api.network.ProtocolState;
|
import com.velocitypowered.api.network.ProtocolState;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@@ -60,4 +61,11 @@ public interface InboundConnection {
|
|||||||
* @return the protocol state of the connection
|
* @return the protocol state of the connection
|
||||||
*/
|
*/
|
||||||
ProtocolState getProtocolState();
|
ProtocolState getProtocolState();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the initial intent for the connection.
|
||||||
|
*
|
||||||
|
* @return the intent of the connection
|
||||||
|
*/
|
||||||
|
HandshakeIntent getHandshakeIntent();
|
||||||
}
|
}
|
||||||
|
@@ -148,4 +148,8 @@ public interface ProxyConfig {
|
|||||||
* @return read timeout (in milliseconds)
|
* @return read timeout (in milliseconds)
|
||||||
*/
|
*/
|
||||||
int getReadTimeout();
|
int getReadTimeout();
|
||||||
|
|
||||||
|
String getNeteaseAuthUrl();
|
||||||
|
|
||||||
|
String getNeteaseGameId();
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
* <li>150-300 will display 4 bars</li>
|
* <li>150-300 will display 4 bars</li>
|
||||||
* <li>300-600 will display 3 bars</li>
|
* <li>300-600 will display 3 bars</li>
|
||||||
* <li>600-1000 will display 2 bars</li>
|
* <li>600-1000 will display 2 bars</li>
|
||||||
* <li>A latency move than 1 second will display 1 bar</li>
|
* <li>A latency greater than 1 second will display 1 bar</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @return latency set for {@code this} entry
|
* @return latency set for {@code this} entry
|
||||||
|
@@ -19,7 +19,7 @@ public final class GameProfile {
|
|||||||
|
|
||||||
private final UUID id;
|
private final UUID id;
|
||||||
private final String undashedId;
|
private final String undashedId;
|
||||||
private final String name;
|
private String name;
|
||||||
private final List<Property> properties;
|
private final List<Property> properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,6 +80,10 @@ public final class GameProfile {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an immutable list of profile properties associated with this profile.
|
* Returns an immutable list of profile properties associated with this profile.
|
||||||
*
|
*
|
||||||
@@ -221,4 +225,116 @@ public final class GameProfile {
|
|||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netease auth response.
|
||||||
|
*/
|
||||||
|
public static class Response {
|
||||||
|
private Integer code = 0;
|
||||||
|
private String message;
|
||||||
|
private String details;
|
||||||
|
private ResponseEntity entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor.
|
||||||
|
*
|
||||||
|
* @param code -
|
||||||
|
* @param message -
|
||||||
|
* @param details -
|
||||||
|
* @param entity the game profile
|
||||||
|
*/
|
||||||
|
public Response(Integer code, String message, String details, ResponseEntity entity) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.details = details;
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(Integer code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(String details) {
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity getEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntity(ResponseEntity entity) {
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netease auth response entity.
|
||||||
|
*/
|
||||||
|
public static class ResponseEntity {
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private List<Property> properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor.
|
||||||
|
*
|
||||||
|
* @param id -
|
||||||
|
* @param name -
|
||||||
|
* @param properties -
|
||||||
|
*/
|
||||||
|
public ResponseEntity(String id, String name, List<Property> properties) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Property> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperties(List<Property> properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ResponseEntity{"
|
||||||
|
+ "id='" + id + '\''
|
||||||
|
+ ", name='" + name + '\''
|
||||||
|
+ ", properties=" + properties
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,8 +11,8 @@ shadow = "io.github.goooler.shadow:8.1.5"
|
|||||||
spotless = "com.diffplug.spotless:6.25.0"
|
spotless = "com.diffplug.spotless:6.25.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
adventure-bom = "net.kyori:adventure-bom:4.17.0"
|
adventure-bom = "net.kyori:adventure-bom:4.18.0"
|
||||||
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.17.0"
|
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.18.0"
|
||||||
adventure-facet = "net.kyori:adventure-platform-facet:4.3.4"
|
adventure-facet = "net.kyori:adventure-platform-facet:4.3.4"
|
||||||
asm = "org.ow2.asm:asm:9.6"
|
asm = "org.ow2.asm:asm:9.6"
|
||||||
auto-service = "com.google.auto.service:auto-service:1.0.1"
|
auto-service = "com.google.auto.service:auto-service:1.0.1"
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
9
gradlew
vendored
9
gradlew
vendored
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -84,7 +86,8 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -200,7 +203,7 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -34,7 +36,7 @@ set APP_HOME=%DIRNAME%
|
|||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
@@ -26,6 +26,15 @@ Java_com_velocitypowered_natives_encryption_OpenSslCipherImpl_init(JNIEnv *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// But, you're saying, *why* are we using the key as the IV? After all, reusing the key as
|
||||||
|
// the IV defeats the entire point - we might as well just initialize it to all zeroes.
|
||||||
|
//
|
||||||
|
// You can blame Mojang. For the record, we also don't consider the Minecraft protocol
|
||||||
|
// encryption scheme to be secure, and it has reached the point where any serious cryptographic
|
||||||
|
// protocol needs a refresh. There are multiple obvious weaknesses, and this is far from the
|
||||||
|
// most serious.
|
||||||
|
//
|
||||||
|
// If you are using Minecraft in a security-sensitive application, *I don't know what to say.*
|
||||||
CCCryptorRef cryptor = NULL;
|
CCCryptorRef cryptor = NULL;
|
||||||
CCCryptorStatus result = CCCryptorCreateWithMode(encrypt ? kCCEncrypt : kCCDecrypt,
|
CCCryptorStatus result = CCCryptorCreateWithMode(encrypt ? kCCEncrypt : kCCDecrypt,
|
||||||
kCCModeCFB8,
|
kCCModeCFB8,
|
||||||
|
@@ -32,6 +32,15 @@ Java_com_velocitypowered_natives_encryption_OpenSslCipherImpl_init(JNIEnv *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// But, you're saying, *why* are we using the key as the IV? After all, reusing the key as
|
||||||
|
// the IV defeats the entire point - we might as well just initialize it to all zeroes.
|
||||||
|
//
|
||||||
|
// You can blame Mojang. For the record, we also don't consider the Minecraft protocol
|
||||||
|
// encryption scheme to be secure, and it has reached the point where any serious cryptographic
|
||||||
|
// protocol needs a refresh. There are multiple obvious weaknesses, and this is far from the
|
||||||
|
// most serious.
|
||||||
|
//
|
||||||
|
// If you are using Minecraft in a security-sensitive application, *I don't know what to say.*
|
||||||
int result = EVP_CipherInit(ctx, EVP_aes_128_cfb8(), (byte*) keyBytes, (byte*) keyBytes,
|
int result = EVP_CipherInit(ctx, EVP_aes_128_cfb8(), (byte*) keyBytes, (byte*) keyBytes,
|
||||||
encrypt);
|
encrypt);
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
|
@@ -57,7 +57,8 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
|||||||
inflater.setInput(source.nioBuffer());
|
inflater.setInput(source.nioBuffer());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!inflater.finished() && inflater.getBytesWritten() < uncompressedSize) {
|
final int readable = source.readableBytes();
|
||||||
|
while (!inflater.finished() && inflater.getBytesRead() < readable) {
|
||||||
if (!destination.isWritable()) {
|
if (!destination.isWritable()) {
|
||||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
@@ -48,6 +48,15 @@ public class JavaVelocityCipher implements VelocityCipher {
|
|||||||
|
|
||||||
private JavaVelocityCipher(boolean encrypt, SecretKey key) throws GeneralSecurityException {
|
private JavaVelocityCipher(boolean encrypt, SecretKey key) throws GeneralSecurityException {
|
||||||
this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
|
this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||||
|
// But, you're saying, *why* are we using the key as the IV? After all, reusing the key as
|
||||||
|
// the IV defeats the entire point - we might as well just initialize it to all zeroes.
|
||||||
|
//
|
||||||
|
// You can blame Mojang. For the record, we also don't consider the Minecraft protocol
|
||||||
|
// encryption scheme to be secure, and it has reached the point where any serious cryptographic
|
||||||
|
// protocol needs a refresh. There are multiple obvious weaknesses, and this is far from the
|
||||||
|
// most serious.
|
||||||
|
//
|
||||||
|
// If you are using Minecraft in a security-sensitive application, *I don't know what to say.*
|
||||||
this.cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key,
|
this.cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key,
|
||||||
new IvParameterSpec(key.getEncoded()));
|
new IvParameterSpec(key.getEncoded()));
|
||||||
}
|
}
|
||||||
|
@@ -236,6 +236,15 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
|
|
||||||
registerTranslations();
|
registerTranslations();
|
||||||
|
|
||||||
|
// Yes, you're reading that correctly. We're generating a 1024-bit RSA keypair. Sounds
|
||||||
|
// dangerous, right? We're well within the realm of factoring such a key...
|
||||||
|
//
|
||||||
|
// You can blame Mojang. For the record, we also don't consider the Minecraft protocol
|
||||||
|
// encryption scheme to be secure, and it has reached the point where any serious cryptographic
|
||||||
|
// protocol needs a refresh. There are multiple obvious weaknesses, and this is far from the
|
||||||
|
// most serious.
|
||||||
|
//
|
||||||
|
// If you are using Minecraft in a security-sensitive application, *I don't know what to say.*
|
||||||
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
|
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
|
||||||
|
|
||||||
cm.logChannelInformation();
|
cm.logChannelInformation();
|
||||||
|
@@ -92,6 +92,11 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
@Expose
|
@Expose
|
||||||
private boolean forceKeyAuthentication = true; // Added in 1.19
|
private boolean forceKeyAuthentication = true; // Added in 1.19
|
||||||
|
|
||||||
|
@Expose
|
||||||
|
private String authUrl = "http://192.168.46.50:9999/check";
|
||||||
|
@Expose
|
||||||
|
private String gameId = "77140593557373952";
|
||||||
|
|
||||||
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced,
|
||||||
Query query, Metrics metrics) {
|
Query query, Metrics metrics) {
|
||||||
this.servers = servers;
|
this.servers = servers;
|
||||||
@@ -106,7 +111,8 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
|
PlayerInfoForwarding playerInfoForwardingMode, byte[] forwardingSecret,
|
||||||
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough,
|
boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough,
|
||||||
boolean enablePlayerAddressLogging, Servers servers, ForcedHosts forcedHosts,
|
boolean enablePlayerAddressLogging, Servers servers, ForcedHosts forcedHosts,
|
||||||
Advanced advanced, Query query, Metrics metrics, boolean forceKeyAuthentication) {
|
Advanced advanced, Query query, Metrics metrics, boolean forceKeyAuthentication,
|
||||||
|
String authUrl, String gameId) {
|
||||||
this.bind = bind;
|
this.bind = bind;
|
||||||
this.motd = motd;
|
this.motd = motd;
|
||||||
this.showMaxPlayers = showMaxPlayers;
|
this.showMaxPlayers = showMaxPlayers;
|
||||||
@@ -124,6 +130,8 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
this.query = query;
|
this.query = query;
|
||||||
this.metrics = metrics;
|
this.metrics = metrics;
|
||||||
this.forceKeyAuthentication = forceKeyAuthentication;
|
this.forceKeyAuthentication = forceKeyAuthentication;
|
||||||
|
this.authUrl = authUrl;
|
||||||
|
this.gameId = gameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -407,6 +415,16 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
return forceKeyAuthentication;
|
return forceKeyAuthentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNeteaseAuthUrl() {
|
||||||
|
return authUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNeteaseGameId() {
|
||||||
|
return gameId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
@@ -424,6 +442,8 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
.add("favicon", favicon)
|
.add("favicon", favicon)
|
||||||
.add("enablePlayerAddressLogging", enablePlayerAddressLogging)
|
.add("enablePlayerAddressLogging", enablePlayerAddressLogging)
|
||||||
.add("forceKeyAuthentication", forceKeyAuthentication)
|
.add("forceKeyAuthentication", forceKeyAuthentication)
|
||||||
|
.add("authUrl", authUrl)
|
||||||
|
.add("gameId", gameId)
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,6 +541,8 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
|| forwardingMode == PlayerInfoForwarding.BUNGEEGUARD)) {
|
|| forwardingMode == PlayerInfoForwarding.BUNGEEGUARD)) {
|
||||||
throw new RuntimeException("The forwarding-secret file must not be empty.");
|
throw new RuntimeException("The forwarding-secret file must not be empty.");
|
||||||
}
|
}
|
||||||
|
final String authUrl = config.getOrElse("auth-url", "http://192.168.46.50:9999/check");
|
||||||
|
final String gameId = config.getOrElse("game-id", "77140593557373952");
|
||||||
|
|
||||||
return new VelocityConfiguration(
|
return new VelocityConfiguration(
|
||||||
bind,
|
bind,
|
||||||
@@ -539,7 +561,9 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
new Advanced(advancedConfig),
|
new Advanced(advancedConfig),
|
||||||
new Query(queryConfig),
|
new Query(queryConfig),
|
||||||
new Metrics(metricsConfig),
|
new Metrics(metricsConfig),
|
||||||
forceKeyAuthentication
|
forceKeyAuthentication,
|
||||||
|
authUrl,
|
||||||
|
gameId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -301,6 +301,21 @@ public class BungeeCordMessageResponder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processGetPlayerServer(ByteBufDataInput in) {
|
||||||
|
proxy.getPlayer(in.readUTF()).ifPresent(player -> {
|
||||||
|
player.getCurrentServer().ifPresent(server -> {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ByteBufDataOutput out = new ByteBufDataOutput(buf);
|
||||||
|
|
||||||
|
out.writeUTF("GetPlayerServer");
|
||||||
|
out.writeUTF(player.getUsername());
|
||||||
|
out.writeUTF(server.getServerInfo().getName());
|
||||||
|
|
||||||
|
sendResponseOnConnection(buf);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static String getBungeeCordChannel(ProtocolVersion version) {
|
static String getBungeeCordChannel(ProtocolVersion version) {
|
||||||
return version.noLessThan(ProtocolVersion.MINECRAFT_1_13) ? MODERN_CHANNEL.getId()
|
return version.noLessThan(ProtocolVersion.MINECRAFT_1_13) ? MODERN_CHANNEL.getId()
|
||||||
: LEGACY_CHANNEL.getId();
|
: LEGACY_CHANNEL.getId();
|
||||||
@@ -331,6 +346,9 @@ public class BungeeCordMessageResponder {
|
|||||||
ByteBufDataInput in = new ByteBufDataInput(message.content());
|
ByteBufDataInput in = new ByteBufDataInput(message.content());
|
||||||
String subChannel = in.readUTF();
|
String subChannel = in.readUTF();
|
||||||
switch (subChannel) {
|
switch (subChannel) {
|
||||||
|
case "GetPlayerServer":
|
||||||
|
this.processGetPlayerServer(in);
|
||||||
|
break;
|
||||||
case "ForwardToPlayer":
|
case "ForwardToPlayer":
|
||||||
this.processForwardToPlayer(in);
|
this.processForwardToPlayer(in);
|
||||||
break;
|
break;
|
||||||
|
@@ -97,7 +97,7 @@ public class AuthSessionHandler implements MinecraftSessionHandler {
|
|||||||
// Initiate a regular connection and move over to it.
|
// Initiate a regular connection and move over to it.
|
||||||
ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(),
|
ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(),
|
||||||
mcConnection, inbound.getVirtualHost().orElse(null), inbound.getRawVirtualHost().orElse(null), onlineMode,
|
mcConnection, inbound.getVirtualHost().orElse(null), inbound.getRawVirtualHost().orElse(null), onlineMode,
|
||||||
inbound.getIdentifiedKey());
|
inbound.getHandshakeIntent(), inbound.getIdentifiedKey());
|
||||||
this.connectedPlayer = player;
|
this.connectedPlayer = player;
|
||||||
if (!server.canRegisterConnection(player)) {
|
if (!server.canRegisterConnection(player)) {
|
||||||
player.disconnect0(
|
player.disconnect0(
|
||||||
|
@@ -38,6 +38,7 @@ import com.velocitypowered.api.event.player.PlayerModInfoEvent;
|
|||||||
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
|
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
|
||||||
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
||||||
import com.velocitypowered.api.event.player.configuration.PlayerEnterConfigurationEvent;
|
import com.velocitypowered.api.event.player.configuration.PlayerEnterConfigurationEvent;
|
||||||
|
import com.velocitypowered.api.network.HandshakeIntent;
|
||||||
import com.velocitypowered.api.network.ProtocolState;
|
import com.velocitypowered.api.network.ProtocolState;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.permission.PermissionFunction;
|
import com.velocitypowered.api.permission.PermissionFunction;
|
||||||
@@ -156,6 +157,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
private final MinecraftConnection connection;
|
private final MinecraftConnection connection;
|
||||||
private final @Nullable InetSocketAddress virtualHost;
|
private final @Nullable InetSocketAddress virtualHost;
|
||||||
private final @Nullable String rawVirtualHost;
|
private final @Nullable String rawVirtualHost;
|
||||||
|
private final HandshakeIntent handshakeIntent;
|
||||||
private GameProfile profile;
|
private GameProfile profile;
|
||||||
private PermissionFunction permissionFunction;
|
private PermissionFunction permissionFunction;
|
||||||
private int tryIndex = 0;
|
private int tryIndex = 0;
|
||||||
@@ -193,12 +195,13 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
|
|
||||||
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
|
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
|
||||||
@Nullable InetSocketAddress virtualHost, @Nullable String rawVirtualHost, boolean onlineMode,
|
@Nullable InetSocketAddress virtualHost, @Nullable String rawVirtualHost, boolean onlineMode,
|
||||||
@Nullable IdentifiedKey playerKey) {
|
HandshakeIntent handshakeIntent, @Nullable IdentifiedKey playerKey) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.virtualHost = virtualHost;
|
this.virtualHost = virtualHost;
|
||||||
this.rawVirtualHost = rawVirtualHost;
|
this.rawVirtualHost = rawVirtualHost;
|
||||||
|
this.handshakeIntent = handshakeIntent;
|
||||||
this.permissionFunction = PermissionFunction.ALWAYS_UNDEFINED;
|
this.permissionFunction = PermissionFunction.ALWAYS_UNDEFINED;
|
||||||
this.connectionPhase = connection.getType().getInitialClientPhase();
|
this.connectionPhase = connection.getType().getInitialClientPhase();
|
||||||
this.onlineMode = onlineMode;
|
this.onlineMode = onlineMode;
|
||||||
@@ -1335,6 +1338,11 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
return connection.getState().toProtocolState();
|
return connection.getState().toProtocolState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandshakeIntent getHandshakeIntent() {
|
||||||
|
return handshakeIntent;
|
||||||
|
}
|
||||||
|
|
||||||
private final class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder {
|
private final class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder {
|
||||||
|
|
||||||
private final RegisteredServer toConnect;
|
private final RegisteredServer toConnect;
|
||||||
|
@@ -277,5 +277,10 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
|||||||
public ProtocolState getProtocolState() {
|
public ProtocolState getProtocolState() {
|
||||||
return connection.getState().toProtocolState();
|
return connection.getState().toProtocolState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandshakeIntent getHandshakeIntent() {
|
||||||
|
return HandshakeIntent.STATUS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.connection.client;
|
package com.velocitypowered.proxy.connection.client;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.HandshakeIntent;
|
||||||
import com.velocitypowered.api.network.ProtocolState;
|
import com.velocitypowered.api.network.ProtocolState;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.InboundConnection;
|
import com.velocitypowered.api.proxy.InboundConnection;
|
||||||
@@ -98,6 +99,11 @@ public final class InitialInboundConnection implements VelocityInboundConnection
|
|||||||
return connection.getState().toProtocolState();
|
return connection.getState().toProtocolState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandshakeIntent getHandshakeIntent() {
|
||||||
|
return handshake.getIntent();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects the connection from the server.
|
* Disconnects the connection from the server.
|
||||||
*
|
*
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.connection.client;
|
package com.velocitypowered.proxy.connection.client;
|
||||||
|
|
||||||
import static com.google.common.net.UrlEscapers.urlFormParameterEscaper;
|
|
||||||
import static com.velocitypowered.proxy.VelocityServer.GENERAL_GSON;
|
import static com.velocitypowered.proxy.VelocityServer.GENERAL_GSON;
|
||||||
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
||||||
import static com.velocitypowered.proxy.crypto.EncryptionUtils.decryptRsa;
|
import static com.velocitypowered.proxy.crypto.EncryptionUtils.decryptRsa;
|
||||||
@@ -25,6 +24,7 @@ import static com.velocitypowered.proxy.crypto.EncryptionUtils.generateServerId;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import com.velocitypowered.api.event.connection.PreLoginEvent;
|
import com.velocitypowered.api.event.connection.PreLoginEvent;
|
||||||
import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult;
|
import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
@@ -50,6 +50,7 @@ import java.net.http.HttpResponse;
|
|||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
@@ -198,22 +199,23 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] decryptedSharedSecret = decryptRsa(serverKeyPair, packet.getSharedSecret());
|
final byte[] decryptedSharedSecret = decryptRsa(serverKeyPair, packet.getSharedSecret());
|
||||||
String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
|
final String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
|
||||||
|
final String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString();
|
||||||
|
|
||||||
String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString();
|
JsonObject data = new JsonObject();
|
||||||
String url = String.format(MOJANG_HASJOINED_URL,
|
data.addProperty("username", login.getUsername());
|
||||||
urlFormParameterEscaper().escape(login.getUsername()), serverId);
|
data.addProperty("serverId", serverId);
|
||||||
|
data.addProperty("gameID", server.getConfiguration().getNeteaseGameId());
|
||||||
|
|
||||||
if (server.getConfiguration().shouldPreventClientProxyConnections()) {
|
HttpRequest httpRequest = HttpRequest.newBuilder()
|
||||||
url += "&ip=" + urlFormParameterEscaper().escape(playerIp);
|
.headers(
|
||||||
}
|
"User-Agent", server.getVersion().getName() + "/" + server.getVersion().getVersion(),
|
||||||
|
"Content-Type", "application/json"
|
||||||
final HttpRequest httpRequest = HttpRequest.newBuilder()
|
).POST(HttpRequest.BodyPublishers.ofString(data.toString()))
|
||||||
.setHeader("User-Agent",
|
.uri(URI.create(server.getConfiguration().getNeteaseAuthUrl()))
|
||||||
server.getVersion().getName() + "/" + server.getVersion().getVersion())
|
|
||||||
.uri(URI.create(url))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final HttpClient httpClient = server.createHttpClient();
|
final HttpClient httpClient = server.createHttpClient();
|
||||||
httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
|
httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
|
||||||
.whenCompleteAsync((response, throwable) -> {
|
.whenCompleteAsync((response, throwable) -> {
|
||||||
@@ -240,9 +242,26 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
if (response.statusCode() == 200) {
|
if (response.statusCode() == 200) {
|
||||||
final GameProfile profile = GENERAL_GSON.fromJson(response.body(),
|
final GameProfile.Response authResponse = GENERAL_GSON.fromJson(response.body(),
|
||||||
GameProfile.class);
|
GameProfile.Response.class);
|
||||||
|
if (authResponse.getCode() != 0) {
|
||||||
|
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
|
||||||
|
logger.error("Error authenticating {} with netease", login.getUsername());
|
||||||
|
} else {
|
||||||
|
GameProfile.ResponseEntity entity = authResponse.getEntity();
|
||||||
|
if (entity.getName() == null || entity.getName().isEmpty()) {
|
||||||
|
entity.setName(login.getUsername());
|
||||||
|
}
|
||||||
|
if (entity.getProperties() == null) {
|
||||||
|
entity.setProperties(new ArrayList<>());
|
||||||
|
}
|
||||||
|
if (entity.getId() == null) {
|
||||||
|
inbound.disconnect(
|
||||||
|
Component.translatable("velocity.error.online-mode-only", NamedTextColor.RED));
|
||||||
|
} else {
|
||||||
|
GameProfile profile = new GameProfile(entity.getId(), entity.getName(), entity.getProperties());
|
||||||
// Not so fast, now we verify the public key for 1.19.1+
|
// Not so fast, now we verify the public key for 1.19.1+
|
||||||
if (inbound.getIdentifiedKey() != null
|
if (inbound.getIdentifiedKey() != null
|
||||||
&& inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
|
&& inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
|
||||||
@@ -255,6 +274,8 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
// All went well, initialize the session.
|
// All went well, initialize the session.
|
||||||
mcConnection.setActiveSessionHandler(StateRegistry.LOGIN,
|
mcConnection.setActiveSessionHandler(StateRegistry.LOGIN,
|
||||||
new AuthSessionHandler(server, inbound, profile, true));
|
new AuthSessionHandler(server, inbound, profile, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (response.statusCode() == 204) {
|
} else if (response.statusCode() == 204) {
|
||||||
// Apparently an offline-mode user logged onto this online-mode proxy.
|
// Apparently an offline-mode user logged onto this online-mode proxy.
|
||||||
inbound.disconnect(
|
inbound.disconnect(
|
||||||
@@ -266,6 +287,9 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
response.statusCode(), login.getUsername(), playerIp);
|
response.statusCode(), login.getUsername(), playerIp);
|
||||||
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
|
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Got an unexpected error", e);
|
||||||
|
}
|
||||||
}, mcConnection.eventLoop())
|
}, mcConnection.eventLoop())
|
||||||
.thenRun(() -> {
|
.thenRun(() -> {
|
||||||
if (httpClient instanceof final AutoCloseable closeable) {
|
if (httpClient instanceof final AutoCloseable closeable) {
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.connection.client;
|
package com.velocitypowered.proxy.connection.client;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.HandshakeIntent;
|
||||||
import com.velocitypowered.api.network.ProtocolState;
|
import com.velocitypowered.api.network.ProtocolState;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.LoginPhaseConnection;
|
import com.velocitypowered.api.proxy.LoginPhaseConnection;
|
||||||
@@ -177,4 +178,9 @@ public class LoginInboundConnection implements LoginPhaseConnection, KeyIdentifi
|
|||||||
public ProtocolState getProtocolState() {
|
public ProtocolState getProtocolState() {
|
||||||
return delegate.getProtocolState();
|
return delegate.getProtocolState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandshakeIntent getHandshakeIntent() {
|
||||||
|
return delegate.getHandshakeIntent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,8 +23,6 @@ import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
|||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
@@ -111,42 +109,6 @@ public enum EncryptionUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a signature for input data.
|
|
||||||
*
|
|
||||||
* @param algorithm the signature algorithm
|
|
||||||
* @param base the private key to sign with
|
|
||||||
* @param toSign the byte array(s) of data to sign
|
|
||||||
* @return the generated signature
|
|
||||||
*/
|
|
||||||
public static byte[] generateSignature(String algorithm, PrivateKey base, byte[]... toSign) {
|
|
||||||
Preconditions.checkArgument(toSign.length > 0);
|
|
||||||
try {
|
|
||||||
Signature construct = Signature.getInstance(algorithm);
|
|
||||||
construct.initSign(base);
|
|
||||||
for (byte[] bytes : toSign) {
|
|
||||||
construct.update(bytes);
|
|
||||||
}
|
|
||||||
return construct.sign();
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
throw new IllegalArgumentException("Invalid signature parameters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes a long array as Big-endian byte array.
|
|
||||||
*
|
|
||||||
* @param bits the long (array) of numbers to encode
|
|
||||||
* @return the encoded bytes
|
|
||||||
*/
|
|
||||||
public static byte[] longToBigEndianByteArray(long... bits) {
|
|
||||||
ByteBuffer ret = ByteBuffer.allocate(8 * bits.length).order(ByteOrder.BIG_ENDIAN);
|
|
||||||
for (long put : bits) {
|
|
||||||
ret.putLong(put);
|
|
||||||
}
|
|
||||||
return ret.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String encodeUrlEncoded(byte[] data) {
|
public static String encodeUrlEncoded(byte[] data) {
|
||||||
return MIME_SPECIAL_ENCODER.encodeToString(data);
|
return MIME_SPECIAL_ENCODER.encodeToString(data);
|
||||||
}
|
}
|
||||||
@@ -155,22 +117,6 @@ public enum EncryptionUtils {
|
|||||||
return Base64.getMimeDecoder().decode(toParse);
|
return Base64.getMimeDecoder().decode(toParse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a cer-encoded RSA key into its key bytes.
|
|
||||||
*
|
|
||||||
* @param toParse the cer-encoded key String
|
|
||||||
* @param descriptors the type of key
|
|
||||||
* @return the parsed key bytes
|
|
||||||
*/
|
|
||||||
public static byte[] parsePemEncoded(String toParse, Pair<String, String> descriptors) {
|
|
||||||
int startIdx = toParse.indexOf(descriptors.first());
|
|
||||||
Preconditions.checkArgument(startIdx >= 0);
|
|
||||||
int firstLen = descriptors.first().length();
|
|
||||||
int endIdx = toParse.indexOf(descriptors.second(), firstLen + startIdx) + 1;
|
|
||||||
Preconditions.checkArgument(endIdx > 0);
|
|
||||||
return decodeUrlEncoded(toParse.substring(startIdx + firstLen, endIdx));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes an RSA key as String cer format.
|
* Encodes an RSA key as String cer format.
|
||||||
*
|
*
|
||||||
|
@@ -350,8 +350,9 @@ public class VelocityEventManager implements EventManager {
|
|||||||
asyncType = AsyncType.ALWAYS;
|
asyncType = AsyncType.ALWAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The default value of 0 will fall back to PostOrder, the default PostOrder (NORMAL) is also 0
|
||||||
final short order;
|
final short order;
|
||||||
if (subscribe.order() == PostOrder.CUSTOM) {
|
if (subscribe.priority() != 0) {
|
||||||
order = subscribe.priority();
|
order = subscribe.priority();
|
||||||
} else {
|
} else {
|
||||||
order = (short) POST_ORDER_MAP.get(subscribe.order());
|
order = (short) POST_ORDER_MAP.get(subscribe.order());
|
||||||
|
@@ -91,7 +91,7 @@ public class LegacyChatPacket implements MinecraftPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||||
message = ProtocolUtils.readString(buf);
|
message = ProtocolUtils.readString(buf, 256);
|
||||||
if (direction == ProtocolUtils.Direction.CLIENTBOUND
|
if (direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||||
&& version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
&& version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||||
type = buf.readByte();
|
type = buf.readByte();
|
||||||
|
@@ -69,6 +69,20 @@ ping-passthrough = "DISABLED"
|
|||||||
# If not enabled (default is true) player IP addresses will be replaced by <ip address withheld> in logs
|
# If not enabled (default is true) player IP addresses will be replaced by <ip address withheld> in logs
|
||||||
enable-player-address-logging = true
|
enable-player-address-logging = true
|
||||||
|
|
||||||
|
# 认证链接
|
||||||
|
# 正式环境:http://x19authserver.nie.netease.com/check
|
||||||
|
# 测试环境:http://x19authexpr.nie.netease.com/check
|
||||||
|
# 1.20版本请使用以下接口:
|
||||||
|
# 正式环境:https://x19apigatewayobt.nie.netease.com/pcauth/check
|
||||||
|
# 测试环境:https://x19apigatewayexpr.nie.netease.com/pcauth/check
|
||||||
|
# 另有外网测试认证接口,对应接入test版bc认证,通常情况下不使用,需要启用时会另行沟通。
|
||||||
|
# http://x19authtest.nie.netease.com/check
|
||||||
|
auth-url = "http://192.168.46.50:9999/check"
|
||||||
|
|
||||||
|
# 网络服游戏 id
|
||||||
|
# 在开发者平台中可以查看
|
||||||
|
game-id = "77140593557373952"
|
||||||
|
|
||||||
[servers]
|
[servers]
|
||||||
# Configure your servers here. Each key represents the server's name, and the value
|
# Configure your servers here. Each key represents the server's name, and the value
|
||||||
# represents the IP address of the server to connect to.
|
# represents the IP address of the server to connect to.
|
||||||
|
@@ -17,7 +17,7 @@ pluginManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = "velocity"
|
rootProject.name = "velocity"
|
||||||
|
Reference in New Issue
Block a user