Even more Zang telephone work!
This commit is contained in:
parent
822dd27536
commit
c8c1ac153d
@ -71,6 +71,7 @@ import net.frozenorb.apiv3.route.notificationTemplates.DELETENotificationTemplat
|
||||
import net.frozenorb.apiv3.route.notificationTemplates.GETNotificationTemplates;
|
||||
import net.frozenorb.apiv3.route.notificationTemplates.GETNotificationTemplatesId;
|
||||
import net.frozenorb.apiv3.route.notificationTemplates.POSTNotificationTemplates;
|
||||
import net.frozenorb.apiv3.route.phoneIntel.GETPhoneInteld;
|
||||
import net.frozenorb.apiv3.route.punishments.*;
|
||||
import net.frozenorb.apiv3.route.ranks.DELETERanksId;
|
||||
import net.frozenorb.apiv3.route.ranks.GETRanks;
|
||||
@ -299,6 +300,8 @@ public final class APIv3 extends AbstractVerticle {
|
||||
//http.put("/notificationTemplates/:id").blockingHandler(new PUTNotificationTemplatesId(), false);
|
||||
http.delete("/notificationTemplates/:id").blockingHandler(new DELETENotificationTemplatesId(), false);
|
||||
|
||||
http.get("/phoneIntel/:id").handler(new GETPhoneInteld());
|
||||
|
||||
http.get("/punishments/:id").handler(new GETPunishmentsId());
|
||||
http.get("/punishments").handler(new GETPunishments());
|
||||
http.post("/punishments").blockingHandler(new POSTPunishments(), false);
|
||||
|
70
src/main/java/net/frozenorb/apiv3/model/PhoneIntel.java
Normal file
70
src/main/java/net/frozenorb/apiv3/model/PhoneIntel.java
Normal file
@ -0,0 +1,70 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import com.mongodb.async.client.MongoCollection;
|
||||
import fr.javatic.mongo.jacksonCodec.Entity;
|
||||
import fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.util.ZangUtils;
|
||||
import net.frozenorb.apiv3.zang.ZangResult;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
public final class PhoneIntel {
|
||||
|
||||
private static final MongoCollection<PhoneIntel> phoneIntelCollection = APIv3.getDatabase().getCollection("phoneIntel", PhoneIntel.class);
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private Instant lastUpdatedAt;
|
||||
@Getter private ZangResult result;
|
||||
|
||||
public static void findAll(SingleResultCallback<List<PhoneIntel>> callback) {
|
||||
phoneIntelCollection.find().sort(new Document("lastSeenAt", -1)).into(new LinkedList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<PhoneIntel> callback) {
|
||||
phoneIntelCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findOrCreateById(String id, SingleResultCallback<PhoneIntel> callback) {
|
||||
findById(id, (existingPhoneIntel, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
} else if (existingPhoneIntel != null) {
|
||||
callback.onResult(existingPhoneIntel, null);
|
||||
} else {
|
||||
ZangUtils.getCarrierInfo(id, (zangResult, error2) -> {
|
||||
if (error2 != null) {
|
||||
callback.onResult(null, error2);
|
||||
} else {
|
||||
PhoneIntel newPhoneIntel = new PhoneIntel(id, zangResult);
|
||||
|
||||
phoneIntelCollection.insertOne(newPhoneIntel, (ignored, error3) -> {
|
||||
if (error3 != null) {
|
||||
callback.onResult(null, error3);
|
||||
} else {
|
||||
callback.onResult(newPhoneIntel, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private PhoneIntel() {} // For Jackson
|
||||
|
||||
private PhoneIntel(String phoneNumber, ZangResult result) {
|
||||
this.id = phoneNumber;
|
||||
this.lastUpdatedAt = Instant.now();
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
}
|
@ -486,16 +486,16 @@ public final class User {
|
||||
|
||||
public void startPhoneRegistration(String phoneNumber) {
|
||||
this.pendingPhone = phoneNumber;
|
||||
this.pendingEmailToken = UUID.randomUUID().toString().replace("-", "");
|
||||
this.pendingEmailTokenSetAt = Instant.now();
|
||||
this.pendingPhoneToken = String.valueOf(new Random().nextInt(999999 - 100000) + 100000);
|
||||
this.pendingPhoneTokenSetAt = Instant.now();
|
||||
}
|
||||
|
||||
public void completeRegistration(String email) {
|
||||
this.email = email;
|
||||
this.registeredAt = Instant.now();
|
||||
this.pendingEmail = null;
|
||||
this.pendingEmailToken = null;
|
||||
this.pendingEmailTokenSetAt = null;
|
||||
public void completePhoneRegistration(String phoneNumber) {
|
||||
this.phone = phoneNumber;
|
||||
this.phoneRegisteredAt = Instant.now();
|
||||
this.pendingPhone = null;
|
||||
this.pendingPhoneToken = null;
|
||||
this.pendingPhoneTokenSetAt = null;
|
||||
}
|
||||
|
||||
public void hasPermissionAnywhere(String permission, SingleResultCallback<Boolean> callback) {
|
||||
|
@ -26,9 +26,7 @@ public final class POSTEmailTokensIdConfirm implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't check email != null as that's set while we're pending
|
||||
// confirmation, we have to check the token.
|
||||
if (user.getPendingEmailToken() == null) {
|
||||
if (user.getEmail() != null) {
|
||||
ErrorUtils.respondGeneric(ctx, 400, "User provided already has email set.");
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package net.frozenorb.apiv3.route.phoneIntel;
|
||||
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.PhoneIntel;
|
||||
import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
import net.frozenorb.apiv3.util.PhoneUtils;
|
||||
|
||||
public final class GETPhoneInteld implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
String phoneNumber = ctx.request().getParam("id");
|
||||
|
||||
if (!PhoneUtils.isValidPhone(phoneNumber)) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Phone number \"" + phoneNumber + "\" is not valid.");
|
||||
return;
|
||||
}
|
||||
|
||||
PhoneIntel.findOrCreateById(phoneNumber, (ipIntel, error) -> {
|
||||
if (error != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, ipIntel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package net.frozenorb.apiv3.route.users;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
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.User;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class POSTUsersIdConfirmPhone implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
BlockingCallback<User> userCallback = new BlockingCallback<>();
|
||||
User.findById(ctx.request().getParam("id"), userCallback);
|
||||
User user = userCallback.get();
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.getPhone() != null) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "User provided already has a confirmed phone number.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.getPendingPhoneToken() == null) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "User provided already hasn't started confirming a phone number.");
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject requestBody = ctx.getBodyAsJson();
|
||||
int phoneCode = requestBody.getInteger("phoneCode");
|
||||
|
||||
if ((System.currentTimeMillis() - user.getPendingPhoneTokenSetAt().toEpochMilli()) > TimeUnit.MINUTES.toMillis(20)) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Phone token is expired");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!String.valueOf(phoneCode).equals(user.getPendingPhoneToken())) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Phone token doesn't match");
|
||||
return;
|
||||
}
|
||||
|
||||
user.completePhoneRegistration(user.getPendingPhone());
|
||||
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||
user.save(callback);
|
||||
callback.get();
|
||||
|
||||
AuditLog.log(user.getId(), requestBody.getString("userIp"), ctx, AuditLogActionType.USER_CONFIRM_PHONE, (ignored, error) -> {
|
||||
if (error != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"success", true
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -8,12 +8,15 @@ 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.BannedCellCarrier;
|
||||
import net.frozenorb.apiv3.model.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.model.PhoneIntel;
|
||||
import net.frozenorb.apiv3.model.User;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.unsorted.Notification;
|
||||
import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
import net.frozenorb.apiv3.util.PhoneUtils;
|
||||
import net.frozenorb.apiv3.zang.ZangResult;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -43,8 +46,8 @@ public final class POSTUsersIdRegisterPhone implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.getPendingPhoneToken() != null && (System.currentTimeMillis() - user.getPendingPhoneTokenSetAt().toEpochMilli()) < TimeUnit.DAYS.toMillis(2)) {
|
||||
ErrorUtils.respondGeneric(ctx, 200, "We just recently sent you a confirmation code. Please wait before trying to register again.");
|
||||
if (user.getPendingPhoneToken() != null && (System.currentTimeMillis() - user.getPendingPhoneTokenSetAt().toEpochMilli()) < TimeUnit.MINUTES.toMillis(20)) {
|
||||
ErrorUtils.respondGeneric(ctx, 200, "We just recently sent you a confirmation code. Please wait before trying to register your phone again.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -56,6 +59,15 @@ public final class POSTUsersIdRegisterPhone implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockingCallback<PhoneIntel> phoneIntelCallback = new BlockingCallback<>();
|
||||
PhoneIntel.findOrCreateById(phone, phoneIntelCallback);
|
||||
PhoneIntel phoneIntel = phoneIntelCallback.get();
|
||||
|
||||
if (BannedCellCarrier.findById(phoneIntel.getResult().getCarrierId()) != null) {
|
||||
ErrorUtils.respondInvalidInput(ctx, phone + " is from a banned cell provider.");
|
||||
return;
|
||||
}
|
||||
|
||||
user.startPhoneRegistration(phone);
|
||||
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||
user.save(callback);
|
||||
|
Loading…
Reference in New Issue
Block a user