From 408124f5cd666da4bd8a54d2d987544391714d64 Mon Sep 17 00:00:00 2001 From: Alfie Cleveland Date: Sun, 24 Sep 2017 14:25:35 +0100 Subject: [PATCH] Fix some stuff for Velt --- .../net/frozenorb/apiv3/domain/IpIntel.java | 35 ++++---- .../service/geoip/MaxMindGeoIpService.java | 81 ------------------- .../net/frozenorb/apiv3/util/UuidUtils.java | 70 ++++++++++++---- .../apiv3/web/route/grants/POSTGrants.java | 5 ++ .../route/punishments/POSTPunishments.java | 8 +- 5 files changed, 86 insertions(+), 113 deletions(-) delete mode 100644 src/main/java/net/frozenorb/apiv3/service/geoip/MaxMindGeoIpService.java diff --git a/src/main/java/net/frozenorb/apiv3/domain/IpIntel.java b/src/main/java/net/frozenorb/apiv3/domain/IpIntel.java index e36b1cd..f80b512 100644 --- a/src/main/java/net/frozenorb/apiv3/domain/IpIntel.java +++ b/src/main/java/net/frozenorb/apiv3/domain/IpIntel.java @@ -1,20 +1,5 @@ package net.frozenorb.apiv3.domain; -import com.google.common.base.Charsets; -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.service.geoip.GeoIpInfo; -import net.frozenorb.apiv3.service.geoip.GeoIpService; -import net.frozenorb.apiv3.util.GeoJsonPoint; -import net.frozenorb.apiv3.util.SpringUtils; -import net.frozenorb.apiv3.util.SyncUtils; - -import org.bson.Document; - import java.time.Instant; import java.util.ArrayList; import java.util.Collection; @@ -23,6 +8,14 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.bson.Document; + +import com.google.common.base.Charsets; +import com.google.common.hash.Hashing; +import com.mongodb.async.SingleResultCallback; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.async.client.MongoDatabase; + import fr.javatic.mongo.jacksonCodec.Entity; import fr.javatic.mongo.jacksonCodec.objectId.Id; import io.vertx.core.CompositeFuture; @@ -30,6 +23,10 @@ import io.vertx.core.Future; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import net.frozenorb.apiv3.service.geoip.GeoIpInfo; +import net.frozenorb.apiv3.util.GeoJsonPoint; +import net.frozenorb.apiv3.util.SpringUtils; +import net.frozenorb.apiv3.util.SyncUtils; @Entity @AllArgsConstructor @@ -66,6 +63,7 @@ public final class IpIntel { } else if (existingIpIntel != null) { callback.onResult(existingIpIntel, null); } else { + /* SpringUtils.getBean(GeoIpService.class).lookupInfo(id, (geoIpResult, error2) -> { if (error2 != null) { callback.onResult(null, error2); @@ -83,7 +81,8 @@ public final class IpIntel { // MaxMind failed to return result callback.onResult(null, null); } - }); + });*/ + callback.onResult(null, null); } }); } @@ -111,6 +110,7 @@ public final class IpIntel { Future createNewIntelFuture = Future.future(); createNewIntelFutures.add(createNewIntelFuture); + /* SpringUtils.getBean(GeoIpService.class).lookupInfo(ip, (geoIpResult, error2) -> { if (error2 != null) { createNewIntelFuture.fail(error2); @@ -133,7 +133,8 @@ public final class IpIntel { createNewIntelFuture.complete(); } })); - }); + });*/ + createNewIntelFuture.complete(); }); CompositeFuture.all(createNewIntelFutures).setHandler((creationStatus) -> { diff --git a/src/main/java/net/frozenorb/apiv3/service/geoip/MaxMindGeoIpService.java b/src/main/java/net/frozenorb/apiv3/service/geoip/MaxMindGeoIpService.java deleted file mode 100644 index 0bca065..0000000 --- a/src/main/java/net/frozenorb/apiv3/service/geoip/MaxMindGeoIpService.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.frozenorb.apiv3.service.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 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); - } - }); - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/util/UuidUtils.java b/src/main/java/net/frozenorb/apiv3/util/UuidUtils.java index cb9b7e0..9821c20 100644 --- a/src/main/java/net/frozenorb/apiv3/util/UuidUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/UuidUtils.java @@ -1,24 +1,66 @@ package net.frozenorb.apiv3.util; import java.util.UUID; +import java.util.logging.Logger; import lombok.experimental.UtilityClass; @UtilityClass public class UuidUtils { + + public static boolean isAcceptableUuid(UUID uuid) { + return uuid != null && uuid.version() == 4; + } + + public static UUID parseUuid(String input) { + if (input.length() == 36) { + return UUID.fromString(input); + } else if (input.length() == 32) { + Logger.getGlobal().info("Got 32 length UUID"); + return from32(input); + } else { + throw new IllegalArgumentException("Invalid UUID string: " + input); + } + } + + private static UUID from32(String id) { + long lo, hi; + lo = hi = 0; + + for (int i = 0, j = 0; i < 32; ++j) { + int curr; + char c = id.charAt(i); + + if (c >= '0' && c <= '9') { + curr = (c - '0'); + } else if (c >= 'a' && c <= 'f') { + curr = (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + curr = (c - 'A' + 10); + } else { + throw new NumberFormatException("Non-hex character at #" + i + ": '" + c + "' (value 0x" + Integer.toHexString(c) + ")"); + } + curr = (curr << 4); + + c = id.charAt(++i); + + if (c >= '0' && c <= '9') { + curr |= (c - '0'); + } else if (c >= 'a' && c <= 'f') { + curr |= (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + curr |= (c - 'A' + 10); + } else { + throw new NumberFormatException("Non-hex character at #" + i + ": '" + c + "' (value 0x" + Integer.toHexString(c) + ")"); + } - public static boolean isAcceptableUuid(UUID uuid) { - return uuid.version() == 4; - } - - public static UUID parseUuid(String input) { - if (input.length() == 36) { - return UUID.fromString(input); - } else if (input.length() == 32) { - return UUID.fromString(input.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5")); - } else { - throw new IllegalArgumentException("Invalid UUID string: " + input); - } - } - + if (j < 8) { + hi = (hi << 8) | curr; + } else { + lo = (lo << 8) | curr; + } + ++i; + } + return new UUID(hi, lo); + } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/web/route/grants/POSTGrants.java b/src/main/java/net/frozenorb/apiv3/web/route/grants/POSTGrants.java index 01ded24..df818e2 100644 --- a/src/main/java/net/frozenorb/apiv3/web/route/grants/POSTGrants.java +++ b/src/main/java/net/frozenorb/apiv3/web/route/grants/POSTGrants.java @@ -91,6 +91,11 @@ public final class POSTGrants implements Handler { } if (rank.isGrantRequiresTotp()) { + if (!requestBody.containsKey("totpCode")) { + ErrorUtils.respondInvalidInput(ctx, "Rank must be granted through API or website."); + return; + } + int code = requestBody.getInteger("totpCode", -1); TotpAuthorizationResult totpAuthorizationResult = SyncUtils.runBlocking(v -> addedBy.checkTotpAuthorization(code, null, v)); diff --git a/src/main/java/net/frozenorb/apiv3/web/route/punishments/POSTPunishments.java b/src/main/java/net/frozenorb/apiv3/web/route/punishments/POSTPunishments.java index a8fbe39..dff8c5c 100644 --- a/src/main/java/net/frozenorb/apiv3/web/route/punishments/POSTPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/web/route/punishments/POSTPunishments.java @@ -58,7 +58,13 @@ public final class POSTPunishments implements Handler { for (Punishment alternatePunishment : punishments) { if (alternatePunishment.isActive()) { User user = SyncUtils.runBlocking(v -> User.findById(alternatePunishment.getAddedBy(), v)); - ErrorUtils.respondOther(ctx, 409, "User already covered by alternate punishment.", "alreadyCoveredByAlternatePunishment", ImmutableMap.of("alternatePunishmentBy", user.getLastUsername())); + String lastPunishmentAddedBy = ""; + + if (user != null) { + lastPunishmentAddedBy = user.getLastUsername(); + } + + ErrorUtils.respondOther(ctx, 409, "User already covered by alternate punishment.", "alreadyCoveredByAlternatePunishment", ImmutableMap.of("alternatePunishmentBy", lastPunishmentAddedBy)); return; } }