diff --git a/pom.xml b/pom.xml
index e01b5ab..0940f09 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,27 +67,27 @@
io.vertx
vertx-core
- 3.3.1
+ 3.3.2
io.vertx
vertx-web
- 3.3.1
+ 3.3.2
io.vertx
vertx-redis-client
- 3.3.1
+ 3.3.2
io.vertx
vertx-circuit-breaker
- 3.3.1
+ 3.3.2
io.vertx
vertx-dropwizard-metrics
- 3.3.1
+ 3.3.2
diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java
index 7774d73..04404b7 100644
--- a/src/main/java/net/frozenorb/apiv3/APIv3.java
+++ b/src/main/java/net/frozenorb/apiv3/APIv3.java
@@ -105,6 +105,7 @@ import net.frozenorb.apiv3.serialization.mongodb.UuidCodecProvider;
import net.frozenorb.apiv3.util.EmailUtils;
import net.frozenorb.apiv3.util.MojangUtils;
import net.frozenorb.apiv3.util.SyncUtils;
+import net.frozenorb.apiv3.util.UserSessionUtils;
import org.bson.Document;
import org.bson.codecs.BsonValueCodecProvider;
import org.bson.codecs.DocumentCodecProvider;
@@ -139,6 +140,29 @@ public final class APIv3 extends AbstractVerticle {
setupMetrics();
setupHttpServer();
+ UserSessionUtils.setupRedis();
+
+ try {
+ Thread.sleep(2000L);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ UserSessionUtils.createSession(UUID.randomUUID(), "192.168.1.1", (v, i) -> {
+ if (i == null) {
+ System.out.println("a: " + v);
+ } else {
+ i.printStackTrace();
+ }
+ });
+ UserSessionUtils.createSession(UUID.randomUUID(), "::1", (v, i) -> {
+ if (i == null) {
+ System.out.println("b: " + v);
+ } else {
+ i.printStackTrace();
+ }
+ });
+
/*User.findAll((users, error) -> {
if (error != null) {
error.printStackTrace();
diff --git a/src/main/java/net/frozenorb/apiv3/handler/WebsiteUserSessionHandler.java b/src/main/java/net/frozenorb/apiv3/handler/WebsiteUserSessionHandler.java
index 0961f20..a377010 100644
--- a/src/main/java/net/frozenorb/apiv3/handler/WebsiteUserSessionHandler.java
+++ b/src/main/java/net/frozenorb/apiv3/handler/WebsiteUserSessionHandler.java
@@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.UserSessionUtils;
@Slf4j
@@ -30,6 +31,11 @@ public final class WebsiteUserSessionHandler implements Handler
String userSession = ctx.request().getHeader("MHQ-UserSession");
String userIp = ctx.request().getHeader("MHQ-UserIp");
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
UserSessionUtils.sessionExists(userIp, userSession, (exists, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
diff --git a/src/main/java/net/frozenorb/apiv3/route/emailTokens/POSTEmailTokensIdConfirm.java b/src/main/java/net/frozenorb/apiv3/route/emailTokens/POSTEmailTokensIdConfirm.java
index 81630a6..e2653ab 100644
--- a/src/main/java/net/frozenorb/apiv3/route/emailTokens/POSTEmailTokensIdConfirm.java
+++ b/src/main/java/net/frozenorb/apiv3/route/emailTokens/POSTEmailTokensIdConfirm.java
@@ -9,6 +9,7 @@ import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.PasswordUtils;
import net.frozenorb.apiv3.util.SyncUtils;
@@ -57,8 +58,14 @@ public final class POSTEmailTokensIdConfirm implements Handler {
user.completeEmailRegistration(user.getPendingEmail());
user.updatePassword(password);
SyncUtils.runBlocking(v -> user.save(v));
+ String userIp = requestBody.getString("userIp");
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_CONFIRM_EMAIL, (ignored, error) -> {
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_CONFIRM_EMAIL, (ignored, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java
index 4a72242..155f433 100644
--- a/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java
+++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/GETIpBans.java
@@ -5,6 +5,7 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.IpBan;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import org.bson.Document;
@@ -14,8 +15,14 @@ public final class GETIpBans implements Handler {
try {
int skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip"));
int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize"));
+ String userIp = ctx.request().getParam("userIp");
- IpBan.findPaginated(ctx.request().getParam("userIp") == null ? new Document() : new Document("userIp", UuidUtils.parseUuid(ctx.request().getParam("user"))), skip, pageSize, (grants, error) -> {
+ if (userIp != null && !IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ IpBan.findPaginated(userIp == null ? new Document() : new Document("userIp", userIp), skip, pageSize, (grants, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java b/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java
index 2ef8277..29a7532 100644
--- a/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java
+++ b/src/main/java/net/frozenorb/apiv3/route/punishments/POSTPunishments.java
@@ -14,6 +14,7 @@ import net.frozenorb.apiv3.model.Punishment;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import java.time.Instant;
@@ -96,6 +97,9 @@ public final class POSTPunishments implements Handler {
if (latestIpLogEntry != null) {
userIp = latestIpLogEntry.getUserIp();
}
+ } else if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid.");
+ return;
}
if (addedBy != null) {
diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java
index d003da0..07bc060 100644
--- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java
+++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java
@@ -15,6 +15,7 @@ import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.model.*;
import net.frozenorb.apiv3.unsorted.MongoToVertxCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.PermissionUtils;
import net.frozenorb.apiv3.util.UuidUtils;
@@ -216,9 +217,10 @@ public final class POSTServersHeartbeat implements Handler {
players.forEach((entry) -> {
UUID uuid = UuidUtils.parseUuid(entry.getKey());
JsonObject data = (JsonObject) entry.getValue();
+ String userIp = data.getString("userIp");
- if (UuidUtils.isAcceptableUuid(uuid)) {
- result.put(uuid, data.getString("userIp"));
+ if (UuidUtils.isAcceptableUuid(uuid) && IpUtils.isValidIp(userIp)) {
+ result.put(uuid, userIp);
}
});
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdVerifyPassword.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdVerifyPassword.java
index aac2de8..cf06d76 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdVerifyPassword.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdVerifyPassword.java
@@ -7,6 +7,7 @@ import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.UserSessionUtils;
@@ -41,6 +42,11 @@ public final class GETUsersIdVerifyPassword implements Handler {
boolean authorized = user.checkPassword(ctx.request().getParam("password"));
String userIp = ctx.request().getParam("userIp");
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
AuditLog.log(user.getId(), userIp, ctx, authorized ? AuditLogActionType.USER_LOGIN_SUCCESS : AuditLogActionType.USER_LOGIN_FAIL, (ignored, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdChangePassword.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdChangePassword.java
index 19fe184..3366d12 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdChangePassword.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdChangePassword.java
@@ -10,10 +10,7 @@ import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.RequiresTotpResult;
import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult;
-import net.frozenorb.apiv3.util.ErrorUtils;
-import net.frozenorb.apiv3.util.PasswordUtils;
-import net.frozenorb.apiv3.util.SyncUtils;
-import net.frozenorb.apiv3.util.UserSessionUtils;
+import net.frozenorb.apiv3.util.*;
import java.util.concurrent.TimeUnit;
@@ -86,8 +83,14 @@ public final class POSTUsersIdChangePassword implements Handler
user.updatePassword(newPassword);
SyncUtils.runBlocking(v -> user.save(v));
SyncUtils.runBlocking(v -> UserSessionUtils.invalidateAllSessions(user.getId(), v));
+ String userIp = requestBody.getString("userIp");
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_CHANGE_PASSWORD, (ignored, error) -> {
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_CHANGE_PASSWORD, (ignored, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdConfirmPhone.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdConfirmPhone.java
index 8d3b26c..7268cf0 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdConfirmPhone.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdConfirmPhone.java
@@ -9,6 +9,7 @@ import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import java.util.concurrent.TimeUnit;
@@ -61,8 +62,14 @@ public final class POSTUsersIdConfirmPhone implements Handler {
user.completePhoneRegistration(user.getPendingPhone());
SyncUtils.runBlocking(v -> user.save(v));
+ String userIp = requestBody.getString("userIp");
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_CONFIRM_PHONE, (ignored, error) -> {
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_CONFIRM_PHONE, (ignored, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdPasswordReset.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdPasswordReset.java
index 8bf8f0d..9b52c0d 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdPasswordReset.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdPasswordReset.java
@@ -11,6 +11,7 @@ import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.Notification;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import java.util.Map;
@@ -47,8 +48,14 @@ public final class POSTUsersIdPasswordReset implements Handler {
ErrorUtils.respondInternalError(ctx, error);
} else {
JsonObject requestBody = ctx.getBodyAsJson();
+ String userIp = requestBody.getString("userIp");
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_PASSWORD_RESET, (ignored2, error2) -> {
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_PASSWORD_RESET, (ignored2, error2) -> {
if (error2 != null) {
ErrorUtils.respondInternalError(ctx, error2);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterEmail.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterEmail.java
index 2de0ed1..1462df1 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterEmail.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterEmail.java
@@ -12,6 +12,7 @@ import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.Notification;
import net.frozenorb.apiv3.util.EmailUtils;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import java.util.Map;
@@ -73,7 +74,14 @@ public final class POSTUsersIdRegisterEmail implements Handler {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_REGISTER_EMAIL, (ignored2, error2) -> {
+ String userIp = requestBody.getString("userIp");
+
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_REGISTER_EMAIL, (ignored2, error2) -> {
if (error2 != null) {
ErrorUtils.respondInternalError(ctx, error2);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterPhone.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterPhone.java
index 50ff1e6..347f468 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterPhone.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdRegisterPhone.java
@@ -13,6 +13,7 @@ import net.frozenorb.apiv3.model.PhoneIntel;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.Notification;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.PhoneUtils;
import net.frozenorb.apiv3.util.SyncUtils;
@@ -77,7 +78,14 @@ public final class POSTUsersIdRegisterPhone implements Handler {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_REGISTER_PHONE, (ignored2, error2) -> {
+ String userIp = requestBody.getString("userIp");
+
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_REGISTER_PHONE, (ignored2, error2) -> {
if (error2 != null) {
ErrorUtils.respondInternalError(ctx, error2);
} else {
diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdSetupTotp.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdSetupTotp.java
index 1f5bd12..cd35edd 100644
--- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdSetupTotp.java
+++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdSetupTotp.java
@@ -9,6 +9,7 @@ import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils;
+import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TotpUtils;
@@ -34,8 +35,14 @@ public final class POSTUsersIdSetupTotp implements Handler {
if (TotpUtils.authorizeUser(secret, totpCode)) {
user.setTotpSecret(secret);
SyncUtils.runBlocking(v -> user.save(v));
+ String userIp = requestBody.getString("userIp");
- AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_SETUP_TOTP, (ignored, error) -> {
+ if (!IpUtils.isValidIp(userIp)) {
+ ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
+ return;
+ }
+
+ AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_SETUP_TOTP, (ignored, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {