Push code for griffin
This commit is contained in:
parent
c3efe78ce4
commit
799a8de386
5
pom.xml
5
pom.xml
@ -87,6 +87,11 @@
|
|||||||
<artifactId>morphia-logging-slf4j</artifactId>
|
<artifactId>morphia-logging-slf4j</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.warrenstrange</groupId>
|
||||||
|
<artifactId>googleauth</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
@ -10,7 +10,6 @@ import lombok.Getter;
|
|||||||
import net.frozenorb.apiv3.filters.ActorAttributeFilter;
|
import net.frozenorb.apiv3.filters.ActorAttributeFilter;
|
||||||
import net.frozenorb.apiv3.filters.AuthorizationFilter;
|
import net.frozenorb.apiv3.filters.AuthorizationFilter;
|
||||||
import net.frozenorb.apiv3.filters.ContentTypeFilter;
|
import net.frozenorb.apiv3.filters.ContentTypeFilter;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
|
||||||
import net.frozenorb.apiv3.routes.GETDump;
|
import net.frozenorb.apiv3.routes.GETDump;
|
||||||
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
||||||
import net.frozenorb.apiv3.routes.NotFound;
|
import net.frozenorb.apiv3.routes.NotFound;
|
||||||
@ -45,7 +44,6 @@ import org.mongodb.morphia.Datastore;
|
|||||||
import org.mongodb.morphia.Morphia;
|
import org.mongodb.morphia.Morphia;
|
||||||
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
|
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
|
||||||
import org.mongodb.morphia.logging.slf4j.SLF4JLoggerImplFactory;
|
import org.mongodb.morphia.logging.slf4j.SLF4JLoggerImplFactory;
|
||||||
import org.slf4j.impl.StaticLoggerBinder;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -57,7 +55,7 @@ public final class APIv3 {
|
|||||||
|
|
||||||
@Getter private static Datastore datastore;
|
@Getter private static Datastore datastore;
|
||||||
@Getter private static Properties config = new Properties();
|
@Getter private static Properties config = new Properties();
|
||||||
private final Gson gson = new GsonBuilder()
|
@Getter private static final Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter())
|
.registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter())
|
||||||
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
||||||
.create();
|
.create();
|
||||||
@ -152,12 +150,14 @@ public final class APIv3 {
|
|||||||
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
||||||
get("/user/:id/grants", new GETUserGrants(), gson::toJson);
|
get("/user/:id/grants", new GETUserGrants(), gson::toJson);
|
||||||
get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson);
|
get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson);
|
||||||
|
get("/user/:id/verifyTOTP", new GETUserVerifyTOTP(), gson::toJson);
|
||||||
get("/user/:id", new GETUser(), gson::toJson);
|
get("/user/:id", new GETUser(), gson::toJson);
|
||||||
post("/user/:id:/grant", new POSTUserGrant(), gson::toJson);
|
post("/user/:id:/grant", new POSTUserGrant(), gson::toJson);
|
||||||
post("/user/:id:/punish", new POSTUserPunish(), gson::toJson);
|
post("/user/:id:/punish", new POSTUserPunish(), gson::toJson);
|
||||||
post("/user/:id/loginInfo", new POSTUserLoginInfo(), gson::toJson);
|
post("/user/:id/loginInfo", new POSTUserLoginInfo(), gson::toJson);
|
||||||
post("/user/:id/notify", new POSTUserNotify(), gson::toJson);
|
post("/user/:id/notify", new POSTUserNotify(), gson::toJson);
|
||||||
post("/user/:id/register", new POSTUserRegister(), gson::toJson);
|
post("/user/:id/register", new POSTUserRegister(), gson::toJson);
|
||||||
|
post("/user/:id/setupTOTP", new POSTUserSetupTOTP(), gson::toJson);
|
||||||
post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson);
|
post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson);
|
||||||
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
||||||
delete("/user/:id/meta", new DELETEUserMeta(), gson::toJson);
|
delete("/user/:id/meta", new DELETEUserMeta(), gson::toJson);
|
||||||
|
@ -3,12 +3,10 @@ package net.frozenorb.apiv3.auditLog;
|
|||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.auditLog.actions.CreatePunishmentAction;
|
|
||||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
@ -18,7 +16,7 @@ public class AuditLog {
|
|||||||
log(performedBy, performedByIp, actor, actionType, new Document());
|
log(performedBy, performedByIp, actor, actionType, new Document());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Document actionData) {
|
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map<String, Object> actionData) {
|
||||||
APIv3.getDatastore().save(new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData));
|
APIv3.getDatastore().save(new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
package net.frozenorb.apiv3.auditLog;
|
package net.frozenorb.apiv3.auditLog;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||||
|
|
||||||
public enum AuditLogActionType {
|
public enum AuditLogActionType {
|
||||||
|
|
||||||
CREATE_PUNISHMENT {
|
DELETE_PUNISHMENT {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revert(AuditLogEntry entry) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
DELETE_GRANT {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void revert(AuditLogEntry entry) {
|
public void revert(AuditLogEntry entry) {
|
||||||
|
@ -9,8 +9,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||||||
import spark.Filter;
|
import spark.Filter;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
|
import spark.Spark;
|
||||||
import static spark.Spark.halt;
|
|
||||||
|
|
||||||
public final class ActorAttributeFilter implements Filter {
|
public final class ActorAttributeFilter implements Filter {
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
halt(401, ErrorUtils.error("Failed to authorize.").toJson());
|
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize.")));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +60,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
Server server = Server.byId(split[1]);
|
Server server = Server.byId(split[1]);
|
||||||
|
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
halt(401, ErrorUtils.notFound("Server", split[1]).toJson());
|
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.notFound("Server", split[1])));
|
||||||
}
|
}
|
||||||
|
|
||||||
String givenKey = split[2];
|
String givenKey = split[2];
|
||||||
@ -73,7 +72,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
halt(401, ErrorUtils.error("Failed to authorize.").toJson());
|
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize.")));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.frozenorb.apiv3.filters;
|
package net.frozenorb.apiv3.filters;
|
||||||
|
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Filter;
|
import spark.Filter;
|
||||||
@ -13,7 +14,7 @@ public final class AuthorizationFilter implements Filter {
|
|||||||
Actor actor = req.attribute("actor");
|
Actor actor = req.attribute("actor");
|
||||||
|
|
||||||
if (!actor.isAuthorized()) {
|
if (!actor.isAuthorized()) {
|
||||||
Spark.halt(ErrorUtils.error("Unauthorized access: Please authenticate as either a server, the website, or an authorized user.").toJson());
|
Spark.halt(APIv3.getGson().toJson(ErrorUtils.error("Unauthorized access: Please authenticate as either a server, the website, or an authorized user. You're currently authorized as " + actor.getName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import org.bson.Document;
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -17,9 +17,9 @@ import java.util.UUID;
|
|||||||
public final class AuditLogEntry {
|
public final class AuditLogEntry {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private UUID performedBy;
|
@Getter @Indexed private UUID performedBy;
|
||||||
@Getter private String performedByIp;
|
@Getter private String performedByIp;
|
||||||
@Getter private Date performedAt;
|
@Getter @Indexed private Date performedAt;
|
||||||
@Getter private String actorName;
|
@Getter private String actorName;
|
||||||
@Getter private Actor.Type actorType;
|
@Getter private Actor.Type actorType;
|
||||||
@Getter private AuditLogActionType actionType;
|
@Getter private AuditLogActionType actionType;
|
||||||
|
@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -16,14 +17,14 @@ import java.util.UUID;
|
|||||||
public final class Grant {
|
public final class Grant {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private UUID target;
|
@Getter @Indexed private UUID target;
|
||||||
@Getter private String reason;
|
@Getter private String reason;
|
||||||
@Getter private Set<String> scopes;
|
@Getter private Set<String> scopes;
|
||||||
@Getter private String rank;
|
@Getter @Indexed private String rank;
|
||||||
@Getter private Date expiresAt;
|
@Getter private Date expiresAt;
|
||||||
|
|
||||||
@Getter private UUID addedBy;
|
@Getter private UUID addedBy;
|
||||||
@Getter private Date addedAt;
|
@Getter @Indexed private Date addedAt;
|
||||||
|
|
||||||
@Getter private UUID removedBy;
|
@Getter private UUID removedBy;
|
||||||
@Getter private Date removedAt;
|
@Getter private Date removedAt;
|
||||||
|
@ -5,6 +5,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -13,8 +14,8 @@ import java.util.UUID;
|
|||||||
public final class IPLogEntry {
|
public final class IPLogEntry {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private UUID user;
|
@Getter @Indexed private UUID user;
|
||||||
@Getter private String ip;
|
@Getter @Indexed private String ip;
|
||||||
@Getter private Date firstSeen;
|
@Getter private Date firstSeen;
|
||||||
@Getter private Date lastSeen;
|
@Getter private Date lastSeen;
|
||||||
@Getter private int uses;
|
@Getter private int uses;
|
||||||
|
@ -5,6 +5,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -13,14 +14,14 @@ import java.util.UUID;
|
|||||||
public final class Punishment {
|
public final class Punishment {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private UUID target;
|
@Getter @Indexed private UUID target;
|
||||||
@Getter private String reason;
|
@Getter private String reason;
|
||||||
@Getter private PunishmentType type;
|
@Getter @Indexed private PunishmentType type; // Type is indexed for the rank dump
|
||||||
@Getter private Date expiresAt;
|
@Getter private Date expiresAt;
|
||||||
|
|
||||||
@Getter private UUID addedBy;
|
@Getter private UUID addedBy;
|
||||||
@Getter private Date addedAt;
|
@Getter @Indexed private Date addedAt;
|
||||||
@Getter private String addedOn;
|
@Getter private String addedOn; // TODO: Make this store actor like the audit log?
|
||||||
|
|
||||||
@Getter private UUID removedBy;
|
@Getter private UUID removedBy;
|
||||||
@Getter private Date removedAt;
|
@Getter private Date removedAt;
|
||||||
|
@ -4,6 +4,7 @@ import lombok.Getter;
|
|||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ public final class Rank {
|
|||||||
@Getter private String displayName;
|
@Getter private String displayName;
|
||||||
@Getter private String gameColor;
|
@Getter private String gameColor;
|
||||||
@Getter private String websiteColor;
|
@Getter private String websiteColor;
|
||||||
@Getter private boolean staffRank;
|
@Getter @Indexed private boolean staffRank;
|
||||||
|
|
||||||
public static Rank byId(String id) {
|
public static Rank byId(String id) {
|
||||||
return APIv3.getDatastore().createQuery(Rank.class).field("id").equal(id).get();
|
return APIv3.getDatastore().createQuery(Rank.class).field("id").equal(id).get();
|
||||||
|
@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ public final class Server {
|
|||||||
@Getter private String bungeeId;
|
@Getter private String bungeeId;
|
||||||
@Getter private String displayName;
|
@Getter private String displayName;
|
||||||
@Getter @ExcludeFromReplies String apiKey;
|
@Getter @ExcludeFromReplies String apiKey;
|
||||||
@Getter private String group;
|
@Getter @Indexed private String group;
|
||||||
@Getter private String ip;
|
@Getter private String ip;
|
||||||
@Getter @Setter private Date lastUpdate;
|
@Getter @Setter private Date lastUpdate;
|
||||||
@Getter @Setter private double lastTps;
|
@Getter @Setter private double lastTps;
|
||||||
|
@ -11,6 +11,7 @@ import org.bson.Document;
|
|||||||
import org.mindrot.jbcrypt.BCrypt;
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -18,10 +19,10 @@ import java.util.*;
|
|||||||
public final class User {
|
public final class User {
|
||||||
|
|
||||||
@Getter @Id private UUID id;
|
@Getter @Id private UUID id;
|
||||||
@Getter private String lastUsername;
|
@Getter @Indexed private String lastUsername;
|
||||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases;
|
@Getter @ExcludeFromReplies private Map<String, Date> aliases;
|
||||||
@Getter @ExcludeFromReplies private String otpCode;
|
@Getter @Setter @ExcludeFromReplies private String totpSecret;
|
||||||
@Getter @ExcludeFromReplies @Setter private String emailToken;
|
@Getter @Indexed @ExcludeFromReplies @Setter private String emailToken;
|
||||||
@Getter @ExcludeFromReplies @Setter private Date emailTokenSet;
|
@Getter @ExcludeFromReplies @Setter private Date emailTokenSet;
|
||||||
@Getter @ExcludeFromReplies private String password;
|
@Getter @ExcludeFromReplies private String password;
|
||||||
@Getter @Setter private String email;
|
@Getter @Setter private String email;
|
||||||
@ -57,7 +58,7 @@ public final class User {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.lastUsername = lastUsername;
|
this.lastUsername = lastUsername;
|
||||||
this.aliases = new HashMap<>();
|
this.aliases = new HashMap<>();
|
||||||
this.otpCode = null;
|
this.totpSecret = null;
|
||||||
this.password = null;
|
this.password = null;
|
||||||
this.email = null;
|
this.email = null;
|
||||||
this.phoneNumber = -1;
|
this.phoneNumber = -1;
|
||||||
|
@ -7,6 +7,7 @@ import org.bson.Document;
|
|||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -14,8 +15,8 @@ import java.util.UUID;
|
|||||||
public final class UserMetaEntry {
|
public final class UserMetaEntry {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private UUID user;
|
@Getter @Indexed private UUID user;
|
||||||
@Getter private String serverGroup;
|
@Getter @Indexed private String serverGroup;
|
||||||
@Getter @Setter private Document data;
|
@Getter @Setter private Document data;
|
||||||
|
|
||||||
public UserMetaEntry() {} // For Morphia
|
public UserMetaEntry() {} // For Morphia
|
||||||
|
@ -2,7 +2,6 @@ package net.frozenorb.apiv3.routes;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import org.bson.Document;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package net.frozenorb.apiv3.routes;
|
package net.frozenorb.apiv3.routes;
|
||||||
|
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
@ -12,7 +10,7 @@ import spark.Spark;
|
|||||||
public final class NotFound implements Route {
|
public final class NotFound implements Route {
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
Spark.halt(404, ErrorUtils.notFound("Route", req.url()).toJson());
|
Spark.halt(404, APIv3.getGson().toJson(ErrorUtils.notFound("Route", req.url())));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes.grants;
|
package net.frozenorb.apiv3.routes.grants;
|
||||||
|
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.auditLog.AuditLog;
|
|
||||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
@ -33,7 +34,8 @@ public final class DELETEGrant implements Route {
|
|||||||
String reason = req.queryParams("removalReason");
|
String reason = req.queryParams("removalReason");
|
||||||
|
|
||||||
grant.delete(removedBy, reason);
|
grant.delete(removedBy, reason);
|
||||||
AuditLog.log(removedBy, req.attribute("actor"), "grant.remove", new Document("grantId", grant.getId()));
|
// TODO: Fix IP
|
||||||
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_GRANT, new Document("grantId", grant.getId()));
|
||||||
return grant;
|
return grant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.frozenorb.apiv3.routes.grants;
|
package net.frozenorb.apiv3.routes.grants;
|
||||||
|
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes.punishments;
|
package net.frozenorb.apiv3.routes.punishments;
|
||||||
|
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.auditLog.AuditLog;
|
|
||||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
@ -33,7 +34,8 @@ public final class DELETEPunishment implements Route {
|
|||||||
String reason = req.queryParams("removalReason");
|
String reason = req.queryParams("removalReason");
|
||||||
|
|
||||||
punishment.delete(removedBy, reason);
|
punishment.delete(removedBy, reason);
|
||||||
AuditLog.log(removedBy, req.attribute("actor"), "punishment.remove", new Document("punishmentId", punishment.getId()));
|
// TODO: Fix IP
|
||||||
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, new Document("punishmentId", punishment.getId()));
|
||||||
return punishment;
|
return punishment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import net.frozenorb.apiv3.models.User;
|
||||||
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
import spark.Route;
|
||||||
|
|
||||||
|
public final class GETUserVerifyTOTP implements Route {
|
||||||
|
|
||||||
|
public Object handle(Request req, Response res) {
|
||||||
|
User user = User.byId(req.params("id"));
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
return ErrorUtils.notFound("User", req.params("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.getTotpSecret() == null) {
|
||||||
|
return ErrorUtils.invalidInput("User provided does not have TOTP code set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int providedCode = Integer.parseInt(req.queryParams("code"));
|
||||||
|
|
||||||
|
return ImmutableMap.of(
|
||||||
|
"verified", TOTPUtils.authorizeUser(user, providedCode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import org.bson.Document;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -51,7 +51,9 @@ public final class POSTUserConfirmRegister implements Route {
|
|||||||
user.setPassword(password.toCharArray());
|
user.setPassword(password.toCharArray());
|
||||||
APIv3.getDatastore().save(user);
|
APIv3.getDatastore().save(user);
|
||||||
|
|
||||||
return new Document("success", true).append("message", "User confirmed");
|
return ImmutableMap.of(
|
||||||
|
"success", true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.unsorted.Notification;
|
import net.frozenorb.apiv3.unsorted.Notification;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import org.bson.Document;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -46,7 +46,9 @@ public final class POSTUserNotify implements Route {
|
|||||||
Notification notification = new Notification(template, subjectReplacements, bodyReplacements);
|
Notification notification = new Notification(template, subjectReplacements, bodyReplacements);
|
||||||
|
|
||||||
notification.sendAsEmail(user.getEmail());
|
notification.sendAsEmail(user.getEmail());
|
||||||
return new Document("success", true);
|
return ImmutableMap.of(
|
||||||
|
"success", true
|
||||||
|
);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return ErrorUtils.error("Failed to send notification");
|
return ErrorUtils.error("Failed to send notification");
|
||||||
|
@ -6,7 +6,6 @@ import net.frozenorb.apiv3.models.NotificationTemplate;
|
|||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.unsorted.Notification;
|
import net.frozenorb.apiv3.unsorted.Notification;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import org.bson.Document;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -59,7 +58,9 @@ public final class POSTUserRegister implements Route {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
notification.sendAsEmail(user.getEmail());
|
notification.sendAsEmail(user.getEmail());
|
||||||
return new Document("success", true).append("message", "User registered");
|
return ImmutableMap.of(
|
||||||
|
"success", true
|
||||||
|
);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return ErrorUtils.error("Failed to send confirmation email. Please contact a MineHQ staff member.");
|
return ErrorUtils.error("Failed to send confirmation email. Please contact a MineHQ staff member.");
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import net.frozenorb.apiv3.models.User;
|
||||||
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
import spark.Route;
|
||||||
|
|
||||||
|
public final class POSTUserSetupTOTP implements Route {
|
||||||
|
|
||||||
|
public Object handle(Request req, Response res) {
|
||||||
|
User user = User.byId(req.params("id"));
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
return ErrorUtils.notFound("User", req.params("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.getTotpSecret() != null) {
|
||||||
|
return ErrorUtils.invalidInput("User provided already has TOTP code set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GoogleAuthenticatorKey generated = TOTPUtils.generateTOTPKey();
|
||||||
|
|
||||||
|
user.setTotpSecret(generated.getKey());
|
||||||
|
APIv3.getDatastore().save(user);
|
||||||
|
|
||||||
|
return ImmutableMap.of(
|
||||||
|
"qrCode", TOTPUtils.getQRCodeURL(user, generated)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.unsorted;
|
package net.frozenorb.apiv3.unsorted;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import spark.ExceptionHandler;
|
import spark.ExceptionHandler;
|
||||||
@ -16,7 +17,7 @@ public final class LoggingExceptionHandler implements ExceptionHandler {
|
|||||||
log.error(code + ":");
|
log.error(code + ":");
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
|
||||||
res.body(ErrorUtils.error("An unknown error has occurred. Please contact a developer with the code \"" + code + "\".").toJson());
|
res.body(APIv3.getGson().toJson(ErrorUtils.error("An unknown error has occurred. Please contact a developer with the code \"" + code + "\".")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,29 +1,34 @@
|
|||||||
package net.frozenorb.apiv3.utils;
|
package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import org.bson.Document;
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class ErrorUtils {
|
public class ErrorUtils {
|
||||||
|
|
||||||
public static Document serverOnly() {
|
public static Map<String, Object> serverOnly() {
|
||||||
return error("This action can only be performed when requested by a server.");
|
return error("This action can only be performed when requested by a server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Document notFound(String itemType, String id) {
|
public static Map<String, Object> notFound(String itemType, String id) {
|
||||||
return error("Not found: " + itemType + " with id " + id + " cannot be found.");
|
return error("Not found: " + itemType + " with id " + id + " cannot be found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Document unauthorized(String permission) {
|
public static Map<String, Object> unauthorized(String permission) {
|
||||||
return error("Unauthorized access: Permission \"" + permission + "\" required.");
|
return error("Unauthorized access: Permission \"" + permission + "\" required.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Document invalidInput(String message) {
|
public static Map<String, Object> invalidInput(String message) {
|
||||||
return error("Invalid input: " + message);
|
return error("Invalid input: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Document error(String message) {
|
public static Map<String, Object> error(String message) {
|
||||||
return new Document("success", false).append("message", message);
|
return ImmutableMap.of(
|
||||||
|
"success", false,
|
||||||
|
"message", message
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
32
src/main/java/net/frozenorb/apiv3/utils/TOTPUtils.java
Normal file
32
src/main/java/net/frozenorb/apiv3/utils/TOTPUtils.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
||||||
|
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
||||||
|
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.frozenorb.apiv3.models.User;
|
||||||
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class TOTPUtils {
|
||||||
|
|
||||||
|
private static GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
|
||||||
|
|
||||||
|
public static GoogleAuthenticatorKey generateTOTPKey() {
|
||||||
|
return googleAuthenticator.createCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean authorizeUser(User user, int code) {
|
||||||
|
return googleAuthenticator.authorize(user.getTotpSecret(), code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getQRCodeURL(User user, GoogleAuthenticatorKey key) {
|
||||||
|
return GoogleAuthenticatorQRGenerator.getOtpAuthURL(
|
||||||
|
"MineHQ v3",
|
||||||
|
user.getLastUsername(),
|
||||||
|
key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user