Skip to content

Commit

Permalink
fix: refactor and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Oct 26, 2023
1 parent 4f43057 commit 9ca810f
Show file tree
Hide file tree
Showing 7 changed files with 1,254 additions and 192 deletions.
31 changes: 31 additions & 0 deletions src/main/java/io/supertokens/authRecipe/AuthRecipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,21 @@ public static LinkAccountsResult linkAccounts(Main main, String recipeUserId, St
}
}

@TestOnly
public static LinkAccountsResult linkAccounts(Main main, String recipeUserId, String primaryUserId, boolean forMfa)
throws StorageQueryException, AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException,
UnknownUserIdException,
FeatureNotEnabledException, InputUserIdIsNotAPrimaryUserException,
RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException {
AppIdentifierWithStorage appId = new AppIdentifierWithStorage(null, null,
StorageLayer.getStorage(main));
try {
return linkAccounts(main, appId, recipeUserId, primaryUserId, forMfa);
} catch (TenantOrAppNotFoundException e) {
throw new RuntimeException(e);
}
}

public static LinkAccountsResult linkAccounts(Main main, AppIdentifierWithStorage appIdentifierWithStorage,
String _recipeUserId, String _primaryUserId)
throws StorageQueryException,
Expand Down Expand Up @@ -550,6 +565,22 @@ public static CreatePrimaryUserResult createPrimaryUser(Main main,
}
}

@TestOnly
public static CreatePrimaryUserResult createPrimaryUser(Main main,
String recipeUserId,
boolean forMfa)
throws StorageQueryException, AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException,
RecipeUserIdAlreadyLinkedWithPrimaryUserIdException, UnknownUserIdException,
FeatureNotEnabledException {
AppIdentifierWithStorage appId = new AppIdentifierWithStorage(null, null,
StorageLayer.getStorage(main));
try {
return createPrimaryUser(main, appId, recipeUserId, forMfa);
} catch (TenantOrAppNotFoundException e) {
throw new RuntimeException(e);
}
}

@TestOnly
public static CreatePrimaryUserResult createPrimaryUser(Main main,
AppIdentifierWithStorage appIdentifierWithStorage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,16 @@ public CreatePrimaryUserAPI(Main main) {
super(main, RECIPE_ID.ACCOUNT_LINKING.toString());
}

public CreatePrimaryUserAPI(Main main, String recipeId) {
super(main, recipeId);
}

@Override
public String getPath() {
return "/recipe/accountlinking/user/primary";
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// API is app specific
public void handle(HttpServletRequest req, HttpServletResponse resp, boolean forMfa) throws IOException, ServletException {
JsonObject input = InputParser.parseJsonObjectOrThrowError(req);
String inputRecipeUserId = InputParser.parseStringOrThrowError(input, "recipeUserId", false);

Expand All @@ -67,7 +69,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
appIdentifierWithStorage = mappingAndStorage.appIdentifierWithStorage;

AuthRecipe.CreatePrimaryUserResult result = AuthRecipe.createPrimaryUser(main, appIdentifierWithStorage,
userId, false);
userId, forMfa);
JsonObject response = new JsonObject();
response.addProperty("status", "OK");
response.addProperty("wasAlreadyAPrimaryUser", result.wasAlreadyAPrimaryUser);
Expand Down Expand Up @@ -118,4 +120,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
}
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// API is app specific
handle(req, resp, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@ public LinkAccountsAPI(Main main) {
super(main, RECIPE_ID.ACCOUNT_LINKING.toString());
}

public LinkAccountsAPI(Main main, String recipeId) {
super(main, recipeId);
}

@Override
public String getPath() {
return "/recipe/accountlinking/user/link";
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// API is app specific
public void handle(HttpServletRequest req, HttpServletResponse resp, boolean forMfa) throws IOException, ServletException {
JsonObject input = InputParser.parseJsonObjectOrThrowError(req);
String inputRecipeUserId = InputParser.parseStringOrThrowError(input, "recipeUserId", false);
String inputPrimaryUserId = InputParser.parseStringOrThrowError(input, "primaryUserId", false);
Expand Down Expand Up @@ -99,7 +101,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I

AuthRecipe.LinkAccountsResult linkAccountsResult = AuthRecipe.linkAccounts(main,
primaryUserIdAppIdentifierWithStorage,
recipeUserId, primaryUserId, false);
recipeUserId, primaryUserId, forMfa);

UserIdMapping.populateExternalUserIdForUsers(primaryUserIdAppIdentifierWithStorage, new AuthRecipeUserInfo[]{linkAccountsResult.user});
JsonObject response = new JsonObject();
Expand Down Expand Up @@ -146,4 +148,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
super.sendJsonResponse(200, response, resp);
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// API is app specific
handle(req, resp, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,15 @@

package io.supertokens.webserver.api.mfa;

import com.google.gson.JsonObject;
import io.supertokens.AppIdentifierWithStorageAndUserIdMapping;
import io.supertokens.Main;
import io.supertokens.authRecipe.AuthRecipe;
import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException;
import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithPrimaryUserIdException;
import io.supertokens.featureflag.exceptions.FeatureNotEnabledException;
import io.supertokens.pluginInterface.RECIPE_ID;
import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException;
import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.pluginInterface.multitenancy.AppIdentifierWithStorage;
import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException;
import io.supertokens.useridmapping.UserIdMapping;
import io.supertokens.useridmapping.UserIdType;
import io.supertokens.webserver.InputParser;
import io.supertokens.webserver.WebserverAPI;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

public class CreatePrimaryUserAPI extends WebserverAPI {
public class CreatePrimaryUserAPI extends io.supertokens.webserver.api.accountlinking.CreatePrimaryUserAPI {

public CreatePrimaryUserAPI(Main main) {
super(main, RECIPE_ID.MFA.toString());
Expand All @@ -52,70 +38,6 @@ public String getPath() {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// API is app specific
JsonObject input = InputParser.parseJsonObjectOrThrowError(req);
String inputRecipeUserId = InputParser.parseStringOrThrowError(input, "recipeUserId", false);

AppIdentifierWithStorage appIdentifierWithStorage = null;
try {
String userId = inputRecipeUserId;
AppIdentifierWithStorageAndUserIdMapping mappingAndStorage =
getAppIdentifierWithStorageAndUserIdMappingFromRequest(
req, inputRecipeUserId, UserIdType.ANY);
if (mappingAndStorage.userIdMapping != null) {
userId = mappingAndStorage.userIdMapping.superTokensUserId;
}
appIdentifierWithStorage = mappingAndStorage.appIdentifierWithStorage;

AuthRecipe.CreatePrimaryUserResult result = AuthRecipe.createPrimaryUser(main, appIdentifierWithStorage,
userId, true);
JsonObject response = new JsonObject();
response.addProperty("status", "OK");
response.addProperty("wasAlreadyAPrimaryUser", result.wasAlreadyAPrimaryUser);
if (mappingAndStorage.userIdMapping != null) {
result.user.setExternalUserId(mappingAndStorage.userIdMapping.externalUserId);
} else {
result.user.setExternalUserId(null);
}
response.add("user", result.user.toJson());
super.sendJsonResponse(200, response, resp);
} catch (StorageQueryException | TenantOrAppNotFoundException | FeatureNotEnabledException e) {
throw new ServletException(e);
} catch (UnknownUserIdException e) {
throw new ServletException(new BadRequestException("Unknown user ID provided"));
} catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) {
try {
JsonObject response = new JsonObject();
response.addProperty("status", "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR");
io.supertokens.pluginInterface.useridmapping.UserIdMapping result = UserIdMapping.getUserIdMapping(
appIdentifierWithStorage, e.primaryUserId,
UserIdType.SUPERTOKENS);
if (result != null) {
response.addProperty("primaryUserId", result.externalUserId);
} else {
response.addProperty("primaryUserId", e.primaryUserId);
}
response.addProperty("description", e.getMessage());
super.sendJsonResponse(200, response, resp);
} catch (StorageQueryException ex) {
throw new ServletException(ex);
}
} catch (RecipeUserIdAlreadyLinkedWithPrimaryUserIdException e) {
try {
JsonObject response = new JsonObject();
response.addProperty("status", "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR");
io.supertokens.pluginInterface.useridmapping.UserIdMapping result = UserIdMapping.getUserIdMapping(
appIdentifierWithStorage, e.primaryUserId,
UserIdType.SUPERTOKENS);
if (result != null) {
response.addProperty("primaryUserId", result.externalUserId);
} else {
response.addProperty("primaryUserId", e.primaryUserId);
}
response.addProperty("description", e.getMessage());
super.sendJsonResponse(200, response, resp);
} catch (StorageQueryException ex) {
throw new ServletException(ex);
}
}
handle(req, resp, true);
}
}
106 changes: 2 additions & 104 deletions src/main/java/io/supertokens/webserver/api/mfa/LinkAccountsAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,15 @@

package io.supertokens.webserver.api.mfa;

import com.google.gson.JsonObject;
import io.supertokens.AppIdentifierWithStorageAndUserIdMapping;
import io.supertokens.Main;
import io.supertokens.authRecipe.AuthRecipe;
import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException;
import io.supertokens.authRecipe.exception.InputUserIdIsNotAPrimaryUserException;
import io.supertokens.authRecipe.exception.RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException;
import io.supertokens.featureflag.exceptions.FeatureNotEnabledException;
import io.supertokens.pluginInterface.RECIPE_ID;
import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo;
import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException;
import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.pluginInterface.multitenancy.AppIdentifierWithStorage;
import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException;
import io.supertokens.useridmapping.UserIdMapping;
import io.supertokens.useridmapping.UserIdType;
import io.supertokens.webserver.InputParser;
import io.supertokens.webserver.WebserverAPI;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

public class LinkAccountsAPI extends WebserverAPI {
public class LinkAccountsAPI extends io.supertokens.webserver.api.accountlinking.LinkAccountsAPI {

public LinkAccountsAPI(Main main) {
super(main, RECIPE_ID.MFA.toString());
Expand All @@ -54,92 +38,6 @@ public String getPath() {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// API is app specific
JsonObject input = InputParser.parseJsonObjectOrThrowError(req);
String inputRecipeUserId = InputParser.parseStringOrThrowError(input, "recipeUserId", false);
String inputPrimaryUserId = InputParser.parseStringOrThrowError(input, "primaryUserId", false);

AppIdentifierWithStorage primaryUserIdAppIdentifierWithStorage = null;
AppIdentifierWithStorage recipeUserIdAppIdentifierWithStorage = null;
try {
String recipeUserId = inputRecipeUserId;
{
AppIdentifierWithStorageAndUserIdMapping mappingAndStorage =
getAppIdentifierWithStorageAndUserIdMappingFromRequest(
req, inputRecipeUserId, UserIdType.ANY);
if (mappingAndStorage.userIdMapping != null) {
recipeUserId = mappingAndStorage.userIdMapping.superTokensUserId;
}
recipeUserIdAppIdentifierWithStorage = mappingAndStorage.appIdentifierWithStorage;
}
String primaryUserId = inputPrimaryUserId;
{
AppIdentifierWithStorageAndUserIdMapping mappingAndStorage =
getAppIdentifierWithStorageAndUserIdMappingFromRequest(
req, inputPrimaryUserId, UserIdType.ANY);
if (mappingAndStorage.userIdMapping != null) {
primaryUserId = mappingAndStorage.userIdMapping.superTokensUserId;
}
primaryUserIdAppIdentifierWithStorage = mappingAndStorage.appIdentifierWithStorage;
}

// we do a check based on user pool ID and not instance reference checks cause the user
// could be in the same db, but their storage layers may just have different
if (!primaryUserIdAppIdentifierWithStorage.getStorage().getUserPoolId().equals(
recipeUserIdAppIdentifierWithStorage.getStorage().getUserPoolId())) {
throw new ServletException(
new BadRequestException(
"Cannot link users that are parts of different databases. Different pool IDs: " +
primaryUserIdAppIdentifierWithStorage.getStorage().getUserPoolId() + " AND " +
recipeUserIdAppIdentifierWithStorage.getStorage().getUserPoolId()));
}

AuthRecipe.LinkAccountsResult linkAccountsResult = AuthRecipe.linkAccounts(main,
primaryUserIdAppIdentifierWithStorage,
recipeUserId, primaryUserId, true);

UserIdMapping.populateExternalUserIdForUsers(primaryUserIdAppIdentifierWithStorage, new AuthRecipeUserInfo[]{linkAccountsResult.user});
JsonObject response = new JsonObject();
response.addProperty("status", "OK");
response.addProperty("accountsAlreadyLinked", linkAccountsResult.wasAlreadyLinked);
response.add("user", linkAccountsResult.user.toJson());
super.sendJsonResponse(200, response, resp);
} catch (StorageQueryException | TenantOrAppNotFoundException | FeatureNotEnabledException e) {
throw new ServletException(e);
} catch (UnknownUserIdException e) {
throw new ServletException(new BadRequestException("Unknown user ID provided"));
} catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) {
try {
JsonObject response = new JsonObject();
response.addProperty("status", "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR");
io.supertokens.pluginInterface.useridmapping.UserIdMapping result = UserIdMapping.getUserIdMapping(
primaryUserIdAppIdentifierWithStorage, e.primaryUserId,
UserIdType.SUPERTOKENS);
if (result != null) {
response.addProperty("primaryUserId", result.externalUserId);
} else {
response.addProperty("primaryUserId", e.primaryUserId);
}
response.addProperty("description", e.getMessage());
super.sendJsonResponse(200, response, resp);
} catch (StorageQueryException ex) {
throw new ServletException(ex);
}
} catch (RecipeUserIdAlreadyLinkedWithAnotherPrimaryUserIdException e) {
try {
JsonObject response = new JsonObject();
response.addProperty("status", "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR");
UserIdMapping.populateExternalUserIdForUsers(recipeUserIdAppIdentifierWithStorage, new AuthRecipeUserInfo[]{e.recipeUser});
response.addProperty("primaryUserId", e.recipeUser.getSupertokensOrExternalUserId());
response.addProperty("description", e.getMessage());
response.add("user", e.recipeUser.toJson());
super.sendJsonResponse(200, response, resp);
} catch (StorageQueryException ex) {
throw new ServletException(ex);
}
} catch (InputUserIdIsNotAPrimaryUserException e) {
JsonObject response = new JsonObject();
response.addProperty("status", "INPUT_USER_IS_NOT_A_PRIMARY_USER");
super.sendJsonResponse(200, response, resp);
}
handle(req, resp, true);
}
}
Loading

0 comments on commit 9ca810f

Please sign in to comment.