Implement data converter

This commit is contained in:
Colin McDonald 2016-05-13 23:23:46 -04:00
parent b76eead314
commit d863b4f8a5
12 changed files with 201 additions and 28 deletions

View File

@ -1,8 +1,9 @@
general.releaseStage=production
logging.level=info
mongo.address=209.222.96.50
logging.debug=true
mongo.address=localhost
mongo.port=27017
mongo.database=minehqapi
mongo.database=MineHQ
mongo.username=
mongo.password=
redis.address=localhost

View File

@ -2,16 +2,22 @@ package net.frozenorb.apiv3;
import com.bugsnag.Client;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.*;
import com.mongodb.client.MongoDatabase;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.timgroup.statsd.StatsDClient;
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.routes.GETDump;
import net.frozenorb.apiv3.routes.GETWhoAmI;
import net.frozenorb.apiv3.routes.NotFound;
@ -41,6 +47,8 @@ import net.frozenorb.apiv3.serialization.FollowAnnotationExclusionStrategy;
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 org.bson.Document;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.Morphia;
@ -50,10 +58,7 @@ import redis.clients.jedis.JedisPool;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static spark.Spark.*;
@ -81,7 +86,8 @@ public final class APIv3 {
setupBugsnag();
setupHttp();
LoggingFilter.setDebug(true);
//convertData("158.69.126.126", true);
LoggingFilter.setDebug(Boolean.valueOf(config.getProperty("logging.debug")));
}
private void setupConfig() {
@ -156,10 +162,10 @@ public final class APIv3 {
threadPool(Integer.parseInt(workerThreads));
}
before(new MetricsBeforeFilter());
before(new ContentTypeFilter());
before(new ActorAttributeFilter());
before(new AuthorizationFilter());
before(new MetricsBeforeFilter());
after(new MetricsAfterFilter());
after(new LoggingFilter());
exception(Exception.class, new LoggingExceptionHandler());
@ -235,4 +241,153 @@ public final class APIv3 {
delete("/*", new NotFound(), gson::toJson);
}
private void convertData(String oldIp, boolean forReal) {
// 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<>();
importFrom.getCollection("user").find().forEach(new Block<Document>() {
@Override
public void apply(Document user) {
String uuidString = String.valueOf(user.get("uuid"));
if (uuidString == null || uuidString.length() != 32) {
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()));
mongoIdToUUID.put(user.getObjectId("_id"), uuid);
User created = new User(
uuid,
String.valueOf(user.get("name")).toString(),
ImmutableMap.of(),
null,
null,
null,
null,
user.getString("email"),
user.getString("phone"),
"INVALID",
user.getDate("joined"),
user.getDate("joined"),
false
);
if (forReal) {
APIv3.getDatastore().save(created);
}
log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
}
});
importFrom.getCollection("punishment").find().forEach(new Block<Document>() {
@Override
public void apply(Document punishment) {
UUID target = mongoIdToUUID.get(((DBRef) punishment.get("user")).getId());
if (target == null) {
return;
}
Punishment created = new Punishment(
new ObjectId().toString(),
target,
punishment.getString("reason").toString(),
Punishment.PunishmentType.valueOf(punishment.getString("type").toUpperCase()),
punishment.getDate("expires"),
punishment.containsKey("meta") ? (punishment.get("meta") instanceof List ? ImmutableMap.of() : (Document) punishment.get("meta")) : ImmutableMap.of(),
punishment.containsKey("addedBy") ? mongoIdToUUID.get(((DBRef) punishment.get("addedBy")).getId()) : null,
(Date) punishment.getDate("created").clone(),
punishment.containsKey("createdOn") ? String.valueOf(((DBRef) punishment.get("createdOn")).getId()) : "Website",
punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE,
punishment.containsKey("removedBy") ? (((DBRef) punishment.get("removedBy")).getCollectionName().equals("user") ? mongoIdToUUID.get(((DBRef) punishment.get("removedBy")).getId()) : null) : null,
punishment.getDate("created"),
punishment.containsKey("removalReason") ? punishment.getString("removalReason").toString() : ""
);
if (forReal) {
APIv3.getDatastore().save(created);
}
log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
}
});
importFrom.getCollection("grant").find().forEach(new Block<Document>() {
@Override
public void apply(Document grant) {
UUID target = mongoIdToUUID.get(((DBRef) grant.get("target")).getId());
if (target == null || grant.getString("role").equalsIgnoreCase("unban") || grant.getString("role").equalsIgnoreCase("pass")) {
return;
}
Grant created = new Grant(
new ObjectId().toString(),
target,
grant.containsKey("comment") ? grant.getString("comment") : "",
grant.containsKey("scope") ? ImmutableSet.copyOf((Collection<String>) grant.get("scope")) : ImmutableSet.of(),
grant.getString("role"),
grant.getDate("expires"),
grant.containsKey("addedBy") ? mongoIdToUUID.get(((DBRef) grant.get("addedBy")).getId()) : null,
grant.containsKey("created") ? grant.getDate("created") : new Date(),
null,
null,
null
);
if (forReal) {
APIv3.getDatastore().save(created);
}
log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
}
});
importFrom.getCollection("iplog").find().forEach(new Block<Document>() {
@Override
public void apply(Document ipLogEntry) {
UUID user = mongoIdToUUID.get(((DBRef) ipLogEntry.get("user")).getId());
if (user == null || ipLogEntry.getString("ip") == null) {
return;
}
String ip = ipLogEntry.getString("ip").replace("/", "");
if (!IPUtils.isValidIP(ip)) {
return;
}
Date lastSeen = ipLogEntry.getDate("lastSeen");
if (lastSeen == null) {
lastSeen = new Date();
}
IPLogEntry created = new IPLogEntry(
new ObjectId().toString(),
user,
ip,
lastSeen,
lastSeen,
((Number) ipLogEntry.get("uses")).intValue()
);
if (forReal) {
APIv3.getDatastore().save(created);
}
log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
}
});
}
}

View File

@ -34,9 +34,9 @@ public final class ActorAttributeFilter implements Filter {
if (credentials.length == 2) {
User user = User.byLastUsername(credentials[0]);
char[] password = credentials[1].toCharArray();
String password = credentials[1];
if (user != null && user.checkPassword(password)) {
if (user != null && user.getPassword() != null && user.checkPassword(password)) {
return new UserActor(user);
}
}

View File

@ -1,6 +1,7 @@
package net.frozenorb.apiv3.models;
import com.google.common.collect.Collections2;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import org.bson.types.ObjectId;
@ -14,6 +15,7 @@ import java.util.Set;
import java.util.UUID;
@Entity(value = "grants", noClassnameStored = true)
@AllArgsConstructor
public final class Grant {
@Getter @Id private String id;

View File

@ -1,8 +1,8 @@
package net.frozenorb.apiv3.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
import org.bson.types.ObjectId;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
@ -12,10 +12,11 @@ import java.util.Date;
import java.util.UUID;
@Entity(value = "ipLog", noClassnameStored = true)
@AllArgsConstructor
public final class IPLogEntry {
@Getter @Id private String id;
@Getter @ExcludeFromReplies @Indexed private UUID user;
@Getter @Indexed private UUID user;
@Getter @Indexed private String userIp;
@Getter private Date firstSeenAt;
@Getter private Date lastSeenAt;

View File

@ -1,5 +1,6 @@
package net.frozenorb.apiv3.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actors.Actor;
@ -15,6 +16,7 @@ import java.util.Map;
import java.util.UUID;
@Entity(value = "punishments", noClassnameStored = true)
@AllArgsConstructor
public final class Punishment {
@Getter @Id private String id;

View File

@ -16,6 +16,7 @@ import java.util.*;
public final class ServerGroup {
@Getter @Id private String id;
@Getter private String image;
// We rename this to public, we just can't name it that because it's a Java identifier.
@Getter @Property("public") @SerializedName("public") private boolean isPublic;
// We define these HashSets up here because, in the event they're
@ -33,8 +34,9 @@ public final class ServerGroup {
public ServerGroup() {} // For Morphia
public ServerGroup(String id, boolean isPublic) {
public ServerGroup(String id, String image, boolean isPublic) {
this.id = id;
this.image = image;
this.isPublic = isPublic;
}

View File

@ -1,7 +1,10 @@
package net.frozenorb.apiv3.models;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.Hashing;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.frozenorb.apiv3.APIv3;
@ -17,6 +20,7 @@ import org.mongodb.morphia.annotations.Indexed;
import java.util.*;
@Entity(value = "users", noClassnameStored = true)
@AllArgsConstructor
public final class User {
@Getter @Id private UUID id;
@ -169,12 +173,20 @@ public final class User {
this.aliases.put(username, new Date());
}
public void setPassword(char[] unencrypted) {
this.password = BCrypt.hashpw(new String(unencrypted), BCrypt.gensalt());
public void setPassword(String input) {
this.password = Hashing
.sha256()
.hashString(input + "$" + id.toString(), Charsets.UTF_8)
.toString();
}
public boolean checkPassword(char[] unencrypted) {
return BCrypt.checkpw(new String(unencrypted), password);
public boolean checkPassword(String input) {
String hashed = Hashing
.sha256()
.hashString(input + "$" + id.toString(), Charsets.UTF_8)
.toString();
return hashed.equals(password);
}
public Rank getHighestRank() {

View File

@ -10,9 +10,10 @@ public final class POSTServerGroup implements Route {
public Object handle(Request req, Response res) {
String id = req.queryParams("id");
String image = req.queryParams("image");
boolean isPublic = Boolean.valueOf(req.queryParams("public"));
ServerGroup serverGroup = new ServerGroup(id, isPublic);
ServerGroup serverGroup = new ServerGroup(id, image, isPublic);
APIv3.getDatastore().save(serverGroup);
return serverGroup;
}

View File

@ -20,8 +20,7 @@ public final class GETUserVerifyPassword implements Route {
return ErrorUtils.invalidInput("User provided does not have password set.");
}
char[] password = req.queryParams("password").toCharArray();
boolean authorized = user.checkPassword(password);
boolean authorized = user.checkPassword(req.queryParams("password"));
return ImmutableMap.of(
"authorized", authorized

View File

@ -39,11 +39,11 @@ public final class POSTUserConfirmRegister implements Route {
return ErrorUtils.error("Email token is expired");
}
char[] password = req.queryParams("password").toCharArray();
String password = req.queryParams("password");
if (password.length < 8) {
if (password.length() < 8) {
return ErrorUtils.error("Your password is too short.");
} else if (commonPasswords.contains(new String(password))) {
} else if (commonPasswords.contains(password)) {
return ErrorUtils.error("Your password is too common. Please use a more secure password.");
}

View File

@ -1,8 +1,6 @@
package net.frozenorb.apiv3.routes.users;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actors.Actor;
import net.frozenorb.apiv3.actors.ActorType;
import net.frozenorb.apiv3.models.User;
import net.frozenorb.apiv3.utils.ErrorUtils;
import spark.Request;