Skip to content

Commit

Permalink
fix: account linking
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Sep 15, 2023
1 parent 7fba0e5 commit bb7064a
Show file tree
Hide file tree
Showing 14 changed files with 2,483 additions and 887 deletions.
620 changes: 390 additions & 230 deletions src/main/java/io/supertokens/storage/mysql/Start.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.supertokens.storage.mysql.queries;

import java.sql.Connection;
import java.sql.SQLException;

import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
Expand Down Expand Up @@ -37,7 +38,30 @@ public static int countUsersActiveSince(Start start, AppIdentifier appIdentifier
});
}

public static int countUsersEnabledTotp(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException {
public static int countUsersActiveSinceAndHasMoreThanOneLoginMethod(Start start, AppIdentifier appIdentifier, long sinceTime)
throws SQLException, StorageQueryException {
String QUERY = "SELECT count(1) as c FROM ("
+ " SELECT count(user_id) as num_login_methods, app_id, primary_or_recipe_user_id"
+ " FROM " + Config.getConfig(start).getUsersTable()
+ " WHERE primary_or_recipe_user_id IN ("
+ " SELECT user_id FROM " + Config.getConfig(start).getUserLastActiveTable()
+ " WHERE app_id = ? AND last_active_time >= ?"
+ " )"
+ " GROUP BY app_id, primary_or_recipe_user_id"
+ ") uc WHERE num_login_methods > 1";
return execute(start, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setLong(2, sinceTime);
}, result -> {
if (result.next()) {
return result.getInt("c");
}
return 0;
});
}

public static int countUsersEnabledTotp(Start start, AppIdentifier appIdentifier)
throws SQLException, StorageQueryException {
String QUERY = "SELECT COUNT(*) as total FROM " + Config.getConfig(start).getTotpUsersTable()
+ " WHERE app_id = ?";

Expand All @@ -51,7 +75,8 @@ public static int countUsersEnabledTotp(Start start, AppIdentifier appIdentifier
});
}

public static int countUsersEnabledTotpAndActiveSince(Start start, AppIdentifier appIdentifier, long sinceTime) throws SQLException, StorageQueryException {
public static int countUsersEnabledTotpAndActiveSince(Start start, AppIdentifier appIdentifier, long sinceTime)
throws SQLException, StorageQueryException {
String QUERY = "SELECT COUNT(*) as total FROM " + Config.getConfig(start).getTotpUsersTable() + " AS totp_users "
+ "INNER JOIN " + Config.getConfig(start).getUserLastActiveTable() + " AS user_last_active "
+ "ON totp_users.user_id = user_last_active.user_id "
Expand Down Expand Up @@ -101,14 +126,15 @@ public static Long getLastActiveByUserId(Start start, AppIdentifier appIdentifie
}
}

public static void deleteUserActive(Start start, AppIdentifier appIdentifier, String userId)
public static void deleteUserActive_Transaction(Connection con, Start start, AppIdentifier appIdentifier,
String userId)
throws StorageQueryException, SQLException {
String QUERY = "DELETE FROM " + Config.getConfig(start).getUserLastActiveTable()
+ " WHERE app_id = ? AND user_id = ?";

update(start, QUERY, pst -> {
update(con, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, userId);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/

package io.supertokens.storage.mysql.queries;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
import io.supertokens.storage.mysql.Start;
import io.supertokens.storage.mysql.config.Config;
import io.supertokens.storage.mysql.utils.Utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.*;

import static io.supertokens.storage.mysql.QueryExecutorTemplate.execute;
import static io.supertokens.storage.mysql.QueryExecutorTemplate.update;
Expand Down Expand Up @@ -77,7 +77,8 @@ public static void deleteExpiredEmailVerificationTokens(Start start) throws SQLE

public static void updateUsersIsEmailVerified_Transaction(Start start, Connection con, AppIdentifier appIdentifier,
String userId, String email,
boolean isEmailVerified) throws SQLException, StorageQueryException {
boolean isEmailVerified)
throws SQLException, StorageQueryException {

if (isEmailVerified) {
String QUERY = "INSERT INTO " + getConfig(start).getEmailVerificationTable()
Expand All @@ -101,8 +102,10 @@ public static void updateUsersIsEmailVerified_Transaction(Start start, Connectio
}

public static void deleteAllEmailVerificationTokensForUser_Transaction(Start start, Connection con,
TenantIdentifier tenantIdentifier, String userId,
String email) throws SQLException, StorageQueryException {
TenantIdentifier tenantIdentifier,
String userId,
String email)
throws SQLException, StorageQueryException {
String QUERY = "DELETE FROM " + getConfig(start).getEmailVerificationTokensTable()
+ " WHERE app_id = ? AND tenant_id = ? AND user_id = ? AND email = ?";

Expand All @@ -114,7 +117,8 @@ public static void deleteAllEmailVerificationTokensForUser_Transaction(Start sta
});
}

public static EmailVerificationTokenInfo getEmailVerificationTokenInfo(Start start, TenantIdentifier tenantIdentifier,
public static EmailVerificationTokenInfo getEmailVerificationTokenInfo(Start start,
TenantIdentifier tenantIdentifier,
String token)
throws SQLException, StorageQueryException {
String QUERY = "SELECT user_id, token, token_expiry, email FROM "
Expand All @@ -132,7 +136,8 @@ public static EmailVerificationTokenInfo getEmailVerificationTokenInfo(Start sta
});
}

public static void addEmailVerificationToken(Start start, TenantIdentifier tenantIdentifier, String userId, String tokenHash, long expiry,
public static void addEmailVerificationToken(Start start, TenantIdentifier tenantIdentifier, String userId,
String tokenHash, long expiry,
String email) throws SQLException, StorageQueryException {
String QUERY = "INSERT INTO " + getConfig(start).getEmailVerificationTokensTable()
+ "(app_id, tenant_id, user_id, token, token_expiry, email)" + " VALUES(?, ?, ?, ?, ?, ?)";
Expand All @@ -150,10 +155,13 @@ public static void addEmailVerificationToken(Start start, TenantIdentifier tenan
public static EmailVerificationTokenInfo[] getAllEmailVerificationTokenInfoForUser_Transaction(Start start,
Connection con,
TenantIdentifier tenantIdentifier,
String userId, String email) throws SQLException, StorageQueryException {
String userId,
String email)
throws SQLException, StorageQueryException {

String QUERY = "SELECT user_id, token, token_expiry, email FROM "
+ getConfig(start).getEmailVerificationTokensTable() + " WHERE app_id = ? AND tenant_id = ? AND user_id = ? AND email = ? FOR UPDATE";
+ getConfig(start).getEmailVerificationTokensTable() +
" WHERE app_id = ? AND tenant_id = ? AND user_id = ? AND email = ? FOR UPDATE";

return execute(con, QUERY, pst -> {
pst.setString(1, tenantIdentifier.getAppId());
Expand All @@ -176,9 +184,11 @@ public static EmailVerificationTokenInfo[] getAllEmailVerificationTokenInfoForUs
public static EmailVerificationTokenInfo[] getAllEmailVerificationTokenInfoForUser(Start start,
TenantIdentifier tenantIdentifier,
String userId,
String email) throws SQLException, StorageQueryException {
String email)
throws SQLException, StorageQueryException {
String QUERY = "SELECT user_id, token, token_expiry, email FROM "
+ getConfig(start).getEmailVerificationTokensTable() + " WHERE app_id = ? AND tenant_id = ? AND user_id = ? AND email = ?";
+ getConfig(start).getEmailVerificationTokensTable() +
" WHERE app_id = ? AND tenant_id = ? AND user_id = ? AND email = ?";

return execute(start, QUERY, pst -> {
pst.setString(1, tenantIdentifier.getAppId());
Expand Down Expand Up @@ -210,38 +220,130 @@ public static boolean isEmailVerified(Start start, AppIdentifier appIdentifier,
}, result -> result.next());
}

public static void deleteUserInfo(Start start, AppIdentifier appIdentifier, String userId)
throws StorageQueryException, StorageTransactionLogicException {
start.startTransaction(con -> {
Connection sqlCon = (Connection) con.getConnection();
try {
{
String QUERY = "DELETE FROM " + getConfig(start).getEmailVerificationTable()
+ " WHERE app_id = ? AND user_id = ?";
update(sqlCon, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, userId);
});
}
public static class UserIdAndEmail {
public String userId;
public String email;

{
String QUERY = "DELETE FROM " + getConfig(start).getEmailVerificationTokensTable()
+ " WHERE app_id = ? AND user_id = ?";
public UserIdAndEmail(String userId, String email) {
this.userId = userId;
this.email = email;
}
}

// returns list of userIds where email is verified.
public static List<String> isEmailVerified_transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier,
List<UserIdAndEmail> userIdAndEmail)
throws SQLException, StorageQueryException {
if (userIdAndEmail.isEmpty()) {
return new ArrayList<>();
}
List<String> emails = new ArrayList<>();
List<String> userIds = new ArrayList<>();
Map<String, String> userIdToEmailMap = new HashMap<>();
for (UserIdAndEmail ue : userIdAndEmail) {
emails.add(ue.email);
userIds.add(ue.userId);
}
for (UserIdAndEmail ue : userIdAndEmail) {
if (userIdToEmailMap.containsKey(ue.userId)) {
throw new RuntimeException("Found a bug!");
}
userIdToEmailMap.put(ue.userId, ue.email);
}
String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable()
+ " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) +
") AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ")";

update(sqlCon, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, userId);
});
return execute(sqlCon, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
int index = 2;
for (String userId : userIds) {
pst.setString(index++, userId);
}
for (String email : emails) {
pst.setString(index++, email);
}
}, result -> {
List<String> res = new ArrayList<>();
while (result.next()) {
String userId = result.getString("user_id");
String email = result.getString("email");
if (Objects.equals(userIdToEmailMap.get(userId), email)) {
res.add(userId);
}
}
return res;
});
}

sqlCon.commit();
} catch (SQLException throwables) {
throw new StorageTransactionLogicException(throwables);
public static List<String> isEmailVerified(Start start, AppIdentifier appIdentifier,
List<UserIdAndEmail> userIdAndEmail)
throws SQLException, StorageQueryException {
if (userIdAndEmail.isEmpty()) {
return new ArrayList<>();
}
List<String> emails = new ArrayList<>();
List<String> userIds = new ArrayList<>();
Map<String, String> userIdToEmailMap = new HashMap<>();
for (UserIdAndEmail ue : userIdAndEmail) {
emails.add(ue.email);
userIds.add(ue.userId);
}
for (UserIdAndEmail ue : userIdAndEmail) {
if (userIdToEmailMap.containsKey(ue.userId)) {
throw new RuntimeException("Found a bug!");
}
return null;
userIdToEmailMap.put(ue.userId, ue.email);
}
String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable()
+ " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) +
") AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ")";

return execute(start, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
int index = 2;
for (String userId : userIds) {
pst.setString(index++, userId);
}
for (String email : emails) {
pst.setString(index++, email);
}
}, result -> {
List<String> res = new ArrayList<>();
while (result.next()) {
String userId = result.getString("user_id");
String email = result.getString("email");
if (Objects.equals(userIdToEmailMap.get(userId), email)) {
res.add(userId);
}
}
return res;
});
}

public static void deleteUserInfo_Transaction(Connection sqlCon, Start start, AppIdentifier appIdentifier,
String userId)
throws StorageQueryException, SQLException {
{
String QUERY = "DELETE FROM " + getConfig(start).getEmailVerificationTable()
+ " WHERE app_id = ? AND user_id = ?";
update(sqlCon, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, userId);
});
}

{
String QUERY = "DELETE FROM " + getConfig(start).getEmailVerificationTokensTable()
+ " WHERE app_id = ? AND user_id = ?";

update(sqlCon, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, userId);
});
}
}

public static boolean deleteUserInfo(Start start, TenantIdentifier tenantIdentifier, String userId)
throws StorageQueryException, SQLException {
String QUERY = "DELETE FROM " + getConfig(start).getEmailVerificationTokensTable()
Expand Down
Loading

0 comments on commit bb7064a

Please sign in to comment.