diff --git a/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java b/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java index 6dad953..c4853ed 100644 --- a/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java +++ b/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java @@ -2,22 +2,31 @@ package net.frozenorb.apiv3.auditLog; import com.google.common.collect.ImmutableMap; import com.mongodb.async.SingleResultCallback; +import io.vertx.ext.web.RoutingContext; import lombok.experimental.UtilityClass; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.model.AuditLogEntry; -import net.frozenorb.apiv3.model.User; import java.util.Map; +import java.util.UUID; @UtilityClass public class AuditLog { - public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, SingleResultCallback callback) { - log(performedBy, performedByIp, actor, actionType, ImmutableMap.of(), callback); + public static void log(UUID performedBy, String performedByIp, RoutingContext ctx, AuditLogActionType actionType, SingleResultCallback callback) { + log(performedBy, performedByIp, ctx.get("actor"), ctx.request().remoteAddress().host(), actionType, ImmutableMap.of(), callback); } - public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map actionData, SingleResultCallback callback) { - AuditLogEntry entry = new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData); + public static void log(UUID performedBy, String performedByIp, RoutingContext ctx, AuditLogActionType actionType, Map actionData, SingleResultCallback callback) { + log(performedBy, performedByIp, ctx.get("actor"), ctx.request().remoteAddress().host(), actionType, actionData, callback); + } + + public static void log(UUID performedBy, String performedByIp, Actor actor, String actorIp, AuditLogActionType actionType, SingleResultCallback callback) { + log(performedBy, performedByIp, actor, actorIp, actionType, ImmutableMap.of(), callback); + } + + public static void log(UUID performedBy, String performedByIp, Actor actor, String actorIp, AuditLogActionType actionType, Map actionData, SingleResultCallback callback) { + AuditLogEntry entry = new AuditLogEntry(performedBy, performedByIp, actor,actorIp, actionType, actionData); entry.insert((ignored, error) -> { if (error != null) { callback.onResult(null, error); diff --git a/src/main/java/net/frozenorb/apiv3/auditLog/AuditLogActionType.java b/src/main/java/net/frozenorb/apiv3/auditLog/AuditLogActionType.java index c8f2d4e..60cddc7 100644 --- a/src/main/java/net/frozenorb/apiv3/auditLog/AuditLogActionType.java +++ b/src/main/java/net/frozenorb/apiv3/auditLog/AuditLogActionType.java @@ -1,26 +1,49 @@ package net.frozenorb.apiv3.auditLog; import com.mongodb.async.SingleResultCallback; +import lombok.Getter; import net.frozenorb.apiv3.model.AuditLogEntry; public enum AuditLogActionType { - DELETE_PUNISHMENT { + BANNED_ASN_CREATE(false), + BANNED_ASN_UPDATE(false), + BANNED_ASN_DELETE(false), + BANNED_CALL_CARRIER_CREATE(false), + BANNED_CALL_CARRIER_UPDATE(false), + BANNED_CALL_CARRIER_DELETE(false), + GRANT_CREATE(false), + GRANT_UPDATE(false), + GRANT_DELETE(false), + IP_BAN_CREATE(false), + IP_BAN_UPDATE(false), + IP_BAN_DELETE(false), + NOTIFICATION_TEMPLATE_CREATE(false), + NOTIFICATION_TEMPLATE_UPDATE(false), + NOTIFICATION_TEMPLATE_DELETE(false), + PUNISHMENT_CREATE(false), + PUNISHMENT_UPDATE(false), + PUNISHMENT_DELETE(false), + RANK_CREATE(false), + RANK_UPDATE(false), + RANK_DELETE(false), + SERVER_GROUP_CREATE(false), + SERVER_GROUP_UPDATE(false), + SERVER_GROUP_DELETE(false), + SERVER_CREATE(false), + SERVER_UPDATE(false), + SERVER_DELETE(false), + USER_CHANGE_PASSWORD(false), + USER_PASSWORD_RESET(false), + USER_REGISTER(false), + USER_SETUP_TOTP(false), + USER_VERIFY_TOTP(false); - @Override - public void revert(AuditLogEntry entry, SingleResultCallback callback) { - callback.onResult(false, null); - } + @Getter private boolean reversible; - }, - DELETE_GRANT { - - @Override - public void revert(AuditLogEntry entry, SingleResultCallback callback) { - callback.onResult(false, null); - } - - }; + AuditLogActionType(boolean reversible) { + this.reversible = reversible; + } public void revert(AuditLogEntry entry, SingleResultCallback callback) { callback.onResult(null, new UnsupportedOperationException()); diff --git a/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java b/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java index 1f1ceb7..ad5806d 100644 --- a/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/model/AuditLogEntry.java @@ -30,6 +30,10 @@ public final class AuditLogEntry { @Getter private Instant performedAt; @Getter private String actorName; @Getter private ActorType actorType; + @Getter private String actorIp; + // We store 'reversible' in each object in case later on we go back and + // make something reversible (by storing more meta or such) + @Getter private boolean reversible; @Getter private AuditLogActionType type; @Getter private Map metadata; @@ -43,13 +47,15 @@ public final class AuditLogEntry { private AuditLogEntry() {} // For Jackson - public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map metadata) { + public AuditLogEntry(UUID user, String userIp, Actor actor, String actorIp, AuditLogActionType type, Map metadata) { this.id = new ObjectId().toString(); - this.user = user.getId(); + this.user = user; this.userIp = userIp; this.performedAt = Instant.now(); this.actorName = actor.getName(); this.actorType = actor.getType(); + this.actorIp = actorIp; + this.reversible = type.isReversible(); this.type = type; this.metadata = ImmutableMap.copyOf(metadata); } diff --git a/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java b/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java index 97d9960..f6948ba 100644 --- a/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java +++ b/src/main/java/net/frozenorb/apiv3/route/auditLog/POSTAuditLog.java @@ -18,33 +18,37 @@ public final class POSTAuditLog implements Handler { User.findById(requestBody.getString("user"), (user, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); - } else if (user == null) { - ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user")); - } else { - String userIp = requestBody.getString("userIp"); - - if (!IpUtils.isValidIp(userIp)) { - ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); - return; - } - - AuditLogActionType type; - - try { - type = AuditLogActionType.valueOf(requestBody.getString("type")); - } catch (IllegalArgumentException ignored) { - ErrorUtils.respondNotFound(ctx, "Audit log action type", requestBody.getString("type")); - return; - } - - AuditLog.log(user, userIp, ctx.get("actor"), type, ctx.getBodyAsJson().getMap(), (auditLogEntry, error2) -> { - if (error2 != null) { - ErrorUtils.respondInternalError(ctx, error2); - } else { - APIv3.respondJson(ctx, auditLogEntry); - } - }); + return; } + + if (user == null) { + ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user")); + return; + } + + String userIp = requestBody.getString("userIp"); + + if (!IpUtils.isValidIp(userIp)) { + ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); + return; + } + + AuditLogActionType type; + + try { + type = AuditLogActionType.valueOf(requestBody.getString("type")); + } catch (IllegalArgumentException ignored) { + ErrorUtils.respondNotFound(ctx, "Audit log action type", requestBody.getString("type")); + return; + } + + AuditLog.log(user.getId(), userIp, ctx, type, requestBody.getJsonObject("metadata").getMap(), (auditLogEntry, error2) -> { + if (error2 != null) { + ErrorUtils.respondInternalError(ctx, error2); + } else { + APIv3.respondJson(ctx, auditLogEntry); + } + }); }); } diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java b/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java index 0c2c537..1d0f199 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/DELETEGrantsId.java @@ -49,10 +49,14 @@ public final class DELETEGrantsId implements Handler { BlockingCallback callback = new BlockingCallback<>(); grant.delete(removedBy, reason, callback); callback.get(); - BlockingCallback blockingCallback = new BlockingCallback<>(); - AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of(), blockingCallback); - blockingCallback.get(); - APIv3.respondJson(ctx, grant); + + AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.GRANT_DELETE,ImmutableMap.of("grantId", grant.getId()), (ignored, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, grant); + } + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java b/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java index 5775eef..308367c 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java @@ -1,9 +1,12 @@ package net.frozenorb.apiv3.route.grants; +import com.google.common.collect.ImmutableMap; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.auditLog.AuditLog; +import net.frozenorb.apiv3.auditLog.AuditLogActionType; import net.frozenorb.apiv3.model.Grant; import net.frozenorb.apiv3.model.Rank; import net.frozenorb.apiv3.model.ServerGroup; @@ -79,7 +82,18 @@ public final class POSTGrants implements Handler { BlockingCallback callback = new BlockingCallback<>(); grant.insert(callback); callback.get(); - APIv3.respondJson(ctx, grant); + + if (addedBy != null) { + AuditLog.log(addedBy.getId(), requestBody.getString("addedByIp"), ctx, AuditLogActionType.GRANT_CREATE, ImmutableMap.of("grantId", grant.getId()), (ignored, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, grant); + } + }); + } else { + APIv3.respondJson(ctx, grant); + } } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBansId.java b/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBansId.java index d02462f..4024ed2 100644 --- a/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBansId.java +++ b/src/main/java/net/frozenorb/apiv3/route/ipBans/DELETEIpBansId.java @@ -50,7 +50,7 @@ public final class DELETEIpBansId implements Handler { ipBan.delete(removedBy, reason, callback); callback.get(); BlockingCallback blockingCallback = new BlockingCallback<>(); - AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback); + AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.IP_BAN_DELETE, ImmutableMap.of("punishmentId", ipBan.getId()), blockingCallback); blockingCallback.get(); APIv3.respondJson(ctx, ipBan); } diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishmentsId.java b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishmentsId.java index f9b64b2..358ccca 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishmentsId.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEPunishmentsId.java @@ -50,7 +50,7 @@ public final class DELETEPunishmentsId implements Handler { punishment.delete(removedBy, reason, removeCallback); removeCallback.get(); BlockingCallback blockingCallback = new BlockingCallback<>(); - AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback); + AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.PUNISHMENT_DELETE, ImmutableMap.of("punishmentId", punishment.getId()), blockingCallback); blockingCallback.get(); APIv3.respondJson(ctx, punishment); } diff --git a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUsersIdActivePunishment.java b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUsersIdActivePunishment.java index aac25d5..4837f61 100644 --- a/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUsersIdActivePunishment.java +++ b/src/main/java/net/frozenorb/apiv3/route/punishments/DELETEUsersIdActivePunishment.java @@ -50,21 +50,29 @@ public final class DELETEUsersIdActivePunishment implements Handler> callback = new BlockingCallback<>(); Punishment.findByUserAndType(target, ImmutableSet.of(type), callback); + Punishment activePunishment = null; for (Punishment punishment : callback.get()) { if (punishment.isActive()) { - BlockingCallback punishmentCallback = new BlockingCallback<>(); - punishment.delete(removedBy, reason, punishmentCallback); - punishmentCallback.get(); - BlockingCallback blockingCallback = new BlockingCallback<>(); - AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback); - blockingCallback.get(); - APIv3.respondJson(ctx, punishment); - return; + activePunishment = punishment; + break; } } - ErrorUtils.respondGeneric(ctx, 404, "User provided has no active punishments"); + if (activePunishment == null) { + ErrorUtils.respondGeneric(ctx, 404, "User provided has no active punishments"); + return; + } + + BlockingCallback punishmentCallback = new BlockingCallback<>(); + activePunishment.delete(removedBy, reason, punishmentCallback); + punishmentCallback.get(); + + BlockingCallback blockingCallback = new BlockingCallback<>(); + AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.PUNISHMENT_DELETE, ImmutableMap.of("punishmentId", activePunishment.getId()), blockingCallback); + blockingCallback.get(); + + APIv3.respondJson(ctx, activePunishment); } } \ No newline at end of file