From 4a727f3d048a7c5d3e161444c9158fbab247805a Mon Sep 17 00:00:00 2001 From: Colin McDonald Date: Fri, 24 Jun 2016 03:00:37 -0400 Subject: [PATCH] Large commit to convert all models to be full async --- src/main/java/net/frozenorb/apiv3/APIv3.java | 21 +- .../apiv3/dataImport/V2Importer.java | 19 +- .../dataImport/converters/GrantConverter.java | 5 +- .../dataImport/converters/IpLogConverter.java | 5 +- .../converters/PunishmentConverter.java | 5 +- .../dataImport/converters/UserConverter.java | 5 +- .../apiv3/handler/ActorAttributeHandler.java | 10 +- .../java/net/frozenorb/apiv3/model/Grant.java | 26 +- .../java/net/frozenorb/apiv3/model/IpBan.java | 62 +-- .../net/frozenorb/apiv3/model/IpIntel.java | 8 +- .../net/frozenorb/apiv3/model/IpLogEntry.java | 34 +- .../apiv3/model/NotificationTemplate.java | 14 +- .../net/frozenorb/apiv3/model/Punishment.java | 59 +- .../java/net/frozenorb/apiv3/model/Rank.java | 68 +-- .../net/frozenorb/apiv3/model/Server.java | 70 +-- .../frozenorb/apiv3/model/ServerGroup.java | 66 +-- .../java/net/frozenorb/apiv3/model/User.java | 519 ++++++++---------- .../apiv3/route/auditLog/POSTAuditLog.java | 7 +- .../route/emailToken/GETEmailTokensOwner.java | 2 +- .../emailToken/POSTEmailTokensConfirm.java | 10 +- .../apiv3/route/grants/DELETEGrantsId.java | 13 +- .../apiv3/route/grants/POSTGrants.java | 13 +- .../apiv3/route/ipBans/DELETEIpBan.java | 13 +- .../apiv3/route/ipBans/POSTIpBans.java | 9 +- .../DELETENotificationTemplatesId.java | 10 +- .../POSTNotificationTemplates.java | 5 +- .../route/punishments/DELETEPunishments.java | 13 +- .../DELETEUserActivePunishment.java | 21 +- .../route/punishments/POSTPunishments.java | 32 +- .../apiv3/route/ranks/DELETERanksId.java | 6 +- .../apiv3/route/ranks/POSTRanks.java | 5 +- .../serverGroups/DELETEServerGroupsId.java | 6 +- .../route/serverGroups/POSTServerGroups.java | 5 +- .../apiv3/route/servers/DELETEServersId.java | 6 +- .../apiv3/route/servers/POSTServers.java | 5 +- .../route/servers/POSTServersHeartbeat.java | 126 +++-- .../frozenorb/apiv3/route/users/GETStaff.java | 10 +- .../apiv3/route/users/GETUserDetails.java | 38 +- .../apiv3/route/users/GETUserPermissions.java | 23 +- .../route/users/GETUserRequiresTOTP.java | 3 +- .../route/users/GETUserVerifyPassword.java | 13 +- .../route/users/POSTUserChangePassword.java | 16 +- .../apiv3/route/users/POSTUserLogin.java | 32 +- .../apiv3/route/users/POSTUserNotify.java | 9 +- .../apiv3/route/users/POSTUserRegister.java | 16 +- .../apiv3/route/users/POSTUserSetupTOTP.java | 10 +- .../apiv3/route/users/POSTUserVerifyTOTP.java | 4 +- .../unsorted/FutureCompatibilityCallback.java | 22 + .../apiv3/unsorted/RequiresTotpResult.java | 9 + .../net/frozenorb/apiv3/util/SyncUtils.java | 27 - 50 files changed, 810 insertions(+), 725 deletions(-) create mode 100644 src/main/java/net/frozenorb/apiv3/unsorted/FutureCompatibilityCallback.java create mode 100644 src/main/java/net/frozenorb/apiv3/unsorted/RequiresTotpResult.java delete mode 100644 src/main/java/net/frozenorb/apiv3/util/SyncUtils.java diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java index 1fd708e..80d4b90 100644 --- a/src/main/java/net/frozenorb/apiv3/APIv3.java +++ b/src/main/java/net/frozenorb/apiv3/APIv3.java @@ -85,6 +85,7 @@ import java.io.IOException; import java.io.InputStream; import java.time.Instant; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -107,6 +108,13 @@ public final class APIv3 extends AbstractVerticle { setupDatabase(); setupHttpServer(); + /*try { + ObjectMapper mapper = new ObjectMapper(); + log.info(gson.toJson(mapper.readValue("email=test@google.com", Map.class))); + } catch (Exception ex) { + ex.printStackTrace(); + }*/ + /*V2Importer converter = new V2Importer("mongodb://158.69.126.126", "minehq"); converter.startImport((ignored, error) -> { @@ -218,12 +226,12 @@ public final class APIv3 extends AbstractVerticle { http.route().handler(LoggerHandler.create(LoggerFormat.TINY)); http.route().handler(TimeoutHandler.create(TimeUnit.SECONDS.toMillis(5))); - http.route().method(HttpMethod.PUT).method(HttpMethod.POST).handler(BodyHandler.create()); + http.route().method(HttpMethod.PUT).method(HttpMethod.POST).method(HttpMethod.DELETE).handler(BodyHandler.create()); http.route().handler(new ActorAttributeHandler()); http.route().handler(new AuthorizationHandler()); - http.exceptionHandler(Throwable::printStackTrace); // TODO: The commented out routes + // TODO: RENAME THESE ROUTES TO BE RIGHT http.get("/auditLog").handler(new GETAuditLog()); http.post("/auditLog").handler(new POSTAuditLog()); @@ -281,7 +289,7 @@ public final class APIv3 extends AbstractVerticle { http.get("/staff").blockingHandler(new GETStaff(), false); http.get("/users/:id").handler(new GETUser()); http.get("/users/:id/details").blockingHandler(new GETUserDetails(), false); - http.get("/users/:id/permissions").blockingHandler(new GETUserPermissions(), false); + http.get("/users/:id/permissions").handler(new GETUserPermissions()); http.get("/users/:id/requiresTotp").handler(new GETUserRequiresTotp()); http.get("/users/:id/verifyPassword").blockingHandler(new GETUserVerifyPassword(), false); http.post("/users/:id/changePassword").blockingHandler(new POSTUserChangePassword(), false); @@ -299,6 +307,8 @@ public final class APIv3 extends AbstractVerticle { webServer.requestHandler(http::accept).listen(port); } + // TODO: TEST IF OUR MODEL CONSTRUCTORS CAN BE PRIVATE + public static void respondJson(RoutingContext ctx, Object response) { respondJson(ctx, 200, response); } @@ -306,6 +316,11 @@ public final class APIv3 extends AbstractVerticle { public static void respondJson(RoutingContext ctx, int code, Object response) { ctx.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString()); ctx.response().setStatusCode(code); + + if (!ctx.request().path().contains("dumps")) { + log.info(gson.toJson(response)); + } + ctx.response().end(gson.toJson(response)); } diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java b/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java index bd17093..3bd261f 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java @@ -10,6 +10,7 @@ import net.frozenorb.apiv3.dataImport.converters.GrantConverter; import net.frozenorb.apiv3.dataImport.converters.IpLogConverter; import net.frozenorb.apiv3.dataImport.converters.PunishmentConverter; import net.frozenorb.apiv3.dataImport.converters.UserConverter; +import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback; import org.bson.types.ObjectId; import java.util.HashMap; @@ -52,22 +53,4 @@ public final class V2Importer { }); } - private static class FutureCompatibilityCallback implements SingleResultCallback { - - private final Future future; - - private FutureCompatibilityCallback(Future future) { - this.future = future; - } - - public void onResult(T val, Throwable error) { - if (error != null) { - future.fail(error); - } else { - future.complete(val); - } - } - - } - } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/converters/GrantConverter.java b/src/main/java/net/frozenorb/apiv3/dataImport/converters/GrantConverter.java index 22e5715..bb4db64 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/GrantConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/GrantConverter.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet; import com.mongodb.Block; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.model.Grant; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import org.bson.Document; import org.bson.types.ObjectId; @@ -56,7 +57,9 @@ public final class GrantConverter implements Block { null ); - created.insert(); + BlockingCallback callback = new BlockingCallback<>(); + created.insert(callback); + callback.get(); log.info("Created grant " + created.getId() + " (" + created.getRank() + ")"); } diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/converters/IpLogConverter.java b/src/main/java/net/frozenorb/apiv3/dataImport/converters/IpLogConverter.java index 05e16e0..9a07466 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/IpLogConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/IpLogConverter.java @@ -3,6 +3,7 @@ package net.frozenorb.apiv3.dataImport.converters; import com.mongodb.Block; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.model.IpLogEntry; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.IpUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -50,7 +51,9 @@ public final class IpLogConverter implements Block { ((Number) ipLogEntry.get("uses")).intValue() ); - created.insert(); + BlockingCallback callback = new BlockingCallback<>(); + created.insert(callback); + callback.get(); log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")"); } diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java b/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java index 178d5be..cde80af 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java @@ -5,6 +5,7 @@ import com.mongodb.Block; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.model.Punishment; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import org.bson.Document; import org.bson.types.ObjectId; @@ -52,7 +53,9 @@ public final class PunishmentConverter implements Block { punishment.containsKey("removedBy") ? punishment.getString("removalReason").toString() : null ); - created.insert(); + BlockingCallback callback = new BlockingCallback<>(); + created.insert(callback); + callback.get(); log.info("Created punishment " + created.getId() + " (" + created.getType() + ")"); } diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/converters/UserConverter.java b/src/main/java/net/frozenorb/apiv3/dataImport/converters/UserConverter.java index 81ec97c..8f2de0e 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/UserConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/UserConverter.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap; import com.mongodb.Block; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.UuidUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -55,7 +56,9 @@ public final class UserConverter implements Block { false ); - created.insert(); + BlockingCallback callback = new BlockingCallback<>(); + created.insert(callback); + callback.get(); log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")"); } diff --git a/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java b/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java index 31e3dae..20a67f9 100644 --- a/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java +++ b/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java @@ -48,8 +48,14 @@ public final class ActorAttributeHandler implements Handler { } if (user != null && user.checkPassword(password)) { - ctx.put("actor", new UserActor(user, user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST))); // TODO: BLOCKING - ctx.next(); + user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST, (hasPermission, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + ctx.put("actor", new UserActor(user, hasPermission)); + ctx.next(); + } + }); } else { ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as " + username + "."); } diff --git a/src/main/java/net/frozenorb/apiv3/model/Grant.java b/src/main/java/net/frozenorb/apiv3/model/Grant.java index 86637b4..5349603 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Grant.java +++ b/src/main/java/net/frozenorb/apiv3/model/Grant.java @@ -9,8 +9,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -42,21 +40,9 @@ public final class Grant { grantsCollection.find().sort(new Document("addedAt", -1)).into(new LinkedList<>(), callback); } - public static List findByRankSync(Collection ranks) { + public static void findByRank(Collection ranks, SingleResultCallback> callback) { Collection convertedRanks = ranks.stream().map(Rank::getId).collect(Collectors.toList()); - return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", convertedRanks)))); - } - - public static Grant findByIdSync(String id) { - return SyncUtils.blockOne(grantsCollection.find(new Document("_id", id))); - } - - public static List findByUserSync(User user) { - return findByUserSync(user.getId()); - } - - public static List findByUserSync(UUID user) { - return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user))); + grantsCollection.find(new Document("rank", new Document("$in", convertedRanks))).into(new LinkedList<>(), callback); } public static void findPaginated(Document query, int skip, int pageSize, SingleResultCallback> callback) { @@ -128,20 +114,16 @@ public final class Grant { return scopes.isEmpty(); } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { grantsCollection.insertOne(this, callback); - callback.get(); } - public void delete(User removedBy, String reason) { + public void delete(User removedBy, String reason, SingleResultCallback callback) { this.removedBy = removedBy.getId(); this.removedAt = Instant.now(); this.removalReason = reason; - BlockingCallback callback = new BlockingCallback<>(); grantsCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/IpBan.java b/src/main/java/net/frozenorb/apiv3/model/IpBan.java index f9ebde6..0f39cdc 100644 --- a/src/main/java/net/frozenorb/apiv3/model/IpBan.java +++ b/src/main/java/net/frozenorb/apiv3/model/IpBan.java @@ -10,8 +10,6 @@ import lombok.Getter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import net.frozenorb.apiv3.util.TimeUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -39,10 +37,6 @@ public final class IpBan { @Getter private Instant removedAt; @Getter private String removalReason; - public static IpBan findByIdSync(String id) { - return SyncUtils.blockOne(ipBansCollection.find(new Document("_id", id))); - } - public static void findPaginated(Document query, int skip, int pageSize, SingleResultCallback> callback) { ipBansCollection.find(query).sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new LinkedList<>(), callback); } @@ -111,7 +105,6 @@ public final class IpBan { return removedBy != null; } - // TODO: CLEANUP public void getAccessDenialReason(SingleResultCallback callback) { Punishment.findByLinkedIpBanId(id, (punishment, error) -> { if (error != null) { @@ -123,53 +116,44 @@ public final class IpBan { User.findById(punishment.getUser(), (user, error2) -> { if (error2 != null) { callback.onResult(null, error2); - return; - } - - String accessDenialReason; - - if (user != null) { - accessDenialReason = "Your IP address has been suspended from the MineHQ Network for a punishment related to " + user.getLastUsername() + ". \n\n"; } else { - accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n"; + callback.onResult(buildDenialReason(user), null); } - - if (getExpiresAt() != null) { - accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now())); - } else { - accessDenialReason += "Appeal at MineHQ.com/appeal"; - } - - callback.onResult(accessDenialReason, null); }); } else { - String accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n"; - - if (getExpiresAt() != null) { - accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now())); - } else { - accessDenialReason += "Appeal at MineHQ.com/appeal"; - } - - callback.onResult(accessDenialReason, null); + callback.onResult(buildDenialReason(null), null); } }); } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); - ipBansCollection.insertOne(this, callback); - callback.get(); + private String buildDenialReason(User linkedIpBanUser) { + String accessDenialReason; + + if (linkedIpBanUser != null) { + accessDenialReason = "Your IP address has been suspended from the MineHQ Network for a punishment related to " + linkedIpBanUser.getLastUsername() + ". \n\n"; + } else { + accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n"; + } + + if (getExpiresAt() != null) { + accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now())); + } else { + accessDenialReason += "Appeal at MineHQ.com/appeal"; + } + + return accessDenialReason; } - public void delete(User removedBy, String reason) { + public void insert(SingleResultCallback callback) { + ipBansCollection.insertOne(this, callback); + } + + public void delete(User removedBy, String reason, SingleResultCallback callback) { this.removedBy = removedBy.getId(); this.removedAt = Instant.now(); this.removalReason = reason; - BlockingCallback callback = new BlockingCallback<>(); ipBansCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/IpIntel.java b/src/main/java/net/frozenorb/apiv3/model/IpIntel.java index fe6c624..e7b39aa 100644 --- a/src/main/java/net/frozenorb/apiv3/model/IpIntel.java +++ b/src/main/java/net/frozenorb/apiv3/model/IpIntel.java @@ -46,7 +46,7 @@ public final class IpIntel { } else { IpIntel newIpIntel = new IpIntel(id, maxMindResult); - newIpIntel.insert((ignored, error3) -> { + ipIntelCollection.insertOne(newIpIntel, (ignored, error3) -> { if (error3 != null) { callback.onResult(null, error3); } else { @@ -61,14 +61,10 @@ public final class IpIntel { public IpIntel() {} // For Jackson - public IpIntel(String ip, MaxMindResult result) { + private IpIntel(String ip, MaxMindResult result) { this.id = ip; this.lastUpdatedAt = Instant.now(); this.result = result; } - public void insert(SingleResultCallback callback) { - ipIntelCollection.insertOne(this, callback); - } - } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/IpLogEntry.java b/src/main/java/net/frozenorb/apiv3/model/IpLogEntry.java index b26e5c8..ea25f3f 100644 --- a/src/main/java/net/frozenorb/apiv3/model/IpLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/model/IpLogEntry.java @@ -8,8 +8,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -31,30 +29,6 @@ public final class IpLogEntry { @Getter private Instant lastSeenAt; @Getter private int uses; - public static List findAllSync() { - return SyncUtils.blockMulti(ipLogCollection.find().sort(new Document("lastSeenAt", -1))); - } - - public static IpLogEntry findByIdSync(String id) { - return SyncUtils.blockOne(ipLogCollection.find(new Document("_id", id))); - } - - public static List findByUserSync(User user) { - return findByUserSync(user.getId()); - } - - public static List findByUserSync(UUID user) { - return SyncUtils.blockMulti(ipLogCollection.find(new Document("user", user)).sort(new Document("lastSeenAt", -1))); - } - - public static IpLogEntry findByUserAndIpSync(User user, String userIp) { - return findByUserAndIpSync(user.getId(), userIp); - } - - public static IpLogEntry findByUserAndIpSync(UUID user, String userIp) { - return SyncUtils.blockOne(ipLogCollection.find(new Document("user", user).append("userIp", userIp))); - } - public static void findAll(SingleResultCallback> callback) { ipLogCollection.find().sort(new Document("lastSeenAt", -1)).into(new LinkedList<>(), callback); } @@ -95,16 +69,12 @@ public final class IpLogEntry { this.uses++; } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { ipLogCollection.insertOne(this, callback); - callback.get(); } - public void save() { - BlockingCallback callback = new BlockingCallback<>(); + public void save(SingleResultCallback callback) { ipLogCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java index 91b29db..8116929 100644 --- a/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java @@ -8,8 +8,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import java.util.LinkedList; @@ -25,10 +23,6 @@ public final class NotificationTemplate { @Getter @Setter private String subject; @Getter @Setter private String body; - public static NotificationTemplate findByIdSync(String id) { - return SyncUtils.blockOne(notificationTemplatesCollection.find(new Document("_id", id))); - } - public static void findAll(SingleResultCallback> callback) { notificationTemplatesCollection.find().into(new LinkedList<>(), callback); } @@ -64,16 +58,12 @@ public final class NotificationTemplate { return working; } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { notificationTemplatesCollection.insertOne(this, callback); - callback.get(); } - public void delete() { - BlockingCallback callback = new BlockingCallback<>(); + public void delete(SingleResultCallback callback) { notificationTemplatesCollection.deleteOne(new Document("_id", id), callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/Punishment.java b/src/main/java/net/frozenorb/apiv3/model/Punishment.java index 9a5a41c..95f6511 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Punishment.java +++ b/src/main/java/net/frozenorb/apiv3/model/Punishment.java @@ -10,8 +10,6 @@ import lombok.Getter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import net.frozenorb.apiv3.util.TimeUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -48,27 +46,6 @@ public final class Punishment { punishmentsCollection.find(new Document("type", new Document("$in", convertedTypes))).into(new LinkedList<>(), callback); } - public static Punishment findByIdSync(String id) { - return SyncUtils.blockOne(punishmentsCollection.find(new Document("_id", id))); - } - - public static List findByUserSync(User user) { - return findByUserSync(user.getId()); - } - - public static List findByUserSync(UUID user) { - return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user))); - } - - public static List findByUserAndTypeSync(User user, Collection types) { - return findByUserAndTypeSync(user.getId(), types); - } - - public static List findByUserAndTypeSync(UUID user, Collection types) { - Collection convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList()); - return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", convertedTypes)))); - } - public static void findPaginated(Document query, int skip, int pageSize, SingleResultCallback> callback) { punishmentsCollection.find(query).sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new LinkedList<>(), callback); } @@ -168,28 +145,38 @@ public final class Punishment { this.linkedIpBanId = ipBan.getId(); } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { punishmentsCollection.insertOne(this, callback); - callback.get(); } - public void delete(User removedBy, String reason) { + public void delete(User removedBy, String reason, SingleResultCallback callback) { this.removedBy = removedBy.getId(); this.removedAt = Instant.now(); this.removalReason = reason; - if (linkedIpBanId != null) { - IpBan ipBan = IpBan.findByIdSync(linkedIpBanId); - - if (ipBan != null && ipBan.isActive()) { - ipBan.delete(removedBy, "Linked punishment removed: " + reason); - } + if (linkedIpBanId == null) { + punishmentsCollection.replaceOne(new Document("_id", id), this, callback); + return; } - BlockingCallback callback = new BlockingCallback<>(); - punishmentsCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); + IpBan.findById(linkedIpBanId, (ipBan, error) -> { + if (error != null) { + callback.onResult(null, error); + return; + } + + if (ipBan != null && ipBan.isActive()) { + ipBan.delete(removedBy, "Linked punishment removed: " + reason, (ignored, error2) -> { + if (error2 != null) { + callback.onResult(null, error2); + } else { + punishmentsCollection.replaceOne(new Document("_id", id), this, callback); + } + }); + } else { + punishmentsCollection.replaceOne(new Document("_id", id), this, callback); + } + }); } public enum PunishmentType { diff --git a/src/main/java/net/frozenorb/apiv3/model/Rank.java b/src/main/java/net/frozenorb/apiv3/model/Rank.java index 3509a19..efecedd 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Rank.java +++ b/src/main/java/net/frozenorb/apiv3/model/Rank.java @@ -1,15 +1,14 @@ package net.frozenorb.apiv3.model; import com.google.common.collect.ImmutableList; -import com.google.common.primitives.Ints; +import com.google.common.collect.ImmutableMap; +import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; import fr.javatic.mongo.jacksonCodec.Entity; import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.Getter; import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import java.util.HashMap; @@ -23,9 +22,8 @@ public final class Rank { private static final MongoCollection ranksCollection = APIv3.getDatabase().getCollection("ranks", Rank.class); - private static Map rankCache = null; - private static List rankAltCache = null; - private static long rankCacheUpdated = 0; + private static Map rankIdCache = null; + private static List rankCache = null; @Getter @Id private String id; @Getter private int weight; @@ -35,13 +33,37 @@ public final class Rank { @Getter private boolean staffRank; public static List findAll() { - updateCacheIfNeeded(); - return ImmutableList.copyOf(rankAltCache); + return rankCache; } public static Rank findById(String id) { - updateCacheIfNeeded(); - return rankCache.get(id); + return rankIdCache.get(id); + } + + static { + updateCache(); + + APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> { + updateCache(); + }); + } + + private static void updateCache() { + ranksCollection.find().into(new LinkedList<>(), (ranks, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Map working = new HashMap<>(); + + for (Rank rank : ranks) { + working.put(rank.getId(), rank); + } + + rankIdCache = ImmutableMap.copyOf(working); + rankCache = ImmutableList.copyOf(ranks); + }); } public Rank() {} // For Jackson @@ -55,34 +77,12 @@ public final class Rank { this.staffRank = staffRank; } - private static void updateCacheIfNeeded() { - if (rankCache == null || (System.currentTimeMillis() - rankCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) { - Map working = new HashMap<>(); - List workingAlt = new LinkedList<>(); - List allRanks = SyncUtils.blockMulti(ranksCollection.find()); - allRanks.sort((a, b) -> Ints.compare(a.getWeight(), b.getWeight())); - - for (Rank rank : allRanks) { - working.put(rank.getId(), rank); - workingAlt.add(rank); - } - - rankCache = working; - rankAltCache = workingAlt; - rankCacheUpdated = System.currentTimeMillis(); - } - } - - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { ranksCollection.insertOne(this, callback); - callback.get(); } - public void delete() { - BlockingCallback callback = new BlockingCallback<>(); + public void delete(SingleResultCallback callback) { ranksCollection.deleteOne(new Document("_id", id), callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/Server.java b/src/main/java/net/frozenorb/apiv3/model/Server.java index 73c0fc7..53a30d4 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Server.java +++ b/src/main/java/net/frozenorb/apiv3/model/Server.java @@ -1,6 +1,9 @@ package net.frozenorb.apiv3.model; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.UpdateResult; @@ -9,8 +12,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.Getter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import java.time.Instant; @@ -22,9 +23,8 @@ public final class Server { private static final MongoCollection serversCollection = APIv3.getDatabase().getCollection("servers", Server.class); - private static Map serverCache = null; - private static List serverCacheAlt = null; - private static long serverCacheUpdated = 0; + private static Map serverIdCache = null; + private static List serverCache = null; @Getter @Id private String id; @Getter private String displayName; @@ -36,13 +36,37 @@ public final class Server { @Getter @ExcludeFromReplies private Set players; public static List findAll() { - updateCacheIfNeeded(); - return serverCacheAlt; + return serverCache; } public static Server findById(String id) { - updateCacheIfNeeded(); - return serverCache.get(id); + return serverIdCache.get(id); + } + + static { + updateCache(); + + APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> { + updateCache(); + }); + } + + private static void updateCache() { + serversCollection.find().into(new LinkedList<>(), (servers, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Map working = new HashMap<>(); + + for (Server server : servers) { + working.put(server.getId(), server); + } + + serverIdCache = ImmutableMap.copyOf(working); + serverCache = ImmutableList.copyOf(servers); + }); } public Server() {} // For Jackson @@ -58,44 +82,22 @@ public final class Server { this.players = new HashSet<>(); } - private static void updateCacheIfNeeded() { - if (serverCache == null || (System.currentTimeMillis() - serverCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) { - Map working = new HashMap<>(); - List workingAlt = new LinkedList<>(); - - for (Server server : SyncUtils.blockMulti(serversCollection.find())) { - working.put(server.getId(), server); - workingAlt.add(server); - } - - serverCache = working; - serverCacheAlt = workingAlt; - serverCacheUpdated = System.currentTimeMillis(); - } - } - public void receivedHeartbeat(double tps, Iterable players) { this.lastUpdatedAt = Instant.now(); this.lastTps = tps; this.players = ImmutableSet.copyOf(players); } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { serversCollection.insertOne(this, callback); - callback.get(); } - public void save() { - BlockingCallback callback = new BlockingCallback<>(); + public void save(SingleResultCallback callback) { serversCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); } - public void delete() { - BlockingCallback callback = new BlockingCallback<>(); + public void delete(SingleResultCallback callback) { serversCollection.deleteOne(new Document("_id", id), callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java b/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java index cb12eab..54a80b3 100644 --- a/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java +++ b/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.model; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; @@ -10,9 +12,7 @@ import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies; -import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.PermissionUtils; -import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import java.util.*; @@ -23,24 +23,46 @@ public final class ServerGroup { private static final MongoCollection serverGroupsCollection = APIv3.getDatabase().getCollection("serverGroups", ServerGroup.class); - private static Map serverGroupCache = null; - private static List serverGroupAltCache = null; - private static long serverGroupCacheUpdated = 0; + private static Map serverGroupIdCache = null; + private static List serverGroupCache = null; @Getter @Id private String id; @Getter private String image; @Getter @Setter private Set announcements; @Getter @Setter @ExcludeFromReplies private Map> permissions; - // make this and other stuff async public static List findAll() { - updateCacheIfNeeded(); - return serverGroupAltCache; + return serverGroupCache; } public static ServerGroup findById(String id) { - updateCacheIfNeeded(); - return serverGroupCache.get(id); + return serverGroupIdCache.get(id); + } + + static { + updateCache(); + + APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> { + updateCache(); + }); + } + + private static void updateCache() { + serverGroupsCollection.find().into(new LinkedList<>(), (serverGroups, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Map working = new HashMap<>(); + + for (ServerGroup serverGroup : serverGroups) { + working.put(serverGroup.getId(), serverGroup); + } + + serverGroupIdCache = ImmutableMap.copyOf(working); + serverGroupCache = ImmutableList.copyOf(serverGroups); + }); } public ServerGroup() {} // For Jackson @@ -54,36 +76,16 @@ public final class ServerGroup { return PermissionUtils.mergeUpTo(permissions, userRank); } - private static void updateCacheIfNeeded() { - if (serverGroupCache == null || (System.currentTimeMillis() - serverGroupCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) { - Map working = new HashMap<>(); - List workingAlt = new LinkedList<>(); - - for (ServerGroup serverGroup : SyncUtils.blockMulti(serverGroupsCollection.find())) { - working.put(serverGroup.getId(), serverGroup); - workingAlt.add(serverGroup); - } - - serverGroupCache = working; - serverGroupAltCache = workingAlt; - serverGroupCacheUpdated = System.currentTimeMillis(); - } - } - - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { serverGroupsCollection.insertOne(this, callback); - callback.get(); } public void save(SingleResultCallback callback) { serverGroupsCollection.replaceOne(new Document("_id", id), this, callback); } - public void delete() { - BlockingCallback callback = new BlockingCallback<>(); + public void delete(SingleResultCallback callback) { serverGroupsCollection.deleteOne(new Document("_id", id), callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/User.java b/src/main/java/net/frozenorb/apiv3/model/User.java index 541b121..969ea75 100644 --- a/src/main/java/net/frozenorb/apiv3/model/User.java +++ b/src/main/java/net/frozenorb/apiv3/model/User.java @@ -23,8 +23,9 @@ import net.frozenorb.apiv3.maxmind.MaxMindUserType; import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies; import net.frozenorb.apiv3.serialization.jackson.UuidJsonDeserializer; import net.frozenorb.apiv3.serialization.jackson.UuidJsonSerializer; -import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback; import net.frozenorb.apiv3.unsorted.Permissions; +import net.frozenorb.apiv3.unsorted.RequiresTotpResult; import net.frozenorb.apiv3.util.*; import org.bson.Document; @@ -53,44 +54,12 @@ public final class User { @Getter private Instant firstSeenAt; @Getter private boolean online; - public static User findByIdSync(String id) { - UUID uuid; - - try { - uuid = UUID.fromString(id); - } catch (NullPointerException | IllegalArgumentException ex) { - return null; - } - - return findByIdSync(uuid); - } - - public static User findByIdSync(UUID id) { - if (UuidUtils.isAcceptableUuid(id)) { - return SyncUtils.blockOne(usersCollection.find(new Document("_id", id))); - } else { - return null; - } - } - - public static User findByEmailSync(String email) { - return SyncUtils.blockOne(usersCollection.find(new Document("email", email))); - } - - public static User findByEmailTokenSync(String emailToken) { - return SyncUtils.blockOne(usersCollection.find(new Document("emailToken", emailToken))); - } - - public static User findByLastUsernameSync(String lastUsername) { - return SyncUtils.blockOne(usersCollection.find(new Document("lastUsername", lastUsername))); - } - public static void findById(String id, SingleResultCallback callback) { try { UUID uuid = UUID.fromString(id); findById(uuid, callback); - } catch (IllegalArgumentException ex) { // from UUID parsing - callback.onResult(null, ex); + } catch (IllegalArgumentException ignored) { // from UUID parsing + callback.onResult(null, null); // We don't pass in the exception, we just pretend we couldn't find them. } } @@ -102,6 +71,18 @@ public final class User { } } + public static void findByEmail(String email, SingleResultCallback callback) { + usersCollection.find(new Document("email", email)).first(callback); + } + + public static void findByEmailToken(String emailToken, SingleResultCallback callback) { + usersCollection.find(new Document("emailToken", emailToken)).first(callback); + } + + public static void findByLastUsername(String lastUsername, SingleResultCallback callback) { + usersCollection.find(new Document("lastUsername", lastUsername)).first(callback); + } + public static void findByIdGrouped(Iterable search, SingleResultCallback> callback) { usersCollection.find(new Document("_id", new Document("$in", search))).into(new LinkedList<>(), (users, error) -> { if (error != null) { @@ -122,62 +103,211 @@ public final class User { }); } - public static void findByEmailTokenSync(String emailToken, SingleResultCallback callback) { - usersCollection.find(new Document("emailToken", emailToken)).first(callback); - } - - public static void findByLastUsername(String lastUsername, SingleResultCallback callback) { - usersCollection.find(new Document("lastUsername", lastUsername)).first(callback); - } - public User() {} // For Jackson - // TODO: THIS IS CURRENTLY BLOCKING. MAYBE FOR THE HEARTBEAT WE CAN DO SOMETHING - // TO MAKE IT NOT SO BLOCKING public User(UUID id, String lastUsername) { this.id = id; - this.lastUsername = ""; // Intentional, so updateUsername actually does something. + this.lastUsername = lastUsername; this.aliases = new HashMap<>(); this.lastSeenAt = Instant.now(); this.firstSeenAt = Instant.now(); - updateUsername(lastUsername); + this.aliases.put(lastUsername, Instant.now()); } - public boolean hasPermissionAnywhere(String permission) { - Map globalPermissions = getGlobalPermissions(); - return globalPermissions.containsKey(permission) && globalPermissions.get(permission); + public void updateUsername(String newUsername) { + this.aliases.put(newUsername, Instant.now()); + this.lastUsername = newUsername; } - // TODO: ASYNC - public Map getGlobalPermissions() { - Map globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankAnywhere()); + public void checkNameCollisions(SingleResultCallback callback) { + User.findByLastUsername(lastUsername, (collision, error) -> { + if (error != null) { + callback.onResult(null, error); + return; + } - for (Map.Entry serverGroupEntry : getHighestRanks().entrySet()) { - ServerGroup serverGroup = serverGroupEntry.getKey(); - Rank rank = serverGroupEntry.getValue(); + if (collision == null) { + callback.onResult(null, null); + return; + } - globalPermissions = PermissionUtils.mergePermissions( - globalPermissions, - serverGroup.calculatePermissions(rank) - ); + MojangUtils.getName(collision.getId(), (collisionNewUsername, error2) -> { + if (error2 != null) { + callback.onResult(null, error2); + return; + } + + collision.updateUsername(collisionNewUsername); + collision.checkNameCollisions((ignored, error3) -> { + if (error3 != null) { + callback.onResult(null, error3); + return; + } + + collision.save((ignored2, error4) -> { + if (error4 != null) { + callback.onResult(null, error4); + } else { + callback.onResult(null, null); + } + }); + }); + }); + }); + } + + public void getLoginInfo(Server server, String userIp, SingleResultCallback> callback) { + Future> punishmentsFuture = Future.future(); + Future ipIntelFuture = Future.future(); + Future> ipBansFuture = Future.future(); + Future> grantsFuture = Future.future(); + + Punishment.findByUserAndType(this, ImmutableSet.of( + Punishment.PunishmentType.BLACKLIST, + Punishment.PunishmentType.BAN, + Punishment.PunishmentType.MUTE + ), new FutureCompatibilityCallback<>(punishmentsFuture)); + + if (userIp != null) { + IpIntel.findByIdOrInsert(userIp, new FutureCompatibilityCallback<>(ipIntelFuture)); + IpBan.findByIp(userIp, new FutureCompatibilityCallback<>(ipBansFuture)); + } else { + ipIntelFuture.complete(null); + ipBansFuture.complete(ImmutableList.of()); } - return ImmutableMap.copyOf(globalPermissions); + Grant.findByUser(this, new FutureCompatibilityCallback<>(grantsFuture)); + + CompositeFuture.all(punishmentsFuture, ipIntelFuture, ipBansFuture, grantsFuture).setHandler((result) -> { + if (result.succeeded()) { + Iterable punishments = result.result().result(0); + IpIntel ipIntel = result.result().result(1); + Iterable ipBans = result.result().result(2); + Iterable grants = result.result().result(3); + + getLoginInfo(server, ipIntel, punishments, ipBans, grants, (loginInfo, error) -> { + if (error != null) { + callback.onResult(null, error); + } else { + callback.onResult(loginInfo, null); + } + }); + } else { + callback.onResult(null, result.cause()); + } + }); + } + + // This is only used to help batch requests to mongo + public void getLoginInfo(Server server, IpIntel ipIntel, Iterable punishments, Iterable ipBans, Iterable grants, SingleResultCallback> callback) { + getAccessInfo(ipIntel, punishments, ipBans, (accessInfo, error) -> { + ServerGroup serverGroup = ServerGroup.findById(server.getServerGroup()); + Punishment activeMute = null; + + for (Punishment punishment : punishments) { + if (punishment.isActive() && punishment.getType() == Punishment.PunishmentType.MUTE) { + activeMute = punishment; + break; + } + } + + Map result = new HashMap<>(); + + result.put("user", this); + result.put("access", accessInfo); + result.put("rank", getHighestRankScoped(serverGroup, grants).getId()); + result.put("totpSetup", getTotpSecret() != null); + + if (activeMute != null) { + result.put("mute", activeMute); + } + + callback.onResult(result, null); + }); + } + + private void getAccessInfo(IpIntel ipIntel, Iterable punishments, Iterable ipBans, SingleResultCallback> callback) { + Punishment activeBan = null; + IpBan activeIpBan = null; + + for (Punishment punishment : punishments) { + if (punishment.isActive() && (punishment.getType() == Punishment.PunishmentType.BAN || punishment.getType() == Punishment.PunishmentType.BLACKLIST)) { + activeBan = punishment; + break; + } + } + + for (IpBan ipBan : ipBans) { + if (ipBan.isActive()) { + activeIpBan = ipBan; + break; + } + } + + Map accessAllowed = ImmutableMap.of( + "allowed", true, + "message", "" + ); + + if (activeBan != null) { + callback.onResult(ImmutableMap.of( + "allowed", false, + "message", activeBan.getAccessDenialReason() + ), null); + } else if (activeIpBan != null) { + activeIpBan.getAccessDenialReason((denialReason, error) -> { + if (error != null) { + callback.onResult(null, error); + } else { + callback.onResult(ImmutableMap.of( + "allowed", false, + "message", denialReason + ), null); + } + }); + } else if (ipIntel != null) { + MaxMindResult maxMindResult = ipIntel.getResult(); + MaxMindUserType userType = maxMindResult.getTraits().getUserType(); + Map proposedAccess = null; + + if (!userType.isAllowed()) { + proposedAccess = ImmutableMap.of( + "allowed", false, + "message", "You cannot join MineHQ from a VPN." + ); + } else if (ImmutableList.of().contains(maxMindResult.getTraits().getAsn())) { + proposedAccess = ImmutableMap.of( + "allowed", false, + "message", "You cannot join MineHQ from this ISP." + ); + } + + Map finalProposedAccess = proposedAccess; + + if (proposedAccess != null) { + hasPermissionAnywhere(Permissions.BYPASS_VPN_CHECK, (bypass, error) -> { + if (error != null) { + callback.onResult(null, error); + } else { + callback.onResult(bypass ? accessAllowed : finalProposedAccess, null); + } + }); + } else { + callback.onResult(accessAllowed, null); + } + } else { + callback.onResult(accessAllowed, null); + } } - // TODO: Clean public boolean seenOnServer(Server server) { - if (online && server.getId().equals(this.lastSeenOn)) { + if (online && server.getId().equals(lastSeenOn)) { return false; } this.lastSeenOn = server.getId(); - - if (!online) { - this.lastSeenAt = Instant.now(); - } - + this.lastSeenAt = Instant.now(); this.online = true; return true; } @@ -187,23 +317,6 @@ public final class User { this.online = false; } - public void updateUsername(String newUsername) { - if (!newUsername.equals(lastUsername)) { - this.lastUsername = newUsername; - - User withNewUsername; - - while ((withNewUsername = User.findByLastUsernameSync(newUsername)) != null) { - BlockingCallback callback = new BlockingCallback<>(); - MojangUtils.getName(withNewUsername.getId(), callback); - withNewUsername.updateUsername(callback.get()); - withNewUsername.save(); - } - } - - this.aliases.put(newUsername, Instant.now()); - } - public void setPassword(String input) { this.password = Hashing .sha256() @@ -242,15 +355,6 @@ public final class User { }); } - // TODO: CLEAN - public enum RequiresTotpResult { - - NOT_REQUIRED_NOT_SET, - NOT_REQUIRED_IP_PRE_AUTHORIZED, - REQUIRED_NO_EXEMPTIONS - - } - public void completeRegistration(String email) { this.email = email; this.registeredAt = Instant.now(); @@ -265,12 +369,50 @@ public final class User { this.pendingEmailTokenSetAt = Instant.now(); } - public Rank getHighestRankAnywhere() { - return getHighestRankScoped(null, Grant.findByUserSync(this)); + public void hasPermissionAnywhere(String permission, SingleResultCallback callback) { + getGlobalPermissions((permissions, error) -> { + if (error != null) { + callback.onResult(null, error); + } else { + boolean hasPermission = permissions.containsKey(permission) && permissions.get(permission); + callback.onResult(hasPermission, null); + } + }); } - // This is only used to help batch requests to mongo - public Rank getHighestRankScoped(ServerGroup serverGroup, Iterable grants) { + public void getGlobalPermissions(SingleResultCallback> callback) { + Grant.findByUser(this, (grants, error) -> { + if (error != null) { + callback.onResult(null, error); + } else { + Map globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankScoped(null, grants)); + + for (Map.Entry serverGroupEntry : getHighestRanks(grants).entrySet()) { + ServerGroup serverGroup = serverGroupEntry.getKey(); + Rank rank = serverGroupEntry.getValue(); + + globalPermissions = PermissionUtils.mergePermissions( + globalPermissions, + serverGroup.calculatePermissions(rank) + ); + } + + callback.onResult(ImmutableMap.copyOf(globalPermissions), null); + } + }); + } + + private Map getHighestRanks(List grants) { + Map highestRanks = new HashMap<>(); + + for (ServerGroup serverGroup : ServerGroup.findAll()) { + highestRanks.put(serverGroup, getHighestRankScoped(serverGroup, grants)); + } + + return highestRanks; + } + + private Rank getHighestRankScoped(ServerGroup serverGroup, Iterable grants) { Rank highest = null; for (Grant grant : grants) { @@ -292,187 +434,8 @@ public final class User { } } - public Map getHighestRanks() { - Map highestRanks = new HashMap<>(); - Rank defaultRank = Rank.findById("default"); - List userGrants = Grant.findByUserSync(this); - - for (ServerGroup serverGroup : ServerGroup.findAll()) { - Rank highest = defaultRank; - - for (Grant grant : userGrants) { - if (!grant.isActive() || !grant.appliesOn(serverGroup)) { - continue; - } - - Rank rank = Rank.findById(grant.getRank()); - - if (highest == null || rank.getWeight() > highest.getWeight()) { - highest = rank; - } - } - - highestRanks.put(serverGroup, highest); - } - - return highestRanks; - } - - public void getLoginInfo(Server server, String userIp, SingleResultCallback> callback) { - Future> punishmentsFuture = Future.future(); - Future ipIntelFuture = Future.future(); - Future> ipBansFuture = Future.future(); - Future> grantsFuture = Future.future(); - - Punishment.findByUserAndType(this, ImmutableSet.of( - Punishment.PunishmentType.BLACKLIST, - Punishment.PunishmentType.BAN, - Punishment.PunishmentType.MUTE - ), (punishments, error) -> { - if (error != null) { - punishmentsFuture.fail(error); - } else { - punishmentsFuture.complete(punishments); - } - }); - - if (userIp != null) { - IpIntel.findByIdOrInsert(userIp, (ipIntel, error) -> { - if (error != null) { - ipIntelFuture.fail(error); - } else { - ipIntelFuture.complete(ipIntel); - } - }); - - IpBan.findByIp(userIp, (ipBans, error) -> { - if (error != null) { - ipBansFuture.fail(error); - } else { - ipBansFuture.complete(ipBans); - } - }); - } else { - ipIntelFuture.complete(null); - ipBansFuture.complete(ImmutableSet.of()); - } - - Grant.findByUser(this, (grants, error) -> { - if (error != null) { - grantsFuture.fail(error); - } else { - grantsFuture.complete(grants); - } - }); - - CompositeFuture.all(punishmentsFuture, ipIntelFuture, ipBansFuture, grantsFuture).setHandler((result) -> { - if (result.succeeded()) { - Iterable punishments = result.result().result(0); - IpIntel ipIntel = result.result().result(1); - Iterable ipBans = result.result().result(2); - Iterable grants = result.result().result(3); - - callback.onResult(createLoginInfo(server, ipIntel, punishments, ipBans, grants), null); - } else { - callback.onResult(null, result.cause()); - } - }); - } - - // This is only used to help batch requests to mongo - public Map createLoginInfo(Server server, IpIntel ipIntel, Iterable punishments, Iterable ipBans, Iterable grants) { - Punishment activeMute = null; - Punishment activeBan = null; - IpBan activeIpBan = null; - - for (Punishment punishment : punishments) { - if (!punishment.isActive()) { - continue; - } - - if (punishment.getType() == Punishment.PunishmentType.MUTE) { - activeMute = punishment; - } else if (punishment.getType() == Punishment.PunishmentType.BAN || punishment.getType() == Punishment.PunishmentType.BLACKLIST) { - activeBan = punishment; - } - } - - for (IpBan ipBan : ipBans) { - if (ipBan.isActive()) { - activeIpBan = ipBan; - break; - } - } - - Rank highestRank = getHighestRankScoped(ServerGroup.findById(server.getServerGroup()), grants); - Map access = ImmutableMap.of( - "allowed", true, - "message", "" - ); - - if (activeBan != null) { - access = ImmutableMap.of( - "allowed", false, - "message", activeBan.getAccessDenialReason(), - "activeBanId", activeBan.getId() - ); - } else if (activeIpBan != null) { - // TODO: ASYNC - BlockingCallback callback = new BlockingCallback<>(); - activeIpBan.getAccessDenialReason(callback); - String reason = callback.get(); - - access = ImmutableMap.of( - "allowed", false, - "message", reason, - "activeIpBanId", activeIpBan.getId() - ); - } else if (ipIntel != null) { - MaxMindResult maxMindResult = ipIntel.getResult(); - MaxMindUserType userType = maxMindResult.getTraits().getUserType(); - Map proposedAccess = null; - - if (!userType.isAllowed()) { - proposedAccess = ImmutableMap.of( - "allowed", false, - "message", "You cannot join MineHQ from a VPN.", - "userType", userType.name() - ); - } else if (ImmutableList.of().contains(maxMindResult.getTraits().getAsn())) { - // TODO: BANNED ASNS - } - - // We do this to avoid making an expensive .hasPermissionAnywhere call unless we need to. - // TODO: THIS IS BLOCKING :( - if (proposedAccess != null && !hasPermissionAnywhere(Permissions.BYPASS_VPN_CHECK)) { - access = proposedAccess; - } - } - - // Generics are weird, yes we have to do this. - ImmutableMap.Builder result = ImmutableMap.builder() - .put("user", this) - .put("access", access) - .put("rank", highestRank.getId()) - .put("totpSetup", getTotpSecret() != null); - - if (activeMute != null) { - result.put("mute", activeMute); - } - - return result.build(); - } - - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { usersCollection.insertOne(this, callback); - callback.get(); - } - - public void save() { - BlockingCallback callback = new BlockingCallback<>(); - save(callback); - callback.get(); } public void save(SingleResultCallback callback) { diff --git a/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java b/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java index 4772ec7..d5dcc57 100644 --- a/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java +++ b/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java @@ -13,13 +13,14 @@ import net.frozenorb.apiv3.util.IpUtils; public final class POSTAuditLog implements Handler { public void handle(RoutingContext ctx) { - User.findById(ctx.request().getParam("id"), (user, error) -> { + JsonObject requestBody = ctx.getBodyAsJson(); + + User.findById(requestBody.getString("user"), (user, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); } else if (user == null) { - ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user")); } else { - JsonObject requestBody = ctx.getBodyAsJson(); String userIp = requestBody.getString("userIp"); if (!IpUtils.isValidIp(userIp)) { diff --git a/src/main/java/net/frozenorb/apiv3/route/emailToken/GETEmailTokensOwner.java b/src/main/java/net/frozenorb/apiv3/route/emailToken/GETEmailTokensOwner.java index dcaad7b..e234e53 100644 --- a/src/main/java/net/frozenorb/apiv3/route/emailToken/GETEmailTokensOwner.java +++ b/src/main/java/net/frozenorb/apiv3/route/emailToken/GETEmailTokensOwner.java @@ -9,7 +9,7 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class GETEmailTokensOwner implements Handler { public void handle(RoutingContext ctx) { - User.findByEmailTokenSync(ctx.request().getParam("id"), (user, error) -> { + User.findByEmailToken(ctx.request().getParam("id"), (user, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); } else { diff --git a/src/main/java/net/frozenorb/apiv3/route/emailToken/POSTEmailTokensConfirm.java b/src/main/java/net/frozenorb/apiv3/route/emailToken/POSTEmailTokensConfirm.java index c479321..f46020a 100644 --- a/src/main/java/net/frozenorb/apiv3/route/emailToken/POSTEmailTokensConfirm.java +++ b/src/main/java/net/frozenorb/apiv3/route/emailToken/POSTEmailTokensConfirm.java @@ -1,11 +1,13 @@ package net.frozenorb.apiv3.route.emailToken; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; import java.util.concurrent.TimeUnit; @@ -13,7 +15,9 @@ import java.util.concurrent.TimeUnit; public final class POSTEmailTokensConfirm implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByEmailTokenSync(ctx.request().getParam("emailToken")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findByEmailToken(ctx.request().getParam("emailToken"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "Email token", ctx.request().getParam("emailToken")); @@ -42,7 +46,9 @@ public final class POSTEmailTokensConfirm implements Handler { user.completeRegistration(user.getPendingEmail()); user.setPassword(password); - user.save(); + BlockingCallback callback = new BlockingCallback<>(); + user.save(callback); + callback.get(); APIv3.respondJson(ctx, ImmutableMap.of( "success", true diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java b/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java index 0c3398e..0c2c537 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java @@ -1,6 +1,7 @@ package net.frozenorb.apiv3.route.grants; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; @@ -16,7 +17,9 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETEGrantsId implements Handler { public void handle(RoutingContext ctx) { - Grant grant = Grant.findByIdSync(ctx.request().getParam("id")); + BlockingCallback grantCallback = new BlockingCallback<>(); + Grant.findById(ctx.request().getParam("id"), grantCallback); + Grant grant = grantCallback.get(); if (grant == null) { ErrorUtils.respondNotFound(ctx, "Grant", ctx.request().getParam("id")); @@ -27,7 +30,9 @@ public final class DELETEGrantsId implements Handler { } JsonObject requestBody = ctx.getBodyAsJson(); - User removedBy = User.findByIdSync(requestBody.getString("removedBy")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("removedBy"), userCallback); + User removedBy = userCallback.get(); if (removedBy == null) { ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy")); @@ -41,7 +46,9 @@ public final class DELETEGrantsId implements Handler { return; } - grant.delete(removedBy, reason); + BlockingCallback callback = new BlockingCallback<>(); + grant.delete(removedBy, reason, callback); + callback.get(); BlockingCallback blockingCallback = new BlockingCallback<>(); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of(), blockingCallback); blockingCallback.get(); diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java b/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java index 0c1e11b..5775eef 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java @@ -8,6 +8,7 @@ import net.frozenorb.apiv3.model.Grant; import net.frozenorb.apiv3.model.Rank; import net.frozenorb.apiv3.model.ServerGroup; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; import java.time.Instant; @@ -19,7 +20,9 @@ public final class POSTGrants implements Handler { public void handle(RoutingContext ctx) { JsonObject requestBody = ctx.getBodyAsJson(); - User target = User.findByIdSync(requestBody.getString("user")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("user"), userCallback); + User target = userCallback.get(); if (target == null) { ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user")); @@ -68,10 +71,14 @@ public final class POSTGrants implements Handler { } // We purposely don't do a null check, grants don't have to have a source. - User addedBy = User.findByIdSync(requestBody.getString("addedBy")); + BlockingCallback addedByCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("addedBt"), addedByCallback); + User addedBy = addedByCallback.get(); Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy); - grant.insert(); + BlockingCallback callback = new BlockingCallback<>(); + grant.insert(callback); + callback.get(); APIv3.respondJson(ctx, grant); } diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBan.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBan.java index 287a4b9..9a0026e 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBan.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBan.java @@ -1,6 +1,7 @@ package net.frozenorb.apiv3.route.ipBans; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; @@ -16,7 +17,9 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETEIpBan implements Handler { public void handle(RoutingContext ctx) { - IpBan ipBan = IpBan.findByIdSync(ctx.request().getParam("id")); + BlockingCallback ipBanCallback = new BlockingCallback<>(); + IpBan.findById(ctx.request().getParam("id"), ipBanCallback); + IpBan ipBan = ipBanCallback.get(); if (ipBan == null) { ErrorUtils.respondNotFound(ctx, "IpBan", ctx.request().getParam("id")); @@ -27,7 +30,9 @@ public final class DELETEIpBan implements Handler { } JsonObject requestBody = ctx.getBodyAsJson(); - User removedBy = User.findByIdSync(requestBody.getString("removedBy")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("removedBy"), userCallback); + User removedBy = userCallback.get(); if (removedBy == null) { ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy")); @@ -41,7 +46,9 @@ public final class DELETEIpBan implements Handler { return; } - ipBan.delete(removedBy, reason); + BlockingCallback callback = new BlockingCallback<>(); + ipBan.delete(removedBy, reason, callback); + callback.get(); BlockingCallback blockingCallback = new BlockingCallback<>(); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback); blockingCallback.get(); diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpBans.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpBans.java index 8233dd4..f38daac 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpBans.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpBans.java @@ -6,6 +6,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.IpBan; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.IpUtils; @@ -41,10 +42,14 @@ public final class POSTIpBans implements Handler { } // We purposely don't do a null check, ip bans don't have to have a source. - User addedBy = User.findByIdSync(requestBody.getString("addedBy")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("addedBy"), userCallback); + User addedBy = userCallback.get(); IpBan ipBan = new IpBan(userIp, reason, expiresAt, addedBy, ctx.get("actor")); - ipBan.insert(); + BlockingCallback callback = new BlockingCallback<>(); + ipBan.insert(callback); + callback.get(); APIv3.respondJson(ctx, ipBan); } diff --git a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/DELETENotificationTemplatesId.java b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/DELETENotificationTemplatesId.java index 48339b2..301a376 100644 --- a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/DELETENotificationTemplatesId.java +++ b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/DELETENotificationTemplatesId.java @@ -1,22 +1,28 @@ package net.frozenorb.apiv3.route.notificationTemplates; +import com.mongodb.client.result.DeleteResult; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.NotificationTemplate; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETENotificationTemplatesId implements Handler { public void handle(RoutingContext ctx) { - NotificationTemplate notificationTemplate = NotificationTemplate.findByIdSync(ctx.request().getParam("id")); + BlockingCallback notificationTemplateCallback = new BlockingCallback<>(); + NotificationTemplate.findById(ctx.request().getParam("id"), notificationTemplateCallback); + NotificationTemplate notificationTemplate = notificationTemplateCallback.get(); if (notificationTemplate == null) { ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("id")); return; } - notificationTemplate.delete(); + BlockingCallback callback = new BlockingCallback<>(); + notificationTemplate.delete(callback); + callback.get(); APIv3.respondJson(ctx, notificationTemplate); } diff --git a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/POSTNotificationTemplates.java b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/POSTNotificationTemplates.java index cb6c8a7..5cdfe89 100644 --- a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/POSTNotificationTemplates.java +++ b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/POSTNotificationTemplates.java @@ -5,6 +5,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.NotificationTemplate; +import net.frozenorb.apiv3.unsorted.BlockingCallback; public final class POSTNotificationTemplates implements Handler { @@ -15,7 +16,9 @@ public final class POSTNotificationTemplates implements Handler String body = requestBody.getString("body"); NotificationTemplate notificationTemplate = new NotificationTemplate(id, subject, body); - notificationTemplate.insert(); + BlockingCallback callback = new BlockingCallback<>(); + notificationTemplate.insert(callback); + callback.get(); APIv3.respondJson(ctx, notificationTemplate); } diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishments.java b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishments.java index 3aa36c5..a725012 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishments.java @@ -1,6 +1,7 @@ package net.frozenorb.apiv3.route.punishments; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; @@ -16,7 +17,9 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETEPunishments implements Handler { public void handle(RoutingContext ctx) { - Punishment punishment = Punishment.findByIdSync(ctx.request().getParam("id")); + BlockingCallback punishmentCallback = new BlockingCallback<>(); + Punishment.findById(ctx.request().getParam("id"), punishmentCallback); + Punishment punishment = punishmentCallback.get(); if (punishment == null) { ErrorUtils.respondNotFound(ctx, "Punishment", ctx.request().getParam("id")); @@ -27,7 +30,9 @@ public final class DELETEPunishments implements Handler { } JsonObject requestBody = ctx.getBodyAsJson(); - User removedBy = User.findByIdSync(requestBody.getString("removedBy")); + BlockingCallback removedByCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("removedBy"), removedByCallback); + User removedBy = removedByCallback.get(); if (removedBy == null) { ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy")); @@ -41,7 +46,9 @@ public final class DELETEPunishments implements Handler { return; } - punishment.delete(removedBy, reason); + BlockingCallback removeCallback = new BlockingCallback<>(); + punishment.delete(removedBy, reason, removeCallback); + removeCallback.get(); BlockingCallback blockingCallback = new BlockingCallback<>(); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback); blockingCallback.get(); diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUserActivePunishment.java b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUserActivePunishment.java index 0c81c4b..b061543 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUserActivePunishment.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUserActivePunishment.java @@ -2,6 +2,7 @@ package net.frozenorb.apiv3.route.punishments; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; @@ -14,10 +15,14 @@ import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; +import java.util.List; + public final class DELETEUserActivePunishment implements Handler { public void handle(RoutingContext ctx) { - User target = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User target = userCallback.get(); if (target == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); @@ -26,7 +31,10 @@ public final class DELETEUserActivePunishment implements Handler JsonObject requestBody = ctx.getBodyAsJson(); Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(requestBody.getString("type").toUpperCase()); - User removedBy = User.findByIdSync(requestBody.getString("removedBy")); + + BlockingCallback removedByCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("removedBy"), removedByCallback); + User removedBy = removedByCallback.get(); if (removedBy == null) { ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy")); @@ -40,9 +48,14 @@ public final class DELETEUserActivePunishment implements Handler return; } - for (Punishment punishment : Punishment.findByUserAndTypeSync(target, ImmutableSet.of(type))) { + BlockingCallback> callback = new BlockingCallback<>(); + Punishment.findByUserAndType(target, ImmutableSet.of(type), callback); + + for (Punishment punishment : callback.get()) { if (punishment.isActive()) { - punishment.delete(removedBy, reason); + BlockingCallback punishmentCallback = new BlockingCallback<>(); + punishment.delete(removedBy, reason, punishmentCallback); + punishmentCallback.get(); BlockingCallback blockingCallback = new BlockingCallback<>(); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback); blockingCallback.get(); diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java b/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java index 3fb8a25..dfd7f9a 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java @@ -9,17 +9,21 @@ import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.IpBan; import net.frozenorb.apiv3.model.Punishment; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.unsorted.Permissions; import net.frozenorb.apiv3.util.ErrorUtils; import java.time.Instant; +import java.util.List; import java.util.Map; public final class POSTPunishments implements Handler { public void handle(RoutingContext ctx) { JsonObject requestBody = ctx.getBodyAsJson(); - User target = User.findByIdSync(requestBody.getString("user")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("user"), userCallback); + User target = userCallback.get(); if (target == null) { ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user")); @@ -36,9 +40,14 @@ public final class POSTPunishments implements Handler { Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(requestBody.getString("type")); if (type != Punishment.PunishmentType.WARN) { - for (Punishment punishment : Punishment.findByUserAndTypeSync(target, ImmutableSet.of(type))) { + BlockingCallback> punishmentsCallback = new BlockingCallback<>(); + Punishment.findByUserAndType(target, ImmutableSet.of(type), punishmentsCallback); + + for (Punishment punishment : punishmentsCallback.get()) { if (punishment.isActive()) { - ErrorUtils.respondGeneric(ctx, 200, "A punishment by " + User.findByIdSync(punishment.getAddedBy()).getLastUsername() + " already covers this user."); + BlockingCallback addedByCallback = new BlockingCallback<>(); + User.findById(punishment.getAddedBy(), addedByCallback); + ErrorUtils.respondGeneric(ctx, 200, "A punishment by " + addedByCallback.get().getLastUsername() + " already covers this user."); return; } } @@ -63,9 +72,14 @@ public final class POSTPunishments implements Handler { } // We purposely don't do a null check, punishments don't have to have a source. - User addedBy = User.findByIdSync(requestBody.getString("addedBy")); + BlockingCallback addedByCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("addedBy"), addedByCallback); + User addedBy = addedByCallback.get(); - if (target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT)) { + BlockingCallback permissionsCallback = new BlockingCallback<>(); + target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT, permissionsCallback); + + if (permissionsCallback.get()) { ErrorUtils.respondGeneric(ctx, 200, target.getLastSeenOn() + " is protected from punishments."); return; } @@ -76,12 +90,16 @@ public final class POSTPunishments implements Handler { if ((type == Punishment.PunishmentType.BAN || type == Punishment.PunishmentType.BLACKLIST) && userIp != null) { IpBan ipBan = new IpBan(userIp, punishment); - ipBan.insert(); + BlockingCallback ipBanCallback = new BlockingCallback<>(); + ipBan.insert(ipBanCallback); + ipBanCallback.get(); punishment.linkIpBan(ipBan); } - punishment.insert(); + BlockingCallback callback = new BlockingCallback<>(); + punishment.insert(callback); + callback.get(); APIv3.respondJson(ctx, ImmutableMap.of( "punishment", punishment, diff --git a/src/main/java/net/frozenorb/apiv3/route/ranks/DELETERanksId.java b/src/main/java/net/frozenorb/apiv3/route/ranks/DELETERanksId.java index cebfdbe..f9b25ca 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ranks/DELETERanksId.java +++ b/src/main/java/net/frozenorb/apiv3/route/ranks/DELETERanksId.java @@ -1,9 +1,11 @@ package net.frozenorb.apiv3.route.ranks; +import com.mongodb.client.result.DeleteResult; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Rank; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETERanksId implements Handler { @@ -16,7 +18,9 @@ public final class DELETERanksId implements Handler { return; } - rank.delete(); + BlockingCallback callback = new BlockingCallback<>(); + rank.delete(callback); + callback.get(); APIv3.respondJson(ctx, rank); } diff --git a/src/main/java/net/frozenorb/apiv3/route/ranks/POSTRanks.java b/src/main/java/net/frozenorb/apiv3/route/ranks/POSTRanks.java index 5a2f297..c8b553e 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ranks/POSTRanks.java +++ b/src/main/java/net/frozenorb/apiv3/route/ranks/POSTRanks.java @@ -5,6 +5,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Rank; +import net.frozenorb.apiv3.unsorted.BlockingCallback; public final class POSTRanks implements Handler { @@ -18,7 +19,9 @@ public final class POSTRanks implements Handler { boolean staffRank = requestBody.getBoolean("staffRank"); Rank rank = new Rank(id, weight, displayName, gameColor, websiteColor, staffRank); - rank.insert(); + BlockingCallback callback = new BlockingCallback<>(); + rank.insert(callback); + callback.get(); APIv3.respondJson(ctx, rank); } diff --git a/src/main/java/net/frozenorb/apiv3/route/serverGroups/DELETEServerGroupsId.java b/src/main/java/net/frozenorb/apiv3/route/serverGroups/DELETEServerGroupsId.java index 13875c5..7e5614d 100644 --- a/src/main/java/net/frozenorb/apiv3/route/serverGroups/DELETEServerGroupsId.java +++ b/src/main/java/net/frozenorb/apiv3/route/serverGroups/DELETEServerGroupsId.java @@ -1,9 +1,11 @@ package net.frozenorb.apiv3.route.serverGroups; +import com.mongodb.client.result.DeleteResult; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.ServerGroup; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETEServerGroupsId implements Handler { @@ -16,7 +18,9 @@ public final class DELETEServerGroupsId implements Handler { return; } - serverGroup.delete(); + BlockingCallback callback = new BlockingCallback<>(); + serverGroup.delete(callback); + callback.get(); APIv3.respondJson(ctx, serverGroup); } diff --git a/src/main/java/net/frozenorb/apiv3/route/serverGroups/POSTServerGroups.java b/src/main/java/net/frozenorb/apiv3/route/serverGroups/POSTServerGroups.java index 3ec7fb8..59cde37 100644 --- a/src/main/java/net/frozenorb/apiv3/route/serverGroups/POSTServerGroups.java +++ b/src/main/java/net/frozenorb/apiv3/route/serverGroups/POSTServerGroups.java @@ -5,6 +5,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.ServerGroup; +import net.frozenorb.apiv3.unsorted.BlockingCallback; public final class POSTServerGroups implements Handler { @@ -14,7 +15,9 @@ public final class POSTServerGroups implements Handler { String image = requestBody.getString("image"); ServerGroup serverGroup = new ServerGroup(id, image); - serverGroup.insert(); + BlockingCallback callback = new BlockingCallback<>(); + serverGroup.insert(callback); + callback.get(); APIv3.respondJson(ctx, serverGroup); } diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java b/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java index 8d70ba9..df8b254 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java @@ -1,9 +1,11 @@ package net.frozenorb.apiv3.route.servers; +import com.mongodb.client.result.DeleteResult; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Server; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; public final class DELETEServersId implements Handler { @@ -16,7 +18,9 @@ public final class DELETEServersId implements Handler { return; } - server.delete(); + BlockingCallback callback = new BlockingCallback<>(); + server.delete(callback); + callback.get(); APIv3.respondJson(ctx, server); } diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java index 263b225..0702383 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java @@ -6,6 +6,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.ServerGroup; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.IpUtils; @@ -32,7 +33,9 @@ public final class POSTServers implements Handler { String generatedApiKey = UUID.randomUUID().toString(); Server server = new Server(id, displayName, generatedApiKey, group, ip); - server.insert(); + BlockingCallback callback = new BlockingCallback<>(); + server.insert(callback); + callback.get(); APIv3.respondJson(ctx, server); } 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 46e3618..aac63fd 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java @@ -2,6 +2,7 @@ package net.frozenorb.apiv3.route.servers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.CompositeFuture; import io.vertx.core.Future; import io.vertx.core.Handler; @@ -13,14 +14,13 @@ import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.model.*; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.PermissionUtils; import net.frozenorb.apiv3.util.UuidUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; @Slf4j public final class POSTServersHeartbeat implements Handler { @@ -58,14 +58,18 @@ public final class POSTServersHeartbeat implements Handler { }); } - // TODO: ASYNC (MAKE ALL SAVES/INSERTS/ETC USED HERE ASYNC private Future createInfoResponse(Server server, double tps, Map playerNames) { Future callback = Future.future(); server.receivedHeartbeat(tps, playerNames.keySet()); - server.save(); + server.save((ignored, error) -> { + if (error != null) { + callback.fail(error); + } else { + callback.complete(); + } + }); - callback.complete(); return callback; } @@ -76,29 +80,9 @@ public final class POSTServersHeartbeat implements Handler { Future>> grantLookupCallback = Future.future(); Future>> punishmentLookupCallback = Future.future(); - User.findByIdGrouped(playerNames.keySet(), (users, error) -> { - if (error != null) { - userLookupCallback.fail(error); - } else { - userLookupCallback.complete(users); - } - }); - - Grant.findByUserGrouped(playerNames.keySet(), (grants, error) -> { - if (error != null) { - grantLookupCallback.fail(error); - } else { - grantLookupCallback.complete(grants); - } - }); - - Punishment.findByUserGrouped(playerNames.keySet(), (punishments, error) -> { - if (error != null) { - punishmentLookupCallback.fail(error); - } else { - punishmentLookupCallback.complete(punishments); - } - }); + User.findByIdGrouped(playerNames.keySet(), new FutureCompatibilityCallback<>(userLookupCallback)); + Grant.findByUserGrouped(playerNames.keySet(), new FutureCompatibilityCallback<>(grantLookupCallback)); + Punishment.findByUserGrouped(playerNames.keySet(), new FutureCompatibilityCallback<>(punishmentLookupCallback)); CompositeFuture.all( userLookupCallback, @@ -107,38 +91,58 @@ public final class POSTServersHeartbeat implements Handler { ).setHandler((result) -> { if (result.failed()) { callback.fail(result.cause()); - } else { - try { - Map users = result.result().result(0); - Map> grants = result.result().result(1); - Map> punishments = result.result().result(2); - Map response = new HashMap<>(); - - for (Map.Entry userEntry : users.entrySet()) { - UUID uuid = userEntry.getKey(); - User user = userEntry.getValue(); - - if (user == null) { - String username = playerNames.get(uuid); - user = new User(uuid, username); - user.insert(); - users.put(uuid, user); - } - - // Only save if needed - if (user.seenOnServer(server)) { - user.save(); - } - - // TODO: Provide IPs for ip ban lookup (and ip intel) - response.put(uuid.toString(), user.createLoginInfo(server,null, punishments.get(uuid), ImmutableList.of(), grants.get(uuid))); - } - - callback.complete(response); - } catch (Exception ex) { - callback.fail(ex); - } + return; } + + Map users = result.result().result(0); + Map> grants = result.result().result(1); + Map> punishments = result.result().result(2); + Map response = new HashMap<>(); + + List loginInfoFutures = new LinkedList<>(); + + for (Map.Entry userEntry : users.entrySet()) { + Future> loginInfoFuture = Future.future(); + + Map res2 = new HashMap<>(); + UUID uuid = userEntry.getKey(); + User user = userEntry.getValue(); + + if (user == null) { + String username = playerNames.get(uuid); + user = new User(uuid, username); + BlockingCallback nameCollisionCallback = new BlockingCallback<>(); + user.checkNameCollisions(nameCollisionCallback); + nameCollisionCallback.get(); + BlockingCallback insertCallback = new BlockingCallback<>(); + user.insert(insertCallback); + insertCallback.get(); + users.put(uuid, user); + } + + // Only save if needed + if (user.seenOnServer(server)) { + BlockingCallback saveCallback = new BlockingCallback<>(); + user.save(saveCallback); + saveCallback.get(); + } + + // TODO: Provide IPs for ip ban lookup (and ip intel) + BlockingCallback> loginInfo = new BlockingCallback<>(); + user.getLoginInfo(server, null, punishments.get(uuid), ImmutableList.of(), grants.get(uuid), loginInfo); + res2.put(uuid.toString(), loginInfo.get()); + + loginInfoFuture.complete(res2); + loginInfoFutures.add(loginInfoFuture); + } + + CompositeFuture.all(loginInfoFutures).setHandler((allLoginInfo) -> { + for (int i = 0; i < allLoginInfo.result().size(); i++) { + response.putAll(allLoginInfo.result().result(i)); + } + + callback.complete(response); + }); }); return callback; diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETStaff.java b/src/main/java/net/frozenorb/apiv3/route/users/GETStaff.java index 3e63f62..7cdc609 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETStaff.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETStaff.java @@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Grant; import net.frozenorb.apiv3.model.Rank; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import java.util.*; @@ -27,9 +28,14 @@ public final class GETStaff implements Handler { return Integer.compare(firstRank.getWeight(), secondRank.getWeight()); }); - Grant.findByRankSync(staffRanks.values()).forEach(grant -> { + BlockingCallback> grantsCallback = new BlockingCallback<>(); + Grant.findByRank(staffRanks.values(), grantsCallback); + + grantsCallback.get().forEach(grant -> { if (grant.isActive()) { - User user = User.findByIdSync(grant.getUser()); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(grant.getUser(), userCallback); + User user = userCallback.get(); Rank rank = staffRanks.get(grant.getRank()); if (!result.containsKey(rank.getId())) { diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUserDetails.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUserDetails.java index 0245d3e..340d781 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUserDetails.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserDetails.java @@ -1,6 +1,5 @@ package net.frozenorb.apiv3.route.users; -import com.google.common.collect.ImmutableMap; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; @@ -8,28 +7,43 @@ import net.frozenorb.apiv3.model.Grant; import net.frozenorb.apiv3.model.IpLogEntry; import net.frozenorb.apiv3.model.Punishment; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public final class GETUserDetails implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); return; } - // Too many fields to use .of() - APIv3.respondJson(ctx, ImmutableMap.builder() - .put("user", user) - .put("grants", Grant.findByUserSync(user)) - .put("ipLog", IpLogEntry.findByUserSync(user)) - .put("punishments", Punishment.findByUserSync(user)) - .put("aliases", user.getAliases()) - .put("totpSetup", user.getTotpSecret() != null) - .build() - ); + BlockingCallback> grantsCallback = new BlockingCallback<>(); + BlockingCallback> ipLogCallback = new BlockingCallback<>(); + BlockingCallback> punishmentsCallback = new BlockingCallback<>(); + + Grant.findByUser(user, grantsCallback); + IpLogEntry.findByUser(user, ipLogCallback); + Punishment.findByUser(user, punishmentsCallback); + + Map result = new HashMap<>(); + + result.put("user", user); + result.put("grants", grantsCallback.get()); + result.put("ipLog", ipLogCallback.get()); + result.put("punishments", punishmentsCallback.get()); + result.put("aliases", user.getAliases()); + result.put("totpSetup", user.getTotpSecret() != null); + + APIv3.respondJson(ctx, result); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUserPermissions.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUserPermissions.java index bdd8ef6..4147c87 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUserPermissions.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserPermissions.java @@ -9,14 +9,21 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class GETUserPermissions implements Handler { public void handle(RoutingContext ctx) { - User target = User.findByIdSync(ctx.request().getParam("id")); - - if (target == null) { - ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); - return; - } - - APIv3.respondJson(ctx, target.getGlobalPermissions()); + 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.getGlobalPermissions((permissions, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + APIv3.respondJson(ctx, permissions); + } + }); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUserRequiresTOTP.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUserRequiresTOTP.java index 2a840ba..c5637cd 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUserRequiresTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserRequiresTOTP.java @@ -5,6 +5,7 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.RequiresTotpResult; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.IpUtils; @@ -29,7 +30,7 @@ public final class GETUserRequiresTotp implements Handler { ErrorUtils.respondInternalError(ctx, error2); } else { APIv3.respondJson(ctx, ImmutableMap.of( - "required", (requiresTotpResult == User.RequiresTotpResult.REQUIRED_NO_EXEMPTIONS), + "required", (requiresTotpResult == RequiresTotpResult.REQUIRED_NO_EXEMPTIONS), "message", requiresTotpResult.name() )); } diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUserVerifyPassword.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUserVerifyPassword.java index edbcf40..0c91b1b 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUserVerifyPassword.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserVerifyPassword.java @@ -5,19 +5,26 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; public final class GETUserVerifyPassword implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback callback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), callback); + User user = callback.get(); if (user == null) { - user = User.findByLastUsernameSync(ctx.request().getParam("id")); + callback = new BlockingCallback<>(); + User.findByLastUsername(ctx.request().getParam("id"), callback); + user = callback.get(); } if (user == null) { - user = User.findByEmailSync(ctx.request().getParam("id")); + callback = new BlockingCallback<>(); + User.findByEmail(ctx.request().getParam("id"), callback); + user = callback.get(); } if (user == null) { diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserChangePassword.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserChangePassword.java index c12f1d5..c231940 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserChangePassword.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserChangePassword.java @@ -1,18 +1,22 @@ package net.frozenorb.apiv3.route.users; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.RequiresTotpResult; import net.frozenorb.apiv3.util.ErrorUtils; public final class POSTUserChangePassword implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); @@ -33,11 +37,11 @@ public final class POSTUserChangePassword implements Handler { return; } - BlockingCallback totpRequiredCallback = new BlockingCallback<>(); + BlockingCallback totpRequiredCallback = new BlockingCallback<>(); user.requiresTotpAuthorization(null, totpRequiredCallback); - User.RequiresTotpResult requiresTotp = totpRequiredCallback.get(); + RequiresTotpResult requiresTotp = totpRequiredCallback.get(); - if (requiresTotp == User.RequiresTotpResult.REQUIRED_NO_EXEMPTIONS) { + if (requiresTotp == RequiresTotpResult.REQUIRED_NO_EXEMPTIONS) { // TODO } @@ -49,7 +53,9 @@ public final class POSTUserChangePassword implements Handler { } user.setPassword(newPassword); - user.save(); + BlockingCallback saveCallback = new BlockingCallback<>(); + user.save(saveCallback); + saveCallback.get(); APIv3.respondJson(ctx, ImmutableMap.of( "success", true diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserLogin.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserLogin.java index a1fc472..e1525e7 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserLogin.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserLogin.java @@ -1,5 +1,6 @@ package net.frozenorb.apiv3.route.users; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; @@ -9,6 +10,7 @@ import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.model.IpLogEntry; import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.IpUtils; import net.frozenorb.apiv3.util.UuidUtils; @@ -26,7 +28,9 @@ public final class POSTUserLogin implements Handler { } JsonObject requestBody = ctx.getBodyAsJson(); - User user = User.findByIdSync(uuid); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(uuid, userCallback); + User user = userCallback.get(); String username = requestBody.getString("username"); String userIp = requestBody.getString("userIp"); Actor actor = ctx.get("actor"); @@ -44,24 +48,42 @@ public final class POSTUserLogin implements Handler { } if (user == null) { - // Will be saved in the User constructor user = new User(uuid, username); + BlockingCallback nameCollisionCallback = new BlockingCallback<>(); + user.checkNameCollisions(nameCollisionCallback); + nameCollisionCallback.get(); + BlockingCallback insertCallback = new BlockingCallback<>(); + user.checkNameCollisions(insertCallback); + insertCallback.get(); } - IpLogEntry ipLogEntry = IpLogEntry.findByUserAndIpSync(user, userIp); + BlockingCallback ipLogEntryCallback = new BlockingCallback<>(); + IpLogEntry.findByUserAndIp(user, userIp, ipLogEntryCallback); + IpLogEntry ipLogEntry = ipLogEntryCallback.get(); // We use a little bit more verbose code here to save on the // overhead of a .insert() immediately followed by a .save() if (ipLogEntry == null) { ipLogEntry = new IpLogEntry(user, userIp); ipLogEntry.used(); - ipLogEntry.insert(); + BlockingCallback callback = new BlockingCallback<>(); + ipLogEntry.insert(callback); + callback.get(); } else { ipLogEntry.used(); - ipLogEntry.save(); + BlockingCallback callback = new BlockingCallback<>(); + ipLogEntry.save(callback); + callback.get(); + } + + if (!username.equals(user.getLastUsername())) { + BlockingCallback callback = new BlockingCallback<>(); + user.checkNameCollisions(callback); + callback.get(); } user.updateUsername(username); + user.getLoginInfo(server, userIp, (loginInfo, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserNotify.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserNotify.java index fedb3f6..030f94c 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserNotify.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserNotify.java @@ -7,6 +7,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.NotificationTemplate; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.unsorted.Notification; import net.frozenorb.apiv3.util.ErrorUtils; @@ -15,7 +16,9 @@ import java.util.Map; public final class POSTUserNotify implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); @@ -28,7 +31,9 @@ public final class POSTUserNotify implements Handler { } JsonObject requestBody = ctx.getBodyAsJson(); - NotificationTemplate template = NotificationTemplate.findByIdSync(requestBody.getString("template")); + BlockingCallback notificationTemplateCallback = new BlockingCallback<>(); + NotificationTemplate.findById(requestBody.getString("template"), notificationTemplateCallback); + NotificationTemplate template = notificationTemplateCallback.get(); if (template == null) { ErrorUtils.respondNotFound(ctx, "Notification template", requestBody.getString("template")); diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserRegister.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserRegister.java index 37146a5..f86b64d 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserRegister.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserRegister.java @@ -1,12 +1,14 @@ package net.frozenorb.apiv3.route.users; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.NotificationTemplate; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.unsorted.Notification; import net.frozenorb.apiv3.util.ErrorUtils; @@ -22,7 +24,9 @@ public final class POSTUserRegister implements Handler { ); public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); @@ -48,15 +52,19 @@ public final class POSTUserRegister implements Handler { } user.startRegistration(email); - user.save(); + BlockingCallback callback = new BlockingCallback<>(); + user.save(callback); + callback.get(); Map replacements = ImmutableMap.of( "username", user.getLastUsername(), - "email", user.getEmail(), + "email", user.getPendingEmail(), "emailToken", user.getPendingEmailToken() ); - Notification notification = new Notification(NotificationTemplate.findByIdSync("email-confirmation"), replacements, replacements); + BlockingCallback notificationTemplateCallback = new BlockingCallback<>(); + NotificationTemplate.findById("email-confirmation", notificationTemplateCallback); + Notification notification = new Notification(notificationTemplateCallback.get(), replacements, replacements); notification.sendAsEmail(user.getEmail(), (ignored, error) -> { if (error != null) { diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserSetupTOTP.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserSetupTOTP.java index 69f4143..27bb487 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserSetupTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserSetupTOTP.java @@ -1,18 +1,22 @@ package net.frozenorb.apiv3.route.users; import com.google.common.collect.ImmutableMap; +import com.mongodb.client.result.UpdateResult; import com.warrenstrange.googleauth.GoogleAuthenticatorKey; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.TotpUtils; public final class POSTUserSetupTotp implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); @@ -27,7 +31,9 @@ public final class POSTUserSetupTotp implements Handler { GoogleAuthenticatorKey generated = TotpUtils.generateTotpSecret(); user.setTotpSecret(generated.getKey()); - user.save(); + BlockingCallback callback = new BlockingCallback<>(); + user.save(callback); + callback.get(); APIv3.respondJson(ctx, ImmutableMap.of( "qrCode", TotpUtils.getQrCodeUrl(user, generated) diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserVerifyTOTP.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserVerifyTOTP.java index 02cbe7a..313525a 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserVerifyTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserVerifyTOTP.java @@ -16,7 +16,9 @@ import java.util.concurrent.TimeUnit; public final class POSTUserVerifyTotp implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("id"), userCallback); + User user = userCallback.get(); if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); diff --git a/src/main/java/net/frozenorb/apiv3/unsorted/FutureCompatibilityCallback.java b/src/main/java/net/frozenorb/apiv3/unsorted/FutureCompatibilityCallback.java new file mode 100644 index 0000000..d41a951 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/unsorted/FutureCompatibilityCallback.java @@ -0,0 +1,22 @@ +package net.frozenorb.apiv3.unsorted; + +import com.mongodb.async.SingleResultCallback; +import io.vertx.core.Future; + +public class FutureCompatibilityCallback implements SingleResultCallback { + + private final Future future; + + public FutureCompatibilityCallback(Future future) { + this.future = future; + } + + public void onResult(T val, Throwable error) { + if (error != null) { + future.fail(error); + } else { + future.complete(val); + } + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/unsorted/RequiresTotpResult.java b/src/main/java/net/frozenorb/apiv3/unsorted/RequiresTotpResult.java new file mode 100644 index 0000000..6df2d24 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/unsorted/RequiresTotpResult.java @@ -0,0 +1,9 @@ +package net.frozenorb.apiv3.unsorted; + +public enum RequiresTotpResult { + + NOT_REQUIRED_NOT_SET, + NOT_REQUIRED_IP_PRE_AUTHORIZED, + REQUIRED_NO_EXEMPTIONS + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/util/SyncUtils.java b/src/main/java/net/frozenorb/apiv3/util/SyncUtils.java deleted file mode 100644 index f3dd858..0000000 --- a/src/main/java/net/frozenorb/apiv3/util/SyncUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.frozenorb.apiv3.util; - -import com.mongodb.async.client.MongoIterable; -import lombok.experimental.UtilityClass; -import net.frozenorb.apiv3.unsorted.BlockingCallback; - -import java.util.LinkedList; -import java.util.List; - -@UtilityClass -public class SyncUtils { - - public static T blockOne(MongoIterable mongoIterable) { - BlockingCallback callback = new BlockingCallback<>(); - - mongoIterable.first(callback); - return callback.get(); - } - - public static List blockMulti(MongoIterable mongoIterable) { - BlockingCallback> callback = new BlockingCallback<>(); - - mongoIterable.into(new LinkedList<>(), callback); - return callback.get(); - } - -} \ No newline at end of file