diff --git a/apiv3.properties b/apiv3.properties
index e307d26..74192b2 100644
--- a/apiv3.properties
+++ b/apiv3.properties
@@ -1,6 +1,4 @@
general.releaseStage=production
-logging.level=info
-logging.debug=true
mongo.address=localhost
mongo.port=27017
mongo.database=MineHQ
@@ -13,6 +11,5 @@ twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
bugsnag.apiKey=0e47fba8b825416b7cbc839066184509
-auth.permittedUserRanks=developer,owner
auth.websiteApiKey=RVbp4hY6sCFVaf
auth.bungeeCordApiKey=6d9cf76dc9f0d23
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 2ce866f..729b473 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,10 @@
minehq-repo
http://maven.minehq.com:8081/artifactory/minehq-all/
+
+ mongo-jackson-codec-repo
+ https://dl.bintray.com/ylemoigne/maven
+
@@ -62,12 +66,17 @@
io.vertx
vertx-core
- LATEST
+ 3.2.1
io.vertx
vertx-web
- LATEST
+ 3.2.1
+
+
+ io.vertx
+ vertx-redis-client
+ 3.2.1
@@ -89,16 +98,14 @@
3.0.4
- eu.dozd
- mongo-mapper
- 1.0.1
+ fr.javatic.mongo
+ mongo-jackson-codec
+ 3.2.0__0.4
-
-
- redis.clients
- jedis
- 2.8.1
+ de.undercouch
+ bson4jackson
+ 2.6.0
diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java
index a82c07c..08a02e2 100644
--- a/src/main/java/net/frozenorb/apiv3/APIv3.java
+++ b/src/main/java/net/frozenorb/apiv3/APIv3.java
@@ -1,39 +1,50 @@
package net.frozenorb.apiv3;
import com.bugsnag.Client;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mongodb.Block;
+import com.mongodb.ConnectionString;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.async.client.MongoClient;
import com.mongodb.async.client.MongoClientSettings;
import com.mongodb.async.client.MongoClients;
import com.mongodb.async.client.MongoDatabase;
+import com.mongodb.connection.ClusterConnectionMode;
import com.mongodb.connection.ClusterSettings;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.timgroup.statsd.StatsDClient;
-import eu.dozd.mongo.MongoMapper;
+import fr.javatic.mongo.jacksonCodec.JacksonCodecProvider;
+import fr.javatic.mongo.jacksonCodec.ObjectMapperFactory;
import io.vertx.core.AbstractVerticle;
+import io.vertx.core.Handler;
+import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpServer;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.LoggerHandler;
+import io.vertx.ext.web.impl.BlockingHandlerDecorator;
+import io.vertx.ext.web.impl.RouteImpl;
+import io.vertx.redis.RedisClient;
+import io.vertx.redis.RedisOptions;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.actors.ActorType;
-import net.frozenorb.apiv3.filters.ActorAttributeFilter;
-import net.frozenorb.apiv3.filters.AuthorizationFilter;
-import net.frozenorb.apiv3.filters.MetricsHandler;
-import net.frozenorb.apiv3.models.Grant;
-import net.frozenorb.apiv3.models.IPLogEntry;
-import net.frozenorb.apiv3.models.Punishment;
-import net.frozenorb.apiv3.models.User;
+import net.frozenorb.apiv3.handlers.ActorAttributeHandler;
+import net.frozenorb.apiv3.handlers.AuthorizationHandler;
+import net.frozenorb.apiv3.handlers.MetricsHandler;
+import net.frozenorb.apiv3.models.*;
import net.frozenorb.apiv3.routes.GETDump;
import net.frozenorb.apiv3.routes.GETWhoAmI;
import net.frozenorb.apiv3.routes.POSTMetrics;
@@ -57,19 +68,23 @@ import net.frozenorb.apiv3.routes.serverGroups.GETServerGroups;
import net.frozenorb.apiv3.routes.serverGroups.POSTServerGroup;
import net.frozenorb.apiv3.routes.servers.*;
import net.frozenorb.apiv3.routes.users.*;
-import net.frozenorb.apiv3.serialization.DateTypeAdapter;
-import net.frozenorb.apiv3.serialization.FollowAnnotationExclusionStrategy;
-import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
+import net.frozenorb.apiv3.serialization.*;
+import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger;
import net.frozenorb.apiv3.utils.IPUtils;
+import net.frozenorb.apiv3.utils.SyncUtils;
import net.frozenorb.apiv3.utils.UUIDUtils;
import org.bson.Document;
+import org.bson.codecs.BsonValueCodecProvider;
+import org.bson.codecs.DocumentCodecProvider;
+import org.bson.codecs.ValueCodecProvider;
+import org.bson.codecs.configuration.CodecProvider;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.types.ObjectId;
-import redis.clients.jedis.JedisPool;
import java.io.FileInputStream;
import java.io.InputStream;
+import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -80,26 +95,27 @@ public final class APIv3 extends AbstractVerticle {
@Getter private static HttpClient httpClient;
@Getter private static MongoDatabase database;
@Getter private static Properties config = new Properties();
- @Getter private static JedisPool redisPool;
+ @Getter private static RedisClient redisClient;
@Getter private static StatsDClient statsD;
+ @Getter private static Vertx vertxInstance;
@Getter private static final Gson gson = new GsonBuilder()
- .registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter())
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
.create();
@Override
public void start() {
- setupConfig();
- System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", config.getProperty("logging.level"));
+ vertxInstance = vertx;
+ setupConfig();
setupDatabase();
setupRedis();
setupMetrics();
setupBugsnag();
- setupHttpServer();
+ //setupHttpServer();
+ setupHttpClient();
- //convertData("158.69.126.126", true);
+ convertData("mongodb://158.69.126.126", true);
}
private void setupConfig() {
@@ -125,18 +141,37 @@ public final class APIv3 extends AbstractVerticle {
ClusterSettings clusterSettings = ClusterSettings
.builder()
- .hosts(ImmutableList.of(
- new ServerAddress(
- config.getProperty("mongo.address"),
- Integer.parseInt(config.getProperty("mongo.port"))
- )
- ))
+ .applyConnectionString(new ConnectionString("mongodb://" + config.getProperty("mongo.address") + ":" + config.getProperty("mongo.port")))
.build();
+
+ List providers = new ArrayList<>();
+
+ // Our override codec
+ providers.add(new MineHQCodecProvider());
+
+ // Normal providers
+ providers.add(new ValueCodecProvider());
+ providers.add(new DocumentCodecProvider());
+ providers.add(new BsonValueCodecProvider());
+
+ ObjectMapper objectMapper = ObjectMapperFactory.createObjectMapper();
+ SimpleModule simpleModule = new SimpleModule();
+
+ simpleModule.addSerializer(UUID.class, new UUIDJsonSerializer());
+ simpleModule.addDeserializer(UUID.class, new UUIDJsonDeserializer());
+
+ objectMapper.registerModule(simpleModule);
+ objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
+ objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
+ objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ providers.add(new JacksonCodecProvider(objectMapper));
+
MongoClientSettings settings = MongoClientSettings
.builder()
- .codecRegistry(CodecRegistries.fromProviders(MongoMapper.getProviders()))
+ .codecRegistry(CodecRegistries.fromProviders(providers))
.credentialList(credentials)
- .clusterSettings(clusterSettings).build();
+ .clusterSettings(clusterSettings)
+ .build();
MongoClient client = MongoClients.create(settings);
database = client.getDatabase(config.getProperty("mongo.database"));
@@ -144,9 +179,11 @@ public final class APIv3 extends AbstractVerticle {
}
private void setupRedis() {
- redisPool = new JedisPool(
- config.getProperty("redis.address"),
- Integer.parseInt(config.getProperty("redis.port"))
+ redisClient = RedisClient.create(
+ vertx,
+ new RedisOptions()
+ .setAddress(config.getProperty("redis.address"))
+ .setPort(Integer.parseInt(config.getProperty("redis.port")))
);
}
@@ -176,8 +213,8 @@ public final class APIv3 extends AbstractVerticle {
Router mainRouter = Router.router(vertx);
mainRouter.route().handler(new MetricsHandler());
- mainRouter.route().handler(new ActorAttributeFilter());
- mainRouter.route().handler(new AuthorizationFilter());
+ mainRouter.route().handler(new ActorAttributeHandler());
+ mainRouter.route().handler(new AuthorizationHandler());
mainRouter.route().handler(LoggerHandler.create());
mainRouter.route().handler(BodyHandler.create());
@@ -218,7 +255,7 @@ public final class APIv3 extends AbstractVerticle {
mainRouter.get("/server/:id").blockingHandler(new GETServer());
mainRouter.get("/servers").blockingHandler(new GETServers());
- mainRouter.post("/server/heartbeat").blockingHandler(new POSTServerHeartbeat());
+ mainRouter.post("/server/heartbeat").handler(new POSTServerHeartbeat());
mainRouter.post("/server").blockingHandler(new POSTServer());
//put("/server/:id").blockingHandler(new PUTServer());
mainRouter.delete("/server/:id").blockingHandler(new DELETEServer());
@@ -246,7 +283,22 @@ public final class APIv3 extends AbstractVerticle {
mainRouter.delete("/user/:id/punishment").blockingHandler(new DELETEUserPunishment());
mainRouter.getRoutes().forEach((route) -> {
- System.out.println(route.getClass() + "||" + route.getPath());
+ try {
+ RouteImpl impl = (RouteImpl) route;
+ Field field = RouteImpl.class.getDeclaredField("contextHandler");
+ field.setAccessible(true);
+ Handler handler = (Handler) field.get(impl);
+
+ if (handler instanceof BlockingHandlerDecorator) {
+ field = BlockingHandlerDecorator.class.getDeclaredField("decoratedHandler");
+ field.setAccessible(true);
+ handler = (Handler) field.get(handler);
+ }
+
+ System.out.println(route.getPath() + " is handled by " + handler.getClass());
+ } catch (Exception ex) {
+
+ }
});
int port = Integer.parseInt(config.getProperty("http.port"));
@@ -276,174 +328,156 @@ public final class APIv3 extends AbstractVerticle {
AtomicInteger skippedGrants = new AtomicInteger();
AtomicInteger skippedIpLogs = new AtomicInteger();
- importFrom.getCollection("user").find().forEach(new Block() {
+ SyncUtils.blockMulti(importFrom.getCollection("user").find()).forEach((user) -> {
+ String uuidString = String.valueOf(user.get("uuid"));
- @Override
- public void apply(Document user) {
- String uuidString = String.valueOf(user.get("uuid"));
-
- if (uuidString == null || uuidString.length() != 32) {
- return;
- }
-
- 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)) {
- skippedUsers.incrementAndGet();
- return;
- }
-
- mongoIdToUUID.put(user.getObjectId("_id"), uuid);
-
- User created = new User(
- uuid,
- String.valueOf(user.get("name")).toString(),
- ImmutableMap.of(),
- null,
- null,
- null,
- null,
- user.getString("email"),
- user.getString("phone"),
- "INVALID",
- user.getDate("joined"),
- user.getDate("joined"),
- false
- );
-
- if (forReal) {
- created.insert();
- }
-
- log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
+ if (uuidString == null || uuidString.length() != 32) {
+ return;
}
- }, (a, b) -> {});
- importFrom.getCollection("punishment").find().forEach(new 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"));
- @Override
- public void apply(Document punishment) {
- UUID target = mongoIdToUUID.get(((DBRef) punishment.get("user")).getId());
-
- if (target == null) {
- skippedPunishments.incrementAndGet();
- return;
- }
-
- // Old punishments have this value set to false to indicate they're not active anymore.
- if (punishment.containsKey("active") && !punishment.getBoolean("active")) {
- return;
- }
-
- com.mongodb.
-
- Punishment created = new Punishment(
- new ObjectId().toString(),
- target,
- punishment.getString("reason").toString(),
- Punishment.PunishmentType.valueOf(punishment.getString("type").toUpperCase()),
- punishment.getDate("expires"),
- punishment.containsKey("meta") ? (punishment.get("meta") instanceof List ? ImmutableMap.of() : (Document) punishment.get("meta")) : ImmutableMap.of(),
- punishment.containsKey("addedBy") ? mongoIdToUUID.get(((DBRef) punishment.get("addedBy")).getId()) : null,
- (Date) punishment.getDate("created").clone(),
- punishment.containsKey("createdOn") ? String.valueOf(((DBRef) punishment.get("createdOn")).getId()) : "Website",
- punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE,
- punishment.containsKey("removedBy") ? (((DBRef) punishment.get("removedBy")).getCollectionName().equals("user") ? mongoIdToUUID.get(((DBRef) punishment.get("removedBy")).getId()) : null) : null,
- punishment.getDate("created"),
- punishment.containsKey("removalReason") ? punishment.getString("removalReason").toString() : ""
- );
-
- if (forReal) {
- created.insert();
- }
-
- log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
+ if (!UUIDUtils.isAcceptableUUID(uuid)) {
+ skippedUsers.incrementAndGet();
+ return;
}
- }, (a, b) -> {});
- importFrom.getCollection("grant").find().forEach(new Block() {
+ mongoIdToUUID.put(user.getObjectId("_id"), uuid);
- @Override
- public void apply(Document grant) {
- UUID target = mongoIdToUUID.get(((DBRef) grant.get("target")).getId());
+ User created = new User(
+ uuid,
+ String.valueOf(user.get("name")).toString(),
+ ImmutableMap.of(user.getString("name"), user.getDate("joined")),
+ null,
+ null,
+ null,
+ null,
+ user.getString("email"),
+ user.getString("phone"),
+ "INVALID",
+ user.getDate("joined"),
+ user.getDate("joined"),
+ false
+ );
- if (target == null) {
- skippedGrants.incrementAndGet();
- return;
- }
-
- String rank = grant.getString("role");
-
- if (rank.equalsIgnoreCase("unban") || rank.equalsIgnoreCase("pass") || rank.equalsIgnoreCase("pink") || rank.equalsIgnoreCase("jrdev")) {
- return;
- } else if (rank.equalsIgnoreCase("high_roller")) {
- rank = "high-roller";
- } else if (rank.equalsIgnoreCase("dev")) {
- rank = "developer";
- }
-
- Grant created = new Grant(
- new ObjectId().toString(),
- target,
- grant.containsKey("comment") ? grant.getString("comment") : "",
- grant.containsKey("scope") ? ImmutableSet.copyOf((Collection) grant.get("scope")) : ImmutableSet.of(),
- rank,
- grant.getDate("expires"),
- grant.containsKey("addedBy") ? mongoIdToUUID.get(((DBRef) grant.get("addedBy")).getId()) : null,
- grant.containsKey("created") ? grant.getDate("created") : new Date(),
- null,
- null,
- null
- );
-
- if (forReal) {
- created.insert();
- }
-
- log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
+ if (forReal) {
+ created.insert();
}
- }, (a, b) -> {});
- importFrom.getCollection("iplog").find().forEach(new Block() {
+ log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
+ });
- @Override
- public void apply(Document ipLogEntry) {
- UUID user = mongoIdToUUID.get(((DBRef) ipLogEntry.get("user")).getId());
+ SyncUtils.blockMulti(importFrom.getCollection("punishment").find()).forEach((punishment) -> {
+ UUID target = mongoIdToUUID.get(((Map) punishment.get("user")).get("$id"));
- if (user == null || ipLogEntry.getString("ip") == null) {
- skippedIpLogs.incrementAndGet();
- return;
- }
-
- String ip = ipLogEntry.getString("ip").replace("/", "");
-
- if (!IPUtils.isValidIP(ip)) {
- return;
- }
-
- Date lastSeen = ipLogEntry.getDate("lastSeen");
-
- if (lastSeen == null) {
- lastSeen = new Date();
- }
-
- IPLogEntry created = new IPLogEntry(
- new ObjectId().toString(),
- user,
- ip,
- lastSeen,
- lastSeen,
- ((Number) ipLogEntry.get("uses")).intValue()
-
- );
-
- if (forReal) {
- created.insert();
- }
-
- log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
+ if (target == null) {
+ skippedPunishments.incrementAndGet();
+ return;
}
- }, (a, b) -> {});
+
+ // Old punishments have this value set to false to indicate they're not active anymore.
+ if (punishment.containsKey("active") && !punishment.getBoolean("active")) {
+ return;
+ }
+
+ Punishment created = new Punishment(
+ new ObjectId().toString(),
+ target,
+ punishment.getString("reason").toString(),
+ Punishment.PunishmentType.valueOf(punishment.getString("type").toUpperCase()),
+ punishment.getDate("expires"),
+ punishment.containsKey("meta") ? (punishment.get("meta") instanceof List ? ImmutableMap.of() : (Document) punishment.get("meta")) : ImmutableMap.of(),
+ punishment.containsKey("addedBy") ? mongoIdToUUID.get(((Map) punishment.get("addedBy")).get("$id")) : null,
+ (Date) punishment.getDate("created").clone(),
+ 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") ? mongoIdToUUID.get(((Map) punishment.get("removedBy")).get("$id")) : null) : null,
+ punishment.getDate("created"),
+ punishment.containsKey("removalReason") ? punishment.getString("removalReason").toString() : ""
+ );
+
+ if (forReal) {
+ created.insert();
+ }
+
+ log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
+ });
+
+ SyncUtils.blockMulti(importFrom.getCollection("grant").find()).forEach((grant) -> {
+ UUID target = mongoIdToUUID.get(((Map) grant.get("target")).get("$id"));
+
+ if (target == null) {
+ skippedGrants.incrementAndGet();
+ return;
+ }
+
+ String rank = grant.getString("role");
+
+ if (rank.equalsIgnoreCase("unban") || rank.equalsIgnoreCase("pass") || rank.equalsIgnoreCase("pink") || rank.equalsIgnoreCase("jrdev")) {
+ return;
+ } else if (rank.equalsIgnoreCase("high_roller")) {
+ rank = "high-roller";
+ } else if (rank.equalsIgnoreCase("dev")) {
+ rank = "developer";
+ }
+
+ Grant created = new Grant(
+ new ObjectId().toString(),
+ target,
+ grant.containsKey("comment") ? grant.getString("comment") : "",
+ grant.containsKey("scope") ? ImmutableSet.copyOf((Collection) grant.get("scope")) : ImmutableSet.of(),
+ rank,
+ grant.getDate("expires"),
+ grant.containsKey("addedBy") ? mongoIdToUUID.get(((Map) grant.get("addedBy")).get("$id")) : null,
+ grant.containsKey("created") ? grant.getDate("created") : new Date(),
+ null,
+ null,
+ null
+ );
+
+ if (forReal) {
+ created.insert();
+ }
+
+ log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
+ });
+
+ SyncUtils.blockMulti(importFrom.getCollection("iplog").find()).forEach((ipLogEntry) -> {
+ UUID user = mongoIdToUUID.get(((Map) ipLogEntry.get("user")).get("$id"));
+
+ if (user == null || ipLogEntry.getString("ip") == null) {
+ skippedIpLogs.incrementAndGet();
+ return;
+ }
+
+ String ip = ipLogEntry.getString("ip").replace("/", "");
+
+ if (!IPUtils.isValidIP(ip)) {
+ return;
+ }
+
+ Date lastSeen = ipLogEntry.getDate("lastSeen");
+
+ if (lastSeen == null) {
+ lastSeen = new Date();
+ }
+
+ IPLogEntry created = new IPLogEntry(
+ new ObjectId().toString(),
+ user,
+ ip,
+ lastSeen,
+ lastSeen,
+ ((Number) ipLogEntry.get("uses")).intValue()
+
+ );
+
+ if (forReal) {
+ created.insert();
+ }
+
+ log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
+ });
log.info("Skipped " + skippedUsers.get() + " users, " + skippedPunishments.get() + " punishments, " + skippedGrants.get() + " grants, and " + skippedIpLogs.get() + " ip logs");
}
diff --git a/src/main/java/net/frozenorb/apiv3/Main.java b/src/main/java/net/frozenorb/apiv3/Main.java
index 1c60617..d7b382a 100644
--- a/src/main/java/net/frozenorb/apiv3/Main.java
+++ b/src/main/java/net/frozenorb/apiv3/Main.java
@@ -5,6 +5,8 @@ import io.vertx.core.Vertx;
final class Main {
public static void main(String[] args) {
+ System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
+ System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
Vertx.vertx().deployVerticle(new APIv3());
}
diff --git a/src/main/java/net/frozenorb/apiv3/actors/BungeeCordActor.java b/src/main/java/net/frozenorb/apiv3/actors/BungeeCordActor.java
index aa4734d..c1fa682 100644
--- a/src/main/java/net/frozenorb/apiv3/actors/BungeeCordActor.java
+++ b/src/main/java/net/frozenorb/apiv3/actors/BungeeCordActor.java
@@ -2,14 +2,17 @@ package net.frozenorb.apiv3.actors;
public final class BungeeCordActor implements Actor {
+ @Override
public boolean isAuthorized() {
return true;
}
+ @Override
public String getName() {
return "BungeeCord";
}
+ @Override
public ActorType getType() {
return ActorType.BUNGEECORD;
}
diff --git a/src/main/java/net/frozenorb/apiv3/actors/ServerActor.java b/src/main/java/net/frozenorb/apiv3/actors/ServerActor.java
index 43a3411..07347d8 100644
--- a/src/main/java/net/frozenorb/apiv3/actors/ServerActor.java
+++ b/src/main/java/net/frozenorb/apiv3/actors/ServerActor.java
@@ -1,5 +1,6 @@
package net.frozenorb.apiv3.actors;
+import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.models.Server;
@@ -11,14 +12,17 @@ public final class ServerActor implements Actor {
this.server = server;
}
+ @Override
public boolean isAuthorized() {
return true;
}
+ @Override
public String getName() {
return server.getId();
}
+ @Override
public ActorType getType() {
return ActorType.SERVER;
}
diff --git a/src/main/java/net/frozenorb/apiv3/actors/UnknownActor.java b/src/main/java/net/frozenorb/apiv3/actors/UnknownActor.java
index 9d89614..e275a80 100644
--- a/src/main/java/net/frozenorb/apiv3/actors/UnknownActor.java
+++ b/src/main/java/net/frozenorb/apiv3/actors/UnknownActor.java
@@ -2,14 +2,17 @@ package net.frozenorb.apiv3.actors;
public final class UnknownActor implements Actor {
+ @Override
public boolean isAuthorized() {
return false;
}
+ @Override
public String getName() {
return "Unknown";
}
+ @Override
public ActorType getType() {
return ActorType.UNKNOWN;
}
diff --git a/src/main/java/net/frozenorb/apiv3/actors/UserActor.java b/src/main/java/net/frozenorb/apiv3/actors/UserActor.java
index 0da25d3..3873270 100644
--- a/src/main/java/net/frozenorb/apiv3/actors/UserActor.java
+++ b/src/main/java/net/frozenorb/apiv3/actors/UserActor.java
@@ -4,35 +4,40 @@ import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.models.User;
+import net.frozenorb.apiv3.unsorted.Permissions;
import java.util.Set;
public final class UserActor implements Actor {
- private static final Set permittedUserRanks = ImmutableSet.copyOf(APIv3.getConfig().getProperty("auth.permittedUserRanks").toLowerCase().split(","));
-
@Getter private final User user;
// We use Boolean here so we can have null = not calculated;
+ // Currently having this cached isn't important as we only check
+ // this once, but later on when we have non-logged in routes
+ // this will be important.
private Boolean cachedAuthorized = null;
public UserActor(User user) {
this.user = user;
}
+ @Override
public boolean isAuthorized() {
if (cachedAuthorized != null) {
return cachedAuthorized;
} else {
- String highestRankId = user.getHighestRankAnywhere().getId();
- cachedAuthorized = permittedUserRanks.contains(highestRankId.toLowerCase());
- return cachedAuthorized;
+ boolean authorized = user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST);
+ cachedAuthorized = authorized;
+ return authorized;
}
}
+ @Override
public String getName() {
return user.getLastUsername();
}
+ @Override
public ActorType getType() {
return ActorType.USER;
}
diff --git a/src/main/java/net/frozenorb/apiv3/actors/WebsiteActor.java b/src/main/java/net/frozenorb/apiv3/actors/WebsiteActor.java
index 939cf01..ae0e518 100644
--- a/src/main/java/net/frozenorb/apiv3/actors/WebsiteActor.java
+++ b/src/main/java/net/frozenorb/apiv3/actors/WebsiteActor.java
@@ -2,14 +2,17 @@ package net.frozenorb.apiv3.actors;
public final class WebsiteActor implements Actor {
+ @Override
public boolean isAuthorized() {
return true;
}
+ @Override
public String getName() {
return "Website";
}
+ @Override
public ActorType getType() {
return ActorType.WEBSITE;
}
diff --git a/src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java b/src/main/java/net/frozenorb/apiv3/handlers/ActorAttributeHandler.java
similarity index 57%
rename from src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java
rename to src/main/java/net/frozenorb/apiv3/handlers/ActorAttributeHandler.java
index 3c47fbf..8fc1e86 100644
--- a/src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java
+++ b/src/main/java/net/frozenorb/apiv3/handlers/ActorAttributeHandler.java
@@ -1,4 +1,4 @@
-package net.frozenorb.apiv3.filters;
+package net.frozenorb.apiv3.handlers;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@@ -10,41 +10,46 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
import java.util.Base64;
-public final class ActorAttributeFilter implements Handler {
+public final class ActorAttributeHandler implements Handler {
- // TODO: MAKE THIS ASYNC
+ @Override
public void handle(RoutingContext ctx) {
- String authHeader = ctx.request().getHeader("Authorization");
- String mhqAuthHeader = ctx.request().getHeader("MHQ-Authorization");
+ String authorizationHeader = ctx.request().getHeader("Authorization");
+ String mhqAuthorizationHeader = ctx.request().getHeader("MHQ-Authorization");
- if (authHeader != null) {
- processBasicAuthorization(authHeader, ctx);
- } else if (mhqAuthHeader != null) {
- processMHQAuthorization(mhqAuthHeader, ctx);
+ if (authorizationHeader != null) {
+ processBasicAuthorization(authorizationHeader, ctx);
+ } else if (mhqAuthorizationHeader != null) {
+ processMHQAuthorization(mhqAuthorizationHeader, ctx);
} else {
- ctx.put("actor", new UnknownActor());
- ctx.next();
+ processNoAuthorization(ctx);
}
}
- @SuppressWarnings("deprecation") // We purposely get the User by their last username.
private void processBasicAuthorization(String authHeader, RoutingContext ctx) {
String encodedHeader = authHeader.substring("Basic ".length());
- String[] credentials = new String(Base64.getDecoder().decode(encodedHeader.getBytes())).split(":");
+ String decodedHeader = new String(Base64.getDecoder().decode(encodedHeader.getBytes()));
+ String[] credentials = decodedHeader.split(":");
if (credentials.length == 2) {
- User user = User.findByLastUsername(credentials[0]);
- String password = credentials[1];
+ User.findByLastUsername(credentials[0], (user, error) -> {
+ if (error != null) {
+ String password = credentials[1];
- if (user != null && user.getPassword() != null && user.checkPassword(password)) {
- ctx.put("actor", new UserActor(user));
- ctx.next();
- return;
- }
+ if (user != null && user.getPassword() != null && user.checkPassword(password)) {
+ ctx.put("actor", new UserActor(user));
+ ctx.next();
+ return;
+ }
+ }
+
+ ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
+ ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
+ });
+ } else {
+ ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
+ ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
}
-
- ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
- ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
}
private void processMHQAuthorization(String authHeader, RoutingContext ctx) {
@@ -93,4 +98,9 @@ public final class ActorAttributeFilter implements Handler {
ErrorUtils.respondGeneric(ctx, "Failed to authorize.");
}
+ public void processNoAuthorization(RoutingContext ctx) {
+ ctx.put("actor", new UnknownActor());
+ ctx.next();
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java b/src/main/java/net/frozenorb/apiv3/handlers/AuthorizationHandler.java
similarity index 84%
rename from src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java
rename to src/main/java/net/frozenorb/apiv3/handlers/AuthorizationHandler.java
index b078397..b25bf01 100644
--- a/src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java
+++ b/src/main/java/net/frozenorb/apiv3/handlers/AuthorizationHandler.java
@@ -1,4 +1,4 @@
-package net.frozenorb.apiv3.filters;
+package net.frozenorb.apiv3.handlers;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@@ -6,8 +6,9 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actors.Actor;
import net.frozenorb.apiv3.utils.ErrorUtils;
-public final class AuthorizationFilter implements Handler {
+public final class AuthorizationHandler implements Handler {
+ @Override
public void handle(RoutingContext ctx) {
Actor actor = ctx.get("actor");
diff --git a/src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java b/src/main/java/net/frozenorb/apiv3/handlers/MetricsHandler.java
similarity index 85%
rename from src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java
rename to src/main/java/net/frozenorb/apiv3/handlers/MetricsHandler.java
index 5d0fa69..1bb0839 100644
--- a/src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java
+++ b/src/main/java/net/frozenorb/apiv3/handlers/MetricsHandler.java
@@ -1,4 +1,4 @@
-package net.frozenorb.apiv3.filters;
+package net.frozenorb.apiv3.handlers;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3;
public final class MetricsHandler implements Handler {
+ @Override
public void handle(RoutingContext ctx) {
APIv3.getStatsD().incrementCounter("apiv3.http.requests");
ctx.next();
diff --git a/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java b/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java
index fe6a990..49f7065 100644
--- a/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java
+++ b/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java
@@ -1,9 +1,9 @@
package net.frozenorb.apiv3.models;
import com.google.common.collect.ImmutableMap;
+import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
-import eu.dozd.mongo.annotation.Entity;
-import eu.dozd.mongo.annotation.Id;
+import fr.javatic.mongo.jacksonCodec.objectId.Id;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actors.Actor;
@@ -15,12 +15,8 @@ import net.frozenorb.apiv3.utils.SyncUtils;
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;
+import java.util.*;
-@Entity
public final class AuditLogEntry {
private static final MongoCollection auditLogCollection = APIv3.getDatabase().getCollection("auditLog", AuditLogEntry.class);
@@ -34,22 +30,46 @@ public final class AuditLogEntry {
@Getter private AuditLogActionType type;
@Getter private Map metadata;
- public static List findAll() {
+ public static List findAllSync() {
return SyncUtils.blockMulti(auditLogCollection.find());
}
- public static AuditLogEntry findById(String id) {
+ 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 findByUser(User user) {
- return findByUser(user.getId());
+ public static List findByUserSync(User user) {
+ return findByUserSync(user.getId());
}
- public static List findByUser(UUID user) {
+ public static List findByUserSync(UUID user) {
return SyncUtils.blockMulti(auditLogCollection.find(new Document("user", user)));
}
+ public static void findAll(SingleResultCallback> callback) {
+ auditLogCollection.find().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(User user, String userIp, Actor actor, AuditLogActionType type, Map metadata) {
diff --git a/src/main/java/net/frozenorb/apiv3/models/Grant.java b/src/main/java/net/frozenorb/apiv3/models/Grant.java
index 7960b16..cda879e 100644
--- a/src/main/java/net/frozenorb/apiv3/models/Grant.java
+++ b/src/main/java/net/frozenorb/apiv3/models/Grant.java
@@ -1,11 +1,10 @@
package net.frozenorb.apiv3.models;
import com.google.common.collect.Collections2;
+import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.client.result.DeleteResult;
-import com.mongodb.client.result.UpdateResult;
-import eu.dozd.mongo.annotation.Entity;
-import eu.dozd.mongo.annotation.Id;
+import fr.javatic.mongo.jacksonCodec.objectId.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
@@ -16,7 +15,6 @@ import org.bson.types.ObjectId;
import java.util.*;
-@Entity
@AllArgsConstructor
public final class Grant {
@@ -36,26 +34,74 @@ public final class Grant {
@Getter private Date removedAt;
@Getter private String removalReason;
- public static List findAll() {
+ public static List findAllSync() {
return SyncUtils.blockMulti(grantsCollection.find());
}
- public static List findByRank(Iterable ranks) {
+ 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(Iterable ranks) {
return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", ranks))));
}
- public static Grant findById(String id) {
+ public static Grant findByIdSync(String id) {
return SyncUtils.blockOne(grantsCollection.find(new Document("_id", id)));
}
- public static List findByUser(User user) {
- return findByUser(user.getId());
+ public static List findByUserSync(User user) {
+ return findByUserSync(user.getId());
}
- public static List findByUser(UUID user) {
+ public static List findByUserSync(UUID user) {
return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user)));
}
+ public static void findAll(SingleResultCallback> callback) {
+ grantsCollection.find().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(Iterable ranks, SingleResultCallback> callback) {
+ grantsCollection.find(new Document("rank", new Document("$in", ranks))).into(new ArrayList<>(), callback);
+ }
+
+ public static void findById(String id, SingleResultCallback callback) {
+ grantsCollection.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) {
+ grantsCollection.find(new Document("user", user)).into(new ArrayList<>(), callback);
+ }
+
+ public static void findByUserGrouped(Iterable users, SingleResultCallback