mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-12 00:47:26 -04:00
proper mojang api
This commit is contained in:
parent
55231a5a65
commit
b8a0e74434
@ -15,4 +15,5 @@ package de.bixilon.minosoft;
|
||||
|
||||
public class Config {
|
||||
public static String homeDir;
|
||||
public static String configFileName = "game.yml";
|
||||
}
|
||||
|
@ -15,18 +15,21 @@ package de.bixilon.minosoft;
|
||||
|
||||
import de.bixilon.minosoft.config.Configuration;
|
||||
import de.bixilon.minosoft.config.GameConfiguration;
|
||||
import de.bixilon.minosoft.game.datatypes.Player;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.logging.LogLevel;
|
||||
import de.bixilon.minosoft.objects.Account;
|
||||
import de.bixilon.minosoft.objects.Player;
|
||||
import de.bixilon.minosoft.mojang.api.MojangAccount;
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.util.OSUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Minosoft {
|
||||
static Configuration config;
|
||||
static List<MojangAccount> accountList;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// int log thread
|
||||
@ -36,7 +39,7 @@ public class Minosoft {
|
||||
setConfigFolder();
|
||||
Log.info("Reading config file...");
|
||||
try {
|
||||
config = new Configuration("game.yml");
|
||||
config = new Configuration(Config.configFileName);
|
||||
} catch (IOException e) {
|
||||
Log.fatal("Failed to load config file!");
|
||||
e.printStackTrace();
|
||||
@ -46,8 +49,21 @@ public class Minosoft {
|
||||
// set log level from config
|
||||
Log.setLevel(LogLevel.byName(config.getString(GameConfiguration.GENERAL_LOG_LEVEL)));
|
||||
|
||||
checkClientToken();
|
||||
|
||||
Connection c = new Connection(config.getString("debug.host"), config.getInteger("debug.port"));
|
||||
c.setPlayer(new Player(new Account(config.getString("debug.username"), config.getString("debug.password"))));
|
||||
accountList = config.getMojangAccounts();
|
||||
if (accountList.size() == 0) {
|
||||
throw new RuntimeException("No accounts in config file!");
|
||||
//MojangAccount account = MojangAuthentication.login("email", "password");
|
||||
}
|
||||
MojangAccount account = accountList.get(0);
|
||||
if (!account.refreshToken()) {
|
||||
// could not login
|
||||
System.exit(1);
|
||||
}
|
||||
account.saveToConfig();
|
||||
c.setPlayer(new Player(account));
|
||||
c.connect();
|
||||
}
|
||||
|
||||
@ -79,4 +95,11 @@ public class Minosoft {
|
||||
public static Configuration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public static void checkClientToken() {
|
||||
if (config.getString(GameConfiguration.CLIENT_TOKEN) == null || config.getString(GameConfiguration.CLIENT_TOKEN).equals("randomGenerated")) {
|
||||
config.putString(GameConfiguration.CLIENT_TOKEN, UUID.randomUUID().toString());
|
||||
config.saveToFile(Config.configFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.objects;
|
||||
package de.bixilon.minosoft;
|
||||
|
||||
import de.bixilon.minosoft.game.datatypes.TextComponent;
|
||||
import org.json.JSONObject;
|
@ -14,12 +14,13 @@
|
||||
package de.bixilon.minosoft.config;
|
||||
|
||||
import de.bixilon.minosoft.Config;
|
||||
import de.bixilon.minosoft.mojang.api.MojangAccount;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.*;
|
||||
|
||||
public class Configuration {
|
||||
LinkedHashMap<String, Object> config;
|
||||
@ -69,6 +70,38 @@ public class Configuration {
|
||||
}
|
||||
|
||||
|
||||
public void putBoolean(ConfigEnum config, boolean value) {
|
||||
putBoolean(config.getPath(), value);
|
||||
}
|
||||
|
||||
public void putBoolean(String path, boolean value) {
|
||||
put(path, value);
|
||||
}
|
||||
|
||||
public void putInteger(ConfigEnum config, int value) {
|
||||
putInteger(config.getPath(), value);
|
||||
}
|
||||
|
||||
public void putInteger(String path, int value) {
|
||||
put(path, value);
|
||||
}
|
||||
|
||||
public void putString(ConfigEnum config, String value) {
|
||||
putString(config.getPath(), value);
|
||||
}
|
||||
|
||||
public void putString(String path, String value) {
|
||||
put(path, value);
|
||||
}
|
||||
|
||||
public void putMojangAccount(MojangAccount account) {
|
||||
String basePath = String.format("account.accounts.%s.", account.getUserId());
|
||||
putString(basePath + "accessToken", account.getAccessToken());
|
||||
putString(basePath + "uuid", account.getUUID().toString());
|
||||
putString(basePath + "userName", account.getMojangUserName());
|
||||
putString(basePath + "playerName", account.getPlayerName());
|
||||
}
|
||||
|
||||
public Object get(String path) {
|
||||
if (path.contains(".")) {
|
||||
// split
|
||||
@ -78,9 +111,54 @@ public class Configuration {
|
||||
//noinspection unchecked
|
||||
temp = (LinkedHashMap<String, Object>) temp.get(spilt[i]);
|
||||
}
|
||||
if (temp == null) {
|
||||
return null;
|
||||
}
|
||||
return temp.get(spilt[spilt.length - 1]);
|
||||
}
|
||||
return config.get(path);
|
||||
}
|
||||
|
||||
public void put(String path, Serializable value) {
|
||||
if (path.contains(".")) {
|
||||
// split
|
||||
String[] spilt = path.split("\\.");
|
||||
LinkedHashMap<String, Object> temp = config;
|
||||
for (int i = 0; i < spilt.length - 1; i++) {
|
||||
if (temp.get(spilt[i]) == null) {
|
||||
// not yet existing, creating it
|
||||
temp.put(spilt[i], new LinkedHashMap<String, Object>());
|
||||
}
|
||||
temp = (LinkedHashMap<String, Object>) temp.get(spilt[i]);
|
||||
|
||||
}
|
||||
temp.put(spilt[spilt.length - 1], value);
|
||||
return;
|
||||
}
|
||||
config.put(path, value);
|
||||
}
|
||||
|
||||
public void saveToFile(String filename) {
|
||||
Yaml yaml = new Yaml();
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(Config.homeDir + "config/" + filename);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
yaml.dump(config, writer);
|
||||
}
|
||||
|
||||
public List<MojangAccount> getMojangAccounts() {
|
||||
List<MojangAccount> accounts = new ArrayList<>();
|
||||
LinkedHashMap<String, Object> objects = (LinkedHashMap<String, Object>) get("account.accounts");
|
||||
for (Map.Entry<String, Object> set : objects.entrySet()) {
|
||||
LinkedHashMap<String, Object> entry = (LinkedHashMap<String, Object>) set.getValue();
|
||||
accounts.add(new MojangAccount((String) entry.get("accessToken"), set.getKey(), UUID.fromString((String) entry.get("uuid")), (String) entry.get("playerName"), (String) entry.get("mojangUserName")));
|
||||
}
|
||||
return accounts;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,8 @@ public enum GameConfiguration implements ConfigEnum {
|
||||
CONFIG_VERSION("version"),
|
||||
GAME_RENDER_DISTANCE("game.render-distance"),
|
||||
NETWORK_FAKE_CLIENT_BRAND("network.fake-client-brand"),
|
||||
GENERAL_LOG_LEVEL("general.log-level");
|
||||
GENERAL_LOG_LEVEL("general.log-level"),
|
||||
CLIENT_TOKEN("account.clientToken");
|
||||
|
||||
|
||||
final String path;
|
||||
|
@ -11,20 +11,18 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.objects;
|
||||
package de.bixilon.minosoft.game.datatypes;
|
||||
|
||||
import de.bixilon.minosoft.game.datatypes.GameMode;
|
||||
import de.bixilon.minosoft.game.datatypes.Slot;
|
||||
import de.bixilon.minosoft.game.datatypes.Slots;
|
||||
import de.bixilon.minosoft.game.datatypes.entities.Location;
|
||||
import de.bixilon.minosoft.game.datatypes.entities.meta.HumanMetaData;
|
||||
import de.bixilon.minosoft.game.datatypes.world.World;
|
||||
import de.bixilon.minosoft.mojang.api.MojangAccount;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Player {
|
||||
final Account acc;
|
||||
final MojangAccount acc;
|
||||
float health;
|
||||
short food;
|
||||
float saturation;
|
||||
@ -39,9 +37,8 @@ public class Player {
|
||||
HashMap<Slots.Inventory, Slot> inventory = new HashMap<>();
|
||||
boolean spawnConfirmed = false;
|
||||
|
||||
public Player(Account acc) {
|
||||
public Player(MojangAccount acc) {
|
||||
this.acc = acc;
|
||||
acc.login();
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
@ -52,7 +49,7 @@ public class Player {
|
||||
return acc.getUUID();
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
public MojangAccount getAccount() {
|
||||
return this.acc;
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Codename Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.mojang.api;
|
||||
|
||||
import de.bixilon.minosoft.Config;
|
||||
import de.bixilon.minosoft.Minosoft;
|
||||
import de.bixilon.minosoft.util.Util;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MojangAccount {
|
||||
|
||||
String accessToken;
|
||||
String userId;
|
||||
|
||||
UUID uuid;
|
||||
String playerName;
|
||||
|
||||
String mojangUserName;
|
||||
|
||||
public MojangAccount(JSONObject json) {
|
||||
this.accessToken = json.getString("accessToken");
|
||||
JSONObject profile = json.getJSONObject("selectedProfile");
|
||||
this.uuid = Util.formatUUID(profile.getString("id"));
|
||||
this.playerName = profile.getString("name");
|
||||
|
||||
JSONObject mojang = json.getJSONObject("user");
|
||||
this.userId = mojang.getString("id");
|
||||
this.mojangUserName = mojang.getString("username");
|
||||
}
|
||||
|
||||
public MojangAccount(String accessToken, String userId, UUID uuid, String playerName, String mojangUserName) {
|
||||
this.accessToken = accessToken;
|
||||
this.userId = userId;
|
||||
this.uuid = uuid;
|
||||
this.playerName = playerName;
|
||||
this.mojangUserName = mojangUserName;
|
||||
}
|
||||
|
||||
public void join(String serverId) {
|
||||
MojangAuthentication.joinServer(this, serverId);
|
||||
}
|
||||
|
||||
public boolean refreshToken() {
|
||||
String accessToken = MojangAuthentication.refresh(this.accessToken);
|
||||
if (accessToken == null) {
|
||||
return false;
|
||||
}
|
||||
this.accessToken = accessToken;
|
||||
return true;
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return this.playerName;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public String getMojangUserName() {
|
||||
return mojangUserName;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void saveToConfig() {
|
||||
Minosoft.getConfig().putMojangAccount(this);
|
||||
Minosoft.getConfig().saveToFile(Config.configFileName);
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Codename Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.mojang.api;
|
||||
|
||||
import de.bixilon.minosoft.Minosoft;
|
||||
import de.bixilon.minosoft.config.GameConfiguration;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.util.HTTP;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
public class MojangAuthentication {
|
||||
|
||||
public static MojangAccount login(String clientToken, String username, String password) {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("agent", new JSONObject().put("name", "Minecraft").put("version", 1));
|
||||
payload.put("username", username);
|
||||
payload.put("password", password);
|
||||
payload.put("clientToken", clientToken);
|
||||
payload.put("requestUser", true);
|
||||
|
||||
HttpResponse<String> response = HTTP.postJson(MojangURLs.LOGIN.getUrl(), payload);
|
||||
if (response == null) {
|
||||
Log.mojang(String.format("Failed to login with username %s", username));
|
||||
return null;
|
||||
}
|
||||
JSONObject jsonResponse = new JSONObject(response.body());
|
||||
if (response.statusCode() != 200) {
|
||||
Log.mojang(String.format("Failed to login with error code %d: %s", response.statusCode(), jsonResponse.getString("errorMessage")));
|
||||
return null;
|
||||
}
|
||||
// now it is okay
|
||||
return new MojangAccount(jsonResponse);
|
||||
}
|
||||
|
||||
public static MojangAccount login(String username, String password) {
|
||||
return login(Minosoft.getConfig().getString(GameConfiguration.CLIENT_TOKEN), username, password);
|
||||
|
||||
}
|
||||
|
||||
public static void joinServer(MojangAccount account, String serverId) {
|
||||
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("accessToken", account.getAccessToken());
|
||||
payload.put("selectedProfile", account.getUUID().toString().replace("-", ""));
|
||||
payload.put("serverId", serverId);
|
||||
|
||||
HttpResponse<String> response = HTTP.postJson(MojangURLs.JOIN.toString(), payload);
|
||||
|
||||
if (response == null) {
|
||||
Log.mojang(String.format("Failed to join server: %s", serverId));
|
||||
return;
|
||||
}
|
||||
JSONObject jsonResponse = new JSONObject(response.body());
|
||||
if (response.statusCode() != 204) {
|
||||
Log.mojang(String.format("Failed to join server with error code %d: %s", response.statusCode(), jsonResponse.getString("errorMessage")));
|
||||
return;
|
||||
}
|
||||
// joined
|
||||
Log.mojang("Joined server successfully");
|
||||
}
|
||||
|
||||
public static String refresh(String clientToken, String accessToken) {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("accessToken", accessToken);
|
||||
payload.put("clientToken", clientToken);
|
||||
|
||||
HttpResponse<String> response = HTTP.postJson(MojangURLs.REFRESH.getUrl(), payload);
|
||||
if (response == null) {
|
||||
Log.mojang("Failed to refresh session");
|
||||
return null;
|
||||
}
|
||||
JSONObject jsonResponse = new JSONObject(response.body());
|
||||
if (response.statusCode() != 200) {
|
||||
Log.mojang(String.format("Failed to refresh session with error code %d: %s", response.statusCode(), jsonResponse.getString("errorMessage")));
|
||||
return null;
|
||||
}
|
||||
// now it is okay
|
||||
return jsonResponse.getString("accessToken");
|
||||
}
|
||||
|
||||
public static String refresh(String accessToken) {
|
||||
return refresh(Minosoft.getConfig().getString(GameConfiguration.CLIENT_TOKEN), accessToken);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Codename Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.mojang.api;
|
||||
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.util.HTTP;
|
||||
import de.bixilon.minosoft.util.Util;
|
||||
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MojangBlockedServers {
|
||||
|
||||
|
||||
public static List<String> getBlockedServers() {
|
||||
HttpResponse<String> response = HTTP.get(MojangURLs.BLOCKED_SERVERS.getUrl());
|
||||
if (response == null) {
|
||||
Log.mojang("Failed to fetch blocked servers");
|
||||
return null;
|
||||
}
|
||||
if (response.statusCode() != 200) {
|
||||
Log.mojang(String.format("Failed to fetch blocked server error code %d", response.statusCode()));
|
||||
return null;
|
||||
}
|
||||
// now it is hopefully okay
|
||||
return new ArrayList<>(Arrays.asList(response.body().split("\n")));
|
||||
}
|
||||
|
||||
public boolean isServerBlocked(List<String> list, String hostname) {
|
||||
for (String hash : list) {
|
||||
if (hash.equals(Util.sha1(hostname))) {
|
||||
return true;
|
||||
}
|
||||
// ToDo: check subdomains and ip addresses
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
115
src/main/java/de/bixilon/minosoft/mojang/api/MojangStatus.java
Normal file
115
src/main/java/de/bixilon/minosoft/mojang/api/MojangStatus.java
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Codename Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.mojang.api;
|
||||
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.util.HTTP;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class MojangStatus {
|
||||
public static HashMap<Services, ServiceStatus> getStatus() {
|
||||
HttpResponse<String> response = HTTP.get(MojangURLs.STATUS.getUrl());
|
||||
if (response == null) {
|
||||
Log.mojang("Failed to fetch Status");
|
||||
return getUnknownStatusMap();
|
||||
}
|
||||
if (response.statusCode() != 200) {
|
||||
Log.mojang(String.format("Failed to fetch Status with error code %d", response.statusCode()));
|
||||
return getUnknownStatusMap();
|
||||
}
|
||||
// now it is hopefully okay
|
||||
HashMap<Services, ServiceStatus> ret = new HashMap<>();
|
||||
try {
|
||||
JSONArray json = new JSONArray(response.body());
|
||||
for (int i = 0; i < json.length(); i++) {
|
||||
JSONObject innerJson = json.getJSONObject(i);
|
||||
Iterator<String> keys = innerJson.keys();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Services service = Services.byKey(key);
|
||||
ret.put(service, ServiceStatus.byKey(innerJson.getString(key)));
|
||||
}
|
||||
}
|
||||
if (ret.size() != Services.values().length) {
|
||||
// new service or old one removed, technically an error
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
|
||||
} catch (NullPointerException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
return getUnknownStatusMap();
|
||||
}
|
||||
}
|
||||
|
||||
static HashMap<Services, ServiceStatus> getUnknownStatusMap() {
|
||||
HashMap<Services, ServiceStatus> ret = new HashMap<>();
|
||||
for (Services service : Services.values()) {
|
||||
ret.put(service, ServiceStatus.UNKNOWN);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum Services {
|
||||
MINECRAFT_NET("minecraft.net"),
|
||||
ACCOUNT("account.mojang.com"),
|
||||
AUTH("auth.mojang.com"),
|
||||
AUTHENTICATION_SERVER("authserver.mojang.com"),
|
||||
SESSION_SERVER("sessionserver.mojang.com"),
|
||||
API("api.mojang.com"),
|
||||
TEXTURES("textures.minecraft.net"),
|
||||
MOJANG_COM("mojang.com");
|
||||
|
||||
final String key;
|
||||
|
||||
Services(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public static Services byKey(String key) {
|
||||
for (Services s : values()) {
|
||||
if (s.getKey().equals(key)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
enum ServiceStatus {
|
||||
GREEN,
|
||||
YELLOW,
|
||||
RED,
|
||||
UNKNOWN;
|
||||
|
||||
public static ServiceStatus byKey(String key) {
|
||||
for (ServiceStatus s : values()) {
|
||||
if (s.name().equals(key)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
46
src/main/java/de/bixilon/minosoft/mojang/api/MojangURLs.java
Normal file
46
src/main/java/de/bixilon/minosoft/mojang/api/MojangURLs.java
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Codename Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.mojang.api;
|
||||
|
||||
public enum MojangURLs {
|
||||
STATUS("https://status.mojang.com/check"),
|
||||
BLOCKED_SERVERS("https://sessionserver.mojang.com/blockedservers"),
|
||||
LOGIN("https://authserver.mojang.com/authenticate"),
|
||||
JOIN("https://sessionserver.mojang.com/session/minecraft/join"),
|
||||
REFRESH("https://authserver.mojang.com/refresh");
|
||||
|
||||
final String url;
|
||||
|
||||
MojangURLs(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public static MojangURLs byUrl(String key) {
|
||||
for (MojangURLs s : values()) {
|
||||
if (s.getUrl().equals(key)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return url;
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Codename Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.objects;
|
||||
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.util.HTTP;
|
||||
import de.bixilon.minosoft.util.Util;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Account {
|
||||
|
||||
final String username;
|
||||
final String password;
|
||||
String playerName;
|
||||
|
||||
String token;
|
||||
UUID uuid;
|
||||
|
||||
public Account(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void login() {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("agent", new JSONObject().put("name", "Minecraft").put("version", 1));
|
||||
payload.put("username", username);
|
||||
payload.put("password", password);
|
||||
// ToDo not in main thread
|
||||
HttpResponse<String> response = HTTP.postJson("https://authserver.mojang.com/authenticate", payload);
|
||||
if (response == null || response.statusCode() != 200) {
|
||||
assert response != null;
|
||||
Log.info(String.format("[Mojang API] Login failed with username=%s (%s)", username, response.statusCode()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Log.info(String.format("[Mojang API] Login successful with username=%s", username));
|
||||
|
||||
// login good
|
||||
JSONObject raw = new JSONObject(response.body());
|
||||
|
||||
token = raw.getString("accessToken");
|
||||
|
||||
uuid = Util.formatUUID(raw.getJSONObject("selectedProfile").getString("id"));
|
||||
playerName = raw.getJSONObject("selectedProfile").getString("name");
|
||||
}
|
||||
|
||||
public void join(String serverId) {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("accessToken", token);
|
||||
payload.put("selectedProfile", getUUID().toString().replace("-", ""));
|
||||
payload.put("serverId", serverId);
|
||||
// ToDo not in main thread
|
||||
HttpResponse<String> response = HTTP.postJson("https://sessionserver.mojang.com/session/minecraft/join", payload);
|
||||
if (response == null || response.statusCode() != 204) {
|
||||
assert response != null;
|
||||
Log.info("[Mojang API] Login to join server!");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info("[Mojang API] Joined server successfully");
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return this.playerName;
|
||||
}
|
||||
}
|
@ -13,8 +13,8 @@
|
||||
|
||||
package de.bixilon.minosoft.protocol.network;
|
||||
|
||||
import de.bixilon.minosoft.game.datatypes.Player;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.objects.Player;
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
|
||||
import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketHandshake;
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
package de.bixilon.minosoft.protocol.packets.clientbound.status;
|
||||
|
||||
import de.bixilon.minosoft.ServerListPing;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.objects.ServerListPing;
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||
import de.bixilon.minosoft.protocol.protocol.InPacketBuffer;
|
||||
import de.bixilon.minosoft.protocol.protocol.PacketHandler;
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
package de.bixilon.minosoft.protocol.packets.serverbound.login;
|
||||
|
||||
import de.bixilon.minosoft.game.datatypes.Player;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.objects.Player;
|
||||
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
|
||||
import de.bixilon.minosoft.protocol.protocol.OutPacketBuffer;
|
||||
import de.bixilon.minosoft.protocol.protocol.Packets;
|
||||
|
@ -31,8 +31,20 @@ public class HTTP {
|
||||
.header("Content-Type", "application/json")
|
||||
.build();
|
||||
try {
|
||||
return client.send(request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
return client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HttpResponse<String> get(String url) {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.build();
|
||||
try {
|
||||
return client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.DataFormatException;
|
||||
@ -77,4 +80,17 @@ public class Util {
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
public static String sha1(String string) {
|
||||
try {
|
||||
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
||||
crypt.reset();
|
||||
crypt.update(string.getBytes(StandardCharsets.UTF_8));
|
||||
return new String(crypt.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ game:
|
||||
network:
|
||||
fake-client-brand: false # if true, minosoft will tell the server that this is unmodified vanilla. if false, it will tell "minosoft".
|
||||
|
||||
# this will be removed soon
|
||||
account:
|
||||
clientToken: "randomGenerated"
|
||||
accounts:
|
||||
|
||||
# this will be removed soon, only for debugging (pre alpha stage): some features are not implemented yet -/-
|
||||
debug:
|
||||
host: "127.0.0.1"
|
||||
port: 25565
|
||||
username: "Player"
|
||||
password: "secret123"
|
||||
port: 25565
|
Loading…
x
Reference in New Issue
Block a user