Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feat/mfa' into feat/bulk-import-api
Browse files Browse the repository at this point in the history
  • Loading branch information
anku255 committed Feb 27, 2024
1 parent b7fdaeb commit 439d2b6
Show file tree
Hide file tree
Showing 117 changed files with 6,503 additions and 1,017 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [8.0.0] - 2023-11-29

### Added

- Supports CDI version `5.0`
- MFA stats in `EEFeatureFlag`
- Adds `ImportTotpDeviceAPI`

### Changes

- `deviceName` in request body of `CreateOrUpdateTotpDeviceAPI` `POST` is now optional
- Adds `firstFactors` and `requiredSecondaryFactors` in request body of create or update CUD, App and
Tenant APIs
- Adds `deviceName` in the response of `CreateOrUpdateTotpDeviceAPI` `POST`
- `VerifyTOTPAPI` changes
- Removes `allowUnverifiedDevices` from request body and unverified devices are not allowed
- Adds `currentNumberOfFailedAttempts` and `maxNumberOfFailedAttempts` in response when status is
`INVALID_TOTP_ERROR` or `LIMIT_REACHED_ERROR`
- Adds status `UNKNOWN_USER_ID_ERROR`
- `VerifyTotpDeviceAPI` changes
- Adds `currentNumberOfFailedAttempts` and `maxNumberOfFailedAttempts` in response when status is
`INVALID_TOTP_ERROR` or `LIMIT_REACHED_ERROR`
- Adds a new required `useDynamicSigningKey` into the request body of `RefreshSessionAPI`
- This enables smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to
change the signing key type of a session

### Migration

- TODO - copy once postgres / mysql changelog is done

## [7.0.18] - 2024-02-19

- Fixes vulnerabilities in dependencies
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" }
// }
//}

version = "7.0.18"
version = "8.0.0"


repositories {
Expand Down
5 changes: 3 additions & 2 deletions coreDriverInterfaceSupported.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"2.20",
"2.21",
"3.0",
"4.0"
"4.0",
"5.0"
]
}
}
59 changes: 28 additions & 31 deletions ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,43 +185,39 @@ private JsonObject getDashboardLoginStats() throws TenantOrAppNotFoundException,
return stats;
}

private JsonObject getTOTPStats() throws StorageQueryException, TenantOrAppNotFoundException {
JsonObject totpStats = new JsonObject();
JsonArray totpMauArr = new JsonArray();
private boolean isEnterpriseThirdPartyId(String thirdPartyId) {
for (String enterpriseThirdPartyId : ENTERPRISE_THIRD_PARTY_IDS) {
if (thirdPartyId.startsWith(enterpriseThirdPartyId)) {
return true;
}
}
return false;
}

private JsonObject getMFAStats() throws StorageQueryException, TenantOrAppNotFoundException{
// TODO: Active users are present only on public tenant and MFA users may be present on different storages
JsonObject result = new JsonObject();
Storage[] storages = StorageLayer.getStoragesForApp(main, this.appIdentifier);

// TODO Active users are present only on public tenant and TOTP users may be present on different storages
Storage publicTenantStorage = StorageLayer.getStorage(this.appIdentifier.getAsPublicTenantIdentifier(), main);
final long now = System.currentTimeMillis();
for (int i = 1; i <= 31; i++) {
long timestamp = now - (i * 24 * 60 * 60 * 1000L);

int totpMau = 0;
// TODO Need to figure out a way to combine the data from different storages to get the final stats
// for (Storage storage : storages) {
totpMau += ((ActiveUsersStorage) publicTenantStorage).countUsersEnabledTotpAndActiveSince(this.appIdentifier, timestamp);
// }
totpMauArr.add(new JsonPrimitive(totpMau));
}
int totalUserCountWithMoreThanOneLoginMethod = 0;
int[] maus = new int[31];

totpStats.add("maus", totpMauArr);
long now = System.currentTimeMillis();

int totpTotalUsers = 0;
for (Storage storage : storages) {
totpTotalUsers += ((ActiveUsersStorage) storage).countUsersEnabledTotp(this.appIdentifier);
}
totpStats.addProperty("total_users", totpTotalUsers);
return totpStats;
}
totalUserCountWithMoreThanOneLoginMethod += ((AuthRecipeStorage)storage).getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(this.appIdentifier);

private boolean isEnterpriseThirdPartyId(String thirdPartyId) {
for (String enterpriseThirdPartyId : ENTERPRISE_THIRD_PARTY_IDS) {
if (thirdPartyId.startsWith(enterpriseThirdPartyId)) {
return true;
for (int i = 1; i <= 31; i++) {
long timestamp = now - (i * 24 * 60 * 60 * 1000L);

// `maus[i-1]` since i starts from 1
maus[i-1] += ((ActiveUsersStorage)storage).countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(appIdentifier, timestamp);
}
}
return false;

result.addProperty("totalUserCountWithMoreThanOneLoginMethodOrTOTPEnabled", totalUserCountWithMoreThanOneLoginMethod);
result.add("mauWithMoreThanOneLoginMethodOrTOTPEnabled", new Gson().toJsonTree(maus));
return result;
}

private JsonObject getMultiTenancyStats()
Expand Down Expand Up @@ -272,6 +268,7 @@ private JsonObject getMultiTenancyStats()
}

private JsonObject getAccountLinkingStats() throws StorageQueryException {
// TODO: Active users are present only on public tenant and MFA users may be present on different storages
JsonObject result = new JsonObject();
Storage[] storages = StorageLayer.getStoragesForApp(main, this.appIdentifier);
boolean usesAccountLinking = false;
Expand Down Expand Up @@ -355,8 +352,8 @@ public JsonObject getPaidFeatureStats() throws StorageQueryException, TenantOrAp
usageStats.add(EE_FEATURES.DASHBOARD_LOGIN.toString(), getDashboardLoginStats());
}

if (feature == EE_FEATURES.TOTP) {
usageStats.add(EE_FEATURES.TOTP.toString(), getTOTPStats());
if (feature == EE_FEATURES.MFA) {
usageStats.add(EE_FEATURES.MFA.toString(), getMFAStats());
}

if (feature == EE_FEATURES.MULTI_TENANCY) {
Expand Down Expand Up @@ -570,4 +567,4 @@ public static void resetLisenseCheckRequests() {
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public void testPaidStatsIsSentForAllAppsInMultitenancy() throws Exception {
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
null, null,
config
), false);

Expand All @@ -86,6 +87,7 @@ public void testPaidStatsIsSentForAllAppsInMultitenancy() throws Exception {
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
null, null,
config
), false);

Expand All @@ -94,6 +96,7 @@ public void testPaidStatsIsSentForAllAppsInMultitenancy() throws Exception {
new EmailPasswordConfig(true),
new ThirdPartyConfig(true, null),
new PasswordlessConfig(true),
null, null,
config
), false);
}
Expand Down
Binary file added jar/core-5.0.0.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion pluginInterfaceSupported.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"_comment": "contains a list of plugin interfaces branch names that this core supports",
"versions": [
"4.0"
"5.0"
]
}
6 changes: 3 additions & 3 deletions src/main/java/io/supertokens/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ private void init() throws IOException, StorageQueryException {
throw new QuitProgramException(e);
}

// loading version file
Version.loadVersion(this, CLIOptions.get(this).getInstallationPath() + "version.yaml");

Logging.info(this, TenantIdentifier.BASE_TENANT, "Completed config.yaml loading.", true);

// loading storage layer
Expand All @@ -167,9 +170,6 @@ private void init() throws IOException, StorageQueryException {
throw new QuitProgramException(e);
}

// loading version file
Version.loadVersion(this, CLIOptions.get(this).getInstallationPath() + "version.yaml");

// init file logging
Logging.initFileLogging(this);

Expand Down
7 changes: 4 additions & 3 deletions src/main/java/io/supertokens/authRecipe/AuthRecipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public static LinkAccountsResult linkAccounts(Main main, AppIdentifierWithStorag
UnknownUserIdException, TenantOrAppNotFoundException, FeatureNotEnabledException {

if (Arrays.stream(FeatureFlag.getInstance(main, appIdentifierWithStorage).getEnabledFeatures())
.noneMatch(t -> t == EE_FEATURES.ACCOUNT_LINKING)) {
.noneMatch(t -> (t == EE_FEATURES.ACCOUNT_LINKING || t == EE_FEATURES.MFA))) {
throw new FeatureNotEnabledException(
"Account linking feature is not enabled for this app. Please contact support to enable it.");
}
Expand Down Expand Up @@ -544,7 +544,7 @@ public static CreatePrimaryUserResult createPrimaryUser(Main main,
FeatureNotEnabledException {

if (Arrays.stream(FeatureFlag.getInstance(main, appIdentifierWithStorage).getEnabledFeatures())
.noneMatch(t -> t == EE_FEATURES.ACCOUNT_LINKING)) {
.noneMatch(t -> (t == EE_FEATURES.ACCOUNT_LINKING || t == EE_FEATURES.MFA))) {
throw new FeatureNotEnabledException(
"Account linking feature is not enabled for this app. Please contact support to enable it.");
}
Expand Down Expand Up @@ -934,7 +934,6 @@ private static void deleteNonAuthRecipeUser(TransactionConnection con, AppIdenti
.deleteAllRolesForUser_Transaction(con, appIdentifierWithStorage, userId);
appIdentifierWithStorage.getActiveUsersStorage()
.deleteUserActive_Transaction(con, appIdentifierWithStorage, userId);
appIdentifierWithStorage.getTOTPStorage().removeUser_Transaction(con, appIdentifierWithStorage, userId);
}

private static void deleteAuthRecipeUser(TransactionConnection con,
Expand Down Expand Up @@ -975,6 +974,8 @@ public static boolean deleteNonAuthRecipeUser(TenantIdentifierWithStorage
.removeUser(tenantIdentifierWithStorage, userId);
finalDidExist = finalDidExist || didExist;

finalDidExist = finalDidExist || didExist;

return finalDidExist;
}

Expand Down
29 changes: 27 additions & 2 deletions src/main/java/io/supertokens/emailpassword/EmailPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,39 @@ public static AuthRecipeUserInfo signUp(TenantIdentifierWithStorage tenantIdenti
.createHashWithSalt(tenantIdentifierWithStorage.toAppIdentifier(), password);

while (true) {

String userId = Utils.getUUID();
long timeJoined = System.currentTimeMillis();

try {
return tenantIdentifierWithStorage.getEmailPasswordStorage()
AuthRecipeUserInfo newUser = tenantIdentifierWithStorage.getEmailPasswordStorage()
.signUp(tenantIdentifierWithStorage, userId, email, hashedPassword, timeJoined);

if (Utils.isFakeEmail(email)) {
try {
tenantIdentifierWithStorage.getEmailVerificationStorage().startTransaction(con -> {
try {

tenantIdentifierWithStorage.getEmailVerificationStorage()
.updateIsEmailVerified_Transaction(tenantIdentifierWithStorage.toAppIdentifier(), con,
newUser.getSupertokensUserId(), email, true);
tenantIdentifierWithStorage.getEmailVerificationStorage()
.commitTransaction(con);

return null;
} catch (TenantOrAppNotFoundException e) {
throw new StorageTransactionLogicException(e);
}
});
newUser.loginMethods[0].setVerified(); // newly created user has only one loginMethod
} catch (StorageTransactionLogicException e) {
if (e.actualException instanceof TenantOrAppNotFoundException) {
throw (TenantOrAppNotFoundException) e.actualException;
}
throw new StorageQueryException(e);
}
}

return newUser;
} catch (DuplicateUserIdException ignored) {
// we retry with a new userId (while loop)
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/io/supertokens/featureflag/EE_FEATURES.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@

public enum EE_FEATURES {
ACCOUNT_LINKING("account_linking"), MULTI_TENANCY("multi_tenancy"), TEST("test"),
DASHBOARD_LOGIN("dashboard_login"),
TOTP("totp");
DASHBOARD_LOGIN("dashboard_login"), MFA("mfa");

private final String name;

Expand Down
Loading

0 comments on commit 439d2b6

Please sign in to comment.