diff options
| author | ilotterytea <iltsu@alright.party> | 2025-01-23 20:31:23 +0500 |
|---|---|---|
| committer | ilotterytea <iltsu@alright.party> | 2025-01-23 20:31:23 +0500 |
| commit | ff9d8f584616cc3d9d7000e95f681707fd508497 (patch) | |
| tree | b56f83b921f887424e69fffde8c34753a4e09baa | |
| parent | c94a51d6ab4863e2fa6fd230def08aac3f2bf73a (diff) | |
feat: server-side sign-in implementation
13 files changed, 152 insertions, 26 deletions
diff --git a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java index a696121..681b377 100644 --- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java +++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionClient.java @@ -10,6 +10,7 @@ import kz.ilotterytea.frogartha.FrogarthaGame; import kz.ilotterytea.frogartha.domain.Identity; import kz.ilotterytea.frogartha.domain.PlayerData; import kz.ilotterytea.frogartha.domain.RoomTopic; +import kz.ilotterytea.frogartha.domain.actions.IdentificationAction; import kz.ilotterytea.frogartha.domain.actions.JoinRoomAction; import kz.ilotterytea.frogartha.domain.actions.LeaveRoomAction; import kz.ilotterytea.frogartha.domain.events.*; @@ -29,6 +30,7 @@ public class SessionClient implements WebSocketListener { private boolean isJoining, joined; private Integer connectionId; + private Identity identity; private RoomTopic topic; private Throwable lastThrow; @@ -75,7 +77,10 @@ public class SessionClient implements WebSocketListener { } if (obj instanceof IdentifiedEvent) { - SessionHandlers.handleIdentifiedEvent((IdentifiedEvent) obj); + IdentifiedEvent x = (IdentifiedEvent) obj; + identity = x.getIdentity(); + connectionId = x.getPlayerId(); + log.log("The server identified me! I'm {} with ID {}", identity, connectionId); } else if (obj instanceof PlayerJumpEvent) { SessionHandlers.handlePlayerJumpEvent((PlayerJumpEvent) obj); } else if (obj instanceof ChangedDirectionEvent) { @@ -145,7 +150,10 @@ public class SessionClient implements WebSocketListener { } public void updateIdentity() { - send(new Identity(game.getIdentityClient().getUsername())); + send(new IdentificationAction( + game.getIdentityClient().getClientToken(), + game.getIdentityClient().getAccessToken() + )); } public int getConnectionId() { @@ -156,6 +164,10 @@ public class SessionClient implements WebSocketListener { this.connectionId = connectionId; } + public Identity getIdentity() { + return identity; + } + public Throwable getLastThrow() { Throwable cpy = lastThrow; this.lastThrow = null; diff --git a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java index 9ced32b..0c89b04 100644 --- a/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java +++ b/core/src/main/java/kz/ilotterytea/frogartha/sessions/SessionHandlers.java @@ -16,12 +16,6 @@ public class SessionHandlers { private static final FrogarthaGame game = FrogarthaGame.getInstance(); private static final SessionClient client = game.getSessionClient(); - public static void handleIdentifiedEvent(IdentifiedEvent event) { - log.log("The server identified me!"); - - client.setConnectionId(event.getPlayerId()); - } - public static void handlePlayerJumpEvent(PlayerJumpEvent event) { if (!game.getScreen().getClass().equals(GameScreen.class)) { log.log("The screen is not GameScreen, but the session received PlayerJumpEvent"); diff --git a/gradle.properties b/gradle.properties index ac7c536..4b258d2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,4 +9,5 @@ enableGraalNative=false gdxVersion=1.13.1 gdxWsVersion=1.10.1.12.0 javaWebsocketVersion=1.6.0 +okhttpVersion=4.12.0 projectVersion=1.0.0 diff --git a/server/build.gradle b/server/build.gradle index d4acfbd..9ef7670 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -13,6 +13,7 @@ eclipse.project.name = appName + '-server' dependencies { api "org.java-websocket:Java-WebSocket:$javaWebsocketVersion" + implementation "com.squareup.okhttp3:okhttp:$okhttpVersion" implementation project(':shared') } diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java index 6e8fbde..095fb05 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/FrogarthaServer.java @@ -2,7 +2,6 @@ package kz.ilotterytea.frogartha.server; import com.github.czyzby.websocket.serialization.SerializationException; import com.github.czyzby.websocket.serialization.impl.ManualSerializer; -import kz.ilotterytea.frogartha.domain.Identity; import kz.ilotterytea.frogartha.domain.actions.*; import kz.ilotterytea.frogartha.exceptions.PlayerKickException; import kz.ilotterytea.frogartha.utils.Logger; @@ -88,8 +87,8 @@ public class FrogarthaServer extends WebSocketServer { throw PlayerKickException.internalServerError(); } - if (obj instanceof Identity) { - ServerHandlers.handleIdentity(player, (Identity) obj); + if (obj instanceof IdentificationAction) { + ServerHandlers.handleIdentification(player, (IdentificationAction) obj); } else if (obj instanceof PlayerJumpAction) { ServerHandlers.handlePlayerJumpAction(player, (PlayerJumpAction) obj); } else if (obj instanceof ChangedDirectionAction) { diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java index f1d0a3b..83f10ec 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/PlayerConnection.java @@ -1,6 +1,7 @@ package kz.ilotterytea.frogartha.server; import kz.ilotterytea.frogartha.domain.PlayerData; +import kz.ilotterytea.frogartha.domain.actions.IdentificationAction; import org.java_websocket.WebSocket; import java.sql.Timestamp; @@ -10,6 +11,7 @@ public class PlayerConnection extends PlayerData { private final WebSocket connection; private Room room; + private IdentificationAction identification; private final Timestamp connectedTimestamp; @@ -19,6 +21,7 @@ public class PlayerConnection extends PlayerData { TOTAL_CONNECTION_IDS++; this.room = null; + this.identification = null; this.connectedTimestamp = new Timestamp(System.currentTimeMillis()); } @@ -43,6 +46,14 @@ public class PlayerConnection extends PlayerData { this.room = room; } + public IdentificationAction getIdentification() { + return identification; + } + + public void setIdentification(IdentificationAction identification) { + this.identification = identification; + } + public Timestamp getConnectedTimestamp() { return connectedTimestamp; } diff --git a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java index 6891fef..ab5cfd4 100644 --- a/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java +++ b/server/src/main/java/kz/ilotterytea/frogartha/server/ServerHandlers.java @@ -2,6 +2,9 @@ package kz.ilotterytea.frogartha.server; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.utils.JsonReader; +import com.badlogic.gdx.utils.JsonValue; +import com.badlogic.gdx.utils.JsonWriter; import kz.ilotterytea.frogartha.FrogarthaConstants; import kz.ilotterytea.frogartha.domain.Identity; import kz.ilotterytea.frogartha.domain.PlayerState; @@ -12,6 +15,7 @@ import kz.ilotterytea.frogartha.domain.events.IdentifiedEvent; import kz.ilotterytea.frogartha.domain.events.PlayerJumpEvent; import kz.ilotterytea.frogartha.exceptions.PlayerKickException; import kz.ilotterytea.frogartha.utils.Logger; +import okhttp3.*; import java.util.Optional; @@ -19,18 +23,51 @@ public class ServerHandlers { private static final Logger log = new Logger(ServerHandlers.class); private static final FrogarthaServer server = FrogarthaServer.getInstance(); - public static void handleIdentity(PlayerConnection player, Identity identity) { + public static void handleIdentification(PlayerConnection player, IdentificationAction action) { + JsonValue json = new JsonValue(JsonValue.ValueType.object); + json.addChild("clientToken", new JsonValue(action.getClientToken())); + json.addChild("accessToken", new JsonValue(action.getAccessToken())); + + OkHttpClient client = new OkHttpClient(); + + Request httpRequest = new Request.Builder() + .post(RequestBody.create(json.toJson(JsonWriter.OutputType.json), MediaType.parse("application/json; charset=utf-8"))) + .url(FrogarthaConstants.URLS.IDENTITY_IDENTIFY_URL) + .build(); + + try (Response response = client.newCall(httpRequest).execute()) { + if (response.body() == null) { + throw new Exception("Response body is null"); + } + + json = new JsonReader().parse(response.body().string()); + + if (response.code() != 200) { + throw new Exception(json.get("error").getString("message")); + } + + Identity identity = new Identity( + json.get("data").getLong("id"), + json.get("data").getString("username") + ); + + player.setIdentification(action); + player.setIdentity(identity); + player.send(new IdentifiedEvent(player.getId(), identity)); + + log.log("Successfully identified {} for {}", identity, player); + } catch (Exception e) { + log.error("Failed to identify: {}", e); + server.kickConnection(player, PlayerKickException.badLogin(e.getMessage())); + return; + } + if (server.getPlayers() .stream() .filter((x) -> x.getIdentity() != null) - .anyMatch((x) -> x.getIdentity().equals(identity) && x.getId() != player.getId())) { + .anyMatch((x) -> x.getIdentity().getId() == player.getIdentity().getId() && x.getId() != player.getId())) { server.kickConnection(player, PlayerKickException.loggedIn()); - return; } - - player.setIdentity(identity); - player.send(new IdentifiedEvent(player.getId())); - log.log("Successfully identified {} for {}", identity, player); } public static void handlePlayerJumpAction(PlayerConnection player, PlayerJumpAction action) { diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java b/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java index 1e55d52..81c843f 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/FrogarthaConstants.java @@ -13,6 +13,7 @@ public class FrogarthaConstants { public static final String IDENTITY_VALIDATE_URL = IDENTITY_BASE_URL + "/validate"; public static final String IDENTITY_REFRESH_URL = IDENTITY_BASE_URL + "/refresh"; public static final String IDENTITY_AUTHENTICATION_URL = IDENTITY_BASE_URL + "/authenticate"; + public static final String IDENTITY_IDENTIFY_URL = IDENTITY_BASE_URL + "/identify"; public static final String IDENTITY_REGISTRATION_URL = IDENTITY_BASE_URL; } diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/Identity.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/Identity.java index 03c0ef4..2d81055 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/domain/Identity.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/Identity.java @@ -7,14 +7,20 @@ import com.github.czyzby.websocket.serialization.impl.Serializer; public class Identity implements Transferable<Identity> { private String username; + private long id; public Identity() { } - public Identity(String username) { + public Identity(long id, String username) { + this.id = id; this.username = username; } + public long getId() { + return id; + } + public String getUsername() { return username; } @@ -22,7 +28,8 @@ public class Identity implements Transferable<Identity> { @Override public boolean equals(Object obj) { if (obj instanceof Identity) { - return ((Identity) obj).username.equals(username); + Identity i = (Identity) obj; + return i.username.equals(username) && i.id == id; } return false; } @@ -31,16 +38,17 @@ public class Identity implements Transferable<Identity> { public String toString() { return "Identity{" + "username='" + username + '\'' + + ", id=" + id + '}'; } @Override public void serialize(Serializer serializer) throws SerializationException { - serializer.serializeString(username); + serializer.serializeLong(id).serializeString(username); } @Override public Identity deserialize(Deserializer deserializer) throws SerializationException { - return new Identity(deserializer.deserializeString()); + return new Identity(deserializer.deserializeLong(), deserializer.deserializeString()); } } diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/IdentificationAction.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/IdentificationAction.java new file mode 100644 index 0000000..6d3c4d8 --- /dev/null +++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/actions/IdentificationAction.java @@ -0,0 +1,48 @@ +package kz.ilotterytea.frogartha.domain.actions; + +import com.github.czyzby.websocket.serialization.SerializationException; +import com.github.czyzby.websocket.serialization.Transferable; +import com.github.czyzby.websocket.serialization.impl.Deserializer; +import com.github.czyzby.websocket.serialization.impl.Serializer; + +public class IdentificationAction implements Transferable<IdentificationAction> { + private String clientToken, accessToken; + + public IdentificationAction() { + } + + public IdentificationAction(String clientToken, String accessToken) { + this.clientToken = clientToken; + this.accessToken = accessToken; + } + + public String getClientToken() { + return clientToken; + } + + public String getAccessToken() { + return accessToken; + } + + @Override + public void serialize(Serializer serializer) throws SerializationException { + serializer.serializeString(clientToken).serializeString(accessToken); + } + + @Override + public IdentificationAction deserialize(Deserializer deserializer) throws SerializationException { + return new IdentificationAction(deserializer.deserializeString(), deserializer.deserializeString()); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + + if (obj instanceof IdentificationAction) { + IdentificationAction x = (IdentificationAction) obj; + return x.accessToken.equals(accessToken) && x.clientToken.equals(clientToken); + } + + return false; + } +} diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java index d2d9e1e..01a12fe 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/domain/events/IdentifiedEvent.java @@ -4,22 +4,30 @@ import com.github.czyzby.websocket.serialization.SerializationException; import com.github.czyzby.websocket.serialization.Transferable; import com.github.czyzby.websocket.serialization.impl.Deserializer; import com.github.czyzby.websocket.serialization.impl.Serializer; +import kz.ilotterytea.frogartha.domain.Identity; public class IdentifiedEvent extends Event implements Transferable<IdentifiedEvent> { + private Identity identity; + public IdentifiedEvent() { } - public IdentifiedEvent(int playerId) { - this.playerId = playerId; + public IdentifiedEvent(int playerId, Identity identity) { + super(playerId); + this.identity = identity; + } + + public Identity getIdentity() { + return identity; } @Override public void serialize(Serializer serializer) throws SerializationException { - serializer.serializeInt(playerId); + serializer.serializeInt(playerId).serializeTransferable(identity); } @Override public IdentifiedEvent deserialize(Deserializer deserializer) throws SerializationException { - return new IdentifiedEvent(deserializer.deserializeInt()); + return new IdentifiedEvent(deserializer.deserializeInt(), deserializer.deserializeTransferable(new Identity())); } } diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java b/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java index e24c633..22f45cc 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/exceptions/PlayerKickException.java @@ -37,6 +37,10 @@ public class PlayerKickException extends RuntimeException implements Transferabl return new PlayerKickException("Kicked for spamming"); } + public static PlayerKickException badLogin(String reason) { + return new PlayerKickException("Bad login" + ((reason != null) ? (" (" + reason + ")") : "")); + } + @Override public void serialize(Serializer serializer) throws SerializationException { serializer.serializeString(getMessage()); diff --git a/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java b/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java index 3529968..2a22bcc 100644 --- a/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java +++ b/shared/src/main/java/kz/ilotterytea/frogartha/utils/SerializerUtils.java @@ -14,7 +14,9 @@ public class SerializerUtils { serializer.register(new PlayerJumpEvent()); serializer.register(new ChangedDirectionAction()); serializer.register(new ChangedDirectionEvent()); + serializer.register(new IdentifiedEvent()); + serializer.register(new IdentificationAction()); serializer.register(new JoinRoomAction()); serializer.register(new PlayerJoinedRoomEvent()); |
