mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-17 08:35:37 -04:00
[MSA] Authentication implemented
TODO: - Use Json format to save account - [MSA] Refresh implementation
This commit is contained in:
parent
6a2aaaab70
commit
6c250d32c2
@ -1,7 +1,9 @@
|
|||||||
package com.kdt.mojangauth;
|
package com.kdt.mojangauth;
|
||||||
|
|
||||||
|
import net.kdt.pojavlaunch.*;
|
||||||
|
|
||||||
public interface RefreshListener
|
public interface RefreshListener
|
||||||
{
|
{
|
||||||
public void onFailed(Throwable e);
|
public void onFailed(Throwable e);
|
||||||
public void onSuccess();
|
public void onSuccess(MCProfile.Builder profile);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class RefreshTokenTask extends AsyncTask<String, Void, Throwable> {
|
|||||||
public void onPostExecute(Throwable result) {
|
public void onPostExecute(Throwable result) {
|
||||||
build.dismiss();
|
build.dismiss();
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
listener.onSuccess();
|
listener.onSuccess(null);
|
||||||
} else {
|
} else {
|
||||||
listener.onFailed(result);
|
listener.onFailed(result);
|
||||||
}
|
}
|
||||||
|
@ -327,8 +327,9 @@ public class PojavLoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess(MCProfile.Builder b) {
|
||||||
// TODO: Implement this method
|
mProfile = b;
|
||||||
|
playProfile();
|
||||||
}
|
}
|
||||||
}).execute(code);
|
}).execute(code);
|
||||||
// Toast.makeText(this, "Logged in to Microsoft account, but NYI", Toast.LENGTH_LONG).show();
|
// Toast.makeText(this, "Logged in to Microsoft account, but NYI", Toast.LENGTH_LONG).show();
|
||||||
@ -733,7 +734,7 @@ public class PojavLoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess()
|
public void onSuccess(MCProfile.Builder unused)
|
||||||
{
|
{
|
||||||
MCProfile.launch(PojavLoginActivity.this, path);
|
MCProfile.launch(PojavLoginActivity.this, path);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,11 @@ public class HttpResponse<T>
|
|||||||
public T body() throws IOException {
|
public T body() throws IOException {
|
||||||
Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||||
if (type.isAssignableFrom(String.class)) {
|
if (type.isAssignableFrom(String.class)) {
|
||||||
return (T) Tools.read(mRequest.mBuilder.getBase().getInputStream());
|
if (statusCode() >= 200 && statusCode() < 300) {
|
||||||
|
return (T) Tools.read(mRequest.mBuilder.getBase().getInputStream());
|
||||||
|
} else {
|
||||||
|
return (T) Tools.read(mRequest.mBuilder.getBase().getErrorStream());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,15 @@ import org.json.*;
|
|||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import net.kdt.pojavlaunch.value.launcherprofiles.*;
|
||||||
|
import net.kdt.pojavlaunch.value.*;
|
||||||
|
|
||||||
public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
public class MicrosoftAuthenticator extends AsyncTask<String, Void, Object> {
|
||||||
private static final String authTokenUrl = "https://login.live.com/oauth20_token.srf";
|
private static final String authTokenUrl = "https://login.live.com/oauth20_token.srf";
|
||||||
private static final String xblAuthUrl = "https://user.auth.xboxlive.com/user/authenticate";
|
private static final String xblAuthUrl = "https://user.auth.xboxlive.com/user/authenticate";
|
||||||
private static final String xstsAuthUrl = "https://xsts.auth.xboxlive.com/xsts/authorize";
|
private static final String xstsAuthUrl = "https://xsts.auth.xboxlive.com/xsts/authorize";
|
||||||
private static final String mcLoginUrl = "https://api.minecraftservices.com/authentication/login_with_xbox";
|
private static final String mcLoginUrl = "https://api.minecraftservices.com/authentication/login_with_xbox";
|
||||||
private static final String mcStoreUrl = "https://api.minecraftservices.com/entitlements/mcstore";
|
// private static final String mcStoreUrl = "https://api.minecraftservices.com/entitlements/mcstore";
|
||||||
private static final String mcProfileUrl = "https://api.minecraftservices.com/minecraft/profile";
|
private static final String mcProfileUrl = "https://api.minecraftservices.com/minecraft/profile";
|
||||||
|
|
||||||
//private Gson gson = new Gson();
|
//private Gson gson = new Gson();
|
||||||
@ -45,9 +47,8 @@ public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Throwable doInBackground(String... args) {
|
public Object doInBackground(String... args) {
|
||||||
try {
|
try {
|
||||||
MCProfile.Builder profilePath = MCProfile.load(args[0]);
|
|
||||||
String authCode = args[1];
|
String authCode = args[1];
|
||||||
|
|
||||||
publishProgress();
|
publishProgress();
|
||||||
@ -57,16 +58,24 @@ public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
|||||||
String xblToken = acquireXBLToken(msaAccessToken);
|
String xblToken = acquireXBLToken(msaAccessToken);
|
||||||
|
|
||||||
publishProgress();
|
publishProgress();
|
||||||
// TODO
|
String[] xstsData = acquireXsts(xblToken);
|
||||||
|
|
||||||
/*
|
publishProgress();
|
||||||
profilePath.setClientID(response.clientToken.toString());
|
String mcAccessToken = acquireMinecraftToken(xstsData[0], xstsData[1]);
|
||||||
profilePath.setAccessToken(response.accessToken);
|
|
||||||
profilePath.setUsername(response.selectedProfile.name);
|
publishProgress();
|
||||||
profilePath.setProfileID(response.selectedProfile.id);
|
// TODO migrate account format to json
|
||||||
|
MinecraftAccount acc = checkMcProfile(mcAccessToken);
|
||||||
|
|
||||||
|
MCProfile.Builder profilePath = MCProfile.load(args[0]);
|
||||||
|
|
||||||
|
profilePath.setClientID("0" /* FIXME */);
|
||||||
|
profilePath.setAccessToken(acc.accessToken);
|
||||||
|
profilePath.setUsername(acc.username);
|
||||||
|
profilePath.setProfileID(acc.profileId);
|
||||||
MCProfile.build(profilePath);
|
MCProfile.build(profilePath);
|
||||||
*/
|
|
||||||
return null;
|
return profilePath;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -76,16 +85,15 @@ public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
|||||||
protected void onProgressUpdate(Void[] p1) {
|
protected void onProgressUpdate(Void[] p1) {
|
||||||
super.onProgressUpdate(p1);
|
super.onProgressUpdate(p1);
|
||||||
build.setProgress(build.getProgress() + 1);
|
build.setProgress(build.getProgress() + 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostExecute(Throwable result) {
|
public void onPostExecute(Object result) {
|
||||||
build.dismiss();
|
build.dismiss();
|
||||||
if (result == null) {
|
if (result instanceof MCProfile.Builder) {
|
||||||
listener.onSuccess();
|
listener.onSuccess((MCProfile.Builder) result);
|
||||||
} else {
|
} else {
|
||||||
listener.onFailed(result);
|
listener.onFailed((Throwable) result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,12 +123,27 @@ public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
private final class XSTSXUI {
|
||||||
|
private String uhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class XSTSDisplayClaims {
|
||||||
|
private XSTSXUI[] xui;
|
||||||
|
}
|
||||||
|
|
||||||
private final class GlobalToken {
|
private final class GlobalToken {
|
||||||
// MSA AccessToken
|
// MSA AccessToken
|
||||||
private String access_token;
|
private String access_token;
|
||||||
|
|
||||||
// XBL Token
|
// XBL, XSTS Token
|
||||||
private String Token;
|
private String Token;
|
||||||
|
|
||||||
|
// XSTS
|
||||||
|
private XSTSDisplayClaims DisplayClaims;
|
||||||
|
|
||||||
|
// Minecraft side
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String acquireAccessToken(String authcode) throws IOException, URISyntaxException{
|
private String acquireAccessToken(String authcode) throws IOException, URISyntaxException{
|
||||||
@ -137,8 +160,12 @@ public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
|||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.POST(ofFormData(data)).build();
|
.POST(ofFormData(data)).build();
|
||||||
|
|
||||||
HttpResponse response = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
HttpResponse resp = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
||||||
return Tools.GLOBAL_GSON.fromJson((String) response.body(), GlobalToken.class).access_token;
|
if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
|
||||||
|
return Tools.GLOBAL_GSON.fromJson((String) resp.body(), GlobalToken.class).access_token;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error " + resp.statusCode() + ": " + (String) resp.body());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String acquireXBLToken(String accessToken) throws IOException, URISyntaxException {
|
private String acquireXBLToken(String accessToken) throws IOException, URISyntaxException {
|
||||||
@ -160,7 +187,89 @@ public class MicrosoftAuthenticator extends AsyncTask<String, Void, Throwable> {
|
|||||||
.POST(ofJSONData(data)).build();
|
.POST(ofJSONData(data)).build();
|
||||||
|
|
||||||
HttpResponse resp = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
HttpResponse resp = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
||||||
return Tools.GLOBAL_GSON.fromJson((String) resp.body(), GlobalToken.class).Token;
|
if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
|
||||||
|
return Tools.GLOBAL_GSON.fromJson((String) resp.body(), GlobalToken.class).Token;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error " + resp.statusCode() + ": " + (String) resp.body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] acquireXsts(String xblToken) throws IOException, URISyntaxException {
|
||||||
|
URI uri = new URI(xstsAuthUrl);
|
||||||
|
|
||||||
|
Map<Object, Object> dataProp = new ArrayMap<>();
|
||||||
|
dataProp.put("SandboxId", "RETAIL");
|
||||||
|
dataProp.put("UserTokens", Arrays.asList(xblToken));
|
||||||
|
|
||||||
|
Map<Object, Object> data = new ArrayMap<>();
|
||||||
|
data.put("Properties", dataProp);
|
||||||
|
data.put("RelyingParty", "rp://api.minecraftservices.com/");
|
||||||
|
data.put("TokenType", "JWT");
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder(uri)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.POST(ofJSONData(data)).build();
|
||||||
|
|
||||||
|
HttpResponse resp = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
|
||||||
|
String body = (String) resp.body();
|
||||||
|
GlobalToken token = Tools.GLOBAL_GSON.fromJson(body, GlobalToken.class);
|
||||||
|
String xblXsts = token.Token;
|
||||||
|
String uhs = token.DisplayClaims.xui[0].uhs;
|
||||||
|
|
||||||
|
return new String[]{uhs, xblXsts};
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error " + resp.statusCode() + ": " + (String) resp.body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String acquireMinecraftToken(String xblUhs, String xblXsts) throws IOException, URISyntaxException {
|
||||||
|
URI uri = new URI(mcLoginUrl);
|
||||||
|
|
||||||
|
Map<Object, Object> data = new ArrayMap<>();
|
||||||
|
data.put("identityToken", "XBL3.0 x=" + xblUhs + ";" + xblXsts);
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder(uri)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.POST(ofJSONData(data)).build();
|
||||||
|
|
||||||
|
HttpResponse resp = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
|
||||||
|
String body = (String) resp.body();
|
||||||
|
return Tools.GLOBAL_GSON.fromJson(body, GlobalToken.class).access_token;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error " + resp.statusCode() + ": " + (String) resp.body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MinecraftAccount checkMcProfile(String mcAccessToken) throws IOException, URISyntaxException {
|
||||||
|
URI uri = new URI(mcProfileUrl);
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder(uri)
|
||||||
|
.header("Authorization", "Bearer " + mcAccessToken)
|
||||||
|
.GET().build();
|
||||||
|
|
||||||
|
HttpResponse resp = HttpClient.newBuilder().build().sendRequest(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
|
||||||
|
String body = (String) resp.body();
|
||||||
|
GlobalToken token = Tools.GLOBAL_GSON.fromJson(body, GlobalToken.class);
|
||||||
|
String uuid = token.id;
|
||||||
|
String uuidDashes = uuid.replaceFirst(
|
||||||
|
"(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5"
|
||||||
|
);
|
||||||
|
|
||||||
|
MinecraftAccount acc = new MinecraftAccount();
|
||||||
|
acc.isMicrosoft = true;
|
||||||
|
acc.username = token.name;
|
||||||
|
acc.accessToken = mcAccessToken;
|
||||||
|
acc.profileId = uuidDashes;
|
||||||
|
return acc;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error " + resp.statusCode() + ": " + (String) resp.body());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HttpRequest.BodyPublisher ofJSONData(Map<Object, Object> data) {
|
public static HttpRequest.BodyPublisher ofJSONData(Map<Object, Object> data) {
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package net.kdt.pojavlaunch.value;
|
||||||
|
|
||||||
|
public class MinecraftAccount
|
||||||
|
{
|
||||||
|
public String accessToken; // access token
|
||||||
|
public String clientToken; // clientID: refresh and invalidate
|
||||||
|
public String profileId; // authenticate UUID
|
||||||
|
public String username;
|
||||||
|
public String selectedVersion = "1.7.10";
|
||||||
|
public boolean isMicrosoft;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user