mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-08-04 03:46:57 -04:00
test
This commit is contained in:
parent
9b95f9d2d7
commit
a58aeee40c
@ -1,27 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
public class Agent {
|
|
||||||
|
|
||||||
public static final Agent MINECRAFT = new Agent("Minecraft", 1);
|
|
||||||
private final String name;
|
|
||||||
private final int version;
|
|
||||||
|
|
||||||
public Agent(String name, int version) {
|
|
||||||
this.name = name;
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVersion() {
|
|
||||||
return this.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Agent{name='" + this.name + '\'' + ", version=" + this.version + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
public abstract interface AuthenticationService {
|
|
||||||
|
|
||||||
public abstract UserAuthentication createUserAuthentication(Agent paramAgent);
|
|
||||||
}
|
|
@ -1,261 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.jackhuang.hellominecraft.logging.logger.Logger;
|
|
||||||
import org.jackhuang.hellominecraft.utils.StrUtils;
|
|
||||||
import org.jackhuang.mojang.authlib.properties.Property;
|
|
||||||
import org.jackhuang.mojang.authlib.properties.PropertyMap;
|
|
||||||
import org.jackhuang.mojang.util.UUIDTypeAdapter;
|
|
||||||
|
|
||||||
public abstract class BaseUserAuthentication
|
|
||||||
implements UserAuthentication {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = new Logger("BaseUserAuthentication");
|
|
||||||
protected static final String STORAGE_KEY_PROFILE_NAME = "displayName";
|
|
||||||
protected static final String STORAGE_KEY_PROFILE_ID = "uuid";
|
|
||||||
protected static final String STORAGE_KEY_PROFILE_PROPERTIES = "profileProperties";
|
|
||||||
protected static final String STORAGE_KEY_USER_NAME = "username";
|
|
||||||
protected static final String STORAGE_KEY_USER_ID = "userid";
|
|
||||||
protected static final String STORAGE_KEY_USER_PROPERTIES = "userProperties";
|
|
||||||
private final AuthenticationService authenticationService;
|
|
||||||
private final PropertyMap userProperties = new PropertyMap();
|
|
||||||
private String userid;
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
private GameProfile selectedProfile;
|
|
||||||
private UserType userType;
|
|
||||||
|
|
||||||
protected BaseUserAuthentication(AuthenticationService authenticationService) {
|
|
||||||
this.authenticationService = authenticationService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canLogIn() {
|
|
||||||
return (!canPlayOnline()) && (StrUtils.isNotBlank(getUsername())) && (StrUtils.isNotBlank(getPassword()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logOut() {
|
|
||||||
this.password = null;
|
|
||||||
this.userid = null;
|
|
||||||
setSelectedProfile(null);
|
|
||||||
getModifiableUserProperties().clear();
|
|
||||||
setUserType(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLoggedIn() {
|
|
||||||
return getSelectedProfile() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUsername(String username) {
|
|
||||||
if ((isLoggedIn()) && (canPlayOnline())) {
|
|
||||||
throw new IllegalStateException("Cannot change username whilst logged in & online");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPassword(String password) {
|
|
||||||
if ((isLoggedIn()) && (canPlayOnline()) && (StrUtils.isNotBlank(password))) {
|
|
||||||
throw new IllegalStateException("Cannot set password whilst logged in & online");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getUsername() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getPassword() {
|
|
||||||
return this.password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadFromStorage(Map<String, Object> credentials) {
|
|
||||||
logOut();
|
|
||||||
|
|
||||||
setUsername((String)credentials.get("username"));
|
|
||||||
|
|
||||||
if (credentials.containsKey("userid")) {
|
|
||||||
this.userid = (String)credentials.get("userid");
|
|
||||||
} else {
|
|
||||||
this.userid = this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (credentials.containsKey("userProperties")) {
|
|
||||||
try {
|
|
||||||
List<Map> list = (List<Map>) credentials.get("userProperties");
|
|
||||||
|
|
||||||
for (Map propertyMap : list) {
|
|
||||||
String name = (String) propertyMap.get("name");
|
|
||||||
String value = (String) propertyMap.get("value");
|
|
||||||
String signature = (String) propertyMap.get("signature");
|
|
||||||
|
|
||||||
if (signature == null) {
|
|
||||||
getModifiableUserProperties().put(name, new Property(name, value));
|
|
||||||
} else {
|
|
||||||
getModifiableUserProperties().put(name, new Property(name, value, signature));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
LOGGER.warn("Couldn't deserialize user properties", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((credentials.containsKey("displayName")) && (credentials.containsKey("uuid"))) {
|
|
||||||
GameProfile profile = new GameProfile(UUIDTypeAdapter.fromString((String)credentials.get("uuid")), (String)credentials.get("displayName"));
|
|
||||||
if (credentials.containsKey("profileProperties")) {
|
|
||||||
try {
|
|
||||||
List<Map> list = (List<Map>) credentials.get("profileProperties");
|
|
||||||
for (Map propertyMap : list) {
|
|
||||||
String name = (String) propertyMap.get("name");
|
|
||||||
String value = (String) propertyMap.get("value");
|
|
||||||
String signature = (String) propertyMap.get("signature");
|
|
||||||
|
|
||||||
if (signature == null) {
|
|
||||||
profile.getProperties().put(name, new Property(name, value));
|
|
||||||
} else {
|
|
||||||
profile.getProperties().put(name, new Property(name, value, signature));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
LOGGER.warn("Couldn't deserialize profile properties", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setSelectedProfile(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> saveForStorage() {
|
|
||||||
Map result = new HashMap();
|
|
||||||
|
|
||||||
if (getUsername() != null) {
|
|
||||||
result.put("username", getUsername());
|
|
||||||
}
|
|
||||||
if (getUserID() != null) {
|
|
||||||
result.put("userid", getUserID());
|
|
||||||
} else if (getUsername() != null) {
|
|
||||||
result.put("username", getUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!getUserProperties().isEmpty()) {
|
|
||||||
List properties = new ArrayList();
|
|
||||||
for (Property userProperty : getUserProperties().values()) {
|
|
||||||
Map property = new HashMap();
|
|
||||||
property.put("name", userProperty.getName());
|
|
||||||
property.put("value", userProperty.getValue());
|
|
||||||
property.put("signature", userProperty.getSignature());
|
|
||||||
properties.add(property);
|
|
||||||
}
|
|
||||||
result.put("userProperties", properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameProfile sel = getSelectedProfile();
|
|
||||||
if (sel != null) {
|
|
||||||
result.put("displayName", sel.getName());
|
|
||||||
result.put("uuid", sel.getId());
|
|
||||||
|
|
||||||
List properties = new ArrayList();
|
|
||||||
for (Property profileProperty : sel.getProperties().values()) {
|
|
||||||
Map property = new HashMap();
|
|
||||||
property.put("name", profileProperty.getName());
|
|
||||||
property.put("value", profileProperty.getValue());
|
|
||||||
property.put("signature", profileProperty.getSignature());
|
|
||||||
properties.add(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!properties.isEmpty()) {
|
|
||||||
result.put("profileProperties", properties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setSelectedProfile(GameProfile selectedProfile) {
|
|
||||||
this.selectedProfile = selectedProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GameProfile getSelectedProfile() {
|
|
||||||
return this.selectedProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
|
|
||||||
result.append(getClass().getSimpleName());
|
|
||||||
result.append("{");
|
|
||||||
|
|
||||||
if (isLoggedIn()) {
|
|
||||||
result.append("Logged in as ");
|
|
||||||
result.append(getUsername());
|
|
||||||
|
|
||||||
if (getSelectedProfile() != null) {
|
|
||||||
result.append(" / ");
|
|
||||||
result.append(getSelectedProfile());
|
|
||||||
result.append(" - ");
|
|
||||||
|
|
||||||
if (canPlayOnline()) {
|
|
||||||
result.append("Online");
|
|
||||||
} else {
|
|
||||||
result.append("Offline");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.append("Not logged in");
|
|
||||||
}
|
|
||||||
|
|
||||||
result.append("}");
|
|
||||||
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationService getAuthenticationService() {
|
|
||||||
return this.authenticationService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUserID() {
|
|
||||||
return this.userid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyMap getUserProperties() {
|
|
||||||
if (isLoggedIn()) {
|
|
||||||
PropertyMap result = new PropertyMap();
|
|
||||||
result.putAll(getModifiableUserProperties());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return new PropertyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PropertyMap getModifiableUserProperties() {
|
|
||||||
return this.userProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserType getUserType() {
|
|
||||||
if (isLoggedIn()) {
|
|
||||||
return this.userType == null ? UserType.LEGACY : this.userType;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setUserType(UserType userType) {
|
|
||||||
this.userType = userType;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setUserid(String userid) {
|
|
||||||
this.userid = userid;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.properties.PropertyMap;
|
|
||||||
import java.util.UUID;
|
|
||||||
import org.jackhuang.hellominecraft.utils.StrUtils;
|
|
||||||
|
|
||||||
public class GameProfile {
|
|
||||||
|
|
||||||
private final UUID id;
|
|
||||||
private final String name;
|
|
||||||
private final PropertyMap properties = new PropertyMap();
|
|
||||||
private boolean legacy;
|
|
||||||
|
|
||||||
public GameProfile(UUID id, String name) {
|
|
||||||
if ((id == null) && (StrUtils.isBlank(name))) {
|
|
||||||
throw new IllegalArgumentException("Name and ID cannot both be blank");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PropertyMap getProperties() {
|
|
||||||
return this.properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isComplete() {
|
|
||||||
return (this.id != null) && (StrUtils.isNotBlank(getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((o == null) || (getClass() != o.getClass())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameProfile that = (GameProfile) o;
|
|
||||||
|
|
||||||
if (this.id != null ? !this.id.equals(that.id) : that.id != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.name != null ? this.name.equals(that.name) : that.name == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = this.id != null ? this.id.hashCode() : 0;
|
|
||||||
result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "GameProfile{" + "id=" + id + ", name=" + name + ", properties=" + properties + ", legacy=" + legacy + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isLegacy() {
|
|
||||||
return this.legacy;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.jackhuang.hellominecraft.logging.logger.Logger;
|
|
||||||
import org.jackhuang.hellominecraft.utils.system.IOUtils;
|
|
||||||
import org.jackhuang.hellominecraft.utils.NetUtils;
|
|
||||||
import org.jackhuang.hellominecraft.utils.Utils;
|
|
||||||
|
|
||||||
public abstract class HttpAuthenticationService implements AuthenticationService {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = new Logger("HttpAuthenticationService");
|
|
||||||
private final Proxy proxy;
|
|
||||||
|
|
||||||
protected HttpAuthenticationService(Proxy proxy) {
|
|
||||||
this.proxy = proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Proxy getProxy() {
|
|
||||||
return this.proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HttpURLConnection createUrlConnection(URL url) throws IOException {
|
|
||||||
LOGGER.debug("Opening connection to " + url);
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection(this.proxy);
|
|
||||||
connection.setConnectTimeout(15000);
|
|
||||||
connection.setReadTimeout(15000);
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String performPostRequest(URL url, String post, String contentType) throws IOException {
|
|
||||||
Utils.requireNonNull(url);
|
|
||||||
Utils.requireNonNull(post);
|
|
||||||
Utils.requireNonNull(contentType);
|
|
||||||
HttpURLConnection connection = createUrlConnection(url);
|
|
||||||
byte[] postAsBytes = post.getBytes("UTF-8");
|
|
||||||
|
|
||||||
connection.setRequestProperty("Content-Type", contentType + "; charset=utf-8");
|
|
||||||
connection.setRequestProperty("Content-Length", "" + postAsBytes.length);
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
|
|
||||||
LOGGER.debug("Writing POST data to " + url + ": " + post);
|
|
||||||
|
|
||||||
OutputStream outputStream = null;
|
|
||||||
try {
|
|
||||||
outputStream = connection.getOutputStream();
|
|
||||||
IOUtils.write(postAsBytes, outputStream);
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debug("Reading data from " + url);
|
|
||||||
|
|
||||||
InputStream inputStream = null;
|
|
||||||
try {
|
|
||||||
inputStream = connection.getInputStream();
|
|
||||||
String result = NetUtils.getStreamContent(inputStream, "UTF-8");
|
|
||||||
LOGGER.debug("Successful read, server response was " + connection.getResponseCode());
|
|
||||||
LOGGER.debug("Response: " + result);
|
|
||||||
String str1 = result;
|
|
||||||
return str1;
|
|
||||||
} catch (IOException e) {
|
|
||||||
IOUtils.closeQuietly(inputStream);
|
|
||||||
inputStream = connection.getErrorStream();
|
|
||||||
|
|
||||||
if (inputStream != null) {
|
|
||||||
LOGGER.debug("Reading error page from " + url);
|
|
||||||
String result = NetUtils.getStreamContent(inputStream, "UTF-8");
|
|
||||||
LOGGER.debug("Successful read, server response was " + connection.getResponseCode());
|
|
||||||
LOGGER.debug("Response: " + result);
|
|
||||||
String str2 = result;
|
|
||||||
return str2;
|
|
||||||
}
|
|
||||||
LOGGER.debug("Request failed", e);
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(inputStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String performGetRequest(URL url)
|
|
||||||
throws IOException {
|
|
||||||
Utils.requireNonNull(url);
|
|
||||||
HttpURLConnection connection = createUrlConnection(url);
|
|
||||||
|
|
||||||
LOGGER.debug("Reading data from " + url);
|
|
||||||
|
|
||||||
InputStream inputStream = null;
|
|
||||||
try {
|
|
||||||
inputStream = connection.getInputStream();
|
|
||||||
String result = NetUtils.getStreamContent(inputStream, "UTF-8");
|
|
||||||
LOGGER.debug("Successful read, server response was " + connection.getResponseCode());
|
|
||||||
LOGGER.debug("Response: " + result);
|
|
||||||
String str1 = result;
|
|
||||||
return str1;
|
|
||||||
} catch (IOException e) {
|
|
||||||
IOUtils.closeQuietly(inputStream);
|
|
||||||
inputStream = connection.getErrorStream();
|
|
||||||
|
|
||||||
if (inputStream != null) {
|
|
||||||
LOGGER.debug("Reading error page from " + url);
|
|
||||||
String result = NetUtils.getStreamContent(inputStream, "UTF-8");
|
|
||||||
LOGGER.debug("Successful read, server response was " + connection.getResponseCode());
|
|
||||||
LOGGER.debug("Response: " + result);
|
|
||||||
String str2 = result;
|
|
||||||
return str2;
|
|
||||||
}
|
|
||||||
LOGGER.debug("Request failed", e);
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(inputStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String buildQuery(Map<String, Object> query) {
|
|
||||||
if (query == null) return "";
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
for (Map.Entry<String, Object> entry : query.entrySet()) {
|
|
||||||
if (builder.length() > 0)
|
|
||||||
builder.append('&');
|
|
||||||
try {
|
|
||||||
builder.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
LOGGER.error("Unexpected exception building query", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.getValue() != null) {
|
|
||||||
builder.append('=');
|
|
||||||
try {
|
|
||||||
builder.append(URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
LOGGER.error("Unexpected exception building query", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
public abstract class HttpUserAuthentication extends BaseUserAuthentication {
|
|
||||||
|
|
||||||
protected HttpUserAuthentication(HttpAuthenticationService authenticationService) {
|
|
||||||
super(authenticationService);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpAuthenticationService getAuthenticationService() {
|
|
||||||
return (HttpAuthenticationService) super.getAuthenticationService();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.AuthenticationException;
|
|
||||||
import org.jackhuang.mojang.authlib.properties.PropertyMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract interface UserAuthentication {
|
|
||||||
|
|
||||||
public abstract boolean canLogIn();
|
|
||||||
|
|
||||||
public abstract void logIn()
|
|
||||||
throws AuthenticationException;
|
|
||||||
|
|
||||||
public abstract void logOut();
|
|
||||||
|
|
||||||
public abstract boolean isLoggedIn();
|
|
||||||
|
|
||||||
public abstract boolean canPlayOnline();
|
|
||||||
|
|
||||||
public abstract GameProfile[] getAvailableProfiles();
|
|
||||||
|
|
||||||
public abstract GameProfile getSelectedProfile();
|
|
||||||
|
|
||||||
public abstract void selectGameProfile(GameProfile paramGameProfile)
|
|
||||||
throws AuthenticationException;
|
|
||||||
|
|
||||||
public abstract void loadFromStorage(Map<String, Object> paramMap);
|
|
||||||
|
|
||||||
public abstract Map<String, Object> saveForStorage();
|
|
||||||
|
|
||||||
public abstract void setUsername(String paramString);
|
|
||||||
|
|
||||||
public abstract void setPassword(String paramString);
|
|
||||||
|
|
||||||
public abstract String getAuthenticatedToken();
|
|
||||||
|
|
||||||
public abstract String getUserID();
|
|
||||||
|
|
||||||
public abstract PropertyMap getUserProperties();
|
|
||||||
|
|
||||||
public abstract UserType getUserType();
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public enum UserType {
|
|
||||||
|
|
||||||
LEGACY("legacy"),
|
|
||||||
MOJANG("mojang");
|
|
||||||
|
|
||||||
private static final Map<String, UserType> BY_NAME;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private UserType(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserType byName(String name) {
|
|
||||||
return (UserType) BY_NAME.get(name.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
BY_NAME = new HashMap();
|
|
||||||
|
|
||||||
for (UserType type : values()) {
|
|
||||||
BY_NAME.put(type.name, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.exceptions;
|
|
||||||
|
|
||||||
public class AuthenticationException extends Exception {
|
|
||||||
|
|
||||||
public AuthenticationException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.exceptions;
|
|
||||||
|
|
||||||
public class AuthenticationUnavailableException extends AuthenticationException {
|
|
||||||
|
|
||||||
public AuthenticationUnavailableException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationUnavailableException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationUnavailableException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationUnavailableException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.exceptions;
|
|
||||||
|
|
||||||
public class InvalidCredentialsException extends AuthenticationException {
|
|
||||||
|
|
||||||
public InvalidCredentialsException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public InvalidCredentialsException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InvalidCredentialsException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InvalidCredentialsException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.exceptions;
|
|
||||||
|
|
||||||
public class UserMigratedException extends InvalidCredentialsException {
|
|
||||||
|
|
||||||
public UserMigratedException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserMigratedException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserMigratedException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserMigratedException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.properties;
|
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
import org.jackhuang.hellominecraft.utils.code.Base64;
|
|
||||||
|
|
||||||
public class Property {
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final String value;
|
|
||||||
private final String signature;
|
|
||||||
|
|
||||||
public Property(String value, String name) {
|
|
||||||
this(value, name, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Property(String name, String value, String signature) {
|
|
||||||
this.name = name;
|
|
||||||
this.value = value;
|
|
||||||
this.signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSignature() {
|
|
||||||
return this.signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSignature() {
|
|
||||||
return this.signature != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSignatureValid(PublicKey publicKey) {
|
|
||||||
try {
|
|
||||||
Signature signature = Signature.getInstance("SHA1withRSA");
|
|
||||||
signature.initVerify(publicKey);
|
|
||||||
signature.update(this.value.getBytes());
|
|
||||||
return signature.verify(Base64.decode(this.signature.toCharArray()));
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.properties;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonSerializationContext;
|
|
||||||
import com.google.gson.JsonSerializer;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class PropertyMap extends HashMap<String, Property> {
|
|
||||||
|
|
||||||
public PropertyMap() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Serializer implements JsonSerializer<PropertyMap>, JsonDeserializer<PropertyMap> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
PropertyMap result = new PropertyMap();
|
|
||||||
Iterator i$;
|
|
||||||
Map.Entry<String, JsonElement> entry;
|
|
||||||
if ((json instanceof JsonObject)) {
|
|
||||||
JsonObject object = (JsonObject) json;
|
|
||||||
|
|
||||||
for (i$ = object.entrySet().iterator(); i$.hasNext();) {
|
|
||||||
entry = (Map.Entry<String, JsonElement>) i$.next();
|
|
||||||
if ((entry.getValue() instanceof JsonArray)) {
|
|
||||||
for (JsonElement element : (JsonArray) entry.getValue()) {
|
|
||||||
result.put(entry.getKey(),
|
|
||||||
new Property((String) entry.getKey(), element.getAsString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((json instanceof JsonArray)) {
|
|
||||||
for (JsonElement element : (JsonArray) json) {
|
|
||||||
if ((element instanceof JsonObject)) {
|
|
||||||
JsonObject object = (JsonObject) element;
|
|
||||||
String name = object.getAsJsonPrimitive("name").getAsString();
|
|
||||||
String value = object.getAsJsonPrimitive("value").getAsString();
|
|
||||||
|
|
||||||
if (object.has("signature")) {
|
|
||||||
result.put(name, new Property(name, value, object.getAsJsonPrimitive("signature").getAsString()));
|
|
||||||
} else {
|
|
||||||
result.put(name, new Property(name, value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
JsonArray result = new JsonArray();
|
|
||||||
|
|
||||||
for (Property property : src.values()) {
|
|
||||||
JsonObject object = new JsonObject();
|
|
||||||
|
|
||||||
object.addProperty("name", property.getName());
|
|
||||||
object.addProperty("value", property.getValue());
|
|
||||||
|
|
||||||
if (property.hasSignature()) {
|
|
||||||
object.addProperty("signature", property.getSignature());
|
|
||||||
}
|
|
||||||
|
|
||||||
result.add(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonSerializationContext;
|
|
||||||
import com.google.gson.JsonSerializer;
|
|
||||||
import org.jackhuang.mojang.authlib.Agent;
|
|
||||||
import org.jackhuang.mojang.authlib.GameProfile;
|
|
||||||
import org.jackhuang.mojang.authlib.HttpAuthenticationService;
|
|
||||||
import org.jackhuang.mojang.authlib.UserAuthentication;
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.AuthenticationException;
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.AuthenticationUnavailableException;
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.InvalidCredentialsException;
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.UserMigratedException;
|
|
||||||
import org.jackhuang.mojang.authlib.properties.PropertyMap;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.response.Response;
|
|
||||||
import org.jackhuang.mojang.util.UUIDTypeAdapter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.UUID;
|
|
||||||
import org.jackhuang.hellominecraft.C;
|
|
||||||
import org.jackhuang.hellominecraft.utils.StrUtils;
|
|
||||||
|
|
||||||
public class YggdrasilAuthenticationService extends HttpAuthenticationService {
|
|
||||||
|
|
||||||
private final String clientToken;
|
|
||||||
private final Gson gson;
|
|
||||||
|
|
||||||
public YggdrasilAuthenticationService(Proxy proxy, String clientToken) {
|
|
||||||
super(proxy);
|
|
||||||
this.clientToken = clientToken;
|
|
||||||
GsonBuilder builder = new GsonBuilder();
|
|
||||||
builder.registerTypeAdapter(GameProfile.class, new GameProfileSerializer());
|
|
||||||
builder.registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer());
|
|
||||||
builder.registerTypeAdapter(UUID.class, new UUIDTypeAdapter());
|
|
||||||
this.gson = builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserAuthentication createUserAuthentication(Agent agent) {
|
|
||||||
return new YggdrasilUserAuthentication(this, agent);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected <T extends Response> T makeRequest(URL url, Object input, Class<T> classOfT) throws AuthenticationException {
|
|
||||||
try {
|
|
||||||
String jsonResult = input == null ? performGetRequest(url) : performPostRequest(url, this.gson.toJson(input), "application/json");
|
|
||||||
Response result = (Response) this.gson.fromJson(jsonResult, classOfT);
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StrUtils.isNotBlank(result.getError())) {
|
|
||||||
if ("UserMigratedException".equals(result.getCause())) {
|
|
||||||
throw new UserMigratedException(result.getErrorMessage());
|
|
||||||
}
|
|
||||||
if (result.getError().equals("ForbiddenOperationException")) {
|
|
||||||
throw new InvalidCredentialsException(result.getErrorMessage());
|
|
||||||
}
|
|
||||||
throw new AuthenticationException(result.getErrorMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (T) result;
|
|
||||||
} catch (IOException | IllegalStateException | JsonParseException e) {
|
|
||||||
throw new AuthenticationUnavailableException(C.i18n("login.failed.connect_authentication_server"), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClientToken() {
|
|
||||||
return this.clientToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class GameProfileSerializer implements JsonSerializer<GameProfile>, JsonDeserializer<GameProfile> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GameProfile deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
JsonObject object = (JsonObject) json;
|
|
||||||
UUID id = object.has("id") ? (UUID) context.deserialize(object.get("id"), UUID.class) : null;
|
|
||||||
String name = object.has("name") ? object.getAsJsonPrimitive("name").getAsString() : null;
|
|
||||||
return new GameProfile(id, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(GameProfile src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
JsonObject result = new JsonObject();
|
|
||||||
if (src.getId() != null) {
|
|
||||||
result.add("id", context.serialize(src.getId()));
|
|
||||||
}
|
|
||||||
if (src.getName() != null) {
|
|
||||||
result.addProperty("name", src.getName());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,248 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.jackhuang.hellominecraft.C;
|
|
||||||
import org.jackhuang.hellominecraft.logging.logger.Logger;
|
|
||||||
import org.jackhuang.hellominecraft.utils.ArrayUtils;
|
|
||||||
import org.jackhuang.hellominecraft.utils.NetUtils;
|
|
||||||
import org.jackhuang.hellominecraft.utils.StrUtils;
|
|
||||||
import org.jackhuang.mojang.authlib.Agent;
|
|
||||||
import org.jackhuang.mojang.authlib.GameProfile;
|
|
||||||
import org.jackhuang.mojang.authlib.HttpUserAuthentication;
|
|
||||||
import org.jackhuang.mojang.authlib.UserType;
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.AuthenticationException;
|
|
||||||
import org.jackhuang.mojang.authlib.exceptions.InvalidCredentialsException;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.request.AuthenticationRequest;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.request.RefreshRequest;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.response.AuthenticationResponse;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.response.RefreshResponse;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.response.User;
|
|
||||||
|
|
||||||
public class YggdrasilUserAuthentication extends HttpUserAuthentication {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = new Logger("YggdrasilUserAuthentication");
|
|
||||||
private static final String BASE_URL = "https://authserver.mojang.com/";
|
|
||||||
private static final URL ROUTE_AUTHENTICATE = NetUtils.constantURL(BASE_URL + "authenticate");
|
|
||||||
private static final URL ROUTE_REFRESH = NetUtils.constantURL(BASE_URL + "refresh");
|
|
||||||
private static final URL ROUTE_VALIDATE = NetUtils.constantURL(BASE_URL + "validate");
|
|
||||||
private static final URL ROUTE_INVALIDATE = NetUtils.constantURL(BASE_URL + "invalidate");
|
|
||||||
private static final URL ROUTE_SIGNOUT = NetUtils.constantURL(BASE_URL + "signout");
|
|
||||||
private static final String STORAGE_KEY_ACCESS_TOKEN = "accessToken";
|
|
||||||
private final Agent agent;
|
|
||||||
private GameProfile[] profiles;
|
|
||||||
private String accessToken;
|
|
||||||
private boolean isOnline;
|
|
||||||
|
|
||||||
public YggdrasilUserAuthentication(YggdrasilAuthenticationService authenticationService, Agent agent) {
|
|
||||||
super(authenticationService);
|
|
||||||
this.agent = agent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canLogIn() {
|
|
||||||
return (!canPlayOnline()) && (StrUtils.isNotBlank(getUsername())) && ((StrUtils.isNotBlank(getPassword())) || (StrUtils.isNotBlank(getAuthenticatedToken())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logIn() throws AuthenticationException {
|
|
||||||
if (StrUtils.isBlank(getUsername())) {
|
|
||||||
throw new InvalidCredentialsException(C.i18n("login.invalid_username"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StrUtils.isNotBlank(getAuthenticatedToken())) {
|
|
||||||
logInWithToken();
|
|
||||||
} else if (StrUtils.isNotBlank(getPassword())) {
|
|
||||||
logInWithPassword();
|
|
||||||
} else {
|
|
||||||
throw new InvalidCredentialsException(C.i18n("login.invalid_password"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void logInWithPassword() throws AuthenticationException {
|
|
||||||
if (StrUtils.isBlank(getUsername())) {
|
|
||||||
throw new InvalidCredentialsException(C.i18n("login.invalid_username"));
|
|
||||||
}
|
|
||||||
if (StrUtils.isBlank(getPassword())) {
|
|
||||||
throw new InvalidCredentialsException(C.i18n("login.invalid_password"));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.info("Logging in with username & password");
|
|
||||||
|
|
||||||
AuthenticationRequest request = new AuthenticationRequest(this, getUsername(), getPassword());
|
|
||||||
AuthenticationResponse response = (AuthenticationResponse) getAuthenticationService().makeRequest(ROUTE_AUTHENTICATE, request, AuthenticationResponse.class);
|
|
||||||
|
|
||||||
if (!response.getClientToken().equals(getAuthenticationService().getClientToken())) {
|
|
||||||
throw new AuthenticationException(C.i18n("login.changed_client_token"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.getSelectedProfile() != null) {
|
|
||||||
setUserType(response.getSelectedProfile().isLegacy() ? UserType.LEGACY : UserType.MOJANG);
|
|
||||||
} else if (ArrayUtils.isNotEmpty(response.getAvailableProfiles())) {
|
|
||||||
setUserType(response.getAvailableProfiles()[0].isLegacy() ? UserType.LEGACY : UserType.MOJANG);
|
|
||||||
}
|
|
||||||
|
|
||||||
User user = response.getUser();
|
|
||||||
|
|
||||||
if ((user != null) && (user.getId() != null)) {
|
|
||||||
setUserid(user.getId());
|
|
||||||
} else {
|
|
||||||
setUserid(getUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isOnline = true;
|
|
||||||
this.accessToken = response.getAccessToken();
|
|
||||||
|
|
||||||
this.profiles = response.getAvailableProfiles();
|
|
||||||
setSelectedProfile(response.getSelectedProfile());
|
|
||||||
getModifiableUserProperties().clear();
|
|
||||||
|
|
||||||
updateUserProperties(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateUserProperties(User user) {
|
|
||||||
if (user == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.getProperties() != null) {
|
|
||||||
getModifiableUserProperties().putAll(user.getProperties());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void logInWithToken() throws AuthenticationException {
|
|
||||||
if (StrUtils.isBlank(getUserID())) {
|
|
||||||
if (StrUtils.isBlank(getUsername())) {
|
|
||||||
setUserid(getUsername());
|
|
||||||
} else {
|
|
||||||
throw new InvalidCredentialsException(C.i18n("login.invalid_uuid_and_username"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StrUtils.isBlank(getAuthenticatedToken())) {
|
|
||||||
throw new InvalidCredentialsException(C.i18n("login.invalid_access_token"));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.info("Logging in with access token");
|
|
||||||
|
|
||||||
RefreshRequest request = new RefreshRequest(this);
|
|
||||||
RefreshResponse response = (RefreshResponse) getAuthenticationService().makeRequest(ROUTE_REFRESH, request, RefreshResponse.class);
|
|
||||||
|
|
||||||
if (!response.getClientToken().equals(getAuthenticationService().getClientToken())) {
|
|
||||||
throw new AuthenticationException(C.i18n("login.changed_client_token"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.getSelectedProfile() != null) {
|
|
||||||
setUserType(response.getSelectedProfile().isLegacy() ? UserType.LEGACY : UserType.MOJANG);
|
|
||||||
} else if (ArrayUtils.isNotEmpty(response.getAvailableProfiles())) {
|
|
||||||
setUserType(response.getAvailableProfiles()[0].isLegacy() ? UserType.LEGACY : UserType.MOJANG);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((response.getUser() != null) && (response.getUser().getId() != null)) {
|
|
||||||
setUserid(response.getUser().getId());
|
|
||||||
} else {
|
|
||||||
setUserid(getUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isOnline = true;
|
|
||||||
this.accessToken = response.getAccessToken();
|
|
||||||
this.profiles = response.getAvailableProfiles();
|
|
||||||
setSelectedProfile(response.getSelectedProfile());
|
|
||||||
getModifiableUserProperties().clear();
|
|
||||||
|
|
||||||
updateUserProperties(response.getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logOut() {
|
|
||||||
super.logOut();
|
|
||||||
|
|
||||||
this.accessToken = null;
|
|
||||||
this.profiles = null;
|
|
||||||
this.isOnline = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GameProfile[] getAvailableProfiles() {
|
|
||||||
return this.profiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLoggedIn() {
|
|
||||||
return StrUtils.isNotBlank(this.accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canPlayOnline() {
|
|
||||||
return (isLoggedIn()) && (getSelectedProfile() != null) && (this.isOnline);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void selectGameProfile(GameProfile profile) throws AuthenticationException {
|
|
||||||
if (!isLoggedIn()) {
|
|
||||||
throw new AuthenticationException(C.i18n("login.profile.not_logged_in"));
|
|
||||||
}
|
|
||||||
if (getSelectedProfile() != null) {
|
|
||||||
throw new AuthenticationException(C.i18n("login.profile.selected"));
|
|
||||||
}
|
|
||||||
if ((profile == null) || (!ArrayUtils.contains(this.profiles, profile))) {
|
|
||||||
throw new IllegalArgumentException("Invalid profile '" + profile + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
RefreshRequest request = new RefreshRequest(this, profile);
|
|
||||||
RefreshResponse response = (RefreshResponse) getAuthenticationService().makeRequest(ROUTE_REFRESH, request, RefreshResponse.class);
|
|
||||||
|
|
||||||
if (!response.getClientToken().equals(getAuthenticationService().getClientToken())) {
|
|
||||||
throw new AuthenticationException(C.i18n("login.changed_client_token"));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isOnline = true;
|
|
||||||
this.accessToken = response.getAccessToken();
|
|
||||||
setSelectedProfile(response.getSelectedProfile());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadFromStorage(Map<String, Object> credentials) {
|
|
||||||
super.loadFromStorage(credentials);
|
|
||||||
|
|
||||||
this.accessToken = (String)credentials.get(STORAGE_KEY_ACCESS_TOKEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> saveForStorage() {
|
|
||||||
Map result = super.saveForStorage();
|
|
||||||
|
|
||||||
if (StrUtils.isNotBlank(getAuthenticatedToken())) {
|
|
||||||
result.put("accessToken", getAuthenticatedToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public String getSessionToken() {
|
|
||||||
if ((isLoggedIn()) && (getSelectedProfile() != null) && (canPlayOnline())) {
|
|
||||||
return String.format("token:%s:%s", new Object[]{getAuthenticatedToken(), getSelectedProfile().getId()});
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthenticatedToken() {
|
|
||||||
return this.accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Agent getAgent() {
|
|
||||||
return this.agent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "YggdrasilAuthenticationService{agent=" + this.agent + ", profiles=" + Arrays.toString(this.profiles) + ", selectedProfile=" + getSelectedProfile() + ", username='" + getUsername() + '\'' + ", isLoggedIn=" + isLoggedIn() + ", userType=" + getUserType() + ", canPlayOnline=" + canPlayOnline() + ", accessToken='" + this.accessToken + '\'' + ", clientToken='" + getAuthenticationService().getClientToken() + '\'' + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public YggdrasilAuthenticationService getAuthenticationService() {
|
|
||||||
return (YggdrasilAuthenticationService) super.getAuthenticationService();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil.request;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.Agent;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
|
|
||||||
|
|
||||||
public class AuthenticationRequest {
|
|
||||||
|
|
||||||
public Agent agent;
|
|
||||||
public String username;
|
|
||||||
public String password;
|
|
||||||
public String clientToken;
|
|
||||||
public boolean requestUser = true;
|
|
||||||
|
|
||||||
public AuthenticationRequest(YggdrasilUserAuthentication authenticationService, String username, String password) {
|
|
||||||
this.agent = authenticationService.getAgent();
|
|
||||||
this.username = username;
|
|
||||||
this.clientToken = authenticationService.getAuthenticationService().getClientToken();
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil.request;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.GameProfile;
|
|
||||||
import org.jackhuang.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
|
|
||||||
|
|
||||||
public class RefreshRequest {
|
|
||||||
|
|
||||||
public String clientToken;
|
|
||||||
public String accessToken;
|
|
||||||
public GameProfile selectedProfile;
|
|
||||||
public boolean requestUser = true;
|
|
||||||
|
|
||||||
public RefreshRequest(YggdrasilUserAuthentication authenticationService) {
|
|
||||||
this(authenticationService, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefreshRequest(YggdrasilUserAuthentication authenticationService, GameProfile profile) {
|
|
||||||
this.clientToken = authenticationService.getAuthenticationService().getClientToken();
|
|
||||||
this.accessToken = authenticationService.getAuthenticatedToken();
|
|
||||||
this.selectedProfile = profile;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil.response;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.GameProfile;
|
|
||||||
|
|
||||||
public class AuthenticationResponse extends Response {
|
|
||||||
|
|
||||||
private String accessToken;
|
|
||||||
private String clientToken;
|
|
||||||
private GameProfile selectedProfile;
|
|
||||||
private GameProfile[] availableProfiles;
|
|
||||||
private User user;
|
|
||||||
|
|
||||||
public String getAccessToken() {
|
|
||||||
return this.accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClientToken() {
|
|
||||||
return this.clientToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameProfile[] getAvailableProfiles() {
|
|
||||||
return this.availableProfiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameProfile getSelectedProfile() {
|
|
||||||
return this.selectedProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUser() {
|
|
||||||
return this.user;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil.response;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.GameProfile;
|
|
||||||
|
|
||||||
public class RefreshResponse extends Response {
|
|
||||||
|
|
||||||
private String accessToken;
|
|
||||||
private String clientToken;
|
|
||||||
private GameProfile selectedProfile;
|
|
||||||
private GameProfile[] availableProfiles;
|
|
||||||
private User user;
|
|
||||||
|
|
||||||
public String getAccessToken() {
|
|
||||||
return this.accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClientToken() {
|
|
||||||
return this.clientToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameProfile[] getAvailableProfiles() {
|
|
||||||
return this.availableProfiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameProfile getSelectedProfile() {
|
|
||||||
return this.selectedProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUser() {
|
|
||||||
return this.user;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil.response;
|
|
||||||
|
|
||||||
public class Response {
|
|
||||||
|
|
||||||
private String error;
|
|
||||||
private String errorMessage;
|
|
||||||
private String cause;
|
|
||||||
|
|
||||||
public String getError() {
|
|
||||||
return this.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCause() {
|
|
||||||
return this.cause;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getErrorMessage() {
|
|
||||||
return this.errorMessage;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package org.jackhuang.mojang.authlib.yggdrasil.response;
|
|
||||||
|
|
||||||
import org.jackhuang.mojang.authlib.properties.PropertyMap;
|
|
||||||
|
|
||||||
public class User {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private PropertyMap properties;
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PropertyMap getProperties() {
|
|
||||||
return this.properties;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.jackhuang.mojang.util;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import com.google.gson.JsonSerializationContext;
|
|
||||||
import com.google.gson.JsonSerializer;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import org.jackhuang.mojang.authlib.properties.PropertyMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author huangyuhui
|
|
||||||
*/
|
|
||||||
public class LegacyPropertyMapSerializer
|
|
||||||
implements JsonSerializer<PropertyMap> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(PropertyMap src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
JsonObject result = new JsonObject();
|
|
||||||
|
|
||||||
for (String key : src.keySet()) {
|
|
||||||
JsonArray values = new JsonArray();
|
|
||||||
|
|
||||||
values.add(new JsonPrimitive(src.get(key).getValue()));
|
|
||||||
|
|
||||||
result.add(key, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package org.jackhuang.mojang.util;
|
|
||||||
|
|
||||||
import com.google.gson.TypeAdapter;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
|
||||||
|
|
||||||
public void write(JsonWriter out, UUID value)
|
|
||||||
throws IOException {
|
|
||||||
out.value(fromUUID(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID read(JsonReader in) throws IOException {
|
|
||||||
return fromString(in.nextString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromUUID(UUID value) {
|
|
||||||
return value.toString().replace("-", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UUID fromString(String input) {
|
|
||||||
return UUID.fromString(input.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -243,7 +243,7 @@ launcher.versions_json_not_matched=\u7248\u672c%s\u683c\u5f0f\u4e0d\u89c4\u8303\
|
|||||||
launcher.versions_json_not_matched_cannot_auto_completion=\u7248\u672c%s\u7f3a\u5931\u5fc5\u8981\u7684\u7248\u672c\u4fe1\u606f\u6587\u4ef6\uff0c\u662f\u5426\u5220\u9664\u8be5\u7248\u672c\uff1f
|
launcher.versions_json_not_matched_cannot_auto_completion=\u7248\u672c%s\u7f3a\u5931\u5fc5\u8981\u7684\u7248\u672c\u4fe1\u606f\u6587\u4ef6\uff0c\u662f\u5426\u5220\u9664\u8be5\u7248\u672c\uff1f
|
||||||
launcher.versions_json_not_formatted=\u7248\u672c%s\u4fe1\u606f\u6587\u4ef6\u683c\u5f0f\u9519\u8bef\uff0c\u662f\u5426\u91cd\u65b0\u4e0b\u8f7d\uff1f
|
launcher.versions_json_not_formatted=\u7248\u672c%s\u4fe1\u606f\u6587\u4ef6\u683c\u5f0f\u9519\u8bef\uff0c\u662f\u5426\u91cd\u65b0\u4e0b\u8f7d\uff1f
|
||||||
launcher.choose_bgpath=\u9009\u62e9\u80cc\u666f\u8def\u5f84
|
launcher.choose_bgpath=\u9009\u62e9\u80cc\u666f\u8def\u5f84
|
||||||
launcher.background_tooltip=<html>\n<body>\n\u542f\u52a8\u5668\u9ed8\u8ba4\u4f7f\u7528\u81ea\u5e26\u7684\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709background.png\uff0c\u5219\u4f1a\u4f7f\u7528\u8be5\u6587\u4ef6\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709bgskin\u5b50\u76ee\u5f55\uff0c\u5219\u4f1a\u968f\u673a\u4f7f\u7528\u91cc\u9762\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u8be5\u80cc\u666f\u5730\u5740\u88ab\u4fee\u6539\uff0c\u5219\u4f1a\u4f7f\u7528\u80cc\u666f\u5730\u5740\u91cc\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u80cc\u666f\u5730\u5740\u5141\u8bb8\u6709\u591a\u4e2a\u5730\u5740\uff0c\u4f7f\u7528\u534a\u89d2\u5206\u53f7";"(\u4e0d\u5305\u542b\u53cc\u5f15\u53f7)\u5206\u9694\n</body>\n</html>
|
launcher.background_tooltip=<html>\n<body>\n\u542f\u52a8\u5668\u9ed8\u8ba4\u4f7f\u7528\u81ea\u5e26\u7684\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709background.png\uff0c\u5219\u4f1a\u4f7f\u7528\u8be5\u6587\u4ef6\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709bg\u5b50\u76ee\u5f55\uff0c\u5219\u4f1a\u968f\u673a\u4f7f\u7528\u91cc\u9762\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u8be5\u80cc\u666f\u5730\u5740\u88ab\u4fee\u6539\uff0c\u5219\u4f1a\u4f7f\u7528\u80cc\u666f\u5730\u5740\u91cc\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u80cc\u666f\u5730\u5740\u5141\u8bb8\u6709\u591a\u4e2a\u5730\u5740\uff0c\u4f7f\u7528\u534a\u89d2\u5206\u53f7";"(\u4e0d\u5305\u542b\u53cc\u5f15\u53f7)\u5206\u9694\n</body>\n</html>
|
||||||
launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
||||||
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548,\u53ef\u52a0\u5feb\u6e32\u67d3\u901f\u5ea6)
|
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548,\u53ef\u52a0\u5feb\u6e32\u67d3\u901f\u5ea6)
|
||||||
launcher.theme=\u4e3b\u9898
|
launcher.theme=\u4e3b\u9898
|
||||||
|
@ -241,7 +241,7 @@ launcher.exit_failed=Failed to shutdown.
|
|||||||
launcher.versions_json_not_matched=The version %s is malformed! There are a json:%s in this version. Do you want to fix this problem?
|
launcher.versions_json_not_matched=The version %s is malformed! There are a json:%s in this version. Do you want to fix this problem?
|
||||||
launcher.versions_json_not_matched_cannot_auto_completion=The version %s lost version information file, delete it?
|
launcher.versions_json_not_matched_cannot_auto_completion=The version %s lost version information file, delete it?
|
||||||
launcher.choose_bgpath=Choose background path.
|
launcher.choose_bgpath=Choose background path.
|
||||||
launcher.background_tooltip=<html>\n<body>\nThis app uses the default background at first.<br />\nIf there is background.png in the directory, it will be used.<br />\nIf there is "bgskin" subdirectory, this app will chooses one picture in "bgskin" randomly.<br />\nIf you set the background setting, this app will use it.\n</body>\n</html>
|
launcher.background_tooltip=<html>\n<body>\nThis app uses the default background at first.<br />\nIf there is background.png in the directory, it will be used.<br />\nIf there is "bg" subdirectory, this app will chooses one picture in "bgskin" randomly.<br />\nIf you set the background setting, this app will use it.\n</body>\n</html>
|
||||||
launcher.update_launcher=Check for update
|
launcher.update_launcher=Check for update
|
||||||
launcher.enable_shadow=Enable Window Shadow
|
launcher.enable_shadow=Enable Window Shadow
|
||||||
launcher.theme=Theme
|
launcher.theme=Theme
|
||||||
|
@ -243,7 +243,7 @@ launcher.versions_json_not_matched=\u7248\u672c%s\u683c\u5f0f\u4e0d\u89c4\u8303\
|
|||||||
launcher.versions_json_not_matched_cannot_auto_completion=\u7248\u672c%s\u7f3a\u5931\u5fc5\u8981\u7684\u7248\u672c\u4fe1\u606f\u6587\u4ef6\uff0c\u662f\u5426\u5220\u9664\u8be5\u7248\u672c\uff1f
|
launcher.versions_json_not_matched_cannot_auto_completion=\u7248\u672c%s\u7f3a\u5931\u5fc5\u8981\u7684\u7248\u672c\u4fe1\u606f\u6587\u4ef6\uff0c\u662f\u5426\u5220\u9664\u8be5\u7248\u672c\uff1f
|
||||||
launcher.versions_json_not_formatted=\u7248\u672c%s\u4fe1\u606f\u6587\u4ef6\u683c\u5f0f\u9519\u8bef\uff0c\u662f\u5426\u91cd\u65b0\u4e0b\u8f7d\uff1f
|
launcher.versions_json_not_formatted=\u7248\u672c%s\u4fe1\u606f\u6587\u4ef6\u683c\u5f0f\u9519\u8bef\uff0c\u662f\u5426\u91cd\u65b0\u4e0b\u8f7d\uff1f
|
||||||
launcher.choose_bgpath=\u9009\u62e9\u80cc\u666f\u8def\u5f84
|
launcher.choose_bgpath=\u9009\u62e9\u80cc\u666f\u8def\u5f84
|
||||||
launcher.background_tooltip=<html>\n<body>\n\u542f\u52a8\u5668\u9ed8\u8ba4\u4f7f\u7528\u81ea\u5e26\u7684\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709background.png\uff0c\u5219\u4f1a\u4f7f\u7528\u8be5\u6587\u4ef6\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709bgskin\u5b50\u76ee\u5f55\uff0c\u5219\u4f1a\u968f\u673a\u4f7f\u7528\u91cc\u9762\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u8be5\u80cc\u666f\u5730\u5740\u88ab\u4fee\u6539\uff0c\u5219\u4f1a\u4f7f\u7528\u80cc\u666f\u5730\u5740\u91cc\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u80cc\u666f\u5730\u5740\u5141\u8bb8\u6709\u591a\u4e2a\u5730\u5740\uff0c\u4f7f\u7528\u534a\u89d2\u5206\u53f7";"(\u4e0d\u5305\u542b\u53cc\u5f15\u53f7)\u5206\u9694\n</body>\n</html>
|
launcher.background_tooltip=<html>\n<body>\n\u542f\u52a8\u5668\u9ed8\u8ba4\u4f7f\u7528\u81ea\u5e26\u7684\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709background.png\uff0c\u5219\u4f1a\u4f7f\u7528\u8be5\u6587\u4ef6\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u5f53\u524d\u76ee\u5f55\u6709bg\u5b50\u76ee\u5f55\uff0c\u5219\u4f1a\u968f\u673a\u4f7f\u7528\u91cc\u9762\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u5982\u679c\u8be5\u80cc\u666f\u5730\u5740\u88ab\u4fee\u6539\uff0c\u5219\u4f1a\u4f7f\u7528\u80cc\u666f\u5730\u5740\u91cc\u7684\u4e00\u5f20\u56fe\u4f5c\u4e3a\u80cc\u666f<br />\n\u80cc\u666f\u5730\u5740\u5141\u8bb8\u6709\u591a\u4e2a\u5730\u5740\uff0c\u4f7f\u7528\u534a\u89d2\u5206\u53f7";"(\u4e0d\u5305\u542b\u53cc\u5f15\u53f7)\u5206\u9694\n</body>\n</html>
|
||||||
launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
||||||
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548,\u53ef\u52a0\u5feb\u6e32\u67d3\u901f\u5ea6)
|
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548,\u53ef\u52a0\u5feb\u6e32\u67d3\u901f\u5ea6)
|
||||||
launcher.theme=\u4e3b\u9898
|
launcher.theme=\u4e3b\u9898
|
||||||
|
@ -243,7 +243,7 @@ launcher.versions_json_not_matched=\u7248\u672c%s\u683c\u5f0f\u4e0d\u898f\u7bc4\
|
|||||||
launcher.versions_json_not_matched_cannot_auto_completion=\u7248\u672c%s\u7f3a\u5931\u5fc5\u8981\u7684\u7248\u672c\u4fe1\u606f\u6587\u4ef6\uff0c\u662f\u5426\u5220\u9664\u8be5\u7248\u672c\uff1f
|
launcher.versions_json_not_matched_cannot_auto_completion=\u7248\u672c%s\u7f3a\u5931\u5fc5\u8981\u7684\u7248\u672c\u4fe1\u606f\u6587\u4ef6\uff0c\u662f\u5426\u5220\u9664\u8be5\u7248\u672c\uff1f
|
||||||
launcher.versions_json_not_formatted=\u7248\u672c%s\u4fe1\u606f\u6587\u4ef6\u683c\u5f0f\u9519\u8bef\uff0c\u662f\u5426\u91cd\u65b0\u4e0b\u8f7d\uff1f
|
launcher.versions_json_not_formatted=\u7248\u672c%s\u4fe1\u606f\u6587\u4ef6\u683c\u5f0f\u9519\u8bef\uff0c\u662f\u5426\u91cd\u65b0\u4e0b\u8f7d\uff1f
|
||||||
launcher.choose_bgpath=\u9078\u64c7\u80cc\u666f\u8def\u5f91
|
launcher.choose_bgpath=\u9078\u64c7\u80cc\u666f\u8def\u5f91
|
||||||
launcher.background_tooltip=<html>\n<body>\n\u555f\u52d5\u5668\u9ed8\u8a8d\u4f7f\u7528\u81ea\u5e36\u7684\u80cc\u666f<br />\n\u5982\u679c\u7576\u524d\u76ee\u9304\u6709background.png\uff0c\u5247\u6703\u4f7f\u7528\u8a72\u6587\u4ef6\u4f5c\u70ba\u80cc\u666f<br />\n\u5982\u679c\u7576\u524d\u76ee\u9304\u6709bgskin\u5b50\u76ee\u9304\uff0c\u5247\u6703\u96a8\u6a5f\u4f7f\u7528\u88e1\u9762\u7684\u4e00\u5f35\u5716\u4f5c\u70ba\u80cc\u666f<br />\n\u5982\u679c\u8a72\u80cc\u666f\u5730\u5740\u88ab\u4fee\u6539\uff0c\u5247\u6703\u4f7f\u7528\u80cc\u666f\u5730\u5740\u88e1\u7684\u4e00\u5f35\u5716\u4f5c\u70ba\u80cc\u666f<br />\n\u80cc\u666f\u5730\u5740\u5141\u8a31\u6709\u591a\u500b\u5730\u5740\uff0c\u4f7f\u7528\u534a\u89d2\u5206\u865f";"(\u4e0d\u5305\u542b\u96d9\u5f15\u865f)\u5206\u9694\n</body>\n</html>
|
launcher.background_tooltip=<html>\n<body>\n\u555f\u52d5\u5668\u9ed8\u8a8d\u4f7f\u7528\u81ea\u5e36\u7684\u80cc\u666f<br />\n\u5982\u679c\u7576\u524d\u76ee\u9304\u6709background.png\uff0c\u5247\u6703\u4f7f\u7528\u8a72\u6587\u4ef6\u4f5c\u70ba\u80cc\u666f<br />\n\u5982\u679c\u7576\u524d\u76ee\u9304\u6709bg\u5b50\u76ee\u9304\uff0c\u5247\u6703\u96a8\u6a5f\u4f7f\u7528\u88e1\u9762\u7684\u4e00\u5f35\u5716\u4f5c\u70ba\u80cc\u666f<br />\n\u5982\u679c\u8a72\u80cc\u666f\u5730\u5740\u88ab\u4fee\u6539\uff0c\u5247\u6703\u4f7f\u7528\u80cc\u666f\u5730\u5740\u88e1\u7684\u4e00\u5f35\u5716\u4f5c\u70ba\u80cc\u666f<br />\n\u80cc\u666f\u5730\u5740\u5141\u8a31\u6709\u591a\u500b\u5730\u5740\uff0c\u4f7f\u7528\u534a\u89d2\u5206\u865f";"(\u4e0d\u5305\u542b\u96d9\u5f15\u865f)\u5206\u9694\n</body>\n</html>
|
||||||
launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
launcher.update_launcher=\u68c0\u67e5\u66f4\u65b0
|
||||||
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548)
|
launcher.enable_shadow=\u542f\u7528\u7a97\u53e3\u9634\u5f71(\u91cd\u542f\u542f\u52a8\u5668\u751f\u6548)
|
||||||
launcher.theme=\u4e3b\u9898
|
launcher.theme=\u4e3b\u9898
|
||||||
|
Loading…
x
Reference in New Issue
Block a user