Improve conversion and fix permission calculation
This commit is contained in:
parent
199072b5fb
commit
52ad1bd685
2
pom.xml
2
pom.xml
@ -61,7 +61,7 @@
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.4</version>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
|
@ -14,10 +14,7 @@ import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.filters.*;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.IPLogEntry;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.models.*;
|
||||
import net.frozenorb.apiv3.routes.GETDump;
|
||||
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
||||
import net.frozenorb.apiv3.routes.NotFound;
|
||||
@ -48,20 +45,25 @@ import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
||||
import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger;
|
||||
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
||||
import net.frozenorb.apiv3.utils.IPUtils;
|
||||
import net.frozenorb.apiv3.utils.UUIDUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.Datastore;
|
||||
import org.mongodb.morphia.Morphia;
|
||||
import org.mongodb.morphia.converters.UUIDConverter;
|
||||
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
|
||||
import org.mongodb.morphia.logging.slf4j.SLF4JLoggerImplFactory;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import spark.Spark;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static spark.Spark.*;
|
||||
import static spark.route.RouteOverview.enableRouteOverview;
|
||||
|
||||
@Slf4j
|
||||
public final class APIv3 {
|
||||
@ -120,6 +122,7 @@ public final class APIv3 {
|
||||
|
||||
Morphia morphia = new Morphia();
|
||||
morphia.mapPackage("net.frozenorb.apiv3.accessor");
|
||||
morphia.getMapper().getConverters().addConverter(new UUIDConverter());
|
||||
|
||||
datastore = morphia.createDatastore(mongoClient, config.getProperty("mongo.database"));
|
||||
datastore.ensureIndexes();
|
||||
@ -234,6 +237,8 @@ public final class APIv3 {
|
||||
delete("/user/:id/meta/:serverGroup", new DELETEUserMeta(), gson::toJson);
|
||||
delete("/user/:id/punishment", new DELETEUserPunishment(), gson::toJson);
|
||||
|
||||
enableRouteOverview("/routes");
|
||||
|
||||
// There's no way to do a JSON 404 page w/o doing this :(
|
||||
get("/*", new NotFound(), gson::toJson);
|
||||
post("/*", new NotFound(), gson::toJson);
|
||||
@ -245,6 +250,10 @@ public final class APIv3 {
|
||||
// A lot of unneeded .toString()'s and cloning objects is our ghetto null validation.
|
||||
MongoDatabase importFrom = new MongoClient(oldIp).getDatabase("minehq");
|
||||
Map<ObjectId, UUID> mongoIdToUUID = new HashMap<>();
|
||||
AtomicInteger skippedUsers = new AtomicInteger();
|
||||
AtomicInteger skippedPunishments = new AtomicInteger();
|
||||
AtomicInteger skippedGrants = new AtomicInteger();
|
||||
AtomicInteger skippedIpLogs = new AtomicInteger();
|
||||
|
||||
importFrom.getCollection("user").find().forEach(new Block<Document>() {
|
||||
|
||||
@ -256,7 +265,13 @@ public final class APIv3 {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uuid = UUID.fromString(uuidString.substring(0, 7) + "-" + uuidString.substring(7, 11) + "-" + uuidString.substring(11, 15) + "-" + uuidString.substring(15, 20) + "-" + uuidString.substring(20, uuidString.length()));
|
||||
UUID uuid = UUID.fromString(uuidString.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" ));
|
||||
|
||||
if (!UUIDUtils.isAcceptableUUID(uuid)) {
|
||||
skippedUsers.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
mongoIdToUUID.put(user.getObjectId("_id"), uuid);
|
||||
|
||||
User created = new User(
|
||||
@ -290,6 +305,7 @@ public final class APIv3 {
|
||||
UUID target = mongoIdToUUID.get(((DBRef) punishment.get("user")).getId());
|
||||
|
||||
if (target == null) {
|
||||
skippedPunishments.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -324,6 +340,7 @@ public final class APIv3 {
|
||||
UUID target = mongoIdToUUID.get(((DBRef) grant.get("target")).getId());
|
||||
|
||||
if (target == null) {
|
||||
skippedGrants.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -366,6 +383,7 @@ public final class APIv3 {
|
||||
UUID user = mongoIdToUUID.get(((DBRef) ipLogEntry.get("user")).getId());
|
||||
|
||||
if (user == null || ipLogEntry.getString("ip") == null) {
|
||||
skippedIpLogs.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -398,6 +416,8 @@ public final class APIv3 {
|
||||
log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
|
||||
}
|
||||
});
|
||||
|
||||
log.info("Skipped " + skippedUsers.get() + " users, " + skippedPunishments.get() + " punishments, " + skippedGrants.get() + " grants, and " + skippedIpLogs.get() + " ip logs");
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,7 @@ public final class ServerGroup {
|
||||
// We define these HashSets up here because, in the event they're
|
||||
// empty, Morphia will load them as null, not empty sets.
|
||||
@Getter @Setter @ExcludeFromReplies private Set<String> announcements = new HashSet<>();
|
||||
@Getter @ExcludeFromReplies private Map<String, Map<String, Boolean>> permissions = new HashMap<>();
|
||||
@Getter @Setter @ExcludeFromReplies private Map<String, List<String>> permissions = new HashMap<>();
|
||||
|
||||
public static ServerGroup byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(ServerGroup.class).field("id").equal(id).get();
|
||||
|
@ -25,7 +25,7 @@ public final class User {
|
||||
|
||||
@Getter @Id private UUID id;
|
||||
@Getter @Indexed private String lastUsername;
|
||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases;
|
||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases = new HashMap<>();
|
||||
@Getter @Setter @ExcludeFromReplies private String totpSecret;
|
||||
@Getter @Indexed @ExcludeFromReplies @Setter private String emailToken;
|
||||
@Getter @ExcludeFromReplies @Setter private Date emailTokenSetAt;
|
||||
@ -106,7 +106,7 @@ public final class User {
|
||||
}
|
||||
|
||||
public List<Grant> getGrants() {
|
||||
return APIv3.getDatastore().createQuery(Grant.class).field("target").equal(id).asList();
|
||||
return APIv3.getDatastore().createQuery(Grant.class).field("user").equal(id).asList();
|
||||
}
|
||||
|
||||
public List<IPLogEntry> getIPLog() {
|
||||
@ -114,7 +114,7 @@ public final class User {
|
||||
}
|
||||
|
||||
public IPLogEntry getIPLogEntry(String ip) {
|
||||
IPLogEntry existing = APIv3.getDatastore().createQuery(IPLogEntry.class).field("user").equal(id).field("ip").equal(ip).get();
|
||||
IPLogEntry existing = APIv3.getDatastore().createQuery(IPLogEntry.class).field("user").equal(id).field("userIp").equal(ip).get();
|
||||
|
||||
if (existing == null) {
|
||||
existing = new IPLogEntry(this, ip);
|
||||
@ -125,11 +125,11 @@ public final class User {
|
||||
}
|
||||
|
||||
public List<Punishment> getPunishments() {
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("target").equal(id).asList();
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("user").equal(id).asList();
|
||||
}
|
||||
|
||||
public List<Punishment> getPunishments(Collection<Punishment.PunishmentType> types) {
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("target").equal(id).field("type").in(types).asList();
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("user").equal(id).field("type").in(types).asList();
|
||||
}
|
||||
|
||||
public UserMetaEntry getMeta(ServerGroup group) {
|
||||
|
@ -21,15 +21,11 @@ public final class GETStaff implements Route {
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, Set<User>> result = new TreeMap<>((Comparator<String>) (first, second) -> {
|
||||
Map<String, Set<User>> result = new TreeMap<>((first, second) -> {
|
||||
Rank firstRank = Rank.byId(first);
|
||||
Rank secondRank = Rank.byId(second);
|
||||
|
||||
if (firstRank.getWeight() > secondRank.getWeight()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return Integer.compare(firstRank.getWeight(), secondRank.getWeight());
|
||||
});
|
||||
|
||||
APIv3.getDatastore().createQuery(Grant.class).field("rank").in(staffRanks.keySet()).forEach(grant -> {
|
||||
|
@ -1,10 +1,14 @@
|
||||
package net.frozenorb.apiv3.utils;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@UtilityClass
|
||||
@ -18,14 +22,14 @@ public class PermissionUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, Boolean> mergeUpTo(Map<String, Map<String, Boolean>> unmerged, Rank upTo) {
|
||||
public static Map<String, Boolean> mergeUpTo(Map<String, List<String>> unmerged, Rank upTo) {
|
||||
Map<String, Boolean> result = new HashMap<>();
|
||||
|
||||
for (Rank rank : Rank.values()) {
|
||||
Map<String, Boolean> rankPermissions = unmerged.get(rank.getId());
|
||||
Map<String, Boolean> rankPermissions = convertToMap(unmerged.get(rank.getId()));
|
||||
|
||||
// If there's no permissions defined for this rank just skip it.
|
||||
if (rankPermissions != null) {
|
||||
if (!rankPermissions.isEmpty()) {
|
||||
result = mergePermissions(result, rankPermissions);
|
||||
}
|
||||
|
||||
@ -42,4 +46,69 @@ public class PermissionUtils {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
private static Map<String, Boolean> convertToMap(List<String> unconvered) {
|
||||
if (unconvered == null) {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
Map<String, Boolean> result = new HashMap<>();
|
||||
|
||||
for (String permission : unconvered) {
|
||||
boolean negate = permission.startsWith("-");
|
||||
|
||||
if (negate) {
|
||||
result.put(permission.substring(1), false);
|
||||
} else {
|
||||
result.put(permission, true);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, List<String>> fromLegacy(String defaultGroup, String customGroup) {
|
||||
Map<String, List<String>> defaultPerms = legacyServerGroupToPerms(APIv3.getGson().fromJson(defaultGroup, HashMap.class));
|
||||
Map<String, List<String>> customPerms = legacyServerGroupToPerms(APIv3.getGson().fromJson(customGroup, HashMap.class));
|
||||
|
||||
for (Map.Entry<String, List<String>> customPerm : customPerms.entrySet()) {
|
||||
List<String> original = defaultPerms.get(customPerm.getKey());
|
||||
|
||||
original.addAll(customPerm.getValue());
|
||||
|
||||
defaultPerms.put(customPerm.getKey(), new ArrayList<>(ImmutableSet.copyOf(original)));
|
||||
}
|
||||
|
||||
defaultPerms.remove("coowner");
|
||||
defaultPerms.remove("allow-vpns");
|
||||
defaultPerms.remove("head-admin");
|
||||
defaultPerms.remove("registered");
|
||||
defaultPerms.remove("mvp");
|
||||
defaultPerms.remove("super-head-admin");
|
||||
defaultPerms.remove("trial-mod");
|
||||
defaultPerms.remove("forcedeathkick");
|
||||
return defaultPerms;
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> legacyServerGroupToPerms(Map<String, Object> group) {
|
||||
Map<String, List<String>> result = new HashMap<>();
|
||||
Map<String, Object> permissions = (Map<String, Object>) group.get("permissions");
|
||||
|
||||
for (Map.Entry<String, Object> entry : permissions.entrySet()) {
|
||||
List<String> perms = (List<String>) ((Map<String, Object>) entry.getValue()).get("grant");
|
||||
String rank = entry.getKey();
|
||||
|
||||
if (rank.equalsIgnoreCase("unban") || rank.equalsIgnoreCase("pass") || rank.equalsIgnoreCase("pink") || rank.equalsIgnoreCase("jrdev")) {
|
||||
continue;
|
||||
} else if (rank.equalsIgnoreCase("high_roller")) {
|
||||
rank = "high-roller";
|
||||
} else if (rank.equalsIgnoreCase("dev")) {
|
||||
rank = "developer";
|
||||
}
|
||||
|
||||
result.put(rank, perms);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package net.frozenorb.apiv3.utils;
|
||||
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
|
||||
import lombok.experimental.UtilityClass;
|
||||
@ -13,7 +14,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@UtilityClass
|
||||
public class TOTPUtils {
|
||||
|
||||
private static GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
|
||||
private static GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator(new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().setWindowSize(10).build());
|
||||
|
||||
public static GoogleAuthenticatorKey generateTOTPKey() {
|
||||
return googleAuthenticator.createCredentials();
|
||||
|
Loading…
Reference in New Issue
Block a user