diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 3e09e87d1..a5409684e 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -120,10 +120,10 @@ labels: - [ ] check if new env cnofigs need to be added - [ ] try.supertokens.io ``` - docker rm try-supertokens -f - docker rmi supertokens/supertokens-postgresql: - nano ~/try-supertokens/start_container.sh (update version tag) - ~/try-supertokens/start_container.sh + sudo docker rm try-supertokens -f + sudo docker rmi supertokens/supertokens-postgresql: + nano ./start_container.sh (update version tag) + sudo ./start_container.sh ``` - [ ] Run tests against node sdk (all compatible versions) - [ ] Run tests against python sdk (all compatible versions) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26b42640d..40c0ded73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ 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). -## Unreleased +## [Unreleased] ### Changes @@ -24,9 +24,19 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Adds PATCH `/recipe/oauth/clients` for OAuth2 client update ### Migration + TODO: after plugin support -## [9.1.1] -2024-07-24 +## [9.2.0] - 2024-08-20 + +- Adds `SECURITY` feature in `EE_FEATURES`. + +## [9.1.2] - 2024-07-24 + +- Fixes path routing which rejected tenantId stop words even if it was not an exact stop word match. For example, `/hellotenant` is a valid tenantId prefix, however, it was being rejected for the stop word `hello`. - https://github.com/supertokens/supertokens-core/issues/1021 +- 500 errors in core returns actual exception, since these APIs are developer facing, it makes easier to debug these errors. + +## [9.1.1] - 2024-07-24 ### Fixes diff --git a/build.gradle b/build.gradle index c1aa06140..b2f1a910d 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" } // } //} -version = "9.1.1" +version = "9.2.0" repositories { diff --git a/cli/jar/cli.jar b/cli/jar/cli.jar index d5f5d1b5f..4d82d2732 100644 Binary files a/cli/jar/cli.jar and b/cli/jar/cli.jar differ diff --git a/downloader/jar/downloader.jar b/downloader/jar/downloader.jar index 685d7af56..0ff7c3df9 100644 Binary files a/downloader/jar/downloader.jar and b/downloader/jar/downloader.jar differ diff --git a/ee/jar/ee.jar b/ee/jar/ee.jar index 01904dc55..5b0af492a 100644 Binary files a/ee/jar/ee.jar and b/ee/jar/ee.jar differ diff --git a/ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java b/ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java index 202de8626..4c959f6f8 100644 --- a/ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java +++ b/ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java @@ -391,6 +391,10 @@ public JsonObject getPaidFeatureStats() throws StorageQueryException, TenantOrAp if (feature == EE_FEATURES.ACCOUNT_LINKING) { usageStats.add(EE_FEATURES.ACCOUNT_LINKING.toString(), getAccountLinkingStats()); } + + if (feature == EE_FEATURES.SECURITY) { + usageStats.add(EE_FEATURES.SECURITY.toString(), new JsonObject()); + } } usageStats.add("maus", getMAUs()); diff --git a/jar/core-9.1.1.jar b/jar/core-9.2.0.jar similarity index 92% rename from jar/core-9.1.1.jar rename to jar/core-9.2.0.jar index 1fec95195..8208f5d3a 100644 Binary files a/jar/core-9.1.1.jar and b/jar/core-9.2.0.jar differ diff --git a/src/main/java/io/supertokens/featureflag/EE_FEATURES.java b/src/main/java/io/supertokens/featureflag/EE_FEATURES.java index e8b23c2de..8708b883f 100644 --- a/src/main/java/io/supertokens/featureflag/EE_FEATURES.java +++ b/src/main/java/io/supertokens/featureflag/EE_FEATURES.java @@ -18,7 +18,7 @@ public enum EE_FEATURES { ACCOUNT_LINKING("account_linking"), MULTI_TENANCY("multi_tenancy"), TEST("test"), - DASHBOARD_LOGIN("dashboard_login"), MFA("mfa"), OAUTH("oauth"); + DASHBOARD_LOGIN("dashboard_login"), MFA("mfa"), SECURITY("security"), OAUTH("oauth"); private final String name; diff --git a/src/main/java/io/supertokens/webserver/PathRouter.java b/src/main/java/io/supertokens/webserver/PathRouter.java index 5e01d3d52..7bbc34099 100644 --- a/src/main/java/io/supertokens/webserver/PathRouter.java +++ b/src/main/java/io/supertokens/webserver/PathRouter.java @@ -35,7 +35,7 @@ public PathRouter(Main main) { } public void addAPI(WebserverAPI newApi) { - this.apis.add(newApi); + this.apis.add(0, newApi); // add to the front so that the most recent API is checked first for (WebserverAPI api : this.apis) { for (WebserverAPI api2 : this.apis) { if (api != api2 && api.getPath().equals(api2.getPath())) { @@ -82,10 +82,23 @@ private WebserverAPI getAPIThatMatchesPath(HttpServletRequest req) { apiPath = "/" + apiPath; } - String tenantIdStopWords = String.join("|", Utils.INVALID_WORDS_FOR_TENANTID); - if (requestPath.matches( - "^(/appid-[a-z0-9-]*)?(/(?!" + tenantIdStopWords + ")[a-z0-9-]+)?" + apiPath + "/?$")) { - return api; + if (apiPath.endsWith("/")) { + apiPath = apiPath.substring(0, apiPath.length() - 1); + } + + if (apiPath.isBlank()) { + String tenantIdStopWords = String.join("$|", Utils.INVALID_WORDS_FOR_TENANTID) + "$"; // Adds an end of string for each entry + tenantIdStopWords += "|" + String.join("/|", Utils.INVALID_WORDS_FOR_TENANTID) + "/"; // Adds a trailing slash for each entry + if (requestPath.matches( + "^(/appid-[a-z0-9-]*)?(/(?!" + tenantIdStopWords + ")[a-z0-9-]+)?" + "/?$")) { + return api; + } + } else { + String tenantIdStopWords = String.join("/|", Utils.INVALID_WORDS_FOR_TENANTID) + "/"; // Adds a trailing slash for each entry + if (requestPath.matches( + "^(/appid-[a-z0-9-]*)?(/(?!" + tenantIdStopWords + ")[a-z0-9-]+)?" + apiPath + "/?$")) { + return api; + } } } for (WebserverAPI api : this.apis) { diff --git a/src/main/java/io/supertokens/webserver/WebserverAPI.java b/src/main/java/io/supertokens/webserver/WebserverAPI.java index 9f75474fb..558f91c26 100644 --- a/src/main/java/io/supertokens/webserver/WebserverAPI.java +++ b/src/main/java/io/supertokens/webserver/WebserverAPI.java @@ -263,16 +263,23 @@ private String getTenantId(HttpServletRequest req) { if (!apiPath.startsWith("/")) { apiPath = "/" + apiPath; } - if (apiPath.equals("/")) { - if (path.equals("") || path.equals("/")) { - return null; - } + if (apiPath.endsWith("/")) { + apiPath = apiPath.substring(0, apiPath.length() - 1); + } + + if (apiPath.isBlank() && (path.equals("") || path.equals("/"))) { + return null; } else { if (path.matches("^/appid-[a-z0-9-]*/[a-z0-9-]+" + apiPath + "/?$")) { String tenantId = path.split("/")[2].toLowerCase(); if (tenantId.equals(TenantIdentifier.DEFAULT_TENANT_ID)) { return null; } + + if (Utils.INVALID_WORDS_FOR_TENANTID.contains(tenantId)) { + return null; + } + return tenantId; } else if (path.matches("^/appid-[a-z0-9-]*" + apiPath + "/?$")) { return null; @@ -281,12 +288,16 @@ private String getTenantId(HttpServletRequest req) { if (tenantId.equals(TenantIdentifier.DEFAULT_TENANT_ID)) { return null; } + + if (Utils.INVALID_WORDS_FOR_TENANTID.contains(tenantId)) { + return null; + } + return tenantId; } else { return null; } } - return null; } private String getAppId(HttpServletRequest req) { @@ -295,10 +306,12 @@ private String getAppId(HttpServletRequest req) { if (!apiPath.startsWith("/")) { apiPath = "/" + apiPath; } - if (apiPath.equals("/")) { - if (path.equals("") || path.equals("/")) { - return null; - } + if (apiPath.endsWith("/")) { + apiPath = apiPath.substring(0, apiPath.length() - 1); + } + + if (apiPath.isBlank() && (path.equals("") || path.equals("/"))) { + return null; } else { if (path.matches("^/appid-[a-z0-9-]*(/[a-z0-9-]+)?" + apiPath + "/?$")) { String appId = path.split("/")[1].toLowerCase(); @@ -310,7 +323,6 @@ private String getAppId(HttpServletRequest req) { return null; } } - return null; } private String getConnectionUriDomain(HttpServletRequest req) throws ServletException { @@ -528,10 +540,10 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws } else if (rootCause instanceof BadPermissionException) { sendTextResponse(403, rootCause.getMessage(), resp); } else { - sendTextResponse(500, "Internal Error", resp); + sendTextResponse(500, rootCause.getMessage(), resp); } } else { - sendTextResponse(500, "Internal Error", resp); + sendTextResponse(500, e.getMessage(), resp); } } Logging.info(main, tenantIdentifier, "API ended: " + req.getRequestURI() + ". Method: " + req.getMethod(), diff --git a/src/main/java/io/supertokens/webserver/api/core/NotFoundOrHelloAPI.java b/src/main/java/io/supertokens/webserver/api/core/NotFoundOrHelloAPI.java index ce9acc90b..3894e2544 100644 --- a/src/main/java/io/supertokens/webserver/api/core/NotFoundOrHelloAPI.java +++ b/src/main/java/io/supertokens/webserver/api/core/NotFoundOrHelloAPI.java @@ -21,6 +21,7 @@ import io.supertokens.pluginInterface.Storage; import io.supertokens.pluginInterface.exceptions.StorageQueryException; import io.supertokens.pluginInterface.multitenancy.AppIdentifier; +import io.supertokens.pluginInterface.multitenancy.TenantIdentifier; import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException; import io.supertokens.storageLayer.StorageLayer; import io.supertokens.utils.RateLimiter; @@ -79,11 +80,29 @@ protected void handleRequest(HttpServletRequest req, HttpServletResponse resp) t appIdentifier = getAppIdentifier(req); storages = StorageLayer.getStoragesForApp(main, appIdentifier); } catch (TenantOrAppNotFoundException e) { - // we send 500 status code throw new ServletException(e); } - if (req.getServletPath().equals("/")) { + String path = req.getServletPath(); + TenantIdentifier tenantIdentifier = null; + try { + tenantIdentifier = getTenantIdentifier(req); + } catch (TenantOrAppNotFoundException e) { + super.sendTextResponse(404, "Not found", resp); + return; + } + + if (path.startsWith("/appid-")) { + path = path.replace("/appid-"+tenantIdentifier.getAppId(), ""); + } + + if (!tenantIdentifier.getTenantId().equals(TenantIdentifier.DEFAULT_TENANT_ID)) { + path = path.replace("/" + tenantIdentifier.getTenantId(), ""); + } else if (path.startsWith("/public") && tenantIdentifier.getTenantId().equals(TenantIdentifier.DEFAULT_TENANT_ID)) { + path = path.replace("/" + tenantIdentifier.getTenantId(), ""); + } + + if (path.equals("/") || path.isBlank()) { // API is app specific try { RateLimiter rateLimiter = RateLimiter.getInstance(appIdentifier, super.main, 200); diff --git a/src/test/java/io/supertokens/test/FeatureFlagTest.java b/src/test/java/io/supertokens/test/FeatureFlagTest.java index ac09c01f1..39f079c72 100644 --- a/src/test/java/io/supertokens/test/FeatureFlagTest.java +++ b/src/test/java/io/supertokens/test/FeatureFlagTest.java @@ -901,6 +901,9 @@ public void testNetworkCallIsMadeInCoreInit() throws Exception { private final String OPAQUE_KEY_WTIH_MFA_FEATURE = "F1a=1VUxo7-tHNqFDwuhkkCPCB378A57uRU4=rVW01XBv63YizRb6ItTBu" + "FHXQIvmceLTlOekCmHv7mwzEZJJKmO9N8pclQSbs4UBz8pzW5d107TIctJgBwy4upnBHUf"; + private final String OPAQUE_KEY_WITH_SECURITY_FEATURE = "tje5MVjlRz0Kwzax-mKksdYpZvwNhQagFdHj=ma=W0H7WET9R0Hcpv" + + "Aui9r3wIk=swO2TIBLQNa94y10VQkzAa0Q0iw6GPzMeftJ4uvbnb1qpGpyf4K0cUwIZ76Pd9kZ"; + @Test public void testPaidStatsContainsAllEnabledFeatures() throws Exception { String[] args = {"../"}; @@ -913,7 +916,8 @@ public void testPaidStatsContainsAllEnabledFeatures() throws Exception { OPAQUE_KEY_WITH_MULTITENANCY_FEATURE, OPAQUE_KEY_WITH_MFA_FEATURE, OPAQUE_KEY_WITH_DASHBOARD_FEATURE, - OPAQUE_KEY_WITH_ACCOUNT_LINKING_FEATURE + OPAQUE_KEY_WITH_ACCOUNT_LINKING_FEATURE, + OPAQUE_KEY_WITH_SECURITY_FEATURE, }; Set requiredFeatures = new HashSet<>(); diff --git a/src/test/java/io/supertokens/test/HelloAPITest.java b/src/test/java/io/supertokens/test/HelloAPITest.java index 0944b4d3a..fdd6ad3e3 100644 --- a/src/test/java/io/supertokens/test/HelloAPITest.java +++ b/src/test/java/io/supertokens/test/HelloAPITest.java @@ -149,6 +149,10 @@ public void testHelloAPIWithBasePath3() throws Exception { "http://localhost:3567/hello/appid-hello/hello", // baseUrl + app + /hello "http://localhost:3567/hello/appid-hello/hello/", // baseUrl + app + /hello "http://localhost:3567/hello/appid-hello/test/hello", // baseUrl + app + tenant + /hello + "http://localhost:3567/hello/appid-hello", // baseUrl + app + / + "http://localhost:3567/hello/appid-hello/", // baseUrl + app + / + "http://localhost:3567/hello/appid-hello/test", // baseUrl + app + tenant + / + "http://localhost:3567/hello/appid-hello/test/", // baseUrl + app + tenant + / }; for (String helloUrl : HELLO_ROUTES) { @@ -161,10 +165,7 @@ public void testHelloAPIWithBasePath3() throws Exception { } String[] NOT_FOUND_ROUTES = new String[]{ - "http://localhost:3567/hello/appid-hello", // baseUrl + app + / - "http://localhost:3567/hello/appid-hello/", // baseUrl + app + / - "http://localhost:3567/hello/appid-hello/test", // baseUrl + app + tenant + / - "http://localhost:3567/hello/appid-hello/test/", // baseUrl + app + tenant + / + "http://localhost:3567/hello/abcd", }; // Not found @@ -236,6 +237,11 @@ public void testWithBasePathThatHelloAPIDoesNotRequireAPIKeys() throws Exception "http://localhost:3567/hello/appid-hello/hello", // baseUrl + app + /hello "http://localhost:3567/hello/appid-hello/hello/", // baseUrl + app + /hello "http://localhost:3567/hello/appid-hello/test/hello", // baseUrl + app + tenant + /hello + + "http://localhost:3567/hello/appid-hello", // baseUrl + app + / + "http://localhost:3567/hello/appid-hello/", // baseUrl + app + / + "http://localhost:3567/hello/appid-hello/test", // baseUrl + app + tenant + / + "http://localhost:3567/hello/appid-hello/test/", // baseUrl + app + tenant + / }; for (String helloUrl : HELLO_ROUTES) { @@ -250,10 +256,6 @@ public void testWithBasePathThatHelloAPIDoesNotRequireAPIKeys() throws Exception String[] NOT_FOUND_ROUTES = new String[]{ "http://localhost:3567/abcd", "http://localhost:3567", - "http://localhost:3567/hello/appid-hello", // baseUrl + app + / - "http://localhost:3567/hello/appid-hello/", // baseUrl + app + / - "http://localhost:3567/hello/appid-hello/test", // baseUrl + app + tenant + / - "http://localhost:3567/hello/appid-hello/test/", // baseUrl + app + tenant + / }; // Not found @@ -315,6 +317,23 @@ public void testThatHelloAPIDoesNotRequireAPIKeys() throws Exception { new JsonObject() ), false); + Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig( + new TenantIdentifier(null, null, "hellotenant"), + new EmailPasswordConfig(true), + new ThirdPartyConfig(true, null), + new PasswordlessConfig(true), + null, null, + new JsonObject() + ), false); + Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig( + new TenantIdentifier(null, "hello", "hellotenant"), + new EmailPasswordConfig(true), + new ThirdPartyConfig(true, null), + new PasswordlessConfig(true), + null, null, + new JsonObject() + ), false); + String[] HELLO_ROUTES = new String[]{ "http://localhost:3567", // / "http://localhost:3567/", // / @@ -324,6 +343,20 @@ public void testThatHelloAPIDoesNotRequireAPIKeys() throws Exception { "http://localhost:3567/appid-hello/hello", // app + /hello "http://localhost:3567/appid-hello/hello/", // app + /hello "http://localhost:3567/appid-hello/test/hello", // app + tenant + /hello + + "http://localhost:3567/hellotenant", + "http://localhost:3567/hellotenant/", + "http://localhost:3567/hellotenant/hello", + + "http://localhost:3567/appid-hello", // app + / + "http://localhost:3567/appid-hello/", // app + / + "http://localhost:3567/appid-hello/public", + "http://localhost:3567/appid-hello/public/", + "http://localhost:3567/appid-hello/test", // app + tenant + / + "http://localhost:3567/appid-hello/test/", // app + tenant + / + "http://localhost:3567/appid-hello/hellotenant", + "http://localhost:3567/appid-hello/hellotenant/", + "http://localhost:3567/appid-hello/hellotenant/hello", }; for (String helloUrl : HELLO_ROUTES) { @@ -337,15 +370,12 @@ public void testThatHelloAPIDoesNotRequireAPIKeys() throws Exception { String[] NOT_FOUND_ROUTES = new String[]{ "http://localhost:3567/abcd", - "http://localhost:3567/appid-hello", // app + / - "http://localhost:3567/appid-hello/", // app + / - "http://localhost:3567/appid-hello/test", // app + tenant + / - "http://localhost:3567/appid-hello/test/", // app + tenant + / }; // Not found for (String notFoundUrl : NOT_FOUND_ROUTES) { try { + System.out.println(notFoundUrl); String res = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", notFoundUrl, null, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), ""); diff --git a/src/test/java/io/supertokens/test/PathRouterTest.java b/src/test/java/io/supertokens/test/PathRouterTest.java index 3f5879adb..677c404a0 100644 --- a/src/test/java/io/supertokens/test/PathRouterTest.java +++ b/src/test/java/io/supertokens/test/PathRouterTest.java @@ -69,6 +69,79 @@ public void beforeEach() { Utils.reset(); } + @Test + public void test500ErrorMessage() throws Exception { + String[] args = {"../"}; + TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STARTED)); + + Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") { + + private static final long serialVersionUID = 1L; + + @Override + public boolean checkAPIKey(HttpServletRequest req) { + return false; + } + + @Override + public String getPath() { + return "/test/servlet-exception"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws IOException, ServletException { + throw new ServletException(new RuntimeException("Test Exception")); + } + }); + + Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") { + + private static final long serialVersionUID = 1L; + + @Override + public boolean checkAPIKey(HttpServletRequest req) { + return false; + } + + @Override + public String getPath() { + return "/test/runtime-exception"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws IOException, ServletException { + throw new RuntimeException("Runtime Exception"); + } + }); + + { + try { + String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/test/servlet-exception", new HashMap<>(), 1000, 1000, null, + Utils.getCdiVersionStringLatestForTests(), ""); + fail(); + } catch (HttpResponseException e) { + assertEquals(500, e.statusCode); + assertEquals("Http error. Status Code: 500. Message: Test Exception", e.getMessage()); + } + } + + { + try { + String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/test/runtime-exception", new HashMap<>(), 1000, 1000, null, + Utils.getCdiVersionStringLatestForTests(), ""); + fail(); + } catch (HttpResponseException e) { + assertEquals(500, e.statusCode); + assertEquals("Http error. Status Code: 500. Message: Runtime Exception", e.getMessage()); + } + } + } + @Test public void basicTenantIdFetchingTest() throws InterruptedException, IOException, HttpResponseException, InvalidProviderConfigException, diff --git a/src/test/java/io/supertokens/test/StorageTest.java b/src/test/java/io/supertokens/test/StorageTest.java index e242b7656..6483de013 100644 --- a/src/test/java/io/supertokens/test/StorageTest.java +++ b/src/test/java/io/supertokens/test/StorageTest.java @@ -740,7 +740,7 @@ public void storageDeadAndAlive() throws InterruptedException, IOException, Http fail(); } catch (HttpResponseException ex) { assertEquals(ex.statusCode, 500); - assertEquals(ex.getMessage(), "Http error. Status Code: 500. Message: Internal Error"); + assertTrue(ex.getMessage().contains("Storage layer disabled")); } storage.setStorageLayerEnabled(true); @@ -765,7 +765,7 @@ public void storageDeadAndAlive() throws InterruptedException, IOException, Http fail(); } catch (HttpResponseException ex) { assertEquals(ex.statusCode, 500); - assertEquals(ex.getMessage(), "Http error. Status Code: 500. Message: Internal Error"); + assertTrue(ex.getMessage().contains("Storage layer disabled")); } storage.setStorageLayerEnabled(true); diff --git a/src/test/java/io/supertokens/test/emailpassword/api/ImportUserWithPasswordHashAPITest.java b/src/test/java/io/supertokens/test/emailpassword/api/ImportUserWithPasswordHashAPITest.java index 62ae42cd8..cbec01f4c 100644 --- a/src/test/java/io/supertokens/test/emailpassword/api/ImportUserWithPasswordHashAPITest.java +++ b/src/test/java/io/supertokens/test/emailpassword/api/ImportUserWithPasswordHashAPITest.java @@ -297,7 +297,7 @@ public void testImportingAUsesrFromFirebaseWithoutSettingTheSignerKey() throws E throw new Exception("Should not come here"); } catch (io.supertokens.test.httpRequest.HttpResponseException e) { assertTrue(e.statusCode == 500 - && e.getMessage().equals("Http error. Status Code: 500. Message: Internal Error")); + && e.getMessage().equals("Http error. Status Code: 500. Message: 'firebase_password_hashing_signer_key' cannot be null")); } process.kill(); @@ -388,7 +388,7 @@ public void testSigningInAUserWithFirebasePasswordHashWithoutSettingTheSignerKey throw new Exception("Should not come here"); } catch (io.supertokens.test.httpRequest.HttpResponseException e) { assertTrue(e.statusCode == 500 - && e.getMessage().equals("Http error. Status Code: 500. Message: Internal Error")); + && e.getMessage().equals("Http error. Status Code: 500. Message: 'firebase_password_hashing_signer_key' cannot be null")); } process.kill();