JwksResponse class

Пакет: com.hypixel.hytale.server.core.auth

Файл: com/hypixel/hytale/server/core/auth/SessionServiceClient.java

Поля (2)

МодификаторыТипИмя
public static final BuilderCodec<SessionServiceClient.JwksResponse> CODEC
public SessionServiceClient.JwkKey[] keys

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.auth;

class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.codec.EmptyExtraInfo;
class="kw">import com.hypixel.hytale.codec.KeyedCodec;
class="kw">import com.hypixel.hytale.codec.builder.BuilderCodec;
class="kw">import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
class="kw">import com.hypixel.hytale.codec.util.RawJsonReader;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.server.core.util.ServiceHttpClientFactory;
class="kw">import com.hypixel.hytale.sneakythrow.SneakyThrow;
class="kw">import java.io.IOException;
class="kw">import java.net.URI;
class="kw">import java.net.http.HttpClient;
class="kw">import java.net.http.HttpRequest;
class="kw">import java.net.http.HttpResponse;
class="kw">import java.net.http.HttpRequest.BodyPublishers;
class="kw">import java.net.http.HttpResponse.BodyHandlers;
class="kw">import java.time.Instant;
class="kw">import java.util.UUID;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.ExecutorService;
class="kw">import java.util.concurrent.Executors;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class SessionServiceClient {
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   class="kw">private class="kw">static class="kw">final ExecutorService HTTP_EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();
   class="kw">private class="kw">final HttpClient httpClient;
   class="kw">private class="kw">final String sessionServiceUrl;

   class="kw">public SessionServiceClient(@Nonnull String var1) {
      if (var1 != null && !var1.isEmpty()) {
         this.sessionServiceUrl = var1.endsWith("/") ? var1.substring(0, var1.length() - 1) : var1;
         this.httpClient = ServiceHttpClientFactory.create(AuthConfig.HTTP_TIMEOUT);
         LOGGER.at(Level.INFO).log("Session Service client initialized for: %s", this.sessionServiceUrl);
      } else {
         throw new IllegalArgumentException("Session Service URL cannot be null or empty");
      }
   }

   class="kw">public CompletableFuture<String> requestAuthorizationGrantAsync(@Nonnull String var1, @Nonnull String var2, @Nonnull String var3) {
      class="kw">return CompletableFuture.supplyAsync(
         () -> {
            try {
               String var4 = String.format("{\"identityToken\":\"%s\",\"aud\":\"%s\"}", escapeJsonString(var1), escapeJsonString(var2));
               HttpRequest var5 = HttpRequest.newBuilder()
                  .uri(URI.create(this.sessionServiceUrl + "/server-join/auth-grant"))
                  .header("Content-Type", "application/json")
                  .header("Accept", "application/json")
                  .header("Authorization", "Bearer " + var3)
                  .header("User-Agent", AuthConfig.USER_AGENT)
                  .timeout(AuthConfig.HTTP_TIMEOUT)
                  .POST(BodyPublishers.ofString(var4))
                  .build();
               LOGGER.at(Level.INFO).log("Requesting authorization grant with identity token, aud='%s'", var2);
               HttpResponse var6 = this.httpClient.send(var5, BodyHandlers.ofString());
               if (var6.statusCode() != 200) {
                  LOGGER.at(Level.WARNING).log("Failed to request authorization grant: HTTP %d - %s", var6.statusCode(), var6.body());
                  class="kw">return null;
               } else {
                  SessionServiceClient.AuthGrantResponse var7 = SessionServiceClient.AuthGrantResponse.CODEC
                     .decodeJson(new RawJsonReader(var6.body().toCharArray()), EmptyExtraInfo.EMPTY);
                  if (var7 != null && var7.authorizationGrant != null) {
                     LOGGER.at(Level.INFO).log("Successfully obtained authorization grant");
                     class="kw">return var7.authorizationGrant;
                  } else {
                     LOGGER.at(Level.WARNING).log("Session Service response missing authorizationGrant field");
                     class="kw">return null;
                  }
               }
            } catch (IOException var8) {
               LOGGER.at(Level.WARNING).log("IO error while requesting authorization grant: %s", var8.getMessage());
               class="kw">return null;
            } catch (InterruptedException var9) {
               LOGGER.at(Level.WARNING).log("Request interrupted while obtaining authorization grant");
               Thread.currentThread().interrupt();
               class="kw">return null;
            } catch (Exception var10) {
               LOGGER.at(Level.WARNING).log("Unexpected error requesting authorization grant: %s", var10.getMessage());
               class="kw">return null;
            }
         },
         HTTP_EXECUTOR
      );
   }

   class="kw">public CompletableFuture<String> exchangeAuthGrantForTokenAsync(@Nonnull String var1, @Nonnull String var2, @Nonnull String var3) {
      class="kw">return CompletableFuture.supplyAsync(
         () -> {
            try {
               String var4 = String.format("{\"authorizationGrant\":\"%s\",\"x509Fingerprint\":\"%s\"}", escapeJsonString(var1), escapeJsonString(var2));
               HttpRequest var5 = HttpRequest.newBuilder()
                  .uri(URI.create(this.sessionServiceUrl + "/server-join/auth-token"))
                  .header("Content-Type", "application/json")
                  .header("Accept", "application/json")
                  .header("Authorization", "Bearer " + var3)
                  .header("User-Agent", AuthConfig.USER_AGENT)
                  .timeout(AuthConfig.HTTP_TIMEOUT)
                  .POST(BodyPublishers.ofString(var4))
                  .build();
               LOGGER.at(Level.INFO).log("Exchanging authorization grant for access token");
               LOGGER.at(Level.FINE).log("Using bearer token (first 20 chars): %s...", var3.length() > 20 ? var3.substring(0, 20) : var3);
               LOGGER.at(Level.FINE).log("Request body: %s", var4);
               HttpResponse var6 = this.httpClient.send(var5, BodyHandlers.ofString());
               if (var6.statusCode() != 200) {
                  LOGGER.at(Level.WARNING).log("Failed to exchange auth grant: HTTP %d - %s", var6.statusCode(), var6.body());
                  class="kw">return null;
               } else {
                  SessionServiceClient.AccessTokenResponse var7 = SessionServiceClient.AccessTokenResponse.CODEC
                     .decodeJson(new RawJsonReader(var6.body().toCharArray()), EmptyExtraInfo.EMPTY);
                  if (var7 != null && var7.accessToken != null) {
                     LOGGER.at(Level.INFO).log("Successfully obtained access token");
                     class="kw">return var7.accessToken;
                  } else {
                     LOGGER.at(Level.WARNING).log("Session Service response missing accessToken field");
                     class="kw">return null;
                  }
               }
            } catch (IOException var8) {
               LOGGER.at(Level.WARNING).log("IO error while exchanging auth grant: %s", var8.getMessage());
               class="kw">return null;
            } catch (InterruptedException var9) {
               LOGGER.at(Level.WARNING).log("Request interrupted while exchanging auth grant");
               Thread.currentThread().interrupt();
               class="kw">return null;
            } catch (Exception var10) {
               LOGGER.at(Level.WARNING).log("Unexpected error exchanging auth grant: %s", var10.getMessage());
               class="kw">return null;
            }
         },
         HTTP_EXECUTOR
      );
   }

   @Nullable
   class="kw">public SessionServiceClient.JwksResponse getJwks() {
      try {
         HttpRequest var1 = HttpRequest.newBuilder()
            .uri(URI.create(this.sessionServiceUrl + "/.well-known/jwks.json"))
            .header("Accept", "application/json")
            .header("User-Agent", AuthConfig.USER_AGENT)
            .timeout(AuthConfig.HTTP_TIMEOUT)
            .GET()
            .build();
         LOGGER.at(Level.FINE).log("Fetching JWKS from Session Service");
         HttpResponse var2 = this.httpClient.send(var1, BodyHandlers.ofString());
         if (var2.statusCode() != 200) {
            LOGGER.at(Level.WARNING).log("Failed to fetch JWKS: HTTP %d - %s", var2.statusCode(), var2.body());
            class="kw">return null;
         } else {
            SessionServiceClient.JwksResponse var3 = SessionServiceClient.JwksResponse.CODEC
               .decodeJson(new RawJsonReader(var2.body().toCharArray()), EmptyExtraInfo.EMPTY);
            if (var3 != null && var3.keys != null && var3.keys.length != 0) {
               LOGGER.at(Level.INFO).log("Successfully fetched JWKS with %d keys", var3.keys.length);
               class="kw">return var3;
            } else {
               LOGGER.at(Level.WARNING).log("Session Service returned invalid JWKS (no keys)");
               class="kw">return null;
            }
         }
      } catch (IOException var4) {
         LOGGER.at(Level.WARNING).log("IO error while fetching JWKS: %s", var4.getMessage());
         class="kw">return null;
      } catch (InterruptedException var5) {
         LOGGER.at(Level.WARNING).log("Request interrupted while fetching JWKS");
         Thread.currentThread().interrupt();
         class="kw">return null;
      } catch (Exception var6) {
         LOGGER.at(Level.WARNING).log("Unexpected error fetching JWKS: %s", var6.getMessage());
         class="kw">return null;
      }
   }

   @Nullable
   class="kw">public SessionServiceClient.GameProfile[] getGameProfiles(@Nonnull String var1) {
      try {
         HttpRequest var2 = HttpRequest.newBuilder()
            .uri(URI.create("https://account-data.hytale.com/my-account/get-profiles"))
            .header("Accept", "application/json")
            .header("Authorization", "Bearer " + var1)
            .header("User-Agent", AuthConfig.USER_AGENT)
            .timeout(AuthConfig.HTTP_TIMEOUT)
            .GET()
            .build();
         LOGGER.at(Level.INFO).log("Fetching game profiles...");
         HttpResponse var3 = this.httpClient.send(var2, BodyHandlers.ofString());
         if (var3.statusCode() != 200) {
            LOGGER.at(Level.WARNING).log("Failed to fetch profiles: HTTP %d - %s", var3.statusCode(), var3.body());
            class="kw">return null;
         } else {
            SessionServiceClient.LauncherDataResponse var4 = SessionServiceClient.LauncherDataResponse.CODEC
               .decodeJson(new RawJsonReader(var3.body().toCharArray()), EmptyExtraInfo.EMPTY);
            if (var4 != null && var4.profiles != null) {
               LOGGER.at(Level.INFO).log("Found %d game profile(s)", var4.profiles.length);
               class="kw">return var4.profiles;
            } else {
               LOGGER.at(Level.WARNING).log("Account Data returned invalid response");
               class="kw">return null;
            }
         }
      } catch (IOException var5) {
         LOGGER.at(Level.WARNING).log("IO error while fetching profiles: %s", var5.getMessage());
         class="kw">return null;
      } catch (InterruptedException var6) {
         LOGGER.at(Level.WARNING).log("Request interrupted while fetching profiles");
         Thread.currentThread().interrupt();
         class="kw">return null;
      } catch (Exception var7) {
         LOGGER.at(Level.WARNING).log("Unexpected error fetching profiles: %s", var7.getMessage());
         class="kw">return null;
      }
   }

   @Nullable
   class="kw">public SessionServiceClient.GameSessionResponse createGameSession(@Nonnull String var1, @Nonnull UUID var2) {
      try {
         String var3 = String.format("{\"uuid\":\"%s\"}", var2.toString());
         HttpRequest var4 = HttpRequest.newBuilder()
            .uri(URI.create(this.sessionServiceUrl + "/game-session/new"))
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + var1)
            .header("User-Agent", AuthConfig.USER_AGENT)
            .timeout(AuthConfig.HTTP_TIMEOUT)
            .POST(BodyPublishers.ofString(var3))
            .build();
         LOGGER.at(Level.INFO).log("Creating game session...");
         HttpResponse var5 = this.httpClient.send(var4, BodyHandlers.ofString());
         if (var5.statusCode() != 200 && var5.statusCode() != 201) {
            LOGGER.at(Level.WARNING).log("Failed to create game session: HTTP %d - %s", var5.statusCode(), var5.body());
            class="kw">return null;
         } else {
            SessionServiceClient.GameSessionResponse var6 = SessionServiceClient.GameSessionResponse.CODEC
               .decodeJson(new RawJsonReader(var5.body().toCharArray()), EmptyExtraInfo.EMPTY);
            if (var6 != null && var6.identityToken != null) {
               LOGGER.at(Level.INFO).log("Successfully created game session");
               class="kw">return var6;
            } else {
               LOGGER.at(Level.WARNING).log("Session Service returned invalid response");
               class="kw">return null;
            }
         }
      } catch (IOException var7) {
         LOGGER.at(Level.WARNING).log("IO error while creating session: %s", var7.getMessage());
         class="kw">return null;
      } catch (InterruptedException var8) {
         LOGGER.at(Level.WARNING).log("Request interrupted while creating session");
         Thread.currentThread().interrupt();
         class="kw">return null;
      } catch (Exception var9) {
         LOGGER.at(Level.WARNING).log("Unexpected error creating session: %s", var9.getMessage());
         class="kw">return null;
      }
   }

   class="kw">public CompletableFuture<SessionServiceClient.GameSessionResponse> refreshSessionAsync(@Nonnull String var1) {
      class="kw">return CompletableFuture.supplyAsync(
         () -> {
            try {
               HttpRequest var2 = HttpRequest.newBuilder()
                  .uri(URI.create(this.sessionServiceUrl + "/game-session/refresh"))
                  .header("Accept", "application/json")
                  .header("Authorization", "Bearer " + var1)
                  .header("User-Agent", AuthConfig.USER_AGENT)
                  .timeout(AuthConfig.HTTP_TIMEOUT)
                  .POST(BodyPublishers.noBody())
                  .build();
               LOGGER.at(Level.INFO).log("Refreshing game session...");
               HttpResponse var3 = this.httpClient.send(var2, BodyHandlers.ofString());
               int var4 = var3.statusCode();
               if (var4 != 200) {
                  LOGGER.at(Level.WARNING).log("Failed to refresh session: HTTP %d - %s", var4, var3.body());
                  if (!AuthConfig.isRejectedStatusCode(var4)) {
                     throw new HttpResponseException(var4, var3.body());
                  } else {
                     class="kw">return null;
                  }
               } else {
                  SessionServiceClient.GameSessionResponse var5 = SessionServiceClient.GameSessionResponse.CODEC
                     .decodeJson(new RawJsonReader(var3.body().toCharArray()), EmptyExtraInfo.EMPTY);
                  if (var5 != null && var5.identityToken != null) {
                     LOGGER.at(Level.INFO).log("Successfully refreshed game session");
                     class="kw">return var5;
                  } else {
                     LOGGER.at(Level.WARNING).log("Session Service returned invalid response (missing identity token)");
                     class="kw">return null;
                  }
               }
            } catch (IOException var6) {
               LOGGER.at(Level.WARNING).log("IO error while refreshing session: %s", var6.getMessage());
               throw SneakyThrow.sneakyThrow(var6);
            } catch (InterruptedException var7) {
               LOGGER.at(Level.WARNING).log("Request interrupted while refreshing session");
               Thread.currentThread().interrupt();
               class="kw">return null;
            } catch (Exception var8) {
               LOGGER.at(Level.WARNING).log("Unexpected error refreshing session: %s", var8.getMessage());
               class="kw">return null;
            }
         },
         HTTP_EXECUTOR
      );
   }

   class="kw">public void terminateSession(@Nonnull String var1) {
      if (var1 != null && !var1.isEmpty()) {
         try {
            HttpRequest var2 = HttpRequest.newBuilder()
               .uri(URI.create(this.sessionServiceUrl + "/game-session"))
               .header("Authorization", "Bearer " + var1)
               .header("User-Agent", AuthConfig.USER_AGENT)
               .timeout(AuthConfig.HTTP_TIMEOUT)
               .DELETE()
               .build();
            LOGGER.at(Level.INFO).log("Terminating game session...");
            HttpResponse var3 = this.httpClient.send(var2, BodyHandlers.ofString());
            if (var3.statusCode() != 200 && var3.statusCode() != 204) {
               LOGGER.at(Level.WARNING).log("Failed to terminate session: HTTP %d - %s", var3.statusCode(), var3.body());
            } else {
               LOGGER.at(Level.INFO).log("Game session terminated");
            }
         } catch (IOException var4) {
            LOGGER.at(Level.WARNING).log("IO error while terminating session: %s", var4.getMessage());
         } catch (InterruptedException var5) {
            LOGGER.at(Level.WARNING).log("Request interrupted while terminating session");
            Thread.currentThread().interrupt();
         } catch (Exception var6) {
            LOGGER.at(Level.WARNING).log("Error terminating session: %s", var6.getMessage());
         }
      }
   }

   class="kw">private class="kw">static String escapeJsonString(String var0) {
      class="kw">return var0 == null ? "" : var0.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
   }

   class="kw">private class="kw">static <T> KeyedCodec<T> externalKey(String var0, Codec<T> var1) {
      class="kw">return new KeyedCodec<>(var0, var1, false, true);
   }

   class="kw">public class="kw">static class AccessTokenResponse {
      class="kw">public String accessToken;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.AccessTokenResponse> CODEC = BuilderCodec.builder(
            SessionServiceClient.AccessTokenResponse.class, SessionServiceClient.AccessTokenResponse::new
         )
         .append(SessionServiceClient.externalKey("accessToken", Codec.STRING), (var0, var1) -> var0.accessToken = var1, var0 -> var0.accessToken)
         .add()
         .build();

      class="kw">public AccessTokenResponse() {
      }
   }

   class="kw">public class="kw">static class AuthGrantResponse {
      class="kw">public String authorizationGrant;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.AuthGrantResponse> CODEC = BuilderCodec.builder(
            SessionServiceClient.AuthGrantResponse.class, SessionServiceClient.AuthGrantResponse::new
         )
         .append(
            SessionServiceClient.externalKey("authorizationGrant", Codec.STRING),
            (var0, var1) -> var0.authorizationGrant = var1,
            var0 -> var0.authorizationGrant
         )
         .add()
         .build();

      class="kw">public AuthGrantResponse() {
      }
   }

   class="kw">public class="kw">static class GameProfile {
      class="kw">public UUID uuid;
      class="kw">public String username;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.GameProfile> CODEC = BuilderCodec.builder(
            SessionServiceClient.GameProfile.class, SessionServiceClient.GameProfile::new
         )
         .append(SessionServiceClient.externalKey("uuid", Codec.UUID_STRING), (var0, var1) -> var0.uuid = var1, var0 -> var0.uuid)
         .add()
         .append(SessionServiceClient.externalKey("username", Codec.STRING), (var0, var1) -> var0.username = var1, var0 -> var0.username)
         .add()
         .build();

      class="kw">public GameProfile() {
      }
   }

   class="kw">public class="kw">static class GameSessionResponse {
      class="kw">public String sessionToken;
      class="kw">public String identityToken;
      class="kw">public String expiresAt;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.GameSessionResponse> CODEC = BuilderCodec.builder(
            SessionServiceClient.GameSessionResponse.class, SessionServiceClient.GameSessionResponse::new
         )
         .append(SessionServiceClient.externalKey("sessionToken", Codec.STRING), (var0, var1) -> var0.sessionToken = var1, var0 -> var0.sessionToken)
         .add()
         .append(SessionServiceClient.externalKey("identityToken", Codec.STRING), (var0, var1) -> var0.identityToken = var1, var0 -> var0.identityToken)
         .add()
         .append(SessionServiceClient.externalKey("expiresAt", Codec.STRING), (var0, var1) -> var0.expiresAt = var1, var0 -> var0.expiresAt)
         .add()
         .build();

      class="kw">public GameSessionResponse() {
      }

      @Nullable
      class="kw">public Instant getExpiresAtInstant() {
         if (this.expiresAt == null) {
            class="kw">return null;
         }

         try {
            class="kw">return Instant.parse(this.expiresAt);
         } catch (Exception var2) {
            class="kw">return null;
         }
      }
   }

   class="kw">public class="kw">static class JwkKey {
      class="kw">public String kty;
      class="kw">public String alg;
      class="kw">public String use;
      class="kw">public String kid;
      class="kw">public String crv;
      class="kw">public String x;
      class="kw">public String y;
      class="kw">public String n;
      class="kw">public String e;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.JwkKey> CODEC = BuilderCodec.builder(
            SessionServiceClient.JwkKey.class, SessionServiceClient.JwkKey::new
         )
         .append(SessionServiceClient.externalKey("kty", Codec.STRING), (var0, var1) -> var0.kty = var1, var0 -> var0.kty)
         .add()
         .append(SessionServiceClient.externalKey("alg", Codec.STRING), (var0, var1) -> var0.alg = var1, var0 -> var0.alg)
         .add()
         .append(SessionServiceClient.externalKey("use", Codec.STRING), (var0, var1) -> var0.use = var1, var0 -> var0.use)
         .add()
         .append(SessionServiceClient.externalKey("kid", Codec.STRING), (var0, var1) -> var0.kid = var1, var0 -> var0.kid)
         .add()
         .append(SessionServiceClient.externalKey("crv", Codec.STRING), (var0, var1) -> var0.crv = var1, var0 -> var0.crv)
         .add()
         .append(SessionServiceClient.externalKey("x", Codec.STRING), (var0, var1) -> var0.x = var1, var0 -> var0.x)
         .add()
         .append(SessionServiceClient.externalKey("y", Codec.STRING), (var0, var1) -> var0.y = var1, var0 -> var0.y)
         .add()
         .append(SessionServiceClient.externalKey("n", Codec.STRING), (var0, var1) -> var0.n = var1, var0 -> var0.n)
         .add()
         .append(SessionServiceClient.externalKey("e", Codec.STRING), (var0, var1) -> var0.e = var1, var0 -> var0.e)
         .add()
         .build();

      class="kw">public JwkKey() {
      }
   }

   class="kw">public class="kw">static class JwksResponse {
      class="kw">public SessionServiceClient.JwkKey[] keys;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.JwksResponse> CODEC = BuilderCodec.builder(
            SessionServiceClient.JwksResponse.class, SessionServiceClient.JwksResponse::new
         )
         .append(
            SessionServiceClient.externalKey("keys", new ArrayCodec<>(SessionServiceClient.JwkKey.CODEC, SessionServiceClient.JwkKey[]::new)),
            (var0, var1) -> var0.keys = var1,
            var0 -> var0.keys
         )
         .add()
         .build();

      class="kw">public JwksResponse() {
      }
   }

   class="kw">public class="kw">static class LauncherDataResponse {
      class="kw">public UUID owner;
      class="kw">public SessionServiceClient.GameProfile[] profiles;
      class="kw">public class="kw">static class="kw">final BuilderCodec<SessionServiceClient.LauncherDataResponse> CODEC = BuilderCodec.builder(
            SessionServiceClient.LauncherDataResponse.class, SessionServiceClient.LauncherDataResponse::new
         )
         .append(SessionServiceClient.externalKey("owner", Codec.UUID_STRING), (var0, var1) -> var0.owner = var1, var0 -> var0.owner)
         .add()
         .append(
            SessionServiceClient.externalKey("profiles", new ArrayCodec<>(SessionServiceClient.GameProfile.CODEC, SessionServiceClient.GameProfile[]::new)),
            (var0, var1) -> var0.profiles = var1,
            var0 -> var0.profiles
         )
         .add()
         .build();

      class="kw">public LauncherDataResponse() {
      }
   }
}