More stuff
This commit is contained in:
parent
4b49c5bafe
commit
d062ab5718
@ -1,15 +1,15 @@
|
|||||||
general.releaseStage=production
|
general.releaseStage=production
|
||||||
logging.level=info
|
logging.level=info
|
||||||
mongo.address=ds055505.mongolab.com
|
mongo.address=209.222.96.50
|
||||||
mongo.port=55505
|
mongo.port=27017
|
||||||
mongo.database=minehqapi
|
mongo.database=minehqapi
|
||||||
mongo.username=test
|
mongo.username=
|
||||||
mongo.password=test
|
mongo.password=
|
||||||
redis.address=localhost
|
redis.address=localhost
|
||||||
redis.port=6379
|
redis.port=6379
|
||||||
http.address=0.0.0.0
|
http.address=0.0.0.0
|
||||||
http.port=80
|
http.port=80
|
||||||
http.workerThreads=6
|
http.workerThreads=
|
||||||
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
||||||
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
||||||
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
||||||
|
10
pom.xml
10
pom.xml
@ -133,6 +133,16 @@
|
|||||||
<artifactId>googleauth</artifactId>
|
<artifactId>googleauth</artifactId>
|
||||||
<version>0.5.0</version>
|
<version>0.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okio</groupId>
|
||||||
|
<artifactId>okio</artifactId>
|
||||||
|
<version>1.8.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package net.frozenorb.apiv3;
|
package net.frozenorb.apiv3;
|
||||||
|
|
||||||
import com.bugsnag.Client;
|
import com.bugsnag.Client;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.mongodb.MongoClient;
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
import com.mongodb.ServerAddress;
|
import com.mongodb.ServerAddress;
|
||||||
import com.timgroup.statsd.NonBlockingStatsDClient;
|
import com.timgroup.statsd.NonBlockingStatsDClient;
|
||||||
import com.timgroup.statsd.StatsDClient;
|
import com.timgroup.statsd.StatsDClient;
|
||||||
@ -37,6 +39,7 @@ import net.frozenorb.apiv3.routes.users.*;
|
|||||||
import net.frozenorb.apiv3.serialization.DateTypeAdapter;
|
import net.frozenorb.apiv3.serialization.DateTypeAdapter;
|
||||||
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.BugsnagSLF4jLogger;
|
||||||
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.Datastore;
|
import org.mongodb.morphia.Datastore;
|
||||||
@ -77,6 +80,8 @@ public final class APIv3 {
|
|||||||
setupMetrics();
|
setupMetrics();
|
||||||
setupBugsnag();
|
setupBugsnag();
|
||||||
setupHttp();
|
setupHttp();
|
||||||
|
|
||||||
|
LoggingFilter.setDebug(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupConfig() {
|
private void setupConfig() {
|
||||||
@ -88,17 +93,21 @@ public final class APIv3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupDatabase() {
|
private void setupDatabase() {
|
||||||
MongoClient mongoClient = new MongoClient(new ServerAddress(
|
ImmutableList<MongoCredential> credentials = ImmutableList.of();
|
||||||
config.getProperty("mongo.address"),
|
|
||||||
Integer.parseInt(config.getProperty("mongo.port")))/*,
|
if (!config.getProperty("mongo.username").isEmpty()) {
|
||||||
ImmutableList.of(
|
credentials = ImmutableList.of(MongoCredential.createCredential(
|
||||||
MongoCredential.createCredential(
|
|
||||||
config.getProperty("mongo.username"),
|
config.getProperty("mongo.username"),
|
||||||
config.getProperty("mongo.database"),
|
config.getProperty("mongo.database"),
|
||||||
config.getProperty("mongo.password").toCharArray())
|
config.getProperty("mongo.password").toCharArray()
|
||||||
)*/);
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: DISABLE CREDS IF NOT NEEDED
|
MongoClient mongoClient = new MongoClient(new ServerAddress(
|
||||||
|
config.getProperty("mongo.address"),
|
||||||
|
Integer.parseInt(config.getProperty("mongo.port"))),
|
||||||
|
credentials
|
||||||
|
);
|
||||||
|
|
||||||
MorphiaLoggerFactory.reset();
|
MorphiaLoggerFactory.reset();
|
||||||
MorphiaLoggerFactory.registerLogger(SLF4JLoggerImplFactory.class);
|
MorphiaLoggerFactory.registerLogger(SLF4JLoggerImplFactory.class);
|
||||||
@ -120,7 +129,7 @@ public final class APIv3 {
|
|||||||
private void setupMetrics() {
|
private void setupMetrics() {
|
||||||
statsD = new NonBlockingStatsDClient(null, "localhost", 8125);
|
statsD = new NonBlockingStatsDClient(null, "localhost", 8125);
|
||||||
|
|
||||||
new Timer("Librato Post Task").scheduleAtFixedRate(new TimerTask() {
|
new Timer("Metrics Task").scheduleAtFixedRate(new TimerTask() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -135,15 +144,18 @@ public final class APIv3 {
|
|||||||
Client bugsnag = new Client(config.getProperty("bugsnag.apiKey"));
|
Client bugsnag = new Client(config.getProperty("bugsnag.apiKey"));
|
||||||
bugsnag.setReleaseStage(config.getProperty("general.releaseStage"));
|
bugsnag.setReleaseStage(config.getProperty("general.releaseStage"));
|
||||||
bugsnag.setProjectPackages("net.frozenorb.apiv3");
|
bugsnag.setProjectPackages("net.frozenorb.apiv3");
|
||||||
|
bugsnag.setLogger(new BugsnagSLF4jLogger());
|
||||||
// TODO: Use .setLogger to use slf4j with this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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")));
|
||||||
// TODO: if threadPool == null use default value
|
String workerThreads = config.getProperty("http.workerThreads");
|
||||||
threadPool(Integer.parseInt(config.getProperty("http.workerThreads")));
|
|
||||||
|
if (!workerThreads.isEmpty()) {
|
||||||
|
threadPool(Integer.parseInt(workerThreads));
|
||||||
|
}
|
||||||
|
|
||||||
before(new ContentTypeFilter());
|
before(new ContentTypeFilter());
|
||||||
before(new ActorAttributeFilter());
|
before(new ActorAttributeFilter());
|
||||||
before(new AuthorizationFilter());
|
before(new AuthorizationFilter());
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package net.frozenorb.apiv3.actors;
|
package net.frozenorb.apiv3.actors;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
|
|
||||||
public final class ServerActor implements Actor {
|
public final class ServerActor implements Actor {
|
||||||
|
|
||||||
private final Server server;
|
@Getter private final Server server;
|
||||||
|
|
||||||
public ServerActor(Server server) {
|
public ServerActor(Server server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.actors;
|
package net.frozenorb.apiv3.actors;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ public final class UserActor implements Actor {
|
|||||||
|
|
||||||
private static final Set<String> authorizedUserGrants = ImmutableSet.copyOf(APIv3.getConfig().getProperty("auth.permittedUserRanks").split(","));
|
private static final Set<String> authorizedUserGrants = ImmutableSet.copyOf(APIv3.getConfig().getProperty("auth.permittedUserRanks").split(","));
|
||||||
|
|
||||||
private final User user;
|
@Getter private final User user;
|
||||||
// We use Boolean here so we can have null = not calculated;
|
// We use Boolean here so we can have null = not calculated;
|
||||||
private Boolean cachedAuthorized = null;
|
private Boolean cachedAuthorized = null;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import spark.Response;
|
|||||||
public final class ContentTypeFilter implements Filter {
|
public final class ContentTypeFilter implements Filter {
|
||||||
|
|
||||||
public void handle(Request req, Response res) {
|
public void handle(Request req, Response res) {
|
||||||
res.header("content-type", "application/json");
|
res.header("Content-Type", "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.filters;
|
package net.frozenorb.apiv3.filters;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import spark.Filter;
|
import spark.Filter;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
@ -8,12 +10,14 @@ import spark.Response;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public final class LoggingFilter implements Filter {
|
public final class LoggingFilter implements Filter {
|
||||||
|
|
||||||
public void handle(Request req, Response res) {
|
@Getter @Setter private static boolean debug = false;
|
||||||
if (req.url().toLowerCase().contains("password=")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public void handle(Request req, Response res) {
|
||||||
|
if (debug) {
|
||||||
|
log.info(req.requestMethod().toUpperCase() + " " + req.url() + "\n" + res.body());
|
||||||
|
} else {
|
||||||
log.info(req.requestMethod().toUpperCase() + " " + req.url());
|
log.info(req.requestMethod().toUpperCase() + " " + req.url());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ import org.mongodb.morphia.annotations.Id;
|
|||||||
import org.mongodb.morphia.annotations.Indexed;
|
import org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity(value = "punishments", noClassnameStored = true)
|
@Entity(value = "punishments", noClassnameStored = true)
|
||||||
@ -21,6 +22,7 @@ public final class Punishment {
|
|||||||
@Getter private String reason;
|
@Getter private String reason;
|
||||||
@Getter @Indexed private PunishmentType type; // Type is indexed for the rank dump
|
@Getter @Indexed private PunishmentType type; // Type is indexed for the rank dump
|
||||||
@Getter private Date expiresAt;
|
@Getter private Date expiresAt;
|
||||||
|
@Getter private Map<String, Object> meta;
|
||||||
|
|
||||||
@Getter private UUID addedBy;
|
@Getter private UUID addedBy;
|
||||||
@Getter @Indexed private Date addedAt;
|
@Getter @Indexed private Date addedAt;
|
||||||
@ -37,7 +39,7 @@ public final class Punishment {
|
|||||||
|
|
||||||
public Punishment() {} // For Morphia
|
public Punishment() {} // For Morphia
|
||||||
|
|
||||||
public Punishment(User target, String reason, PunishmentType type, Date expiresAt, User addedBy, Actor actor) {
|
public Punishment(User target, String reason, PunishmentType type, Date expiresAt, User addedBy, Actor actor, Map<String, Object> meta) {
|
||||||
this.id = new ObjectId().toString();
|
this.id = new ObjectId().toString();
|
||||||
this.target = target.getId();
|
this.target = target.getId();
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
@ -47,6 +49,7 @@ public final class Punishment {
|
|||||||
this.addedAt = new Date();
|
this.addedAt = new Date();
|
||||||
this.actorName = actor.getName();
|
this.actorName = actor.getName();
|
||||||
this.actorType = actor.getType();
|
this.actorType = actor.getType();
|
||||||
|
this.meta = meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(User removedBy, String reason) {
|
public void delete(User removedBy, String reason) {
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import lombok.Getter;
|
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 org.mongodb.morphia.annotations.Indexed;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Entity(value = "ranks", noClassnameStored = true)
|
@Entity(value = "ranks", noClassnameStored = true)
|
||||||
public final class Rank {
|
public final class Rank {
|
||||||
|
|
||||||
|
private static Map<String, Rank> rankCache = null;
|
||||||
|
private static long rankCacheUpdated = 0;
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private int weight;
|
@Getter private int weight;
|
||||||
@Getter private String displayName;
|
@Getter private String displayName;
|
||||||
@ -19,11 +26,12 @@ public final class Rank {
|
|||||||
@Getter @Indexed 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();
|
updateCacheIfNeeded();
|
||||||
|
return rankCache.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Rank> values() {
|
public static List<Rank> values() {
|
||||||
return APIv3.getDatastore().createQuery(Rank.class).order("weight").asList();
|
return ImmutableList.copyOf(rankCache.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rank() {} // For Morphia
|
public Rank() {} // For Morphia
|
||||||
@ -41,4 +49,17 @@ public final class Rank {
|
|||||||
APIv3.getDatastore().delete(this);
|
APIv3.getDatastore().delete(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void updateCacheIfNeeded() {
|
||||||
|
if (rankCache == null || (System.currentTimeMillis() - rankCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
||||||
|
Map<String, Rank> working = new HashMap<>();
|
||||||
|
|
||||||
|
for (Rank rank : APIv3.getDatastore().createQuery(Rank.class).order("weight").asList()) {
|
||||||
|
working.put(rank.getId(), rank);
|
||||||
|
}
|
||||||
|
|
||||||
|
rankCache = working;
|
||||||
|
rankCacheUpdated = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import lombok.Getter;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||||
|
import net.frozenorb.apiv3.utils.MojangUtils;
|
||||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.mindrot.jbcrypt.BCrypt;
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
@ -57,7 +58,7 @@ public final class User {
|
|||||||
|
|
||||||
public User(UUID id, String lastUsername) {
|
public User(UUID id, String lastUsername) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.lastUsername = lastUsername;
|
this.lastUsername = ""; // Intentional, so updateUsername actually does something.
|
||||||
this.aliases = new HashMap<>();
|
this.aliases = new HashMap<>();
|
||||||
this.totpSecret = null;
|
this.totpSecret = null;
|
||||||
this.password = null;
|
this.password = null;
|
||||||
@ -67,7 +68,7 @@ public final class User {
|
|||||||
this.lastSeenAt = new Date();
|
this.lastSeenAt = new Date();
|
||||||
this.firstSeenAt = new Date();
|
this.firstSeenAt = new Date();
|
||||||
|
|
||||||
aliases.put(lastUsername, new Date());
|
updateUsername(lastUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPermissionScoped(String permission, ServerGroup scope) {
|
public boolean hasPermissionScoped(String permission, ServerGroup scope) {
|
||||||
@ -138,9 +139,23 @@ public final class User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void seenOnServer(String username, Server server) {
|
public void seenOnServer(Server server) {
|
||||||
this.lastSeenOn = server.getId();
|
this.lastSeenOn = server.getId();
|
||||||
this.lastSeenAt = new Date();
|
this.lastSeenAt = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUsername(String username) {
|
||||||
|
if (!username.equals(lastUsername)) {
|
||||||
|
this.lastUsername = username;
|
||||||
|
|
||||||
|
User withNewUsername;
|
||||||
|
|
||||||
|
while ((withNewUsername = User.byLastUsername(username)) != null) {
|
||||||
|
String newUsername = MojangUtils.getName(withNewUsername.getId());
|
||||||
|
withNewUsername.updateUsername(newUsername);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.aliases.put(username, new Date());
|
this.aliases.put(username, new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +172,7 @@ public final class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Rank getHighestRank(ServerGroup serverGroup) {
|
public Rank getHighestRank(ServerGroup serverGroup) {
|
||||||
Rank highest = null;;
|
Rank highest = null;
|
||||||
|
|
||||||
for (Grant grant : getGrants()) {
|
for (Grant grant : getGrants()) {
|
||||||
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
||||||
@ -205,51 +220,43 @@ public final class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getLoginInfo(Server server) {
|
public Map<String, Object> getLoginInfo(Server server) {
|
||||||
|
Punishment activeMute = null;
|
||||||
String accessDenialReason = null;
|
String accessDenialReason = null;
|
||||||
|
|
||||||
for (Punishment punishment : getPunishments(ImmutableSet.of(
|
for (Punishment punishment : getPunishments(ImmutableSet.of(
|
||||||
Punishment.PunishmentType.BLACKLIST,
|
Punishment.PunishmentType.BLACKLIST,
|
||||||
Punishment.PunishmentType.BAN
|
Punishment.PunishmentType.BAN,
|
||||||
|
Punishment.PunishmentType.MUTE
|
||||||
))) {
|
))) {
|
||||||
if (!punishment.isActive()) {
|
if (!punishment.isActive()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (punishment.getType() == Punishment.PunishmentType.MUTE) {
|
||||||
|
activeMute = punishment;
|
||||||
|
} else {
|
||||||
accessDenialReason = punishment.getAccessDenialReason();
|
accessDenialReason = punishment.getAccessDenialReason();
|
||||||
}
|
}
|
||||||
|
|
||||||
Punishment mute = null;
|
|
||||||
for (Punishment punishment : getPunishments(ImmutableSet.of(Punishment.PunishmentType.MUTE))) {
|
|
||||||
if (!punishment.isActive()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mute = punishment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerGroup actorGroup = ServerGroup.byId(server.getGroup());
|
ServerGroup actorGroup = ServerGroup.byId(server.getGroup());
|
||||||
Rank highestRank = getHighestRank(actorGroup);
|
Rank highestRank = getHighestRank(actorGroup);
|
||||||
|
|
||||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
// Generics are weird, yes we have to do this.
|
||||||
PermissionUtils.getDefaultPermissions(highestRank),
|
ImmutableMap.Builder<String, Object> result = ImmutableMap.<String, Object>builder()
|
||||||
actorGroup.calculatePermissions(highestRank)
|
.put("user", this)
|
||||||
);
|
.put("access", ImmutableMap.of(
|
||||||
|
|
||||||
Map<String, Object> loginInfo = Maps.newHashMap();
|
|
||||||
|
|
||||||
loginInfo.put("user", this);
|
|
||||||
loginInfo.put("access", ImmutableMap.of(
|
|
||||||
"allowed", accessDenialReason == null,
|
"allowed", accessDenialReason == null,
|
||||||
"message", accessDenialReason == null ? "Public server" : accessDenialReason
|
"message", accessDenialReason == null ? "Public server" : accessDenialReason
|
||||||
));
|
))
|
||||||
loginInfo.put("rank", highestRank.getId());
|
.put("rank", highestRank.getId())
|
||||||
loginInfo.put("permissions", scopedPermissions);
|
.put("totpSetup", getTotpSecret() != null);
|
||||||
loginInfo.put("totpSetup", getTotpSecret() != null);
|
|
||||||
if (mute != null) {
|
if (activeMute != null) {
|
||||||
loginInfo.put("mute", mute);
|
result.put("mute", activeMute);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loginInfo;
|
return result.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package net.frozenorb.apiv3.routes.announcements;
|
|||||||
|
|
||||||
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.actors.ServerActor;
|
||||||
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;
|
||||||
@ -18,7 +19,7 @@ public final class GETAnnouncements implements Route {
|
|||||||
return ErrorUtils.serverOnly();
|
return ErrorUtils.serverOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
Server sender = Server.byId(actor.getName());
|
Server sender = ((ServerActor) req.attribute("actor")).getServer();
|
||||||
ServerGroup senderGroup = ServerGroup.byId(sender.getGroup());
|
ServerGroup senderGroup = ServerGroup.byId(sender.getGroup());
|
||||||
|
|
||||||
return senderGroup.getAnnouncements();
|
return senderGroup.getAnnouncements();
|
||||||
|
@ -16,7 +16,7 @@ public final class GETAuditLog implements Route {
|
|||||||
|
|
||||||
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) {
|
} catch (NumberFormatException ex) {
|
||||||
return ErrorUtils.invalidInput(";imit and offset must be numerical inputs.");
|
return ErrorUtils.invalidInput("limit and offset must be numerical inputs.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ public final class DELETEGrant implements Route {
|
|||||||
}
|
}
|
||||||
|
|
||||||
grant.delete(removedBy, reason);
|
grant.delete(removedBy, reason);
|
||||||
// TODO: Fix IP
|
|
||||||
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of());
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of());
|
||||||
return grant;
|
return grant;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ public final class DELETEPunishment implements Route {
|
|||||||
}
|
}
|
||||||
|
|
||||||
punishment.delete(removedBy, reason);
|
punishment.delete(removedBy, reason);
|
||||||
// TODO: Fix IP
|
|
||||||
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
||||||
return punishment;
|
return punishment;
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,13 @@ 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;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public final class POSTUserPunish implements Route {
|
public final class POSTUserPunish implements Route {
|
||||||
|
|
||||||
@ -50,6 +52,12 @@ public final class POSTUserPunish implements Route {
|
|||||||
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Object> meta = Document.parse(req.body());
|
||||||
|
|
||||||
|
if (meta == null) {
|
||||||
|
return ErrorUtils.requiredInput("request body meta");
|
||||||
|
}
|
||||||
|
|
||||||
// We purposely don't do a null check, grants don't have to have a source.
|
// We purposely don't do a null check, grants don't have to have a source.
|
||||||
User addedBy = User.byId(req.queryParams("addedBy"));
|
User addedBy = User.byId(req.queryParams("addedBy"));
|
||||||
|
|
||||||
@ -57,12 +65,13 @@ public final class POSTUserPunish implements Route {
|
|||||||
return ErrorUtils.error(target.getLastSeenOn() + " is protected from punishments.");
|
return ErrorUtils.error(target.getLastSeenOn() + " is protected from punishments.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, req.attribute("actor"));
|
Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, req.attribute("actor"), meta);
|
||||||
|
String accessDenialReason = punishment.getAccessDenialReason();
|
||||||
APIv3.getDatastore().save(punishment);
|
APIv3.getDatastore().save(punishment);
|
||||||
|
|
||||||
return ImmutableMap.of(
|
return ImmutableMap.of(
|
||||||
"punishment", punishment,
|
"punishment", punishment,
|
||||||
"accessDenialReason", punishment.getAccessDenialReason() == null ? "" : punishment.getAccessDenialReason()
|
"accessDenialReason", accessDenialReason == null ? "" : accessDenialReason
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
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 lombok.extern.slf4j.Slf4j;
|
||||||
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.actors.ActorType;
|
import net.frozenorb.apiv3.actors.ActorType;
|
||||||
|
import net.frozenorb.apiv3.models.Rank;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
|
import net.frozenorb.apiv3.models.ServerGroup;
|
||||||
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.PermissionUtils;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
@ -14,6 +18,7 @@ import spark.Route;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public final class POSTServerHeartbeat implements Route {
|
public final class POSTServerHeartbeat implements Route {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -25,6 +30,7 @@ public final class POSTServerHeartbeat implements Route {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Server actorServer = Server.byId(actor.getName());
|
Server actorServer = Server.byId(actor.getName());
|
||||||
|
ServerGroup actorServerGroup = ServerGroup.byId(actorServer.getGroup());
|
||||||
Document reqJson = Document.parse(req.body());
|
Document reqJson = Document.parse(req.body());
|
||||||
Set<UUID> onlinePlayers = new HashSet<>();
|
Set<UUID> onlinePlayers = new HashSet<>();
|
||||||
Map<String, Object> playersResponse = new HashMap<>();
|
Map<String, Object> playersResponse = new HashMap<>();
|
||||||
@ -39,7 +45,7 @@ public final class POSTServerHeartbeat implements Route {
|
|||||||
user = new User(UUID.fromString(playerJson.getString("uuid")), username);
|
user = new User(UUID.fromString(playerJson.getString("uuid")), username);
|
||||||
}
|
}
|
||||||
|
|
||||||
user.seenOnServer(username, actorServer);
|
user.seenOnServer(actorServer);
|
||||||
APIv3.getDatastore().save(user);
|
APIv3.getDatastore().save(user);
|
||||||
|
|
||||||
onlinePlayers.add(user.getId());
|
onlinePlayers.add(user.getId());
|
||||||
@ -58,17 +64,29 @@ public final class POSTServerHeartbeat implements Route {
|
|||||||
case "metrics":
|
case "metrics":
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.err.println("Recieved event with unknown type " + type + ".");
|
log.warn("Recieved event with unknown type " + type + ".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Map<String, Boolean>> permissions = new HashMap<>();
|
||||||
|
|
||||||
|
for (Rank rank : Rank.values()) {
|
||||||
|
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||||
|
PermissionUtils.getDefaultPermissions(rank),
|
||||||
|
actorServerGroup.calculatePermissions(rank)
|
||||||
|
);
|
||||||
|
|
||||||
|
permissions.put(rank.getId(), scopedPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
actorServer.setPlayers(onlinePlayers);
|
actorServer.setPlayers(onlinePlayers);
|
||||||
actorServer.setLastTps(reqJson.getDouble("lastTps"));
|
actorServer.setLastTps(reqJson.getDouble("lastTps"));
|
||||||
actorServer.setLastUpdate(new Date());
|
actorServer.setLastUpdate(new Date());
|
||||||
APIv3.getDatastore().save(actorServer);
|
APIv3.getDatastore().save(actorServer);
|
||||||
|
|
||||||
return ImmutableMap.of(
|
return ImmutableMap.of(
|
||||||
"players", playersResponse
|
"players", playersResponse,
|
||||||
|
"permissions", permissions
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ public final class DELETEUserPunishment implements Route {
|
|||||||
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
||||||
if (punishment.isActive()) {
|
if (punishment.isActive()) {
|
||||||
punishment.delete(removedBy, reason);
|
punishment.delete(removedBy, reason);
|
||||||
// TODO: Fix IP
|
|
||||||
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
||||||
return punishment;
|
return punishment;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ public final class POSTUserLogin implements Route {
|
|||||||
Server actorServer = Server.byId(actor.getName());
|
Server actorServer = Server.byId(actor.getName());
|
||||||
|
|
||||||
user.getIPLogEntry(userIp).used();
|
user.getIPLogEntry(userIp).used();
|
||||||
|
user.updateUsername(username);
|
||||||
|
APIv3.getDatastore().save(user);
|
||||||
return user.getLoginInfo(actorServer);
|
return user.getLoginInfo(actorServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,11 @@ import java.util.Date;
|
|||||||
public final class DateTypeAdapter extends TypeAdapter<Date> {
|
public final class DateTypeAdapter extends TypeAdapter<Date> {
|
||||||
|
|
||||||
public void write(JsonWriter writer, Date write) throws IOException {
|
public void write(JsonWriter writer, Date write) throws IOException {
|
||||||
writer.value(write == null ? -1 : write.getTime());
|
if (write == null) {
|
||||||
|
writer.value(-1);
|
||||||
|
} else {
|
||||||
|
writer.value(write.getTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used with Gson, which is only used
|
// This is used with Gson, which is only used
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package net.frozenorb.apiv3.unsorted;
|
||||||
|
|
||||||
|
import com.bugsnag.Logger;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class BugsnagSLF4jLogger extends Logger {
|
||||||
|
|
||||||
|
public void debug(String message) {
|
||||||
|
log.debug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void info(String message) {
|
||||||
|
log.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warn(String message) {
|
||||||
|
log.warn(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warn(String message, Throwable ex) {
|
||||||
|
log.warn(message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warn(Throwable ex) {
|
||||||
|
log.warn("error in bugsnag", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
src/main/java/net/frozenorb/apiv3/utils/MojangUtils.java
Normal file
39
src/main/java/net/frozenorb/apiv3/utils/MojangUtils.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.bson.Document;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class MojangUtils {
|
||||||
|
|
||||||
|
private static OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
|
||||||
|
public static String getName(UUID id) {
|
||||||
|
Request.Builder builder = new Request.Builder();
|
||||||
|
|
||||||
|
builder.get();
|
||||||
|
builder.url("https://sessionserver.mojang.com/session/minecraft/profile/" + id.toString().replace("-", ""));
|
||||||
|
|
||||||
|
try {
|
||||||
|
Response response = okHttpClient.newCall(builder.build()).execute();
|
||||||
|
Document resJson = Document.parse(response.body().string());
|
||||||
|
|
||||||
|
String name = resJson.getString("name");
|
||||||
|
|
||||||
|
if (name == null) {
|
||||||
|
throw new RuntimeException("Hit Mojang API rate limit");
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user