More work
This commit is contained in:
parent
2d05637103
commit
03bc01e5ce
@ -3,6 +3,8 @@ mongo.port=55505
|
|||||||
mongo.database=minehqapi
|
mongo.database=minehqapi
|
||||||
mongo.username=test
|
mongo.username=test
|
||||||
mongo.password=test
|
mongo.password=test
|
||||||
|
redis.address=localhost
|
||||||
|
redis.port=6379
|
||||||
http.address=
|
http.address=
|
||||||
http.port=80
|
http.port=80
|
||||||
http.workerThreads=6
|
http.workerThreads=6
|
||||||
|
10
pom.xml
10
pom.xml
@ -77,6 +77,11 @@
|
|||||||
<artifactId>metrics-core</artifactId>
|
<artifactId>metrics-core</artifactId>
|
||||||
<version>3.1.2</version>
|
<version>3.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.bugsnag</groupId>
|
||||||
|
<artifactId>bugsnag</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongo-java-driver</artifactId>
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
@ -87,6 +92,11 @@
|
|||||||
<artifactId>mandrillClient</artifactId>
|
<artifactId>mandrillClient</artifactId>
|
||||||
<version>1.1</version>
|
<version>1.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twilio.sdk</groupId>
|
||||||
|
<artifactId>twilio-java-sdk</artifactId>
|
||||||
|
<version>6.3.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mindrot</groupId>
|
<groupId>org.mindrot</groupId>
|
||||||
<artifactId>jbcrypt</artifactId>
|
<artifactId>jbcrypt</artifactId>
|
||||||
|
@ -44,6 +44,7 @@ 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 redis.clients.jedis.JedisPool;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -55,6 +56,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();
|
||||||
|
@Getter private static JedisPool redisPool;
|
||||||
@Getter private static 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())
|
||||||
@ -65,6 +67,7 @@ public final class APIv3 {
|
|||||||
|
|
||||||
setupConfig();
|
setupConfig();
|
||||||
setupDatabase();
|
setupDatabase();
|
||||||
|
setupRedis();
|
||||||
setupHttp();
|
setupHttp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +100,13 @@ public final class APIv3 {
|
|||||||
datastore.ensureIndexes();
|
datastore.ensureIndexes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupRedis() {
|
||||||
|
redisPool = new JedisPool(
|
||||||
|
config.getProperty("redis.address"),
|
||||||
|
Integer.parseInt(config.getProperty("redis.port"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void setupHttp() {
|
private void setupHttp() {
|
||||||
ipAddress(config.getProperty("http.address"));
|
ipAddress(config.getProperty("http.address"));
|
||||||
port(Integer.parseInt(config.getProperty("http.port")));
|
port(Integer.parseInt(config.getProperty("http.port")));
|
||||||
@ -106,6 +116,8 @@ public final class APIv3 {
|
|||||||
before(new AuthorizationFilter());
|
before(new AuthorizationFilter());
|
||||||
exception(Exception.class, new LoggingExceptionHandler());
|
exception(Exception.class, new LoggingExceptionHandler());
|
||||||
|
|
||||||
|
// TODO: The commented out routes
|
||||||
|
|
||||||
get("/announcements", new GETAnnouncements(), gson::toJson);
|
get("/announcements", new GETAnnouncements(), gson::toJson);
|
||||||
get("/auditLog", new GETAuditLog(), gson::toJson);
|
get("/auditLog", new GETAuditLog(), gson::toJson);
|
||||||
get("/chatFilterList", new GETChatFilterList(), gson::toJson);
|
get("/chatFilterList", new GETChatFilterList(), gson::toJson);
|
||||||
@ -151,8 +163,9 @@ 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);
|
||||||
post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), gson::toJson);
|
get("/user/:id/requiresTOTP", new GETUserRequiresTOTP(), gson::toJson);
|
||||||
get("/user/:id", new GETUser(), gson::toJson);
|
get("/user/:id", new GETUser(), gson::toJson);
|
||||||
|
post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), 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/login", new POSTUserLogin(), gson::toJson);
|
post("/user/:id/login", new POSTUserLogin(), gson::toJson);
|
||||||
|
@ -26,6 +26,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") // We purposely get the User by their last username.
|
||||||
private Actor processBasicAuthorization(String authHeader) {
|
private Actor processBasicAuthorization(String authHeader) {
|
||||||
String encodedHeader = authHeader.substring("Basic ".length());
|
String encodedHeader = authHeader.substring("Basic ".length());
|
||||||
String[] credentials = Base64.base64Decode(encodedHeader).split(":");
|
String[] credentials = Base64.base64Decode(encodedHeader).split(":");
|
||||||
|
@ -2,6 +2,7 @@ package net.frozenorb.apiv3.routes.auditLog;
|
|||||||
|
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||||
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -9,10 +10,14 @@ import spark.Route;
|
|||||||
public final class GETAuditLog implements Route {
|
public final class GETAuditLog implements Route {
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
|
try {
|
||||||
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
||||||
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
||||||
|
|
||||||
return APIv3.getDatastore().createQuery(AuditLogEntry.class).order("performedAt").limit(limit).offset(offset).asList();
|
return APIv3.getDatastore().createQuery(AuditLogEntry.class).order("performedAt").limit(limit).offset(offset).asList();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
return ErrorUtils.invalidInput(";imit and offset must be numerical inputs.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -31,7 +31,11 @@ public final class DELETEGrant implements Route {
|
|||||||
return ErrorUtils.unauthorized(requiredPermission);
|
return ErrorUtils.unauthorized(requiredPermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
String reason = req.queryParams("removalReason");
|
String reason = req.queryParams("reason");
|
||||||
|
|
||||||
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
|
return ErrorUtils.requiredInput("reason");
|
||||||
|
}
|
||||||
|
|
||||||
grant.delete(removedBy, reason);
|
grant.delete(removedBy, reason);
|
||||||
// TODO: Fix IP
|
// TODO: Fix IP
|
||||||
|
@ -2,6 +2,7 @@ package net.frozenorb.apiv3.routes.grants;
|
|||||||
|
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -9,10 +10,14 @@ import spark.Route;
|
|||||||
public final class GETGrants implements Route {
|
public final class GETGrants implements Route {
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
|
try {
|
||||||
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
||||||
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
||||||
|
|
||||||
return APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList();
|
return APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
return ErrorUtils.invalidInput("limit and offset must be numerical inputs.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -26,8 +26,8 @@ public final class POSTUserGrant implements Route {
|
|||||||
|
|
||||||
String reason = req.queryParams("reason");
|
String reason = req.queryParams("reason");
|
||||||
|
|
||||||
if (reason.trim().isEmpty()) {
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
return ErrorUtils.invalidInput("A reason must be provided.");
|
return ErrorUtils.requiredInput("reason");
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ServerGroup> scopes = new HashSet<>();
|
Set<ServerGroup> scopes = new HashSet<>();
|
||||||
|
@ -33,6 +33,10 @@ public final class DELETEPunishment implements Route {
|
|||||||
|
|
||||||
String reason = req.queryParams("removalReason");
|
String reason = req.queryParams("removalReason");
|
||||||
|
|
||||||
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
|
return ErrorUtils.requiredInput("reason");
|
||||||
|
}
|
||||||
|
|
||||||
punishment.delete(removedBy, reason);
|
punishment.delete(removedBy, reason);
|
||||||
// TODO: Fix IP
|
// TODO: Fix IP
|
||||||
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, new Document("punishmentId", punishment.getId()));
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, new Document("punishmentId", punishment.getId()));
|
||||||
|
@ -2,6 +2,7 @@ package net.frozenorb.apiv3.routes.punishments;
|
|||||||
|
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -9,10 +10,14 @@ import spark.Route;
|
|||||||
public final class GETPunishments implements Route {
|
public final class GETPunishments implements Route {
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
|
try {
|
||||||
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
||||||
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
||||||
|
|
||||||
return APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList();
|
return APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList();
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
return ErrorUtils.invalidInput("limit and offset must be numerical inputs.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -17,14 +17,16 @@ public final class POSTUserPunish implements Route {
|
|||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
User target = User.byId(req.params("id"));
|
User target = User.byId(req.params("id"));
|
||||||
|
|
||||||
|
// TODO: PROTECTED USERS
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
return ErrorUtils.notFound("User", req.params("id"));
|
return ErrorUtils.notFound("User", req.params("id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
String reason = req.queryParams("reason");
|
String reason = req.queryParams("reason");
|
||||||
|
|
||||||
if (reason.trim().isEmpty()) {
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
return ErrorUtils.invalidInput("A reason must be provided.");
|
return ErrorUtils.requiredInput("reason");
|
||||||
}
|
}
|
||||||
|
|
||||||
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type"));
|
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type"));
|
||||||
|
@ -4,6 +4,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
import net.frozenorb.apiv3.models.ServerGroup;
|
import net.frozenorb.apiv3.models.ServerGroup;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
import net.frozenorb.apiv3.utils.IPUtils;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -22,6 +23,10 @@ public final class POSTServer implements Route {
|
|||||||
return ErrorUtils.notFound("Server group", req.queryParams("group"));
|
return ErrorUtils.notFound("Server group", req.queryParams("group"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IPUtils.isValidIP(ip)) {
|
||||||
|
return ErrorUtils.invalidInput("IP address \"" + ip + "\" is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
Server server = new Server(id, bungeeId, displayName, apiKey, group, ip);
|
Server server = new Server(id, bungeeId, displayName, apiKey, group, ip);
|
||||||
APIv3.getDatastore().save(server);
|
APIv3.getDatastore().save(server);
|
||||||
return server;
|
return server;
|
||||||
|
@ -1,20 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.servers;
|
package net.frozenorb.apiv3.routes.servers;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.librato.metrics.LibratoBatch;
|
|
||||||
import net.frozenorb.apiv3.APIv3;
|
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
import net.frozenorb.apiv3.actors.ActorType;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
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;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public final class POSTServerMetrics implements Route {
|
public final class POSTServerMetrics implements Route {
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
|
@ -20,7 +20,8 @@ public final class GETUserDetails implements Route {
|
|||||||
"user", user,
|
"user", user,
|
||||||
"grants", user.getGrants(),
|
"grants", user.getGrants(),
|
||||||
"ipLog", user.getIPLog(),
|
"ipLog", user.getIPLog(),
|
||||||
"punishments", user.getPunishments()
|
"punishments", user.getPunishments(),
|
||||||
|
"totpRequired", user.getTotpSecret() != null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
|
public class GETUserRequiresTOTP {
|
||||||
|
}
|
@ -6,6 +6,7 @@ import net.frozenorb.apiv3.actors.ActorType;
|
|||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
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 net.frozenorb.apiv3.utils.IPUtils;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
@ -24,6 +25,10 @@ public final class POSTUserLogin implements Route {
|
|||||||
return ErrorUtils.serverOnly();
|
return ErrorUtils.serverOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IPUtils.isValidIP(userIp)) {
|
||||||
|
return ErrorUtils.invalidInput("IP address \"" + userIp + "\" is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
user = new User(UUID.fromString(req.params("id")), username);
|
user = new User(UUID.fromString(req.params("id")), username);
|
||||||
APIv3.getDatastore().save(user);
|
APIv3.getDatastore().save(user);
|
||||||
|
@ -19,9 +19,12 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
public final class POSTUserRegister implements Route {
|
public final class POSTUserRegister implements Route {
|
||||||
|
|
||||||
private static final Pattern VALID_EMAIL_ADDRESS_REGEX =
|
private static final Pattern VALID_EMAIL_PATTERN =
|
||||||
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
|
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
// TODO: POSSIBLE? perms check
|
||||||
|
// TODO: make messages better
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
User user = User.byId(req.params("id"));
|
User user = User.byId(req.params("id"));
|
||||||
|
|
||||||
@ -35,7 +38,7 @@ public final class POSTUserRegister implements Route {
|
|||||||
|
|
||||||
String email = req.queryParams("email");
|
String email = req.queryParams("email");
|
||||||
|
|
||||||
if (!VALID_EMAIL_ADDRESS_REGEX.matcher(email).find()) {
|
if (!VALID_EMAIL_PATTERN.matcher(email).matches()) {
|
||||||
return ErrorUtils.error(email + " is not a valid email.");
|
return ErrorUtils.error(email + " is not a valid email.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ public final class LoggingExceptionHandler implements ExceptionHandler {
|
|||||||
String code = new ObjectId().toHexString();
|
String code = new ObjectId().toHexString();
|
||||||
|
|
||||||
log.error(code + ":", ex);
|
log.error(code + ":", ex);
|
||||||
res.body(APIv3.getGson().toJson(ErrorUtils.error("An unknown error has occurred. Please contact a developer with the code \"" + code + "\".")));
|
res.body(APIv3.getGson().toJson(ErrorUtils.error("An unknown error has occurred. Please contact an API developer with the code \"" + code + "\".")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -45,6 +45,7 @@ public final class Notification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendAsText(String phoneNumber) throws IOException {
|
public void sendAsText(String phoneNumber) throws IOException {
|
||||||
|
// TODO
|
||||||
throw new IOException(new NotImplementedException());
|
throw new IOException(new NotImplementedException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ public class Permissions {
|
|||||||
public static final String CREATE_GRANT = "minehq.grant.create"; // minehq.grant.create.%RANK%
|
public static final String CREATE_GRANT = "minehq.grant.create"; // minehq.grant.create.%RANK%
|
||||||
|
|
||||||
public static final String REMOVE_PUNISHMENT = "minehq.punishment.remove"; // minehq.punishment.remove.%TYPE%
|
public static final String REMOVE_PUNISHMENT = "minehq.punishment.remove"; // minehq.punishment.remove.%TYPE%
|
||||||
public static final String CREATE_PUNISHMENT = "minehq.punishment.create"; // minehq.punishment.remove.%TYPE%
|
public static final String CREATE_PUNISHMENT = "minehq.punishment.create"; // minehq.punishment.create.%TYPE%
|
||||||
|
|
||||||
}
|
}
|
@ -24,6 +24,10 @@ public class ErrorUtils {
|
|||||||
return error("Invalid input: " + message);
|
return error("Invalid input: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> requiredInput(String field) {
|
||||||
|
return error("Field \"" + field + "\" is required.");
|
||||||
|
}
|
||||||
|
|
||||||
public static Map<String, Object> error(String message) {
|
public static Map<String, Object> error(String message) {
|
||||||
return ImmutableMap.of(
|
return ImmutableMap.of(
|
||||||
"success", false,
|
"success", false,
|
||||||
|
20
src/main/java/net/frozenorb/apiv3/utils/IPUtils.java
Normal file
20
src/main/java/net/frozenorb/apiv3/utils/IPUtils.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class IPUtils {
|
||||||
|
|
||||||
|
private static final Pattern VALID_IP_PATTERN = Pattern.compile(
|
||||||
|
"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
|
||||||
|
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
|
||||||
|
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
|
||||||
|
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
|
||||||
|
|
||||||
|
public static boolean isValidIP(String ip) {
|
||||||
|
return ip != null && VALID_IP_PATTERN.matcher(ip).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,12 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.utils;
|
package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
|
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import org.apache.http.client.utils.URIBuilder;
|
import redis.clients.jedis.Jedis;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class TOTPUtils {
|
public class TOTPUtils {
|
||||||
@ -23,18 +25,40 @@ public class TOTPUtils {
|
|||||||
|
|
||||||
public static String getQRCodeURL(User user, GoogleAuthenticatorKey key) {
|
public static String getQRCodeURL(User user, GoogleAuthenticatorKey key) {
|
||||||
return GoogleAuthenticatorQRGenerator.getOtpAuthURL(
|
return GoogleAuthenticatorQRGenerator.getOtpAuthURL(
|
||||||
"MineHQ v3",
|
"MineHQ Network",
|
||||||
user.getLastUsername(),
|
user.getLastUsername(),
|
||||||
key
|
key
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean wasRecentlyUsed(User user, int code) {
|
public static boolean isPreAuthorized(User user, String ip) {
|
||||||
|
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||||
|
return redis.exists(user.getId() + ":preAuthorizedIP:" + ip.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void markPreAuthorized(User user, String ip, long duration, TimeUnit unit) {
|
||||||
|
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||||
|
String key = user.getId() + ":preAuthorizedIP:" + ip.toLowerCase();
|
||||||
|
|
||||||
|
redis.set(key, "");
|
||||||
|
redis.expire(key, (int) unit.toSeconds(duration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean wasRecentlyUsed(User user, int code) {
|
||||||
|
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||||
|
return redis.exists(user.getId() + ":recentTOTPCodes:" + code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void markRecentlyUsed(User user, int code) {
|
public static void markRecentlyUsed(User user, int code) {
|
||||||
|
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||||
|
String key = user.getId() + ":recentTOTPCodes:" + code;
|
||||||
|
|
||||||
|
redis.set(key, "");
|
||||||
|
redis.expire(key, (int) TimeUnit.MINUTES.toSeconds(5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user