diff --git a/apiv3.properties b/apiv3.properties index 436214b..dcb7dee 100644 --- a/apiv3.properties +++ b/apiv3.properties @@ -9,5 +9,7 @@ redis.port=6379 http.port=80 mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ bugsnag.apiKey=0e47fba8b825416b7cbc839066184509 +maxMind.userId=66817 +maxMind.maxMindLicenseKey=8Aw9NsOUeOp7 auth.websiteApiKey=RVbp4hY6sCFVaf auth.bungeeApiKey=6d9cf76dc9f0d23 \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java index 8d393ea..eb34d45 100644 --- a/src/main/java/net/frozenorb/apiv3/APIv3.java +++ b/src/main/java/net/frozenorb/apiv3/APIv3.java @@ -21,10 +21,7 @@ import com.mongodb.connection.ClusterSettings; import fr.javatic.mongo.jacksonCodec.JacksonCodecProvider; import fr.javatic.mongo.jacksonCodec.ObjectMapperFactory; import io.vertx.core.AbstractVerticle; -import io.vertx.core.http.HttpClient; -import io.vertx.core.http.HttpHeaders; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServer; +import io.vertx.core.http.*; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.BodyHandler; @@ -36,6 +33,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.handler.ActorAttributeHandler; import net.frozenorb.apiv3.handler.AuthorizationHandler; +import net.frozenorb.apiv3.handler.LoaderIoHandler; import net.frozenorb.apiv3.route.GETDump; import net.frozenorb.apiv3.route.GETWhoAmI; import net.frozenorb.apiv3.route.POSTMetrics; @@ -46,6 +44,7 @@ import net.frozenorb.apiv3.route.auditLog.POSTUserAuditLogEntry; import net.frozenorb.apiv3.route.chatFilterList.GETChatFilterList; import net.frozenorb.apiv3.route.grants.*; import net.frozenorb.apiv3.route.ipBans.*; +import net.frozenorb.apiv3.route.ipIntel.GETIpIntel; import net.frozenorb.apiv3.route.ipLog.GETUserIpLog; import net.frozenorb.apiv3.route.notificationTemplates.DELETENotificationTemplate; import net.frozenorb.apiv3.route.notificationTemplates.GETNotificationTemplate; @@ -62,12 +61,14 @@ import net.frozenorb.apiv3.route.serverGroups.GETServerGroups; import net.frozenorb.apiv3.route.serverGroups.POSTServerGroup; import net.frozenorb.apiv3.route.servers.*; import net.frozenorb.apiv3.route.users.*; -import net.frozenorb.apiv3.serialization.gson.DateTypeAdapter; import net.frozenorb.apiv3.serialization.gson.FollowAnnotationExclusionStrategy; -import net.frozenorb.apiv3.serialization.jackson.UUIDJsonDeserializer; -import net.frozenorb.apiv3.serialization.jackson.UUIDJsonSerializer; -import net.frozenorb.apiv3.serialization.mongodb.UUIDCodecProvider; -import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger; +import net.frozenorb.apiv3.serialization.gson.InstantTypeAdapter; +import net.frozenorb.apiv3.serialization.jackson.InstantJsonDeserializer; +import net.frozenorb.apiv3.serialization.jackson.InstantJsonSerializer; +import net.frozenorb.apiv3.serialization.jackson.UuidJsonDeserializer; +import net.frozenorb.apiv3.serialization.jackson.UuidJsonSerializer; +import net.frozenorb.apiv3.serialization.mongodb.UuidCodecProvider; +import net.frozenorb.apiv3.unsorted.BugsnagSlf4jLogger; import org.bson.Document; import org.bson.codecs.BsonValueCodecProvider; import org.bson.codecs.DocumentCodecProvider; @@ -79,17 +80,22 @@ import org.bson.codecs.configuration.CodecRegistry; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.UUID; @Slf4j public final class APIv3 extends AbstractVerticle { @Getter private static HttpClient httpClient; + @Getter private static HttpClient httpsClient; @Getter private static MongoDatabase database; @Getter private static Properties config = new Properties(); @Getter private static RedisClient redisClient; private static final Gson gson = new GsonBuilder() - .registerTypeAdapter(Date.class, new DateTypeAdapter()) + .registerTypeAdapter(Instant.class, new InstantTypeAdapter()) .setExclusionStrategies(new FollowAnnotationExclusionStrategy()) .create(); @@ -160,11 +166,15 @@ public final class APIv3 extends AbstractVerticle { new IndexModel(new Document("user", 1)), new IndexModel(new Document("user", 1).append("userIp", 1)) ), (a, b) -> {}); + database.getCollection("ipBans").createIndexes(ImmutableList.of( + new IndexModel(new Document("userIp", 1)) + ), (a, b) -> {}); database.getCollection("punishments").createIndexes(ImmutableList.of( new IndexModel(new Document("user", 1)), new IndexModel(new Document("type", 1)), new IndexModel(new Document("addedAt", 1)), - new IndexModel(new Document("addedBy", 1)) + new IndexModel(new Document("addedBy", 1)), + new IndexModel(new Document("linkedIpBanId", 1)) ), (a, b) -> {}); database.getCollection("users").createIndexes(ImmutableList.of( new IndexModel(new Document("lastUsername", 1)), @@ -179,8 +189,10 @@ public final class APIv3 extends AbstractVerticle { ObjectMapper objectMapper = ObjectMapperFactory.createObjectMapper(); SimpleModule simpleModule = new SimpleModule(); - simpleModule.addSerializer(UUID.class, new UUIDJsonSerializer()); - simpleModule.addDeserializer(UUID.class, new UUIDJsonDeserializer()); + simpleModule.addSerializer(Instant.class, new InstantJsonSerializer()); + simpleModule.addDeserializer(Instant.class, new InstantJsonDeserializer()); + simpleModule.addSerializer(UUID.class, new UuidJsonSerializer()); + simpleModule.addDeserializer(UUID.class, new UuidJsonDeserializer()); objectMapper.registerModule(simpleModule); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); @@ -190,7 +202,7 @@ public final class APIv3 extends AbstractVerticle { List providers = new ArrayList<>(); // Our fixed uuid codec - providers.add(new UUIDCodecProvider()); + providers.add(new UuidCodecProvider()); // Normal providers providers.add(new ValueCodecProvider()); @@ -216,7 +228,7 @@ public final class APIv3 extends AbstractVerticle { Client bugsnag = new Client(config.getProperty("bugsnag.apiKey")); bugsnag.setReleaseStage(config.getProperty("general.releaseStage")); bugsnag.setProjectPackages("net.frozenorb.apiv3"); - bugsnag.setLogger(new BugsnagSLF4JLogger()); + bugsnag.setLogger(new BugsnagSlf4jLogger()); } // TODO: blockingHandler -> handler @@ -224,6 +236,7 @@ public final class APIv3 extends AbstractVerticle { HttpServer webServer = vertx.createHttpServer(); Router mainRouter = Router.router(vertx); + mainRouter.route().handler(new LoaderIoHandler()); mainRouter.route().handler(new ActorAttributeHandler()); mainRouter.route().handler(new AuthorizationHandler()); mainRouter.route().handler(LoggerHandler.create(LoggerFormat.TINY)); @@ -231,79 +244,82 @@ public final class APIv3 extends AbstractVerticle { // TODO: The commented out routes - mainRouter.get("/announcements/:id").blockingHandler(new GETAnnouncements()); - mainRouter.put("/announcements/:id").blockingHandler(new PUTAnnouncements()); + mainRouter.get("/announcements/:id").handler(new GETAnnouncements()); + mainRouter.put("/announcements/:id").handler(new PUTAnnouncements()); - mainRouter.get("/auditLog").blockingHandler(new GETAuditLog()); - mainRouter.post("/user/:id/auditLogEntry").blockingHandler(new POSTUserAuditLogEntry()); + mainRouter.get("/auditLog").handler(new GETAuditLog()); + mainRouter.post("/user/:id/auditLogEntry").handler(new POSTUserAuditLogEntry()); mainRouter.get("/chatFilterList").handler(new GETChatFilterList()); - mainRouter.get("/grant/:id").blockingHandler(new GETGrant()); - mainRouter.get("/grants").blockingHandler(new GETGrants()); - mainRouter.get("/user/:id/grants").blockingHandler(new GETUserGrants()); - mainRouter.post("/user/:id/grant").blockingHandler(new POSTUserGrant()); - mainRouter.delete("/grant/:id").blockingHandler(new DELETEGrant()); + mainRouter.get("/grant/:id").handler(new GETGrant()); + mainRouter.get("/grants").handler(new GETGrants()); + mainRouter.get("/user/:id/grants").handler(new GETUserGrants()); + mainRouter.post("/user/:id/grant").blockingHandler(new POSTUserGrant(), false); + mainRouter.delete("/grant/:id").blockingHandler(new DELETEGrant(), false); - mainRouter.get("/ipBan/:id").blockingHandler(new GETIpBan()); - mainRouter.get("/ipBans").blockingHandler(new GETIpBans()); - mainRouter.get("/ip/:id/ipBans").blockingHandler(new GETIpIpBans()); - mainRouter.post("/ip/:id/ipBan").blockingHandler(new POSTIpIpBan()); - mainRouter.delete("/ipBan/:id").blockingHandler(new DELETEIpBan()); + mainRouter.get("/ipBan/:id").handler(new GETIpBan()); + mainRouter.get("/ipBans").handler(new GETIpBans()); + mainRouter.get("/ip/:id/ipBans").handler(new GETIpIpBans()); + mainRouter.post("/ip/:id/ipBan").blockingHandler(new POSTIpIpBan(), false); + mainRouter.delete("/ipBan/:id").blockingHandler(new DELETEIpBan(), false); - mainRouter.get("/user/:id/ipLog").blockingHandler(new GETUserIpLog()); + mainRouter.get("/ip/:id/intel").handler(new GETIpIntel()); - mainRouter.get("/notificationTemplate/:id").blockingHandler(new GETNotificationTemplate()); - mainRouter.get("/notificationTemplates").blockingHandler(new GETNotificationTemplates()); - mainRouter.post("/notificationTemplate").blockingHandler(new POSTNotificationTemplate()); - //mainRouter.put("/notificationTemplate/:id").blockingHandler(new PUTNotificationTemplate()); - mainRouter.delete("/notificationTemplate/:id").blockingHandler(new DELETENotificationTemplate()); + mainRouter.get("/user/:id/ipLog").handler(new GETUserIpLog()); - mainRouter.get("/punishment/:id").blockingHandler(new GETPunishment()); - mainRouter.get("/punishments").blockingHandler(new GETPunishments()); - mainRouter.get("/user/:id/punishments").blockingHandler(new GETUserPunishments()); - mainRouter.post("/user/:id/punish").blockingHandler(new POSTUserPunish()); - mainRouter.delete("/punishment/:id").blockingHandler(new DELETEPunishment()); - mainRouter.delete("/user/:id/punishment").blockingHandler(new DELETEUserPunishment()); + mainRouter.get("/notificationTemplate/:id").handler(new GETNotificationTemplate()); + mainRouter.get("/notificationTemplates").handler(new GETNotificationTemplates()); + mainRouter.post("/notificationTemplate").blockingHandler(new POSTNotificationTemplate(), false); + //mainRouter.put("/notificationTemplate/:id").blockingHandler(new PUTNotificationTemplate(), false); + mainRouter.delete("/notificationTemplate/:id").blockingHandler(new DELETENotificationTemplate(), false); + + mainRouter.get("/punishment/:id").handler(new GETPunishment()); + mainRouter.get("/punishments").handler(new GETPunishments()); + mainRouter.get("/user/:id/punishments").handler(new GETUserPunishments()); + mainRouter.post("/user/:id/punish").blockingHandler(new POSTUserPunish(), false); + mainRouter.delete("/punishment/:id").blockingHandler(new DELETEPunishment(), false); + mainRouter.delete("/user/:id/punishment").blockingHandler(new DELETEUserPunishment(), false); mainRouter.get("/rank/:id").handler(new GETRank()); mainRouter.get("/ranks").handler(new GETRanks()); - mainRouter.post("/rank").blockingHandler(new POSTRank()); - //mainRouter.put("/rank/:id").blockingHandler(new PUTRank()); - mainRouter.delete("/rank/:id").blockingHandler(new DELETERank()); + mainRouter.post("/rank").blockingHandler(new POSTRank(), false); + //mainRouter.put("/rank/:id").blockingHandler(new PUTRank(), false); + mainRouter.delete("/rank/:id").blockingHandler(new DELETERank(), false); mainRouter.get("/serverGroup/:id").handler(new GETServerGroup()); mainRouter.get("/serverGroups").handler(new GETServerGroups()); - mainRouter.post("/serverGroup").blockingHandler(new POSTServerGroup()); - //mainRouter.put("/serverGroup/:id").blockingHandler(new PUTServerGroup()); - mainRouter.delete("/serverGroup/:id").blockingHandler(new DELETEServerGroup()); + mainRouter.post("/serverGroup").blockingHandler(new POSTServerGroup(), false); + //mainRouter.put("/serverGroup/:id").blockingHandler(new PUTServerGroup(), false); + mainRouter.delete("/serverGroup/:id").blockingHandler(new DELETEServerGroup(), false); mainRouter.get("/server/:id").handler(new GETServer()); mainRouter.get("/servers").handler(new GETServers()); mainRouter.post("/server/heartbeat").handler(new POSTServerHeartbeat()); - mainRouter.post("/server").blockingHandler(new POSTServer()); - //mainRouter.put("/server/:id").blockingHandler(new PUTServer()); - mainRouter.delete("/server/:id").blockingHandler(new DELETEServer()); + mainRouter.post("/server").blockingHandler(new POSTServer(), false); + //mainRouter.put("/server/:id").blockingHandler(new PUTServer(), false); + mainRouter.delete("/server/:id").blockingHandler(new DELETEServer(), false); - mainRouter.get("/staff").blockingHandler(new GETStaff()); - mainRouter.get("/user/:id").blockingHandler(new GETUser()); - mainRouter.get("/user/:id/details").blockingHandler(new GETUserDetails()); - mainRouter.get("/user/:id/meta/:serverGroup").blockingHandler(new GETUserMeta()); - mainRouter.get("/user/:id/requiresTOTP").blockingHandler(new GETUserRequiresTOTP()); - mainRouter.get("/user/:id/verifyPassword").blockingHandler(new GETUserVerifyPassword()); - mainRouter.post("/user/confirmRegister/:emailToken").blockingHandler(new POSTUserConfirmRegister()); + mainRouter.get("/staff").blockingHandler(new GETStaff(), false); + mainRouter.get("/user/:id").handler(new GETUser()); + mainRouter.get("/user/:id/details").blockingHandler(new GETUserDetails(), false); + mainRouter.get("/user/:id/meta/:serverGroup").blockingHandler(new GETUserMeta(), false); + mainRouter.get("/user/:id/permissions").blockingHandler(new GETUserPermissions(), false); + mainRouter.get("/user/:id/requiresTOTP").blockingHandler(new GETUserRequiresTOTP(), false); + mainRouter.get("/user/:id/verifyPassword").blockingHandler(new GETUserVerifyPassword(), false); + mainRouter.post("/user/confirmRegister/:emailToken").blockingHandler(new POSTUserConfirmRegister(), false); mainRouter.post("/user/:id/leave").handler(new POSTUserLeave()); - mainRouter.post("/user/:id/login").handler(new POSTUserLogin()); - mainRouter.post("/user/:id/notify").blockingHandler(new POSTUserNotify()); - mainRouter.post("/user/:id/register").blockingHandler(new POSTUserRegister()); - mainRouter.post("/user/:id/setupTOTP").blockingHandler(new POSTUserSetupTOTP()); - mainRouter.post("/user/:id/verifyTOTP").blockingHandler(new POSTUserVerifyTOTP()); - mainRouter.put("/user/:id/meta/:serverGroup").blockingHandler(new PUTUserMeta()); - mainRouter.delete("/user/:id/meta/:serverGroup").blockingHandler(new DELETEUserMeta()); + mainRouter.post("/user/:id/login").blockingHandler(new POSTUserLogin()); + mainRouter.post("/user/:id/notify").blockingHandler(new POSTUserNotify(), false); + mainRouter.post("/user/:id/register").blockingHandler(new POSTUserRegister(), false); + mainRouter.post("/user/:id/setupTOTP").blockingHandler(new POSTUserSetupTOTP(), false); + mainRouter.post("/user/:id/verifyTOTP").blockingHandler(new POSTUserVerifyTOTP(), false); + mainRouter.put("/user/:id/meta/:serverGroup").blockingHandler(new PUTUserMeta(), false); + mainRouter.delete("/user/:id/meta/:serverGroup").blockingHandler(new DELETEUserMeta(), false); mainRouter.get("/dump/:type").handler(new GETDump()); mainRouter.get("/whoami").handler(new GETWhoAmI()); - mainRouter.post("/metrics").blockingHandler(new POSTMetrics()); + mainRouter.post("/metrics").handler(new POSTMetrics()); int port = Integer.parseInt(config.getProperty("http.port")); webServer.requestHandler(mainRouter::accept).listen(port); @@ -311,6 +327,11 @@ public final class APIv3 extends AbstractVerticle { private void setupHttpClient() { httpClient = vertx.createHttpClient(); + httpsClient = vertx.createHttpClient( + new HttpClientOptions() + .setSsl(true) + .setTrustAll(true) + ); } public static void respondJson(RoutingContext ctx, Object response) { diff --git a/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java b/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java index 1f2ddeb..49dd451 100644 --- a/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java +++ b/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java @@ -24,6 +24,7 @@ public final class UserActor implements Actor { if (cachedAuthorized != null) { return cachedAuthorized; } else { + // TODO: THIS IS KINDA BLOCKING boolean authorized = user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST); cachedAuthorized = authorized; return authorized; diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java b/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java index dc29a29..bd17093 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/V2Importer.java @@ -56,7 +56,7 @@ public final class V2Importer { private final Future future; - public FutureCompatibilityCallback(Future future) { + private FutureCompatibilityCallback(Future future) { this.future = future; } 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 9f1bb24..22e5715 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/GrantConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/GrantConverter.java @@ -7,8 +7,8 @@ import net.frozenorb.apiv3.model.Grant; import org.bson.Document; import org.bson.types.ObjectId; +import java.time.Instant; import java.util.Collection; -import java.util.Date; import java.util.Map; import java.util.UUID; @@ -21,6 +21,7 @@ public final class GrantConverter implements Block { this.oidToUniqueId = oidToUniqueId; } + @SuppressWarnings("unchecked") @Override public void apply(Document grant) { UUID target = oidToUniqueId.get(((Map) grant.get("target")).get("$id")); @@ -37,6 +38,8 @@ public final class GrantConverter implements Block { rank = "high-roller"; } else if (rank.equalsIgnoreCase("dev")) { rank = "developer"; + } else if (rank.equalsIgnoreCase("coowner")) { + rank = "owner"; } Grant created = new Grant( @@ -45,9 +48,9 @@ public final class GrantConverter implements Block { grant.containsKey("comment") ? grant.getString("comment") : "", grant.containsKey("scope") ? ImmutableSet.copyOf((Collection) grant.get("scope")) : ImmutableSet.of(), rank, - grant.getDate("expires"), + grant.containsKey("expires") ? grant.getDate("expires").toInstant() : null, grant.containsKey("addedBy") ? oidToUniqueId.get(((Map) grant.get("addedBy")).get("$id")) : null, - grant.containsKey("created") ? grant.getDate("created") : new Date(), + grant.containsKey("created") ? grant.getDate("created").toInstant() : Instant.now(), null, null, null 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 dcf648f..05e16e0 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/IpLogConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/IpLogConverter.java @@ -20,6 +20,7 @@ public final class IpLogConverter implements Block { this.oidToUniqueId = oidToUniqueId; } + @SuppressWarnings("unchecked") @Override public void apply(Document ipLogEntry) { UUID user = oidToUniqueId.get(((Map) ipLogEntry.get("user")).get("$id")); @@ -44,10 +45,9 @@ public final class IpLogConverter implements Block { new ObjectId().toString(), user, ip, - lastSeen, - lastSeen, + lastSeen.toInstant(), + lastSeen.toInstant(), ((Number) ipLogEntry.get("uses")).intValue() - ); created.insert(); 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 e260107..178d5be 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java @@ -8,7 +8,6 @@ import net.frozenorb.apiv3.model.Punishment; import org.bson.Document; import org.bson.types.ObjectId; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; @@ -22,6 +21,7 @@ public final class PunishmentConverter implements Block { this.oidToUniqueId = oidToUniqueId; } + @SuppressWarnings("unchecked") @Override public void apply(Document punishment) { UUID target = oidToUniqueId.get(((Map) punishment.get("user")).get("$id")); @@ -40,15 +40,15 @@ public final class PunishmentConverter implements Block { target, punishment.getString("reason").toString(), Punishment.PunishmentType.valueOf(punishment.getString("type").toUpperCase()), - punishment.getDate("expires"), + punishment.containsKey("expires") ? punishment.getDate("expires").toInstant() : null, punishment.containsKey("meta") ? (punishment.get("meta") instanceof List ? ImmutableMap.of() : (Document) punishment.get("meta")) : ImmutableMap.of(), null, punishment.containsKey("addedBy") ? oidToUniqueId.get(((Map) punishment.get("addedBy")).get("$id")) : null, - (Date) punishment.getDate("created").clone(), + punishment.getDate("created").toInstant(), punishment.containsKey("createdOn") ? String.valueOf(((Map) punishment.get("createdOn")).get("$id")) : "Website", punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE, punishment.containsKey("removedBy") ? (((Map) punishment.get("removedBy")).get("$ref").equals("user") ? oidToUniqueId.get(((Map) punishment.get("removedBy")).get("$id")) : null) : null, - punishment.containsKey("removedBy") ? (punishment.containsKey("removedAt") ? punishment.getDate("removedAt") : punishment.getDate("created")) : null, + punishment.containsKey("removedBy") ? (punishment.containsKey("removedAt") ? punishment.getDate("removedAt") : punishment.getDate("created")).toInstant() : null, punishment.containsKey("removedBy") ? punishment.getString("removalReason").toString() : null ); 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 9b1a47e..b8effbf 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/UserConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/UserConverter.java @@ -4,7 +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.util.UUIDUtils; +import net.frozenorb.apiv3.util.UuidUtils; import org.bson.Document; import org.bson.types.ObjectId; @@ -30,7 +30,7 @@ public final class UserConverter implements Block { UUID uuid = UUID.fromString(uuidString.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5")); - if (!UUIDUtils.isAcceptableUUID(uuid)) { + if (!UuidUtils.isAcceptableUuid(uuid)) { return; } @@ -39,7 +39,7 @@ public final class UserConverter implements Block { User created = new User( uuid, user.get("name").toString(), - ImmutableMap.of(user.get("name").toString(), user.getDate("joined")), + ImmutableMap.of(user.get("name").toString(), user.getDate("joined").toInstant()), null, null, null, @@ -47,8 +47,8 @@ public final class UserConverter implements Block { user.getString("email"), user.getString("phone"), "INVALID", - user.getDate("joined"), - user.getDate("joined"), + user.getDate("joined").toInstant(), + user.getDate("joined").toInstant(), false ); diff --git a/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java b/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java index 21dd9f3..cf5a30d 100644 --- a/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java +++ b/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java @@ -9,7 +9,6 @@ import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; -import java.nio.charset.Charset; import java.util.Base64; public final class ActorAttributeHandler implements Handler { @@ -120,7 +119,7 @@ public final class ActorAttributeHandler implements Handler { } } - public void processNoAuthorization(RoutingContext ctx) { + private void processNoAuthorization(RoutingContext ctx) { ctx.put("actor", new UnknownActor()); ctx.next(); } diff --git a/src/main/java/net/frozenorb/apiv3/handler/LoaderIoHandler.java b/src/main/java/net/frozenorb/apiv3/handler/LoaderIoHandler.java new file mode 100644 index 0000000..8c46e06 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/handler/LoaderIoHandler.java @@ -0,0 +1,19 @@ +package net.frozenorb.apiv3.handler; + +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; + +public final class LoaderIoHandler implements Handler { + + @Override + public void handle(RoutingContext ctx) { + String path = ctx.request().path().replace("/", ""); + + if (path.equals("loaderio-1c81aa574f79c573e7220e15e30a96aa")) { + ctx.response().end(path); + } else { + ctx.next(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCity.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCity.java new file mode 100644 index 0000000..a5cdb35 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCity.java @@ -0,0 +1,21 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +public final class MaxMindCity { + + @Getter private int confidence; + @Getter private int geonameId; + @Getter private String name; + + public MaxMindCity() {} // For Jackson + + public MaxMindCity(Document legacy) { + this.confidence = legacy.getInteger("confidence"); + this.geonameId = legacy.getInteger("geoname_id"); + this.name = MaxMindUtils.getEnglishName(legacy); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindContinent.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindContinent.java new file mode 100644 index 0000000..c2e50a1 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindContinent.java @@ -0,0 +1,21 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +public final class MaxMindContinent { + + @Getter private String code; + @Getter private int geonameId; + @Getter private String name; + + public MaxMindContinent() {} // For Jackson + + public MaxMindContinent(Document legacy) { + this.code = legacy.getString("code"); + this.geonameId = legacy.getInteger("geoname_id"); + this.name = MaxMindUtils.getEnglishName(legacy); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCountry.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCountry.java new file mode 100644 index 0000000..66cf4af --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCountry.java @@ -0,0 +1,23 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +public final class MaxMindCountry { + + @Getter private String isoCode; + @Getter private int confidence; + @Getter private int geonameId; + @Getter private String name; + + public MaxMindCountry() {} // For Jackson + + public MaxMindCountry(Document legacy) { + this.isoCode = legacy.getString("iso_code"); + this.confidence = legacy.getInteger("confidence"); + this.geonameId = legacy.getInteger("geoname_id"); + this.name = MaxMindUtils.getEnglishName(legacy); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java new file mode 100644 index 0000000..f896123 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java @@ -0,0 +1,28 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import org.bson.Document; + +public final class MaxMindLocation { + + @Getter private double latitude; + @Getter private double longitude; + @Getter private int accuracyRadius; + @Getter private String timeZone; + @Getter private int populationDensity; + @Getter private int metroCode; + @Getter private int averageIncome; + + public MaxMindLocation() {} // For Jackson + + public MaxMindLocation(Document legacy) { + this.latitude = legacy.getDouble("latitude"); + this.longitude = legacy.getDouble("longitude"); + this.accuracyRadius = legacy.getInteger("accuracy_radius"); + this.timeZone = legacy.getString("time_zone"); + this.populationDensity = legacy.getInteger("population_density", -1); + this.metroCode = legacy.getInteger("metro_code", -1); // Metro codes are US only + this.averageIncome = legacy.getInteger("average_income", -1); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java new file mode 100644 index 0000000..31247d9 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java @@ -0,0 +1,24 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import org.bson.Document; + +public final class MaxMindPostal { + + @Getter private String code; + @Getter private int confidence; + + public MaxMindPostal() {} // For Jackson + + public MaxMindPostal(Document legacy) { + this.code = legacy.getString("code"); + + // Postal codes aren't guaranteed to exist for all areas + if (code == null) { + code = ""; + } + + this.confidence = legacy.getInteger("confidence"); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindRegisteredCountry.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindRegisteredCountry.java new file mode 100644 index 0000000..07c8b85 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindRegisteredCountry.java @@ -0,0 +1,21 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +public final class MaxMindRegisteredCountry { + + @Getter private String isoCode; + @Getter private int geonameId; + @Getter private String name; + + public MaxMindRegisteredCountry() {} // For Jackson + + public MaxMindRegisteredCountry(Document legacy) { + this.isoCode = legacy.getString("iso_code"); + this.geonameId = legacy.getInteger("geoname_id"); + this.name = MaxMindUtils.getEnglishName(legacy); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindResult.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindResult.java new file mode 100644 index 0000000..55e272d --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindResult.java @@ -0,0 +1,40 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import org.bson.Document; + +import java.util.ArrayList; +import java.util.List; + +public final class MaxMindResult { + + @Getter private MaxMindContinent continent; + @Getter private MaxMindCity city; + @Getter private MaxMindPostal postal; + @Getter private MaxMindTraits traits; + @Getter private MaxMindLocation location; + @Getter private MaxMindSubdivision[] subdivisions; + @Getter private MaxMindCountry country; + @Getter private MaxMindRegisteredCountry registeredCountry; + + public MaxMindResult() {} // For Jackson + + public MaxMindResult(Document legacy) { + this.continent = new MaxMindContinent((Document) legacy.get("continent")); + this.city = new MaxMindCity((Document) legacy.get("city")); + this.postal = new MaxMindPostal((Document) legacy.get("postal")); + this.traits = new MaxMindTraits((Document) legacy.get("traits")); + this.location = new MaxMindLocation((Document) legacy.get("location")); + this.country = new MaxMindCountry((Document) legacy.get("country")); + this.registeredCountry = new MaxMindRegisteredCountry((Document) legacy.get("registered_country")); + + List subdivisions = new ArrayList<>(); + + for (Object subdivision : (List) legacy.get("subdivisions")) { + subdivisions.add(new MaxMindSubdivision((Document) subdivision)); + } + + this.subdivisions = subdivisions.toArray(new MaxMindSubdivision[subdivisions.size()]); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java new file mode 100644 index 0000000..ae28e47 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java @@ -0,0 +1,23 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +public final class MaxMindSubdivision { + + @Getter private String isoCode; + @Getter private int confidence; + @Getter private int geonameId; + @Getter private String name; + + public MaxMindSubdivision() {} // For Jackson + + public MaxMindSubdivision(Document legacy) { + this.isoCode = legacy.getString("iso_code"); + this.confidence = legacy.getInteger("confidence", -1); + this.geonameId = legacy.getInteger("geoname_id"); + this.name = MaxMindUtils.getEnglishName(legacy); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindTraits.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindTraits.java new file mode 100644 index 0000000..c8edf7d --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindTraits.java @@ -0,0 +1,26 @@ +package net.frozenorb.apiv3.maxmind; + +import lombok.Getter; +import org.bson.Document; + +public final class MaxMindTraits { + + @Getter private String isp; + @Getter private String domain; + @Getter private int asn; + @Getter private String asnOrganization; + @Getter private String type; // TODO: MAKE ENUM + @Getter private String organization; + + public MaxMindTraits() {} // For Jackson + + public MaxMindTraits(Document legacy) { + this.isp = legacy.getString("isp"); + this.domain = legacy.getString("domain"); + this.asn = legacy.getInteger("autonomous_system_number"); + this.asnOrganization = legacy.getString("autonomous_system_organization"); + this.type = legacy.getString("user_type"); + this.organization = legacy.getString("organization"); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java b/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java index 1161e3e..ac5ddba 100644 --- a/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java @@ -14,7 +14,11 @@ import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import org.bson.types.ObjectId; -import java.util.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; @Entity public final class AuditLogEntry { @@ -24,59 +28,31 @@ public final class AuditLogEntry { @Getter @Id private String id; @Getter private UUID user; @Getter private String userIp; - @Getter private Date performedAt; + @Getter private Instant performedAt; @Getter private String actorName; @Getter private ActorType actorType; @Getter private AuditLogActionType type; @Getter private Map metadata; - public static List findAllSync() { - return SyncUtils.blockMulti(auditLogCollection.find().sort(new Document("performedAt", -1))); - } - - public static List findAllPaginatedSync(int skip, int pageSize) { - return SyncUtils.blockMulti(auditLogCollection.find().sort(new Document("performedAt", -1)).skip(skip).limit(pageSize)); - } - - public static AuditLogEntry findByIdSync(String id) { - return SyncUtils.blockOne(auditLogCollection.find(new Document("_id", id))); - } - - public static List findByUserSync(User user) { - return findByUserSync(user.getId()); - } - public static List findByUserSync(UUID user) { return SyncUtils.blockMulti(auditLogCollection.find(new Document("user", user))); } - public static void findAll(SingleResultCallback> callback) { - auditLogCollection.find().sort(new Document("performedAt", -1)).into(new ArrayList<>(), callback); - } - public static void findAllPaginated(int skip, int pageSize, SingleResultCallback> callback) { auditLogCollection.find().sort(new Document("performedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback); } - public static void findById(String id, SingleResultCallback callback) { - auditLogCollection.find(new Document("_id", id)).first(callback); - } - - public static void findByUser(User user, SingleResultCallback> callback) { - findByUser(user.getId(), callback); - } - public static void findByUser(UUID user, SingleResultCallback> callback) { auditLogCollection.find(new Document("user", user)).into(new ArrayList<>(), callback); } - public AuditLogEntry() {} // For Morphia + public AuditLogEntry() {} // For Jackson public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map metadata) { this.id = new ObjectId().toString(); this.user = user.getId(); this.userIp = userIp; - this.performedAt = new Date(); + this.performedAt = Instant.now(); this.actorName = actor.getName(); this.actorType = actor.getType(); this.type = type; diff --git a/src/main/java/net/frozenorb/apiv3/model/Grant.java b/src/main/java/net/frozenorb/apiv3/model/Grant.java index bb5e882..bef6794 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Grant.java +++ b/src/main/java/net/frozenorb/apiv3/model/Grant.java @@ -14,6 +14,7 @@ import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import org.bson.types.ObjectId; +import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @@ -26,25 +27,21 @@ public final class Grant { @Getter @Id private String id; @Getter private UUID user; @Getter private String reason; - @Getter private Set scopes = new HashSet<>(); // So on things w/o scopes we still load properly (Morphia drops empty sets) + @Getter private Set scopes; @Getter private String rank; - @Getter private Date expiresAt; + @Getter private Instant expiresAt; @Getter private UUID addedBy; - @Getter private Date addedAt; + @Getter private Instant addedAt; @Getter private UUID removedBy; - @Getter private Date removedAt; + @Getter private Instant removedAt; @Getter private String removalReason; public static List findAllSync() { return SyncUtils.blockMulti(grantsCollection.find().sort(new Document("addedAt", -1))); } - public static List findAllPaginatedSync(int skip, int pageSize) { - return SyncUtils.blockMulti(grantsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize)); - } - public static List findByRankSync(Collection ranks) { Collection convertedRanks = ranks.stream().map(Rank::getId).collect(Collectors.toList()); return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", convertedRanks)))); @@ -62,19 +59,10 @@ public final class Grant { return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user))); } - public static void findAll(SingleResultCallback> callback) { - grantsCollection.find().sort(new Document("addedAt", -1)).into(new ArrayList<>(), callback); - } - public static void findAllPaginated(int skip, int pageSize, SingleResultCallback> callback) { grantsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback); } - public static void findByRank(Collection ranks, SingleResultCallback> callback) { - Collection convertedRanks = ranks.stream().map(Rank::getId).collect(Collectors.toList()); - grantsCollection.find(new Document("rank", new Document("$in", convertedRanks))).into(new ArrayList<>(), callback); - } - public static void findById(String id, SingleResultCallback callback) { grantsCollection.find(new Document("_id", id)).first(callback); } @@ -107,9 +95,9 @@ public final class Grant { }); } - public Grant() {} // For Morphia + public Grant() {} // For Jackson - public Grant(User user, String reason, Set scopes, Rank rank, Date expiresAt, User addedBy) { + public Grant(User user, String reason, Set scopes, Rank rank, Instant expiresAt, User addedBy) { this.id = new ObjectId().toString(); this.user = user.getId(); this.reason = reason; @@ -117,7 +105,7 @@ public final class Grant { this.rank = rank.getId(); this.expiresAt = expiresAt; this.addedBy = addedBy == null ? null : addedBy.getId(); - this.addedAt = new Date(); + this.addedAt = Instant.now(); } public boolean isActive() { @@ -125,11 +113,7 @@ public final class Grant { } public boolean isExpired() { - if (expiresAt == null) { - return false; // Never expires - } else { - return expiresAt.before(new Date()); - } + return expiresAt != null && expiresAt.isBefore(Instant.now()); } public boolean isRemoved() { @@ -152,7 +136,7 @@ public final class Grant { public void delete(User removedBy, String reason) { this.removedBy = removedBy.getId(); - this.removedAt = new Date(); + this.removedAt = Instant.now(); this.removalReason = reason; BlockingCallback callback = new BlockingCallback<>(); diff --git a/src/main/java/net/frozenorb/apiv3/model/IpBan.java b/src/main/java/net/frozenorb/apiv3/model/IpBan.java index cf71079..5a44a43 100644 --- a/src/main/java/net/frozenorb/apiv3/model/IpBan.java +++ b/src/main/java/net/frozenorb/apiv3/model/IpBan.java @@ -16,6 +16,7 @@ import net.frozenorb.apiv3.util.TimeUtils; import org.bson.Document; import org.bson.types.ObjectId; +import java.time.Instant; import java.util.*; @Entity @@ -27,37 +28,21 @@ public final class IpBan { @Getter @Id private String id; @Getter private String userIp; @Getter private String reason; - @Getter private Date expiresAt; + @Getter private Instant expiresAt; @Getter private UUID addedBy; - @Getter private Date addedAt; + @Getter private Instant addedAt; @Getter private String actorName; @Getter private ActorType actorType; @Getter private UUID removedBy; - @Getter private Date removedAt; + @Getter private Instant removedAt; @Getter private String removalReason; - public static List findAllSync() { - return SyncUtils.blockMulti(ipBansCollection.find().sort(new Document("addedAt", -1))); - } - - public static List findAllPaginatedSync(int skip, int pageSize) { - return SyncUtils.blockMulti(ipBansCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize)); - } - public static IpBan findByIdSync(String id) { return SyncUtils.blockOne(ipBansCollection.find(new Document("_id", id))); } - public static List findByIpSync(String userIp) { - return SyncUtils.blockMulti(ipBansCollection.find(new Document("userIp", userIp))); - } - - public static void findAll(SingleResultCallback> callback) { - ipBansCollection.find().sort(new Document("addedAt", -1)).into(new ArrayList<>(), callback); - } - public static void findAllPaginated(int skip, int pageSize, SingleResultCallback> callback) { ipBansCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback); } @@ -90,7 +75,7 @@ public final class IpBan { }); } - public IpBan() {} // For Morphia + public IpBan() {} // For Jackson public IpBan(String userIp, Punishment linked) { this.id = new ObjectId().toString(); @@ -98,18 +83,18 @@ public final class IpBan { this.reason = linked.getReason(); this.expiresAt = linked.getExpiresAt(); this.addedBy = linked.getAddedBy(); - this.addedAt = new Date(); + this.addedAt = Instant.now(); this.actorName = linked.getActorName(); this.actorType = linked.getActorType(); } - public IpBan(String userIp, String reason, Date expiresAt, User addedBy, Actor actor) { + public IpBan(String userIp, String reason, Instant expiresAt, User addedBy, Actor actor) { this.id = new ObjectId().toString(); this.userIp = userIp; this.reason = reason; this.expiresAt = expiresAt; this.addedBy = addedBy == null ? null : addedBy.getId(); - this.addedAt = new Date(); + this.addedAt = Instant.now(); this.actorName = actor.getName(); this.actorType = actor.getType(); } @@ -119,27 +104,56 @@ public final class IpBan { } public boolean isExpired() { - if (expiresAt == null) { - return false; // Never expires - } else { - return expiresAt.before(new Date()); - } + return expiresAt != null && expiresAt.isBefore(Instant.now()); } public boolean isRemoved() { return removedBy != null; } - public String getAccessDenialReason() { - String accessDenialReason = "Your ip address has been suspended from the MineHQ Network. \n\n"; + // TODO: CLEANUP + public void getAccessDenialReason(SingleResultCallback callback) { + Punishment.findByLinkedIpBanId(id, (punishment, error) -> { + if (error != null) { + callback.onResult(null, error); + return; + } - if (getExpiresAt() != null) { - accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), new Date())); - } else { - accessDenialReason += "Appeal at MineHQ.com/appeal"; - } + if (punishment != null) { + User.findById(punishment.getUser(), (user, error2) -> { + if (error2 != null) { + callback.onResult(null, error2); + return; + } - return accessDenialReason; + 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"; + } + + 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); + } + }); } public void insert() { @@ -150,7 +164,7 @@ public final class IpBan { public void delete(User removedBy, String reason) { this.removedBy = removedBy.getId(); - this.removedAt = new Date(); + this.removedAt = Instant.now(); this.removalReason = reason; BlockingCallback callback = new BlockingCallback<>(); diff --git a/src/main/java/net/frozenorb/apiv3/model/IpIntel.java b/src/main/java/net/frozenorb/apiv3/model/IpIntel.java new file mode 100644 index 0000000..1dc550b --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/model/IpIntel.java @@ -0,0 +1,74 @@ +package net.frozenorb.apiv3.model; + +import com.mongodb.async.SingleResultCallback; +import com.mongodb.async.client.MongoCollection; +import fr.javatic.mongo.jacksonCodec.Entity; +import fr.javatic.mongo.jacksonCodec.objectId.Id; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.maxmind.MaxMindResult; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Entity +@AllArgsConstructor +public final class IpIntel { + + private static final MongoCollection ipIntelCollection = APIv3.getDatabase().getCollection("ipIntel", IpIntel.class); + + @Getter @Id private String id; + @Getter private Instant lastUpdatedAt; + @Getter private MaxMindResult result; + + public static void findAll(SingleResultCallback> callback) { + ipIntelCollection.find().sort(new Document("lastSeenAt", -1)).into(new ArrayList<>(), callback); + } + + public static void findById(String id, SingleResultCallback callback) { + ipIntelCollection.find(new Document("_id", id)).first(callback); + } + + public static void findByIdOrInsert(String id, SingleResultCallback callback) { + findById(id, (existingIpIntel, error) -> { + if (error != null) { + callback.onResult(null, error); + } else if (existingIpIntel != null) { + callback.onResult(existingIpIntel, null); + } else { + MaxMindUtils.getInsights(id, (maxMindResult, error2) -> { + if (error2 != null) { + callback.onResult(null, error2); + } else { + IpIntel newIpIntel = new IpIntel(id, maxMindResult); + + newIpIntel.insert((ignored, error3) -> { + if (error3 != null) { + callback.onResult(null, error3); + } else { + callback.onResult(newIpIntel, null); + } + }); + } + }); + } + }); + } + + public IpIntel() {} // For Jackson + + public 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 94f805c..4620e10 100644 --- a/src/main/java/net/frozenorb/apiv3/model/IpLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/model/IpLogEntry.java @@ -13,8 +13,8 @@ import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import org.bson.types.ObjectId; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.UUID; @@ -27,8 +27,8 @@ public final class IpLogEntry { @Getter @Id private String id; @Getter private UUID user; @Getter private String userIp; - @Getter private Date firstSeenAt; - @Getter private Date lastSeenAt; + @Getter private Instant firstSeenAt; + @Getter private Instant lastSeenAt; @Getter private int uses; public static List findAllSync() { @@ -79,19 +79,19 @@ public final class IpLogEntry { ipLogCollection.find(new Document("user", user).append("userIp", userIp)).first(callback); } - public IpLogEntry() {} // For Morphia + public IpLogEntry() {} // For Jackson public IpLogEntry(User user, String userIp) { this.id = new ObjectId().toString(); this.user = user.getId(); this.userIp = userIp; - this.firstSeenAt = new Date(); - this.lastSeenAt = new Date(); + this.firstSeenAt = Instant.now(); + this.lastSeenAt = Instant.now(); this.uses = 0; } public void used() { - this.lastSeenAt = new Date(); + this.lastSeenAt = Instant.now(); this.uses++; } diff --git a/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java index fb748d6..2dc96b9 100644 --- a/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/model/NotificationTemplate.java @@ -3,7 +3,6 @@ package net.frozenorb.apiv3.model; import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; -import com.mongodb.client.result.UpdateResult; import fr.javatic.mongo.jacksonCodec.Entity; import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.Getter; @@ -26,10 +25,6 @@ public final class NotificationTemplate { @Getter @Setter private String subject; @Getter @Setter private String body; - public static List findAllSync() { - return SyncUtils.blockMulti(notificationTemplatesCollection.find()); - } - public static NotificationTemplate findByIdSync(String id) { return SyncUtils.blockOne(notificationTemplatesCollection.find(new Document("_id", id))); } @@ -42,7 +37,7 @@ public final class NotificationTemplate { notificationTemplatesCollection.find(new Document("_id", id)).first(callback); } - public NotificationTemplate() {} // For Morphia + public NotificationTemplate() {} // For Jackson public NotificationTemplate(String id, String subject, String body) { this.id = id; @@ -75,12 +70,6 @@ public final class NotificationTemplate { callback.get(); } - public void save() { - BlockingCallback callback = new BlockingCallback<>(); - notificationTemplatesCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); - } - public void delete() { BlockingCallback callback = new BlockingCallback<>(); notificationTemplatesCollection.deleteOne(new Document("_id", id), callback); diff --git a/src/main/java/net/frozenorb/apiv3/model/Punishment.java b/src/main/java/net/frozenorb/apiv3/model/Punishment.java index 4b80d74..e6f15f7 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Punishment.java +++ b/src/main/java/net/frozenorb/apiv3/model/Punishment.java @@ -16,6 +16,7 @@ import net.frozenorb.apiv3.util.TimeUtils; import org.bson.Document; import org.bson.types.ObjectId; +import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @@ -29,27 +30,19 @@ public final class Punishment { @Getter private UUID user; @Getter private String reason; @Getter private PunishmentType type; - @Getter private Date expiresAt; + @Getter private Instant expiresAt; @Getter private Map metadata; @Getter private String linkedIpBanId; @Getter private UUID addedBy; - @Getter private Date addedAt; + @Getter private Instant addedAt; @Getter private String actorName; @Getter private ActorType actorType; @Getter private UUID removedBy; - @Getter private Date removedAt; + @Getter private Instant removedAt; @Getter private String removalReason; - public static List findAllSync() { - return SyncUtils.blockMulti(punishmentsCollection.find().sort(new Document("addedAt", -1))); - } - - public static List findAllPaginatedSync(int skip, int pageSize) { - return SyncUtils.blockMulti(punishmentsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize)); - } - public static List findByTypeSync(Collection types) { Collection convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList()); return SyncUtils.blockMulti(punishmentsCollection.find(new Document("type", new Document("$in", convertedTypes)))); @@ -76,23 +69,18 @@ public final class Punishment { return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", convertedTypes)))); } - public static void findAll(SingleResultCallback> callback) { - punishmentsCollection.find().sort(new Document("addedAt", -1)).into(new ArrayList<>(), callback); - } - public static void findAllPaginated(int skip, int pageSize, SingleResultCallback> callback) { punishmentsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback); } - public static void findByType(Collection types, SingleResultCallback> callback) { - Collection convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList()); - punishmentsCollection.find(new Document("type", new Document("$in", convertedTypes))).into(new ArrayList<>(), callback); - } - public static void findById(String id, SingleResultCallback callback) { punishmentsCollection.find(new Document("_id", id)).first(callback); } + public static void findByLinkedIpBanId(String id, SingleResultCallback callback) { + punishmentsCollection.find(new Document("linkedIpBanId", id)).first(callback); + } + public static void findByUser(User user, SingleResultCallback> callback) { findByUser(user.getId(), callback); } @@ -130,16 +118,16 @@ public final class Punishment { punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", convertedTypes))).into(new ArrayList<>(), callback); } - public Punishment() {} // For Morphia + public Punishment() {} // For Jackson - public Punishment(User user, String reason, PunishmentType type, Date expiresAt, User addedBy, Actor actor, Map metadata) { + public Punishment(User user, String reason, PunishmentType type, Instant expiresAt, User addedBy, Actor actor, Map metadata) { this.id = new ObjectId().toString(); this.user = user.getId(); this.reason = reason; this.type = type; this.expiresAt = expiresAt; this.addedBy = addedBy == null ? null : addedBy.getId(); - this.addedAt = new Date(); + this.addedAt = Instant.now(); this.actorName = actor.getName(); this.actorType = actor.getType(); this.metadata = metadata; @@ -150,11 +138,7 @@ public final class Punishment { } public boolean isExpired() { - if (expiresAt == null) { - return false; // Never expires - } else { - return expiresAt.before(new Date()); - } + return expiresAt != null && expiresAt.isBefore(Instant.now()); } public boolean isRemoved() { @@ -169,7 +153,7 @@ public final class Punishment { String accessDenialReason = "Your account has been suspended from the MineHQ Network. \n\n"; if (getExpiresAt() != null) { - accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), new Date())); + accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now())); } else { accessDenialReason += "Appeal at MineHQ.com/appeal"; } @@ -181,7 +165,7 @@ public final class Punishment { } public void linkIpBan(IpBan ipBan) { - + this.linkedIpBanId = ipBan.getId(); } public void insert() { @@ -192,7 +176,7 @@ public final class Punishment { public void delete(User removedBy, String reason) { this.removedBy = removedBy.getId(); - this.removedAt = new Date(); + this.removedAt = Instant.now(); this.removalReason = reason; if (linkedIpBanId != null) { diff --git a/src/main/java/net/frozenorb/apiv3/model/Rank.java b/src/main/java/net/frozenorb/apiv3/model/Rank.java index 44c9933..605b09c 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Rank.java +++ b/src/main/java/net/frozenorb/apiv3/model/Rank.java @@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.primitives.Ints; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; -import com.mongodb.client.result.UpdateResult; import fr.javatic.mongo.jacksonCodec.Entity; import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.Getter; @@ -45,7 +44,7 @@ public final class Rank { return rankCache.get(id); } - public Rank() {} // For Morphia + public Rank() {} // For Jackson public Rank(String id, int weight, String displayName, String gameColor, String websiteColor, boolean staffRank) { this.id = id; @@ -80,12 +79,6 @@ public final class Rank { callback.get(); } - public void save() { - BlockingCallback callback = new BlockingCallback<>(); - ranksCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); - } - public void delete() { BlockingCallback callback = new BlockingCallback<>(); ranksCollection.deleteOne(new Document("_id", id), callback); diff --git a/src/main/java/net/frozenorb/apiv3/model/Server.java b/src/main/java/net/frozenorb/apiv3/model/Server.java index 4cc11f3..411743b 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Server.java +++ b/src/main/java/net/frozenorb/apiv3/model/Server.java @@ -7,13 +7,13 @@ import com.mongodb.client.result.UpdateResult; import fr.javatic.mongo.jacksonCodec.Entity; import fr.javatic.mongo.jacksonCodec.objectId.Id; 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.SyncUtils; import org.bson.Document; +import java.time.Instant; import java.util.*; import java.util.concurrent.TimeUnit; @@ -31,9 +31,9 @@ public final class Server { @Getter @ExcludeFromReplies String apiKey; @Getter private String serverGroup; @Getter private String serverIp; - @Getter @Setter private Date lastUpdatedAt; - @Getter @Setter private double lastTps; - @Getter @Setter @ExcludeFromReplies private Set players; + @Getter private Instant lastUpdatedAt; + @Getter private double lastTps; + @Getter @ExcludeFromReplies private Set players; public static List findAll() { updateCacheIfNeeded(); @@ -45,7 +45,7 @@ public final class Server { return serverCache.get(id); } - public Server() {} // For Morphia + public Server() {} // For Jackson public Server(String id, String displayName, String apiKey, ServerGroup serverGroup, String serverIp) { this.id = id; @@ -53,7 +53,7 @@ public final class Server { this.apiKey = apiKey; this.serverGroup = serverGroup.getId(); this.serverIp = serverIp; - this.lastUpdatedAt = new Date(); + this.lastUpdatedAt = Instant.now(); this.lastTps = 0; this.players = new HashSet<>(); } @@ -75,7 +75,7 @@ public final class Server { } public void receivedHeartbeat(double tps, Iterable players) { - this.lastUpdatedAt = new Date(); + this.lastUpdatedAt = Instant.now(); this.lastTps = tps; this.players = ImmutableSet.copyOf(players); } diff --git a/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java b/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java index 6ca53b0..64bd245 100644 --- a/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java +++ b/src/main/java/net/frozenorb/apiv3/model/ServerGroup.java @@ -1,5 +1,6 @@ package net.frozenorb.apiv3.model; +import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.UpdateResult; @@ -28,10 +29,8 @@ public final class ServerGroup { @Getter @Id private String id; @Getter private String image; - // We define these HashSets up here because, in the event they're - // empty, Morphia will load them as null, not empty sets. - @Getter @Setter @ExcludeFromReplies private Set announcements = new HashSet<>(); - @Getter @Setter @ExcludeFromReplies private Map> permissions = new HashMap<>(); + @Getter @Setter @ExcludeFromReplies private Set announcements; + @Getter @Setter @ExcludeFromReplies private Map> permissions; // make this and other stuff async public static List findAll() { @@ -44,7 +43,7 @@ public final class ServerGroup { return serverGroupCache.get(id); } - public ServerGroup() {} // For Morphia + public ServerGroup() {} // For Jackson public ServerGroup(String id, String image) { this.id = id; @@ -77,10 +76,8 @@ public final class ServerGroup { callback.get(); } - public void save() { - BlockingCallback callback = new BlockingCallback<>(); + public void save(SingleResultCallback callback) { serverGroupsCollection.replaceOne(new Document("_id", id), this, callback); - callback.get(); } public void delete() { diff --git a/src/main/java/net/frozenorb/apiv3/model/User.java b/src/main/java/net/frozenorb/apiv3/model/User.java index 9a105a6..f34e1fc 100644 --- a/src/main/java/net/frozenorb/apiv3/model/User.java +++ b/src/main/java/net/frozenorb/apiv3/model/User.java @@ -18,15 +18,16 @@ import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; 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.serialization.jackson.UuidJsonDeserializer; +import net.frozenorb.apiv3.serialization.jackson.UuidJsonSerializer; import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.MojangUtils; import net.frozenorb.apiv3.util.PermissionUtils; import net.frozenorb.apiv3.util.SyncUtils; -import net.frozenorb.apiv3.util.UUIDUtils; +import net.frozenorb.apiv3.util.UuidUtils; import org.bson.Document; +import java.time.Instant; import java.util.*; @Entity @@ -35,30 +36,26 @@ public final class User { private static final MongoCollection usersCollection = APIv3.getDatabase().getCollection("users", User.class); - @Getter @Id @JsonSerialize(using=UUIDJsonSerializer.class) @JsonDeserialize(using=UUIDJsonDeserializer.class) private UUID id; + @Getter @Id @JsonSerialize(using=UuidJsonSerializer.class) @JsonDeserialize(using=UuidJsonDeserializer.class) private UUID id; @Getter private String lastUsername; - @Getter @ExcludeFromReplies private Map aliases = new HashMap<>(); + @Getter @ExcludeFromReplies private Map aliases = new HashMap<>(); @Getter @ExcludeFromReplies @Setter private String totpSecret; @Getter @ExcludeFromReplies @Setter private String emailToken; - @Getter @ExcludeFromReplies @Setter private Date emailTokenSetAt; + @Getter @ExcludeFromReplies @Setter private Instant emailTokenSetAt; @Getter @ExcludeFromReplies private String password; @Getter @Setter private String email; @Getter private String phoneNumber; @Getter private String lastSeenOn; - @Getter private Date lastSeenAt; - @Getter private Date firstSeenAt; + @Getter private Instant lastSeenAt; + @Getter private Instant firstSeenAt; @Getter private boolean online; - public static List findAllSync() { - return SyncUtils.blockMulti(usersCollection.find().sort(new Document("lastSeenAt", -1))); - } - public static User findByIdSync(String id) { UUID uuid; try { uuid = UUID.fromString(id); - } catch (IllegalArgumentException ex) { + } catch (NullPointerException | IllegalArgumentException ex) { return null; } @@ -66,13 +63,17 @@ public final class User { } public static User findByIdSync(UUID id) { - if (UUIDUtils.isAcceptableUUID(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))); } @@ -81,10 +82,6 @@ public final class User { return SyncUtils.blockOne(usersCollection.find(new Document("lastUsername", lastUsername))); } - public static void findAll(SingleResultCallback> callback) { - usersCollection.find().sort(new Document("lastSeenAt", -1)).into(new ArrayList<>(), callback); - } - public static void findById(String id, SingleResultCallback callback) { try { UUID uuid = UUID.fromString(id); @@ -95,7 +92,7 @@ public final class User { } public static void findById(UUID id, SingleResultCallback callback) { - if (UUIDUtils.isAcceptableUUID(id)) { + if (UuidUtils.isAcceptableUuid(id)) { usersCollection.find(new Document("_id", id)).first(callback); } else { callback.onResult(null, null); @@ -122,35 +119,31 @@ public final class User { }); } - 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 User() {} // For Morphia + 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.aliases = new HashMap<>(); - this.totpSecret = null; - this.password = null; - this.email = null; - this.phoneNumber = null; - this.lastSeenOn = null; - this.lastSeenAt = new Date(); - this.firstSeenAt = new Date(); + this.lastSeenAt = Instant.now(); + this.firstSeenAt = Instant.now(); - // TODO: MAKE THIS ASYNC? SOMEHOW? - BlockingCallback blockingCallback = new BlockingCallback<>(); - updateUsername(lastUsername, blockingCallback); - blockingCallback.get(); + updateUsername(lastUsername); } public boolean hasPermissionAnywhere(String permission) { + Map globalPermissions = getGlobalPermissions(); + return globalPermissions.containsKey(permission) && globalPermissions.get(permission); + } + + // TODO: ASYNC + public Map getGlobalPermissions() { Map globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankAnywhere()); for (Map.Entry serverGroupEntry : getHighestRanks().entrySet()) { @@ -163,7 +156,7 @@ public final class User { ); } - return globalPermissions.containsKey(permission) && globalPermissions.get(permission); + return ImmutableMap.copyOf(globalPermissions); } // TODO: Clean @@ -175,7 +168,7 @@ public final class User { this.lastSeenOn = server.getId(); if (!online) { - this.lastSeenAt = new Date(); + this.lastSeenAt = Instant.now(); } this.online = true; @@ -183,35 +176,24 @@ public final class User { } public void leftServer() { - this.lastSeenAt = new Date(); + this.lastSeenAt = Instant.now(); this.online = false; } - public void updateUsername(String newUsername, SingleResultCallback callback) { - this.aliases.put(newUsername, new Date()); + public void updateUsername(String newUsername) { + if (!newUsername.equals(lastUsername)) { + this.lastUsername = newUsername; - if (newUsername.equalsIgnoreCase(lastUsername)) { - callback.onResult(null, null); - return; + User withNewUsername; + + while ((withNewUsername = User.findByLastUsernameSync(newUsername)) != null) { + BlockingCallback callback = new BlockingCallback<>(); + MojangUtils.getName(withNewUsername.getId(), callback); + withNewUsername.updateUsername(callback.get()); + } } - this.lastUsername = newUsername; - - User.findByLastUsername(newUsername, (otherUser, error) -> { - if (error != null) { - callback.onResult(null, error); - } else if (otherUser != null) { - MojangUtils.getName(otherUser.getId(), (newName, error2) -> { - if (error2 != null) { - callback.onResult(null, error2); - } else { - otherUser.updateUsername(newName, callback); - } - }); - } else { - callback.onResult(null, null); - } - }); + this.aliases.put(newUsername, Instant.now()); } public void setPassword(String input) { @@ -231,11 +213,7 @@ public final class User { } public Rank getHighestRankAnywhere() { - return getHighestRankScoped(null); - } - - public Rank getHighestRankScoped(ServerGroup serverGroup) { - return getHighestRankScoped(serverGroup, Grant.findByUserSync(this)); + return getHighestRankScoped(null, Grant.findByUserSync(this)); } // TODO: Clean @@ -377,9 +355,14 @@ public final class User { "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", activeIpBan.getAccessDenialReason(), + "message", reason, "activeIpBanId", activeIpBan.getId() ); } diff --git a/src/main/java/net/frozenorb/apiv3/model/UserMetaEntry.java b/src/main/java/net/frozenorb/apiv3/model/UserMetaEntry.java index 4e6a40a..08aec82 100644 --- a/src/main/java/net/frozenorb/apiv3/model/UserMetaEntry.java +++ b/src/main/java/net/frozenorb/apiv3/model/UserMetaEntry.java @@ -1,7 +1,6 @@ package net.frozenorb.apiv3.model; import com.google.common.collect.ImmutableMap; -import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.UpdateResult; @@ -15,8 +14,6 @@ import net.frozenorb.apiv3.util.SyncUtils; import org.bson.Document; import org.bson.types.ObjectId; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.UUID; @@ -30,14 +27,6 @@ public final class UserMetaEntry { @Getter private String serverGroup; @Getter @Setter private Map data; - public static List findAllSync() { - return SyncUtils.blockMulti(userMetaCollection.find()); - } - - public static UserMetaEntry findByIdSync(String id) { - return SyncUtils.blockOne(userMetaCollection.find(new Document("_id", id))); - } - public static UserMetaEntry findByUserAndGroupSync(User user, ServerGroup serverGroup) { return findByUserAndGroupSync(user.getId(), serverGroup); } @@ -46,23 +35,7 @@ public final class UserMetaEntry { return SyncUtils.blockOne(userMetaCollection.find(new Document("user", user).append("serverGroup", serverGroup.getId()))); } - public static void findAll(SingleResultCallback> callback) { - userMetaCollection.find().into(new ArrayList<>(), callback); - } - - public static void findById(String id, SingleResultCallback callback) { - userMetaCollection.find(new Document("_id", id)).first(callback); - } - - public static void findByUserAndGroup(User user, ServerGroup serverGroup, SingleResultCallback callback) { - findByUserAndGroup(user.getId(), serverGroup, callback); - } - - public static void findByUserAndGroup(UUID user, ServerGroup serverGroup, SingleResultCallback callback) { - userMetaCollection.find(new Document("user", user).append("serverGroup", serverGroup.getId())).first(callback); - } - - public UserMetaEntry() {} // For Morphia + public UserMetaEntry() {} // For Jackson public UserMetaEntry(User user, ServerGroup serverGroup, Map data) { this.id = new ObjectId().toString(); diff --git a/src/main/java/net/frozenorb/apiv3/route/GETDump.java b/src/main/java/net/frozenorb/apiv3/route/GETDump.java index c972f87..d90c193 100644 --- a/src/main/java/net/frozenorb/apiv3/route/GETDump.java +++ b/src/main/java/net/frozenorb/apiv3/route/GETDump.java @@ -108,7 +108,6 @@ public final class GETDump implements Handler { return; default: ErrorUtils.respondInvalidInput(ctx, type + " is not a valid type. Not in [ban, blacklist, accessDeniable, grant]"); - return; } } diff --git a/src/main/java/net/frozenorb/apiv3/route/announcements/GETAnnouncements.java b/src/main/java/net/frozenorb/apiv3/route/announcements/GETAnnouncements.java index 85b6dc7..3d104ce 100644 --- a/src/main/java/net/frozenorb/apiv3/route/announcements/GETAnnouncements.java +++ b/src/main/java/net/frozenorb/apiv3/route/announcements/GETAnnouncements.java @@ -13,10 +13,9 @@ public final class GETAnnouncements implements Handler { if (serverGroup == null) { ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("id")); - return; + } else { + APIv3.respondJson(ctx, serverGroup.getAnnouncements()); } - - APIv3.respondJson(ctx, serverGroup.getAnnouncements()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/announcements/PUTAnnouncements.java b/src/main/java/net/frozenorb/apiv3/route/announcements/PUTAnnouncements.java index a6cd155..3fc9f67 100644 --- a/src/main/java/net/frozenorb/apiv3/route/announcements/PUTAnnouncements.java +++ b/src/main/java/net/frozenorb/apiv3/route/announcements/PUTAnnouncements.java @@ -16,18 +16,22 @@ public final class PUTAnnouncements implements Handler { if (serverGroup == null) { ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("id")); - return; + } else { + Set announcements = new HashSet<>(); + + for (Object announcement : ctx.getBodyAsJsonArray()) { + announcements.add((String) announcement); + } + + serverGroup.setAnnouncements(announcements); + serverGroup.save((ignored, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, serverGroup.getAnnouncements()); + } + }); } - - Set announcements = new HashSet<>(); - - for (Object announcement : ctx.getBodyAsJsonArray()) { - announcements.add((String) announcement); - } - - serverGroup.setAnnouncements(announcements); - serverGroup.save(); - APIv3.respondJson(ctx, serverGroup.getAnnouncements()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/auditLog/GETAuditLog.java b/src/main/java/net/frozenorb/apiv3/route/auditLog/GETAuditLog.java index d07cce2..6a93fec 100644 --- a/src/main/java/net/frozenorb/apiv3/route/auditLog/GETAuditLog.java +++ b/src/main/java/net/frozenorb/apiv3/route/auditLog/GETAuditLog.java @@ -13,7 +13,13 @@ public final class GETAuditLog implements Handler { int skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip")); int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize")); - APIv3.respondJson(ctx, AuditLogEntry.findAllPaginatedSync(skip, pageSize)); + AuditLogEntry.findAllPaginated(skip, pageSize, (auditLog, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, auditLog); + } + }); } catch (NumberFormatException ex) { ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs."); } diff --git a/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTUserAuditLogEntry.java b/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTUserAuditLogEntry.java index d449420..5c29e73 100644 --- a/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTUserAuditLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTUserAuditLogEntry.java @@ -5,9 +5,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; -import net.frozenorb.apiv3.model.AuditLogEntry; 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 org.bson.Document; @@ -15,33 +13,37 @@ import org.bson.Document; public final class POSTUserAuditLogEntry implements Handler { public void handle(RoutingContext ctx) { - User user = User.findByIdSync(ctx.request().getParam("id")); + 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 { + String userIp = ctx.request().getParam("userIp"); - if (user == null) { - ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); - return; - } + if (!IpUtils.isValidIp(userIp)) { + ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); + return; + } - String userIp = ctx.request().getParam("userIp"); + AuditLogActionType type; - if (!IpUtils.isValidIp(userIp)) { - ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); - return; - } + try { + type = AuditLogActionType.valueOf(ctx.request().getParam("type")); + } catch (IllegalArgumentException ex) { + ErrorUtils.respondNotFound(ctx, "Audit log action type", ctx.request().getParam("type")); + return; + } - AuditLogActionType type; - - try { - type = AuditLogActionType.valueOf(ctx.request().getParam("type")); - } catch (IllegalArgumentException ex) { - ErrorUtils.respondNotFound(ctx, "Audit log action type", ctx.request().getParam("type")); - return; - } - - BlockingCallback blockingCallback = new BlockingCallback<>(); - AuditLog.log(user, userIp, ctx.get("actor"), type, Document.parse(ctx.getBodyAsString()), blockingCallback); - AuditLogEntry entry = blockingCallback.get(); - APIv3.respondJson(ctx, entry); + AuditLog.log(user, userIp, ctx.get("actor"), type, Document.parse(ctx.getBodyAsString()), (auditLogEntry, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + APIv3.respondJson(ctx, auditLogEntry); + } + }); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/GETGrant.java b/src/main/java/net/frozenorb/apiv3/route/grants/GETGrant.java index 91588b2..9754ceb 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/GETGrant.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/GETGrant.java @@ -4,11 +4,18 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Grant; +import net.frozenorb.apiv3.util.ErrorUtils; public final class GETGrant implements Handler { public void handle(RoutingContext ctx) { - APIv3.respondJson(ctx, Grant.findByIdSync(ctx.request().getParam("id"))); + Grant.findById(ctx.request().getParam("id"), (grant, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, grant); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/GETGrants.java b/src/main/java/net/frozenorb/apiv3/route/grants/GETGrants.java index f7a2dc5..0af423b 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/GETGrants.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/GETGrants.java @@ -13,7 +13,13 @@ public final class GETGrants implements Handler { int skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip")); int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize")); - APIv3.respondJson(ctx, Grant.findAllPaginatedSync(skip, pageSize)); + Grant.findAllPaginated(skip, pageSize, (grants, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, grants); + } + }); } catch (NumberFormatException ex) { ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs."); } diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/GETUserGrants.java b/src/main/java/net/frozenorb/apiv3/route/grants/GETUserGrants.java index c78954b..110a671 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/GETUserGrants.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/GETUserGrants.java @@ -10,14 +10,21 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class GETUserGrants 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, Grant.findByUserSync(target)); + 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 { + Grant.findByUser(user, (grants, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + APIv3.respondJson(ctx, grants); + } + }); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/POSTUserGrant.java b/src/main/java/net/frozenorb/apiv3/route/grants/POSTUserGrant.java index f55e72f..770970a 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/POSTUserGrant.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/POSTUserGrant.java @@ -9,7 +9,7 @@ import net.frozenorb.apiv3.model.ServerGroup; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; -import java.util.Date; +import java.time.Instant; import java.util.HashSet; import java.util.Set; @@ -53,16 +53,16 @@ public final class POSTUserGrant implements Handler { return; } - Date expiresAt; + Instant expiresAt = null; try { - expiresAt = new Date(Long.parseLong(ctx.request().getParam("expiresAt"))); - } catch (NumberFormatException ex) { - expiresAt = null; + expiresAt = Instant.ofEpochMilli(Long.parseLong(ctx.request().getParam("expiresAt"))); + } catch (NumberFormatException ignored) { + // Just leave it null, we don't need an expiration date. } - if (expiresAt != null && expiresAt.before(new Date())) { - ErrorUtils.respondInvalidInput(ctx, "Expiration date cannot be in the past."); + if (expiresAt != null && expiresAt.isBefore(Instant.now())) { + ErrorUtils.respondInvalidInput(ctx, "Expiration time cannot be in the past."); return; } diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBan.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBan.java index bce6429..873bfac 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBan.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBan.java @@ -4,11 +4,18 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.IpBan; +import net.frozenorb.apiv3.util.ErrorUtils; public final class GETIpBan implements Handler { public void handle(RoutingContext ctx) { - APIv3.respondJson(ctx, IpBan.findByIdSync(ctx.request().getParam("id"))); + IpBan.findById(ctx.request().getParam("id"), (ipBan, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, ipBan); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java index 42e1ef8..ff605bd 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java @@ -13,7 +13,13 @@ public final class GETIpBans implements Handler { int skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip")); int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize")); - APIv3.respondJson(ctx, IpBan.findAllPaginatedSync(skip, pageSize)); + IpBan.findAllPaginated(skip, pageSize, (grants, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, grants); + } + }); } catch (NumberFormatException ex) { ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs."); } diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpIpBans.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpIpBans.java index d22664c..e5c1820 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpIpBans.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpIpBans.java @@ -17,7 +17,13 @@ public final class GETIpIpBans implements Handler { return; } - APIv3.respondJson(ctx, IpBan.findByIpSync(userIp)); + IpBan.findByIp(userIp, (ipBans, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, ipBans); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpIpBan.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpIpBan.java index d8d9105..7476d60 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpIpBan.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/POSTIpIpBan.java @@ -8,7 +8,7 @@ import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.IpUtils; -import java.util.Date; +import java.time.Instant; public final class POSTIpIpBan implements Handler { @@ -27,16 +27,16 @@ public final class POSTIpIpBan implements Handler { return; } - Date expiresAt; + Instant expiresAt = null; try { - expiresAt = new Date(Long.parseLong(ctx.request().getParam("expiresAt"))); - } catch (NumberFormatException ex) { - expiresAt = null; + expiresAt = Instant.ofEpochMilli(Long.parseLong(ctx.request().getParam("expiresAt"))); + } catch (NumberFormatException ignored) { + // Just leave it null, we don't need an expiration date. } - if (expiresAt != null && expiresAt.before(new Date())) { - ErrorUtils.respondInvalidInput(ctx, "Expiration date cannot be in the past."); + if (expiresAt != null && expiresAt.isBefore(Instant.now())) { + ErrorUtils.respondInvalidInput(ctx, "Expiration time cannot be in the past."); return; } diff --git a/src/main/java/net/frozenorb/apiv3/route/ipIntel/GETIPIntel.java b/src/main/java/net/frozenorb/apiv3/route/ipIntel/GETIPIntel.java new file mode 100644 index 0000000..2678e7f --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/route/ipIntel/GETIPIntel.java @@ -0,0 +1,29 @@ +package net.frozenorb.apiv3.route.ipIntel; + +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.model.IpIntel; +import net.frozenorb.apiv3.util.ErrorUtils; +import net.frozenorb.apiv3.util.IpUtils; + +public final class GETIpIntel implements Handler { + + public void handle(RoutingContext ctx) { + String userIp = ctx.request().getParam("id"); + + if (!IpUtils.isValidIp(userIp)) { + ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); + return; + } + + IpIntel.findByIdOrInsert(userIp, (ipIntel, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, ipIntel); + } + }); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/ipLog/GETUserIpLog.java b/src/main/java/net/frozenorb/apiv3/route/ipLog/GETUserIpLog.java index 6655259..19637f2 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipLog/GETUserIpLog.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipLog/GETUserIpLog.java @@ -10,14 +10,21 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class GETUserIpLog 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, IpLogEntry.findByUserSync(target)); + 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 { + IpLogEntry.findByUser(user, (ipLog, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + APIv3.respondJson(ctx, ipLog); + } + }); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplate.java index 1dc2d64..3874364 100644 --- a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplate.java @@ -4,11 +4,18 @@ 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.util.ErrorUtils; public final class GETNotificationTemplate implements Handler { public void handle(RoutingContext ctx) { - APIv3.respondJson(ctx, NotificationTemplate.findByIdSync(ctx.request().getParam("id"))); + NotificationTemplate.findById(ctx.request().getParam("id"), (notificationTemplate, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, notificationTemplate); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplates.java b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplates.java index 4bc315c..e8cb6b8 100644 --- a/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplates.java +++ b/src/main/java/net/frozenorb/apiv3/route/notificationTemplates/GETNotificationTemplates.java @@ -4,11 +4,18 @@ 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.util.ErrorUtils; public final class GETNotificationTemplates implements Handler { public void handle(RoutingContext ctx) { - APIv3.respondJson(ctx, NotificationTemplate.findAllSync()); + NotificationTemplate.findAll((notificationTemplates, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, notificationTemplates); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishment.java b/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishment.java index 876c091..756d2e8 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishment.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishment.java @@ -4,11 +4,18 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.Punishment; +import net.frozenorb.apiv3.util.ErrorUtils; public final class GETPunishment implements Handler { public void handle(RoutingContext ctx) { - APIv3.respondJson(ctx, Punishment.findByIdSync(ctx.request().getParam("id"))); + Punishment.findById(ctx.request().getParam("id"), (punishment, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, punishment); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishments.java b/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishments.java index ff07bc8..2bbc71e 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/GETPunishments.java @@ -13,7 +13,13 @@ public final class GETPunishments implements Handler { int skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip")); int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize")); - APIv3.respondJson(ctx, Punishment.findAllPaginatedSync(skip, pageSize)); + Punishment.findAllPaginated(skip, pageSize, (grants, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, grants); + } + }); } catch (NumberFormatException ex) { ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs."); } diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/GETUserPunishments.java b/src/main/java/net/frozenorb/apiv3/route/punishments/GETUserPunishments.java index a094b38..7fb06f4 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/GETUserPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/GETUserPunishments.java @@ -10,14 +10,21 @@ import net.frozenorb.apiv3.util.ErrorUtils; public final class GETUserPunishments 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, Punishment.findByUserSync(target)); + 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 { + Punishment.findByUser(user, (punishments, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + APIv3.respondJson(ctx, punishments); + } + }); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/POSTUserPunish.java b/src/main/java/net/frozenorb/apiv3/route/punishments/POSTUserPunish.java index 9e5354f..65dd99c 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/POSTUserPunish.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/POSTUserPunish.java @@ -12,7 +12,7 @@ import net.frozenorb.apiv3.unsorted.Permissions; import net.frozenorb.apiv3.util.ErrorUtils; import org.bson.Document; -import java.util.Date; +import java.time.Instant; import java.util.Map; public final class POSTUserPunish implements Handler { @@ -43,16 +43,16 @@ public final class POSTUserPunish implements Handler { } } - Date expiresAt; + Instant expiresAt = null; try { - expiresAt = new Date(Long.parseLong(ctx.request().getParam("expiresAt"))); - } catch (NumberFormatException ex) { - expiresAt = null; + expiresAt = Instant.ofEpochMilli(Long.parseLong(ctx.request().getParam("expiresAt"))); + } catch (NumberFormatException ignored) { + // Just leave it null, we don't need an expiration date. } - if (expiresAt != null && expiresAt.before(new Date())) { - ErrorUtils.respondInvalidInput(ctx, "Expiration date cannot be in the past."); + if (expiresAt != null && expiresAt.isBefore(Instant.now())) { + ErrorUtils.respondInvalidInput(ctx, "Expiration time cannot be in the past."); return; } @@ -73,7 +73,7 @@ public final class POSTUserPunish implements Handler { Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, ctx.get("actor"), meta); String accessDenialReason = punishment.getAccessDenialReason(); - String userIp = ctx.request().getParam("userIp"); + String userIp = ctx.request().getParam("playerIp"); // TODO: YELL AT GRIFFIN FOR THIS, IT SHOULD BE USERIP if (userIp != null) { IpBan ipBan = new IpBan(userIp, punishment); diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServerHeartbeat.java b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServerHeartbeat.java index 0ad2b64..baa664f 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServerHeartbeat.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServerHeartbeat.java @@ -13,10 +13,13 @@ import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.model.*; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.PermissionUtils; -import net.frozenorb.apiv3.util.UUIDUtils; +import net.frozenorb.apiv3.util.UuidUtils; import org.bson.Document; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; @Slf4j public final class POSTServerHeartbeat implements Handler { @@ -55,19 +58,17 @@ public final class POSTServerHeartbeat implements Handler { } // TODO: ASYNC (MAKE ALL SAVES/INSERTS/ETC USED HERE ASYNC - public Future createInfoResponse(Server server, double tps, Map playerNames) { + private Future createInfoResponse(Server server, double tps, Map playerNames) { Future callback = Future.future(); - server.setPlayers(playerNames.keySet()); - server.setLastTps(tps); - server.setLastUpdatedAt(new Date()); + server.receivedHeartbeat(tps, playerNames.keySet()); server.save(); callback.complete(); return callback; } - public Future> createPlayerResponse(Server server, Map playerNames) { + private Future> createPlayerResponse(Server server, Map playerNames) { Future> callback = Future.future(); Future> userLookupCallback = Future.future(); @@ -138,7 +139,7 @@ public final class POSTServerHeartbeat implements Handler { return callback; } - public Future> createPermissionsResponse(ServerGroup serverGroup) { + private Future> createPermissionsResponse(ServerGroup serverGroup) { Future> callback = Future.future(); Map permissionsResponse = new HashMap<>(); @@ -155,7 +156,7 @@ public final class POSTServerHeartbeat implements Handler { return callback; } - public Future> createEventsResponse(List eventsData) { + private Future> createEventsResponse(List eventsData) { Future> callback = Future.future(); for (Object event : eventsData) { @@ -178,7 +179,7 @@ public final class POSTServerHeartbeat implements Handler { return callback; } - public Map extractPlayerNames(Document reqJson) { + private Map extractPlayerNames(Document reqJson) { Map result = new HashMap<>(); for (Object player : (List) reqJson.get("players")) { @@ -186,7 +187,7 @@ public final class POSTServerHeartbeat implements Handler { UUID uuid = UUID.fromString(playerJson.getString("uuid")); String username = playerJson.getString("username"); - if (UUIDUtils.isAcceptableUUID(uuid)) { + if (UuidUtils.isAcceptableUuid(uuid)) { result.put(uuid, username); } } diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUser.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUser.java index 1323359..bbcee15 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUser.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUser.java @@ -4,11 +4,18 @@ 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.util.ErrorUtils; public final class GETUser implements Handler { public void handle(RoutingContext ctx) { - APIv3.respondJson(ctx, User.findByIdSync(ctx.request().getParam("id"))); + User.findById(ctx.request().getParam("id"), (user, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, user); + } + }); } } \ 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 new file mode 100644 index 0000000..bdd8ef6 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserPermissions.java @@ -0,0 +1,22 @@ +package net.frozenorb.apiv3.route.users; + +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.model.User; +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()); + } + +} \ 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 abc04f4..201830a 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUserRequiresTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserRequiresTOTP.java @@ -8,7 +8,7 @@ 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.TOTPUtils; +import net.frozenorb.apiv3.util.TotpUtils; public final class GETUserRequiresTOTP implements Handler { @@ -36,7 +36,7 @@ public final class GETUserRequiresTOTP implements Handler { } BlockingCallback preAuthorizedCallback = new BlockingCallback<>(); - TOTPUtils.isPreAuthorized(user, userIp, preAuthorizedCallback); + TotpUtils.isPreAuthorized(user, userIp, preAuthorizedCallback); if (preAuthorizedCallback.get()) { APIv3.respondJson(ctx, ImmutableMap.of( 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 5de1c1a..e365042 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUserVerifyPassword.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUserVerifyPassword.java @@ -12,6 +12,14 @@ public final class GETUserVerifyPassword implements Handler { public void handle(RoutingContext ctx) { User user = User.findByIdSync(ctx.request().getParam("id")); + if (user == null) { + user = User.findByLastUsernameSync(ctx.request().getParam("id")); + } + + if (user == null) { + user = User.findByEmailSync(ctx.request().getParam("id")); + } + if (user == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); return; diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserConfirmRegister.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserConfirmRegister.java index c71ec5f..366340f 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserConfirmRegister.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserConfirmRegister.java @@ -36,7 +36,7 @@ public final class POSTUserConfirmRegister implements Handler { return; } - if ((System.currentTimeMillis() - user.getEmailTokenSetAt().getTime()) > TimeUnit.DAYS.toMillis(2)) { + if ((System.currentTimeMillis() - user.getEmailTokenSetAt().toEpochMilli()) > TimeUnit.DAYS.toMillis(2)) { ErrorUtils.respondGeneric(ctx, 200, "Email token is expired"); return; } 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 359aac9..2786a34 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserLogin.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserLogin.java @@ -11,7 +11,7 @@ import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.IpUtils; -import net.frozenorb.apiv3.util.UUIDUtils; +import net.frozenorb.apiv3.util.UuidUtils; import java.util.UUID; @@ -20,11 +20,14 @@ public final class POSTUserLogin implements Handler { public void handle(RoutingContext ctx) { UUID uuid = UUID.fromString(ctx.request().getParam("id")); - if (!UUIDUtils.isAcceptableUUID(uuid)) { + if (!UuidUtils.isAcceptableUuid(uuid)) { ErrorUtils.respondInvalidInput(ctx, "UUID \"" + uuid + "\" is not valid - must be version 4 UUID."); return; } + User user = User.findByIdSync(uuid); + String username = ctx.request().getParam("username"); + String userIp = ctx.request().getParam("userIp"); Actor actor = ctx.get("actor"); Server server; @@ -39,52 +42,36 @@ public final class POSTUserLogin implements Handler { } } - String username = ctx.request().getParam("username"); - String userIp = ctx.request().getParam("userIp"); - if (!IpUtils.isValidIp(userIp)) { - ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); + ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); return; } - User.findById(uuid, (user, error) -> { + if (user == null) { + // Will be saved in the User constructor + user = new User(uuid, username); + } + + IpLogEntry ipLogEntry = IpLogEntry.findByUserAndIpSync(user, userIp); + + // 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(); + } else { + ipLogEntry.used(); + ipLogEntry.save(); + } + + user.updateUsername(username); + user.getLoginInfo(server, userIp, (loginInfo, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); - return; - } else if (user == null) { - user = new User(uuid, username); - user.insert(); // TODO + } else { + APIv3.respondJson(ctx, loginInfo); } - - User finalUser = user; - - IpLogEntry.findByUserAndIp(user, userIp, (ipLogEntry, error2) -> { - if (error2 != null) { - ErrorUtils.respondInternalError(ctx, error2); - return; - } else if (ipLogEntry == null) { - ipLogEntry = new IpLogEntry(finalUser, userIp); - ipLogEntry.used(); - ipLogEntry.insert(); //TODO - } else { - ipLogEntry.used(); - ipLogEntry.save(); // TODO - } - - finalUser.updateUsername(username, (ignored, error3) -> { - if (error3 != null) { - ErrorUtils.respondInternalError(ctx, error3); - } else { - finalUser.getLoginInfo(server, userIp, (loginInfo, error4) -> { - if (error4 != null) { - ErrorUtils.respondInternalError(ctx, error4); - } else { - APIv3.respondJson(ctx, loginInfo); - } - }); - } - }); - }); }); } 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 811cf77..93c50b6 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserRegister.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserRegister.java @@ -10,7 +10,7 @@ import net.frozenorb.apiv3.unsorted.Notification; import net.frozenorb.apiv3.util.ErrorUtils; import java.math.BigInteger; -import java.util.Date; +import java.time.Instant; import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -43,14 +43,14 @@ public final class POSTUserRegister implements Handler { return; } - if (user.getEmailToken() != null && (System.currentTimeMillis() - user.getEmailTokenSetAt().getTime()) < TimeUnit.DAYS.toMillis(2)) { + if (user.getEmailToken() != null && (System.currentTimeMillis() - user.getEmailTokenSetAt().toEpochMilli()) < TimeUnit.DAYS.toMillis(2)) { ErrorUtils.respondGeneric(ctx, 200, "We just recently sent you a confirmation email. Please wait before trying to register again."); return; } user.setEmail(email); user.setEmailToken(new BigInteger(130, new Random()).toString(32)); - user.setEmailTokenSetAt(new Date()); + user.setEmailTokenSetAt(Instant.now()); user.save(); Map replacements = ImmutableMap.of( 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 8135b7d..1d0ae19 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserSetupTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserSetupTOTP.java @@ -7,7 +7,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; -import net.frozenorb.apiv3.util.TOTPUtils; +import net.frozenorb.apiv3.util.TotpUtils; public final class POSTUserSetupTOTP implements Handler { @@ -24,13 +24,13 @@ public final class POSTUserSetupTOTP implements Handler { return; } - GoogleAuthenticatorKey generated = TOTPUtils.generateTOTPSecret(); + GoogleAuthenticatorKey generated = TotpUtils.generateTotpSecret(); user.setTotpSecret(generated.getKey()); user.save(); APIv3.respondJson(ctx, ImmutableMap.of( - "qrCode", TOTPUtils.getQRCodeURL(user, generated) + "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 72e0faf..1f3ab5e 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUserVerifyTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUserVerifyTOTP.java @@ -8,7 +8,7 @@ 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.TOTPUtils; +import net.frozenorb.apiv3.util.TotpUtils; import java.util.concurrent.TimeUnit; @@ -36,7 +36,7 @@ public final class POSTUserVerifyTOTP implements Handler { int providedCode = Integer.parseInt(ctx.request().getParam("code")); BlockingCallback recentlyUsedCallback = new BlockingCallback<>(); - TOTPUtils.wasRecentlyUsed(user, providedCode, recentlyUsedCallback); + TotpUtils.wasRecentlyUsed(user, providedCode, recentlyUsedCallback); if (recentlyUsedCallback.get()) { APIv3.respondJson(ctx, ImmutableMap.of( @@ -46,15 +46,15 @@ public final class POSTUserVerifyTOTP implements Handler { return; } - boolean authorized = TOTPUtils.authorizeUser(user, providedCode); + boolean authorized = TotpUtils.authorizeUser(user, providedCode); if (authorized) { BlockingCallback markPreAuthorizedCallback = new BlockingCallback<>(); - TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS, markPreAuthorizedCallback); + TotpUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS, markPreAuthorizedCallback); markPreAuthorizedCallback.get(); BlockingCallback markRecentlyUsedCallback = new BlockingCallback<>(); - TOTPUtils.markRecentlyUsed(user, providedCode, markRecentlyUsedCallback); + TotpUtils.markRecentlyUsed(user, providedCode, markRecentlyUsedCallback); markRecentlyUsedCallback.get(); APIv3.respondJson(ctx, ImmutableMap.of( diff --git a/src/main/java/net/frozenorb/apiv3/serialization/gson/DateTypeAdapter.java b/src/main/java/net/frozenorb/apiv3/serialization/gson/InstantTypeAdapter.java similarity index 64% rename from src/main/java/net/frozenorb/apiv3/serialization/gson/DateTypeAdapter.java rename to src/main/java/net/frozenorb/apiv3/serialization/gson/InstantTypeAdapter.java index 813a274..d53c6ea 100644 --- a/src/main/java/net/frozenorb/apiv3/serialization/gson/DateTypeAdapter.java +++ b/src/main/java/net/frozenorb/apiv3/serialization/gson/InstantTypeAdapter.java @@ -5,22 +5,22 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; -import java.util.Date; +import java.time.Instant; -public final class DateTypeAdapter extends TypeAdapter { +public final class InstantTypeAdapter extends TypeAdapter { - public void write(JsonWriter writer, Date write) throws IOException { + public void write(JsonWriter writer, Instant write) throws IOException { if (write == null) { writer.nullValue(); } else { - writer.value(write.getTime()); + writer.value(write.toEpochMilli()); } } // This is used with Gson, which is only used // to serialize outgoing responses, thus we // don't need to have a read method. - public Date read(JsonReader reader) { + public Instant read(JsonReader reader) { throw new IllegalArgumentException(); } diff --git a/src/main/java/net/frozenorb/apiv3/serialization/jackson/InstantJsonDeserializer.java b/src/main/java/net/frozenorb/apiv3/serialization/jackson/InstantJsonDeserializer.java new file mode 100644 index 0000000..ac464b3 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/serialization/jackson/InstantJsonDeserializer.java @@ -0,0 +1,18 @@ +package net.frozenorb.apiv3.serialization.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.time.Instant; + +public final class InstantJsonDeserializer extends JsonDeserializer { + + @Override + public Instant deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + return Instant.ofEpochMilli(jsonParser.getValueAsLong()); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/serialization/jackson/InstantJsonSerializer.java b/src/main/java/net/frozenorb/apiv3/serialization/jackson/InstantJsonSerializer.java new file mode 100644 index 0000000..2af3601 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/serialization/jackson/InstantJsonSerializer.java @@ -0,0 +1,18 @@ +package net.frozenorb.apiv3.serialization.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.time.Instant; + +public final class InstantJsonSerializer extends JsonSerializer { + + @Override + public void serialize(Instant instant, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + jsonGenerator.writeNumber(instant.toEpochMilli()); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonDeserializer.java b/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonDeserializer.java index 35c1af5..f086f8f 100644 --- a/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonDeserializer.java +++ b/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonDeserializer.java @@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; import java.util.UUID; -public class UUIDJsonDeserializer extends JsonDeserializer { +public final class UuidJsonDeserializer extends JsonDeserializer { @Override public UUID deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { diff --git a/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonSerializer.java b/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonSerializer.java index c81e401..6818f95 100644 --- a/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonSerializer.java +++ b/src/main/java/net/frozenorb/apiv3/serialization/jackson/UUIDJsonSerializer.java @@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.util.UUID; -public final class UUIDJsonSerializer extends JsonSerializer { +public final class UuidJsonSerializer extends JsonSerializer { @Override public void serialize(UUID uuid, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { diff --git a/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodec.java b/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodec.java index 211956b..2c3d949 100644 --- a/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodec.java +++ b/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodec.java @@ -8,7 +8,7 @@ import org.bson.codecs.EncoderContext; import java.util.UUID; -public final class UUIDCodec implements Codec { +public final class UuidCodec implements Codec { @Override public UUID decode(BsonReader bsonReader, DecoderContext decoderContext) { diff --git a/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodecProvider.java b/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodecProvider.java index b5bd0b8..afd0e9a 100644 --- a/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodecProvider.java +++ b/src/main/java/net/frozenorb/apiv3/serialization/mongodb/UUIDCodecProvider.java @@ -6,11 +6,11 @@ import org.bson.codecs.configuration.CodecRegistry; import java.util.UUID; -public final class UUIDCodecProvider implements CodecProvider { +public final class UuidCodecProvider implements CodecProvider { public Codec get(Class clazz, CodecRegistry codecRegistry) { if (clazz == UUID.class) { - return (Codec) new UUIDCodec(); + return (Codec) new UuidCodec(); } else { return null; } diff --git a/src/main/java/net/frozenorb/apiv3/unsorted/BugsnagSLF4JLogger.java b/src/main/java/net/frozenorb/apiv3/unsorted/BugsnagSLF4JLogger.java index f1574c6..2aba341 100644 --- a/src/main/java/net/frozenorb/apiv3/unsorted/BugsnagSLF4JLogger.java +++ b/src/main/java/net/frozenorb/apiv3/unsorted/BugsnagSLF4JLogger.java @@ -4,7 +4,7 @@ import com.bugsnag.Logger; import lombok.extern.slf4j.Slf4j; @Slf4j -public class BugsnagSLF4JLogger extends Logger { +public class BugsnagSlf4jLogger extends Logger { public void debug(String message) { log.debug(message); diff --git a/src/main/java/net/frozenorb/apiv3/util/ErrorUtils.java b/src/main/java/net/frozenorb/apiv3/util/ErrorUtils.java index ebb7dbd..254102f 100644 --- a/src/main/java/net/frozenorb/apiv3/util/ErrorUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/ErrorUtils.java @@ -21,6 +21,7 @@ public class ErrorUtils { } public static void respondInternalError(RoutingContext ctx, Throwable error) { + error.printStackTrace(); respondGeneric(ctx, 500, "Internal error: " + error.getClass().getSimpleName()); } diff --git a/src/main/java/net/frozenorb/apiv3/util/MaxMindUtils.java b/src/main/java/net/frozenorb/apiv3/util/MaxMindUtils.java new file mode 100644 index 0000000..729e9c5 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/util/MaxMindUtils.java @@ -0,0 +1,37 @@ +package net.frozenorb.apiv3.util; + +import com.google.common.base.Charsets; +import com.mongodb.async.SingleResultCallback; +import lombok.experimental.UtilityClass; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.maxmind.MaxMindResult; +import org.bson.Document; + +import java.util.Base64; +import java.util.Map; + +@UtilityClass +public class MaxMindUtils { + + private static final String maxMindUserId = APIv3.getConfig().getProperty("maxMind.userId"); + private static final String maxMindLicenseKey = APIv3.getConfig().getProperty("maxMind.maxMindLicenseKey"); + + public static void getInsights(String ip, SingleResultCallback callback) { + // We have to specifically use getHttpSClient(), vertx's http client is dumb. + APIv3.getHttpsClient().get(443, "geoip.maxmind.com", "/geoip/v2.1/insights/" + ip, (response) -> { + response.bodyHandler((body) -> { + Document resJson = Document.parse(body.toString()); + callback.onResult(new MaxMindResult(resJson), null); + }); + + response.exceptionHandler((error) -> { + callback.onResult(null, error); + }); + }).putHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString((maxMindUserId + ":" + maxMindLicenseKey).getBytes(Charsets.UTF_8))).end(); + } + + public static String getEnglishName(Document source) { + return ((Map) source.get("names")).get("en"); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/util/MojangUtils.java b/src/main/java/net/frozenorb/apiv3/util/MojangUtils.java index b37e4d1..9b554f8 100644 --- a/src/main/java/net/frozenorb/apiv3/util/MojangUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/MojangUtils.java @@ -12,7 +12,7 @@ import java.util.UUID; public class MojangUtils { public static void getName(UUID id, SingleResultCallback callback) { - APIv3.getHttpClient().get("sessionserver.mojang.com", "session/minecraft/profile/" + id.toString().replace("-", ""), (response) -> { + APIv3.getHttpClient().get("sessionserver.mojang.com", "/session/minecraft/profile/" + id.toString().replace("-", ""), (response) -> { response.bodyHandler((body) -> { Document resJson = Document.parse(body.toString()); String name = resJson.getString("name"); diff --git a/src/main/java/net/frozenorb/apiv3/util/TOTPUtils.java b/src/main/java/net/frozenorb/apiv3/util/TOTPUtils.java index 9c29844..42c81ac 100644 --- a/src/main/java/net/frozenorb/apiv3/util/TOTPUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/TOTPUtils.java @@ -12,11 +12,11 @@ import net.frozenorb.apiv3.model.User; import java.util.concurrent.TimeUnit; @UtilityClass -public class TOTPUtils { +public class TotpUtils { private static GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator(new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().setWindowSize(10).build()); - public static GoogleAuthenticatorKey generateTOTPSecret() { + public static GoogleAuthenticatorKey generateTotpSecret() { return googleAuthenticator.createCredentials(); } @@ -24,7 +24,7 @@ public class TOTPUtils { return googleAuthenticator.authorize(user.getTotpSecret(), code); } - public static String getQRCodeURL(User user, GoogleAuthenticatorKey secret) { + public static String getQrCodeUrl(User user, GoogleAuthenticatorKey secret) { return GoogleAuthenticatorQRGenerator.getOtpAuthURL( "MineHQ Network", user.getLastUsername(), diff --git a/src/main/java/net/frozenorb/apiv3/util/TimeUtils.java b/src/main/java/net/frozenorb/apiv3/util/TimeUtils.java index 2d4228e..0ce40de 100644 --- a/src/main/java/net/frozenorb/apiv3/util/TimeUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/TimeUtils.java @@ -2,7 +2,7 @@ package net.frozenorb.apiv3.util; import lombok.experimental.UtilityClass; -import java.util.Date; +import java.time.Instant; @UtilityClass public class TimeUtils { @@ -27,8 +27,8 @@ public class TimeUtils { return (fDays + fHours + fMinutes + fSeconds).trim(); } - public static int getSecondsBetween(Date a, Date b) { - return (Math.abs((int) (a.getTime() - b.getTime()) / 1000)); + public static int getSecondsBetween(Instant a, Instant b) { + return (Math.abs((int) (a.toEpochMilli() - b.toEpochMilli()) / 1000)); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/util/UUIDUtils.java b/src/main/java/net/frozenorb/apiv3/util/UUIDUtils.java index 01529ef..ce0af79 100644 --- a/src/main/java/net/frozenorb/apiv3/util/UUIDUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/UUIDUtils.java @@ -5,9 +5,9 @@ import lombok.experimental.UtilityClass; import java.util.UUID; @UtilityClass -public class UUIDUtils { +public class UuidUtils { - public static boolean isAcceptableUUID(UUID uuid) { + public static boolean isAcceptableUuid(UUID uuid) { return uuid.version() == 4; }