From 8972605a021defacc6afe72638487a642494ff34 Mon Sep 17 00:00:00 2001 From: Colin McDonald Date: Fri, 24 Jun 2016 22:18:45 -0400 Subject: [PATCH] Fix possible concurrency issue with POST /users/:id/leave --- src/main/java/net/frozenorb/apiv3/model/User.java | 10 +++++++--- .../apiv3/route/servers/POSTServersHeartbeat.java | 3 ++- .../apiv3/route/users/POSTUsersIdLeave.java | 15 ++++++++++++++- .../apiv3/route/users/POSTUsersIdLogin.java | 5 +++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/frozenorb/apiv3/model/User.java b/src/main/java/net/frozenorb/apiv3/model/User.java index d33ba72..1845490 100644 --- a/src/main/java/net/frozenorb/apiv3/model/User.java +++ b/src/main/java/net/frozenorb/apiv3/model/User.java @@ -313,9 +313,13 @@ public final class User { return true; } - public void leftServer() { - this.lastSeenAt = Instant.now(); - this.online = false; + public void leftServer(Server server) { + // We have this check to prevent issues where one server's + // leave is processed after another server's login. + if (server.getId().equals(lastSeenOn)) { + this.lastSeenAt = Instant.now(); + this.online = false; + } } public void startPasswordReset() { diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java index aac63fd..87690c4 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java @@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; +import net.frozenorb.apiv3.actor.actors.ServerActor; import net.frozenorb.apiv3.model.*; import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback; @@ -33,7 +34,7 @@ public final class POSTServersHeartbeat implements Handler { return; } - Server actorServer = Server.findById(actor.getName()); + Server actorServer = ((ServerActor) actor).getServer(); ServerGroup actorServerGroup = ServerGroup.findById(actorServer.getServerGroup()); JsonObject requestBody = ctx.getBodyAsJson(); Map playerNames = extractPlayerNames(requestBody.getJsonArray("players")); diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLeave.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLeave.java index 0127bba..8534205 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLeave.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLeave.java @@ -3,6 +3,10 @@ package net.frozenorb.apiv3.route.users; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.actor.Actor; +import net.frozenorb.apiv3.actor.ActorType; +import net.frozenorb.apiv3.actor.actors.ServerActor; +import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; @@ -10,13 +14,22 @@ public class POSTUsersIdLeave implements Handler { @Override public void handle(RoutingContext ctx) { + Actor actor = ctx.get("actor"); + + if (actor.getType() != ActorType.SERVER) { + ErrorUtils.respondGeneric(ctx, 400, "This action can only be performed when requested by a server."); + return; + } + + Server actorServer = ((ServerActor) actor).getServer(); + User.findById(ctx.request().getParam("id"), ((user, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); } else if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); } else { - user.leftServer(); + user.leftServer(actorServer); user.save((ignored, error2) -> { if (error2 != null) { ErrorUtils.respondInternalError(ctx, error2); diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java index 09ca685..b59fe64 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java @@ -7,6 +7,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; +import net.frozenorb.apiv3.actor.actors.ServerActor; import net.frozenorb.apiv3.model.IpLogEntry; import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.User; @@ -40,7 +41,7 @@ public final class POSTUsersIdLogin implements Handler { return; } - Server server = Server.findById(actor.getName()); + Server actorServer = ((ServerActor) actor).getServer(); if (!IpUtils.isValidIp(userIp)) { ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); @@ -84,7 +85,7 @@ public final class POSTUsersIdLogin implements Handler { user.updateUsername(username); - user.getLoginInfo(server, userIp, (loginInfo, error) -> { + user.getLoginInfo(actorServer, userIp, (loginInfo, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); } else {