diff --git a/CHANGELOG.md b/CHANGELOG.md index 8003eac..f3cdbe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [4.0.5] - 2024-03-29 + +- Fixes user id mapping queries +- Adds a new `useStaticKey` param to `updateSessionInfo_Transaction` + - This enables smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to + change the signing key type of a session +- Fixes performance issue with user pagination + ## [4.0.4] - 2024-02-20 - Fixes vulnerabilities in dependencies diff --git a/build.gradle b/build.gradle index 5db4122..97ee992 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java-library' } -version = "4.0.4" +version = "4.0.5" repositories { mavenCentral() diff --git a/src/main/java/io/supertokens/storage/mysql/Start.java b/src/main/java/io/supertokens/storage/mysql/Start.java index be1b6af..dc23958 100644 --- a/src/main/java/io/supertokens/storage/mysql/Start.java +++ b/src/main/java/io/supertokens/storage/mysql/Start.java @@ -611,11 +611,11 @@ public SessionInfo getSessionInfo_Transaction(TenantIdentifier tenantIdentifier, @Override public void updateSessionInfo_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, String sessionHandle, String refreshTokenHash2, - long expiry) throws StorageQueryException { + long expiry, boolean useStaticKey) throws StorageQueryException { Connection sqlCon = (Connection) con.getConnection(); try { SessionQueries.updateSessionInfo_Transaction(this, sqlCon, tenantIdentifier, sessionHandle, - refreshTokenHash2, expiry); + refreshTokenHash2, expiry, useStaticKey); } catch (SQLException e) { throw new StorageQueryException(e); } @@ -2188,10 +2188,10 @@ public boolean updateOrDeleteExternalUserIdInfo(AppIdentifier appIdentifier, Str } @Override - public HashMap getUserIdMappingForSuperTokensIds(ArrayList userIds) + public HashMap getUserIdMappingForSuperTokensIds(AppIdentifier appIdentifier, ArrayList userIds) throws StorageQueryException { try { - return UserIdMappingQueries.getUserIdMappingWithUserIds(this, userIds); + return UserIdMappingQueries.getUserIdMappingWithUserIds(this, appIdentifier, userIds); } catch (SQLException e) { throw new StorageQueryException(e); } diff --git a/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java index 28c7516..d98aa4a 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java @@ -699,8 +699,12 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant usersFromQuery = new ArrayList<>(); } else { + // This query is slightly different from one in postgres because we want to use same ordering for + // primary_or_recipe_user_time_joined and primary_or_recipe_user_id because mysql 5.7 does not support + // different ordering for different columns using an index String finalQuery = "SELECT * FROM ( " + USER_SEARCH_TAG_CONDITION.toString() + " )" - + " AS finalResultTable ORDER BY time_joined " + timeJoinedOrder + ", user_id DESC "; + + " AS finalResultTable ORDER BY time_joined " + timeJoinedOrder + + ", user_id " + timeJoinedOrder; usersFromQuery = execute(start, finalQuery, pst -> { for (int i = 1; i <= queryList.size(); i++) { pst.setString(i, queryList.get(i - 1)); @@ -738,11 +742,14 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant recipeIdCondition = recipeIdCondition + " AND"; } String timeJoinedOrderSymbol = timeJoinedOrder.equals("ASC") ? ">" : "<"; + // This query is slightly different from one in postgres because we want to use same ordering for + // primary_or_recipe_user_time_joined and primary_or_recipe_user_id because mysql 5.7 does not support + // different ordering for different columns using an index String QUERY = "SELECT user_id, recipe_id FROM " + Config.getConfig(start).getUsersTable() + " WHERE " + recipeIdCondition + " (time_joined " + timeJoinedOrderSymbol - + " ? OR (time_joined = ? AND user_id <= ?)) AND app_id = ? AND tenant_id = ?" + + " ? OR (time_joined = ? AND user_id " + timeJoinedOrderSymbol +"= ?)) AND app_id = ? AND tenant_id = ?" + " ORDER BY time_joined " + timeJoinedOrder - + ", user_id DESC LIMIT ?"; + + ", user_id " + timeJoinedOrderSymbol + " LIMIT ?"; usersFromQuery = execute(start, QUERY, pst -> { if (includeRecipeIds != null) { for (int i = 0; i < includeRecipeIds.length; i++) { @@ -767,12 +774,15 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant }); } else { String recipeIdCondition = RECIPE_ID_CONDITION.toString(); + // This query is slightly different from one in postgres because we want to use same ordering for + // primary_or_recipe_user_time_joined and primary_or_recipe_user_id because mysql 5.7 does not support + // different ordering for different columns using an index String QUERY = "SELECT user_id, recipe_id FROM " + Config.getConfig(start).getUsersTable() + " WHERE "; if (!recipeIdCondition.equals("")) { QUERY += recipeIdCondition + " AND"; } QUERY += " app_id = ? AND tenant_id = ? ORDER BY time_joined " + timeJoinedOrder - + ", user_id DESC LIMIT ?"; + + ", user_id " + timeJoinedOrder + " LIMIT ?"; usersFromQuery = execute(start, QUERY, pst -> { if (includeRecipeIds != null) { for (int i = 0; i < includeRecipeIds.length; i++) { diff --git a/src/main/java/io/supertokens/storage/mysql/queries/SessionQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/SessionQueries.java index f5d1f76..f588767 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/SessionQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/SessionQueries.java @@ -116,18 +116,19 @@ public static SessionInfo getSessionInfo_Transaction(Start start, Connection con public static void updateSessionInfo_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier, String sessionHandle, - String refreshTokenHash2, long expiry) + String refreshTokenHash2, long expiry, boolean useStaticKey) throws SQLException, StorageQueryException { String QUERY = "UPDATE " + Config.getConfig(start).getSessionInfoTable() - + " SET refresh_token_hash_2 = ?, expires_at = ?" + + " SET refresh_token_hash_2 = ?, expires_at = ?, use_static_key = ?" + " WHERE app_id = ? AND tenant_id = ? AND session_handle = ?"; update(con, QUERY, pst -> { pst.setString(1, refreshTokenHash2); pst.setLong(2, expiry); - pst.setString(3, tenantIdentifier.getAppId()); - pst.setString(4, tenantIdentifier.getTenantId()); - pst.setString(5, sessionHandle); + pst.setBoolean(3, useStaticKey); + pst.setString(4, tenantIdentifier.getAppId()); + pst.setString(5, tenantIdentifier.getTenantId()); + pst.setString(6, sessionHandle); }); } diff --git a/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java index f6c2cf0..2b43f45 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java @@ -115,7 +115,8 @@ public static UserIdMapping[] getUserIdMappingWithEitherSuperTokensUserIdOrExter } - public static HashMap getUserIdMappingWithUserIds(Start start, ArrayList userIds) + public static HashMap getUserIdMappingWithUserIds(Start start, AppIdentifier appIdentifier, + ArrayList userIds) throws SQLException, StorageQueryException { if (userIds.size() == 0) { @@ -134,9 +135,10 @@ public static HashMap getUserIdMappingWithUserIds(Start start, A } QUERY.append(")"); return execute(start, QUERY.toString(), pst -> { + pst.setString(1, appIdentifier.getAppId()); for (int i = 0; i < userIds.size(); i++) { - // i+1 cause this starts with 1 and not 0 - pst.setString(i + 1, userIds.get(i)); + // i+2 cause this starts with 1 and not 0, and 1 is the app_id + pst.setString(i + 2, userIds.get(i)); } }, result -> { HashMap userIdMappings = new HashMap<>();