Added an online-mode fix.

This commit is contained in:
Alex231 2020-10-30 20:01:17 +00:00
parent 31df51d672
commit 1b3b36f281
5 changed files with 337 additions and 1 deletions

View File

@ -1,5 +1,5 @@
name: MineOnlineBroadcast
version: 1.0.7
version: 1.0.8
description: Lists a server on mineonline.codie.gg/servers
author: codieradical
authors: [Codie]

View File

@ -1,3 +1,4 @@
import gg.codie.mineonline.ProxyThread;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.plugin.java.JavaPlugin;
@ -6,6 +7,7 @@ import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.ServerSocket;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
@ -20,6 +22,26 @@ public class MineOnlineBroadcast extends JavaPlugin {
public static long lastPing;
MineOnlineBroadcastListener listener;
Logger log;
ProxyThread proxyThread;
public void launchProxy() throws IOException {
ServerSocket serverSocket = new ServerSocket(0);
proxyThread = new ProxyThread(serverSocket);
proxyThread.start();
System.out.println("Enabling online-mode fix.");
System.setProperty("http.proxyHost", serverSocket.getInetAddress().getHostAddress());
System.setProperty("http.proxyPort", "" + serverSocket.getLocalPort());
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
}
public void stopProxy() {
if (proxyThread != null) {
proxyThread.stop();
proxyThread = null;
}
}
public static byte[] createChecksum(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
@ -123,6 +145,10 @@ public class MineOnlineBroadcast extends JavaPlugin {
Properties propertiesFile = new Properties();
propertiesFile.load(new FileInputStream(new File("server.properties")));
boolean isPublic = propertiesFile.getProperty("public", "true").equals("true");
if(!isPublic)
return;
String ip = propertiesFile.getProperty("serverlist-ip", propertiesFile.getProperty("server-ip", propertiesFile.getProperty("ip", null)));
String port = propertiesFile.getProperty("serverlist-port", propertiesFile.getProperty("server-port", propertiesFile.getProperty("port", "25565")));
int users = getServer().getOnlinePlayers().length;
@ -162,10 +188,21 @@ public class MineOnlineBroadcast extends JavaPlugin {
this.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_LOGIN, this.listener, Event.Priority.Lowest, this);
this.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_QUIT, this.listener, Event.Priority.Highest, this);
this.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_KICK, this.listener, Event.Priority.Highest, this);
try {
Properties propertiesFile = new Properties();
propertiesFile.load(new FileInputStream(new File("server.properties")));
boolean onlineMode = propertiesFile.getProperty("online-mode", "true").equals("true");
if (onlineMode)
launchProxy();
} catch (Exception ex) {
log.warning("Failed to enable online-mode fix. Authentication may fail.");
}
}
@Override
public void onDisable() {
broadcastThread.interrupt();
stopProxy();
}
}

View File

@ -0,0 +1,23 @@
package gg.codie.minecraft.api;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class SessionServer {
private static final String BASE_URL = "https://sessionserver.mojang.com";
public static boolean hasJoined(String username, String serverId, String ip) throws IOException {
HttpURLConnection connection;
URL url = new URL(BASE_URL + "/session/minecraft/hasJoined?username=" + username + "&serverId=" + serverId + (ip != null ? "&ip=" + ip : ""));
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.setDoOutput(false);
connection.connect();
return connection.getResponseCode() == 200;
}
}

View File

@ -0,0 +1,262 @@
package gg.codie.mineonline;
import gg.codie.minecraft.api.SessionServer;
import gg.codie.utils.ArrayUtils;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ProxyThread implements Runnable {
private AtomicReference<ServerSocket> serverSocket = new AtomicReference<>();
private Thread worker;
private AtomicBoolean running = new AtomicBoolean(false);
public void start() {
worker = new Thread(this);
worker.start();
}
public void stop() {
running.set(false);
}
boolean isRunning() {
return running.get();
}
public ProxyThread(ServerSocket serverSocket) {
this.serverSocket.set(serverSocket);
}
@Override
public void run() {
running.set(true);
System.setProperty("java.net.preferIPv4Stack", "true");
Socket clientSocket = null;
// DEBUG
System.out.println(serverSocket.get().getInetAddress() + ":" + serverSocket.get().getLocalPort());
while (running.get()) {
//Stream to put data to the browser
PrintWriter outGoing = null;
try {
clientSocket = serverSocket.get().accept();
outGoing = new PrintWriter(clientSocket.getOutputStream(), true);
final int bufferSize = 8096;
byte[] buffer = new byte[bufferSize];
int bytes_read;
LinkedList<Byte> request = new LinkedList();
bytes_read = clientSocket.getInputStream().read(buffer, 0, bufferSize);
for(int i = 0; i < bytes_read; i++)
request.add(buffer[i]);
String requestHeaders = new String(buffer).split("\r\n\r\n")[0];
// keep reading.
String requestString = new String(buffer);
for (String header : requestHeaders.split("\r\n")) {
if(header.contains("Content-Length")) {
int contentLength = Integer.parseInt(header.split(": ")[1]);
int headerLength = requestString.substring(0, requestString.indexOf("\r\n\r\n") + 4).length();
while(request.size() < contentLength + headerLength) {
bytes_read = clientSocket.getInputStream().read(buffer, 0, bufferSize);
for(int i = 0; i < bytes_read; i++)
request.add(buffer[i]);
}
break;
}
}
byte[] requestBytes = ArrayUtils.toPrimitives(request.toArray(new Byte[0]));
requestString = new String(requestBytes);
int headerSize = requestString.split("\r\n\r\n")[0].length() + 4;
// DEBUG
System.out.println("Request");
requestHeaders = requestString.split("\r\n\r\n")[0];
// DEBUG
System.out.println(requestString);
String urlString = "";
try {
urlString = pullLinks(requestString).get(0);
} catch (IndexOutOfBoundsException ex) {
return;
}
// Fix online-mode.
if(urlString.contains("minecraft.net/game/checkserver.jsp?")) {
System.out.println("here.");
String username = null;
String serverId = null;
String ip = null;
String[] args = urlString.replace("http://www.minecraft.net/game/checkserver.jsp?", "").split("&");
for (String arg : args) {
String[] keyValue = arg.split("=");
if (keyValue[0].equals("user"))
username = keyValue[1];
else if (keyValue[0].equals("serverId"))
serverId = keyValue[1];
else if (keyValue[0].equals("ip"))
ip = keyValue[1];
}
if (username != null && serverId != null) {
boolean validJoin = SessionServer.hasJoined(
username,
serverId,
ip
);
if (validJoin) {
String responseHeaders =
"HTTP/1.0 200 OKServer:Werkzeug/1.0.1 Python/3.7.0\r\n\r\n";
clientSocket.getOutputStream().write(responseHeaders.getBytes());
clientSocket.getOutputStream().write("YES".getBytes(StandardCharsets.UTF_8));
clientSocket.getOutputStream().flush();
clientSocket.getOutputStream().close();
continue;
}
}
}
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
for (String header : requestHeaders.substring(requestHeaders.indexOf("\r\n") + 2).split("\r\n")) {
String headerName = header.substring(0, header.indexOf(":"));
String headerValue = header.substring(header.indexOf(":") + 2);
connection.setRequestProperty(headerName, headerValue);
}
String methodLine = requestHeaders.substring(0, requestHeaders.indexOf("\r\n"));
connection.setRequestMethod(methodLine.substring(0, methodLine.indexOf(" ")));
byte[] content = new byte[0];
try {
if (headerSize < requestBytes.length) {
content = Arrays.copyOfRange(requestBytes, headerSize, requestBytes.length);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(content);
wr.flush();
wr.close();
} else {
connection.setUseCaches(false);
connection.setDoInput(true);
connection.connect();
}
String responseHeader = "";
for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
if (header.getKey() == null) {
Iterator<String> valueIterator = header.getValue().iterator();
responseHeader += valueIterator.next();
while (valueIterator.hasNext()) {
responseHeader += " " + valueIterator.next();
}
continue;
}
responseHeader += header.getKey() + ":";
Iterator<String> valueIterator = header.getValue().iterator();
responseHeader += valueIterator.next();
while (valueIterator.hasNext()) {
responseHeader += ", " + valueIterator.next();
}
responseHeader += "\r\n";
}
responseHeader += "\r\n";
String contentString = new String(content);
// DEBUG
System.out.println("Response");
System.out.print(responseHeader);
System.out.println(contentString);
InputStream is = connection.getInputStream();
clientSocket.getOutputStream().write(responseHeader.getBytes());
buffer = new byte[bufferSize];
while ((bytes_read = is.read(buffer, 0, bufferSize)) != -1) {
for (int i = 0; i < bytes_read; i++) {
clientSocket.getOutputStream().write(buffer[i]);
}
}
clientSocket.getOutputStream().flush();
clientSocket.getOutputStream().close();
} catch (Exception ex) {
String responseHeaders =
"HTTP/1.0 404 Not FoundServer:Werkzeug/1.0.1 Python/3.7.0\r\n\r\n";
clientSocket.getOutputStream().write(responseHeaders.getBytes());
clientSocket.getOutputStream().flush();
clientSocket.getOutputStream().close();
ex.printStackTrace();
}
} catch (FileNotFoundException ex) {
System.err.println("Got a 404 for: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("Something went very wrong.");
ex.printStackTrace();
} finally {
outGoing.close();
try {
clientSocket.close();
} catch (Exception e) { }
}
}
try {
serverSocket.get().close();
} catch (Exception e) { }
running.set(false);
}
//Pull all links from the body for easy retrieval
private static ArrayList<String> pullLinks(String text) {
ArrayList<String> links = new ArrayList<String>();
String regex = "\\(?\\b(http://|www[.])[-A-Za-z0-9+&amp;@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&amp;@#/%=~_()|]";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(text);
while(m.find()) {
String urlStr = m.group();
if (urlStr.startsWith("(") && urlStr.endsWith(")"))
{
urlStr = urlStr.substring(1, urlStr.length() - 1);
}
links.add(urlStr);
}
return links;
}
}

View File

@ -0,0 +1,14 @@
package gg.codie.utils;
public class ArrayUtils {
public static byte[] toPrimitives(Byte[] oBytes)
{
byte[] bytes = new byte[oBytes.length];
for(int i = 0; i < oBytes.length; i++){
bytes[i] = oBytes[i];
}
return bytes;
}
}