Config changes + cleanup
This commit is contained in:
parent
f4b59cf9b3
commit
db0b173f15
@ -1,23 +0,0 @@
|
||||
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
|
35
application.yml
Normal file
35
application.yml
Normal file
@ -0,0 +1,35 @@
|
||||
mongoUri: mongodb://158.69.26.208:27027/MineHQ
|
||||
redisUri: redis://209.222.96.50:6379
|
||||
|
||||
http:
|
||||
port: 80
|
||||
keystoreFile:
|
||||
keystorePassword:
|
||||
|
||||
disposableLoginToken:
|
||||
tokenLifetimeSeconds: 300
|
||||
|
||||
ipHashing:
|
||||
salt: J$gMsq6#!sWTK^JvB!px
|
||||
|
||||
userSession:
|
||||
sessionExpirationTimeDays: 30
|
||||
|
||||
totp:
|
||||
windowSize: 10
|
||||
recentlyUsedPeriodSeconds: 300
|
||||
ipAuthorizationDays: 5
|
||||
|
||||
maxMind:
|
||||
userId: 66817
|
||||
licenseKey: 8Aw9NsOUeOp7
|
||||
|
||||
mandrill:
|
||||
apiKey: 0OYtwymqJP6oqvszeJu0vQ
|
||||
fromEmail: no-reply@minehq.com
|
||||
fromName: MineHQ Network
|
||||
|
||||
zang:
|
||||
accountSid: ACf18890845596403e330944d98886440c
|
||||
authToken: dc70bbd1fbd8411ba133fa93813a461b
|
||||
fromNumber: 339-337-5300
|
@ -3,6 +3,7 @@ package net.frozenorb.apiv3;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@ -14,6 +15,7 @@ import io.vertx.core.Vertx;
|
||||
class Main {
|
||||
|
||||
@Autowired private APIv3 verticle;
|
||||
@Autowired private Environment environment;
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
|
||||
|
@ -8,13 +8,16 @@ 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 com.mongodb.connection.ConnectionPoolSettings;
|
||||
import com.mongodb.connection.ServerSettings;
|
||||
import com.mongodb.connection.SocketSettings;
|
||||
import com.mongodb.connection.SslSettings;
|
||||
|
||||
import net.frozenorb.apiv3.serialization.jackson.InstantJsonDeserializer;
|
||||
import net.frozenorb.apiv3.serialization.jackson.InstantJsonSerializer;
|
||||
@ -32,7 +35,6 @@ 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;
|
||||
@ -42,82 +44,68 @@ import fr.javatic.mongo.jacksonCodec.ObjectMapperFactory;
|
||||
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();
|
||||
public MongoDatabase mongoDatabase(@Value("${mongoUri}") String mongoUri) {
|
||||
ConnectionString connStr = new ConnectionString(mongoUri);
|
||||
|
||||
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()
|
||||
// all of these lines except for .codecRegistry are copied from MongoClients#create(ConnectionString)
|
||||
MongoClient mongoClient = MongoClients.create(MongoClientSettings.builder()
|
||||
.clusterSettings(ClusterSettings.builder().applyConnectionString(connStr).build())
|
||||
.connectionPoolSettings(ConnectionPoolSettings.builder().applyConnectionString(connStr).build())
|
||||
.serverSettings(ServerSettings.builder().build()).credentialList(connStr.getCredentialList())
|
||||
.sslSettings(SslSettings.builder().applyConnectionString(connStr).build())
|
||||
.socketSettings(SocketSettings.builder().applyConnectionString(connStr).build())
|
||||
.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
|
||||
)))
|
||||
.build()
|
||||
);
|
||||
|
||||
MongoDatabase db = mongoClient.getDatabase(database);
|
||||
MongoDatabase database = mongoClient.getDatabase(connStr.getDatabase());
|
||||
|
||||
db.getCollection("auditLog").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("user", 1)),
|
||||
new IndexModel(new Document("performedAt", 1)),
|
||||
new IndexModel(new Document("type", 1))
|
||||
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) -> {});
|
||||
db.getCollection("grants").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("user", 1)),
|
||||
new IndexModel(new Document("rank", 1)),
|
||||
new IndexModel(new Document("addedAt", 1))
|
||||
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) -> {});
|
||||
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))
|
||||
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) -> {});
|
||||
db.getCollection("ipBans").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("userIp", 1))
|
||||
database.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"))
|
||||
database.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))
|
||||
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) -> {});
|
||||
db.getCollection("users").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("lastUsername", 1)),
|
||||
new IndexModel(new Document("lastUsernameLower", 1)),
|
||||
new IndexModel(new Document("emailToken", 1)),
|
||||
new IndexModel(new Document("totpSecret", 1))
|
||||
database.getCollection("users").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("lastUsername", 1)),
|
||||
new IndexModel(new Document("lastUsernameLower", 1)),
|
||||
new IndexModel(new Document("emailToken", 1)),
|
||||
new IndexModel(new Document("totpSecret", 1))
|
||||
), (a, b) -> {});
|
||||
db.getCollection("userMeta").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("user", 1).append("serverGroup", 1))
|
||||
database.getCollection("userMeta").createIndexes(ImmutableList.of(
|
||||
new IndexModel(new Document("user", 1).append("serverGroup", 1))
|
||||
), (a, b) -> {});
|
||||
|
||||
return db;
|
||||
return database;
|
||||
}
|
||||
|
||||
private ObjectMapper createMongoJacksonMapper() {
|
||||
|
@ -4,6 +4,8 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.redis.RedisClient;
|
||||
import io.vertx.redis.RedisOptions;
|
||||
@ -17,11 +19,10 @@ public class RedisConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisOptions redisOptions(
|
||||
@Value("${redis.address}") String address,
|
||||
@Value("${redis.port}") int port
|
||||
) {
|
||||
return new RedisOptions().setAddress(address).setPort(port);
|
||||
public RedisOptions redisOptions(@Value("${redisUri}") URI redisUri) {
|
||||
return new RedisOptions()
|
||||
.setAddress(redisUri.getHost())
|
||||
.setPort(redisUri.getPort());
|
||||
}
|
||||
|
||||
}
|
@ -5,10 +5,10 @@ import com.mongodb.async.SingleResultCallback;
|
||||
import net.frozenorb.apiv3.model.User;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.vertx.redis.RedisClient;
|
||||
|
||||
@ -16,6 +16,7 @@ import io.vertx.redis.RedisClient;
|
||||
public final class RedisDisposableLoginTokenService implements DisposableLoginTokenService {
|
||||
|
||||
@Autowired private RedisClient redisClient;
|
||||
@Value("${disposableLoginToken.tokenLifetimeSeconds}") private int tokenLifetimeSeconds;
|
||||
|
||||
@Override
|
||||
public void attemptLogin(String token, String userIp, SingleResultCallback<User> callback) {
|
||||
@ -56,7 +57,7 @@ public final class RedisDisposableLoginTokenService implements DisposableLoginTo
|
||||
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) -> {
|
||||
redisClient.setex("apiv3:disposableLoginTokens:" + userIp + ":" + token, tokenLifetimeSeconds, user.toString(), (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(token, null);
|
||||
} else {
|
||||
|
@ -47,7 +47,6 @@ import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import fr.javatic.mongo.jacksonCodec.Entity;
|
||||
import fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
@ -585,7 +584,7 @@ public final class User {
|
||||
Future<Void> markPreAuthFuture = Future.future();
|
||||
Future<Void> markRecentlyUsedFuture = Future.future();
|
||||
|
||||
totpService.markPreAuthorized(this, ip, 3, TimeUnit.DAYS, new MongoToVertxCallback<>(markPreAuthFuture));
|
||||
totpService.markPreAuthorized(this, ip, new MongoToVertxCallback<>(markPreAuthFuture));
|
||||
totpService.markRecentlyUsed(this, code, new MongoToVertxCallback<>(markRecentlyUsedFuture));
|
||||
|
||||
CompositeFuture.all(markPreAuthFuture, markRecentlyUsedFuture).setHandler((result) -> {
|
||||
|
@ -8,17 +8,34 @@ import net.frozenorb.apiv3.model.User;
|
||||
import net.frozenorb.apiv3.util.IpUtils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import io.vertx.redis.RedisClient;
|
||||
|
||||
@Component
|
||||
public final class RedisTotpService implements TotpService {
|
||||
|
||||
private final GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator(new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().setWindowSize(10).build());
|
||||
@Autowired private RedisClient redisClient;
|
||||
@Value("${totp.windowSize}") int windowSize;
|
||||
@Value("${totp.recentlyUsedPeriodSeconds}") int recentlyUsedPeriodSeconds;
|
||||
@Value("${totp.ipAuthorizationDays}") int ipAuthorizationDays;
|
||||
private GoogleAuthenticator googleAuthenticator;
|
||||
|
||||
// has to be ran after construction (or else windowSize won't be defined when we go to
|
||||
// create this object)
|
||||
@PostConstruct
|
||||
private void setupGoogleAuth() {
|
||||
googleAuthenticator = new GoogleAuthenticator(
|
||||
new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder()
|
||||
.setWindowSize(windowSize)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authorizeUser(String secret, int code) {
|
||||
@ -42,7 +59,7 @@ public final class RedisTotpService implements TotpService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markPreAuthorized(User user, String ip, long duration, TimeUnit unit, SingleResultCallback<Void> callback) {
|
||||
public void markPreAuthorized(User user, String ip, SingleResultCallback<Void> callback) {
|
||||
if (!IpUtils.isValidIp(ip)) {
|
||||
callback.onResult(null, null);
|
||||
return;
|
||||
@ -50,7 +67,7 @@ public final class RedisTotpService implements TotpService {
|
||||
|
||||
String key = user.getId() + ":preAuthorizedIp:" + ip.toLowerCase();
|
||||
|
||||
redisClient.setex(key, unit.toSeconds(duration), "", (result) -> {
|
||||
redisClient.setex(key, TimeUnit.DAYS.toSeconds(ipAuthorizationDays), "", (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
@ -74,7 +91,7 @@ public final class RedisTotpService implements TotpService {
|
||||
public void markRecentlyUsed(User user, int code, SingleResultCallback<Void> callback) {
|
||||
String key = user.getId() + ":recentTotpCodes:" + code;
|
||||
|
||||
redisClient.setex(key, TimeUnit.MINUTES.toSeconds(5), "", (result) -> {
|
||||
redisClient.setex(key, recentlyUsedPeriodSeconds, "", (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
|
@ -6,8 +6,6 @@ import net.frozenorb.apiv3.model.User;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public interface TotpService {
|
||||
|
||||
@ -15,7 +13,7 @@ public interface TotpService {
|
||||
|
||||
void isPreAuthorized(User user, String ip, SingleResultCallback<Boolean> callback);
|
||||
|
||||
void markPreAuthorized(User user, String ip, long duration, TimeUnit unit, SingleResultCallback<Void> callback);
|
||||
void markPreAuthorized(User user, String ip, SingleResultCallback<Void> callback);
|
||||
|
||||
void wasRecentlyUsed(User user, int code, SingleResultCallback<Boolean> callback);
|
||||
|
||||
|
@ -3,6 +3,7 @@ package net.frozenorb.apiv3.usersession;
|
||||
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.List;
|
||||
@ -15,6 +16,7 @@ import io.vertx.redis.RedisClient;
|
||||
public final class RedisUserSessionService implements UserSessionService {
|
||||
|
||||
@Autowired private RedisClient redisClient;
|
||||
@Value("${userSession.sessionExpirationTimeDays}") private int sessionExpirationTimeDays;
|
||||
|
||||
@Override
|
||||
public void sessionExists(String userIp, String userSession, SingleResultCallback<Boolean> callback) {
|
||||
@ -37,7 +39,7 @@ public final class RedisUserSessionService implements UserSessionService {
|
||||
String userSession = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
String key = "apiv3:sessions:" + userIp + ":" + userSession;
|
||||
|
||||
redisClient.setex(key, TimeUnit.DAYS.toSeconds(30), "", (result) -> {
|
||||
redisClient.setex(key, TimeUnit.DAYS.toSeconds(sessionExpirationTimeDays), "", (result) -> {
|
||||
if (result.succeeded()) {
|
||||
redisClient.sadd("apiv3:sessions:" + user, key, (result2) -> {
|
||||
if (result2.succeeded()) {
|
||||
|
Loading…
Reference in New Issue
Block a user