From dca7ced92fe049fdbf94aa0f73e162f585736fd5 Mon Sep 17 00:00:00 2001 From: artdeell Date: Sun, 3 Apr 2022 11:22:34 +0300 Subject: [PATCH] Return the Mojang login (testing required) --- .../kdt/pojavlaunch/PojavLoginActivity.java | 57 ++++++++++++-- .../net/kdt/pojavlaunch/PojavProfile.java | 6 ++ .../main/java/net/kdt/pojavlaunch/Tools.java | 2 +- .../mojang/AuthenticateRequest.java | 24 ++++++ .../authenticator/mojang/LoginListener.java | 7 ++ .../authenticator/mojang/LoginTask.java | 71 +++++++++++++++++ .../mojang/RefreshTokenTask.java | 78 +++++++++++++++++++ .../yggdrasil/AuthenticateResponse.java | 10 +++ .../mojang/yggdrasil/RefreshResponse.java | 9 +++ .../yggdrasil/YggdrasilAuthenticator.java | 25 ++++++ .../main/res/layout/activity_pojav_login.xml | 35 ++++++++- .../src/main/res/values/strings.xml | 3 +- 12 files changed, 313 insertions(+), 14 deletions(-) create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/AuthenticateRequest.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginListener.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginTask.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/RefreshTokenTask.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/AuthenticateResponse.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/RefreshResponse.java diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java index 6b015f889..45954e54b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java @@ -44,6 +44,8 @@ import androidx.core.content.ContextCompat; import net.kdt.pojavlaunch.authenticator.microsoft.MicrosoftAuthTask; import net.kdt.pojavlaunch.authenticator.microsoft.ui.MicrosoftLoginGUIActivity; import net.kdt.pojavlaunch.authenticator.mojang.InvalidateTokenTask; +import net.kdt.pojavlaunch.authenticator.mojang.LoginListener; +import net.kdt.pojavlaunch.authenticator.mojang.LoginTask; import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener; import net.kdt.pojavlaunch.customcontrols.CustomControls; import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog; @@ -70,9 +72,9 @@ public class PojavLoginActivity extends BaseActivity { private final Object mLockStoragePerm = new Object(); private final Object mLockSelectJRE = new Object(); - private EditText edit2; + private EditText edit2, edit3; private final int REQUEST_STORAGE_REQUEST_CODE = 1; - private CheckBox sRemember; + private CheckBox sRemember, sLocal; private TextView startupTextView; private SharedPreferences firstLaunchPrefs; private MinecraftAccount mProfile = null; @@ -237,9 +239,14 @@ public class PojavLoginActivity extends BaseActivity { public void onNothingSelected(AdapterView adapter) {} }); - edit2 = (EditText) findViewById(R.id.login_edit_email); - + edit2 = findViewById(R.id.login_edit_email); + edit3 = findViewById(R.id.login_edit_password); sRemember = findViewById(R.id.login_switch_remember); + sLocal = findViewById(R.id.login_switch_local); + sLocal.setOnCheckedChangeListener((p1, p2) -> { + // May delete later + edit3.setEnabled(!p2); + }); isSkipInit = true; } @@ -551,7 +558,7 @@ public class PojavLoginActivity extends BaseActivity { }; MinecraftAccount acc = MinecraftAccount.load(selectedAccName); - if (acc.accessToken.length() >= 5){ + if (acc.isMicrosoft){ new MicrosoftAuthTask(PojavLoginActivity.this, authListener) .execute("true", acc.msaRefreshToken); } else { @@ -613,12 +620,46 @@ public class PojavLoginActivity extends BaseActivity { } return null; } - + public void loginMC(final View v) { - mProfile = loginLocal(); - playProfile(false); + if (sLocal.isChecked()) { + mProfile = loginLocal(); + playProfile(false); + } else { + ProgressBar prb = findViewById(R.id.launcherAccProgress); + new LoginTask().setLoginListener(new LoginListener(){ + + + @Override + public void onBeforeLogin() { + v.setEnabled(false); + prb.setVisibility(View.VISIBLE); + } + + @Override + public void onLoginDone(String[] result) { + if(result[0].equals("ERROR")){ + Tools.dialogOnUiThread(PojavLoginActivity.this, + getResources().getString(R.string.global_error), strArrToString(result)); + } else{ + MinecraftAccount builder = new MinecraftAccount(); + builder.accessToken = result[1]; + builder.clientToken = result[2]; + builder.profileId = result[3]; + builder.username = result[4]; + builder.updateSkinFace(); + mProfile = builder; + } + runOnUiThread(() -> { + v.setEnabled(true); + prb.setVisibility(View.GONE); + playProfile(false); + }); + } + }).execute(edit2.getText().toString(), edit3.getText().toString()); + } } private void playProfile(boolean notOnLogin) { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavProfile.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavProfile.java index 53252682b..54c1b06b0 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavProfile.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavProfile.java @@ -8,6 +8,9 @@ import android.util.Log; import com.google.gson.JsonSyntaxException; import java.io.File; import java.io.IOException; + +import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener; +import net.kdt.pojavlaunch.authenticator.mojang.RefreshTokenTask; import net.kdt.pojavlaunch.value.MinecraftAccount; public class PojavProfile { @@ -101,4 +104,7 @@ public class PojavProfile { Intent intent = new Intent(ctx, PojavLauncherActivity.class); //MCLauncherActivity.class); ctx.startActivity(intent); } + public static void updateTokens(final Activity ctx, final String name, RefreshListener listen) throws Exception { + new RefreshTokenTask(ctx, listen).execute(name); + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 54f5fee01..c4bea8ce8 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -202,7 +202,7 @@ public final class Tools { versionName = versionInfo.inheritsFrom; } - String userType = "msa"; + String userType = "mojang"; File gameDir = new File(strGameDir); gameDir.mkdirs(); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/AuthenticateRequest.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/AuthenticateRequest.java new file mode 100644 index 000000000..2d72a9eca --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/AuthenticateRequest.java @@ -0,0 +1,24 @@ + +package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil; + +import java.util.UUID; + +public class AuthenticateRequest { + public AgentInfo agent = new AgentInfo(); + public UUID clientToken; + public String password; + public String username; + + public static class AgentInfo { + public String name; + public int version; + } + + public AuthenticateRequest(String username, String password, UUID clientToken, String clientName, int clientVersion) { + this.username = username; + this.password = password; + this.clientToken = clientToken; + this.agent.name = clientName; + this.agent.version = clientVersion; + } +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginListener.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginListener.java new file mode 100644 index 000000000..540c3dc7a --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginListener.java @@ -0,0 +1,7 @@ +package net.kdt.pojavlaunch.authenticator.mojang; + +public interface LoginListener +{ + public void onBeforeLogin(); + public void onLoginDone(String[] result); +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginTask.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginTask.java new file mode 100644 index 000000000..d75901275 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/LoginTask.java @@ -0,0 +1,71 @@ +package net.kdt.pojavlaunch.authenticator.mojang; + +import android.os.*; +import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*; +import java.io.*; +import java.util.*; +import net.kdt.pojavlaunch.*; + +public class LoginTask extends AsyncTask +{ + private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator(); + //private String TAG = "MojangAuth-login"; + private LoginListener listener; + + public LoginTask setLoginListener(LoginListener listener) { + this.listener = listener; + return this; + } + + private UUID getRandomUUID() { + return UUID.randomUUID(); + } + + @Override + protected void onPreExecute() { + listener.onBeforeLogin(); + + super.onPreExecute(); + } + + @Override + protected Void doInBackground(String[] args) { + ArrayList str = new ArrayList(); + str.add("ERROR"); + try{ + try{ + AuthenticateResponse response = authenticator.authenticate(args[0], args[1], getRandomUUID()); + if (response.selectedProfile == null) { + str.add("Can't login a demo account!\n"); + } else { + if (new File(Tools.DIR_ACCOUNT_NEW + "/" + response.selectedProfile.name + ".json").exists()) { + str.add("This account already exist!\n"); + } else { + str.add(response.accessToken); // Access token + str.add(response.clientToken.toString()); // Client token + str.add(response.selectedProfile.id); // Profile ID + str.add(response.selectedProfile.name); // Username + str.set(0, "NORMAL"); + } + } + } + //MainActivity.updateStatus(804); + catch(Throwable e){ + str.add(e.getMessage()); + } + } + catch(Exception e){ + str.add(e.getMessage()); + } + + listener.onLoginDone(str.toArray(new String[0])); + + return null; + } + + @Override + protected void onPostExecute(Void result) { + // listener.onLoginDone(result); + super.onPostExecute(result); + } +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/RefreshTokenTask.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/RefreshTokenTask.java new file mode 100644 index 000000000..6ecab4cd8 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/RefreshTokenTask.java @@ -0,0 +1,78 @@ +package net.kdt.pojavlaunch.authenticator.mojang; + +import android.content.*; +import android.os.*; +import com.google.gson.*; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.*; +import net.kdt.pojavlaunch.*; +import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*; +import android.app.*; +import net.kdt.pojavlaunch.value.*; + +public class RefreshTokenTask extends AsyncTask { + private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator(); + //private Gson gson = new Gson(); + private RefreshListener listener; + private MinecraftAccount profilePath; + + private final WeakReference ctx; + private ProgressDialog build; + + public RefreshTokenTask(Context ctx, RefreshListener listener) { + this.ctx = new WeakReference<>(ctx); + this.listener = listener; + } + + @Override + public void onPreExecute() { + build = new ProgressDialog(ctx.get()); + build.setMessage(ctx.get().getString(R.string.global_waiting)); + build.setProgressStyle(ProgressDialog.STYLE_SPINNER); + build.setCancelable(false); + build.show(); + } + + @Override + public Throwable doInBackground(String... args) { + try { + this.profilePath = MinecraftAccount.load(args[0]); + int responseCode = 400; + try { + responseCode = this.authenticator.validate(profilePath.accessToken).statusCode; + }catch(RuntimeException e) {} + + if (responseCode == 403) { + RefreshResponse response = this.authenticator.refresh(profilePath.accessToken, UUID.fromString(profilePath.clientToken)); + if (response == null) { + // Refresh when offline? + return null; + } else if (response.selectedProfile == null) { + throw new IllegalArgumentException("Can't refresh a demo account!"); + } + + profilePath.clientToken = response.clientToken.toString(); + profilePath.accessToken = response.accessToken; + profilePath.username = response.selectedProfile.name; + profilePath.profileId = response.selectedProfile.id; + } + profilePath.updateSkinFace(); + profilePath.save(); + return null; + } catch (Throwable e) { + return e; + } + } + + @Override + public void onPostExecute(Throwable result) { + build.dismiss(); + if (result == null) { + listener.onSuccess(profilePath); + } else { + listener.onFailed(result); + } + } +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/AuthenticateResponse.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/AuthenticateResponse.java new file mode 100644 index 000000000..1e166964d --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/AuthenticateResponse.java @@ -0,0 +1,10 @@ +package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil; + +import java.util.UUID; + +public class AuthenticateResponse { + public String accessToken; + public Profile[] availableProfiles; + public UUID clientToken; + public Profile selectedProfile; +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/RefreshResponse.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/RefreshResponse.java new file mode 100644 index 000000000..9c87f7fea --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/RefreshResponse.java @@ -0,0 +1,9 @@ +package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil; + +import java.util.UUID; + +public class RefreshResponse { + public String accessToken; + public UUID clientToken; + public Profile selectedProfile; +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/YggdrasilAuthenticator.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/YggdrasilAuthenticator.java index 8cf004610..7fb7ba5cd 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/YggdrasilAuthenticator.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/authenticator/mojang/yggdrasil/YggdrasilAuthenticator.java @@ -89,6 +89,31 @@ public class YggdrasilAuthenticator { throw th; } } + public AuthenticateResponse authenticate(String username, String password, UUID clientId) throws IOException, Throwable { + NetworkResponse obj = makeRequest("authenticate", new net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.AuthenticateRequest(username, password, clientId, this.clientName, this.clientVersion), AuthenticateResponse.class); + /* + if (obj.statusCode != 200) { + throw new RuntimeException("Invalid username or password, status code: " + obj.statusCode); + } + */ + obj.throwExceptionIfNeed(); + return (AuthenticateResponse) obj.response; + } + + public RefreshResponse refresh(String authToken, UUID clientId) throws IOException, Throwable { + NetworkResponse obj = makeRequest("refresh", new RefreshRequest(authToken, clientId), RefreshResponse.class); + if (obj == null) { + return null; + } else { + obj.throwExceptionIfNeed(); // "Invalid username or password, status code: " + obj.statusCode); + return (RefreshResponse) obj.response; + } + } + + public NetworkResponse validate(String authToken) throws Throwable { + return makeRequest("validate", new RefreshRequest(authToken, null), null); + } + public NetworkResponse invalidate(String authToken, UUID clientId) throws Throwable { return makeRequest("invalidate", new RefreshRequest(authToken, clientId), null); diff --git a/app_pojavlauncher/src/main/res/layout/activity_pojav_login.xml b/app_pojavlauncher/src/main/res/layout/activity_pojav_login.xml index e1ae586c3..6af453b06 100644 --- a/app_pojavlauncher/src/main/res/layout/activity_pojav_login.xml +++ b/app_pojavlauncher/src/main/res/layout/activity_pojav_login.xml @@ -16,12 +16,12 @@ + android:src="@drawable/ic_setting_sign_in_background" /> + app:layout_constraintStart_toStartOf="@+id/login_edit_password" + app:layout_constraintTop_toBottomOf="@+id/login_switch_local" /> + + + + + + diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 374eb2ab9..0be407441 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -10,7 +10,8 @@ - Local username + Email or username + Password Keep me logged in Login