Start adding IoC elements

This commit is contained in:
Colin McDonald 2016-11-27 20:47:40 -05:00
parent 1c9983de66
commit 6ae09cde9b
159 changed files with 1707 additions and 1184 deletions

View File

@ -1,18 +0,0 @@
mongo.address=209.222.96.50
mongo.port=27017
mongo.database=MineHQ
mongo.username=
mongo.password=
redis.address=209.222.96.50
redis.port=6379
http.port=80
http.keystoreFile=/home/keystore.idk
http.keystorePassword=123abc
librato.email=cmcdonald.main@gmail.com
librato.apiToken=a818c3eca8a59d6d9cf76dc9f0d237c6aa97f257c482ce3363cf55a5431bc153
librato.sourceIdentifier=apiv3-dev-01
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
maxMind.userId=66817
maxMind.maxMindLicenseKey=8Aw9NsOUeOp7
zang.accountSid=ACf18890845596403e330944d98886440c
zang.authToken=dc70bbd1fbd8411ba133fa93813a461b

23
application.properties Normal file
View File

@ -0,0 +1,23 @@
mongo.address=158.69.26.208
mongo.port=27027
mongo.database=MineHQDev
mongo.username=
mongo.password=
redis.address=209.222.96.50
redis.port=6379
http.port=80
http.keystoreFile=
http.keystorePassword=
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
mandrill.fromEmail=no-reply@minehq.com
mandrill.fromName=MineHQ Network
maxMind.userId=66817
maxMind.licenseKey=8Aw9NsOUeOp7
zang.accountSid=ACf18890845596403e330944d98886440c
zang.authToken=dc70bbd1fbd8411ba133fa93813a461b
zang.fromNumber=339-337-5300

87
pom.xml
View File

@ -1,20 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.frozenorb</groupId>
<artifactId>APIv3</artifactId>
<version>1.0</version>
<parent>
<groupId>net.frozenorb</groupId>
<artifactId>minehq-parent</artifactId>
<version>1.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
<relativePath/>
</parent>
<properties>
<minehq.mavenUrl>http://maven.minehq.com:8081/artifactory</minehq.mavenUrl>
<minehq.mavenLevel>minehq-high</minehq.mavenLevel>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<vertx.version>3.3.3</vertx.version>
</properties>
<build>
<finalName>${project.artifactId}</finalName>
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources/</directory>
<excludes>
<exclude>**/*.jar</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -48,6 +65,21 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.2.RELEASE</version>
</plugin>
</plugins>
</build>
@ -62,32 +94,44 @@
</repository>
</repositories>
<distributionManagement>
<repository>
<id>minehq-repo</id>
<url>${minehq.mavenUrl}/${minehq.mavenLevel}</url>
</repository>
<snapshotRepository>
<id>minehq-repo</id>
<url>${minehq.mavenUrl}/${minehq.mavenLevel}</url>
</snapshotRepository>
</distributionManagement>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Vert.x -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.3.2</version>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>3.3.2</version>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-redis-client</artifactId>
<version>3.3.2</version>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-circuit-breaker</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-dropwizard-metrics</artifactId>
<version>3.3.2</version>
<version>${vertx.version}</version>
</dependency>
<!-- Google Libs -->
@ -126,13 +170,6 @@
<version>2.7.0</version>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>com.librato.metrics</groupId>
<artifactId>metrics-librato</artifactId>
<version>4.1.2.5</version>
</dependency>
<!-- Totp -->
<dependency>
<groupId>com.warrenstrange</groupId>
@ -140,18 +177,6 @@
<version>1.1.1</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>

View File

@ -1,27 +1,9 @@
package net.frozenorb.apiv3;
import com.google.common.collect.ImmutableList;
import com.google.common.net.MediaType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.librato.metrics.LibratoReporter;
import com.mongodb.ConnectionString;
import com.mongodb.MongoCredential;
import com.mongodb.async.client.MongoClient;
import com.mongodb.async.client.MongoClientSettings;
import com.mongodb.async.client.MongoClients;
import com.mongodb.async.client.MongoDatabase;
import com.mongodb.client.model.IndexModel;
import com.mongodb.connection.ClusterSettings;
import net.frozenorb.apiv3.filter.AuthenticationFilter;
import net.frozenorb.apiv3.filter.AuthorizationFilter;
import net.frozenorb.apiv3.filter.MetricsFilter;
@ -32,7 +14,6 @@ import net.frozenorb.apiv3.model.Rank;
import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.route.GETDumpsType;
import net.frozenorb.apiv3.route.GETMetrics;
import net.frozenorb.apiv3.route.GETSearch;
import net.frozenorb.apiv3.route.GETWhoAmI;
import net.frozenorb.apiv3.route.POSTLogout;
@ -113,31 +94,19 @@ import net.frozenorb.apiv3.route.users.POSTUsersIdVerifyTotp;
import net.frozenorb.apiv3.route.users.POSTUsersUsePasswordResetToken;
import net.frozenorb.apiv3.serialization.gson.FollowAnnotationExclusionStrategy;
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.util.EmailUtils;
import net.frozenorb.apiv3.util.SpringUtils;
import org.bson.Document;
import org.bson.codecs.BsonValueCodecProvider;
import org.bson.codecs.DocumentCodecProvider;
import org.bson.codecs.ValueCodecProvider;
import org.bson.codecs.configuration.CodecRegistries;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import fr.javatic.mongo.jacksonCodec.JacksonCodecProvider;
import fr.javatic.mongo.jacksonCodec.ObjectMapperFactory;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
@ -150,15 +119,12 @@ import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.LoggerFormat;
import io.vertx.ext.web.handler.LoggerHandler;
import io.vertx.ext.web.handler.TimeoutHandler;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public final class APIv3 extends AbstractVerticle {
@Component
public final class APIv3 extends AbstractVerticle implements ApplicationContextAware {
@Getter private static Vertx vertxInstance;
@Getter private static MongoDatabase database;
@Getter private static final Properties config = new Properties();
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Instant.class, new InstantTypeAdapter())
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
@ -166,299 +132,168 @@ public final class APIv3 extends AbstractVerticle {
@Override
public void start() {
vertxInstance = vertx;
setupConfig();
setupDatabase();
setupMetrics();
setupHttpServer();
/*User.findAll((users, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
for (User user : users) {
String currentUsername = SyncUtils.runBlocking(v -> MojangUtils.getName(user.getId(), v));
String lastUsername = user.getLastUsername();
if (!currentUsername.equals(lastUsername)) {
SyncUtils.<Void>runBlocking(v -> user.checkNameCollisions(v));
}
log.info(user.getLastUsername() + " - " + user.getLastSeenAt());
}
});*/
}
private void setupConfig() {
try (InputStream in = new FileInputStream("apiv3.properties")) {
config.load(in);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private void setupDatabase() {
List<MongoCredential> credentials = ImmutableList.of();
if (!config.getProperty("mongo.username").isEmpty()) {
credentials = ImmutableList.of(
MongoCredential.createCredential(
config.getProperty("mongo.username"),
config.getProperty("mongo.database"),
config.getProperty("mongo.password").toCharArray()
)
);
}
ConnectionString connectionString = new ConnectionString("mongodb://" + config.getProperty("mongo.address") + ":" + config.getProperty("mongo.port"));
MongoClient mongoClient = MongoClients.create(MongoClientSettings
.builder()
.codecRegistry(CodecRegistries.fromProviders(ImmutableList.of(
new UuidCodecProvider(), // MHQ, fixes uuid serialization
new ValueCodecProvider(),
new DocumentCodecProvider(),
new BsonValueCodecProvider(),
new JacksonCodecProvider(createMongoJacksonMapper()) // Jackson codec, provides serialization/deserialization
)))
.credentialList(credentials)
.clusterSettings(ClusterSettings.builder()
.applyConnectionString(connectionString)
.build()
)
.build()
);
database = mongoClient.getDatabase(config.getProperty("mongo.database"));
database.getCollection("auditLog").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1)),
new IndexModel(new Document("performedAt", 1)),
new IndexModel(new Document("type", 1))
), (a, b) -> {
});
database.getCollection("grants").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1)),
new IndexModel(new Document("rank", 1)),
new IndexModel(new Document("addedAt", 1))
), (a, b) -> {
});
database.getCollection("ipLog").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1)),
new IndexModel(new Document("user", 1).append("userIp", 1)),
new IndexModel(new Document("hashedUserIp", 1))
), (a, b) -> {
});
database.getCollection("ipBans").createIndexes(ImmutableList.of(
new IndexModel(new Document("userIp", 1))
), (a, b) -> {
});
database.getCollection("ipIntel").createIndexes(ImmutableList.of(
new IndexModel(new Document("hashedIp", 1)),
new IndexModel(new Document("location", "2dsphere"))
), (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("linkedIpBanId", 1))
), (a, b) -> {
});
database.getCollection("users").createIndexes(ImmutableList.of(
new IndexModel(new Document("lastUsername", 1)),
new IndexModel(new Document("lastUsernameLower", 1)),
new IndexModel(new Document("emailToken", 1))
), (a, b) -> {
});
database.getCollection("userMeta").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1).append("serverGroup", 1))
), (a, b) -> {
});
BannedAsn.updateCache();
BannedCellCarrier.updateCache();
Rank.updateCache();
Server.updateCache();
ServerGroup.updateCache();
EmailUtils.updateBannedEmailDomains();
GETDumpsType.updateCache();
}
private ObjectMapper createMongoJacksonMapper() {
ObjectMapper mongoJacksonMapper = ObjectMapperFactory.createObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Instant.class, new InstantJsonSerializer());
module.addDeserializer(Instant.class, new InstantJsonDeserializer());
module.addSerializer(UUID.class, new UuidJsonSerializer());
module.addDeserializer(UUID.class, new UuidJsonDeserializer());
mongoJacksonMapper.registerModule(module);
mongoJacksonMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
mongoJacksonMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mongoJacksonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mongoJacksonMapper;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringUtils.setBeanFactory(applicationContext);
}
private void setupMetrics() {
MetricRegistry registry = SharedMetricRegistries.getOrCreate("apiv3-registry");
LibratoReporter.enable(
LibratoReporter.builder(
registry,
config.getProperty("librato.email"),
config.getProperty("librato.apiToken"),
config.getProperty("librato.sourceIdentifier")),
10,
TimeUnit.SECONDS);
@Bean
public Vertx vertx() {
return vertx;
}
private void setupHttpServer() {
Environment environment = SpringUtils.getBean(Environment.class);
HttpServerOptions httpServerOptions = new HttpServerOptions();
httpServerOptions.setCompressionSupported(true);
if (!config.getProperty("http.keystoreFile").isEmpty()) {
if (!environment.getProperty("http.keystoreFile").isEmpty()) {
httpServerOptions.setSsl(true);
httpServerOptions.setKeyStoreOptions(
new JksOptions()
.setPassword(config.getProperty("http.keystorePassword"))
.setPath(config.getProperty("http.keystoreFile"))
.setPassword(environment.getProperty("http.keystorePassword"))
.setPath(environment.getProperty("http.keystoreFile"))
);
}
HttpServer webServer = vertx.createHttpServer(httpServerOptions);
Router http = Router.router(vertx); // we just name this http to make the route declarations easier to read
Router router = Router.router(vertx);
http.route().handler(LoggerHandler.create(LoggerFormat.TINY));
http.route().handler(TimeoutHandler.create(TimeUnit.SECONDS.toMillis(5)));
http.route().method(HttpMethod.PUT).method(HttpMethod.POST).method(HttpMethod.DELETE).handler(BodyHandler.create());
http.route().handler(new AuthenticationFilter());
http.route().handler(new MetricsFilter());
http.route().handler(new WebsiteUserSessionFilter());
http.route().handler(new AuthorizationFilter());
http.exceptionHandler(Throwable::printStackTrace);
router.route().handler(LoggerHandler.create(LoggerFormat.TINY));
router.route().handler(TimeoutHandler.create(TimeUnit.SECONDS.toMillis(5)));
router.route().method(HttpMethod.PUT).method(HttpMethod.POST).method(HttpMethod.DELETE).handler(BodyHandler.create());
router.route().handler(SpringUtils.getBean(AuthenticationFilter.class));
router.route().handler(SpringUtils.getBean(MetricsFilter.class));
router.route().handler(SpringUtils.getBean(WebsiteUserSessionFilter.class));
router.route().handler(SpringUtils.getBean(AuthorizationFilter.class));
router.exceptionHandler(Throwable::printStackTrace);
// TODO: The commented out routes
http.get("/accessTokens/:accessToken").blockingHandler(new GETAccessTokensId());
http.get("/accessTokens").blockingHandler(new GETAccessTokens());
http.post("/accessTokens").blockingHandler(new POSTAccessTokens(), false);
//http.put("/accessTokens/:accessToken").blockingHandler(new PUTAccessTokensId(), false);
http.delete("/accessTokens/:accessToken").blockingHandler(new DELETEAccessTokensId(), false);
httpGet(router, "/accessTokens/:accessToken", GETAccessTokensId.class);
httpGet(router, "/accessTokens", GETAccessTokens.class);
httpPost(router, "/accessTokens", POSTAccessTokens.class);
//httpPut(router, "/accessTokens/:accessToken", PUTAccessTokensId.class);
httpDelete(router, "/accessTokens/:accessToken", DELETEAccessTokensId.class);
http.get("/auditLog").handler(new GETAuditLog());
http.post("/auditLog").handler(new POSTAuditLog());
http.delete("/auditLog/:auditLogEntryId").blockingHandler(new DELETEAuditLogId());
httpGet(router, "/auditLog", GETAuditLog.class);
httpPost(router, "/auditLog", POSTAuditLog.class);
httpDelete(router, "/auditLog/:auditLogEntryId", DELETEAuditLogId.class);
http.get("/bannedAsns/:bannedAsn").handler(new GETBannedAsnsId());
http.get("/bannedAsns").handler(new GETBannedAsns());
http.post("/bannedAsns").blockingHandler(new POSTBannedAsns(), false);
//http.put("/bannedAsns/:bannedAsn").blockingHandler(new PUTBannedAsnsId(), false);
http.delete("/bannedAsns/:bannedAsn").blockingHandler(new DELETEBannedAsnsId(), false);
httpGet(router, "/bannedAsns/:bannedAsn", GETBannedAsnsId.class);
httpGet(router, "/bannedAsns", GETBannedAsns.class);
httpPost(router, "/bannedAsns", POSTBannedAsns.class);
//httpPut(router, "/bannedAsns/:bannedAsn", PUTBannedAsnsId.class);
httpDelete(router, "/bannedAsns/:bannedAsn", DELETEBannedAsnsId.class);
http.get("/bannedCellCarriers/:bannedCellCarrier").handler(new GETBannedCellCarriersId());
http.get("/bannedCellCarriers").handler(new GETBannedCellCarriers());
http.post("/bannedCellCarriers").blockingHandler(new POSTBannedCellCarriers(), false);
//http.put("/bannedCellCarriers/:bannedCellCarrier").blockingHandler(new PUTBannedCellCarriersId(), false);
http.delete("/bannedCellCarriers/:bannedCellCarrier").blockingHandler(new DELETEBannedCellCarriersId(), false);
httpGet(router, "/bannedCellCarriers/:bannedCellCarrier", GETBannedCellCarriersId.class);
httpGet(router, "/bannedCellCarriers", GETBannedCellCarriers.class);
httpPost(router, "/bannedCellCarriers", POSTBannedCellCarriers.class);
//httpPut(router, "/bannedCellCarriers/:bannedCellCarrier", PUTBannedCellCarriersId.class);
httpDelete(router, "/bannedCellCarriers/:bannedCellCarrier", DELETEBannedCellCarriersId.class);
http.get("/chatFilter/:chatFilterEntryId").handler(new GETChatFilterId());
http.get("/chatFilter").handler(new GETChatFilter());
http.post("/chatFilter").blockingHandler(new POSTChatFilter(), false);
//http.put("/chatFilter/:chatFilterEntryId").blockingHandler(new PUTChatFilterId(), false);
http.delete("/chatFilter/:chatFilterEntryId").blockingHandler(new DELETEChatFilterId(), false);
httpGet(router, "/chatFilter/:chatFilterEntryId", GETChatFilterId.class);
httpGet(router, "/chatFilter", GETChatFilter.class);
httpPost(router, "/chatFilter", POSTChatFilter.class);
//httpPut(router, "/chatFilter/:chatFilterEntryId", PUTChatFilterId.class);
httpDelete(router, "/chatFilter/:chatFilterEntryId", DELETEChatFilterId.class);
http.post("/deployment/updateServer/:serverId").blockingHandler(new POSTDeploymentUpdateServer(), false);
httpPost(router, "/deployment/updateServer/:serverId", POSTDeploymentUpdateServer.class);
http.post("/disposableLoginTokens").blockingHandler(new POSTDisposableLoginTokens(), false);
http.post("/disposableLoginTokens/:disposableLoginToken/use").blockingHandler(new POSTDisposableLoginTokensIdUse(), false);
httpPost(router, "/disposableLoginTokens", POSTDisposableLoginTokens.class);
httpPost(router, "/disposableLoginTokens/:disposableLoginToken/use", POSTDisposableLoginTokensIdUse.class);
http.get("/emailTokens/:emailToken/owner").blockingHandler(new GETEmailTokensIdOwner(), false);
http.post("/emailTokens/:emailToken/confirm").blockingHandler(new POSTEmailTokensIdConfirm(), false);
httpGet(router, "/emailTokens/:emailToken/owner", GETEmailTokensIdOwner.class);
httpPost(router, "/emailTokens/:emailToken/confirm", POSTEmailTokensIdConfirm.class);
http.get("/grants/:grantId").handler(new GETGrantsId());
http.get("/grants").handler(new GETGrants());
http.post("/grants").blockingHandler(new POSTGrants(), false);
//http.put("/grants/:grantId").blockingHandler(new PUTGrantsId(), false);
http.delete("/grants/:grantId").blockingHandler(new DELETEGrantsId(), false);
httpGet(router, "/grants/:grantId", GETGrantsId.class);
httpGet(router, "/grants", GETGrants.class);
httpPost(router, "/grants", POSTGrants.class);
//httpPut(router, "/grants/:grantId", PUTGrantsId.class);
httpDelete(router, "/grants/:grantId", DELETEGrantsId.class);
http.get("/ipBans/:ipBanId").handler(new GETIpBansId());
http.get("/ipBans").handler(new GETIpBans());
http.post("/ipBans").blockingHandler(new POSTIpBans(), false);
//http.put("/ipBans/:ipBanId").blockingHandler(new PUTIpBansId(), false);
http.delete("/ipBans/:ipBanId").blockingHandler(new DELETEIpBansId(), false);
httpGet(router, "/ipBans/:ipBanId", GETIpBansId.class);
httpGet(router, "/ipBans", GETIpBans.class);
httpPost(router, "/ipBans", POSTIpBans.class);
//httpPut(router, "/ipBans/:ipBanId", PUTIpBansId.class);
httpDelete(router, "/ipBans/:ipBanId", DELETEIpBansId.class);
http.get("/ipIntel/:userIp").handler(new GETIpInteld());
httpGet(router, "/ipIntel/:userIp", GETIpInteld.class);
http.get("/ipLog/:id").handler(new GETIpLogId());
httpGet(router, "/ipLog/:id", GETIpLogId.class);
http.post("/lookup/byName").blockingHandler(new POSTLookupByName());
http.post("/lookup/byUuid").blockingHandler(new POSTLookupByUuid());
httpPost(router, "/lookup/byName", POSTLookupByName.class);
httpPost(router, "/lookup/byUuid", POSTLookupByUuid.class);
http.get("/notificationTemplates/:notificationTemplateId").handler(new GETNotificationTemplatesId());
http.get("/notificationTemplates").handler(new GETNotificationTemplates());
http.post("/notificationTemplates").blockingHandler(new POSTNotificationTemplates(), false);
//http.put("/notificationTemplates/:notificationTemplateId").blockingHandler(new PUTNotificationTemplatesId(), false);
http.delete("/notificationTemplates/:notificationTemplateId").blockingHandler(new DELETENotificationTemplatesId(), false);
httpGet(router, "/notificationTemplates/:notificationTemplateId", GETNotificationTemplatesId.class);
httpGet(router, "/notificationTemplates", GETNotificationTemplates.class);
httpPost(router, "/notificationTemplates", POSTNotificationTemplates.class);
//httpPut(router, "/notificationTemplates/:notificationTemplateId", PUTNotificationTemplatesId.class);
httpDelete(router, "/notificationTemplates/:notificationTemplateId", DELETENotificationTemplatesId.class);
http.get("/phoneIntel/:phone").handler(new GETPhoneInteld());
httpGet(router, "/phoneIntel/:phone", GETPhoneInteld.class);
http.get("/punishments/:punishmentId").handler(new GETPunishmentsId());
http.get("/punishments").handler(new GETPunishments());
http.post("/punishments").blockingHandler(new POSTPunishments(), false);
//http.put("/punishments/:punishmentId").blockingHandler(new PUTPunishmentsId(), false);
http.delete("/punishments/:punishmentId").blockingHandler(new DELETEPunishmentsId(), false);
http.delete("/users/:userId/activePunishment").blockingHandler(new DELETEUsersIdActivePunishment(), false);
httpGet(router, "/punishments/:punishmentId", GETPunishmentsId.class);
httpGet(router, "/punishments", GETPunishments.class);
httpPost(router, "/punishments", POSTPunishments.class);
//httpPut(router, "/punishments/:punishmentId", PUTPunishmentsId.class);
httpDelete(router, "/punishments/:punishmentId", DELETEPunishmentsId.class);
httpDelete(router, "/users/:userId/activePunishment", DELETEUsersIdActivePunishment.class);
http.get("/ranks/:rankId").handler(new GETRanksId());
http.get("/ranks").handler(new GETRanks());
http.post("/ranks").blockingHandler(new POSTRanks(), false);
//http.put("/ranks/:rankId").blockingHandler(new PUTRanksId(), false);
http.delete("/ranks/:rankId").blockingHandler(new DELETERanksId(), false);
httpGet(router, "/ranks/:rankId", GETRanksId.class);
httpGet(router, "/ranks", GETRanks.class);
httpPost(router, "/ranks", POSTRanks.class);
//httpPut(router, "/ranks/:rankId", PUTRanksId.class);
httpDelete(router, "/ranks/:rankId", DELETERanksId.class);
http.get("/serverGroups/:serverGroupId").handler(new GETServerGroupsId());
http.get("/serverGroups").handler(new GETServerGroups());
http.post("/serverGroups").blockingHandler(new POSTServerGroups(), false);
//http.put("/serverGroups/:serverGroupId").blockingHandler(new PUTServerGroupsId(), false);
http.delete("/serverGroups/:serverGroupId").blockingHandler(new DELETEServerGroupsId(), false);
httpGet(router, "/serverGroups/:serverGroupId", GETServerGroupsId.class);
httpGet(router, "/serverGroups", GETServerGroups.class);
httpPost(router, "/serverGroups", POSTServerGroups.class);
//httpPut(router, "/serverGroups/:serverGroupId", PUTServerGroupsId.class);
httpDelete(router, "/serverGroups/:serverGroupId", DELETEServerGroupsId.class);
http.get("/servers/:serverId").handler(new GETServersId());
http.get("/servers").handler(new GETServers());
http.post("/servers/heartbeat").handler(new POSTServersHeartbeat());
http.post("/servers").blockingHandler(new POSTServers(), false);
//http.put("/servers/:serverId").blockingHandler(new PUTServersId(), false);
http.delete("/servers/:serverId").blockingHandler(new DELETEServersId(), false);
httpGet(router, "/servers/:serverId", GETServersId.class);
httpGet(router, "/servers", GETServers.class);
httpPost(router, "/servers/heartbeat", POSTServersHeartbeat.class);
httpPost(router, "/servers", POSTServers.class);
//httpPut(router, "/servers/:serverId", PUTServersId.class);
httpDelete(router, "/servers/:serverId", DELETEServersId.class);
http.get("/staff").blockingHandler(new GETStaff(), false);
http.get("/users/:userId").handler(new GETUsersId());
http.get("/users/:userId/compoundedPermissions").handler(new GETUsersIdCompoundedPermissions());
http.get("/users/:userId/details").blockingHandler(new GETUsersIdDetails(), false);
http.get("/users/:userId/requiresTotp").handler(new GETUsersIdRequiresTotp());
http.get("/users/:userId/verifyPassword").blockingHandler(new GETUsersIdVerifyPassword(), false);
http.post("/users/:userId/changePassword").blockingHandler(new POSTUsersIdChangePassword(), false);
http.post("/users/:userId/confirmPhone").blockingHandler(new POSTUsersIdConfirmPhone(), false);
http.post("/users/:userId/login").handler(new POSTUsersIdLogin());
http.post("/users/:userId/notify").blockingHandler(new POSTUsersIdNotify(), false);
http.post("/users/:userId/passwordReset").blockingHandler(new POSTUsersIdPasswordReset(), false);
http.post("/users/:userId/registerEmail").blockingHandler(new POSTUsersIdRegisterEmail(), false);
http.post("/users/:userId/registerPhone").blockingHandler(new POSTUsersIdRegisterPhone(), false);
http.post("/users/usePasswordResetToken").blockingHandler(new POSTUsersUsePasswordResetToken(), false);
http.post("/users/:userId/setupTotp").blockingHandler(new POSTUsersIdSetupTotp(), false);
http.post("/users/:userId/verifyTotp").handler(new POSTUsersIdVerifyTotp());
httpGet(router, "/staff", GETStaff.class);
httpGet(router, "/users/:userId", GETUsersId.class);
httpGet(router, "/users/:userId/compoundedPermissions", GETUsersIdCompoundedPermissions.class);
httpGet(router, "/users/:userId/details", GETUsersIdDetails.class);
httpGet(router, "/users/:userId/requiresTotp", GETUsersIdRequiresTotp.class);
httpGet(router, "/users/:userId/verifyPassword", GETUsersIdVerifyPassword.class);
httpPost(router, "/users/:userId/changePassword", POSTUsersIdChangePassword.class);
httpPost(router, "/users/:userId/confirmPhone", POSTUsersIdConfirmPhone.class);
httpPost(router, "/users/:userId/login", POSTUsersIdLogin.class);
httpPost(router, "/users/:userId/notify", POSTUsersIdNotify.class);
httpPost(router, "/users/:userId/passwordReset", POSTUsersIdPasswordReset.class);
httpPost(router, "/users/:userId/registerEmail", POSTUsersIdRegisterEmail.class);
httpPost(router, "/users/:userId/registerPhone", POSTUsersIdRegisterPhone.class);
httpPost(router, "/users/usePasswordResetToken", POSTUsersUsePasswordResetToken.class);
httpPost(router, "/users/:userId/setupTotp", POSTUsersIdSetupTotp.class);
httpPost(router, "/users/:userId/verifyTotp", POSTUsersIdVerifyTotp.class);
http.get("/dumps/:dumpType").handler(new GETDumpsType());
http.get("/metrics").handler(new GETMetrics());
http.get("/search").blockingHandler(new GETSearch());
http.get("/whoami").handler(new GETWhoAmI());
http.post("/logout").handler(new POSTLogout());
httpGet(router, "/dumps/:dumpType", GETDumpsType.class);
httpGet(router, "/search", GETSearch.class);
httpGet(router, "/whoami", GETWhoAmI.class);
httpPost(router, "/logout", POSTLogout.class);
int port = Integer.parseInt(config.getProperty("http.port"));
webServer.requestHandler(http::accept).listen(port);
int port = environment.getProperty("http.port", Integer.class);
webServer.requestHandler(router::accept).listen(port);
}
public static void respondJson(RoutingContext ctx, int code, Object response) {
@ -473,4 +308,16 @@ public final class APIv3 extends AbstractVerticle {
}
}
private void httpGet(Router router, String route, Class<?> handler) {
router.get(route).blockingHandler((Handler<RoutingContext>) SpringUtils.getBean(handler), false);
}
private void httpPost(Router router, String route, Class<?> handler) {
router.post(route).blockingHandler((Handler<RoutingContext>) SpringUtils.getBean(handler), false);
}
private void httpDelete(Router router, String route, Class<?> handler) {
router.delete(route).blockingHandler((Handler<RoutingContext>) SpringUtils.getBean(handler), false);
}
}

View File

@ -1,16 +1,28 @@
package net.frozenorb.apiv3;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.ext.dropwizard.DropwizardMetricsOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
final class Main {
import javax.annotation.PostConstruct;
import io.vertx.core.Vertx;
@SpringBootApplication
@EnableScheduling
class Main {
@Autowired private APIv3 verticle;
public static void main(String[] args) {
System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
Vertx.vertx(new VertxOptions().setMetricsOptions(
new DropwizardMetricsOptions().setEnabled(true).setRegistryName("apiv3-registry")
)).deployVerticle(new APIv3());
SpringApplication.run(Main.class, args);
}
@PostConstruct
public void deployVerticle() {
Vertx.vertx().deployVerticle(verticle);
}
}

View File

@ -0,0 +1,23 @@
package net.frozenorb.apiv3.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
@Configuration
public class HttpClientConfig {
@Bean
public HttpClient httpsClient(Vertx vertx) {
return vertx.createHttpClient(new HttpClientOptions().setSsl(true).setTrustAll(true));
}
@Bean
public HttpClient httpClient(Vertx vertx) {
return vertx.createHttpClient();
}
}

View File

@ -0,0 +1,139 @@
package net.frozenorb.apiv3.config;
import com.google.common.collect.ImmutableList;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.mongodb.ConnectionString;
import com.mongodb.MongoCredential;
import com.mongodb.async.client.MongoClient;
import com.mongodb.async.client.MongoClientSettings;
import com.mongodb.async.client.MongoClients;
import com.mongodb.async.client.MongoDatabase;
import com.mongodb.client.model.IndexModel;
import com.mongodb.connection.ClusterSettings;
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 org.bson.Document;
import org.bson.codecs.BsonValueCodecProvider;
import org.bson.codecs.DocumentCodecProvider;
import org.bson.codecs.ValueCodecProvider;
import org.bson.codecs.configuration.CodecRegistries;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Instant;
import java.util.List;
import java.util.UUID;
import fr.javatic.mongo.jacksonCodec.JacksonCodecProvider;
import fr.javatic.mongo.jacksonCodec.ObjectMapperFactory;
@Configuration
public class MongoConfig {
@Bean
public MongoDatabase mongoDatabase(
@Value("${mongo.username}") String username,
@Value("${mongo.database}") String database,
@Value("${mongo.password}") String password,
@Value("${mongo.address}") String address,
@Value("${mongo.port}") int port
) {
List<MongoCredential> credentials = ImmutableList.of();
if (!username.isEmpty()) {
credentials = ImmutableList.of(
MongoCredential.createCredential(username, database, password.toCharArray())
);
}
ConnectionString connectionString = new ConnectionString("mongodb://" + address + ":" + port);
MongoClient mongoClient = MongoClients.create(MongoClientSettings
.builder()
.codecRegistry(CodecRegistries.fromProviders(ImmutableList.of(
new UuidCodecProvider(), // MHQ, fixes uuid serialization
new ValueCodecProvider(),
new DocumentCodecProvider(),
new BsonValueCodecProvider(),
new JacksonCodecProvider(createMongoJacksonMapper()) // Jackson codec, provides serialization/deserialization
)))
.credentialList(credentials)
.clusterSettings(ClusterSettings.builder()
.applyConnectionString(connectionString)
.build()
)
.build()
);
MongoDatabase db = mongoClient.getDatabase(database);
db.getCollection("auditLog").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1)),
new IndexModel(new Document("performedAt", 1)),
new IndexModel(new Document("type", 1))
), (a, b) -> {});
db.getCollection("grants").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1)),
new IndexModel(new Document("rank", 1)),
new IndexModel(new Document("addedAt", 1))
), (a, b) -> {});
db.getCollection("ipLog").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1)),
new IndexModel(new Document("user", 1).append("userIp", 1)),
new IndexModel(new Document("hashedUserIp", 1))
), (a, b) -> {});
db.getCollection("ipBans").createIndexes(ImmutableList.of(
new IndexModel(new Document("userIp", 1))
), (a, b) -> {});
db.getCollection("ipIntel").createIndexes(ImmutableList.of(
new IndexModel(new Document("hashedIp", 1)),
new IndexModel(new Document("location", "2dsphere"))
), (a, b) -> {});
db.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("linkedIpBanId", 1))
), (a, b) -> {});
db.getCollection("users").createIndexes(ImmutableList.of(
new IndexModel(new Document("lastUsername", 1)),
new IndexModel(new Document("lastUsernameLower", 1)),
new IndexModel(new Document("emailToken", 1))
), (a, b) -> {});
db.getCollection("userMeta").createIndexes(ImmutableList.of(
new IndexModel(new Document("user", 1).append("serverGroup", 1))
), (a, b) -> {});
return db;
}
private ObjectMapper createMongoJacksonMapper() {
ObjectMapper mongoJacksonMapper = ObjectMapperFactory.createObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Instant.class, new InstantJsonSerializer());
module.addDeserializer(Instant.class, new InstantJsonDeserializer());
module.addSerializer(UUID.class, new UuidJsonSerializer());
module.addDeserializer(UUID.class, new UuidJsonDeserializer());
mongoJacksonMapper.registerModule(module);
mongoJacksonMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
mongoJacksonMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mongoJacksonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mongoJacksonMapper;
}
}

View File

@ -0,0 +1,27 @@
package net.frozenorb.apiv3.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.vertx.core.Vertx;
import io.vertx.redis.RedisClient;
import io.vertx.redis.RedisOptions;
@Configuration
public class RedisConfig {
@Bean
public RedisClient redisClient(Vertx vertx, RedisOptions redisOptions) {
return RedisClient.create(vertx, redisOptions);
}
@Bean
public RedisOptions redisOptions(
@Value("${redis.address}") String address,
@Value("${redis.port}") int port
) {
return new RedisOptions().setAddress(address).setPort(port);
}
}

View File

@ -0,0 +1,18 @@
package net.frozenorb.apiv3.disposablelogintoken;
import com.mongodb.async.SingleResultCallback;
import net.frozenorb.apiv3.model.User;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public interface DisposableLoginTokenService {
void attemptLogin(String token, String userIp, SingleResultCallback<User> callback);
void createToken(UUID user, String userIp, SingleResultCallback<String> callback);
}

View File

@ -0,0 +1,68 @@
package net.frozenorb.apiv3.disposablelogintoken;
import com.mongodb.async.SingleResultCallback;
import net.frozenorb.apiv3.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import io.vertx.redis.RedisClient;
@Component
public final class RedisDisposableLoginTokenService implements DisposableLoginTokenService {
@Autowired private RedisClient redisClient;
@Override
public void attemptLogin(String token, String userIp, SingleResultCallback<User> callback) {
if (token == null || token.isEmpty()) {
callback.onResult(null, null);
return;
}
redisClient.get("apiv3:disposableLoginTokens:" + userIp + ":" + token, (result) -> {
if (result.failed()) {
callback.onResult(null, result.cause());
return;
}
if (result.result() == null) {
callback.onResult(null, null);
return;
}
User.findById(result.result(), (user, error) -> {
if (error != null) {
callback.onResult(null, error);
return;
}
redisClient.del("apiv3:disposableLoginTokens:" + userIp + ":" + token, (result2) -> {
if (result2.failed()) {
callback.onResult(null, result2.cause());
} else {
callback.onResult(user, null);
}
});
});
});
}
@Override
public void createToken(UUID user, String userIp, SingleResultCallback<String> callback) {
String token = UUID.randomUUID().toString().replaceAll("-", "");
redisClient.setex("apiv3:disposableLoginTokens:" + userIp + ":" + token, TimeUnit.MINUTES.toSeconds(5), user.toString(), (result) -> {
if (result.succeeded()) {
callback.onResult(token, null);
} else {
callback.onResult(null, result.cause());
}
});
}
}

View File

@ -0,0 +1,10 @@
package net.frozenorb.apiv3.email;
import org.springframework.stereotype.Service;
@Service
public interface EmailDomainService {
boolean isBannedDomain(String email);
}

View File

@ -0,0 +1,14 @@
package net.frozenorb.apiv3.email;
import com.mongodb.async.SingleResultCallback;
import net.frozenorb.apiv3.unsorted.Notification;
import org.springframework.stereotype.Service;
@Service
public interface EmailService {
void sendEmail(Notification notification, String target, SingleResultCallback<Void> callback);
}

View File

@ -0,0 +1,37 @@
package net.frozenorb.apiv3.email;
import com.google.common.collect.ImmutableSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Set;
import io.vertx.core.http.HttpClient;
// no RestTemplate because we don't depend on spring-web yet
@Component
public final class GitHubEmailDomainService implements EmailDomainService {
@Autowired private HttpClient httpsClient;
private Set<String> bannedDomains = ImmutableSet.of();
// 10 minutes, can't use TimeUnit expression in annotation
@Scheduled(fixedRate = 10 * 60 * 1000)
private void updateDomains() {
httpsClient.get(443, "raw.githubusercontent.com", "/martenson/disposable-email-domains/master/disposable_email_blacklist.conf", (response) -> {
response.bodyHandler(body -> bannedDomains = ImmutableSet.copyOf(body.toString().split("\n")));
response.exceptionHandler(Throwable::printStackTrace);
}).end();
}
@Override
public boolean isBannedDomain(String email) {
String[] split = email.split("@");
String domain = split[1];
return bannedDomains.contains(domain.toLowerCase());
}
}

View File

@ -0,0 +1,64 @@
package net.frozenorb.apiv3.email;
import com.google.common.net.MediaType;
import com.mongodb.async.SingleResultCallback;
import net.frozenorb.apiv3.unsorted.Notification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
@Component
public final class MandrillEmailService implements EmailService {
@Autowired private HttpClient httpClient;
@Value("${mandrill.apiKey}") String apiKey;
@Value("${mandrill.fromEmail}") String fromEmail;
@Value("${mandrill.fromName}") String fromName;
@Override
public void sendEmail(Notification notification, String target, SingleResultCallback<Void> callback) {
JsonObject requestBody = new JsonObject()
.put("key", apiKey)
.put("message", new JsonObject()
.put("html", notification.getBody())
.put("subject", notification.getSubject())
.put("from_email", fromEmail)
.put("from_name", fromName)
.put("to", new JsonArray()
.add(new JsonObject()
.put("email", target)
)
)
);
httpClient.post("mandrillapp.com", "/api/1.0/messages/send.json", (response) -> {
response.bodyHandler((responseBody) -> {
try {
JsonArray bodyJson = new JsonArray(responseBody.toString());
JsonObject emailJson = bodyJson.getJsonObject(0);
String emailStatus = emailJson.getString("status");
if (emailStatus.equals("rejected") || emailStatus.equals("invalid")) {
callback.onResult(null, new IOException("Illegal email status while reading Mandrill response: " + emailStatus + " (" + emailJson.encode() + ")"));
} else {
callback.onResult(null, null);
}
} catch (Exception ex) {
callback.onResult(null, new IOException("Failed to process Mandrill response: " + responseBody, ex));
}
});
response.exceptionHandler((error) -> callback.onResult(null, error));
}).putHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString()).end(requestBody.encode());
}
}

View File

@ -7,9 +7,12 @@ import net.frozenorb.apiv3.actor.SimpleActor;
import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class AuthenticationFilter implements Handler<RoutingContext> {
@Override

View File

@ -5,9 +5,12 @@ import com.google.common.collect.ImmutableMap;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class AuthorizationFilter implements Handler<RoutingContext> {
@Override

View File

@ -1,19 +1,16 @@
package net.frozenorb.apiv3.filter;
import net.frozenorb.apiv3.APIv3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import io.vertx.redis.RedisClient;
import io.vertx.redis.RedisOptions;
@Component
public final class MetricsFilter implements Handler<RoutingContext> {
private static final RedisClient redisClient = RedisClient.create(APIv3.getVertxInstance(),
new RedisOptions()
.setAddress(APIv3.getConfig().getProperty("redis.address"))
.setPort(Integer.parseInt(APIv3.getConfig().getProperty("redis.port")))
);
@Autowired private RedisClient redisClient;
@Override
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import com.google.common.collect.ImmutableMap;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.usersession.UserSessionService;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.UserSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpMethod;
@ -14,8 +17,11 @@ import io.vertx.ext.web.RoutingContext;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public final class WebsiteUserSessionFilter implements Handler<RoutingContext> {
@Autowired private UserSessionService userSessionService;
@Override
public void handle(RoutingContext ctx) {
Actor actor = ctx.get("actor");
@ -38,7 +44,7 @@ public final class WebsiteUserSessionFilter implements Handler<RoutingContext> {
return;
}
UserSessionUtils.sessionExists(userIp, userSession, (exists, error) -> {
userSessionService.sessionExists(userIp, userSession, (exists, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
return;
@ -78,7 +84,6 @@ public final class WebsiteUserSessionFilter implements Handler<RoutingContext> {
/*if (method == HttpMethod.GET) {
switch (path) {
case "/ranks":
case "/metrics":
case "/staff":
case "/servers":
case "/servergroups":

View File

@ -1,22 +1,20 @@
package net.frozenorb.apiv3.maxmind;
import net.frozenorb.apiv3.util.MaxMindUtils;
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindCity {
public final class GeoIpCity {
@Getter private int confidence;
@Getter private int geonameId;
@Getter private String name;
private MaxMindCity() {} // For Jackson
private GeoIpCity() {} // For Jackson
public MaxMindCity(JsonObject legacy) {
public GeoIpCity(JsonObject legacy) {
this.confidence = legacy.getInteger("confidence", -1);
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = MaxMindUtils.getEnglishName(legacy);
this.name = legacy.getJsonObject("names", new JsonObject()).getString("en", "INVALID");
}
}

View File

@ -0,0 +1,20 @@
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class GeoIpContinent {
@Getter private String code;
@Getter private int geonameId;
@Getter private String name;
private GeoIpContinent() {} // For Jackson
public GeoIpContinent(JsonObject legacy) {
this.code = legacy.getString("code", "");
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = legacy.getJsonObject("names", new JsonObject()).getString("en", "INVALID");
}
}

View File

@ -1,24 +1,22 @@
package net.frozenorb.apiv3.maxmind;
import net.frozenorb.apiv3.util.MaxMindUtils;
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindCountry {
public final class GeoIpCountry {
@Getter private String isoCode;
@Getter private int confidence;
@Getter private int geonameId;
@Getter private String name;
private MaxMindCountry() {} // For Jackson
private GeoIpCountry() {} // For Jackson
public MaxMindCountry(JsonObject legacy) {
public GeoIpCountry(JsonObject legacy) {
this.isoCode = legacy.getString("iso_code", "");
this.confidence = legacy.getInteger("confidence", -1);
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = MaxMindUtils.getEnglishName(legacy);
this.name = legacy.getJsonObject("names", new JsonObject()).getString("en", "INVALID");
}
}

View File

@ -0,0 +1,43 @@
package net.frozenorb.apiv3.geoip;
import com.google.common.collect.ImmutableList;
import java.util.LinkedList;
import java.util.List;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class GeoIpInfo {
@Getter private GeoIpContinent continent;
@Getter private GeoIpCity city;
@Getter private GeoIpPostal postal;
@Getter private GeoIpTraits traits;
@Getter private GeoIpLocation location;
@Getter private List<GeoIpSubdivision> subdivisions;
@Getter private GeoIpCountry country;
@Getter private GeoIpRegisteredCountry registeredCountry;
private GeoIpInfo() {} // For Jackson
public GeoIpInfo(JsonObject legacy) {
this.continent = new GeoIpContinent(legacy.getJsonObject("continent", new JsonObject()));
this.city = new GeoIpCity(legacy.getJsonObject("city", new JsonObject()));
this.postal = new GeoIpPostal(legacy.getJsonObject("postal", new JsonObject()));
this.traits = new GeoIpTraits(legacy.getJsonObject("traits"));
this.location = new GeoIpLocation(legacy.getJsonObject("location", new JsonObject()));
this.country = new GeoIpCountry(legacy.getJsonObject("country", new JsonObject()));
this.registeredCountry = new GeoIpRegisteredCountry(legacy.getJsonObject("registered_country", new JsonObject()));
List<GeoIpSubdivision> subdivisions = new LinkedList<>();
for (Object subdivision : legacy.getJsonArray("subdivisions", new JsonArray())) {
subdivisions.add(new GeoIpSubdivision((JsonObject) subdivision));
}
this.subdivisions = ImmutableList.copyOf(subdivisions);
}
}

View File

@ -1,9 +1,9 @@
package net.frozenorb.apiv3.maxmind;
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindLocation {
public final class GeoIpLocation {
@Getter private double latitude;
@Getter private double longitude;
@ -13,9 +13,9 @@ public final class MaxMindLocation {
@Getter private int metroCode;
@Getter private int averageIncome;
private MaxMindLocation() {} // For Jackson
private GeoIpLocation() {} // For Jackson
public MaxMindLocation(JsonObject legacy) {
public GeoIpLocation(JsonObject legacy) {
this.latitude = legacy.getDouble("latitude", -1D);
this.longitude = legacy.getDouble("longitude", -1D);
this.accuracyRadius = legacy.getInteger("accuracy_radius", -1);

View File

@ -1,16 +1,16 @@
package net.frozenorb.apiv3.maxmind;
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindPostal {
public final class GeoIpPostal {
@Getter private String code;
@Getter private int confidence;
private MaxMindPostal() {} // For Jackson
private GeoIpPostal() {} // For Jackson
public MaxMindPostal(JsonObject legacy) {
public GeoIpPostal(JsonObject legacy) {
this.code = legacy.getString("code", "");
this.confidence = legacy.getInteger("confidence", -1);
}

View File

@ -0,0 +1,20 @@
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class GeoIpRegisteredCountry {
@Getter private String isoCode;
@Getter private int geonameId;
@Getter private String name;
private GeoIpRegisteredCountry() {} // For Jackson
public GeoIpRegisteredCountry(JsonObject legacy) {
this.isoCode = legacy.getString("iso_code", "");
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = legacy.getJsonObject("names", new JsonObject()).getString("en", "INVALID");
}
}

View File

@ -0,0 +1,12 @@
package net.frozenorb.apiv3.geoip;
import com.mongodb.async.SingleResultCallback;
import org.springframework.stereotype.Service;
@Service
public interface GeoIpService {
void lookupInfo(String ip, SingleResultCallback<GeoIpInfo> callback);
}

View File

@ -1,24 +1,22 @@
package net.frozenorb.apiv3.maxmind;
import net.frozenorb.apiv3.util.MaxMindUtils;
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindSubdivision {
public final class GeoIpSubdivision {
@Getter private String isoCode;
@Getter private int confidence;
@Getter private int geonameId;
@Getter private String name;
private MaxMindSubdivision() {} // For Jackson
private GeoIpSubdivision() {} // For Jackson
public MaxMindSubdivision(JsonObject legacy) {
public GeoIpSubdivision(JsonObject legacy) {
this.isoCode = legacy.getString("iso_code", "");
this.confidence = legacy.getInteger("confidence", -1);
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = MaxMindUtils.getEnglishName(legacy);
this.name = legacy.getJsonObject("names", new JsonObject()).getString("en", "INVALID");
}
}

View File

@ -1,25 +1,25 @@
package net.frozenorb.apiv3.maxmind;
package net.frozenorb.apiv3.geoip;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindTraits {
public final class GeoIpTraits {
@Getter private String isp;
@Getter private String domain;
@Getter private int asn;
@Getter private String asnOrganization;
@Getter private MaxMindUserType userType;
@Getter private GeoIpUserType userType;
@Getter private String organization;
private MaxMindTraits() {} // For Jackson
private GeoIpTraits() {} // For Jackson
public MaxMindTraits(JsonObject legacy) {
public GeoIpTraits(JsonObject legacy) {
this.isp = legacy.getString("isp", "");
this.domain = legacy.getString("domain", "");
this.asn = legacy.getInteger("autonomous_system_number", -1);
this.asnOrganization = legacy.getString("autonomous_system_organization", "");
this.userType = legacy.containsKey("user_type") ? MaxMindUserType.valueOf(legacy.getString("user_type").toUpperCase()) : MaxMindUserType.UNKNOWN;
this.userType = legacy.containsKey("user_type") ? GeoIpUserType.valueOf(legacy.getString("user_type").toUpperCase()) : GeoIpUserType.UNKNOWN;
this.organization = legacy.getString("organization", "");
}

View File

@ -1,8 +1,8 @@
package net.frozenorb.apiv3.maxmind;
package net.frozenorb.apiv3.geoip;
import lombok.Getter;
public enum MaxMindUserType {
public enum GeoIpUserType {
BUSINESS(true),
CAFE(true),
@ -23,7 +23,7 @@ public enum MaxMindUserType {
@Getter private final boolean allowed;
MaxMindUserType(boolean allowed) {
GeoIpUserType(boolean allowed) {
this.allowed = allowed;
}

View File

@ -0,0 +1,81 @@
package net.frozenorb.apiv3.geoip;
import com.google.common.base.Charsets;
import com.mongodb.async.SingleResultCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Base64;
import io.vertx.circuitbreaker.CircuitBreaker;
import io.vertx.circuitbreaker.CircuitBreakerOptions;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.json.JsonObject;
@Component
public final class MaxMindGeoIpService implements GeoIpService {
@Autowired private HttpClient httpsClient;
@Value("${maxMind.userId}") private String userId;
@Value("${maxMind.licenseKey}") private String licenseKey;
private final CircuitBreaker breaker;
// MaxMind likes to randomly not respond, so we take advantage of the circuit breaker pattern to only
// check MaxMind periodically (while it's in a non-responsive state) to keep our average response times
// nice and low.
@Autowired
public MaxMindGeoIpService(Vertx vertx) {
this.breaker = CircuitBreaker.create(getClass().getName(), vertx,
new CircuitBreakerOptions()
.setMaxFailures(5)
.setTimeout(5000) // 5 seconds
.setFallbackOnFailure(true)
.setResetTimeout(120_000) // 2 minutes
);
}
@Override
public void lookupInfo(String ip, SingleResultCallback<GeoIpInfo> callback) {
breaker.execute((future) -> {
String authHeader = "Basic " + Base64.getEncoder().encodeToString((userId + ":" + licenseKey).getBytes(Charsets.UTF_8));
httpsClient.get(443, "geoip.maxmind.com", "/geoip/v2.1/insights/" + ip, (response) -> {
response.bodyHandler((body) -> {
JsonObject bodyJson = new JsonObject(body.toString());
try {
GeoIpInfo geoIpInfo = new GeoIpInfo(bodyJson);
// we have to check !isComplete() because the circuit breaker's timeout might mark us as failed already
if (!future.isComplete()) {
future.complete(geoIpInfo);
}
} catch (Exception ignored) {
// we have to check !isComplete() because the circuit breaker's timeout might mark us as failed already
if (!future.isComplete()) {
future.complete(null);
}
}
});
response.exceptionHandler((error) -> {
// we have to check !isComplete() because the circuit breaker's timeout will might us as failed already
if (!future.isComplete()) {
future.fail(error);
}
});
}).putHeader("Authorization", authHeader).end();
}).setHandler((result) -> {
if (result.failed()) {
callback.onResult(null, result.cause());
} else {
callback.onResult((GeoIpInfo) result.result(), null);
}
});
}
}

View File

@ -1,22 +0,0 @@
package net.frozenorb.apiv3.maxmind;
import net.frozenorb.apiv3.util.MaxMindUtils;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindContinent {
@Getter private String code;
@Getter private int geonameId;
@Getter private String name;
private MaxMindContinent() {} // For Jackson
public MaxMindContinent(JsonObject legacy) {
this.code = legacy.getString("code", "");
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = MaxMindUtils.getEnglishName(legacy);
}
}

View File

@ -1,22 +0,0 @@
package net.frozenorb.apiv3.maxmind;
import net.frozenorb.apiv3.util.MaxMindUtils;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
public final class MaxMindRegisteredCountry {
@Getter private String isoCode;
@Getter private int geonameId;
@Getter private String name;
private MaxMindRegisteredCountry() {} // For Jackson
public MaxMindRegisteredCountry(JsonObject legacy) {
this.isoCode = legacy.getString("iso_code", "");
this.geonameId = legacy.getInteger("geoname_id", -1);
this.name = MaxMindUtils.getEnglishName(legacy);
}
}

View File

@ -1,43 +0,0 @@
package net.frozenorb.apiv3.maxmind;
import com.google.common.collect.ImmutableList;
import java.util.LinkedList;
import java.util.List;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import lombok.Getter;
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 List<MaxMindSubdivision> subdivisions;
@Getter private MaxMindCountry country;
@Getter private MaxMindRegisteredCountry registeredCountry;
private MaxMindResult() {} // For Jackson
public MaxMindResult(JsonObject legacy) {
this.continent = new MaxMindContinent(legacy.getJsonObject("continent", new JsonObject()));
this.city = new MaxMindCity(legacy.getJsonObject("city", new JsonObject()));
this.postal = new MaxMindPostal(legacy.getJsonObject("postal", new JsonObject()));
this.traits = new MaxMindTraits(legacy.getJsonObject("traits"));
this.location = new MaxMindLocation(legacy.getJsonObject("location", new JsonObject()));
this.country = new MaxMindCountry(legacy.getJsonObject("country", new JsonObject()));
this.registeredCountry = new MaxMindRegisteredCountry(legacy.getJsonObject("registered_country", new JsonObject()));
List<MaxMindSubdivision> subdivisions = new LinkedList<>();
for (Object subdivision : legacy.getJsonArray("subdivisions", new JsonArray())) {
subdivisions.add(new MaxMindSubdivision((JsonObject) subdivision));
}
this.subdivisions = ImmutableList.copyOf(subdivisions);
}
}

View File

@ -4,10 +4,11 @@ import com.google.common.collect.ImmutableList;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -27,7 +28,7 @@ import lombok.Setter;
@AllArgsConstructor
public final class AccessToken {
private static final MongoCollection<AccessToken> accessTokensCollection = APIv3.getDatabase().getCollection("accessTokens", AccessToken.class);
private static final MongoCollection<AccessToken> accessTokensCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("accessTokens", AccessToken.class);
@Getter @Id private String id;
@Getter private String actorName;

View File

@ -4,11 +4,12 @@ import com.google.common.collect.ImmutableMap;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -27,7 +28,7 @@ import lombok.Getter;
@Entity
public final class AuditLogEntry {
private static final MongoCollection<AuditLogEntry> auditLogCollection = APIv3.getDatabase().getCollection("auditLog", AuditLogEntry.class);
private static final MongoCollection<AuditLogEntry> auditLogCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("auditLog", AuditLogEntry.class);
@Getter @Id private String id;
@Getter private UUID user;

View File

@ -4,9 +4,10 @@ import com.google.common.collect.ImmutableList;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -20,13 +21,14 @@ import java.util.concurrent.TimeUnit;
import fr.javatic.mongo.jacksonCodec.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id;
import io.vertx.core.Vertx;
import lombok.Getter;
import lombok.Setter;
@Entity
public final class BannedAsn {
private static final MongoCollection<BannedAsn> bannedAsnsCollection = APIv3.getDatabase().getCollection("bannedAsns", BannedAsn.class);
private static final MongoCollection<BannedAsn> bannedAsnsCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("bannedAsns", BannedAsn.class);
private static Map<Integer, BannedAsn> bannedAsnIdCache = null;
private static List<BannedAsn> bannedAsnCache = null;
@ -45,7 +47,7 @@ public final class BannedAsn {
}
static {
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateCache());
SpringUtils.getBean(Vertx.class).setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateCache());
}
public static void updateCache() {

View File

@ -5,9 +5,10 @@ import com.google.common.collect.ImmutableList;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -21,13 +22,14 @@ import java.util.concurrent.TimeUnit;
import fr.javatic.mongo.jacksonCodec.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id;
import io.vertx.core.Vertx;
import lombok.Getter;
import lombok.Setter;
@Entity
public final class BannedCellCarrier {
private static final MongoCollection<BannedCellCarrier> bannedCellCarriersCollection = APIv3.getDatabase().getCollection("bannedCellCarriers", BannedCellCarrier.class);
private static final MongoCollection<BannedCellCarrier> bannedCellCarriersCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("bannedCellCarriers", BannedCellCarrier.class);
private static Map<Integer, BannedCellCarrier> bannedCellCarrierIdCache = null;
private static List<BannedCellCarrier> bannedCellCarrierCache = null;
@ -46,7 +48,7 @@ public final class BannedCellCarrier {
}
static {
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateCache());
SpringUtils.getBean(Vertx.class).setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateCache());
}
public static void updateCache() {

View File

@ -2,9 +2,10 @@ package net.frozenorb.apiv3.model;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -19,7 +20,7 @@ import lombok.Getter;
@Entity
public final class ChatFilterEntry {
private static final MongoCollection<ChatFilterEntry> chatFilterCollection = APIv3.getDatabase().getCollection("chatFilter", ChatFilterEntry.class);
private static final MongoCollection<ChatFilterEntry> chatFilterCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("chatFilter", ChatFilterEntry.class);
@Getter @Id private String id;
@Getter private String regex;

View File

@ -4,9 +4,10 @@ import com.google.common.collect.Collections2;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -32,7 +33,7 @@ import lombok.Getter;
@AllArgsConstructor
public final class Grant {
private static final MongoCollection<Grant> grantsCollection = APIv3.getDatabase().getCollection("grants", Grant.class);
private static final MongoCollection<Grant> grantsCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("grants", Grant.class);
@Getter @Id private String id;
@Getter private UUID user;

View File

@ -2,11 +2,12 @@ package net.frozenorb.apiv3.model;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TimeUtils;
@ -29,7 +30,7 @@ import lombok.Getter;
@AllArgsConstructor
public final class IpBan {
private static final MongoCollection<IpBan> ipBansCollection = APIv3.getDatabase().getCollection("ipBans", IpBan.class);
private static final MongoCollection<IpBan> ipBansCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("ipBans", IpBan.class);
@Getter @Id private String id;
@Getter private String userIp;

View File

@ -5,14 +5,16 @@ import com.google.common.hash.Hashing;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.maxmind.MaxMindResult;
import net.frozenorb.apiv3.geoip.GeoIpInfo;
import net.frozenorb.apiv3.geoip.GeoIpService;
import net.frozenorb.apiv3.util.GeoJsonPoint;
import net.frozenorb.apiv3.util.MaxMindUtils;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import org.springframework.core.env.Environment;
import java.time.Instant;
import java.util.ArrayList;
@ -34,12 +36,12 @@ import lombok.Setter;
@AllArgsConstructor
public final class IpIntel {
private static final MongoCollection<IpIntel> ipIntelCollection = APIv3.getDatabase().getCollection("ipIntel", IpIntel.class);
private static final MongoCollection<IpIntel> ipIntelCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("ipIntel", IpIntel.class);
@Getter @Setter @Id private String id;
@Getter private String hashedIp;
@Getter private Instant lastUpdatedAt;
@Getter private MaxMindResult result;
@Getter private GeoIpInfo result;
@Getter private GeoJsonPoint location;
public static void findAllNoSort(SingleResultCallback<List<IpIntel>> callback) {
@ -65,11 +67,11 @@ public final class IpIntel {
} else if (existingIpIntel != null) {
callback.onResult(existingIpIntel, null);
} else {
MaxMindUtils.getInsights(id, (maxMindResult, error2) -> {
SpringUtils.getBean(GeoIpService.class).lookupInfo(id, (geoIpResult, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
} else if (maxMindResult != null) {
IpIntel newIpIntel = new IpIntel(id, maxMindResult);
} else if (geoIpResult != null) {
IpIntel newIpIntel = new IpIntel(id, geoIpResult);
ipIntelCollection.insertOne(newIpIntel, SyncUtils.vertxWrap((ignored, error3) -> {
if (error3 != null) {
@ -110,19 +112,19 @@ public final class IpIntel {
Future createNewIntelFuture = Future.future();
createNewIntelFutures.add(createNewIntelFuture);
MaxMindUtils.getInsights(ip, (maxMindResult, error2) -> {
SpringUtils.getBean(GeoIpService.class).lookupInfo(ip, (geoIpResult, error2) -> {
if (error2 != null) {
createNewIntelFuture.fail(error2);
return;
}
// MaxMind failed to return result
if (maxMindResult == null) {
if (geoIpResult == null) {
createNewIntelFuture.complete();
return;
}
IpIntel newIpIntel = new IpIntel(ip, maxMindResult);
IpIntel newIpIntel = new IpIntel(ip, geoIpResult);
ipIntelCollection.insertOne(newIpIntel, SyncUtils.vertxWrap((ignored, error3) -> {
if (error3 != null) {
@ -147,9 +149,9 @@ public final class IpIntel {
private IpIntel() {} // For Jackson
private IpIntel(String ip, MaxMindResult result) {
private IpIntel(String ip, GeoIpInfo result) {
this.id = ip;
this.hashedIp = Hashing.sha256().hashString(id + APIv3.getConfig().getProperty("ipHashing.salt"), Charsets.UTF_8).toString();
this.hashedIp = Hashing.sha256().hashString(id + SpringUtils.getBean(Environment.class).getProperty("ipHashing.salt"), Charsets.UTF_8).toString();
this.lastUpdatedAt = Instant.now();
this.result = result;
this.location = new GeoJsonPoint(result.getLocation());

View File

@ -5,13 +5,15 @@ import com.google.common.hash.Hashing;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.core.env.Environment;
import java.time.Instant;
import java.util.LinkedList;
@ -27,7 +29,7 @@ import lombok.Getter;
@AllArgsConstructor
public final class IpLogEntry {
private static final MongoCollection<IpLogEntry> ipLogCollection = APIv3.getDatabase().getCollection("ipLog", IpLogEntry.class);
private static final MongoCollection<IpLogEntry> ipLogCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("ipLog", IpLogEntry.class);
@Getter @Id private String id;
@Getter private UUID user;
@ -79,7 +81,7 @@ public final class IpLogEntry {
this.id = new ObjectId().toString();
this.user = user.getId();
this.userIp = userIp;
this.hashedUserIp = Hashing.sha256().hashString(userIp + APIv3.getConfig().getProperty("ipHashing.salt"), Charsets.UTF_8).toString();
this.hashedUserIp = Hashing.sha256().hashString(userIp + SpringUtils.getBean(Environment.class).getProperty("ipHashing.salt"), Charsets.UTF_8).toString();
this.firstSeenAt = Instant.now();
this.lastSeenAt = Instant.now();
this.uses = 0;

View File

@ -2,9 +2,10 @@ package net.frozenorb.apiv3.model;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -21,7 +22,7 @@ import lombok.Setter;
@Entity
public final class NotificationTemplate {
private static final MongoCollection<NotificationTemplate> notificationTemplatesCollection = APIv3.getDatabase().getCollection("notificationTemplates", NotificationTemplate.class);
private static final MongoCollection<NotificationTemplate> notificationTemplatesCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("notificationTemplates", NotificationTemplate.class);
@Getter @Id private String id;
@Getter @Setter private String subject;

View File

@ -2,12 +2,13 @@ package net.frozenorb.apiv3.model;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.sms.SmsCarrierInfo;
import net.frozenorb.apiv3.sms.SmsService;
import net.frozenorb.apiv3.util.PhoneUtils;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.ZangUtils;
import net.frozenorb.apiv3.zang.ZangResult;
import org.bson.Document;
@ -24,11 +25,11 @@ import lombok.Getter;
@AllArgsConstructor
public final class PhoneIntel {
private static final MongoCollection<PhoneIntel> phoneIntelCollection = APIv3.getDatabase().getCollection("phoneIntel", PhoneIntel.class);
private static final MongoCollection<PhoneIntel> phoneIntelCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("phoneIntel", PhoneIntel.class);
@Getter @Id private String id;
@Getter private Instant lastUpdatedAt;
@Getter private ZangResult result;
@Getter private SmsCarrierInfo result;
public static void findAll(SingleResultCallback<List<PhoneIntel>> callback) {
phoneIntelCollection.find().sort(new Document("lastSeenAt", -1)).into(new LinkedList<>(), SyncUtils.vertxWrap(callback));
@ -63,13 +64,14 @@ public final class PhoneIntel {
return;
}
ZangUtils.getCarrierInfo(e164Phone, (zangResult, error2) -> {
SpringUtils.getBean(SmsService.class).lookupCarrierInfo(e164Phone, (smsCarrierInfo, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
return;
}
PhoneIntel newPhoneIntel = new PhoneIntel(e164Phone, zangResult);
PhoneIntel newPhoneIntel = new PhoneIntel(e164Phone, smsCarrierInfo);
phoneIntelCollection.insertOne(newPhoneIntel, SyncUtils.vertxWrap((ignored, error3) -> {
if (error3 != null) {
@ -84,7 +86,7 @@ public final class PhoneIntel {
private PhoneIntel() {} // For Jackson
private PhoneIntel(String phoneNumber, ZangResult result) {
private PhoneIntel(String phoneNumber, SmsCarrierInfo result) {
this.id = phoneNumber;
this.lastUpdatedAt = Instant.now();
this.result = result;

View File

@ -2,11 +2,12 @@ package net.frozenorb.apiv3.model;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TimeUtils;
@ -31,7 +32,7 @@ import lombok.Getter;
@AllArgsConstructor
public final class Punishment {
private static final MongoCollection<Punishment> punishmentsCollection = APIv3.getDatabase().getCollection("punishments", Punishment.class);
private static final MongoCollection<Punishment> punishmentsCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("punishments", Punishment.class);
@Getter @Id private String id;
@Getter private UUID user;

View File

@ -4,9 +4,10 @@ import com.google.common.collect.ImmutableList;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -19,12 +20,13 @@ import java.util.concurrent.TimeUnit;
import fr.javatic.mongo.jacksonCodec.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id;
import io.vertx.core.Vertx;
import lombok.Getter;
@Entity
public final class Rank {
private static final MongoCollection<Rank> ranksCollection = APIv3.getDatabase().getCollection("ranks", Rank.class);
private static final MongoCollection<Rank> ranksCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("ranks", Rank.class);
private static Map<String, Rank> rankIdCache = null;
private static List<Rank> rankCache = null;
@ -51,7 +53,7 @@ public final class Rank {
}
static {
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateCache());
SpringUtils.getBean(Vertx.class).setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateCache());
}
public static void updateCache() {

View File

@ -5,10 +5,11 @@ import com.google.common.collect.ImmutableSet;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TimeUtils;
@ -26,13 +27,14 @@ import java.util.concurrent.TimeUnit;
import fr.javatic.mongo.jacksonCodec.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id;
import io.vertx.core.Vertx;
import lombok.Getter;
import lombok.Setter;
@Entity
public final class Server {
private static final MongoCollection<Server> serversCollection = APIv3.getDatabase().getCollection("servers", Server.class);
private static final MongoCollection<Server> serversCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("servers", Server.class);
private static Map<String, Server> serverIdCache = null;
private static List<Server> serverCache = null;
@ -54,8 +56,8 @@ public final class Server {
}
static {
APIv3.getVertxInstance().setPeriodic(TimeUnit.SECONDS.toMillis(15), (id) -> updateCache());
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateTimedOutServers());
SpringUtils.getBean(Vertx.class).setPeriodic(TimeUnit.SECONDS.toMillis(15), (id) -> updateCache());
SpringUtils.getBean(Vertx.class).setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> updateTimedOutServers());
}
public static void updateCache() {

View File

@ -5,11 +5,12 @@ import com.google.common.collect.ImmutableMap;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.util.PermissionUtils;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
@ -23,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import fr.javatic.mongo.jacksonCodec.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id;
import io.vertx.core.Vertx;
import lombok.Getter;
import lombok.Setter;
@ -30,7 +32,7 @@ import lombok.Setter;
public final class ServerGroup {
public static final String DEFAULT_GROUP_ID = "default";
private static final MongoCollection<ServerGroup> serverGroupsCollection = APIv3.getDatabase().getCollection("serverGroups", ServerGroup.class);
private static final MongoCollection<ServerGroup> serverGroupsCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("serverGroups", ServerGroup.class);
private static Map<String, ServerGroup> serverGroupIdCache = null;
private static List<ServerGroup> serverGroupCache = null;
@ -53,7 +55,7 @@ public final class ServerGroup {
}
static {
APIv3.getVertxInstance().setPeriodic(TimeUnit.SECONDS.toMillis(15), (id) -> updateCache());
SpringUtils.getBean(Vertx.class).setPeriodic(TimeUnit.SECONDS.toMillis(15), (id) -> updateCache());
}
public static void updateCache() {

View File

@ -12,24 +12,25 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.maxmind.MaxMindResult;
import net.frozenorb.apiv3.maxmind.MaxMindUserType;
import net.frozenorb.apiv3.geoip.GeoIpInfo;
import net.frozenorb.apiv3.geoip.GeoIpUserType;
import net.frozenorb.apiv3.mojang.MojangService;
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.totp.RequiresTotpResult;
import net.frozenorb.apiv3.totp.TotpAuthorizationResult;
import net.frozenorb.apiv3.totp.TotpService;
import net.frozenorb.apiv3.unsorted.MongoToVertxCallback;
import net.frozenorb.apiv3.unsorted.MongoToVoidMongoCallback;
import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.unsorted.RequiresTotpResult;
import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult;
import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.MojangUtils;
import net.frozenorb.apiv3.util.PermissionUtils;
import net.frozenorb.apiv3.util.PhoneUtils;
import net.frozenorb.apiv3.util.SpringUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TotpUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.bson.Document;
@ -60,7 +61,7 @@ import lombok.Setter;
@AllArgsConstructor
public final class User {
private static final MongoCollection<User> usersCollection = APIv3.getDatabase().getCollection("users", User.class);
private static final MongoCollection<User> usersCollection = SpringUtils.getBean(MongoDatabase.class).getCollection("users", User.class);
@Getter @Id @JsonSerialize(using = UuidJsonSerializer.class) @JsonDeserialize(using = UuidJsonDeserializer.class) private UUID id;
@Getter private String lastUsername;
@ -276,7 +277,7 @@ public final class User {
return;
}
MojangUtils.getName(collision.getId(), (collisionNewUsername, error2) -> {
SpringUtils.getBean(MojangService.class).getName(collision.getId(), (collisionNewUsername, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
return;
@ -427,8 +428,8 @@ public final class User {
}
});
} else if (ipIntel != null) {
MaxMindResult maxMindResult = ipIntel.getResult();
MaxMindUserType userType = maxMindResult.getTraits().getUserType();
GeoIpInfo geoIpInfo = ipIntel.getResult();
GeoIpUserType userType = geoIpInfo.getTraits().getUserType();
Map<String, Object> proposedAccess = null;
if (!userType.isAllowed()) {
@ -436,7 +437,7 @@ public final class User {
"allowed", false,
"message", "You cannot join the server from a VPN."
);
} else if (BannedAsn.findById(maxMindResult.getTraits().getAsn()) != null) {
} else if (BannedAsn.findById(geoIpInfo.getTraits().getAsn()) != null) {
proposedAccess = ImmutableMap.of(
"allowed", false,
"message", "You cannot join the server from this ISP."
@ -521,7 +522,9 @@ public final class User {
return;
}
TotpUtils.isPreAuthorized(this, ip, (ipPreAuth, error) -> {
TotpService totpService = SpringUtils.getBean(TotpService.class);
totpService.isPreAuthorized(this, ip, (ipPreAuth, error) -> {
if (error != null) {
callback.onResult(null, error);
} else if (ipPreAuth) {
@ -546,7 +549,9 @@ public final class User {
return;
}
TotpUtils.isPreAuthorized(this, ip, (preAuthorized, error) -> {
TotpService totpService = SpringUtils.getBean(TotpService.class);
totpService.isPreAuthorized(this, ip, (preAuthorized, error) -> {
if (error != null) {
callback.onResult(null, error);
return;
@ -557,7 +562,7 @@ public final class User {
return;
}
TotpUtils.wasRecentlyUsed(this, code, (recentlyUsed, error2) -> {
totpService.wasRecentlyUsed(this, code, (recentlyUsed, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
return;
@ -568,7 +573,7 @@ public final class User {
return;
}
if (!TotpUtils.authorizeUser(totpSecret, code)) {
if (!totpService.authorizeUser(totpSecret, code)) {
callback.onResult(TotpAuthorizationResult.NOT_AUTHORIZED_BAD_CODE, null);
return;
}
@ -576,8 +581,8 @@ public final class User {
Future<Void> markPreAuthFuture = Future.future();
Future<Void> markRecentlyUsedFuture = Future.future();
TotpUtils.markPreAuthorized(this, ip, 3, TimeUnit.DAYS, new MongoToVertxCallback<>(markPreAuthFuture));
TotpUtils.markRecentlyUsed(this, code, new MongoToVertxCallback<>(markRecentlyUsedFuture));
totpService.markPreAuthorized(this, ip, 3, TimeUnit.DAYS, new MongoToVertxCallback<>(markPreAuthFuture));
totpService.markRecentlyUsed(this, code, new MongoToVertxCallback<>(markRecentlyUsedFuture));
CompositeFuture.all(markPreAuthFuture, markRecentlyUsedFuture).setHandler((result) -> {
if (result.failed()) {

View File

@ -0,0 +1,42 @@
package net.frozenorb.apiv3.mojang;
import com.mongodb.async.SingleResultCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.UUID;
import io.vertx.core.http.HttpClient;
import io.vertx.core.json.DecodeException;
import io.vertx.core.json.JsonObject;
@Component
public final class HttpMojangService implements MojangService {
@Autowired private HttpClient httpsClient;
@Override
public void getName(UUID id, SingleResultCallback<String> callback) {
httpsClient.get(443, "sessionserver.mojang.com", "/session/minecraft/profile/" + id.toString().replace("-", ""), (response) -> {
response.bodyHandler((body) -> {
try {
JsonObject bodyJson = new JsonObject(body.toString());
String name = bodyJson.getString("name");
if (name == null) {
callback.onResult(null, new IOException("Hit Mojang API rate limit: " + bodyJson.encode()));
} else {
callback.onResult(name, null);
}
} catch (DecodeException ex) {
callback.onResult(null, ex);
}
});
response.exceptionHandler((error) -> callback.onResult(null, error));
}).end();
}
}

View File

@ -0,0 +1,14 @@
package net.frozenorb.apiv3.mojang;
import com.mongodb.async.SingleResultCallback;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public interface MojangService {
void getName(UUID id, SingleResultCallback<String> callback);
}

View File

@ -18,6 +18,9 @@ import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.GeoJsonPoint;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
@ -27,26 +30,24 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETDumpsType implements Handler<RoutingContext> {
private static final DecimalFormat coordinateFormat = new DecimalFormat("#.#####");
private final DecimalFormat coordinateFormat = new DecimalFormat("#.#####");
private static List<UUID> banCache = ImmutableList.of();
private static List<UUID> blacklistCache = ImmutableList.of();
private static List<String> ipBanCache = ImmutableList.of();
private static Map<String, Map<String, List<UUID>>> grantCache = ImmutableMap.of();
private static Map<String, GeoJsonPoint> ipIntelCache = ImmutableMap.of();
private List<UUID> banCache = ImmutableList.of();
private List<UUID> blacklistCache = ImmutableList.of();
private List<String> ipBanCache = ImmutableList.of();
private Map<String, Map<String, List<UUID>>> grantCache = ImmutableMap.of();
private Map<String, GeoJsonPoint> ipIntelCache = ImmutableMap.of();
static {
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(5), (id) -> updateCache());
}
public static void updateCache() {
// 5 minutes, can't use TimeUnit expression in annotation
@Scheduled(fixedRate = 5 * 60 * 1000)
public void updateCache() {
Punishment.findByType(ImmutableSet.of(
Punishment.PunishmentType.BAN,
Punishment.PunishmentType.BLACKLIST
@ -71,8 +72,8 @@ public final class GETDumpsType implements Handler<RoutingContext> {
}
}
GETDumpsType.banCache = banCache;
GETDumpsType.blacklistCache = blacklistCache;
this.banCache = banCache;
this.blacklistCache = blacklistCache;
});
Grant.findAll((grants, error) -> {
@ -109,7 +110,7 @@ public final class GETDumpsType implements Handler<RoutingContext> {
}
}
GETDumpsType.grantCache = grantCache;
this.grantCache = grantCache;
});
IpBan.find((ipBans, error) -> {
@ -128,7 +129,7 @@ public final class GETDumpsType implements Handler<RoutingContext> {
ipBanCache.add(ipBan.getUserIp());
}
GETDumpsType.ipBanCache = ipBanCache;
this.ipBanCache = ipBanCache;
});
IpIntel.findAllNoSort((ipIntel, error) -> {
@ -148,7 +149,7 @@ public final class GETDumpsType implements Handler<RoutingContext> {
}
}
GETDumpsType.ipIntelCache = ipIntelCache;
this.ipIntelCache = ipIntelCache;
});
}

View File

@ -1,22 +0,0 @@
package net.frozenorb.apiv3.route;
import net.frozenorb.apiv3.APIv3;
import org.bson.Document;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.dropwizard.MetricsService;
import io.vertx.ext.web.RoutingContext;
public final class GETMetrics implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
MetricsService metricsService = MetricsService.create(APIv3.getVertxInstance());
JsonObject metrics = metricsService.getMetricsSnapshot(APIv3.getVertxInstance());
// We encode and then parse because JsonObject and Gson don't play nicely with each other
APIv3.respondJson(ctx, 200, Document.parse(metrics.encode()));
}
}

View File

@ -5,9 +5,12 @@ import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETSearch implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -5,9 +5,12 @@ import com.google.common.collect.ImmutableMap;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETWhoAmI implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,19 +3,25 @@ package net.frozenorb.apiv3.route;
import com.google.common.collect.ImmutableMap;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.usersession.UserSessionService;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.UserSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTLogout implements Handler<RoutingContext> {
@Autowired private UserSessionService userSessionService;
public void handle(RoutingContext ctx) {
String userSession = ctx.request().getHeader("MHQ-UserSession");
String userIp = ctx.request().getHeader("MHQ-UserIp");
UserSessionUtils.invalidateSession(userIp, userSession, (ignored, error) -> {
userSessionService.invalidateSession(userIp, userSession, (ignored, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEAccessTokensId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,13 +3,16 @@ package net.frozenorb.apiv3.route.accessTokens;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult;
import net.frozenorb.apiv3.totp.TotpAuthorizationResult;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETAccessTokens implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETAccessTokensId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -8,16 +8,19 @@ import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult;
import net.frozenorb.apiv3.totp.TotpAuthorizationResult;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTAccessTokens implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEAuditLogId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -6,10 +6,12 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.bson.Document;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETAuditLog implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -7,10 +7,13 @@ import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTAuditLog implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEBannedAsnsId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,9 +3,12 @@ package net.frozenorb.apiv3.route.bannedAsns;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.BannedAsn;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETBannedAsns implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,9 +3,12 @@ package net.frozenorb.apiv3.route.bannedAsns;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.BannedAsn;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETBannedAsnsId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTBannedAsns implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -1,4 +1,7 @@
package net.frozenorb.apiv3.route.bannedAsns;
import org.springframework.stereotype.Component;
@Component
public class PUTBannedAsnsId {
}

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEBannedCellCarriersId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,9 +3,12 @@ package net.frozenorb.apiv3.route.bannedCellCarriers;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.BannedCellCarrier;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETBannedCellCarriers implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,9 +3,12 @@ package net.frozenorb.apiv3.route.bannedCellCarriers;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.BannedCellCarrier;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETBannedCellCarriersId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTBannedCellCarriers implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -1,4 +1,7 @@
package net.frozenorb.apiv3.route.bannedCellCarriers;
import org.springframework.stereotype.Component;
@Component
public class PUTBannedCellCarriersId {
}

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEChatFilterId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.ChatFilterEntry;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETChatFilter implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.ChatFilterEntry;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETChatFilterId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTChatFilter implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -1,4 +1,7 @@
package net.frozenorb.apiv3.route.chatFilter;
import org.springframework.stereotype.Component;
@Component
public class PUTChatFilterId {
}

View File

@ -11,12 +11,15 @@ import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import java.time.Instant;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTDeploymentUpdateServer implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,18 +3,24 @@ package net.frozenorb.apiv3.route.disposableLoginTokens;
import com.google.common.collect.ImmutableMap;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.disposablelogintoken.DisposableLoginTokenService;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.DisposableLoginTokenUtils;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTDisposableLoginTokens implements Handler<RoutingContext> {
@Autowired private DisposableLoginTokenService disposableLoginTokenService;
public void handle(RoutingContext ctx) {
JsonObject requestBody = ctx.getBodyAsJson();
User user = SyncUtils.runBlocking(v -> User.findById(requestBody.getString("user"), v));
@ -30,7 +36,7 @@ public final class POSTDisposableLoginTokens implements Handler<RoutingContext>
return;
}
DisposableLoginTokenUtils.createToken(user.getId(), userIp, (token, error) -> {
disposableLoginTokenService.createToken(user.getId(), userIp, (token, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {

View File

@ -5,18 +5,25 @@ import com.google.common.collect.ImmutableMap;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.util.DisposableLoginTokenUtils;
import net.frozenorb.apiv3.disposablelogintoken.DisposableLoginTokenService;
import net.frozenorb.apiv3.usersession.UserSessionService;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UserSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTDisposableLoginTokensIdUse implements Handler<RoutingContext> {
@Autowired private UserSessionService userSessionService;
@Autowired private DisposableLoginTokenService disposableLoginTokenService;
public void handle(RoutingContext ctx) {
JsonObject requestBody = ctx.getBodyAsJson();
String disposableLoginToken = ctx.request().getParam("disposableLoginToken");
@ -32,7 +39,7 @@ public final class POSTDisposableLoginTokensIdUse implements Handler<RoutingCont
return;
}
DisposableLoginTokenUtils.useToken(disposableLoginToken, userIp, (user, error) -> {
disposableLoginTokenService.attemptLogin(disposableLoginToken, userIp, (user, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
return;
@ -43,7 +50,7 @@ public final class POSTDisposableLoginTokensIdUse implements Handler<RoutingCont
return;
}
String session = SyncUtils.runBlocking(v -> UserSessionUtils.createSession(user.getId(), userIp, v));
String session = SyncUtils.runBlocking(v -> userSessionService.createSession(user.getId(), userIp, v));
AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.DISPOSABLE_LOGIN_TOKEN_USE, (ignored, error2) -> {
if (error2 != null) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETEmailTokensIdOwner implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -11,12 +11,15 @@ import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.PasswordUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTEmailTokensIdConfirm implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -11,10 +11,13 @@ import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEGrantsId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -6,12 +6,14 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.bson.Document;
import org.springframework.stereotype.Component;
import java.util.stream.Collectors;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETGrants implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.Grant;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETGrantsId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -9,11 +9,13 @@ import net.frozenorb.apiv3.model.Grant;
import net.frozenorb.apiv3.model.Rank;
import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.totp.TotpAuthorizationResult;
import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
@ -23,6 +25,7 @@ import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTGrants implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETEIpBansId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -6,10 +6,12 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import org.bson.Document;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETIpBans implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.IpBan;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETIpBansId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -11,12 +11,15 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.springframework.stereotype.Component;
import java.time.Instant;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTIpBans implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -5,9 +5,12 @@ import net.frozenorb.apiv3.model.IpIntel;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETIpInteld implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -5,11 +5,14 @@ import net.frozenorb.apiv3.model.IpLogEntry;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import java.util.UUID;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETIpLogId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -3,12 +3,15 @@ package net.frozenorb.apiv3.route.lookup;
import com.google.common.collect.ImmutableMap;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
@ -20,9 +23,15 @@ import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
public class POSTLookupByName implements Handler<RoutingContext> {
@Component
public final class POSTLookupByName implements Handler<RoutingContext> {
private static final MongoCollection<Document> usersCollection = APIv3.getDatabase().getCollection("users");
private final MongoCollection<Document> usersCollection;
@Autowired
public POSTLookupByName(MongoDatabase database) {
this.usersCollection = database.getCollection("users");
}
public void handle(RoutingContext ctx) {
JsonObject requestBody = ctx.getBodyAsJson();

View File

@ -1,6 +1,7 @@
package net.frozenorb.apiv3.route.lookup;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.util.ErrorUtils;
@ -8,6 +9,8 @@ import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
@ -20,9 +23,15 @@ import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTLookupByUuid implements Handler<RoutingContext> {
private static final MongoCollection<Document> usersCollection = APIv3.getDatabase().getCollection("users");
private final MongoCollection<Document> usersCollection;
@Autowired
public POSTLookupByUuid(MongoDatabase database) {
this.usersCollection = database.getCollection("users");
}
public void handle(RoutingContext ctx) {
JsonObject requestBody = ctx.getBodyAsJson();

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class DELETENotificationTemplatesId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETNotificationTemplates implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -4,9 +4,12 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.util.ErrorUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
@Component
public final class GETNotificationTemplatesId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -10,10 +10,13 @@ import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.springframework.stereotype.Component;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@Component
public final class POSTNotificationTemplates implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {

View File

@ -1,4 +1,7 @@
package net.frozenorb.apiv3.route.notificationTemplates;
import org.springframework.stereotype.Component;
@Component
public class PUTNotificationTemplatesId {
}

Some files were not shown because too many files have changed in this diff Show More