More stuff
This commit is contained in:
parent
27d139f0f6
commit
53c7222107
@ -1,3 +1,5 @@
|
|||||||
|
general.id=main
|
||||||
|
general.releaseStage=production
|
||||||
mongo.address=ds055505.mongolab.com
|
mongo.address=ds055505.mongolab.com
|
||||||
mongo.port=55505
|
mongo.port=55505
|
||||||
mongo.database=minehqapi
|
mongo.database=minehqapi
|
||||||
@ -5,11 +7,14 @@ mongo.username=test
|
|||||||
mongo.password=test
|
mongo.password=test
|
||||||
redis.address=localhost
|
redis.address=localhost
|
||||||
redis.port=6379
|
redis.port=6379
|
||||||
http.address=
|
http.address=0.0.0.0
|
||||||
http.port=80
|
http.port=80
|
||||||
http.workerThreads=6
|
http.workerThreads=6
|
||||||
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
||||||
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
||||||
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
||||||
|
librato.email=cmcdonald.main@gmail.com
|
||||||
|
librato.apiKey=a818c3eca8a59d6d9cf76dc9f0d237c6aa97f257c482ce3363cf55a5431bc153
|
||||||
|
bugsnag.apiKey=
|
||||||
auth.permittedUserRanks=developer,owner
|
auth.permittedUserRanks=developer,owner
|
||||||
auth.websiteApiKey=RVbp4hY6sCFVaf
|
auth.websiteApiKey=RVbp4hY6sCFVaf
|
@ -1,17 +1,17 @@
|
|||||||
package net.frozenorb.apiv3;
|
package net.frozenorb.apiv3;
|
||||||
|
|
||||||
|
import com.bugsnag.Client;
|
||||||
|
import com.codahale.metrics.Gauge;
|
||||||
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.librato.metrics.LibratoReporter;
|
||||||
import com.mongodb.MongoClient;
|
import com.mongodb.MongoClient;
|
||||||
import com.mongodb.MongoCredential;
|
import com.mongodb.MongoCredential;
|
||||||
import com.mongodb.ServerAddress;
|
import com.mongodb.ServerAddress;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.filters.ActorAttributeFilter;
|
import net.frozenorb.apiv3.filters.*;
|
||||||
import net.frozenorb.apiv3.filters.AuthorizationFilter;
|
|
||||||
import net.frozenorb.apiv3.filters.ContentTypeFilter;
|
|
||||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
|
||||||
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;
|
||||||
@ -41,7 +41,6 @@ import net.frozenorb.apiv3.routes.users.*;
|
|||||||
import net.frozenorb.apiv3.serialization.FollowAnnotationExclusionStrategy;
|
import net.frozenorb.apiv3.serialization.FollowAnnotationExclusionStrategy;
|
||||||
import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
||||||
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
||||||
import net.frozenorb.apiv3.unsorted.Notification;
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.Datastore;
|
import org.mongodb.morphia.Datastore;
|
||||||
import org.mongodb.morphia.Morphia;
|
import org.mongodb.morphia.Morphia;
|
||||||
@ -52,6 +51,7 @@ import redis.clients.jedis.JedisPool;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static spark.Spark.*;
|
import static spark.Spark.*;
|
||||||
|
|
||||||
@ -60,6 +60,8 @@ 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 JedisPool redisPool;
|
||||||
|
@Getter private static MetricRegistry metrics = new MetricRegistry();
|
||||||
|
@Getter private static Client bugsnagClient;
|
||||||
@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())
|
||||||
@ -71,6 +73,8 @@ public final class APIv3 {
|
|||||||
setupConfig();
|
setupConfig();
|
||||||
setupDatabase();
|
setupDatabase();
|
||||||
setupRedis();
|
setupRedis();
|
||||||
|
setupMetrics();
|
||||||
|
setupBugsnag();
|
||||||
setupHttp();
|
setupHttp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +114,30 @@ public final class APIv3 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupMetrics() {
|
||||||
|
Gauge memoryUsageGauge = () -> Runtime.getRuntime().totalMemory() / (1024 * 1024);
|
||||||
|
Gauge memoryMaxGauge = () -> Runtime.getRuntime().maxMemory() / (1024 * 1024);
|
||||||
|
|
||||||
|
metrics.register(MetricRegistry.name("apiv3", "memory", "usage"), memoryUsageGauge);
|
||||||
|
metrics.register(MetricRegistry.name("apiv3", "memory", "max"), memoryMaxGauge);
|
||||||
|
|
||||||
|
LibratoReporter.enable(
|
||||||
|
LibratoReporter.builder(
|
||||||
|
metrics,
|
||||||
|
config.getProperty("librato.email"),
|
||||||
|
config.getProperty("librato.apiKey"),
|
||||||
|
config.getProperty("general.id")
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
TimeUnit.MINUTES
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupBugsnag() {
|
||||||
|
bugsnagClient = new Client(config.getProperty("bugsnag.apiKey"));
|
||||||
|
bugsnagClient.setReleaseStage(config.getProperty("general.releaseStage"));
|
||||||
|
}
|
||||||
|
|
||||||
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")));
|
||||||
@ -117,6 +145,8 @@ public final class APIv3 {
|
|||||||
before(new ContentTypeFilter());
|
before(new ContentTypeFilter());
|
||||||
before(new ActorAttributeFilter());
|
before(new ActorAttributeFilter());
|
||||||
before(new AuthorizationFilter());
|
before(new AuthorizationFilter());
|
||||||
|
before(new MetricsBeforeFilter());
|
||||||
|
after(new MetricsAfterFilter());
|
||||||
exception(Exception.class, new LoggingExceptionHandler());
|
exception(Exception.class, new LoggingExceptionHandler());
|
||||||
|
|
||||||
// TODO: The commented out routes
|
// TODO: The commented out routes
|
||||||
|
@ -6,7 +6,6 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
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 java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
String mhqAuthHeader = req.headers("MHQ-Authorization");
|
String mhqAuthHeader = req.headers("MHQ-Authorization");
|
||||||
|
|
||||||
if (authHeader != null) {
|
if (authHeader != null) {
|
||||||
req.attribute("actor", processBasicAuthorization(authHeader));
|
req.attribute("actor", processBasicAuthorization(authHeader, res));
|
||||||
} else if (mhqAuthHeader != null) {
|
} else if (mhqAuthHeader != null) {
|
||||||
req.attribute("actor", processMHQAuthorization(mhqAuthHeader));
|
req.attribute("actor", processMHQAuthorization(mhqAuthHeader));
|
||||||
} else {
|
} else {
|
||||||
@ -27,7 +27,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // We purposely get the User by their last username.
|
@SuppressWarnings("deprecation") // We purposely get the User by their last username.
|
||||||
private Actor processBasicAuthorization(String authHeader) {
|
private Actor processBasicAuthorization(String authHeader, Response res) {
|
||||||
String encodedHeader = authHeader.substring("Basic ".length());
|
String encodedHeader = authHeader.substring("Basic ".length());
|
||||||
String[] credentials = Base64.base64Decode(encodedHeader).split(":");
|
String[] credentials = Base64.base64Decode(encodedHeader).split(":");
|
||||||
|
|
||||||
@ -40,6 +40,7 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.header("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
||||||
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize.")));
|
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize.")));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ public final class AuthorizationFilter implements Filter {
|
|||||||
Actor actor = req.attribute("actor");
|
Actor actor = req.attribute("actor");
|
||||||
|
|
||||||
if (!actor.isAuthorized()) {
|
if (!actor.isAuthorized()) {
|
||||||
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())));
|
res.header("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
||||||
|
Spark.halt(401, 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())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package net.frozenorb.apiv3.filters;
|
||||||
|
|
||||||
|
import com.codahale.metrics.Histogram;
|
||||||
|
import com.codahale.metrics.MetricRegistry;
|
||||||
|
import com.codahale.metrics.Timer;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import spark.Filter;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
public final class MetricsAfterFilter implements Filter {
|
||||||
|
|
||||||
|
private Histogram responseLengthMetric = APIv3.getMetrics().histogram(MetricRegistry.name("apiv3", "http", "responseLength"));
|
||||||
|
|
||||||
|
public void handle(Request req, Response res) {
|
||||||
|
responseLengthMetric.update(req.contentLength());
|
||||||
|
|
||||||
|
Timer.Context timerMetricActorType = req.attribute("timerMetric.actorType");
|
||||||
|
Timer.Context timerMetricGlobal = req.attribute("timerMetric.global");
|
||||||
|
|
||||||
|
timerMetricActorType.stop();
|
||||||
|
timerMetricGlobal.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package net.frozenorb.apiv3.filters;
|
||||||
|
|
||||||
|
import com.codahale.metrics.MetricRegistry;
|
||||||
|
import com.codahale.metrics.Timer;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
|
import spark.Filter;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
public final class MetricsBeforeFilter implements Filter {
|
||||||
|
|
||||||
|
private Timer responseTimesGlobalMetric = APIv3.getMetrics().timer(MetricRegistry.name(getClass(), "responseTimes", "global"));
|
||||||
|
|
||||||
|
public void handle(Request req, Response res) {
|
||||||
|
Actor actor = req.attribute("actor");
|
||||||
|
String metricName = MetricRegistry.name(getClass(), "responseTimes", actor.getType().name());
|
||||||
|
Timer responseTimesActorTypeMetric = APIv3.getMetrics().timer(metricName);
|
||||||
|
|
||||||
|
req.attribute("timerMetric.global", responseTimesGlobalMetric.time());
|
||||||
|
req.attribute("timerMetric.actorType", responseTimesActorTypeMetric.time());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,8 +3,6 @@ package net.frozenorb.apiv3.models;
|
|||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
|
||||||
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;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
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;
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package net.frozenorb.apiv3.routes.chatFilterList;
|
package net.frozenorb.apiv3.routes.chatFilterList;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
|
||||||
import net.frozenorb.apiv3.models.Server;
|
|
||||||
import net.frozenorb.apiv3.models.ServerGroup;
|
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
|
@ -7,7 +7,6 @@ import net.frozenorb.apiv3.models.Grant;
|
|||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
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 spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
|
@ -7,7 +7,6 @@ import net.frozenorb.apiv3.models.Punishment;
|
|||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
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 spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
|
@ -2,7 +2,6 @@ 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.models.Server;
|
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
@ -3,14 +3,10 @@ package net.frozenorb.apiv3.routes.users;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
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 net.frozenorb.apiv3.utils.TOTPUtils;
|
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
import spark.Route;
|
import spark.Route;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public final class GETUserVerifyPassword implements Route {
|
public final class GETUserVerifyPassword implements Route {
|
||||||
|
|
||||||
public Object handle(Request req, Response res) {
|
public Object handle(Request req, Response res) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.frozenorb.apiv3.unsorted;
|
package net.frozenorb.apiv3.unsorted;
|
||||||
|
|
||||||
|
import com.codahale.metrics.Timer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
@ -12,6 +13,12 @@ import spark.Response;
|
|||||||
public final class LoggingExceptionHandler implements ExceptionHandler {
|
public final class LoggingExceptionHandler implements ExceptionHandler {
|
||||||
|
|
||||||
public void handle(Exception ex, Request req, Response res) {
|
public void handle(Exception ex, Request req, Response res) {
|
||||||
|
Timer.Context timerMetricActorType = req.attribute("timerMetric.actorType");
|
||||||
|
Timer.Context timerMetricGlobal = req.attribute("timerMetric.global");
|
||||||
|
|
||||||
|
timerMetricActorType.stop();
|
||||||
|
timerMetricGlobal.stop();
|
||||||
|
|
||||||
String code = new ObjectId().toHexString();
|
String code = new ObjectId().toHexString();
|
||||||
|
|
||||||
log.error(code + ":", ex);
|
log.error(code + ":", ex);
|
||||||
|
@ -7,8 +7,6 @@ import com.cribbstechnologies.clients.mandrill.model.MandrillRecipient;
|
|||||||
import com.cribbstechnologies.clients.mandrill.request.MandrillMessagesRequest;
|
import com.cribbstechnologies.clients.mandrill.request.MandrillMessagesRequest;
|
||||||
import com.twilio.sdk.TwilioRestException;
|
import com.twilio.sdk.TwilioRestException;
|
||||||
import com.twilio.sdk.resource.factory.MessageFactory;
|
import com.twilio.sdk.resource.factory.MessageFactory;
|
||||||
import com.twilio.sdk.resource.instance.Message;
|
|
||||||
import net.frozenorb.apiv3.APIv3;
|
|
||||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||||
import net.frozenorb.apiv3.utils.MandrillUtils;
|
import net.frozenorb.apiv3.utils.MandrillUtils;
|
||||||
import net.frozenorb.apiv3.utils.TwillioUtils;
|
import net.frozenorb.apiv3.utils.TwillioUtils;
|
||||||
|
Loading…
Reference in New Issue
Block a user