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>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.warrenstrange</groupId>
|
||||
<artifactId>googleauth</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
|
|
@ -10,7 +10,6 @@ import lombok.Getter;
|
|||
import net.frozenorb.apiv3.filters.ActorAttributeFilter;
|
||||
import net.frozenorb.apiv3.filters.AuthorizationFilter;
|
||||
import net.frozenorb.apiv3.filters.ContentTypeFilter;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.routes.GETDump;
|
||||
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
||||
import net.frozenorb.apiv3.routes.NotFound;
|
||||
|
@ -45,7 +44,6 @@ import org.mongodb.morphia.Datastore;
|
|||
import org.mongodb.morphia.Morphia;
|
||||
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
|
||||
import org.mongodb.morphia.logging.slf4j.SLF4JLoggerImplFactory;
|
||||
import org.slf4j.impl.StaticLoggerBinder;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
|
@ -57,7 +55,7 @@ public final class APIv3 {
|
|||
|
||||
@Getter private static Datastore datastore;
|
||||
@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())
|
||||
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
||||
.create();
|
||||
|
@ -152,12 +150,14 @@ public final class APIv3 {
|
|||
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
||||
get("/user/:id/grants", new GETUserGrants(), 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);
|
||||
post("/user/:id:/grant", new POSTUserGrant(), gson::toJson);
|
||||
post("/user/:id:/punish", new POSTUserPunish(), gson::toJson);
|
||||
post("/user/:id/loginInfo", new POSTUserLoginInfo(), gson::toJson);
|
||||
post("/user/:id/notify", new POSTUserNotify(), 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);
|
||||
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
||||
delete("/user/:id/meta", new DELETEUserMeta(), gson::toJson);
|
||||
|
|
|
@ -3,12 +3,10 @@ package net.frozenorb.apiv3.auditLog;
|
|||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.auditLog.actions.CreatePunishmentAction;
|
||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@UtilityClass
|
||||
|
@ -18,7 +16,7 @@ public class AuditLog {
|
|||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
package net.frozenorb.apiv3.auditLog;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||
|
||||
public enum AuditLogActionType {
|
||||
|
||||
CREATE_PUNISHMENT {
|
||||
DELETE_PUNISHMENT {
|
||||
|
||||
@Override
|
||||
public void revert(AuditLogEntry entry) {
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
DELETE_GRANT {
|
||||
|
||||
@Override
|
||||
public void revert(AuditLogEntry entry) {
|
||||
|
|
|
@ -9,8 +9,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||
import spark.Filter;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
import static spark.Spark.halt;
|
||||
import spark.Spark;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -61,7 +60,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||
Server server = Server.byId(split[1]);
|
||||
|
||||
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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.frozenorb.apiv3.filters;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Filter;
|
||||
|
@ -13,7 +14,7 @@ public final class AuthorizationFilter implements Filter {
|
|||
Actor actor = req.attribute("actor");
|
||||
|
||||
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 net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
@ -17,9 +17,9 @@ import java.util.UUID;
|
|||
public final class AuditLogEntry {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private UUID performedBy;
|
||||
@Getter @Indexed private UUID performedBy;
|
||||
@Getter private String performedByIp;
|
||||
@Getter private Date performedAt;
|
||||
@Getter @Indexed private Date performedAt;
|
||||
@Getter private String actorName;
|
||||
@Getter private Actor.Type actorType;
|
||||
@Getter private AuditLogActionType actionType;
|
||||
|
|
|
@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
|
@ -16,14 +17,14 @@ import java.util.UUID;
|
|||
public final class Grant {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private UUID target;
|
||||
@Getter @Indexed private UUID target;
|
||||
@Getter private String reason;
|
||||
@Getter private Set<String> scopes;
|
||||
@Getter private String rank;
|
||||
@Getter @Indexed private String rank;
|
||||
@Getter private Date expiresAt;
|
||||
|
||||
@Getter private UUID addedBy;
|
||||
@Getter private Date addedAt;
|
||||
@Getter @Indexed private Date addedAt;
|
||||
|
||||
@Getter private UUID removedBy;
|
||||
@Getter private Date removedAt;
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
@ -13,8 +14,8 @@ import java.util.UUID;
|
|||
public final class IPLogEntry {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private UUID user;
|
||||
@Getter private String ip;
|
||||
@Getter @Indexed private UUID user;
|
||||
@Getter @Indexed private String ip;
|
||||
@Getter private Date firstSeen;
|
||||
@Getter private Date lastSeen;
|
||||
@Getter private int uses;
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
@ -13,14 +14,14 @@ import java.util.UUID;
|
|||
public final class Punishment {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private UUID target;
|
||||
@Getter @Indexed private UUID target;
|
||||
@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 UUID addedBy;
|
||||
@Getter private Date addedAt;
|
||||
@Getter private String addedOn;
|
||||
@Getter @Indexed private Date addedAt;
|
||||
@Getter private String addedOn; // TODO: Make this store actor like the audit log?
|
||||
|
||||
@Getter private UUID removedBy;
|
||||
@Getter private Date removedAt;
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Getter;
|
|||
import net.frozenorb.apiv3.APIv3;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -15,7 +16,7 @@ public final class Rank {
|
|||
@Getter private String displayName;
|
||||
@Getter private String gameColor;
|
||||
@Getter private String websiteColor;
|
||||
@Getter private boolean staffRank;
|
||||
@Getter @Indexed private boolean staffRank;
|
||||
|
||||
public static Rank byId(String id) {
|
||||
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 org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -16,7 +17,7 @@ public final class Server {
|
|||
@Getter private String bungeeId;
|
||||
@Getter private String displayName;
|
||||
@Getter @ExcludeFromReplies String apiKey;
|
||||
@Getter private String group;
|
||||
@Getter @Indexed private String group;
|
||||
@Getter private String ip;
|
||||
@Getter @Setter private Date lastUpdate;
|
||||
@Getter @Setter private double lastTps;
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.bson.Document;
|
|||
import org.mindrot.jbcrypt.BCrypt;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -18,10 +19,10 @@ import java.util.*;
|
|||
public final class User {
|
||||
|
||||
@Getter @Id private UUID id;
|
||||
@Getter private String lastUsername;
|
||||
@Getter @Indexed private String lastUsername;
|
||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases;
|
||||
@Getter @ExcludeFromReplies private String otpCode;
|
||||
@Getter @ExcludeFromReplies @Setter private String emailToken;
|
||||
@Getter @Setter @ExcludeFromReplies private String totpSecret;
|
||||
@Getter @Indexed @ExcludeFromReplies @Setter private String emailToken;
|
||||
@Getter @ExcludeFromReplies @Setter private Date emailTokenSet;
|
||||
@Getter @ExcludeFromReplies private String password;
|
||||
@Getter @Setter private String email;
|
||||
|
@ -57,7 +58,7 @@ public final class User {
|
|||
this.id = id;
|
||||
this.lastUsername = lastUsername;
|
||||
this.aliases = new HashMap<>();
|
||||
this.otpCode = null;
|
||||
this.totpSecret = null;
|
||||
this.password = null;
|
||||
this.email = null;
|
||||
this.phoneNumber = -1;
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.bson.Document;
|
|||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -14,8 +15,8 @@ import java.util.UUID;
|
|||
public final class UserMetaEntry {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private UUID user;
|
||||
@Getter private String serverGroup;
|
||||
@Getter @Indexed private UUID user;
|
||||
@Getter @Indexed private String serverGroup;
|
||||
@Getter @Setter private Document data;
|
||||
|
||||
public UserMetaEntry() {} // For Morphia
|
||||
|
|
|
@ -2,7 +2,6 @@ package net.frozenorb.apiv3.routes;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
@ -12,7 +10,7 @@ import spark.Spark;
|
|||
public final class NotFound implements Route {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
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.User;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
|
@ -33,7 +34,8 @@ public final class DELETEGrant implements Route {
|
|||
String reason = req.queryParams("removalReason");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package net.frozenorb.apiv3.routes.grants;
|
||||
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
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.User;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
|
@ -33,7 +34,8 @@ public final class DELETEPunishment implements Route {
|
|||
String reason = req.queryParams("removalReason");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
@ -51,7 +51,9 @@ public final class POSTUserConfirmRegister implements Route {
|
|||
user.setPassword(password.toCharArray());
|
||||
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;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.Notification;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
@ -46,7 +46,9 @@ public final class POSTUserNotify implements Route {
|
|||
Notification notification = new Notification(template, subjectReplacements, bodyReplacements);
|
||||
|
||||
notification.sendAsEmail(user.getEmail());
|
||||
return new Document("success", true);
|
||||
return ImmutableMap.of(
|
||||
"success", true
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
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.unsorted.Notification;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
@ -59,7 +58,9 @@ public final class POSTUserRegister implements Route {
|
|||
|
||||
try {
|
||||
notification.sendAsEmail(user.getEmail());
|
||||
return new Document("success", true).append("message", "User registered");
|
||||
return ImmutableMap.of(
|
||||
"success", true
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
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;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.types.ObjectId;
|
||||
import spark.ExceptionHandler;
|
||||
|
@ -16,7 +17,7 @@ public final class LoggingExceptionHandler implements ExceptionHandler {
|
|||
log.error(code + ":");
|
||||
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;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@UtilityClass
|
||||
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.");
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
public static Document unauthorized(String permission) {
|
||||
public static Map<String, Object> unauthorized(String permission) {
|
||||
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);
|
||||
}
|
||||
|
||||
public static Document error(String message) {
|
||||
return new Document("success", false).append("message", message);
|
||||
public static Map<String, Object> error(String message) {
|
||||
return ImmutableMap.of(
|
||||
"success", false,
|
||||
"message", message
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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