feat(multiplayer): move token storage to glboal to prevent from token leak.
This commit is contained in:
@@ -158,12 +158,6 @@ public final class Config implements Cloneable, Observable {
|
|||||||
@SerializedName("logLines")
|
@SerializedName("logLines")
|
||||||
private IntegerProperty logLines = new SimpleIntegerProperty(100);
|
private IntegerProperty logLines = new SimpleIntegerProperty(100);
|
||||||
|
|
||||||
@SerializedName("multiplayerAgreementVersion")
|
|
||||||
private IntegerProperty multiplayerAgreementVersion = new SimpleIntegerProperty(0);
|
|
||||||
|
|
||||||
@SerializedName("multiplayerToken")
|
|
||||||
private StringProperty multiplayerToken = new SimpleStringProperty();
|
|
||||||
|
|
||||||
@SerializedName("authlibInjectorServers")
|
@SerializedName("authlibInjectorServers")
|
||||||
private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList(server -> new Observable[] { server });
|
private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList(server -> new Observable[] { server });
|
||||||
|
|
||||||
@@ -587,27 +581,4 @@ public final class Config implements Cloneable, Observable {
|
|||||||
return preferredLoginType;
|
return preferredLoginType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMultiplayerAgreementVersion() {
|
|
||||||
return multiplayerAgreementVersion.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntegerProperty multiplayerAgreementVersionProperty() {
|
|
||||||
return multiplayerAgreementVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMultiplayerAgreementVersion(int multiplayerAgreementVersion) {
|
|
||||||
this.multiplayerAgreementVersion.set(multiplayerAgreementVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMultiplayerToken() {
|
|
||||||
return multiplayerToken.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringProperty multiplayerTokenProperty() {
|
|
||||||
return multiplayerToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMultiplayerToken(String multiplayerToken) {
|
|
||||||
this.multiplayerToken.set(multiplayerToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.setting;
|
package org.jackhuang.hmcl.setting;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.*;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import javafx.beans.InvalidationListener;
|
import javafx.beans.InvalidationListener;
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
import javafx.collections.ObservableSet;
|
import javafx.collections.ObservableSet;
|
||||||
@@ -39,8 +39,11 @@ import org.jackhuang.hmcl.util.javafx.PropertyUtils;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@JsonAdapter(GlobalConfig.Serializer.class)
|
||||||
public class GlobalConfig implements Cloneable, Observable {
|
public class GlobalConfig implements Cloneable, Observable {
|
||||||
|
|
||||||
private static final Gson CONFIG_GSON = new GsonBuilder()
|
private static final Gson CONFIG_GSON = new GsonBuilder()
|
||||||
@@ -62,12 +65,18 @@ public class GlobalConfig implements Cloneable, Observable {
|
|||||||
}
|
}
|
||||||
GlobalConfig instance = new GlobalConfig();
|
GlobalConfig instance = new GlobalConfig();
|
||||||
PropertyUtils.copyProperties(loaded, instance);
|
PropertyUtils.copyProperties(loaded, instance);
|
||||||
|
instance.unknownFields.putAll(loaded.unknownFields);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SerializedName("agreementVersion")
|
|
||||||
private IntegerProperty agreementVersion = new SimpleIntegerProperty();
|
private IntegerProperty agreementVersion = new SimpleIntegerProperty();
|
||||||
|
|
||||||
|
private StringProperty multiplayerToken = new SimpleStringProperty();
|
||||||
|
|
||||||
|
private IntegerProperty multiplayerAgreementVersion = new SimpleIntegerProperty(0);
|
||||||
|
|
||||||
|
private final Map<String, Object> unknownFields = new HashMap<>();
|
||||||
|
|
||||||
private transient ObservableHelper helper = new ObservableHelper(this);
|
private transient ObservableHelper helper = new ObservableHelper(this);
|
||||||
|
|
||||||
public GlobalConfig() {
|
public GlobalConfig() {
|
||||||
@@ -104,4 +113,73 @@ public class GlobalConfig implements Cloneable, Observable {
|
|||||||
public void setAgreementVersion(int agreementVersion) {
|
public void setAgreementVersion(int agreementVersion) {
|
||||||
this.agreementVersion.set(agreementVersion);
|
this.agreementVersion.set(agreementVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMultiplayerAgreementVersion() {
|
||||||
|
return multiplayerAgreementVersion.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerProperty multiplayerAgreementVersionProperty() {
|
||||||
|
return multiplayerAgreementVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMultiplayerAgreementVersion(int multiplayerAgreementVersion) {
|
||||||
|
this.multiplayerAgreementVersion.set(multiplayerAgreementVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMultiplayerToken() {
|
||||||
|
return multiplayerToken.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringProperty multiplayerTokenProperty() {
|
||||||
|
return multiplayerToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMultiplayerToken(String multiplayerToken) {
|
||||||
|
this.multiplayerToken.set(multiplayerToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Serializer implements JsonSerializer<GlobalConfig>, JsonDeserializer<GlobalConfig> {
|
||||||
|
private static final Set<String> knownFields = new HashSet<>(Arrays.asList(
|
||||||
|
"agreementVersion",
|
||||||
|
"multiplayerToken",
|
||||||
|
"multiplayerAgreementVersion"
|
||||||
|
));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(GlobalConfig src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
|
if (src == null) {
|
||||||
|
return JsonNull.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.add("agreementVersion", context.serialize(src.getAgreementVersion()));
|
||||||
|
jsonObject.add("multiplayerToken", context.serialize(src.getMultiplayerToken()));
|
||||||
|
jsonObject.add("multiplayerAgreementVersion", context.serialize(src.getMultiplayerAgreementVersion()));
|
||||||
|
for (Map.Entry<String, Object> entry : src.unknownFields.entrySet()) {
|
||||||
|
jsonObject.add(entry.getKey(), context.serialize(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GlobalConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
if (!(json instanceof JsonObject)) return null;
|
||||||
|
|
||||||
|
JsonObject obj = (JsonObject) json;
|
||||||
|
|
||||||
|
GlobalConfig config = new GlobalConfig();
|
||||||
|
config.setAgreementVersion(Optional.ofNullable(obj.get("agreementVersion")).map(JsonElement::getAsInt).orElse(0));
|
||||||
|
config.setMultiplayerToken(Optional.ofNullable(obj.get("multiplayerToken")).map(JsonElement::getAsString).orElse(null));
|
||||||
|
config.setMultiplayerAgreementVersion(Optional.ofNullable(obj.get("multiplayerAgreementVersion")).map(JsonElement::getAsInt).orElse(0));
|
||||||
|
|
||||||
|
for (Map.Entry<String, JsonElement> entry : obj.entrySet()) {
|
||||||
|
if (!knownFields.contains(entry.getKey())) {
|
||||||
|
config.unknownFields.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
@@ -139,7 +139,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkAgreement(Runnable runnable) {
|
private void checkAgreement(Runnable runnable) {
|
||||||
if (config().getMultiplayerAgreementVersion() < MultiplayerManager.CATO_AGREEMENT_VERSION) {
|
if (globalConfig().getMultiplayerAgreementVersion() < MultiplayerManager.CATO_AGREEMENT_VERSION) {
|
||||||
JFXDialogLayout agreementPane = new JFXDialogLayout();
|
JFXDialogLayout agreementPane = new JFXDialogLayout();
|
||||||
agreementPane.setHeading(new Label(i18n("launcher.agreement")));
|
agreementPane.setHeading(new Label(i18n("launcher.agreement")));
|
||||||
agreementPane.setBody(new Label(i18n("multiplayer.agreement.prompt")));
|
agreementPane.setBody(new Label(i18n("multiplayer.agreement.prompt")));
|
||||||
@@ -148,7 +148,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
|||||||
JFXButton yesButton = new JFXButton(i18n("launcher.agreement.accept"));
|
JFXButton yesButton = new JFXButton(i18n("launcher.agreement.accept"));
|
||||||
yesButton.getStyleClass().add("dialog-accept");
|
yesButton.getStyleClass().add("dialog-accept");
|
||||||
yesButton.setOnAction(e -> {
|
yesButton.setOnAction(e -> {
|
||||||
config().setMultiplayerAgreementVersion(MultiplayerManager.CATO_AGREEMENT_VERSION);
|
globalConfig().setMultiplayerAgreementVersion(MultiplayerManager.CATO_AGREEMENT_VERSION);
|
||||||
runnable.run();
|
runnable.run();
|
||||||
agreementPane.fireEvent(new DialogCloseEvent());
|
agreementPane.fireEvent(new DialogCloseEvent());
|
||||||
});
|
});
|
||||||
@@ -209,7 +209,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
|||||||
Controllers.dialog(new CreateMultiplayerRoomDialog((result, resolve, reject) -> {
|
Controllers.dialog(new CreateMultiplayerRoomDialog((result, resolve, reject) -> {
|
||||||
int gamePort = result.getAd();
|
int gamePort = result.getAd();
|
||||||
try {
|
try {
|
||||||
MultiplayerManager.CatoSession session = MultiplayerManager.createSession(config().getMultiplayerToken(), result.getMotd(), gamePort);
|
MultiplayerManager.CatoSession session = MultiplayerManager.createSession(globalConfig().getMultiplayerToken(), result.getMotd(), gamePort);
|
||||||
session.getServer().setOnClientAdding((client, resolveClient, rejectClient) -> {
|
session.getServer().setOnClientAdding((client, resolveClient, rejectClient) -> {
|
||||||
runInFX(() -> {
|
runInFX(() -> {
|
||||||
Controllers.confirm(i18n("multiplayer.session.create.join.prompt", client.getUsername()), i18n("multiplayer.session.create.join"), MessageDialogPane.MessageType.INFO,
|
Controllers.confirm(i18n("multiplayer.session.create.join.prompt", client.getUsername()), i18n("multiplayer.session.create.join"), MessageDialogPane.MessageType.INFO,
|
||||||
@@ -264,7 +264,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MultiplayerManager.joinSession(config().getMultiplayerToken(), invitation.getVersion(), invitation.getSessionName(), invitation.getId(), invitation.getChannelPort(), localPort)
|
MultiplayerManager.joinSession(globalConfig().getMultiplayerToken(), invitation.getVersion(), invitation.getSessionName(), invitation.getId(), invitation.getChannelPort(), localPort)
|
||||||
.thenAcceptAsync(session -> {
|
.thenAcceptAsync(session -> {
|
||||||
initCatoSession(session);
|
initCatoSession(session);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import org.jackhuang.hmcl.ui.versions.Versions;
|
|||||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||||
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
|
||||||
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
|
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ public class MultiplayerPageSkin extends SkinBase<MultiplayerPage> {
|
|||||||
gridPane.setHgap(16);
|
gridPane.setHgap(16);
|
||||||
|
|
||||||
JFXTextField tokenField = new JFXTextField();
|
JFXTextField tokenField = new JFXTextField();
|
||||||
tokenField.textProperty().bindBidirectional(config().multiplayerTokenProperty());
|
tokenField.textProperty().bindBidirectional(globalConfig().multiplayerTokenProperty());
|
||||||
tokenField.setPromptText(i18n("multiplayer.session.create.token.prompt"));
|
tokenField.setPromptText(i18n("multiplayer.session.create.token.prompt"));
|
||||||
|
|
||||||
JFXHyperlink applyLink = new JFXHyperlink(i18n("multiplayer.session.create.token.apply"));
|
JFXHyperlink applyLink = new JFXHyperlink(i18n("multiplayer.session.create.token.apply"));
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
package org.jackhuang.hmcl.ui.multiplayer;
|
package org.jackhuang.hmcl.ui.multiplayer;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.util.Logging;
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
import org.junit.Ignore;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class MultiplayerClientServerTest {
|
public class MultiplayerClientServerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
// @Ignore
|
||||||
public void startServer() throws Exception {
|
public void startServer() throws Exception {
|
||||||
Logging.initForTest();
|
Logging.initForTest();
|
||||||
MultiplayerServer server = new MultiplayerServer(1000);
|
MultiplayerServer server = new MultiplayerServer(1000);
|
||||||
@@ -33,7 +33,8 @@ public class MultiplayerClientServerTest {
|
|||||||
MultiplayerClient client = new MultiplayerClient("username", 44444);
|
MultiplayerClient client = new MultiplayerClient("username", 44444);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
server.onKeepAlive().register(event -> {
|
server.onClientAdded().register(event -> {
|
||||||
|
Assert.assertEquals("username", event.getUsername());
|
||||||
client.interrupt();
|
client.interrupt();
|
||||||
server.interrupt();
|
server.interrupt();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user