commit
8cc20089da
@ -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
|
@ -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<CodecProvider> 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) {
|
||||
|
@ -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;
|
||||
|
@ -56,7 +56,7 @@ public final class V2Importer {
|
||||
|
||||
private final Future<T> future;
|
||||
|
||||
public FutureCompatibilityCallback(Future<T> future) {
|
||||
private FutureCompatibilityCallback(Future<T> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
|
@ -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<Document> {
|
||||
this.oidToUniqueId = oidToUniqueId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void apply(Document grant) {
|
||||
UUID target = oidToUniqueId.get(((Map<String, Object>) grant.get("target")).get("$id"));
|
||||
@ -37,6 +38,8 @@ public final class GrantConverter implements Block<Document> {
|
||||
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<Document> {
|
||||
grant.containsKey("comment") ? grant.getString("comment") : "",
|
||||
grant.containsKey("scope") ? ImmutableSet.copyOf((Collection<String>) grant.get("scope")) : ImmutableSet.of(),
|
||||
rank,
|
||||
grant.getDate("expires"),
|
||||
grant.containsKey("expires") ? grant.getDate("expires").toInstant() : null,
|
||||
grant.containsKey("addedBy") ? oidToUniqueId.get(((Map<String, Object>) 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
|
||||
|
@ -20,6 +20,7 @@ public final class IpLogConverter implements Block<Document> {
|
||||
this.oidToUniqueId = oidToUniqueId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void apply(Document ipLogEntry) {
|
||||
UUID user = oidToUniqueId.get(((Map<String, Object>) ipLogEntry.get("user")).get("$id"));
|
||||
@ -44,10 +45,9 @@ public final class IpLogConverter implements Block<Document> {
|
||||
new ObjectId().toString(),
|
||||
user,
|
||||
ip,
|
||||
lastSeen,
|
||||
lastSeen,
|
||||
lastSeen.toInstant(),
|
||||
lastSeen.toInstant(),
|
||||
((Number) ipLogEntry.get("uses")).intValue()
|
||||
|
||||
);
|
||||
|
||||
created.insert();
|
||||
|
@ -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<Document> {
|
||||
this.oidToUniqueId = oidToUniqueId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void apply(Document punishment) {
|
||||
UUID target = oidToUniqueId.get(((Map<String, Object>) punishment.get("user")).get("$id"));
|
||||
@ -40,15 +40,15 @@ public final class PunishmentConverter implements Block<Document> {
|
||||
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<String, Object>) punishment.get("addedBy")).get("$id")) : null,
|
||||
(Date) punishment.getDate("created").clone(),
|
||||
punishment.getDate("created").toInstant(),
|
||||
punishment.containsKey("createdOn") ? String.valueOf(((Map<String, Object>) punishment.get("createdOn")).get("$id")) : "Website",
|
||||
punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE,
|
||||
punishment.containsKey("removedBy") ? (((Map<String, Object>) punishment.get("removedBy")).get("$ref").equals("user") ? oidToUniqueId.get(((Map<String, Object>) 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
|
||||
);
|
||||
|
||||
|
@ -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<Document> {
|
||||
|
||||
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<Document> {
|
||||
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<Document> {
|
||||
user.getString("email"),
|
||||
user.getString("phone"),
|
||||
"INVALID",
|
||||
user.getDate("joined"),
|
||||
user.getDate("joined"),
|
||||
user.getDate("joined").toInstant(),
|
||||
user.getDate("joined").toInstant(),
|
||||
false
|
||||
);
|
||||
|
||||
|
@ -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<RoutingContext> {
|
||||
@ -120,7 +119,7 @@ public final class ActorAttributeHandler implements Handler<RoutingContext> {
|
||||
}
|
||||
}
|
||||
|
||||
public void processNoAuthorization(RoutingContext ctx) {
|
||||
private void processNoAuthorization(RoutingContext ctx) {
|
||||
ctx.put("actor", new UnknownActor());
|
||||
ctx.next();
|
||||
}
|
||||
|
@ -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<RoutingContext> {
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext ctx) {
|
||||
String path = ctx.request().path().replace("/", "");
|
||||
|
||||
if (path.equals("loaderio-1c81aa574f79c573e7220e15e30a96aa")) {
|
||||
ctx.response().end(path);
|
||||
} else {
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCity.java
Normal file
21
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindCity.java
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
24
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java
Normal file
24
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java
Normal file
@ -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");
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
40
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindResult.java
Normal file
40
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindResult.java
Normal file
@ -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<MaxMindSubdivision> subdivisions = new ArrayList<>();
|
||||
|
||||
for (Object subdivision : (List<Object>) legacy.get("subdivisions")) {
|
||||
subdivisions.add(new MaxMindSubdivision((Document) subdivision));
|
||||
}
|
||||
|
||||
this.subdivisions = subdivisions.toArray(new MaxMindSubdivision[subdivisions.size()]);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
26
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindTraits.java
Normal file
26
src/main/java/net/frozenorb/apiv3/maxmind/MaxMindTraits.java
Normal file
@ -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");
|
||||
}
|
||||
|
||||
}
|
@ -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<String, Object> metadata;
|
||||
|
||||
public static List<AuditLogEntry> findAllSync() {
|
||||
return SyncUtils.blockMulti(auditLogCollection.find().sort(new Document("performedAt", -1)));
|
||||
}
|
||||
|
||||
public static List<AuditLogEntry> 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<AuditLogEntry> findByUserSync(User user) {
|
||||
return findByUserSync(user.getId());
|
||||
}
|
||||
|
||||
public static List<AuditLogEntry> findByUserSync(UUID user) {
|
||||
return SyncUtils.blockMulti(auditLogCollection.find(new Document("user", user)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
auditLogCollection.find().sort(new Document("performedAt", -1)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
auditLogCollection.find().sort(new Document("performedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<AuditLogEntry> callback) {
|
||||
auditLogCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUser(User user, SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
findByUser(user.getId(), callback);
|
||||
}
|
||||
|
||||
public static void findByUser(UUID user, SingleResultCallback<List<AuditLogEntry>> 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<String, Object> 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;
|
||||
|
@ -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<String> scopes = new HashSet<>(); // So on things w/o scopes we still load properly (Morphia drops empty sets)
|
||||
@Getter private Set<String> 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<Grant> findAllSync() {
|
||||
return SyncUtils.blockMulti(grantsCollection.find().sort(new Document("addedAt", -1)));
|
||||
}
|
||||
|
||||
public static List<Grant> findAllPaginatedSync(int skip, int pageSize) {
|
||||
return SyncUtils.blockMulti(grantsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize));
|
||||
}
|
||||
|
||||
public static List<Grant> findByRankSync(Collection<Rank> ranks) {
|
||||
Collection<String> 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<List<Grant>> callback) {
|
||||
grantsCollection.find().sort(new Document("addedAt", -1)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<Grant>> callback) {
|
||||
grantsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByRank(Collection<Rank> ranks, SingleResultCallback<List<Grant>> callback) {
|
||||
Collection<String> 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<Grant> 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<ServerGroup> scopes, Rank rank, Date expiresAt, User addedBy) {
|
||||
public Grant(User user, String reason, Set<ServerGroup> 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<UpdateResult> callback = new BlockingCallback<>();
|
||||
|
@ -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<IpBan> findAllSync() {
|
||||
return SyncUtils.blockMulti(ipBansCollection.find().sort(new Document("addedAt", -1)));
|
||||
}
|
||||
|
||||
public static List<IpBan> 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<IpBan> findByIpSync(String userIp) {
|
||||
return SyncUtils.blockMulti(ipBansCollection.find(new Document("userIp", userIp)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<IpBan>> callback) {
|
||||
ipBansCollection.find().sort(new Document("addedAt", -1)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<IpBan>> 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<String> callback) {
|
||||
Punishment.findByLinkedIpBanId(id, (punishment, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (punishment != null) {
|
||||
User.findById(punishment.getUser(), (user, error2) -> {
|
||||
if (error2 != null) {
|
||||
callback.onResult(null, error2);
|
||||
return;
|
||||
}
|
||||
|
||||
String accessDenialReason;
|
||||
|
||||
if (user != null) {
|
||||
accessDenialReason = "Your IP address has been suspended from the MineHQ Network for a punishment related to " + user.getLastUsername() + ". \n\n";
|
||||
} else {
|
||||
accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n";
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
return accessDenialReason;
|
||||
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<UpdateResult> callback = new BlockingCallback<>();
|
||||
|
74
src/main/java/net/frozenorb/apiv3/model/IpIntel.java
Normal file
74
src/main/java/net/frozenorb/apiv3/model/IpIntel.java
Normal file
@ -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<IpIntel> 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<List<IpIntel>> callback) {
|
||||
ipIntelCollection.find().sort(new Document("lastSeenAt", -1)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<IpIntel> callback) {
|
||||
ipIntelCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByIdOrInsert(String id, SingleResultCallback<IpIntel> 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<Void> callback) {
|
||||
ipIntelCollection.insertOne(this, callback);
|
||||
}
|
||||
|
||||
}
|
@ -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<IpLogEntry> 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++;
|
||||
}
|
||||
|
||||
|
@ -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<NotificationTemplate> 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<UpdateResult> callback = new BlockingCallback<>();
|
||||
notificationTemplatesCollection.replaceOne(new Document("_id", id), this, callback);
|
||||
callback.get();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||
notificationTemplatesCollection.deleteOne(new Document("_id", id), callback);
|
||||
|
@ -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<String, Object> 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<Punishment> findAllSync() {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find().sort(new Document("addedAt", -1)));
|
||||
}
|
||||
|
||||
public static List<Punishment> findAllPaginatedSync(int skip, int pageSize) {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize));
|
||||
}
|
||||
|
||||
public static List<Punishment> findByTypeSync(Collection<PunishmentType> types) {
|
||||
Collection<String> 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<List<Punishment>> callback) {
|
||||
punishmentsCollection.find().sort(new Document("addedAt", -1)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<Punishment>> callback) {
|
||||
punishmentsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByType(Collection<PunishmentType> types, SingleResultCallback<List<Punishment>> callback) {
|
||||
Collection<String> 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<Punishment> callback) {
|
||||
punishmentsCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByLinkedIpBanId(String id, SingleResultCallback<Punishment> callback) {
|
||||
punishmentsCollection.find(new Document("linkedIpBanId", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUser(User user, SingleResultCallback<List<Punishment>> 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<String, Object> metadata) {
|
||||
public Punishment(User user, String reason, PunishmentType type, Instant expiresAt, User addedBy, Actor actor, Map<String, Object> 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) {
|
||||
|
@ -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<UpdateResult> callback = new BlockingCallback<>();
|
||||
ranksCollection.replaceOne(new Document("_id", id), this, callback);
|
||||
callback.get();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||
ranksCollection.deleteOne(new Document("_id", id), callback);
|
||||
|
@ -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<UUID> players;
|
||||
@Getter private Instant lastUpdatedAt;
|
||||
@Getter private double lastTps;
|
||||
@Getter @ExcludeFromReplies private Set<UUID> players;
|
||||
|
||||
public static List<Server> 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<UUID> players) {
|
||||
this.lastUpdatedAt = new Date();
|
||||
this.lastUpdatedAt = Instant.now();
|
||||
this.lastTps = tps;
|
||||
this.players = ImmutableSet.copyOf(players);
|
||||
}
|
||||
|
@ -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<String> announcements = new HashSet<>();
|
||||
@Getter @Setter @ExcludeFromReplies private Map<String, List<String>> permissions = new HashMap<>();
|
||||
@Getter @Setter @ExcludeFromReplies private Set<String> announcements;
|
||||
@Getter @Setter @ExcludeFromReplies private Map<String, List<String>> permissions;
|
||||
|
||||
// make this and other stuff async
|
||||
public static List<ServerGroup> 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<UpdateResult> callback = new BlockingCallback<>();
|
||||
public void save(SingleResultCallback<UpdateResult> callback) {
|
||||
serverGroupsCollection.replaceOne(new Document("_id", id), this, callback);
|
||||
callback.get();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
@ -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<User> 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<String, Date> aliases = new HashMap<>();
|
||||
@Getter @ExcludeFromReplies private Map<String, Instant> 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<User> 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<List<User>> callback) {
|
||||
usersCollection.find().sort(new Document("lastSeenAt", -1)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<User> callback) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(id);
|
||||
@ -95,7 +92,7 @@ public final class User {
|
||||
}
|
||||
|
||||
public static void findById(UUID id, SingleResultCallback<User> 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<User> callback) {
|
||||
usersCollection.find(new Document("emailToken", emailToken)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByLastUsername(String lastUsername, SingleResultCallback<User> 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<Void> blockingCallback = new BlockingCallback<>();
|
||||
updateUsername(lastUsername, blockingCallback);
|
||||
blockingCallback.get();
|
||||
updateUsername(lastUsername);
|
||||
}
|
||||
|
||||
public boolean hasPermissionAnywhere(String permission) {
|
||||
Map<String, Boolean> globalPermissions = getGlobalPermissions();
|
||||
return globalPermissions.containsKey(permission) && globalPermissions.get(permission);
|
||||
}
|
||||
|
||||
// TODO: ASYNC
|
||||
public Map<String, Boolean> getGlobalPermissions() {
|
||||
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankAnywhere());
|
||||
|
||||
for (Map.Entry<ServerGroup, Rank> 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<Void> callback) {
|
||||
this.aliases.put(newUsername, new Date());
|
||||
|
||||
if (newUsername.equalsIgnoreCase(lastUsername)) {
|
||||
callback.onResult(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
public void updateUsername(String newUsername) {
|
||||
if (!newUsername.equals(lastUsername)) {
|
||||
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);
|
||||
User withNewUsername;
|
||||
|
||||
while ((withNewUsername = User.findByLastUsernameSync(newUsername)) != null) {
|
||||
BlockingCallback<String> callback = new BlockingCallback<>();
|
||||
MojangUtils.getName(withNewUsername.getId(), callback);
|
||||
withNewUsername.updateUsername(callback.get());
|
||||
}
|
||||
});
|
||||
} 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<String> callback = new BlockingCallback<>();
|
||||
activeIpBan.getAccessDenialReason(callback);
|
||||
String reason = callback.get();
|
||||
|
||||
access = ImmutableMap.of(
|
||||
"allowed", false,
|
||||
"message", activeIpBan.getAccessDenialReason(),
|
||||
"message", reason,
|
||||
"activeIpBanId", activeIpBan.getId()
|
||||
);
|
||||
}
|
||||
|
@ -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<String, Object> data;
|
||||
|
||||
public static List<UserMetaEntry> 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<List<UserMetaEntry>> callback) {
|
||||
userMetaCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<UserMetaEntry> callback) {
|
||||
userMetaCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndGroup(User user, ServerGroup serverGroup, SingleResultCallback<UserMetaEntry> callback) {
|
||||
findByUserAndGroup(user.getId(), serverGroup, callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndGroup(UUID user, ServerGroup serverGroup, SingleResultCallback<UserMetaEntry> 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<String, Object> data) {
|
||||
this.id = new ObjectId().toString();
|
||||
|
@ -108,7 +108,6 @@ public final class GETDump implements Handler<RoutingContext> {
|
||||
return;
|
||||
default:
|
||||
ErrorUtils.respondInvalidInput(ctx, type + " is not a valid type. Not in [ban, blacklist, accessDeniable, grant]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,9 @@ public final class GETAnnouncements implements Handler<RoutingContext> {
|
||||
|
||||
if (serverGroup == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("id"));
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
APIv3.respondJson(ctx, serverGroup.getAnnouncements());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,9 +16,7 @@ public final class PUTAnnouncements implements Handler<RoutingContext> {
|
||||
|
||||
if (serverGroup == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("id"));
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
Set<String> announcements = new HashSet<>();
|
||||
|
||||
for (Object announcement : ctx.getBodyAsJsonArray()) {
|
||||
@ -26,8 +24,14 @@ public final class PUTAnnouncements implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
serverGroup.setAnnouncements(announcements);
|
||||
serverGroup.save();
|
||||
serverGroup.save((ignored, error) -> {
|
||||
if (error != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, serverGroup.getAnnouncements());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,13 @@ public final class GETAuditLog implements Handler<RoutingContext> {
|
||||
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.");
|
||||
}
|
||||
|
@ -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,13 +13,12 @@ import org.bson.Document;
|
||||
public final class POSTUserAuditLogEntry implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
String userIp = ctx.request().getParam("userIp");
|
||||
|
||||
if (!IpUtils.isValidIp(userIp)) {
|
||||
@ -38,10 +35,15 @@ public final class POSTUserAuditLogEntry implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockingCallback<AuditLogEntry> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,13 @@ public final class GETGrants implements Handler<RoutingContext> {
|
||||
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.");
|
||||
}
|
||||
|
@ -10,14 +10,21 @@ import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
public final class GETUserGrants implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
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"));
|
||||
return;
|
||||
} else {
|
||||
Grant.findByUser(user, (grants, error2) -> {
|
||||
if (error2 != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error2);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, grants);
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, Grant.findByUserSync(target));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,13 @@ public final class GETIpBans implements Handler<RoutingContext> {
|
||||
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.");
|
||||
}
|
||||
|
@ -17,7 +17,13 @@ public final class GETIpIpBans implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, IpBan.findByIpSync(userIp));
|
||||
IpBan.findByIp(userIp, (ipBans, error) -> {
|
||||
if (error != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, ipBans);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
@ -27,16 +27,16 @@ public final class POSTIpIpBan implements Handler<RoutingContext> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -10,14 +10,21 @@ import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
public final class GETUserIpLog implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
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"));
|
||||
return;
|
||||
} else {
|
||||
IpLogEntry.findByUser(user, (ipLog, error2) -> {
|
||||
if (error2 != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error2);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, ipLog);
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, IpLogEntry.findByUserSync(target));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,13 @@ public final class GETPunishments implements Handler<RoutingContext> {
|
||||
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.");
|
||||
}
|
||||
|
@ -10,14 +10,21 @@ import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
public final class GETUserPunishments implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
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"));
|
||||
return;
|
||||
} else {
|
||||
Punishment.findByUser(user, (punishments, error2) -> {
|
||||
if (error2 != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error2);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, punishments);
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, Punishment.findByUserSync(target));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
@ -43,16 +43,16 @@ public final class POSTUserPunish implements Handler<RoutingContext> {
|
||||
}
|
||||
}
|
||||
|
||||
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<RoutingContext> {
|
||||
|
||||
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);
|
||||
|
@ -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<RoutingContext> {
|
||||
@ -55,19 +58,17 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
// TODO: ASYNC (MAKE ALL SAVES/INSERTS/ETC USED HERE ASYNC
|
||||
public Future<Void> createInfoResponse(Server server, double tps, Map<UUID, String> playerNames) {
|
||||
private Future<Void> createInfoResponse(Server server, double tps, Map<UUID, String> playerNames) {
|
||||
Future<Void> 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<Map<String, Object>> createPlayerResponse(Server server, Map<UUID, String> playerNames) {
|
||||
private Future<Map<String, Object>> createPlayerResponse(Server server, Map<UUID, String> playerNames) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
|
||||
Future<Map<UUID, User>> userLookupCallback = Future.future();
|
||||
@ -138,7 +139,7 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public Future<Map<String, Object>> createPermissionsResponse(ServerGroup serverGroup) {
|
||||
private Future<Map<String, Object>> createPermissionsResponse(ServerGroup serverGroup) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
Map<String, Object> permissionsResponse = new HashMap<>();
|
||||
|
||||
@ -155,7 +156,7 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public Future<Map<String, Object>> createEventsResponse(List<Object> eventsData) {
|
||||
private Future<Map<String, Object>> createEventsResponse(List<Object> eventsData) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
|
||||
for (Object event : eventsData) {
|
||||
@ -178,7 +179,7 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public Map<UUID, String> extractPlayerNames(Document reqJson) {
|
||||
private Map<UUID, String> extractPlayerNames(Document reqJson) {
|
||||
Map<UUID, String> result = new HashMap<>();
|
||||
|
||||
for (Object player : (List<Object>) reqJson.get("players")) {
|
||||
@ -186,7 +187,7 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
UUID uuid = UUID.fromString(playerJson.getString("uuid"));
|
||||
String username = playerJson.getString("username");
|
||||
|
||||
if (UUIDUtils.isAcceptableUUID(uuid)) {
|
||||
if (UuidUtils.isAcceptableUuid(uuid)) {
|
||||
result.put(uuid, username);
|
||||
}
|
||||
}
|
||||
|
@ -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<RoutingContext> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
|
||||
@ -36,7 +36,7 @@ public final class GETUserRequiresTOTP implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
BlockingCallback<Boolean> preAuthorizedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.isPreAuthorized(user, userIp, preAuthorizedCallback);
|
||||
TotpUtils.isPreAuthorized(user, userIp, preAuthorizedCallback);
|
||||
|
||||
if (preAuthorizedCallback.get()) {
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
|
@ -12,6 +12,14 @@ public final class GETUserVerifyPassword implements Handler<RoutingContext> {
|
||||
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;
|
||||
|
@ -36,7 +36,7 @@ public final class POSTUserConfirmRegister implements Handler<RoutingContext> {
|
||||
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;
|
||||
}
|
||||
|
@ -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<RoutingContext> {
|
||||
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,53 +42,37 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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<RoutingContext> {
|
||||
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<String, Object> replacements = ImmutableMap.of(
|
||||
|
@ -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<RoutingContext> {
|
||||
|
||||
@ -24,13 +24,13 @@ public final class POSTUserSetupTOTP implements Handler<RoutingContext> {
|
||||
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)
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -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<RoutingContext> {
|
||||
|
||||
int providedCode = Integer.parseInt(ctx.request().getParam("code"));
|
||||
BlockingCallback<Boolean> 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<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean authorized = TOTPUtils.authorizeUser(user, providedCode);
|
||||
boolean authorized = TotpUtils.authorizeUser(user, providedCode);
|
||||
|
||||
if (authorized) {
|
||||
BlockingCallback<Void> markPreAuthorizedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS, markPreAuthorizedCallback);
|
||||
TotpUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS, markPreAuthorizedCallback);
|
||||
markPreAuthorizedCallback.get();
|
||||
|
||||
BlockingCallback<Void> markRecentlyUsedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.markRecentlyUsed(user, providedCode, markRecentlyUsedCallback);
|
||||
TotpUtils.markRecentlyUsed(user, providedCode, markRecentlyUsedCallback);
|
||||
markRecentlyUsedCallback.get();
|
||||
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
|
@ -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<Date> {
|
||||
public final class InstantTypeAdapter extends TypeAdapter<Instant> {
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -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<Instant> {
|
||||
|
||||
@Override
|
||||
public Instant deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
|
||||
return Instant.ofEpochMilli(jsonParser.getValueAsLong());
|
||||
}
|
||||
|
||||
}
|
@ -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<Instant> {
|
||||
|
||||
@Override
|
||||
public void serialize(Instant instant, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
|
||||
jsonGenerator.writeNumber(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDJsonDeserializer extends JsonDeserializer<UUID> {
|
||||
public final class UuidJsonDeserializer extends JsonDeserializer<UUID> {
|
||||
|
||||
@Override
|
||||
public UUID deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
|
||||
|
@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class UUIDJsonSerializer extends JsonSerializer<UUID> {
|
||||
public final class UuidJsonSerializer extends JsonSerializer<UUID> {
|
||||
|
||||
@Override
|
||||
public void serialize(UUID uuid, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
|
||||
|
@ -8,7 +8,7 @@ import org.bson.codecs.EncoderContext;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public final class UUIDCodec implements Codec<UUID> {
|
||||
public final class UuidCodec implements Codec<UUID> {
|
||||
|
||||
@Override
|
||||
public UUID decode(BsonReader bsonReader, DecoderContext decoderContext) {
|
||||
|
@ -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 <T> Codec<T> get(Class<T> clazz, CodecRegistry codecRegistry) {
|
||||
if (clazz == UUID.class) {
|
||||
return (Codec<T>) new UUIDCodec();
|
||||
return (Codec<T>) new UuidCodec();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
37
src/main/java/net/frozenorb/apiv3/util/MaxMindUtils.java
Normal file
37
src/main/java/net/frozenorb/apiv3/util/MaxMindUtils.java
Normal file
@ -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<MaxMindResult> 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<String, String>) source.get("names")).get("en");
|
||||
}
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ import java.util.UUID;
|
||||
public class MojangUtils {
|
||||
|
||||
public static void getName(UUID id, SingleResultCallback<String> 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");
|
||||
|
@ -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(),
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user