Skip to content

Commit

Permalink
Fixed json deduplication
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphiMC committed Nov 13, 2023
1 parent 4211d88 commit 617b21a
Show file tree
Hide file tree
Showing 24 changed files with 117 additions and 82 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ try (CloseableHttpClient httpClient = MicrosoftConstants.createHttpClient()) {
```
### Save the token chain to a json object
```java
JsonObject serializedSession = javaSession.toJson();
JsonObject serializedSession = MinecraftAuth.JAVA_DEVICE_CODE_LOGIN.toJson(javaSession);
```
### Load the token chain from a json object
When loading the token chain it is important to use the same login flow as when the token chain was created.
```java
StepFullJavaSession.FullJavaSession loadedSession = MinecraftAuth.JAVA_DEVICE_CODE_LOGIN.fromJson(serializedSession);
```
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/net/raphimc/minecraftauth/MinecraftAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ private MinecraftBuilder(final XblXstsTokenBuilder parent) {
}

public SameInputOptionalMergeStep<StepMCProfile.MCProfile, StepPlayerCertificates.PlayerCertificates, StepMCToken.MCToken, StepFullJavaSession.FullJavaSession> buildMinecraftJavaProfileStep() {
final StepMCToken mctokenStep = new StepMCToken(this.xblXstsTokenStep);
return new StepFullJavaSession(new StepMCProfile(mctokenStep), new StepPlayerCertificates(mctokenStep));
final StepMCToken mcTokenStep = new StepMCToken(this.xblXstsTokenStep);
return new StepFullJavaSession(new StepMCProfile(mcTokenStep), new StepPlayerCertificates(mcTokenStep));
}

public SameInputOptionalMergeStep<StepMCChain.MCChain, StepPlayFabToken.PlayFabToken, StepXblXstsToken.XblXsts<?>, StepFullBedrockSession.FullBedrockSession> buildMinecraftBedrockChainStep() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

public abstract class AbstractStep<I extends AbstractStep.StepResult<?>, O extends AbstractStep.StepResult<?>> {

public final String name;
protected final AbstractStep<?, I> prevStep;

public AbstractStep(final AbstractStep<?, I> prevStep) {
public AbstractStep(final String name, final AbstractStep<?, I> prevStep) {
this.name = name;
this.prevStep = prevStep;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public abstract class OptionalMergeStep<I1 extends AbstractStep.StepResult<?>, I

protected final AbstractStep<?, I2> prevStep2;

public OptionalMergeStep(final AbstractStep<?, I1> prevStep1, final AbstractStep<?, I2> prevStep2) {
super(prevStep1);
public OptionalMergeStep(final String name, final AbstractStep<?, I1> prevStep1, final AbstractStep<?, I2> prevStep2) {
super(name, prevStep1);

this.prevStep2 = prevStep2;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,41 +27,38 @@

public abstract class SameInputOptionalMergeStep<I1 extends AbstractStep.StepResult<?>, I2 extends AbstractStep.StepResult<?>, I extends AbstractStep.StepResult<?>, O extends OptionalMergeStep.StepResult<?, ?>> extends OptionalMergeStep<I1, I2, O> {

private final List<AbstractStep<?, ?>> stepsUntilSameInput = new ArrayList<>();
private final int step1SameInputOffset;
private final List<AbstractStep<?, ?>> steps1UntilSameInput = new ArrayList<>();
private final List<AbstractStep<?, ?>> steps2UntilSameInput = new ArrayList<>();

public SameInputOptionalMergeStep(final AbstractStep<I, I1> prevStep1, final AbstractStep<I, I2> prevStep2) {
super(prevStep1, prevStep2);
public SameInputOptionalMergeStep(final String name, final AbstractStep<I, I1> prevStep1, final AbstractStep<I, I2> prevStep2) {
super(name, prevStep1, prevStep2);

STEP2_CHECK:
if (this.prevStep2 != null) {
if (!((ParameterizedType) this.prevStep.getClass().getGenericSuperclass()).getActualTypeArguments()[0].equals(((ParameterizedType) this.prevStep2.getClass().getGenericSuperclass()).getActualTypeArguments()[0])) {
throw new IllegalStateException("Steps do not take the same input");
}

this.stepsUntilSameInput.add(this.prevStep2);
this.steps2UntilSameInput.add(this.prevStep2);
AbstractStep<?, ?> step2 = this.prevStep2;
while ((step2 = step2.prevStep) != null) {
this.stepsUntilSameInput.add(step2);
this.steps2UntilSameInput.add(step2);
this.steps1UntilSameInput.clear();
this.steps1UntilSameInput.add(this.prevStep);

AbstractStep<?, ?> step1 = this.prevStep;
int steps1Offset = 0;
while ((step1 = step1.prevStep) != null) {
steps1Offset++;
this.steps1UntilSameInput.add(step1);
if (step2 == step1) {
Collections.reverse(this.stepsUntilSameInput);
this.stepsUntilSameInput.remove(0);
this.step1SameInputOffset = steps1Offset;
Collections.reverse(this.steps2UntilSameInput);
Collections.reverse(this.steps1UntilSameInput);
break STEP2_CHECK;
}
}
}

throw new IllegalStateException("Cannot find a common step");
} else {
this.step1SameInputOffset = 0;
}

System.out.println(this.step1SameInputOffset + " " + this.stepsUntilSameInput.size() + " " + getClass().getSimpleName());
}

@Override
Expand All @@ -75,13 +72,14 @@ public O refresh(final HttpClient httpClient, final O result) throws Exception {
public O getFromInput(final HttpClient httpClient, final Object input) throws Exception {
final I1 prevResult1 = this.prevStep.getFromInput(httpClient, input);

if (!this.stepsUntilSameInput.isEmpty()) {
if (!this.steps2UntilSameInput.isEmpty()) {
AbstractStep.StepResult<?> result2 = prevResult1;
for (int i = 0; i < this.step1SameInputOffset; i++) {
for (int i = 0; i < this.steps1UntilSameInput.size() - 1; i++) {
result2 = result2.prevResult();
}

for (AbstractStep step : this.stepsUntilSameInput) {
for (int i = 1; i < this.steps2UntilSameInput.size(); i++) {
final AbstractStep step = this.steps2UntilSameInput.get(i);
result2 = step.applyStep(httpClient, result2);
}

Expand All @@ -92,13 +90,49 @@ public O getFromInput(final HttpClient httpClient, final Object input) throws Ex
}

@Override
public O fromJson(final JsonObject json) {
return this.fromDeduplicatedJson(json);
public final JsonObject toJson(final O result) {
final JsonObject json = this.toRawJson(result);

if (!this.steps2UntilSameInput.isEmpty()) {
JsonObject resultJson = json;
for (int i = this.steps2UntilSameInput.size() - 1; i >= 1; i--) {
final AbstractStep<?, ?> step = this.steps2UntilSameInput.get(i);
if (i == 1) {
resultJson.remove(step.name);
break;
}

resultJson = resultJson.getAsJsonObject(step.name);
}
}

return json;
}

@Override
public JsonObject toJson(final O result) {
return this.toRawJson(result);
public final O fromJson(final JsonObject json) {
if (!this.steps2UntilSameInput.isEmpty()) {
String targetName = null;
JsonObject step2Json = json;
for (int i = this.steps2UntilSameInput.size() - 1; i >= 1; i--) {
final AbstractStep<?, ?> step = this.steps2UntilSameInput.get(i);
if (i == 1) {
targetName = step.name;
break;
}

step2Json = step2Json.getAsJsonObject(step.name);
}

JsonObject step1Json = json;
for (int i = this.steps1UntilSameInput.size() - 1; i >= 0; i--) {
final AbstractStep<?, ?> step = this.steps1UntilSameInput.get(i);
step1Json = step1Json.getAsJsonObject(step.name);
}
step2Json.add(targetName, step1Json);
}

return this.fromDeduplicatedJson(json);
}

protected abstract O fromDeduplicatedJson(final JsonObject json);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class StepMCChain extends AbstractStep<StepXblXstsToken.XblXsts<?>, StepM
private static final int CLOCK_SKEW = 60;

public StepMCChain(final AbstractStep<?, StepXblXstsToken.XblXsts<?>> prevStep) {
super(prevStep);
super("mcChain", prevStep);
}

@Override
Expand Down Expand Up @@ -113,7 +113,7 @@ public MCChain refresh(final HttpClient httpClient, final MCChain result) throws

@Override
public MCChain fromJson(final JsonObject json) {
final StepXblXstsToken.XblXsts<?> xblXsts = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("xblXsts")) : null;
final StepXblXstsToken.XblXsts<?> xblXsts = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
return new MCChain(
CryptUtil.publicKeyFromBase64(json.get("publicKey").getAsString()),
CryptUtil.privateKeyFromBase64(json.get("privateKey").getAsString()),
Expand All @@ -136,7 +136,7 @@ public JsonObject toJson(final MCChain result) {
json.addProperty("xuid", result.xuid);
json.addProperty("id", result.id.toString());
json.addProperty("displayName", result.displayName);
if (this.prevStep != null) json.add("xblXsts", this.prevStep.toJson(result.xblXsts));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.xblXsts));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class StepPlayFabToken extends AbstractStep<StepXblXstsToken.XblXsts<?>,
public static final String PLAY_FAB_URL = "https://" + MicrosoftConstants.BEDROCK_PLAY_FAB_TITLE_ID.toLowerCase() + ".playfabapi.com/Client/LoginWithXbox";

public StepPlayFabToken(final AbstractStep<?, StepXblXstsToken.XblXsts<?>> prevStep) {
super(prevStep);
super("playFabToken", prevStep);
}

@Override
Expand Down Expand Up @@ -98,7 +98,7 @@ public PlayFabToken refresh(final HttpClient httpClient, final PlayFabToken resu

@Override
public PlayFabToken fromJson(final JsonObject json) {
final StepXblXstsToken.XblXsts<?> xblXsts = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("xblXsts")) : null;
final StepXblXstsToken.XblXsts<?> xblXsts = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
return new PlayFabToken(
json.get("expireTimeMs").getAsLong(),
json.get("entityToken").getAsString(),
Expand All @@ -117,7 +117,7 @@ public JsonObject toJson(final PlayFabToken result) {
json.addProperty("entityId", result.entityId);
json.addProperty("sessionTicket", result.sessionTicket);
json.addProperty("playFabId", result.playFabId);
if (this.prevStep != null) json.add("xblXsts", this.prevStep.toJson(result.xblXsts));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.xblXsts));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public class StepFullBedrockSession extends SameInputOptionalMergeStep<StepMCChain.MCChain, StepPlayFabToken.PlayFabToken, StepXblXstsToken.XblXsts<?>, StepFullBedrockSession.FullBedrockSession> {

public StepFullBedrockSession(final AbstractStep<StepXblXstsToken.XblXsts<?>, StepMCChain.MCChain> prevStep1, final AbstractStep<StepXblXstsToken.XblXsts<?>, StepPlayFabToken.PlayFabToken> prevStep2) {
super(prevStep1, prevStep2);
super("fullBedrockSession", prevStep1, prevStep2);
}

@Override
Expand All @@ -41,16 +41,16 @@ public FullBedrockSession applyStep(final HttpClient httpClient, final StepMCCha

@Override
protected FullBedrockSession fromDeduplicatedJson(final JsonObject json) {
final StepMCChain.MCChain mcChain = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("mcChain")) : null;
final StepPlayFabToken.PlayFabToken playFabToken = this.prevStep2 != null ? this.prevStep2.fromJson(json.getAsJsonObject("playFabToken")) : null;
final StepMCChain.MCChain mcChain = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
final StepPlayFabToken.PlayFabToken playFabToken = this.prevStep2 != null ? this.prevStep2.fromJson(json.getAsJsonObject(this.prevStep2.name)) : null;
return new FullBedrockSession(mcChain, playFabToken);
}

@Override
protected JsonObject toRawJson(final FullBedrockSession result) {
final JsonObject json = new JsonObject();
if (this.prevStep != null) json.add("mcChain", this.prevStep.toJson(result.mcChain));
if (this.prevStep2 != null) json.add("playFabToken", this.prevStep2.toJson(result.playFabToken));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.mcChain));
if (this.prevStep2 != null) json.add(this.prevStep2.name, this.prevStep2.toJson(result.playFabToken));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class StepMCProfile extends AbstractStep<StepMCToken.MCToken, StepMCProfi
public static final String MINECRAFT_PROFILE_URL = "https://api.minecraftservices.com/minecraft/profile";

public StepMCProfile(final AbstractStep<?, StepMCToken.MCToken> prevStep) {
super(prevStep);
super("mcProfile", prevStep);
}

@Override
Expand Down Expand Up @@ -63,7 +63,7 @@ public MCProfile applyStep(final HttpClient httpClient, final StepMCToken.MCToke

@Override
public MCProfile fromJson(final JsonObject json) {
final StepMCToken.MCToken mcToken = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("mcToken")) : null;
final StepMCToken.MCToken mcToken = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
return new MCProfile(
UUID.fromString(json.get("id").getAsString()),
json.get("name").getAsString(),
Expand All @@ -78,7 +78,7 @@ public JsonObject toJson(final MCProfile result) {
json.addProperty("id", result.id.toString());
json.addProperty("name", result.name);
json.addProperty("skinUrl", result.skinUrl);
if (this.prevStep != null) json.add("mcToken", this.prevStep.toJson(result.mcToken));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.mcToken));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class StepMCToken extends AbstractStep<StepXblXstsToken.XblXsts<?>, StepM
public static final String MINECRAFT_LOGIN_URL = "https://api.minecraftservices.com/authentication/login_with_xbox";

public StepMCToken(final AbstractStep<?, StepXblXstsToken.XblXsts<?>> prevStep) {
super(prevStep);
super("mcToken", prevStep);
}

@Override
Expand Down Expand Up @@ -72,7 +72,7 @@ public MCToken refresh(final HttpClient httpClient, final MCToken result) throws

@Override
public MCToken fromJson(final JsonObject json) {
final StepXblXstsToken.XblXsts<?> xblXsts = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("xblXsts")) : null;
final StepXblXstsToken.XblXsts<?> xblXsts = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
return new MCToken(
json.get("accessToken").getAsString(),
json.get("tokenType").getAsString(),
Expand All @@ -87,7 +87,7 @@ public JsonObject toJson(final MCToken result) {
json.addProperty("accessToken", result.accessToken);
json.addProperty("tokenType", result.tokenType);
json.addProperty("expireTimeMs", result.expireTimeMs);
if (this.prevStep != null) json.add("xblXsts", this.prevStep.toJson(result.xblXsts));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.xblXsts));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class StepPlayerCertificates extends AbstractStep<StepMCToken.MCToken, St
public static final String PLAYER_CERTIFICATES_URL = "https://api.minecraftservices.com/player/certificates";

public StepPlayerCertificates(final AbstractStep<?, StepMCToken.MCToken> prevStep) {
super(prevStep);
super("playerCertificates", prevStep);
}

@Override
Expand Down Expand Up @@ -90,7 +90,7 @@ public PlayerCertificates refresh(final HttpClient httpClient, final PlayerCerti

@Override
public PlayerCertificates fromJson(final JsonObject json) {
final StepMCToken.MCToken mcToken = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("mcToken")) : null;
final StepMCToken.MCToken mcToken = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
return new PlayerCertificates(
json.get("expireTimeMs").getAsLong(),
CryptUtil.publicKeyFromBase64(json.get("publicKey").getAsString()),
Expand All @@ -109,7 +109,7 @@ public JsonObject toJson(final PlayerCertificates result) {
json.addProperty("privateKey", Base64.getEncoder().encodeToString(result.privateKey.getEncoded()));
json.addProperty("publicKeySignature", Base64.getEncoder().encodeToString(result.publicKeySignature));
json.addProperty("legacyPublicKeySignature", Base64.getEncoder().encodeToString(result.legacyPublicKeySignature));
if (this.prevStep != null) json.add("mcToken", this.prevStep.toJson(result.mcToken));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.mcToken));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public class StepFullJavaSession extends SameInputOptionalMergeStep<StepMCProfile.MCProfile, StepPlayerCertificates.PlayerCertificates, StepMCToken.MCToken, StepFullJavaSession.FullJavaSession> {

public StepFullJavaSession(final AbstractStep<StepMCToken.MCToken, StepMCProfile.MCProfile> prevStep1, final AbstractStep<StepMCToken.MCToken, StepPlayerCertificates.PlayerCertificates> prevStep2) {
super(prevStep1, prevStep2);
super("fullJavaSession", prevStep1, prevStep2);
}

@Override
Expand All @@ -41,16 +41,16 @@ public FullJavaSession applyStep(final HttpClient httpClient, final StepMCProfil

@Override
protected FullJavaSession fromDeduplicatedJson(final JsonObject json) {
final StepMCProfile.MCProfile mcProfile = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject("mcProfile")) : null;
final StepPlayerCertificates.PlayerCertificates playerCertificates = this.prevStep2 != null ? this.prevStep2.fromJson(json.getAsJsonObject("playerCertificates")) : null;
final StepMCProfile.MCProfile mcProfile = this.prevStep != null ? this.prevStep.fromJson(json.getAsJsonObject(this.prevStep.name)) : null;
final StepPlayerCertificates.PlayerCertificates playerCertificates = this.prevStep2 != null ? this.prevStep2.fromJson(json.getAsJsonObject(this.prevStep2.name)) : null;
return new FullJavaSession(mcProfile, playerCertificates);
}

@Override
protected JsonObject toRawJson(final FullJavaSession result) {
final JsonObject json = new JsonObject();
if (this.prevStep != null) json.add("mcProfile", this.prevStep.toJson(result.mcProfile));
if (this.prevStep2 != null) json.add("playerCertificates", this.prevStep2.toJson(result.playerCertificates));
if (this.prevStep != null) json.add(this.prevStep.name, this.prevStep.toJson(result.mcProfile));
if (this.prevStep2 != null) json.add(this.prevStep2.name, this.prevStep2.toJson(result.playerCertificates));
return json;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public abstract class MsaCodeStep<I extends AbstractStep.StepResult<?>> extends
protected final String clientSecret;

public MsaCodeStep(final AbstractStep<?, I> prevStep, final String clientId, final String scope, final String clientSecret) {
super(prevStep);
super("msaCode", prevStep);

this.clientId = clientId;
this.scope = scope;
Expand Down
Loading

0 comments on commit 617b21a

Please sign in to comment.