diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java index 2a26b60..5cb0bdf 100644 --- a/src/main/java/net/frozenorb/apiv3/APIv3.java +++ b/src/main/java/net/frozenorb/apiv3/APIv3.java @@ -250,8 +250,8 @@ public final class APIv3 extends AbstractVerticle { // TODO: The commented out routes - http.get("/accessTokens/:id").handler(new GETAccessTokensId()); - http.get("/accessTokens").handler(new GETAccessTokens()); + http.get("/accessTokens/:id").blockingHandler(new GETAccessTokensId()); + http.get("/accessTokens").blockingHandler(new GETAccessTokens()); http.post("/accessTokens").blockingHandler(new POSTAccessTokens(), false); //http.put("/accessTokens/:id").blockingHandler(new PUTAccessTokensId(), false); http.delete("/accessTokens/:id").blockingHandler(new DELETEAccessTokensId(), false); diff --git a/src/main/java/net/frozenorb/apiv3/model/Rank.java b/src/main/java/net/frozenorb/apiv3/model/Rank.java index 51297cb..cbcb85c 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Rank.java +++ b/src/main/java/net/frozenorb/apiv3/model/Rank.java @@ -31,6 +31,7 @@ public final class Rank { @Getter private String gameColor; @Getter private String websiteColor; @Getter private boolean staffRank; + @Getter private boolean higherStaffRank; public static List findAll() { return ImmutableList.copyOf(rankCache); @@ -64,7 +65,7 @@ public final class Rank { private Rank() {} // For Jackson - public Rank(String id, String inheritsFromId, int weight, String displayName, String gameColor, String websiteColor, boolean staffRank) { + public Rank(String id, String inheritsFromId, int weight, String displayName, String gameColor, String websiteColor, boolean staffRank, boolean higherStaffRank) { this.id = id; this.inheritsFromId = inheritsFromId; this.weight = weight; @@ -72,6 +73,7 @@ public final class Rank { this.gameColor = gameColor; this.websiteColor = websiteColor; this.staffRank = staffRank; + this.higherStaffRank = higherStaffRank; } public void insert(SingleResultCallback callback) { diff --git a/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokens.java b/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokens.java index f640a8f..b13f8fc 100644 --- a/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokens.java +++ b/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokens.java @@ -4,11 +4,33 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.AccessToken; +import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult; import net.frozenorb.apiv3.util.ErrorUtils; public final class GETAccessTokens implements Handler { public void handle(RoutingContext ctx) { + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("user"), userCallback); + User user = userCallback.get(); + + if (user == null) { + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("user")); + return; + } + + int code = Integer.parseInt(ctx.request().getParam("totpCode")); + BlockingCallback totpAuthorizationCallback = new BlockingCallback<>(); + user.checkTotpAuthorization(code, null, totpAuthorizationCallback); + TotpAuthorizationResult totpAuthorizationResult = totpAuthorizationCallback.get(); + + if (!totpAuthorizationResult.isAuthorized()) { + ErrorUtils.respondInvalidInput(ctx, "Totp authorization failed: " + totpAuthorizationResult.name()); + return; + } + AccessToken.findAll((accessTokens, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); diff --git a/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokensId.java b/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokensId.java index cc4dc03..7c988aa 100644 --- a/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokensId.java +++ b/src/main/java/net/frozenorb/apiv3/route/accessTokens/GETAccessTokensId.java @@ -4,11 +4,33 @@ import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.AccessToken; +import net.frozenorb.apiv3.model.User; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult; import net.frozenorb.apiv3.util.ErrorUtils; public final class GETAccessTokensId implements Handler { public void handle(RoutingContext ctx) { + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(ctx.request().getParam("user"), userCallback); + User user = userCallback.get(); + + if (user == null) { + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("user")); + return; + } + + int code = Integer.parseInt(ctx.request().getParam("totpCode")); + BlockingCallback totpAuthorizationCallback = new BlockingCallback<>(); + user.checkTotpAuthorization(code, null, totpAuthorizationCallback); + TotpAuthorizationResult totpAuthorizationResult = totpAuthorizationCallback.get(); + + if (!totpAuthorizationResult.isAuthorized()) { + ErrorUtils.respondInvalidInput(ctx, "Totp authorization failed: " + totpAuthorizationResult.name()); + return; + } + AccessToken.findById(ctx.request().getParam("id"), (accessToken, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); diff --git a/src/main/java/net/frozenorb/apiv3/route/accessTokens/POSTAccessTokens.java b/src/main/java/net/frozenorb/apiv3/route/accessTokens/POSTAccessTokens.java index cc6d651..9eb1e88 100644 --- a/src/main/java/net/frozenorb/apiv3/route/accessTokens/POSTAccessTokens.java +++ b/src/main/java/net/frozenorb/apiv3/route/accessTokens/POSTAccessTokens.java @@ -9,7 +9,10 @@ import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; import net.frozenorb.apiv3.model.AccessToken; +import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.RequiresTotpResult; +import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult; import net.frozenorb.apiv3.util.ErrorUtils; import java.util.List; @@ -23,6 +26,25 @@ public final class POSTAccessTokens implements Handler { ActorType actorType = ActorType.valueOf(requestBody.getString("actorType").toUpperCase()); List lockedIps = (List) requestBody.getJsonArray("lockedIps").getList(); + BlockingCallback userCallback = new BlockingCallback<>(); + User.findById(requestBody.getString("user"), userCallback); + User user = userCallback.get(); + + if (user == null) { + ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user")); + return; + } + + int code = requestBody.getInteger("totpCode"); + BlockingCallback totpAuthorizationCallback = new BlockingCallback<>(); + user.checkTotpAuthorization(code, null, totpAuthorizationCallback); + TotpAuthorizationResult totpAuthorizationResult = totpAuthorizationCallback.get(); + + if (!totpAuthorizationResult.isAuthorized()) { + ErrorUtils.respondInvalidInput(ctx, "Totp authorization failed: " + totpAuthorizationResult.name()); + return; + } + AccessToken accessToken = new AccessToken(actorName, actorType, lockedIps); BlockingCallback callback = new BlockingCallback<>(); accessToken.insert(callback); 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 308367c..e353f49 100644 --- a/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java +++ b/src/main/java/net/frozenorb/apiv3/route/grants/POSTGrants.java @@ -12,6 +12,7 @@ import net.frozenorb.apiv3.model.Rank; import net.frozenorb.apiv3.model.ServerGroup; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.unsorted.TotpAuthorizationResult; import net.frozenorb.apiv3.util.ErrorUtils; import java.time.Instant; @@ -73,11 +74,23 @@ public final class POSTGrants implements Handler { return; } - // We purposely don't do a null check, grants don't have to have a source. + // We purposely don't fail on a null check, grants don't have to have a source. BlockingCallback addedByCallback = new BlockingCallback<>(); User.findById(requestBody.getString("addedBt"), addedByCallback); User addedBy = addedByCallback.get(); + if (addedBy != null && rank.isHigherStaffRank()) { + int code = requestBody.getInteger("totpCode"); + BlockingCallback totpAuthorizationCallback = new BlockingCallback<>(); + addedBy.checkTotpAuthorization(code, null, totpAuthorizationCallback); + TotpAuthorizationResult totpAuthorizationResult = totpAuthorizationCallback.get(); + + if (!totpAuthorizationResult.isAuthorized()) { + ErrorUtils.respondInvalidInput(ctx, "Totp authorization failed: " + totpAuthorizationResult.name()); + return; + } + } + Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy); BlockingCallback callback = new BlockingCallback<>(); grant.insert(callback);