Skip to content

Commit

Permalink
Merge branch 'feat/bulk-import-api' into feat/bulk-import-api-1
Browse files Browse the repository at this point in the history
  • Loading branch information
anku255 committed Feb 27, 2024
2 parents b919311 + 93336d8 commit 039958c
Show file tree
Hide file tree
Showing 17 changed files with 172 additions and 60 deletions.
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [5.0.0] - 2023-11-29

- Replace `TotpNotEnabledException` with `UnknownUserTotpIdException`
- ActiveUsersSQLStorage interface changes
- Adds `deleteUserActive_Transaction` function
- ActiveUsersStorage interface changes
- Removes `countUsersEnabledTotp`, `countUsersEnabledTotpAndActiveSince` and `deleteUserActive_Transaction` functions
- Adds `countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince` function
- AuthRecipeStorage interface changes
- Adds `getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled` function
- TenantConfig changes
- Adds `firstFactors` and `requiredSecondaryFactors` fields
- Adds `createdAt` field to `TOTPDevice`
- TOTPSQLStorage interface changes
- Adds `getDeviceByName_Transaction` and `createDevice_Transaction` functions
- 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

## [4.0.5] - 2023-12-05

- Adds `InvalidConfigException` to throws list of `canBeUsed` function
Expand Down Expand Up @@ -88,7 +107,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.22.0] - 2023-03-30

- Adds Support for Dashboard Search
- Adds Support for Dashboard Search

## [2.21.0] - 2023-03-27

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
id 'java-library'
}

version = "4.0.5"
version = "5.0.0"

repositories {
mavenCentral()
Expand Down
Binary file added jar/plugin-interface-2.23.0.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* You may not use this file except in compliance with the License. You may
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* 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.pluginInterface;

import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
import io.supertokens.pluginInterface.sqlStorage.SQLStorage;
import io.supertokens.pluginInterface.sqlStorage.TransactionConnection;

public interface ActiveUsersSQLStorage extends ActiveUsersStorage, SQLStorage {
/* Delete a user from active users table */
void deleteUserActive_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId)
throws StorageQueryException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
import io.supertokens.pluginInterface.nonAuthRecipe.NonAuthRecipeStorage;
import io.supertokens.pluginInterface.sqlStorage.TransactionConnection;

public interface ActiveUsersStorage extends NonAuthRecipeStorage {
/* Update the last active time of a user to now */
Expand All @@ -12,14 +11,7 @@ public interface ActiveUsersStorage extends NonAuthRecipeStorage {
/* Count the number of users who did some activity after given timestamp */
int countUsersActiveSince(AppIdentifier appIdentifier, long time) throws StorageQueryException;

/* Count the number of users who have enabled TOTP */
int countUsersEnabledTotp(AppIdentifier appIdentifier) throws StorageQueryException;

/* Count the number of users who have enabled TOTP and are active */
int countUsersEnabledTotpAndActiveSince(AppIdentifier appIdentifier, long time) throws StorageQueryException;

void deleteUserActive_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId)
throws StorageQueryException;

int countUsersThatHaveMoreThanOneLoginMethodAndActiveSince(AppIdentifier appIdentifier, long sinceTime) throws StorageQueryException;

int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(AppIdentifier appIdentifier, long timestamp) throws StorageQueryException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public enum RECIPE_ID {
EMAIL_PASSWORD("emailpassword"), THIRD_PARTY("thirdparty"), SESSION("session"),
EMAIL_VERIFICATION("emailverification"), JWT("jwt"), PASSWORDLESS("passwordless"), USER_METADATA("usermetadata"),
USER_ROLES("userroles"), USER_ID_MAPPING("useridmapping"), DASHBOARD("dashboard"), TOTP("totp"),
MULTITENANCY("multitenancy"), ACCOUNT_LINKING("accountlinking");
MULTITENANCY("multitenancy"), ACCOUNT_LINKING("accountlinking"), MFA("mfa");

private final String name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,6 @@ AuthRecipeUserInfo getPrimaryUserByThirdPartyInfo(TenantIdentifier tenantIdentif
boolean checkIfUsesAccountLinking(AppIdentifier appIdentifier) throws StorageQueryException;

int getUsersCountWithMoreThanOneLoginMethod(AppIdentifier appIdentifier) throws StorageQueryException;

int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(AppIdentifier appIdentifier) throws StorageQueryException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package io.supertokens.pluginInterface.multitenancy;

import io.supertokens.pluginInterface.ActiveUsersStorage;
import io.supertokens.pluginInterface.ActiveUsersSQLStorage;
import io.supertokens.pluginInterface.STORAGE_TYPE;
import io.supertokens.pluginInterface.Storage;
import io.supertokens.pluginInterface.authRecipe.AuthRecipeStorage;
Expand Down Expand Up @@ -153,12 +153,12 @@ public TOTPSQLStorage getTOTPStorage() {
return (TOTPSQLStorage) this.storage;
}

public ActiveUsersStorage getActiveUsersStorage() {
public ActiveUsersSQLStorage getActiveUsersStorage() {
if (this.storage.getType() != STORAGE_TYPE.SQL) {
// we only support SQL for now
throw new UnsupportedOperationException("");
}
return (ActiveUsersStorage) this.storage;
return (ActiveUsersSQLStorage) this.storage;
}

public BulkImportStorage getBulkImportStorage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
import io.supertokens.pluginInterface.Storage;
import io.supertokens.pluginInterface.utils.Utils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand All @@ -41,17 +42,29 @@ public class TenantConfig {
@SerializedName("passwordless")
public final PasswordlessConfig passwordlessConfig;

@Nullable
@SerializedName("firstFactors")
public final String[] firstFactors;

@Nullable
@SerializedName("requiredSecondaryFactors")
public final String[] requiredSecondaryFactors;

@Nonnull
public final JsonObject coreConfig;

public TenantConfig(@Nonnull TenantIdentifier tenantIdentifier, @Nonnull EmailPasswordConfig emailPasswordConfig,
@Nonnull ThirdPartyConfig thirdPartyConfig,
@Nonnull PasswordlessConfig passwordlessConfig, @Nullable JsonObject coreConfig) {
@Nonnull PasswordlessConfig passwordlessConfig,
@Nullable String[] firstFactors, @Nullable String[] requiredSecondaryFactors,
@Nullable JsonObject coreConfig) {
this.tenantIdentifier = tenantIdentifier;
this.coreConfig = coreConfig == null ? new JsonObject() : coreConfig;
this.emailPasswordConfig = emailPasswordConfig;
this.passwordlessConfig = passwordlessConfig;
this.thirdPartyConfig = thirdPartyConfig;
this.firstFactors = firstFactors == null || firstFactors.length == 0 ? null : firstFactors;
this.requiredSecondaryFactors = requiredSecondaryFactors == null || requiredSecondaryFactors.length == 0 ? null : requiredSecondaryFactors;
}

public TenantConfig(TenantConfig other) {
Expand All @@ -62,6 +75,8 @@ public TenantConfig(TenantConfig other) {
this.emailPasswordConfig = new EmailPasswordConfig(other.emailPasswordConfig.enabled);
this.passwordlessConfig = new PasswordlessConfig(other.passwordlessConfig.enabled);
this.thirdPartyConfig = new ThirdPartyConfig(other.thirdPartyConfig.enabled, other.thirdPartyConfig.providers.clone());
this.firstFactors = other.firstFactors == null ? null : other.firstFactors.clone();
this.requiredSecondaryFactors = other.requiredSecondaryFactors == null ? null : other.requiredSecondaryFactors.clone();
}

public boolean deepEquals(TenantConfig other) {
Expand All @@ -72,6 +87,8 @@ public boolean deepEquals(TenantConfig other) {
this.emailPasswordConfig.equals(other.emailPasswordConfig) &&
this.passwordlessConfig.equals(other.passwordlessConfig) &&
this.thirdPartyConfig.equals(other.thirdPartyConfig) &&
Utils.unorderedArrayEquals(this.firstFactors, other.firstFactors) && // order is not important
Utils.unorderedArrayEquals(this.requiredSecondaryFactors, other.requiredSecondaryFactors) && // order is not important
this.coreConfig.equals(other.coreConfig);
}

Expand All @@ -94,9 +111,16 @@ public JsonObject toJson(boolean shouldProtectDbConfig, Storage storage, String[
JsonObject tenantConfigObject = gson.toJsonTree(this).getAsJsonObject();

tenantConfigObject.add("thirdParty", this.thirdPartyConfig.toJson());

tenantConfigObject.addProperty("tenantId", this.tenantIdentifier.getTenantId());

if (tenantConfigObject.has("firstFactors") && tenantConfigObject.get("firstFactors").getAsJsonArray().size() == 0) {
tenantConfigObject.remove("firstFactors");
}

if (tenantConfigObject.has("requiredSecondaryFactors") && tenantConfigObject.get("requiredSecondaryFactors").getAsJsonArray().size() == 0) {
tenantConfigObject.remove("requiredSecondaryFactors");
}

if (shouldProtectDbConfig) {
String[] protectedConfigs = storage.getProtectedConfigsFromSuperTokensSaaSUsers();
for (String config : protectedConfigs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public TOTPSQLStorage getTOTPStorage() {
}
return (TOTPSQLStorage) this.storage;
}

public MultitenancyStorage getMultitenancyStorageWithTargetStorage() {
if (this.storage.getType() != STORAGE_TYPE.SQL) {
// we only support SQL for now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.supertokens.pluginInterface.utils.Utils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -48,38 +49,6 @@ public JsonObject toJson() {
return result;
}

public static boolean unorderedArrayEquals(Object[] array1, Object[] array2) {
if (array1 == null && array2 == null) {
return true;
} else if (array1 == null || array2 == null) {
return false;
}

List<Object> items1 = List.of(array1);
List<Object> items2 = new ArrayList<>();
items2.addAll(Arrays.asList(array2));

if (items1.size() != items2.size()) return false;

for (Object p1 : items1) {
boolean found = false;
for (Object p2 : items2) {
if (p1.equals(p2)) {
found = true;
break;
}
}

if (!found) {
return false;
} else {
items2.remove(p1);
}
}

return true;
}

public static class Provider {

@Nonnull
Expand Down Expand Up @@ -189,7 +158,7 @@ public boolean equals(Object other) {
Provider otherProvider = (Provider) other;
return Objects.equals(otherProvider.thirdPartyId, this.thirdPartyId) &&
Objects.equals(otherProvider.name, this.name) &&
unorderedArrayEquals(otherProvider.clients, this.clients) &&
Utils.unorderedArrayEquals(otherProvider.clients, this.clients) &&
Objects.equals(otherProvider.authorizationEndpoint, this.authorizationEndpoint) &&
Objects.equals(otherProvider.authorizationEndpointQueryParams,
this.authorizationEndpointQueryParams) &&
Expand Down Expand Up @@ -245,7 +214,7 @@ public boolean equals(Object other) {
return Objects.equals(otherProviderClient.clientType, this.clientType) &&
otherProviderClient.clientId.equals(this.clientId) &&
Objects.equals(otherProviderClient.clientSecret, this.clientSecret) &&
unorderedArrayEquals(otherProviderClient.scope, this.scope) &&
Utils.unorderedArrayEquals(otherProviderClient.scope, this.scope) &&
otherProviderClient.forcePKCE == this.forcePKCE &&
Objects.equals(otherProviderClient.additionalConfig, this.additionalConfig);
}
Expand Down Expand Up @@ -310,7 +279,7 @@ public boolean equals(Object other) {
if (other instanceof ThirdPartyConfig) {
ThirdPartyConfig otherThirdPartyConfig = (ThirdPartyConfig) other;
return otherThirdPartyConfig.enabled == this.enabled &&
unorderedArrayEquals(otherThirdPartyConfig.providers, this.providers);
Utils.unorderedArrayEquals(otherThirdPartyConfig.providers, this.providers);
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ public interface SessionNoSQLStorage_1 extends SessionStorage, NoSQLStorage_1 {
SessionInfoWithLastUpdated getSessionInfo_Transaction(String sessionHandle) throws StorageQueryException;

boolean updateSessionInfo_Transaction(String sessionHandle, String refreshTokenHash2, long expiry,
String lastUpdatedSign) throws StorageQueryException;
String lastUpdatedSign, boolean useStaticKey) throws StorageQueryException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ SessionInfo getSessionInfo_Transaction(TenantIdentifier tenantIdentifier, Transa

void updateSessionInfo_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con,
String sessionHandle, String refreshTokenHash2,
long expiry) throws StorageQueryException;
long expiry, boolean useStaticKey) throws StorageQueryException;

void deleteSessionsOfUser_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId)
throws StorageQueryException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ public class TOTPDevice {
public final int period;
public final int skew;
public final boolean verified;
public final long createdAt;

public TOTPDevice(String userId, String deviceName, String secretKey, int period,
int skew, boolean verified) {
int skew, boolean verified, long createdAt) {
this.userId = userId;
this.deviceName = deviceName;
this.secretKey = secretKey;
this.period = period;
this.skew = skew;
this.verified = verified;
this.createdAt = createdAt;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package io.supertokens.pluginInterface.totp.exception;

public class TotpNotEnabledException extends Exception {
public class UnknownTotpUserIdException extends Exception {
private static final long serialVersionUID = 6848053563771647272L;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
import io.supertokens.pluginInterface.totp.TOTPDevice;
import io.supertokens.pluginInterface.totp.TOTPStorage;
import io.supertokens.pluginInterface.totp.TOTPUsedCode;
import io.supertokens.pluginInterface.totp.exception.TotpNotEnabledException;
import io.supertokens.pluginInterface.totp.exception.DeviceAlreadyExistsException;
import io.supertokens.pluginInterface.totp.exception.UsedCodeAlreadyExistsException;
import io.supertokens.pluginInterface.totp.exception.UnknownTotpUserIdException;

public interface TOTPSQLStorage extends TOTPStorage, SQLStorage {
public int deleteDevice_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId,
Expand Down Expand Up @@ -38,7 +39,11 @@ public TOTPUsedCode[] getAllUsedCodesDescOrder_Transaction(TransactionConnection
* Insert a used TOTP code for an existing user:
*/
void insertUsedCode_Transaction(TransactionConnection con, TenantIdentifier tenantIdentifier, TOTPUsedCode code)
throws StorageQueryException, TotpNotEnabledException, UsedCodeAlreadyExistsException,
throws StorageQueryException, UnknownTotpUserIdException, UsedCodeAlreadyExistsException,
TenantOrAppNotFoundException;

TOTPDevice getDeviceByName_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId, String deviceName) throws StorageQueryException;

TOTPDevice createDevice_Transaction(TransactionConnection con, AppIdentifier appIdentifier, TOTPDevice device)
throws StorageQueryException, DeviceAlreadyExistsException, TenantOrAppNotFoundException;
}
Loading

0 comments on commit 039958c

Please sign in to comment.