Add POST /users/usePasswordResetToken to use password reset token without user uuid
This commit is contained in:
parent
e0090cdeb5
commit
831348b4f8
@ -409,6 +409,7 @@ public final class APIv3 extends AbstractVerticle {
|
||||
http.post("/users/:userId/passwordReset").blockingHandler(new POSTUsersIdPasswordReset(), false);
|
||||
http.post("/users/:userId/registerEmail").blockingHandler(new POSTUsersIdRegisterEmail(), false);
|
||||
http.post("/users/:userId/registerPhone").blockingHandler(new POSTUsersIdRegisterPhone(), false);
|
||||
http.post("/users/usePasswordResetToken").blockingHandler(new POSTUsersUsePasswordResetToken(), false);
|
||||
http.post("/users/:userId/setupTotp").blockingHandler(new POSTUsersIdSetupTotp(), false);
|
||||
http.post("/users/:userId/verifyTotp").handler(new POSTUsersIdVerifyTotp());
|
||||
|
||||
|
@ -136,6 +136,10 @@ public final class User {
|
||||
usersCollection.find(new Document("email", email)).first(SyncUtils.vertxWrap(callback));
|
||||
}
|
||||
|
||||
public static void findByPasswordResetToken(String passwordResetToken, SingleResultCallback<User> callback) {
|
||||
usersCollection.find(new Document("passwordResetToken", passwordResetToken)).first(SyncUtils.vertxWrap(callback));
|
||||
}
|
||||
|
||||
public static void findByEmailToken(String emailToken, SingleResultCallback<User> callback) {
|
||||
usersCollection.find(new Document("pendingEmailToken", emailToken)).first(SyncUtils.vertxWrap(callback));
|
||||
}
|
||||
|
@ -18,56 +18,40 @@ public final class POSTUsersIdChangePassword implements Handler<RoutingContext>
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = SyncUtils.runBlocking(v -> User.findById(ctx.request().getParam("userId"), v));
|
||||
JsonObject requestBody = ctx.getBodyAsJson();
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("userId"));
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject requestBody = ctx.getBodyAsJson();
|
||||
if (user.getPassword() == null) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "User provided does not have password set.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestBody.containsKey("currentPassword")) {
|
||||
if (user.getPassword() == null) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "User provided does not have password set.");
|
||||
return;
|
||||
}
|
||||
if (!requestBody.containsKey("currentPassword")) {
|
||||
ErrorUtils.respondRequiredInput(ctx, "currentPassword");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.checkPassword(requestBody.getString("currentPassword"))) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Could not authorize password change.");
|
||||
return;
|
||||
}
|
||||
|
||||
RequiresTotpResult requiresTotp = SyncUtils.runBlocking(v -> user.requiresTotpAuthorization(null, v));
|
||||
|
||||
if (requiresTotp == RequiresTotpResult.REQUIRED_NO_EXEMPTIONS) {
|
||||
int code = requestBody.getInteger("totpCode");
|
||||
TotpAuthorizationResult totpAuthorizationResult = SyncUtils.runBlocking(v -> user.checkTotpAuthorization(code, null, v));
|
||||
|
||||
if (!totpAuthorizationResult.isAuthorized()) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Totp authorization failed: " + totpAuthorizationResult.name());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (requestBody.containsKey("passwordResetToken")) {
|
||||
if (user.getPasswordResetToken() == null) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "User provided does not have password reset token set.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.getPasswordResetToken().equals(requestBody.getString("passwordResetToken"))) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Could not authorize password change.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((System.currentTimeMillis() - user.getPasswordResetTokenSetAt().toEpochMilli()) > TimeUnit.DAYS.toMillis(2)) {
|
||||
ErrorUtils.respondOther(ctx, 409, "Password reset token is expired.", "passwordTokenExpired", ImmutableMap.of());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!user.checkPassword(requestBody.getString("currentPassword"))) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Could not authorize password change.");
|
||||
return;
|
||||
}
|
||||
|
||||
RequiresTotpResult requiresTotp = SyncUtils.runBlocking(v -> user.requiresTotpAuthorization(null, v));
|
||||
|
||||
if (requiresTotp == RequiresTotpResult.REQUIRED_NO_EXEMPTIONS) {
|
||||
int code = requestBody.getInteger("totpCode");
|
||||
TotpAuthorizationResult totpAuthorizationResult = SyncUtils.runBlocking(v -> user.checkTotpAuthorization(code, null, v));
|
||||
|
||||
if (!totpAuthorizationResult.isAuthorized()) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Totp authorization failed: " + totpAuthorizationResult.name());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String newPassword = requestBody.getString("newPassword");
|
||||
|
||||
if (PasswordUtils.isTooShort(newPassword)) {
|
||||
|
@ -0,0 +1,72 @@
|
||||
package net.frozenorb.apiv3.route.users;
|
||||
|
||||
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.User;
|
||||
import net.frozenorb.apiv3.util.*;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class POSTUsersUsePasswordResetToken implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
JsonObject requestBody = ctx.getBodyAsJson();
|
||||
|
||||
if (!requestBody.containsKey("passwordResetToken")) {
|
||||
ErrorUtils.respondRequiredInput(ctx, "passwordResetToken");
|
||||
return;
|
||||
}
|
||||
|
||||
String passwordResetToken = requestBody.getString("passwordResetToken");
|
||||
User user = SyncUtils.runBlocking(v -> User.findByPasswordResetToken(passwordResetToken, v));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Password reset token", passwordResetToken);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((System.currentTimeMillis() - user.getPasswordResetTokenSetAt().toEpochMilli()) > TimeUnit.DAYS.toMillis(2)) {
|
||||
ErrorUtils.respondOther(ctx, 409, "Password reset token is expired.", "passwordTokenExpired", ImmutableMap.of());
|
||||
return;
|
||||
}
|
||||
|
||||
String newPassword = requestBody.getString("newPassword");
|
||||
|
||||
if (PasswordUtils.isTooShort(newPassword)) {
|
||||
ErrorUtils.respondOther(ctx, 409, "Your password is too short.", "passwordTooShort", ImmutableMap.of());
|
||||
return;
|
||||
}
|
||||
|
||||
if (PasswordUtils.isTooSimple(newPassword)) {
|
||||
ErrorUtils.respondOther(ctx, 409, "Your password is too simple.", "passwordTooSimple", ImmutableMap.of());
|
||||
return;
|
||||
}
|
||||
|
||||
user.updatePassword(newPassword);
|
||||
SyncUtils.<Void>runBlocking(v -> user.save(v));
|
||||
SyncUtils.<Void>runBlocking(v -> UserSessionUtils.invalidateAllSessions(user.getId(), v));
|
||||
String userIp = requestBody.getString("userIp");
|
||||
|
||||
if (!IpUtils.isValidIp(userIp)) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
|
||||
return;
|
||||
}
|
||||
|
||||
AuditLog.log(user.getId(), userIp, ctx, AuditLogActionType.USER_CHANGE_PASSWORD, (ignored, error) -> {
|
||||
if (error != null) {
|
||||
ErrorUtils.respondInternalError(ctx, error);
|
||||
} else {
|
||||
APIv3.respondJson(ctx, 200, ImmutableMap.of(
|
||||
"success", true,
|
||||
"uuid", user.getId()
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user