Fix some stuff for Velt

This commit is contained in:
Alfie Cleveland 2017-09-24 14:25:35 +01:00
parent 276564f21f
commit 408124f5cd
5 changed files with 86 additions and 113 deletions

View File

@ -1,20 +1,5 @@
package net.frozenorb.apiv3.domain; 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.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -23,6 +8,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; 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.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id; import fr.javatic.mongo.jacksonCodec.objectId.Id;
import io.vertx.core.CompositeFuture; import io.vertx.core.CompositeFuture;
@ -30,6 +23,10 @@ import io.vertx.core.Future;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; 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 @Entity
@AllArgsConstructor @AllArgsConstructor
@ -66,6 +63,7 @@ public final class IpIntel {
} else if (existingIpIntel != null) { } else if (existingIpIntel != null) {
callback.onResult(existingIpIntel, null); callback.onResult(existingIpIntel, null);
} else { } else {
/*
SpringUtils.getBean(GeoIpService.class).lookupInfo(id, (geoIpResult, error2) -> { SpringUtils.getBean(GeoIpService.class).lookupInfo(id, (geoIpResult, error2) -> {
if (error2 != null) { if (error2 != null) {
callback.onResult(null, error2); callback.onResult(null, error2);
@ -83,7 +81,8 @@ public final class IpIntel {
// MaxMind failed to return result // MaxMind failed to return result
callback.onResult(null, null); callback.onResult(null, null);
} }
}); });*/
callback.onResult(null, null);
} }
}); });
} }
@ -111,6 +110,7 @@ public final class IpIntel {
Future createNewIntelFuture = Future.future(); Future createNewIntelFuture = Future.future();
createNewIntelFutures.add(createNewIntelFuture); createNewIntelFutures.add(createNewIntelFuture);
/*
SpringUtils.getBean(GeoIpService.class).lookupInfo(ip, (geoIpResult, error2) -> { SpringUtils.getBean(GeoIpService.class).lookupInfo(ip, (geoIpResult, error2) -> {
if (error2 != null) { if (error2 != null) {
createNewIntelFuture.fail(error2); createNewIntelFuture.fail(error2);
@ -133,7 +133,8 @@ public final class IpIntel {
createNewIntelFuture.complete(); createNewIntelFuture.complete();
} }
})); }));
}); });*/
createNewIntelFuture.complete();
}); });
CompositeFuture.all(createNewIntelFutures).setHandler((creationStatus) -> { CompositeFuture.all(createNewIntelFutures).setHandler((creationStatus) -> {

View File

@ -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<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,6 +1,7 @@
package net.frozenorb.apiv3.util; package net.frozenorb.apiv3.util;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Logger;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
@ -8,17 +9,58 @@ import lombok.experimental.UtilityClass;
public class UuidUtils { public class UuidUtils {
public static boolean isAcceptableUuid(UUID uuid) { public static boolean isAcceptableUuid(UUID uuid) {
return uuid.version() == 4; return uuid != null && uuid.version() == 4;
} }
public static UUID parseUuid(String input) { public static UUID parseUuid(String input) {
if (input.length() == 36) { if (input.length() == 36) {
return UUID.fromString(input); return UUID.fromString(input);
} else if (input.length() == 32) { } 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")); Logger.getGlobal().info("Got 32 length UUID");
return from32(input);
} else { } else {
throw new IllegalArgumentException("Invalid UUID string: " + input); 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) + ")");
}
if (j < 8) {
hi = (hi << 8) | curr;
} else {
lo = (lo << 8) | curr;
}
++i;
}
return new UUID(hi, lo);
}
} }

View File

@ -91,6 +91,11 @@ public final class POSTGrants implements Handler<RoutingContext> {
} }
if (rank.isGrantRequiresTotp()) { 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); int code = requestBody.getInteger("totpCode", -1);
TotpAuthorizationResult totpAuthorizationResult = SyncUtils.runBlocking(v -> addedBy.checkTotpAuthorization(code, null, v)); TotpAuthorizationResult totpAuthorizationResult = SyncUtils.runBlocking(v -> addedBy.checkTotpAuthorization(code, null, v));

View File

@ -58,7 +58,13 @@ public final class POSTPunishments implements Handler<RoutingContext> {
for (Punishment alternatePunishment : punishments) { for (Punishment alternatePunishment : punishments) {
if (alternatePunishment.isActive()) { if (alternatePunishment.isActive()) {
User user = SyncUtils.runBlocking(v -> User.findById(alternatePunishment.getAddedBy(), v)); 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; return;
} }
} }