Fix possible concurrency issue with POST /users/:id/leave

This commit is contained in:
Colin McDonald 2016-06-24 22:18:45 -04:00
parent a87578a8a6
commit 8972605a02
4 changed files with 26 additions and 7 deletions

View File

@ -313,10 +313,14 @@ public final class User {
return true;
}
public void leftServer() {
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() {
this.passwordResetToken = UUID.randomUUID().toString().replaceAll("-", "");

View File

@ -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<RoutingContext> {
return;
}
Server actorServer = Server.findById(actor.getName());
Server actorServer = ((ServerActor) actor).getServer();
ServerGroup actorServerGroup = ServerGroup.findById(actorServer.getServerGroup());
JsonObject requestBody = ctx.getBodyAsJson();
Map<UUID, String> playerNames = extractPlayerNames(requestBody.getJsonArray("players"));

View File

@ -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<RoutingContext> {
@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);

View File

@ -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<RoutingContext> {
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<RoutingContext> {
user.updateUsername(username);
user.getLoginInfo(server, userIp, (loginInfo, error) -> {
user.getLoginInfo(actorServer, userIp, (loginInfo, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {