From 729ba6a623992ce67bf2f4f399a3c2024a45cc6b Mon Sep 17 00:00:00 2001 From: rishabhpoddar Date: Mon, 8 Jul 2024 21:41:55 +0530 Subject: [PATCH] reformates code --- .github/PULL_REQUEST_TEMPLATE.md | 23 +- .github/helpers/package.json | 24 +- .../workflows/github-actions-changelog.yml | 12 +- .github/workflows/lint-pr-title.yml | 30 +- .github/workflows/tests-pass-check-pr.yml | 38 +- .github/workflows/tests.yml | 8 +- CHANGELOG.md | 63 +-- CONTRIBUTING.md | 57 ++- LICENSE.md | 371 +++++++++--------- README.md | 14 +- .../storage/postgresql/ConnectionPool.java | 3 +- .../postgresql/QueryExecutorTemplate.java | 4 +- .../supertokens/storage/postgresql/Start.java | 56 ++- .../postgresql/annotations/DashboardInfo.java | 8 +- .../storage/postgresql/config/Config.java | 3 +- .../postgresql/config/PostgreSQLConfig.java | 101 +++-- .../queries/ActiveUsersQueries.java | 47 +-- .../postgresql/queries/DashboardQueries.java | 19 +- .../queries/EmailPasswordQueries.java | 33 +- .../queries/EmailVerificationQueries.java | 20 +- .../postgresql/queries/GeneralQueries.java | 140 ++++--- .../postgresql/queries/JWTSigningQueries.java | 8 +- .../queries/MultitenancyQueries.java | 64 +-- .../queries/PasswordlessQueries.java | 42 +- .../postgresql/queries/TOTPQueries.java | 33 +- .../postgresql/queries/ThirdPartyQueries.java | 26 +- .../queries/UserIdMappingQueries.java | 45 ++- .../postgresql/queries/UserRolesQueries.java | 2 +- .../queries/multitenancy/MfaSqlHelper.java | 23 +- .../multitenancy/TenantConfigSQLHelper.java | 31 +- .../ThirdPartyProviderClientSQLHelper.java | 34 +- .../ThirdPartyProviderSQLHelper.java | 47 ++- .../storage/postgresql/test/ConfigTest.java | 7 +- .../postgresql/test/DbConnectionPoolTest.java | 7 +- .../storage/postgresql/test/DeadlockTest.java | 21 +- .../storage/postgresql/test/LogLevelTest.java | 10 +- .../storage/postgresql/test/LoggingTest.java | 30 +- .../postgresql/test/OneMillionUsersTest.java | 26 +- .../test/PostgresSQLConfigTest.java | 10 +- .../postgresql/test/StorageLayerTest.java | 20 +- .../test/SuperTokensSaaSSecretTest.java | 30 +- .../postgresql/test/TableCreationTest.java | 2 +- .../postgresql/test/TestMainThread.java | 5 +- .../httpRequest/HttpRequestForTesting.java | 141 +++---- .../test/multitenancy/StorageLayerTest.java | 6 +- .../TestForNoCrashDuringStartup.java | 73 ++-- 46 files changed, 1086 insertions(+), 731 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4de1c9d4..2b22ae85 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,27 +1,38 @@ ## Summary of change + (A few sentences about this PR) ## Related issues + - Link to issue1 here - Link to issue1 here ## Test Plan -(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos!) + +(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your +changes work. Bonus points for screenshots and videos!) ## Documentation changes -(If relevant, please create a PR in our [docs repo](https://github.com/supertokens/docs), or create a checklist here highlighting the necessary changes) + +(If relevant, please create a PR in our [docs repo](https://github.com/supertokens/docs), or create a checklist here +highlighting the necessary changes) ## Checklist for important updates + - [ ] Changelog has been updated - [ ] `pluginInterfaceSupported.json` file has been updated (if needed) - [ ] Changes to the version if needed - - In `build.gradle` + - In `build.gradle` - [ ] Had installed and ran the pre-commit hook -- [ ] If there are new dependencies that have been added in `build.gradle`, please make sure to add them in `implementationDependencies.json`. +- [ ] If there are new dependencies that have been added in `build.gradle`, please make sure to add them + in `implementationDependencies.json`. - [ ] Issue this PR against the latest non released version branch. - - To know which one it is, run find the latest released tag (`git tag`) in the format `vX.Y.Z`, and then find the latest branch (`git branch --all`) whose `X.Y` is greater than the latest released tag. - - If no such branch exists, then create one from the latest released branch. + - To know which one it is, run find the latest released tag (`git tag`) in the format `vX.Y.Z`, and then find the + latest branch (`git branch --all`) whose `X.Y` is greater than the latest released tag. + - If no such branch exists, then create one from the latest released branch. - [ ] When adding new recipes, ensure that its performance is being measured in the `OneMillionUsersTest` + ## Remaining TODOs for this PR + - [ ] Item1 - [ ] Item2 \ No newline at end of file diff --git a/.github/helpers/package.json b/.github/helpers/package.json index 80ec546b..28051cdb 100644 --- a/.github/helpers/package.json +++ b/.github/helpers/package.json @@ -1,14 +1,14 @@ { - "name": "helpers", - "version": "1.0.0", - "description": "", - "main": "test-pass-check-pr.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "github-workflow-helpers": "github:supertokens/github-workflow-helpers" - } + "name": "helpers", + "version": "1.0.0", + "description": "", + "main": "test-pass-check-pr.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "github-workflow-helpers": "github:supertokens/github-workflow-helpers" + } } \ No newline at end of file diff --git a/.github/workflows/github-actions-changelog.yml b/.github/workflows/github-actions-changelog.yml index 0007ca9a..47aaf4a2 100644 --- a/.github/workflows/github-actions-changelog.yml +++ b/.github/workflows/github-actions-changelog.yml @@ -1,15 +1,15 @@ name: "Enforcing changelog in PRs Workflow" on: pull_request: - types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] + types: [ opened, synchronize, reopened, ready_for_review, labeled, unlabeled ] jobs: # Enforces the update of a changelog file on every pull request changelog: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: dangoslen/changelog-enforcer@v2 - with: - changeLogPath: 'CHANGELOG.md' - skipLabels: 'Skip-Changelog' \ No newline at end of file + - uses: actions/checkout@v2 + - uses: dangoslen/changelog-enforcer@v2 + with: + changeLogPath: 'CHANGELOG.md' + skipLabels: 'Skip-Changelog' \ No newline at end of file diff --git a/.github/workflows/lint-pr-title.yml b/.github/workflows/lint-pr-title.yml index 904efde8..96281a74 100644 --- a/.github/workflows/lint-pr-title.yml +++ b/.github/workflows/lint-pr-title.yml @@ -1,20 +1,20 @@ name: "Lint PR Title" on: - pull_request: - types: - - opened - - reopened - - edited - - synchronize + pull_request: + types: + - opened + - reopened + - edited + - synchronize jobs: - pr-title: - name: Lint PR title - runs-on: ubuntu-latest - steps: - - uses: amannn/action-semantic-pull-request@v3 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - validateSingleCommit: true \ No newline at end of file + pr-title: + name: Lint PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v3 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + validateSingleCommit: true \ No newline at end of file diff --git a/.github/workflows/tests-pass-check-pr.yml b/.github/workflows/tests-pass-check-pr.yml index 4f03705b..07467d9d 100644 --- a/.github/workflows/tests-pass-check-pr.yml +++ b/.github/workflows/tests-pass-check-pr.yml @@ -1,24 +1,24 @@ name: "Check if \"Run tests\" action succeeded" on: - pull_request: - types: - - opened - - reopened - - edited - - synchronize + pull_request: + types: + - opened + - reopened + - edited + - synchronize jobs: - pr-run-test-action: - name: Check if "Run tests" action succeeded - timeout-minutes: 60 - concurrency: - group: ${{ github.head_ref }} - cancel-in-progress: true - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: node install - run: cd ./.github/helpers && npm i - - name: Calling github API - run: cd ./.github/helpers && GITHUB_TOKEN=${{ github.token }} REPO=${{ github.repository }} RUN_ID=${{ github.run_id }} BRANCH=${{ github.head_ref }} JOB_ID=${{ github.job }} SOURCE_OWNER=${{ github.event.pull_request.head.repo.owner.login }} CURRENT_SHA=${{ github.event.pull_request.head.sha }} node node_modules/github-workflow-helpers/test-pass-check-pr.js \ No newline at end of file + pr-run-test-action: + name: Check if "Run tests" action succeeded + timeout-minutes: 60 + concurrency: + group: ${{ github.head_ref }} + cancel-in-progress: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: node install + run: cd ./.github/helpers && npm i + - name: Calling github API + run: cd ./.github/helpers && GITHUB_TOKEN=${{ github.token }} REPO=${{ github.repository }} RUN_ID=${{ github.run_id }} BRANCH=${{ github.head_ref }} JOB_ID=${{ github.job }} SOURCE_OWNER=${{ github.event.pull_request.head.repo.owner.login }} CURRENT_SHA=${{ github.event.pull_request.head.sha }} node node_modules/github-workflow-helpers/test-pass-check-pr.js \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8bb11ba3..dc2133e9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,19 +4,19 @@ on: inputs: coreRepoOwnerName: description: 'supertokens-core repo owner name' - default: supertokens + default: supertokens required: true coreRepoBranch: description: 'supertokens-core repos branch name' - default: master + default: master required: true pluginRepoOwnerName: description: 'supertokens-plugin-interface repo owner name' - default: supertokens + default: supertokens required: true pluginInterfaceBranch: description: 'supertokens-plugin-interface repos branch name' - default: master + default: master required: true jobs: diff --git a/CHANGELOG.md b/CHANGELOG.md index 518be7b1..ffb3c2ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [7.1.0] - Adds implementation for a new method `getConfigFieldsInfo` to fetch the plugin config fields. -- Adds `null` state for `firstFactors` and `providers` by adding `is_first_factors_null` and `is_third_party_providers_null` fields in `tenant_configs` table +- Adds `null` state for `firstFactors` and `providers` by adding `is_first_factors_null` + and `is_third_party_providers_null` fields in `tenant_configs` table ### Migration @@ -32,8 +33,8 @@ ALTER TABLE tenant_configs ALTER COLUMN is_third_party_providers_null DROP DEFAU - Support for MFA recipe - Adds `firstFactors` and `requiredSecondaryFactors` for tenant config. - 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 + - This enables smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to + change the signing key type of a session ### Migration @@ -64,7 +65,8 @@ ALTER TABLE user_roles DROP CONSTRAINT IF EXISTS user_roles_role_fkey; - Fixes the issue where passwords were inadvertently logged in the logs. - Adds tests to check connection pool behaviour. -- Adds `postgresql_idle_connection_timeout` and `postgresql_minimum_idle_connections` configs to control active connections to the database. +- Adds `postgresql_idle_connection_timeout` and `postgresql_minimum_idle_connections` configs to control active + connections to the database. ## [5.0.6] - 2023-12-05 @@ -104,15 +106,16 @@ CREATE INDEX IF NOT EXISTS app_id_to_user_id_primary_user_id_index ON app_id_to_ ### Changes - Support for Account Linking - - Adds columns `primary_or_recipe_user_id`, `is_linked_or_is_a_primary_user` and `primary_or_recipe_user_time_joined` to `all_auth_recipe_users` table - - Adds columns `primary_or_recipe_user_id` and `is_linked_or_is_a_primary_user` to `app_id_to_user_id` table - - Removes index `all_auth_recipe_users_pagination_index` and addes `all_auth_recipe_users_pagination_index1`, - `all_auth_recipe_users_pagination_index2`, `all_auth_recipe_users_pagination_index3` and - `all_auth_recipe_users_pagination_index4` indexes instead on `all_auth_recipe_users` table - - Adds `all_auth_recipe_users_recipe_id_index` on `all_auth_recipe_users` table - - Adds `all_auth_recipe_users_primary_user_id_index` on `all_auth_recipe_users` table - - Adds `email` column to `emailpassword_pswd_reset_tokens` table - - Changes `user_id` foreign key constraint on `emailpassword_pswd_reset_tokens` to `app_id_to_user_id` table + - Adds columns `primary_or_recipe_user_id`, `is_linked_or_is_a_primary_user` + and `primary_or_recipe_user_time_joined` to `all_auth_recipe_users` table + - Adds columns `primary_or_recipe_user_id` and `is_linked_or_is_a_primary_user` to `app_id_to_user_id` table + - Removes index `all_auth_recipe_users_pagination_index` and addes `all_auth_recipe_users_pagination_index1`, + `all_auth_recipe_users_pagination_index2`, `all_auth_recipe_users_pagination_index3` and + `all_auth_recipe_users_pagination_index4` indexes instead on `all_auth_recipe_users` table + - Adds `all_auth_recipe_users_recipe_id_index` on `all_auth_recipe_users` table + - Adds `all_auth_recipe_users_primary_user_id_index` on `all_auth_recipe_users` table + - Adds `email` column to `emailpassword_pswd_reset_tokens` table + - Changes `user_id` foreign key constraint on `emailpassword_pswd_reset_tokens` to `app_id_to_user_id` table ### Migration @@ -193,21 +196,20 @@ CREATE INDEX IF NOT EXISTS app_id_to_user_id_primary_user_id_index ON app_id_to_ - Fixes null pointer issue when user belongs to no tenant. - ## [4.0.1] - 2023-07-11 - Fixes duplicate users in users search queries when user is associated to multiple tenants - ## [4.0.0] - 2023-06-02 ### Changes - Support for multitenancy - - New tables `apps` and `tenants` have been added. - - Schema of tables have been changed, adding `app_id` and `tenant_id` columns in tables and constraints & indexes have been modified to include this columns. - - New user tables have been added to map users to apps and tenants. - - New tables for multitenancy have been added. + - New tables `apps` and `tenants` have been added. + - Schema of tables have been changed, adding `app_id` and `tenant_id` columns in tables and constraints & indexes + have been modified to include this columns. + - New user tables have been added to map users to apps and tenants. + - New tables for multitenancy have been added. - Increased transaction retry count to 50 from 20. ### Migration @@ -1085,19 +1087,19 @@ CREATE INDEX IF NOT EXISTS app_id_to_user_id_primary_user_id_index ON app_id_to_ ### Migration - If using `access_token_signing_key_dynamic` false in the core: - - ```sql - ALTER TABLE session_info ADD COLUMN use_static_key BOOLEAN NOT NULL DEFAULT(true); - ALTER TABLE session_info ALTER COLUMN use_static_key DROP DEFAULT; + - ```sql + ALTER TABLE session_info ADD COLUMN use_static_key BOOLEAN NOT NULL DEFAULT(true); + ALTER TABLE session_info ALTER COLUMN use_static_key DROP DEFAULT; ``` - - ```sql + - ```sql INSERT INTO jwt_signing_keys(key_id, key_string, algorithm, created_at) select CONCAT('s-', created_at_time) as key_id, value as key_string, 'RS256' as algorithm, created_at_time as created_at from session_access_token_signing_keys; ``` - If using `access_token_signing_key_dynamic` true (or not set) in the core: - - ```sql - ALTER TABLE session_info ADD COLUMN use_static_key BOOLEAN NOT NULL DEFAULT(false); - ALTER TABLE session_info ALTER COLUMN use_static_key DROP DEFAULT; + - ```sql + ALTER TABLE session_info ADD COLUMN use_static_key BOOLEAN NOT NULL DEFAULT(false); + ALTER TABLE session_info ALTER COLUMN use_static_key DROP DEFAULT; ``` ## [2.4.0] - 2023-03-30 @@ -1105,14 +1107,17 @@ CREATE INDEX IF NOT EXISTS app_id_to_user_id_primary_user_id_index ON app_id_to_ - Support for Dashboard Search ## [2.3.0] - 2023-03-27 + - Support for TOTP recipe - Support for active users ### Database changes + - Add new tables for TOTP recipe: - - `totp_users` that stores the users that have enabled TOTP - - `totp_user_devices` that stores devices (each device has its own secret) for each user - - `totp_used_codes` that stores used codes for each user. This is to implement rate limiting and prevent replay attacks. + - `totp_users` that stores the users that have enabled TOTP + - `totp_user_devices` that stores devices (each device has its own secret) for each user + - `totp_used_codes` that stores used codes for each user. This is to implement rate limiting and prevent replay + attacks. - Add `user_last_active` table to store the last active time of a user. ## [2.2.0] - 2023-02-21 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 53732985..a222aea4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,51 +1,70 @@ - # Contributing -We're so excited you're interested in helping with SuperTokens! We are happy to help you get started, even if you don't have any previous open-source experience :blush: +We're so excited you're interested in helping with SuperTokens! We are happy to help you get started, even if you don't +have any previous open-source experience :blush: ## New to Open Source? -1. Take a look at [How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) -2. Go thorugh the [SuperTokens Code of Conduct](https://github.com/supertokens/supertokens-postgresql-plugin/blob/master/CODE_OF_CONDUCT.md) + +1. Take a look + at [How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) +2. Go thorugh + the [SuperTokens Code of Conduct](https://github.com/supertokens/supertokens-postgresql-plugin/blob/master/CODE_OF_CONDUCT.md) ## Where to ask Questions? -1. Check our [Github Issues](https://github.com/supertokens/supertokens-postgresql-plugin/issues) to see if someone has already answered your question. -2. Join our community on [Discord](https://supertokens.io/discord) and feel free to ask us your questions +1. Check our [Github Issues](https://github.com/supertokens/supertokens-postgresql-plugin/issues) to see if someone has + already answered your question. +2. Join our community on [Discord](https://supertokens.io/discord) and feel free to ask us your questions ## Development Setup + ### Prerequisites + - OS: Linux or macOS - IDE: Intellij (recommended) or equivalent IDE - PostgreSQL ### Project Setup -1. Setup the `supertokens-core` by following [this guide](https://github.com/supertokens/supertokens-core/blob/master/CONTRIBUTING.md#development-setup). If you are not modifying the `supertokens-core` repo, then you do not need to fork that. + +1. Setup the `supertokens-core` by + following [this guide](https://github.com/supertokens/supertokens-core/blob/master/CONTRIBUTING.md#development-setup). + If you are not modifying the `supertokens-core` repo, then you do not need to fork that. 2. Start PostgreSQL on port `5432`, listening to `locahost` or `0.0.0.0`. 3. Create a PostgreSQL user (if not already exists) with username `root` and password `root` 4. Create a database called `supertokens`. 5. Fork the `supertokens-pstgresql-plugin` repository -6. Open `modules.txt` in the `supertokens-root` directory and change it so that it looks like (the last line has changed): +6. Open `modules.txt` in the `supertokens-root` directory and change it so that it looks like (the last line has + changed): ``` // put module name like module name,branch name,github username(if contributing with a forked repository) and then call ./loadModules script core,master plugin-interface,master postgresql-plugin,master, ``` -7. Run `./loadModules` in the `supertokens-root` directory. This will clone your forked `supertokens-postgresql-plugin` repo. -8. Follow the [CONTRIBUTING.md](https://github.com/supertokens/supertokens-core/blob/master/CONTRIBUTING.md#modifying-code) guide from `supertokens-core` repo for modifying and testing. +7. Run `./loadModules` in the `supertokens-root` directory. This will clone your forked `supertokens-postgresql-plugin` + repo. +8. Follow + the [CONTRIBUTING.md](https://github.com/supertokens/supertokens-core/blob/master/CONTRIBUTING.md#modifying-code) + guide from `supertokens-core` repo for modifying and testing. ## Pull Request + 1. Before submitting a pull request make sure all tests have passed -2. Reference the relevant issue or pull request and give a clear description of changes/features added when submitting a pull request +2. Reference the relevant issue or pull request and give a clear description of changes/features added when submitting a + pull request 3. Make sure the PR title follows [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) specification ## SuperTokens Community -SuperTokens is made possible by a passionate team and a strong community of developers. If you have any questions or would like to get more involved in the SuperTokens community you can check out: - - [Github Issues](https://github.com/supertokens/supertokens-postgresql-plugin/issues) - - [Discord](https://supertokens.io/discord) - - [Twitter](https://twitter.com/supertokensio) - - or [email us](mailto:team@supertokens.io) - + +SuperTokens is made possible by a passionate team and a strong community of developers. If you have any questions or +would like to get more involved in the SuperTokens community you can check out: + +- [Github Issues](https://github.com/supertokens/supertokens-postgresql-plugin/issues) +- [Discord](https://supertokens.io/discord) +- [Twitter](https://twitter.com/supertokensio) +- or [email us](mailto:team@supertokens.io) + Additional resources you might find useful: - - [SuperTokens Docs](https://supertokens.io/docs/community/getting-started/installation) - - [Blog Posts](https://supertokens.io/blog/) + +- [SuperTokens Docs](https://supertokens.io/docs/community/getting-started/installation) +- [Blog Posts](https://supertokens.io/blog/) diff --git a/LICENSE.md b/LICENSE.md index e105852e..7a85c9c7 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,191 +1,192 @@ - Copyright (c) 2020, 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 software except in compliance with the License. A copy - of the License is available below the line. - - 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. +Copyright (c) 2020, 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 software except in compliance with the License. A copy +of the License is available below the line. + +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. ------------------------------------------------------------------------------- + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/README.md b/README.md index cc88cb0b..d44d464f 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,32 @@ - ![SuperTokens banner](https://raw.githubusercontent.com/supertokens/supertokens-logo/master/images/Artboard%20%E2%80%93%2027%402x.png) # PostgreSQL plugin for SuperTokens Community + chat on Discord ## About + This plugin is responsible for interfacing between SuperTokens Community version and an instance of PostgreSQL. Learn more at https://supertokens.io ## Documentation + To see documentation, please click [here](https://supertokens.io/docs/community/introduction). ## Contributing -Please refer to the [CONTRIBUTING.md](https://github.com/supertokens/supertokens-postgresql-plugin/blob/master/CONTRIBUTING.md) file in this repo. + +Please refer to +the [CONTRIBUTING.md](https://github.com/supertokens/supertokens-postgresql-plugin/blob/master/CONTRIBUTING.md) file in +this repo. ## Contact us -For any queries, or support requests, please email us at team@supertokens.io, or join our [Discord](supertokens.io/discord) server. + +For any queries, or support requests, please email us at team@supertokens.io, or join +our [Discord](supertokens.io/discord) server. # Authors + Created with :heart: by the folks at SuperTokens.io. diff --git a/src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java b/src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java index 534e706a..acab61f5 100644 --- a/src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java +++ b/src/main/java/io/supertokens/storage/postgresql/ConnectionPool.java @@ -149,7 +149,8 @@ static boolean isAlreadyInitialised(Start start) { return getInstance(start) != null && getInstance(start).hikariDataSource != null; } - static void initPool(Start start, boolean shouldWait, PostConnectCallback postConnectCallback) throws DbInitException { + static void initPool(Start start, boolean shouldWait, PostConnectCallback postConnectCallback) + throws DbInitException { if (isAlreadyInitialised(start)) { return; } diff --git a/src/main/java/io/supertokens/storage/postgresql/QueryExecutorTemplate.java b/src/main/java/io/supertokens/storage/postgresql/QueryExecutorTemplate.java index db0c9785..179a871b 100644 --- a/src/main/java/io/supertokens/storage/postgresql/QueryExecutorTemplate.java +++ b/src/main/java/io/supertokens/storage/postgresql/QueryExecutorTemplate.java @@ -26,14 +26,14 @@ public interface QueryExecutorTemplate { static T execute(Start start, String QUERY, PreparedStatementValueSetter setter, - ResultSetValueExtractor mapper) throws SQLException, StorageQueryException { + ResultSetValueExtractor mapper) throws SQLException, StorageQueryException { try (Connection con = ConnectionPool.getConnection(start)) { return execute(con, QUERY, setter, mapper); } } static T execute(Connection con, String QUERY, PreparedStatementValueSetter setter, - ResultSetValueExtractor mapper) throws SQLException, StorageQueryException { + ResultSetValueExtractor mapper) throws SQLException, StorageQueryException { if (setter == null) setter = PreparedStatementValueSetter.NO_OP_SETTER; try (PreparedStatement pst = con.prepareStatement(QUERY)) { diff --git a/src/main/java/io/supertokens/storage/postgresql/Start.java b/src/main/java/io/supertokens/storage/postgresql/Start.java index 0ee1839f..a0eea865 100644 --- a/src/main/java/io/supertokens/storage/postgresql/Start.java +++ b/src/main/java/io/supertokens/storage/postgresql/Start.java @@ -843,7 +843,8 @@ public void addInfoToNonAuthRecipesBasedOnUserId(TenantIdentifier tenantIdentifi } } else if (className.equals(TOTPStorage.class.getName())) { try { - TOTPDevice device = new TOTPDevice(userId, "testDevice", "secret", 0, 30, false, System.currentTimeMillis()); + TOTPDevice device = new TOTPDevice(userId, "testDevice", "secret", 0, 30, false, + System.currentTimeMillis()); this.startTransaction(con -> { try { long now = System.currentTimeMillis(); @@ -886,7 +887,7 @@ public String[] getProtectedConfigsFromSuperTokensSaaSUsers() { @Override public AuthRecipeUserInfo signUp(TenantIdentifier tenantIdentifier, String id, String email, String passwordHash, - long timeJoined) + long timeJoined) throws StorageQueryException, DuplicateUserIdException, DuplicateEmailException, TenantOrAppNotFoundException { try { @@ -1196,8 +1197,10 @@ public boolean isEmailVerified(AppIdentifier appIdentifier, String userId, Strin } @Override - public void updateIsEmailVerifiedToExternalUserId(AppIdentifier appIdentifier, String supertokensUserId, String externalUserId) throws StorageQueryException { - EmailVerificationQueries.updateIsEmailVerifiedToExternalUserId(this, appIdentifier, supertokensUserId, externalUserId); + public void updateIsEmailVerifiedToExternalUserId(AppIdentifier appIdentifier, String supertokensUserId, + String externalUserId) throws StorageQueryException { + EmailVerificationQueries.updateIsEmailVerifiedToExternalUserId(this, appIdentifier, supertokensUserId, + externalUserId); } @Override @@ -1718,10 +1721,10 @@ public void createCode(TenantIdentifier tenantIdentifier, PasswordlessCode code) @Override public AuthRecipeUserInfo createUser(TenantIdentifier tenantIdentifier, - String id, - @javax.annotation.Nullable String email, - @javax.annotation.Nullable - String phoneNumber, long timeJoined) + String id, + @javax.annotation.Nullable String email, + @javax.annotation.Nullable + String phoneNumber, long timeJoined) throws StorageQueryException, DuplicateEmailException, DuplicatePhoneNumberException, DuplicateUserIdException, TenantOrAppNotFoundException { @@ -2242,7 +2245,8 @@ public boolean updateOrDeleteExternalUserIdInfo(AppIdentifier appIdentifier, Str } @Override - public HashMap getUserIdMappingForSuperTokensIds(AppIdentifier appIdentifier, ArrayList userIds) + public HashMap getUserIdMappingForSuperTokensIds(AppIdentifier appIdentifier, + ArrayList userIds) throws StorageQueryException { try { return UserIdMappingQueries.getUserIdMappingWithUserIds(this, appIdentifier, userIds); @@ -2361,7 +2365,8 @@ public TenantConfig[] getAllTenants() throws StorageQueryException { } @Override - public boolean addUserIdToTenant_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, String userId) + public boolean addUserIdToTenant_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, + String userId) throws TenantOrAppNotFoundException, UnknownUserIdException, StorageQueryException, DuplicateEmailException, DuplicateThirdPartyUserException, DuplicatePhoneNumberException { Connection sqlCon = (Connection) con.getConnection(); @@ -2660,7 +2665,8 @@ public void createDevice(AppIdentifier appIdentifier, TOTPDevice device) } @Override - public TOTPDevice createDevice_Transaction(TransactionConnection con, AppIdentifier appIdentifier, TOTPDevice device) + public TOTPDevice createDevice_Transaction(TransactionConnection con, AppIdentifier appIdentifier, + TOTPDevice device) throws StorageQueryException, DeviceAlreadyExistsException, TenantOrAppNotFoundException { Connection sqlCon = (Connection) con.getConnection(); try { @@ -2673,9 +2679,9 @@ public TOTPDevice createDevice_Transaction(TransactionConnection con, AppIdentif ServerErrorMessage errMsg = ((PSQLException) actualException).getServerErrorMessage(); if (isPrimaryKeyError(errMsg, Config.getConfig(this).getTotpUserDevicesTable())) { - throw new DeviceAlreadyExistsException(); + throw new DeviceAlreadyExistsException(); } else if (isForeignKeyConstraintError(errMsg, Config.getConfig(this).getTotpUsersTable(), "app_id")) { - throw new TenantOrAppNotFoundException(appIdentifier); + throw new TenantOrAppNotFoundException(appIdentifier); } } throw new StorageQueryException(e); @@ -2683,7 +2689,8 @@ public TOTPDevice createDevice_Transaction(TransactionConnection con, AppIdentif } @Override - public TOTPDevice getDeviceByName_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId, String deviceName) throws StorageQueryException { + public TOTPDevice getDeviceByName_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId, + String deviceName) throws StorageQueryException { Connection sqlCon = (Connection) con.getConnection(); try { return TOTPQueries.getDeviceByName_Transaction(this, sqlCon, appIdentifier, userId, deviceName); @@ -2753,7 +2760,7 @@ public void updateDeviceName(AppIdentifier appIdentifier, String userId, String if (e instanceof PSQLException) { ServerErrorMessage errMsg = ((PSQLException) e).getServerErrorMessage(); if (isPrimaryKeyError(errMsg, Config.getConfig(this).getTotpUserDevicesTable())) { - throw new DeviceAlreadyExistsException(); + throw new DeviceAlreadyExistsException(); } } throw new StorageQueryException(e); @@ -2961,7 +2968,8 @@ public void linkAccounts_Transaction(AppIdentifier appIdentifier, TransactionCon } @Override - public void unlinkAccounts_Transaction(AppIdentifier appIdentifier, TransactionConnection con, String primaryUserId, String recipeUserId) + public void unlinkAccounts_Transaction(AppIdentifier appIdentifier, TransactionConnection con, String primaryUserId, + String recipeUserId) throws StorageQueryException { try { Connection sqlCon = (Connection) con.getConnection(); @@ -2994,7 +3002,8 @@ public boolean checkIfUsesAccountLinking(AppIdentifier appIdentifier) throws Sto } @Override - public int countUsersThatHaveMoreThanOneLoginMethodAndActiveSince(AppIdentifier appIdentifier, long sinceTime) throws StorageQueryException { + public int countUsersThatHaveMoreThanOneLoginMethodAndActiveSince(AppIdentifier appIdentifier, long sinceTime) + throws StorageQueryException { try { return ActiveUsersQueries.countUsersActiveSinceAndHasMoreThanOneLoginMethod(this, appIdentifier, sinceTime); } catch (SQLException e) { @@ -3023,11 +3032,13 @@ public UserIdMapping getUserIdMapping_Transaction(TransactionConnection con, App try { Connection sqlCon = (Connection) con.getConnection(); if (isSuperTokensUserId) { - return UserIdMappingQueries.getuseraIdMappingWithSuperTokensUserId_Transaction(this, sqlCon, appIdentifier, + return UserIdMappingQueries.getuseraIdMappingWithSuperTokensUserId_Transaction(this, sqlCon, + appIdentifier, userId); } - return UserIdMappingQueries.getUserIdMappingWithExternalUserId_Transaction(this, sqlCon, appIdentifier, userId); + return UserIdMappingQueries.getUserIdMappingWithExternalUserId_Transaction(this, sqlCon, appIdentifier, + userId); } catch (SQLException e) { throw new StorageQueryException(e); } @@ -3048,7 +3059,8 @@ public UserIdMapping[] getUserIdMapping_Transaction(TransactionConnection con, A } @Override - public int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(AppIdentifier appIdentifier) throws StorageQueryException { + public int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(AppIdentifier appIdentifier) + throws StorageQueryException { try { return GeneralQueries.getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(this, appIdentifier); } catch (SQLException e) { @@ -3057,7 +3069,9 @@ public int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(AppIdentifier ap } @Override - public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(AppIdentifier appIdentifier, long sinceTime) throws StorageQueryException { + public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(AppIdentifier appIdentifier, + long sinceTime) + throws StorageQueryException { try { return ActiveUsersQueries.countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(this, appIdentifier, sinceTime); diff --git a/src/main/java/io/supertokens/storage/postgresql/annotations/DashboardInfo.java b/src/main/java/io/supertokens/storage/postgresql/annotations/DashboardInfo.java index a40b0a1e..9bc1ced3 100644 --- a/src/main/java/io/supertokens/storage/postgresql/annotations/DashboardInfo.java +++ b/src/main/java/io/supertokens/storage/postgresql/annotations/DashboardInfo.java @@ -14,7 +14,7 @@ * under the License. */ - package io.supertokens.storage.postgresql.annotations; +package io.supertokens.storage.postgresql.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -25,11 +25,15 @@ * Annotation to provide a description for a configuration fields. To be used on the fields of `CoreConfig` and config * class in the plugin like `PostgreSQLConfig`, `MysqlConfig`, etc. */ -@Retention(RetentionPolicy.RUNTIME) // Make annotation accessible at runtime so that config descriptions can be read from API +@Retention(RetentionPolicy.RUNTIME) +// Make annotation accessible at runtime so that config descriptions can be read from API @Target(ElementType.FIELD) // Annotation can only be applied to fields public @interface DashboardInfo { String description() default ""; + boolean isOptional() default false; + String defaultValue() default ""; + boolean isEditable() default false; } diff --git a/src/main/java/io/supertokens/storage/postgresql/config/Config.java b/src/main/java/io/supertokens/storage/postgresql/config/Config.java index 41088d73..1ce21e06 100644 --- a/src/main/java/io/supertokens/storage/postgresql/config/Config.java +++ b/src/main/java/io/supertokens/storage/postgresql/config/Config.java @@ -53,7 +53,8 @@ private static Config getInstance(Start start) { return (Config) start.getResourceDistributor().getResource(RESOURCE_KEY); } - public static void loadConfig(Start start, JsonObject configJson, Set logLevels, TenantIdentifier tenantIdentifier) + public static void loadConfig(Start start, JsonObject configJson, Set logLevels, + TenantIdentifier tenantIdentifier) throws InvalidConfigException { if (getInstance(start) != null) { return; diff --git a/src/main/java/io/supertokens/storage/postgresql/config/PostgreSQLConfig.java b/src/main/java/io/supertokens/storage/postgresql/config/PostgreSQLConfig.java index 7ff9daa1..a1ff555c 100644 --- a/src/main/java/io/supertokens/storage/postgresql/config/PostgreSQLConfig.java +++ b/src/main/java/io/supertokens/storage/postgresql/config/PostgreSQLConfig.java @@ -46,72 +46,102 @@ public class PostgreSQLConfig { @JsonProperty @ConnectionPoolProperty - @DashboardInfo(description = "Defines the connection pool size to PostgreSQL. Please see https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing", defaultValue = "10", isOptional = true, isEditable = true) + @DashboardInfo( + description = "Defines the connection pool size to PostgreSQL. Please see https://github" + + ".com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing", + defaultValue = "10", isOptional = true, isEditable = true) private int postgresql_connection_pool_size = 10; @JsonProperty @UserPoolProperty - @DashboardInfo(description = "Specify the postgresql host url here. For example: - \"localhost\" - \"192.168.0.1\" - \"\" - \"example.com\"", defaultValue = "\"localhost\"", isOptional = true) + @DashboardInfo( + description = "Specify the postgresql host url here. For example: - \"localhost\" - \"192.168.0.1\" - " + + "\"\" - \"example.com\"", + defaultValue = "\"localhost\"", isOptional = true) private String postgresql_host = null; @JsonProperty @UserPoolProperty - @DashboardInfo(description = "Specify the port to use when connecting to PostgreSQL instance.", defaultValue = "5432", isOptional = true) + @DashboardInfo(description = "Specify the port to use when connecting to PostgreSQL instance.", + defaultValue = "5432", isOptional = true) private int postgresql_port = -1; @JsonProperty @ConnectionPoolProperty - @DashboardInfo(description = "The PostgreSQL user to use to query the database. If the relevant tables are not already created by you, this user should have the ability to create new tables. To see the tables needed, visit: https://supertokens.com/docs/thirdpartyemailpassword/pre-built-ui/setup/database-setup/postgresql", defaultValue = "null") + @DashboardInfo( + description = "The PostgreSQL user to use to query the database. If the relevant tables are not already " + + "created by you, this user should have the ability to create new tables. To see the tables " + + "needed, visit: https://supertokens.com/docs/thirdpartyemailpassword/pre-built-ui/setup/database" + + "-setup/postgresql", + defaultValue = "null") private String postgresql_user = null; @JsonProperty @ConnectionPoolProperty - @DashboardInfo(description = "Password for the PostgreSQL user. If you have not set a password make this an empty string.", defaultValue = "null") + @DashboardInfo( + description = "Password for the PostgreSQL user. If you have not set a password make this an empty string.", + defaultValue = "null") private String postgresql_password = null; @JsonProperty @UserPoolProperty - @DashboardInfo(description = "The database name to store SuperTokens related data.", defaultValue = "\"supertokens\"", isOptional = true) + @DashboardInfo(description = "The database name to store SuperTokens related data.", + defaultValue = "\"supertokens\"", isOptional = true) private String postgresql_database_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "A prefix to add to all table names managed by SuperTokens. An \"_\" will be added between this prefix and the actual table name if the prefix is defined.", defaultValue = "\"\"", isOptional = true) + @DashboardInfo( + description = "A prefix to add to all table names managed by SuperTokens. An \"_\" will be added between " + + "this prefix and the actual table name if the prefix is defined.", + defaultValue = "\"\"", isOptional = true) private String postgresql_table_names_prefix = ""; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store secret keys and app info necessary for the functioning sessions.", defaultValue = "\"key_value\"", isOptional = true) + @DashboardInfo( + description = "Specify the name of the table that will store secret keys and app info necessary for the " + + "functioning sessions.", + defaultValue = "\"key_value\"", isOptional = true) private String postgresql_key_value_table_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store the session info for users.", defaultValue = "\"session_info\"", isOptional = true) + @DashboardInfo(description = "Specify the name of the table that will store the session info for users.", + defaultValue = "\"session_info\"", isOptional = true) private String postgresql_session_info_table_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store the user information, along with their email and hashed password.", defaultValue = "\"emailpassword_users\"", isOptional = true) + @DashboardInfo( + description = "Specify the name of the table that will store the user information, along with their email" + + " and hashed password.", + defaultValue = "\"emailpassword_users\"", isOptional = true) private String postgresql_emailpassword_users_table_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store the password reset tokens for users.", defaultValue = "\"emailpassword_pswd_reset_tokens\"", isOptional = true) + @DashboardInfo(description = "Specify the name of the table that will store the password reset tokens for users.", + defaultValue = "\"emailpassword_pswd_reset_tokens\"", isOptional = true) private String postgresql_emailpassword_pswd_reset_tokens_table_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store the email verification tokens for users.", defaultValue = "\"emailverification_tokens\"", isOptional = true) + @DashboardInfo( + description = "Specify the name of the table that will store the email verification tokens for users.", + defaultValue = "\"emailverification_tokens\"", isOptional = true) private String postgresql_emailverification_tokens_table_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store the verified email addresses.", defaultValue = "\"emailverification_verified_emails\"", isOptional = true) + @DashboardInfo(description = "Specify the name of the table that will store the verified email addresses.", + defaultValue = "\"emailverification_verified_emails\"", isOptional = true) private String postgresql_emailverification_verified_emails_table_name = null; @JsonProperty @NotConflictingWithinUserPool - @DashboardInfo(description = "Specify the name of the table that will store the thirdparty recipe users.", defaultValue = "\"thirdparty_users\"", isOptional = true) + @DashboardInfo(description = "Specify the name of the table that will store the thirdparty recipe users.", + defaultValue = "\"thirdparty_users\"", isOptional = true) private String postgresql_thirdparty_users_table_name = null; @JsonProperty @@ -121,25 +151,35 @@ public class PostgreSQLConfig { @JsonProperty @IgnoreForAnnotationCheck - @DashboardInfo(description = "Specify the PostgreSQL connection URI in the following format: postgresql://[user[:[password]]@]host[:port][/dbname][?attr1=val1&attr2=val2... Values provided via other configs will override values provided by this config.", defaultValue = "null", isOptional = true) + @DashboardInfo( + description = "Specify the PostgreSQL connection URI in the following format: " + + "postgresql://[user[:[password]]@]host[:port][/dbname][?attr1=val1&attr2=val2... Values provided " + + "via other configs will override values provided by this config.", + defaultValue = "null", isOptional = true) private String postgresql_connection_uri = null; @ConnectionPoolProperty - @DashboardInfo(description = "The connection attributes of the PostgreSQL database.", defaultValue = "\"allowPublicKeyRetrieval=true\"", isOptional = true) + @DashboardInfo(description = "The connection attributes of the PostgreSQL database.", + defaultValue = "\"allowPublicKeyRetrieval=true\"", isOptional = true) private String postgresql_connection_attributes = "allowPublicKeyRetrieval=true"; @ConnectionPoolProperty - @DashboardInfo(description = "The scheme of the PostgreSQL database.", defaultValue = "\"postgresql\"", isOptional = true) + @DashboardInfo(description = "The scheme of the PostgreSQL database.", defaultValue = "\"postgresql\"", + isOptional = true) private String postgresql_connection_scheme = "postgresql"; @JsonProperty @ConnectionPoolProperty - @DashboardInfo(description = "Timeout in milliseconds for the idle connections to be closed.", defaultValue = "60000", isOptional = true, isEditable = true) + @DashboardInfo(description = "Timeout in milliseconds for the idle connections to be closed.", + defaultValue = "60000", isOptional = true, isEditable = true) private long postgresql_idle_connection_timeout = 60000; @JsonProperty @ConnectionPoolProperty - @DashboardInfo(description = "Minimum number of idle connections to be kept active. If not set, minimum idle connections will be same as the connection pool size.", defaultValue = "null", isOptional = true, isEditable = true) + @DashboardInfo( + description = "Minimum number of idle connections to be kept active. If not set, minimum idle connections" + + " will be same as the connection pool size.", + defaultValue = "null", isOptional = true, isEditable = true) private Integer postgresql_minimum_idle_connections = null; @IgnoreForAnnotationCheck @@ -439,7 +479,8 @@ private void validateAndNormalise(boolean skipValidation) throws InvalidConfigEx } catch (Exception e) { throw new InvalidConfigException( "The provided postgresql connection URI has an incorrect format. Please use a format like " - + "postgresql://[user[:[password]]@]host[:port][/dbname][?attr1=val1&attr2=val2..."); + + + "postgresql://[user[:[password]]@]host[:port][/dbname][?attr1=val1&attr2=val2..."); } } else { if (this.getUser() == null) { @@ -613,21 +654,26 @@ private void validateAndNormalise(boolean skipValidation) throws InvalidConfigEx } if (postgresql_emailpassword_pswd_reset_tokens_table_name != null) { - postgresql_emailpassword_pswd_reset_tokens_table_name = addSchemaToTableName(postgresql_emailpassword_pswd_reset_tokens_table_name); + postgresql_emailpassword_pswd_reset_tokens_table_name = addSchemaToTableName( + postgresql_emailpassword_pswd_reset_tokens_table_name); } else { - postgresql_emailpassword_pswd_reset_tokens_table_name = addSchemaAndPrefixToTableName("emailpassword_pswd_reset_tokens"); + postgresql_emailpassword_pswd_reset_tokens_table_name = addSchemaAndPrefixToTableName( + "emailpassword_pswd_reset_tokens"); } if (postgresql_emailverification_tokens_table_name != null) { - postgresql_emailverification_tokens_table_name = addSchemaToTableName(postgresql_emailverification_tokens_table_name); + postgresql_emailverification_tokens_table_name = addSchemaToTableName( + postgresql_emailverification_tokens_table_name); } else { postgresql_emailverification_tokens_table_name = addSchemaAndPrefixToTableName("emailverification_tokens"); } if (postgresql_emailverification_verified_emails_table_name != null) { - postgresql_emailverification_verified_emails_table_name = addSchemaToTableName(postgresql_emailverification_verified_emails_table_name); + postgresql_emailverification_verified_emails_table_name = addSchemaToTableName( + postgresql_emailverification_verified_emails_table_name); } else { - postgresql_emailverification_verified_emails_table_name = addSchemaAndPrefixToTableName("emailverification_verified_emails"); + postgresql_emailverification_verified_emails_table_name = addSchemaAndPrefixToTableName( + "emailverification_verified_emails"); } if (postgresql_thirdparty_users_table_name != null) { @@ -679,10 +725,11 @@ public String getConnectionPoolId() { try { String fieldName = field.getName(); String fieldValue = field.get(this) != null ? field.get(this).toString() : null; - if(fieldValue == null) { + if (fieldValue == null) { continue; } - // To ensure a unique connectionPoolId we include the database password and use the "|db_pass|" identifier. + // To ensure a unique connectionPoolId we include the database password and use the "|db_pass|" + // identifier. // This facilitates easy removal of the password from logs when necessary. if (fieldName.equals("postgresql_password")) { connectionPoolId.append("|db_pass|" + fieldValue + "|db_pass"); diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/ActiveUsersQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/ActiveUsersQueries.java index 3a39c384..327ed6ce 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/ActiveUsersQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/ActiveUsersQueries.java @@ -50,7 +50,8 @@ public static int countUsersActiveSince(Start start, AppIdentifier appIdentifier }); } - public static int countUsersActiveSinceAndHasMoreThanOneLoginMethod(Start start, AppIdentifier appIdentifier, long sinceTime) + public static int countUsersActiveSinceAndHasMoreThanOneLoginMethod(Start start, AppIdentifier appIdentifier, + long sinceTime) throws SQLException, StorageQueryException { // TODO: Active users are present only on public tenant and MFA users may be present on different storages String QUERY = "SELECT count(1) as c FROM (" @@ -121,30 +122,32 @@ public static void deleteUserActive_Transaction(Connection con, Start start, App }); } - public static int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(Start start, AppIdentifier appIdentifier, long sinceTime) + public static int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(Start start, + AppIdentifier appIdentifier, + long sinceTime) throws SQLException, StorageQueryException { // TODO: Active users are present only on public tenant and MFA users may be present on different storages String QUERY = - "SELECT COUNT (DISTINCT user_id) as c FROM (" - + " (" // users with more than one login method - + " SELECT primary_or_recipe_user_id AS user_id FROM (" - + " SELECT COUNT(user_id) as num_login_methods, app_id, primary_or_recipe_user_id" - + " FROM " + getConfig(start).getAppIdToUserIdTable() - + " WHERE app_id = ? AND primary_or_recipe_user_id IN (" - + " SELECT user_id FROM " + getConfig(start).getUserLastActiveTable() - + " WHERE app_id = ? AND last_active_time >= ?" - + " )" - + " GROUP BY (app_id, primary_or_recipe_user_id)" - + " ) AS nloginmethods" - + " WHERE num_login_methods > 1" - + " ) UNION (" // TOTP users - + " SELECT user_id FROM " + getConfig(start).getTotpUsersTable() - + " WHERE app_id = ? AND user_id IN (" - + " SELECT user_id FROM " + getConfig(start).getUserLastActiveTable() - + " WHERE app_id = ? AND last_active_time >= ?" - + " )" - + " )" - + ") AS all_users"; + "SELECT COUNT (DISTINCT user_id) as c FROM (" + + " (" // users with more than one login method + + " SELECT primary_or_recipe_user_id AS user_id FROM (" + + " SELECT COUNT(user_id) as num_login_methods, app_id, primary_or_recipe_user_id" + + " FROM " + getConfig(start).getAppIdToUserIdTable() + + " WHERE app_id = ? AND primary_or_recipe_user_id IN (" + + " SELECT user_id FROM " + getConfig(start).getUserLastActiveTable() + + " WHERE app_id = ? AND last_active_time >= ?" + + " )" + + " GROUP BY (app_id, primary_or_recipe_user_id)" + + " ) AS nloginmethods" + + " WHERE num_login_methods > 1" + + " ) UNION (" // TOTP users + + " SELECT user_id FROM " + getConfig(start).getTotpUsersTable() + + " WHERE app_id = ? AND user_id IN (" + + " SELECT user_id FROM " + getConfig(start).getUserLastActiveTable() + + " WHERE app_id = ? AND last_active_time >= ?" + + " )" + + " )" + + ") AS all_users"; return execute(start, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/DashboardQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/DashboardQueries.java index 135d2f7a..89e85607 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/DashboardQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/DashboardQueries.java @@ -51,7 +51,7 @@ public static String getQueryToCreateDashboardUsersTable(Start start) { + " PRIMARY KEY (app_id, user_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, dashboardUsersTable, "app_id", "fkey") + " FOREIGN KEY(app_id)" - + " REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -119,7 +119,8 @@ public static boolean deleteDashboardUserWithUserId(Start start, AppIdentifier a } - public static DashboardUser[] getAllDashBoardUsers(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { + public static DashboardUser[] getAllDashBoardUsers(Start start, AppIdentifier appIdentifier) + throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getDashboardUsersTable() + " WHERE app_id = ? ORDER BY time_joined ASC"; return QueryExecutorTemplate.execute(start, QUERY, @@ -172,8 +173,9 @@ public static boolean updateDashboardUsersPasswordWithUserId_Transaction(Start s return rowsUpdated > 0; } - public static void createDashboardSession(Start start, AppIdentifier appIdentifier, String userId, String sessionId, long timeCreated, - long expiry) throws SQLException, StorageQueryException { + public static void createDashboardSession(Start start, AppIdentifier appIdentifier, String userId, String sessionId, + long timeCreated, + long expiry) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + Config.getConfig(start).getDashboardSessionsTable() + "(app_id, user_id, session_id, time_created, expiry)" + " VALUES(?, ?, ?, ?, ?)"; QueryExecutorTemplate.update(start, QUERY, pst -> { @@ -185,7 +187,8 @@ public static void createDashboardSession(Start start, AppIdentifier appIdentifi }); } - public static DashboardSessionInfo getSessionInfoWithSessionId(Start start, AppIdentifier appIdentifier, String sessionId) + public static DashboardSessionInfo getSessionInfoWithSessionId(Start start, AppIdentifier appIdentifier, + String sessionId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getDashboardSessionsTable() + " WHERE app_id = ? AND session_id = ?"; @@ -200,7 +203,8 @@ public static DashboardSessionInfo getSessionInfoWithSessionId(Start start, AppI }); } - public static DashboardSessionInfo[] getAllSessionsForUserId(Start start, AppIdentifier appIdentifier, String userId) + public static DashboardSessionInfo[] getAllSessionsForUserId(Start start, AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getDashboardSessionsTable() + " WHERE app_id = ? AND user_id = ?"; @@ -234,7 +238,8 @@ public static DashboardUser getDashboardUserByEmail(Start start, AppIdentifier a }); } - public static boolean deleteDashboardUserSessionWithSessionId(Start start, AppIdentifier appIdentifier, String sessionId) + public static boolean deleteDashboardUserSessionWithSessionId(Start start, AppIdentifier appIdentifier, + String sessionId) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + Config.getConfig(start).getDashboardSessionsTable() + " WHERE app_id = ? AND session_id = ?"; diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/EmailPasswordQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/EmailPasswordQueries.java index 55bb51c4..efed6c7f 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/EmailPasswordQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/EmailPasswordQueries.java @@ -285,7 +285,9 @@ public static AuthRecipeUserInfo signUp(Start start, TenantIdentifier tenantIden { // all_auth_recipe_users String QUERY = "INSERT INTO " + getConfig(start).getUsersTable() - + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, primary_or_recipe_user_time_joined)" + + + + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, " + + "primary_or_recipe_user_time_joined)" + " VALUES(?, ?, ?, ?, ?, ?, ?)"; update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); @@ -375,8 +377,10 @@ public static void deleteUser_Transaction(Connection sqlCon, Start start, AppIde } } - private static UserInfoPartial getUserInfoUsingId_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, - String id) throws SQLException, StorageQueryException { + private static UserInfoPartial getUserInfoUsingId_Transaction(Start start, Connection sqlCon, + AppIdentifier appIdentifier, + String id) + throws SQLException, StorageQueryException { // we don't need a FOR UPDATE here because this is already part of a transaction, and locked on // app_id_to_user_id table String QUERY = "SELECT user_id, email, password_hash, time_joined FROM " @@ -426,7 +430,7 @@ public static List getUsersInfoUsingIdList(Start start, Set } public static List getUsersInfoUsingIdList_Transaction(Start start, Connection con, Set ids, - AppIdentifier appIdentifier) + AppIdentifier appIdentifier) throws SQLException, StorageQueryException { if (ids.size() > 0) { // No need to filter based on tenantId because the id list is already filtered for a tenant @@ -456,6 +460,7 @@ public static List getUsersInfoUsingIdList_Transaction(Start start, } return Collections.emptyList(); } + public static String lockEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier, String email) @@ -475,7 +480,7 @@ public static String lockEmail_Transaction(Start start, Connection con, } public static String getPrimaryUserIdUsingEmail(Start start, TenantIdentifier tenantIdentifier, - String email) + String email) throws StorageQueryException, SQLException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + "FROM " + getConfig(start).getEmailPasswordUserToTenantTable() + " AS ep" + @@ -495,8 +500,9 @@ public static String getPrimaryUserIdUsingEmail(Start start, TenantIdentifier te }); } - public static List getPrimaryUserIdsUsingEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier, - String email) + public static List getPrimaryUserIdsUsingEmail_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, + String email) throws StorageQueryException, SQLException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + "FROM " + getConfig(start).getEmailPasswordUsersTable() + " AS ep" + @@ -526,11 +532,14 @@ public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlC throw new UnknownUserIdException(); } - GeneralQueries.AccountLinkingInfo accountLinkingInfo = GeneralQueries.getAccountLinkingInfo_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userId); + GeneralQueries.AccountLinkingInfo accountLinkingInfo = GeneralQueries.getAccountLinkingInfo_Transaction(start, + sqlCon, tenantIdentifier.toAppIdentifier(), userId); { // all_auth_recipe_users String QUERY = "INSERT INTO " + getConfig(start).getUsersTable() - + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, is_linked_or_is_a_primary_user, recipe_id, time_joined, primary_or_recipe_user_time_joined)" + + + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, is_linked_or_is_a_primary_user, " + + "recipe_id, time_joined, primary_or_recipe_user_time_joined)" + " VALUES(?, ?, ?, ?, ?, ?, ?, ?)" + " ON CONFLICT DO NOTHING"; GeneralQueries.AccountLinkingInfo finalAccountLinkingInfo = accountLinkingInfo; @@ -545,14 +554,16 @@ public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlC pst.setLong(8, userInfo.timeJoined); }); - GeneralQueries.updateTimeJoinedForPrimaryUser_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), finalAccountLinkingInfo.primaryUserId); + GeneralQueries.updateTimeJoinedForPrimaryUser_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), + finalAccountLinkingInfo.primaryUserId); } { // emailpassword_user_to_tenant String QUERY = "INSERT INTO " + getConfig(start).getEmailPasswordUserToTenantTable() + "(app_id, tenant_id, user_id, email)" + " VALUES(?, ?, ?, ?) " + " ON CONFLICT ON CONSTRAINT " - + Utils.getConstraintName(Config.getConfig(start).getTableSchema(), getConfig(start).getEmailPasswordUserToTenantTable(), null, "pkey") + + Utils.getConstraintName(Config.getConfig(start).getTableSchema(), + getConfig(start).getEmailPasswordUserToTenantTable(), null, "pkey") + " DO NOTHING"; int numRows = update(sqlCon, QUERY, pst -> { diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/EmailVerificationQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/EmailVerificationQueries.java index 6fd00660..9c70cf8f 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/EmailVerificationQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/EmailVerificationQueries.java @@ -270,8 +270,10 @@ public static List isEmailVerified_transaction(Start start, Connection s // We have external user id stored in the email verification table, so we need to fetch the mapped userids for // calculating the verified emails - HashMap supertokensUserIdToExternalUserIdMap = UserIdMappingQueries.getUserIdMappingWithUserIds_Transaction(start, - sqlCon, appIdentifier, supertokensUserIds); + HashMap supertokensUserIdToExternalUserIdMap = + UserIdMappingQueries.getUserIdMappingWithUserIds_Transaction( + start, + sqlCon, appIdentifier, supertokensUserIds); HashMap externalUserIdToSupertokensUserIdMap = new HashMap<>(); List supertokensOrExternalUserIdsToQuery = new ArrayList<>(); @@ -298,7 +300,8 @@ public static List isEmailVerified_transaction(Start start, Connection s } String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable() - + " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(supertokensOrExternalUserIdsToQuery.size()) + + + " WHERE app_id = ? AND user_id IN (" + + Utils.generateCommaSeperatedQuestionMarks(supertokensOrExternalUserIdsToQuery.size()) + ") AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ")"; return execute(sqlCon, QUERY, pst -> { @@ -324,7 +327,7 @@ public static List isEmailVerified_transaction(Start start, Connection s } public static List isEmailVerified(Start start, AppIdentifier appIdentifier, - List userIdAndEmail) + List userIdAndEmail) throws SQLException, StorageQueryException { if (userIdAndEmail.isEmpty()) { @@ -339,7 +342,8 @@ public static List isEmailVerified(Start start, AppIdentifier appIdentif } // We have external user id stored in the email verification table, so we need to fetch the mapped userids for // calculating the verified emails - HashMap supertokensUserIdToExternalUserIdMap = UserIdMappingQueries.getUserIdMappingWithUserIds(start, + HashMap supertokensUserIdToExternalUserIdMap = UserIdMappingQueries.getUserIdMappingWithUserIds( + start, appIdentifier, supertokensUserIds); HashMap externalUserIdToSupertokensUserIdMap = new HashMap<>(); List supertokensOrExternalUserIdsToQuery = new ArrayList<>(); @@ -365,7 +369,8 @@ public static List isEmailVerified(Start start, AppIdentifier appIdentif supertokensOrExternalUserIdToEmailMap.put(supertokensOrExternalUserId, ue.email); } String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable() - + " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(supertokensOrExternalUserIdsToQuery.size()) + + + " WHERE app_id = ? AND user_id IN (" + + Utils.generateCommaSeperatedQuestionMarks(supertokensOrExternalUserIdsToQuery.size()) + ") AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ")"; return execute(start, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); @@ -476,7 +481,8 @@ public static boolean isUserIdBeingUsedForEmailVerification(Start start, AppIden } } - public static void updateIsEmailVerifiedToExternalUserId(Start start, AppIdentifier appIdentifier, String supertokensUserId, String externalUserId) + public static void updateIsEmailVerifiedToExternalUserId(Start start, AppIdentifier appIdentifier, + String supertokensUserId, String externalUserId) throws StorageQueryException { try { start.startTransaction((TransactionConnection con) -> { diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/GeneralQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/GeneralQueries.java index 94b54514..1608d3df 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/GeneralQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/GeneralQueries.java @@ -56,13 +56,15 @@ public class GeneralQueries { - private static boolean doesTableExists(Start start, Connection connection, String tableName) throws SQLException, StorageQueryException { + private static boolean doesTableExists(Start start, Connection connection, String tableName) + throws SQLException, StorageQueryException { try { String QUERY = "SELECT 1 FROM " + tableName + " LIMIT 1"; execute(connection, QUERY, NO_OP_SETTER, result -> null); return true; } catch (SQLException | StorageQueryException e) { - if (e.getMessage().contains("relation") && e.getMessage().contains(tableName) && e.getMessage().contains("does not exist")) { + if (e.getMessage().contains("relation") && e.getMessage().contains(tableName) && + e.getMessage().contains("does not exist")) { return false; } throw e; @@ -89,7 +91,8 @@ static String getQueryToCreateUsersTable(Start start) { + " REFERENCES " + Config.getConfig(start).getTenantsTable() + " (app_id, tenant_id) ON DELETE CASCADE," + "CONSTRAINT " + Utils.getConstraintName(schema, usersTable, "primary_or_recipe_user_id", "fkey") + " FOREIGN KEY(app_id, primary_or_recipe_user_id)" - + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + " (app_id, user_id) ON DELETE CASCADE," + + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + + " (app_id, user_id) ON DELETE CASCADE," + "CONSTRAINT " + Utils.getConstraintName(schema, usersTable, "user_id", "fkey") + " FOREIGN KEY(app_id, user_id)" + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + @@ -120,12 +123,16 @@ static String getQueryToCreateUserPaginationIndex2(Start start) { static String getQueryToCreateUserPaginationIndex3(Start start) { return "CREATE INDEX all_auth_recipe_users_pagination_index3 ON " + Config.getConfig(start).getUsersTable() - + "(recipe_id, app_id, tenant_id, primary_or_recipe_user_time_joined DESC, primary_or_recipe_user_id DESC);"; + + + "(recipe_id, app_id, tenant_id, primary_or_recipe_user_time_joined DESC, primary_or_recipe_user_id " + + "DESC);"; } static String getQueryToCreateUserPaginationIndex4(Start start) { return "CREATE INDEX all_auth_recipe_users_pagination_index4 ON " + Config.getConfig(start).getUsersTable() - + "(recipe_id, app_id, tenant_id, primary_or_recipe_user_time_joined ASC, primary_or_recipe_user_id DESC);"; + + + "(recipe_id, app_id, tenant_id, primary_or_recipe_user_time_joined ASC, primary_or_recipe_user_id " + + "DESC);"; } static String getQueryToCreatePrimaryUserId(Start start) { @@ -221,7 +228,8 @@ private static String getQueryToCreateAppIdToUserIdTable(Start start) { + " PRIMARY KEY (app_id, user_id), " + "CONSTRAINT " + Utils.getConstraintName(schema, appToUserTable, "primary_or_recipe_user_id", "fkey") + " FOREIGN KEY(app_id, primary_or_recipe_user_id)" - + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + " (app_id, user_id) ON DELETE CASCADE," + + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + + " (app_id, user_id) ON DELETE CASCADE," + "CONSTRAINT " + Utils.getConstraintName(schema, appToUserTable, "app_id", "fkey") + " FOREIGN KEY(app_id) REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" @@ -614,7 +622,7 @@ public static void deleteAllTables(Start start) throws SQLException, StorageQuer + getConfig(start).getUserRolesTable() + "," + getConfig(start).getDashboardUsersTable() + "," + getConfig(start).getDashboardSessionsTable() + "," - + getConfig(start).getTotpUsedCodesTable() + "," + + getConfig(start).getTotpUsedCodesTable() + "," + getConfig(start).getTotpUserDevicesTable() + "," + getConfig(start).getTotpUsersTable(); update(start, DROP_QUERY, NO_OP_SETTER); @@ -774,7 +782,8 @@ public static boolean doesUserIdExist(Start start, AppIdentifier appIdentifier, }, ResultSet::next); } - public static boolean doesUserIdExist_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String userId) + public static boolean doesUserIdExist_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { // We query both tables cause there is a case where a primary user ID exists, but its associated // recipe user ID has been deleted AND there are other recipe user IDs linked to this primary user ID already. @@ -986,8 +995,11 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant usersFromQuery = new ArrayList<>(); } else { - String finalQuery = "SELECT DISTINCT primary_or_recipe_user_id, primary_or_recipe_user_time_joined FROM ( " + USER_SEARCH_TAG_CONDITION.toString() + " )" - + " AS finalResultTable ORDER BY primary_or_recipe_user_time_joined " + timeJoinedOrder + ", primary_or_recipe_user_id DESC "; + String finalQuery = + "SELECT DISTINCT primary_or_recipe_user_id, primary_or_recipe_user_time_joined FROM ( " + + USER_SEARCH_TAG_CONDITION.toString() + " )" + + " AS finalResultTable ORDER BY primary_or_recipe_user_time_joined " + + timeJoinedOrder + ", primary_or_recipe_user_id DESC "; usersFromQuery = execute(start, finalQuery, pst -> { for (int i = 1; i <= queryList.size(); i++) { pst.setString(i, queryList.get(i - 1)); @@ -1023,9 +1035,12 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant recipeIdCondition = recipeIdCondition + " AND"; } String timeJoinedOrderSymbol = timeJoinedOrder.equals("ASC") ? ">" : "<"; - String QUERY = "SELECT DISTINCT primary_or_recipe_user_id, primary_or_recipe_user_time_joined FROM " + getConfig(start).getUsersTable() + " WHERE " + String QUERY = "SELECT DISTINCT primary_or_recipe_user_id, primary_or_recipe_user_time_joined FROM " + + getConfig(start).getUsersTable() + " WHERE " + recipeIdCondition + " (primary_or_recipe_user_time_joined " + timeJoinedOrderSymbol - + " ? OR (primary_or_recipe_user_time_joined = ? AND primary_or_recipe_user_id <= ?)) AND app_id = ? AND tenant_id = ?" + + + " ? OR (primary_or_recipe_user_time_joined = ? AND primary_or_recipe_user_id <= ?)) AND " + + "app_id = ? AND tenant_id = ?" + " ORDER BY primary_or_recipe_user_time_joined " + timeJoinedOrder + ", primary_or_recipe_user_id DESC LIMIT ?"; usersFromQuery = execute(start, QUERY, pst -> { @@ -1051,7 +1066,8 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant }); } else { String recipeIdCondition = RECIPE_ID_CONDITION.toString(); - String QUERY = "SELECT DISTINCT primary_or_recipe_user_id, primary_or_recipe_user_time_joined FROM " + getConfig(start).getUsersTable() + " WHERE "; + String QUERY = "SELECT DISTINCT primary_or_recipe_user_id, primary_or_recipe_user_time_joined FROM " + + getConfig(start).getUsersTable() + " WHERE "; if (!recipeIdCondition.equals("")) { QUERY += recipeIdCondition + " AND"; } @@ -1237,7 +1253,8 @@ public static AuthRecipeUserInfo[] listPrimaryUsersByThirdPartyInfo_Transaction( // now that we have locks on all the relevant tables, we can read from them safely List userIds = ThirdPartyQueries.listUserIdsByThirdPartyInfo_Transaction(start, sqlCon, appIdentifier, thirdPartyId, thirdPartyUserId); - List result = getPrimaryUserInfoForUserIds_Transaction(start, sqlCon, appIdentifier, userIds); + List result = getPrimaryUserInfoForUserIds_Transaction(start, sqlCon, appIdentifier, + userIds); // this is going to order them based on oldest that joined to newest that joined. result.sort(Comparator.comparingLong(o -> o.timeJoined)); @@ -1335,9 +1352,9 @@ public static AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber(Start start, } public static AuthRecipeUserInfo getPrimaryUserByThirdPartyInfo(Start start, - TenantIdentifier tenantIdentifier, - String thirdPartyId, - String thirdPartyUserId) + TenantIdentifier tenantIdentifier, + String thirdPartyId, + String thirdPartyUserId) throws StorageQueryException, SQLException { String userId = ThirdPartyQueries.getUserIdByThirdPartyInfo(start, tenantIdentifier, thirdPartyId, thirdPartyUserId); @@ -1371,7 +1388,7 @@ public static AuthRecipeUserInfo getPrimaryUserInfoForUserId(Start start, AppIde } public static AuthRecipeUserInfo getPrimaryUserInfoForUserId_Transaction(Start start, Connection con, - AppIdentifier appIdentifier, String id) + AppIdentifier appIdentifier, String id) throws SQLException, StorageQueryException { List ids = new ArrayList<>(); ids.add(id); @@ -1394,14 +1411,18 @@ private static List getPrimaryUserInfoForUserIds(Start start // which is linked to a primary user ID in which case it won't be in the primary_or_recipe_user_id column, // or the input may have a primary user ID whose recipe user ID was removed, so it won't be in the user_id // column - String QUERY = "SELECT au.user_id, au.primary_or_recipe_user_id, au.is_linked_or_is_a_primary_user, au.recipe_id, aaru.tenant_id, aaru.time_joined FROM " + getConfig(start).getAppIdToUserIdTable() + " as au " + - "LEFT JOIN " + getConfig(start).getUsersTable() + " as aaru ON au.app_id = aaru.app_id AND au.user_id = aaru.user_id" + - " WHERE au.primary_or_recipe_user_id IN (SELECT primary_or_recipe_user_id FROM " + - getConfig(start).getAppIdToUserIdTable() + " WHERE (user_id IN (" - + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + - ") OR primary_or_recipe_user_id IN (" + - Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + - ")) AND app_id = ?) AND au.app_id = ?"; + String QUERY = + "SELECT au.user_id, au.primary_or_recipe_user_id, au.is_linked_or_is_a_primary_user, au.recipe_id, " + + "aaru.tenant_id, aaru.time_joined FROM " + + getConfig(start).getAppIdToUserIdTable() + " as au " + + "LEFT JOIN " + getConfig(start).getUsersTable() + + " as aaru ON au.app_id = aaru.app_id AND au.user_id = aaru.user_id" + + " WHERE au.primary_or_recipe_user_id IN (SELECT primary_or_recipe_user_id FROM " + + getConfig(start).getAppIdToUserIdTable() + " WHERE (user_id IN (" + + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + + ") OR primary_or_recipe_user_id IN (" + + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + + ")) AND app_id = ?) AND au.app_id = ?"; List allAuthUsersResult = execute(start, QUERY, pst -> { // IN user_id @@ -1475,8 +1496,8 @@ private static List getPrimaryUserInfoForUserIds(Start start } private static List getPrimaryUserInfoForUserIds_Transaction(Start start, Connection sqlCon, - AppIdentifier appIdentifier, - List userIds) + AppIdentifier appIdentifier, + List userIds) throws StorageQueryException, SQLException { if (userIds.size() == 0) { return new ArrayList<>(); @@ -1486,14 +1507,18 @@ private static List getPrimaryUserInfoForUserIds_Transaction // which is linked to a primary user ID in which case it won't be in the primary_or_recipe_user_id column, // or the input may have a primary user ID whose recipe user ID was removed, so it won't be in the user_id // column - String QUERY = "SELECT au.user_id, au.primary_or_recipe_user_id, au.is_linked_or_is_a_primary_user, au.recipe_id, aaru.tenant_id, aaru.time_joined FROM " + getConfig(start).getAppIdToUserIdTable() + " as au" + - " LEFT JOIN " + getConfig(start).getUsersTable() + " as aaru ON au.app_id = aaru.app_id AND au.user_id = aaru.user_id" + - " WHERE au.primary_or_recipe_user_id IN (SELECT primary_or_recipe_user_id FROM " + - getConfig(start).getAppIdToUserIdTable() + " WHERE (user_id IN (" - + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + - ") OR primary_or_recipe_user_id IN (" + - Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + - ")) AND app_id = ?) AND au.app_id = ?"; + String QUERY = + "SELECT au.user_id, au.primary_or_recipe_user_id, au.is_linked_or_is_a_primary_user, au.recipe_id, " + + "aaru.tenant_id, aaru.time_joined FROM " + + getConfig(start).getAppIdToUserIdTable() + " as au" + + " LEFT JOIN " + getConfig(start).getUsersTable() + + " as aaru ON au.app_id = aaru.app_id AND au.user_id = aaru.user_id" + + " WHERE au.primary_or_recipe_user_id IN (SELECT primary_or_recipe_user_id FROM " + + getConfig(start).getAppIdToUserIdTable() + " WHERE (user_id IN (" + + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + + ") OR primary_or_recipe_user_id IN (" + + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + + ")) AND app_id = ?) AND au.app_id = ?"; List allAuthUsersResult = execute(sqlCon, QUERY, pst -> { // IN user_id @@ -1530,10 +1555,13 @@ private static List getPrimaryUserInfoForUserIds_Transaction List loginMethods = new ArrayList<>(); loginMethods.addAll( - EmailPasswordQueries.getUsersInfoUsingIdList_Transaction(start, sqlCon, recipeUserIdsToFetch, appIdentifier)); - loginMethods.addAll(ThirdPartyQueries.getUsersInfoUsingIdList_Transaction(start, sqlCon, recipeUserIdsToFetch, appIdentifier)); + EmailPasswordQueries.getUsersInfoUsingIdList_Transaction(start, sqlCon, recipeUserIdsToFetch, + appIdentifier)); + loginMethods.addAll(ThirdPartyQueries.getUsersInfoUsingIdList_Transaction(start, sqlCon, recipeUserIdsToFetch, + appIdentifier)); loginMethods.addAll( - PasswordlessQueries.getUsersInfoUsingIdList_Transaction(start, sqlCon, recipeUserIdsToFetch, appIdentifier)); + PasswordlessQueries.getUsersInfoUsingIdList_Transaction(start, sqlCon, recipeUserIdsToFetch, + appIdentifier)); Map recipeUserIdToLoginMethodMap = new HashMap<>(); for (LoginMethod loginMethod : loginMethods) { @@ -1732,20 +1760,20 @@ public static int getUsersCountWithMoreThanOneLoginMethod(Start start, AppIdenti public static int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { String QUERY = - "SELECT COUNT (DISTINCT user_id) as c FROM (" - + " (" // Users with number of login methods > 1 - + " SELECT primary_or_recipe_user_id AS user_id FROM (" - + " SELECT COUNT(user_id) as num_login_methods, app_id, primary_or_recipe_user_id" - + " FROM " + getConfig(start).getAppIdToUserIdTable() - + " WHERE app_id = ? " - + " GROUP BY (app_id, primary_or_recipe_user_id)" - + " ) AS nloginmethods" - + " WHERE num_login_methods > 1" - + " ) UNION (" // TOTP users - + " SELECT user_id FROM " + getConfig(start).getTotpUsersTable() - + " WHERE app_id = ?" - + " )" - + ") AS all_users"; + "SELECT COUNT (DISTINCT user_id) as c FROM (" + + " (" // Users with number of login methods > 1 + + " SELECT primary_or_recipe_user_id AS user_id FROM (" + + " SELECT COUNT(user_id) as num_login_methods, app_id, primary_or_recipe_user_id" + + " FROM " + getConfig(start).getAppIdToUserIdTable() + + " WHERE app_id = ? " + + " GROUP BY (app_id, primary_or_recipe_user_id)" + + " ) AS nloginmethods" + + " WHERE num_login_methods > 1" + + " ) UNION (" // TOTP users + + " SELECT user_id FROM " + getConfig(start).getTotpUsersTable() + + " WHERE app_id = ?" + + " )" + + ") AS all_users"; return execute(start, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); @@ -1768,7 +1796,8 @@ public static boolean checkIfUsesAccountLinking(Start start, AppIdentifier appId }); } - public static AccountLinkingInfo getAccountLinkingInfo_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String userId) + public static AccountLinkingInfo getAccountLinkingInfo_Transaction(Start start, Connection sqlCon, + AppIdentifier appIdentifier, String userId) throws SQLException, StorageQueryException { GeneralQueries.AccountLinkingInfo accountLinkingInfo = new GeneralQueries.AccountLinkingInfo(userId, false); { @@ -1790,7 +1819,8 @@ public static AccountLinkingInfo getAccountLinkingInfo_Transaction(Start start, return accountLinkingInfo; } - public static void updateTimeJoinedForPrimaryUser_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String primaryUserId) + public static void updateTimeJoinedForPrimaryUser_Transaction(Start start, Connection sqlCon, + AppIdentifier appIdentifier, String primaryUserId) throws SQLException, StorageQueryException { String QUERY = "UPDATE " + getConfig(start).getUsersTable() + " SET primary_or_recipe_user_time_joined = (SELECT MIN(time_joined) FROM " + diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/JWTSigningQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/JWTSigningQueries.java index f57c4402..9e80fe48 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/JWTSigningQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/JWTSigningQueries.java @@ -52,14 +52,14 @@ static String getQueryToCreateJWTSigningTable(Start start) { return "CREATE TABLE IF NOT EXISTS " + jwtSigningKeysTable + " (" + "app_id VARCHAR(64) DEFAULT 'public'," + "key_id VARCHAR(255) NOT NULL," - + "key_string TEXT NOT NULL," + + "key_string TEXT NOT NULL," + "algorithm VARCHAR(10) NOT NULL," - + "created_at BIGINT," + + "created_at BIGINT," + "CONSTRAINT " + Utils.getConstraintName(schema, jwtSigningKeysTable, null, "pkey") + " PRIMARY KEY(app_id, key_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, jwtSigningKeysTable, "app_id", "fkey") + " FOREIGN KEY(app_id)" - + " REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -75,7 +75,7 @@ public static List getJWTSigningKeys_Transaction(Start start, String QUERY = "SELECT * FROM " + getConfig(start).getJWTSigningKeysTable() + " WHERE app_id = ? ORDER BY created_at DESC FOR UPDATE"; - return execute(con, QUERY, pst -> pst.setString(1, appIdentifier.getAppId()),result -> { + return execute(con, QUERY, pst -> pst.setString(1, appIdentifier.getAppId()), result -> { List keys = new ArrayList<>(); while (result.next()) { diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/MultitenancyQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/MultitenancyQueries.java index 447ffb40..a6c9b749 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/MultitenancyQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/MultitenancyQueries.java @@ -53,7 +53,8 @@ static String getQueryToCreateTenantConfigsTable(Start start) { + "third_party_enabled BOOLEAN," + "is_first_factors_null BOOLEAN," + "is_third_party_providers_null BOOLEAN," - + "CONSTRAINT " + Utils.getConstraintName(schema, tenantConfigsTable, null, "pkey") + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id)" + + "CONSTRAINT " + Utils.getConstraintName(schema, tenantConfigsTable, null, "pkey") + + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id)" + ");"; // @formatter:on } @@ -84,10 +85,12 @@ static String getQueryToCreateTenantThirdPartyProvidersTable(Start start) { + "user_info_map_from_user_info_endpoint_user_id VARCHAR(64)," + "user_info_map_from_user_info_endpoint_email VARCHAR(64)," + "user_info_map_from_user_info_endpoint_email_verified VARCHAR(64)," - + "CONSTRAINT " + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, null, "pkey") + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id)," + + "CONSTRAINT " + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, null, "pkey") + + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, "tenant_id", "fkey") + " FOREIGN KEY(connection_uri_domain, app_id, tenant_id)" - + " REFERENCES " + Config.getConfig(start).getTenantConfigsTable() + " (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getTenantConfigsTable() + + " (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -111,16 +114,20 @@ static String getQueryToCreateTenantThirdPartyProviderClientsTable(Start start) + "scope VARCHAR(128)[]," + "force_pkce BOOLEAN," + "additional_config TEXT," - + "CONSTRAINT " + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, null, "pkey") + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id, client_type)," - + "CONSTRAINT " + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, "third_party_id", "fkey") + + "CONSTRAINT " + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, null, "pkey") + + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id, client_type)," + + "CONSTRAINT " + + Utils.getConstraintName(schema, tenantThirdPartyProvidersTable, "third_party_id", "fkey") + " FOREIGN KEY(connection_uri_domain, app_id, tenant_id, third_party_id)" - + " REFERENCES " + Config.getConfig(start).getTenantThirdPartyProvidersTable() + " (connection_uri_domain, app_id, tenant_id, third_party_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getTenantThirdPartyProvidersTable() + + " (connection_uri_domain, app_id, tenant_id, third_party_id) ON DELETE CASCADE" + ");"; } public static String getQueryToCreateThirdPartyIdIndexForTenantThirdPartyProviderClientsTable(Start start) { return "CREATE INDEX IF NOT EXISTS tenant_thirdparty_provider_clients_third_party_id_index ON " - + getConfig(start).getTenantThirdPartyProviderClientsTable() + " (connection_uri_domain, app_id, tenant_id, third_party_id);"; + + getConfig(start).getTenantThirdPartyProviderClientsTable() + + " (connection_uri_domain, app_id, tenant_id, third_party_id);"; } public static String getQueryToCreateFirstFactorsTable(Start start) { @@ -136,7 +143,8 @@ public static String getQueryToCreateFirstFactorsTable(Start start) { + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id, factor_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, tableName, "tenant_id", "fkey") + " FOREIGN KEY (connection_uri_domain, app_id, tenant_id)" - + " REFERENCES " + Config.getConfig(start).getTenantConfigsTable() + " (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getTenantConfigsTable() + + " (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -159,14 +167,16 @@ public static String getQueryToCreateRequiredSecondaryFactorsTable(Start start) + " PRIMARY KEY (connection_uri_domain, app_id, tenant_id, factor_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, tableName, "tenant_id", "fkey") + " FOREIGN KEY (connection_uri_domain, app_id, tenant_id)" - + " REFERENCES " + Config.getConfig(start).getTenantConfigsTable() + " (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getTenantConfigsTable() + + " (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE" + ");"; // @formatter:on } public static String getQueryToCreateTenantIdIndexForRequiredSecondaryFactorsTable(Start start) { return "CREATE INDEX IF NOT EXISTS tenant_default_required_factor_ids_tenant_id_index ON " - + getConfig(start).getTenantRequiredSecondaryFactorsTable() + " (connection_uri_domain, app_id, tenant_id);"; + + getConfig(start).getTenantRequiredSecondaryFactorsTable() + + " (connection_uri_domain, app_id, tenant_id);"; } @@ -186,10 +196,12 @@ private static void executeCreateTenantQueries(Start start, Connection sqlCon, T } MfaSqlHelper.createFirstFactors(start, sqlCon, tenantConfig.tenantIdentifier, tenantConfig.firstFactors); - MfaSqlHelper.createRequiredSecondaryFactors(start, sqlCon, tenantConfig.tenantIdentifier, tenantConfig.requiredSecondaryFactors); + MfaSqlHelper.createRequiredSecondaryFactors(start, sqlCon, tenantConfig.tenantIdentifier, + tenantConfig.requiredSecondaryFactors); } - public static void createTenantConfig(Start start, TenantConfig tenantConfig) throws StorageQueryException, StorageTransactionLogicException { + public static void createTenantConfig(Start start, TenantConfig tenantConfig) + throws StorageQueryException, StorageTransactionLogicException { start.startTransaction(con -> { Connection sqlCon = (Connection) con.getConnection(); { @@ -205,7 +217,8 @@ public static void createTenantConfig(Start start, TenantConfig tenantConfig) th }); } - public static boolean deleteTenantConfig(Start start, TenantIdentifier tenantIdentifier) throws StorageQueryException { + public static boolean deleteTenantConfig(Start start, TenantIdentifier tenantIdentifier) + throws StorageQueryException { try { String QUERY = "DELETE FROM " + getConfig(start).getTenantConfigsTable() + " WHERE connection_uri_domain = ? AND app_id = ? AND tenant_id = ?"; @@ -223,7 +236,8 @@ public static boolean deleteTenantConfig(Start start, TenantIdentifier tenantIde } } - public static void overwriteTenantConfig(Start start, TenantConfig tenantConfig) throws StorageQueryException, StorageTransactionLogicException { + public static void overwriteTenantConfig(Start start, TenantConfig tenantConfig) + throws StorageQueryException, StorageTransactionLogicException { start.startTransaction(con -> { Connection sqlCon = (Connection) con.getConnection(); { @@ -237,7 +251,8 @@ public static void overwriteTenantConfig(Start start, TenantConfig tenantConfig) pst.setString(3, tenantConfig.tenantIdentifier.getTenantId()); }); if (rowsAffected == 0) { - throw new StorageTransactionLogicException(new TenantOrAppNotFoundException(tenantConfig.tenantIdentifier)); + throw new StorageTransactionLogicException( + new TenantOrAppNotFoundException(tenantConfig.tenantIdentifier)); } } @@ -260,16 +275,21 @@ public static TenantConfig[] getAllTenants(Start start) throws StorageQueryExcep try { // Map TenantIdentifier -> thirdPartyId -> clientType - HashMap>> providerClientsMap = ThirdPartyProviderClientSQLHelper.selectAll(start); + HashMap>> providerClientsMap = ThirdPartyProviderClientSQLHelper.selectAll( + start); // Map (tenantIdentifier) -> thirdPartyId -> provider - HashMap> providerMap = ThirdPartyProviderSQLHelper.selectAll(start, providerClientsMap); + HashMap> providerMap = + ThirdPartyProviderSQLHelper.selectAll( + start, providerClientsMap); // Map (tenantIdentifier) -> firstFactors HashMap firstFactorsMap = MfaSqlHelper.selectAllFirstFactors(start); // Map (tenantIdentifier) -> requiredSecondaryFactors - HashMap requiredSecondaryFactorsMap = MfaSqlHelper.selectAllRequiredSecondaryFactors(start); + HashMap requiredSecondaryFactorsMap = + MfaSqlHelper.selectAllRequiredSecondaryFactors( + start); return TenantConfigSQLHelper.selectAll(start, providerMap, firstFactorsMap, requiredSecondaryFactorsMap); } catch (SQLException throwables) { @@ -294,7 +314,7 @@ public static void addTenantIdInTargetStorage(Start start, TenantIdentifier tena } public static void addTenantIdInTargetStorage_Transaction(Start start, Connection con, - TenantIdentifier tenantIdentifier) throws + TenantIdentifier tenantIdentifier) throws SQLException, StorageQueryException { { if (Start.isTesting && simulateErrorInAddingTenantIdInTargetStorage_forTesting) { @@ -318,7 +338,7 @@ public static void addTenantIdInTargetStorage_Transaction(Start start, Connectio + "(app_id, created_at_time)" + " VALUES(?, ?) ON CONFLICT DO NOTHING"; update(con, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); - pst.setLong(2, currentTime); + pst.setLong(2, currentTime); }); } @@ -329,14 +349,14 @@ public static void addTenantIdInTargetStorage_Transaction(Start start, Connectio update(con, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); pst.setString(2, tenantIdentifier.getTenantId()); - pst.setLong(3, currentTime); + pst.setLong(3, currentTime); }); } } } public static void deleteTenantIdInTargetStorage(Start start, TenantIdentifier tenantIdentifier) - throws StorageQueryException { + throws StorageQueryException { try { if (tenantIdentifier.getTenantId().equals(TenantIdentifier.DEFAULT_TENANT_ID)) { // Delete the app diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/PasswordlessQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/PasswordlessQueries.java index 8f8df3d6..bfe1a2a9 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/PasswordlessQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/PasswordlessQueries.java @@ -388,7 +388,8 @@ public static void deleteCode_Transaction(Start start, Connection con, TenantIde }); } - public static AuthRecipeUserInfo createUser(Start start, TenantIdentifier tenantIdentifier, String id, @Nullable String email, + public static AuthRecipeUserInfo createUser(Start start, TenantIdentifier tenantIdentifier, String id, + @Nullable String email, @Nullable String phoneNumber, long timeJoined) throws StorageTransactionLogicException, StorageQueryException { return start.startTransaction(con -> { @@ -407,7 +408,9 @@ public static AuthRecipeUserInfo createUser(Start start, TenantIdentifier tenant { // all_auth_recipe_users String QUERY = "INSERT INTO " + getConfig(start).getUsersTable() - + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, primary_or_recipe_user_time_joined)" + + + + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, " + + "primary_or_recipe_user_time_joined)" + " VALUES(?, ?, ?, ?, ?, ?, ?)"; update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); @@ -457,7 +460,7 @@ public static AuthRecipeUserInfo createUser(Start start, TenantIdentifier tenant } private static UserInfoWithTenantId[] getUserInfosWithTenant_Transaction(Start start, Connection con, - AppIdentifier appIdentifier, String userId) + AppIdentifier appIdentifier, String userId) throws StorageQueryException, SQLException { String QUERY = "SELECT pl_users.user_id as user_id, pl_users.email as email, " + "pl_users.phone_number as phone_number, pl_users_to_tenant.tenant_id as tenant_id " @@ -742,7 +745,7 @@ public static List getUsersInfoUsingIdList(Start start, Set } public static List getUsersInfoUsingIdList_Transaction(Start start, Connection con, Set ids, - AppIdentifier appIdentifier) + AppIdentifier appIdentifier) throws SQLException, StorageQueryException { if (ids.size() > 0) { // No need to filter based on tenantId because the id list is already filtered for a tenant @@ -772,7 +775,7 @@ public static List getUsersInfoUsingIdList_Transaction(Start start, } private static UserInfoPartial getUserById_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, - String userId) + String userId) throws StorageQueryException, SQLException { // we don't need a LOCK here because this is already part of a transaction, and locked on app_id_to_user_id // table @@ -810,8 +813,8 @@ public static List lockEmail_Transaction(Start start, Connection con, Ap } public static List lockPhoneAndTenant_Transaction(Start start, Connection con, - AppIdentifier appIdentifier, - String phoneNumber) + AppIdentifier appIdentifier, + String phoneNumber) throws SQLException, StorageQueryException { String QUERY = "SELECT user_id FROM " + getConfig(start).getPasswordlessUsersTable() + @@ -829,7 +832,7 @@ public static List lockPhoneAndTenant_Transaction(Start start, Connectio } public static String getPrimaryUserIdUsingEmail(Start start, TenantIdentifier tenantIdentifier, - String email) + String email) throws StorageQueryException, SQLException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + "FROM " + getConfig(start).getPasswordlessUserToTenantTable() + " AS pless" + @@ -849,8 +852,9 @@ public static String getPrimaryUserIdUsingEmail(Start start, TenantIdentifier te }); } - public static List getPrimaryUserIdsUsingEmail_Transaction(Start start, Connection con, AppIdentifier appIdentifier, - String email) + public static List getPrimaryUserIdsUsingEmail_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, + String email) throws StorageQueryException, SQLException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + "FROM " + getConfig(start).getPasswordlessUsersTable() + " AS pless" + @@ -891,8 +895,9 @@ public static String getPrimaryUserByPhoneNumber(Start start, TenantIdentifier t }); } - public static List listUserIdsByPhoneNumber_Transaction(Start start, Connection con, AppIdentifier appIdentifier, - @Nonnull String phoneNumber) + public static List listUserIdsByPhoneNumber_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, + @Nonnull String phoneNumber) throws StorageQueryException, SQLException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " + "FROM " + getConfig(start).getPasswordlessUsersTable() + " AS pless" + @@ -922,11 +927,14 @@ public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlC throw new UnknownUserIdException(); } - GeneralQueries.AccountLinkingInfo accountLinkingInfo = GeneralQueries.getAccountLinkingInfo_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userId); + GeneralQueries.AccountLinkingInfo accountLinkingInfo = GeneralQueries.getAccountLinkingInfo_Transaction(start, + sqlCon, tenantIdentifier.toAppIdentifier(), userId); { // all_auth_recipe_users String QUERY = "INSERT INTO " + getConfig(start).getUsersTable() - + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, is_linked_or_is_a_primary_user, recipe_id, time_joined, primary_or_recipe_user_time_joined)" + + + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, is_linked_or_is_a_primary_user, " + + "recipe_id, time_joined, primary_or_recipe_user_time_joined)" + " VALUES(?, ?, ?, ?, ?, ?, ?, ?)" + " ON CONFLICT DO NOTHING"; update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); @@ -939,14 +947,16 @@ public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlC pst.setLong(8, userInfo.timeJoined); }); - GeneralQueries.updateTimeJoinedForPrimaryUser_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), accountLinkingInfo.primaryUserId); + GeneralQueries.updateTimeJoinedForPrimaryUser_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), + accountLinkingInfo.primaryUserId); } { // passwordless_user_to_tenant String QUERY = "INSERT INTO " + getConfig(start).getPasswordlessUserToTenantTable() + "(app_id, tenant_id, user_id, email, phone_number)" + " VALUES(?, ?, ?, ?, ?)" + " ON CONFLICT ON CONSTRAINT " - + Utils.getConstraintName(Config.getConfig(start).getTableSchema(), getConfig(start).getPasswordlessUserToTenantTable(), null, "pkey") + + Utils.getConstraintName(Config.getConfig(start).getTableSchema(), + getConfig(start).getPasswordlessUserToTenantTable(), null, "pkey") + " DO NOTHING"; int numRows = update(sqlCon, QUERY, pst -> { diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/TOTPQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/TOTPQueries.java index 8a8269d5..60270a65 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/TOTPQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/TOTPQueries.java @@ -32,7 +32,7 @@ public static String getQueryToCreateUsersTable(Start start) { + " PRIMARY KEY (app_id, user_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, tableName, "app_id", "fkey") + " FOREIGN KEY(app_id)" - + " REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getAppsTable() + " (app_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -119,10 +119,13 @@ private static int insertUser_Transaction(Start start, Connection con, AppIdenti }); } - private static int insertDevice_Transaction(Start start, Connection con, AppIdentifier appIdentifier, TOTPDevice device) + private static int insertDevice_Transaction(Start start, Connection con, AppIdentifier appIdentifier, + TOTPDevice device) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + Config.getConfig(start).getTotpUserDevicesTable() - + " (app_id, user_id, device_name, secret_key, period, skew, verified, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + + + " (app_id, user_id, device_name, secret_key, period, skew, verified, created_at) VALUES (?, ?, ?, ?, " + + "?, ?, ?, ?)"; return update(con, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); @@ -136,13 +139,15 @@ private static int insertDevice_Transaction(Start start, Connection con, AppIden }); } - public static void createDevice_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, TOTPDevice device) + public static void createDevice_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, + TOTPDevice device) throws SQLException, StorageQueryException { insertUser_Transaction(start, sqlCon, appIdentifier, device.userId); insertDevice_Transaction(start, sqlCon, appIdentifier, device); } - public static TOTPDevice getDeviceByName_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String userId, String deviceName) + public static TOTPDevice getDeviceByName_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, + String userId, String deviceName) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getTotpUserDevicesTable() + " WHERE app_id = ? AND user_id = ? AND device_name = ? FOR UPDATE;"; @@ -170,7 +175,8 @@ public static int markDeviceAsVerified(Start start, AppIdentifier appIdentifier, }); } - public static int deleteDevice_Transaction(Start start, Connection con, AppIdentifier appIdentifier, String userId, String deviceName) + public static int deleteDevice_Transaction(Start start, Connection con, AppIdentifier appIdentifier, String userId, + String deviceName) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + Config.getConfig(start).getTotpUserDevicesTable() + " WHERE app_id = ? AND user_id = ? AND device_name = ?;"; @@ -207,7 +213,8 @@ public static boolean removeUser(Start start, TenantIdentifier tenantIdentifier, return removedUsersCount > 0; } - public static int updateDeviceName(Start start, AppIdentifier appIdentifier, String userId, String oldDeviceName, String newDeviceName) + public static int updateDeviceName(Start start, AppIdentifier appIdentifier, String userId, String oldDeviceName, + String newDeviceName) throws StorageQueryException, SQLException { String QUERY = "UPDATE " + Config.getConfig(start).getTotpUserDevicesTable() + " SET device_name = ? WHERE app_id = ? AND user_id = ? AND device_name = ?;"; @@ -238,7 +245,8 @@ public static TOTPDevice[] getDevices(Start start, AppIdentifier appIdentifier, }); } - public static TOTPDevice[] getDevices_Transaction(Start start, Connection con, AppIdentifier appIdentifier, String userId) + public static TOTPDevice[] getDevices_Transaction(Start start, Connection con, AppIdentifier appIdentifier, + String userId) throws StorageQueryException, SQLException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getTotpUserDevicesTable() + " WHERE app_id = ? AND user_id = ? FOR UPDATE;"; @@ -257,10 +265,13 @@ public static TOTPDevice[] getDevices_Transaction(Start start, Connection con, A } - public static int insertUsedCode_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier, TOTPUsedCode code) + public static int insertUsedCode_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier, + TOTPUsedCode code) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + Config.getConfig(start).getTotpUsedCodesTable() - + " (app_id, tenant_id, user_id, code, is_valid, expiry_time_ms, created_time_ms) VALUES (?, ?, ?, ?, ?, ?, ?);"; + + + " (app_id, tenant_id, user_id, code, is_valid, expiry_time_ms, created_time_ms) VALUES (?, ?, ?, ?, " + + "?, ?, ?);"; return update(con, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); @@ -278,7 +289,7 @@ public static int insertUsedCode_Transaction(Start start, Connection con, Tenant * order of creation time. */ public static TOTPUsedCode[] getAllUsedCodesDescOrder_Transaction(Start start, Connection con, - TenantIdentifier tenantIdentifier, String userId) + TenantIdentifier tenantIdentifier, String userId) throws SQLException, StorageQueryException { // Take a lock based on the user id: String QUERY = "SELECT * FROM " + diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/ThirdPartyQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/ThirdPartyQueries.java index 2a37c9dc..964b53cd 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/ThirdPartyQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/ThirdPartyQueries.java @@ -117,7 +117,9 @@ public static AuthRecipeUserInfo signUp(Start start, TenantIdentifier tenantIden { // all_auth_recipe_users String QUERY = "INSERT INTO " + getConfig(start).getUsersTable() - + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, primary_or_recipe_user_time_joined)" + + + + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, recipe_id, time_joined, " + + "primary_or_recipe_user_time_joined)" + " VALUES(?, ?, ?, ?, ?, ?, ?)"; update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); @@ -274,7 +276,7 @@ public static List getUsersInfoUsingIdList(Start start, Set } public static List getUsersInfoUsingIdList_Transaction(Start start, Connection con, Set ids, - AppIdentifier appIdentifier) + AppIdentifier appIdentifier) throws SQLException, StorageQueryException { if (ids.size() > 0) { String QUERY = "SELECT user_id, third_party_id, third_party_user_id, email, time_joined " @@ -305,7 +307,7 @@ public static List getUsersInfoUsingIdList_Transaction(Start start, public static List listUserIdsByThirdPartyInfo(Start start, AppIdentifier appIdentifier, - String thirdPartyId, String thirdPartyUserId) + String thirdPartyId, String thirdPartyUserId) throws SQLException, StorageQueryException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " @@ -327,7 +329,8 @@ public static List listUserIdsByThirdPartyInfo(Start start, AppIdentifie }); } - public static List listUserIdsByThirdPartyInfo_Transaction(Start start, Connection con, AppIdentifier appIdentifier, + public static List listUserIdsByThirdPartyInfo_Transaction(Start start, Connection con, + AppIdentifier appIdentifier, String thirdPartyId, String thirdPartyUserId) throws SQLException, StorageQueryException { @@ -388,7 +391,7 @@ public static void updateUserEmail_Transaction(Start start, Connection con, AppI } private static UserInfoPartial getUserInfoUsingUserId_Transaction(Start start, Connection con, - AppIdentifier appIdentifier, String userId) + AppIdentifier appIdentifier, String userId) throws SQLException, StorageQueryException { // we don't need a LOCK here because this is already part of a transaction, and locked on app_id_to_user_id @@ -462,11 +465,14 @@ public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlC throw new UnknownUserIdException(); } - GeneralQueries.AccountLinkingInfo accountLinkingInfo = GeneralQueries.getAccountLinkingInfo_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userId); + GeneralQueries.AccountLinkingInfo accountLinkingInfo = GeneralQueries.getAccountLinkingInfo_Transaction(start, + sqlCon, tenantIdentifier.toAppIdentifier(), userId); { // all_auth_recipe_users String QUERY = "INSERT INTO " + getConfig(start).getUsersTable() - + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, is_linked_or_is_a_primary_user, recipe_id, time_joined, primary_or_recipe_user_time_joined)" + + + "(app_id, tenant_id, user_id, primary_or_recipe_user_id, is_linked_or_is_a_primary_user, " + + "recipe_id, time_joined, primary_or_recipe_user_time_joined)" + " VALUES(?, ?, ?, ?, ?, ?, ?, ?)" + " ON CONFLICT DO NOTHING"; update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); @@ -479,14 +485,16 @@ public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlC pst.setLong(8, userInfo.timeJoined); }); - GeneralQueries.updateTimeJoinedForPrimaryUser_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), accountLinkingInfo.primaryUserId); + GeneralQueries.updateTimeJoinedForPrimaryUser_Transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), + accountLinkingInfo.primaryUserId); } { // thirdparty_user_to_tenant String QUERY = "INSERT INTO " + getConfig(start).getThirdPartyUserToTenantTable() + "(app_id, tenant_id, user_id, third_party_id, third_party_user_id)" + " VALUES(?, ?, ?, ?, ?)" + " ON CONFLICT ON CONSTRAINT " - + Utils.getConstraintName(Config.getConfig(start).getTableSchema(), getConfig(start).getThirdPartyUserToTenantTable(), null, "pkey") + + Utils.getConstraintName(Config.getConfig(start).getTableSchema(), + getConfig(start).getThirdPartyUserToTenantTable(), null, "pkey") + " DO NOTHING"; int numRows = update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getAppId()); diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/UserIdMappingQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/UserIdMappingQueries.java index a2388765..072571c1 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/UserIdMappingQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/UserIdMappingQueries.java @@ -55,7 +55,8 @@ public static String getQueryToCreateUserIdMappingTable(Start start) { + " PRIMARY KEY(app_id, supertokens_user_id, external_user_id)," + "CONSTRAINT " + Utils.getConstraintName(schema, userIdMappingTable, "supertokens_user_id", "fkey") + " FOREIGN KEY (app_id, supertokens_user_id)" - + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + "(app_id, user_id)" + " ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getAppIdToUserIdTable() + "(app_id, user_id)" + + " ON DELETE CASCADE" + ");"; // @formatter:on } @@ -65,7 +66,8 @@ public static String getQueryToCreateSupertokensUserIdIndexForUserIdMappingTable + getConfig(start).getUserIdMappingTable() + "(app_id, supertokens_user_id);"; } - public static void createUserIdMapping(Start start, AppIdentifier appIdentifier, String superTokensUserId, String externalUserId, + public static void createUserIdMapping(Start start, AppIdentifier appIdentifier, String superTokensUserId, + String externalUserId, String externalUserIdInfo) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + Config.getConfig(start).getUserIdMappingTable() + " (app_id, supertokens_user_id, external_user_id, external_user_id_info)" + " VALUES(?, ?, ?, ?)"; @@ -78,7 +80,8 @@ public static void createUserIdMapping(Start start, AppIdentifier appIdentifier, }); } - public static UserIdMapping getuseraIdMappingWithSuperTokensUserId(Start start, AppIdentifier appIdentifier, String userId) + public static UserIdMapping getuseraIdMappingWithSuperTokensUserId(Start start, AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND supertokens_user_id = ?"; @@ -93,7 +96,8 @@ public static UserIdMapping getuseraIdMappingWithSuperTokensUserId(Start start, }); } - public static UserIdMapping getUserIdMappingWithExternalUserId(Start start, AppIdentifier appIdentifier, String userId) + public static UserIdMapping getUserIdMappingWithExternalUserId(Start start, AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND external_user_id = ?"; @@ -110,7 +114,9 @@ public static UserIdMapping getUserIdMappingWithExternalUserId(Start start, AppI } public static UserIdMapping[] getUserIdMappingWithEitherSuperTokensUserIdOrExternalUserId(Start start, - AppIdentifier appIdentifier, String userId) throws SQLException, StorageQueryException { + AppIdentifier appIdentifier, + String userId) + throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND (supertokens_user_id = ? OR external_user_id = ?)"; @@ -201,7 +207,8 @@ public static HashMap getUserIdMappingWithUserIds_Transaction(St }); } - public static boolean deleteUserIdMappingWithSuperTokensUserId(Start start, AppIdentifier appIdentifier, String userId) + public static boolean deleteUserIdMappingWithSuperTokensUserId(Start start, AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND supertokens_user_id = ?"; @@ -217,7 +224,8 @@ public static boolean deleteUserIdMappingWithSuperTokensUserId(Start start, AppI public static boolean deleteUserIdMappingWithExternalUserId(Start start, AppIdentifier appIdentifier, String userId) throws SQLException, StorageQueryException { - String QUERY = "DELETE FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND external_user_id = ?"; + String QUERY = "DELETE FROM " + Config.getConfig(start).getUserIdMappingTable() + + " WHERE app_id = ? AND external_user_id = ?"; // store the number of rows updated int rowUpdatedCount = update(start, QUERY, pst -> { @@ -229,8 +237,10 @@ public static boolean deleteUserIdMappingWithExternalUserId(Start start, AppIden } public static boolean updateOrDeleteExternalUserIdInfoWithSuperTokensUserId(Start start, - AppIdentifier appIdentifier, String userId, - @Nullable String externalUserIdInfo) throws SQLException, StorageQueryException { + AppIdentifier appIdentifier, + String userId, + @Nullable String externalUserIdInfo) + throws SQLException, StorageQueryException { String QUERY = "UPDATE " + Config.getConfig(start).getUserIdMappingTable() + " SET external_user_id_info = ? WHERE app_id = ? AND supertokens_user_id = ?"; @@ -245,7 +255,8 @@ public static boolean updateOrDeleteExternalUserIdInfoWithSuperTokensUserId(Star public static boolean updateOrDeleteExternalUserIdInfoWithExternalUserId(Start start, AppIdentifier appIdentifier, String userId, - @Nullable String externalUserIdInfo) throws SQLException, StorageQueryException { + @Nullable String externalUserIdInfo) + throws SQLException, StorageQueryException { String QUERY = "UPDATE " + Config.getConfig(start).getUserIdMappingTable() + " SET external_user_id_info = ? WHERE app_id = ? AND external_user_id = ?"; @@ -258,7 +269,9 @@ public static boolean updateOrDeleteExternalUserIdInfoWithExternalUserId(Start s return rowUpdated > 0; } - public static UserIdMapping getuseraIdMappingWithSuperTokensUserId_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String userId) + public static UserIdMapping getuseraIdMappingWithSuperTokensUserId_Transaction(Start start, Connection sqlCon, + AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND supertokens_user_id = ?"; @@ -273,7 +286,9 @@ public static UserIdMapping getuseraIdMappingWithSuperTokensUserId_Transaction(S }); } - public static UserIdMapping getUserIdMappingWithExternalUserId_Transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String userId) + public static UserIdMapping getUserIdMappingWithExternalUserId_Transaction(Start start, Connection sqlCon, + AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND external_user_id = ?"; @@ -289,8 +304,10 @@ public static UserIdMapping getUserIdMappingWithExternalUserId_Transaction(Start }); } - public static UserIdMapping[] getUserIdMappingWithEitherSuperTokensUserIdOrExternalUserId_Transaction(Start start, Connection sqlCon, - AppIdentifier appIdentifier, String userId) + public static UserIdMapping[] getUserIdMappingWithEitherSuperTokensUserIdOrExternalUserId_Transaction(Start start, + Connection sqlCon, + AppIdentifier appIdentifier, + String userId) throws SQLException, StorageQueryException { String QUERY = "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE app_id = ? AND (supertokens_user_id = ? OR external_user_id = ?)"; diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/UserRolesQueries.java b/src/main/java/io/supertokens/storage/postgresql/queries/UserRolesQueries.java index 10fcb1a7..5825164c 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/UserRolesQueries.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/UserRolesQueries.java @@ -142,7 +142,7 @@ public static void addPermissionToRoleOrDoNothingIfExists_Transaction(Start star } public static boolean deleteRole(Start start, AppIdentifier appIdentifier, - String role) + String role) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + getConfig(start).getRolesTable() + " WHERE app_id = ? AND role = ? ;"; diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/MfaSqlHelper.java b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/MfaSqlHelper.java index b5abf91d..ccbab4f6 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/MfaSqlHelper.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/MfaSqlHelper.java @@ -33,11 +33,13 @@ public static HashMap selectAllFirstFactors(Start st throws SQLException, StorageQueryException { String QUERY = "SELECT connection_uri_domain, app_id, tenant_id, factor_id FROM " + getConfig(start).getTenantFirstFactorsTable() + ";"; - return execute(start, QUERY, pst -> {}, result -> { + return execute(start, QUERY, pst -> { + }, result -> { HashMap> firstFactors = new HashMap<>(); while (result.next()) { - TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), result.getString("app_id"), result.getString("tenant_id")); + TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), + result.getString("app_id"), result.getString("tenant_id")); if (!firstFactors.containsKey(tenantIdentifier)) { firstFactors.put(tenantIdentifier, new ArrayList<>()); } @@ -58,7 +60,8 @@ public static HashMap selectAllRequiredSecondaryFact throws SQLException, StorageQueryException { String QUERY = "SELECT connection_uri_domain, app_id, tenant_id, factor_id FROM " + getConfig(start).getTenantRequiredSecondaryFactorsTable() + ";"; - return execute(start, QUERY, pst -> {}, result -> { + return execute(start, QUERY, pst -> { + }, result -> { HashMap> defaultRequiredFactors = new HashMap<>(); while (result.next()) { @@ -80,16 +83,18 @@ public static HashMap selectAllRequiredSecondaryFact }); } - public static void createFirstFactors(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String[] firstFactors) + public static void createFirstFactors(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, + String[] firstFactors) throws SQLException, StorageQueryException { if (firstFactors == null || firstFactors.length == 0) { return; } - String QUERY = "INSERT INTO " + getConfig(start).getTenantFirstFactorsTable() + "(connection_uri_domain, app_id, tenant_id, factor_id) VALUES (?, ?, ?, ?);"; + String QUERY = "INSERT INTO " + getConfig(start).getTenantFirstFactorsTable() + + "(connection_uri_domain, app_id, tenant_id, factor_id) VALUES (?, ?, ?, ?);"; for (String factorId : new HashSet<>(Arrays.asList(firstFactors))) { update(sqlCon, QUERY, pst -> { - pst.setString(1, tenantIdentifier.getConnectionUriDomain()); + pst.setString(1, tenantIdentifier.getConnectionUriDomain()); pst.setString(2, tenantIdentifier.getAppId()); pst.setString(3, tenantIdentifier.getTenantId()); pst.setString(4, factorId); @@ -97,13 +102,15 @@ public static void createFirstFactors(Start start, Connection sqlCon, TenantIden } } - public static void createRequiredSecondaryFactors(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String[] requiredSecondaryFactors) + public static void createRequiredSecondaryFactors(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, + String[] requiredSecondaryFactors) throws SQLException, StorageQueryException { if (requiredSecondaryFactors == null || requiredSecondaryFactors.length == 0) { return; } - String QUERY = "INSERT INTO " + getConfig(start).getTenantRequiredSecondaryFactorsTable() + "(connection_uri_domain, app_id, tenant_id, factor_id) VALUES (?, ?, ?, ?);"; + String QUERY = "INSERT INTO " + getConfig(start).getTenantRequiredSecondaryFactorsTable() + + "(connection_uri_domain, app_id, tenant_id, factor_id) VALUES (?, ?, ?, ?);"; for (String factorId : requiredSecondaryFactors) { update(sqlCon, QUERY, pst -> { pst.setString(1, tenantIdentifier.getConnectionUriDomain()); diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/TenantConfigSQLHelper.java b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/TenantConfigSQLHelper.java index 3c9c100a..3a57f9aa 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/TenantConfigSQLHelper.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/TenantConfigSQLHelper.java @@ -39,13 +39,16 @@ public static class TenantConfigRowMapper implements RowMapper> providerMap, HashMap firstFactorsMap, HashMap requiredSecondaryFactorsMap) + public static TenantConfig[] selectAll(Start start, + HashMap> providerMap, + HashMap firstFactorsMap, + HashMap requiredSecondaryFactorsMap) throws SQLException, StorageQueryException { String QUERY = "SELECT connection_uri_domain, app_id, tenant_id, core_config," + " email_password_enabled, passwordless_enabled, third_party_enabled, " + " is_first_factors_null, is_third_party_providers_null FROM " + getConfig(start).getTenantConfigsTable() + ";"; - TenantConfig[] tenantConfigs = execute(start, QUERY, pst -> {}, result -> { + TenantConfig[] tenantConfigs = execute(start, QUERY, pst -> { + }, result -> { List temp = new ArrayList<>(); while (result.next()) { - TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), result.getString("app_id"), result.getString("tenant_id")); + TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), + result.getString("app_id"), result.getString("tenant_id")); ThirdPartyConfig.Provider[] providers; if (providerMap.containsKey(tenantIdentifier)) { providers = providerMap.get(tenantIdentifier).values().toArray(new ThirdPartyConfig.Provider[0]); } else { providers = new ThirdPartyConfig.Provider[0]; } - String[] firstFactors = firstFactorsMap.containsKey(tenantIdentifier) ? firstFactorsMap.get(tenantIdentifier) : new String[0]; + String[] firstFactors = + firstFactorsMap.containsKey(tenantIdentifier) ? firstFactorsMap.get(tenantIdentifier) : + new String[0]; - String[] requiredSecondaryFactors = requiredSecondaryFactorsMap.containsKey(tenantIdentifier) ? requiredSecondaryFactorsMap.get(tenantIdentifier) : new String[0]; + String[] requiredSecondaryFactors = requiredSecondaryFactorsMap.containsKey(tenantIdentifier) ? + requiredSecondaryFactorsMap.get(tenantIdentifier) : new String[0]; - temp.add(TenantConfigSQLHelper.TenantConfigRowMapper.getInstance(providers, firstFactors, requiredSecondaryFactors).mapOrThrow(result)); + temp.add(TenantConfigSQLHelper.TenantConfigRowMapper.getInstance(providers, firstFactors, + requiredSecondaryFactors).mapOrThrow(result)); } TenantConfig[] finalResult = new TenantConfig[temp.size()]; for (int i = 0; i < temp.size(); i++) { diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderClientSQLHelper.java b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderClientSQLHelper.java index ced73d6e..100194ea 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderClientSQLHelper.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderClientSQLHelper.java @@ -35,7 +35,8 @@ public class ThirdPartyProviderClientSQLHelper { public static class TenantThirdPartyProviderClientRowMapper implements RowMapper { - public static final ThirdPartyProviderClientSQLHelper.TenantThirdPartyProviderClientRowMapper INSTANCE = new ThirdPartyProviderClientSQLHelper.TenantThirdPartyProviderClientRowMapper(); + public static final ThirdPartyProviderClientSQLHelper.TenantThirdPartyProviderClientRowMapper INSTANCE = + new ThirdPartyProviderClientSQLHelper.TenantThirdPartyProviderClientRowMapper(); private TenantThirdPartyProviderClientRowMapper() { } @@ -77,37 +78,48 @@ public ThirdPartyConfig.ProviderClient map(ResultSet result) throws StorageQuery } } - public static HashMap>> selectAll(Start start) + public static HashMap>> selectAll( + Start start) throws SQLException, StorageQueryException { HashMap>> providerClientsMap = new HashMap<>(); - String QUERY = "SELECT connection_uri_domain, app_id, tenant_id, third_party_id, client_type, client_id, client_secret, scope, force_pkce, additional_config FROM " - + getConfig(start).getTenantThirdPartyProviderClientsTable() + ";"; + String QUERY = + "SELECT connection_uri_domain, app_id, tenant_id, third_party_id, client_type, client_id, " + + "client_secret, scope, force_pkce, additional_config FROM " + + getConfig(start).getTenantThirdPartyProviderClientsTable() + ";"; - execute(start, QUERY, pst -> {}, result -> { + execute(start, QUERY, pst -> { + }, result -> { while (result.next()) { - TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), result.getString("app_id"), result.getString("tenant_id")); - ThirdPartyConfig.ProviderClient providerClient = ThirdPartyProviderClientSQLHelper.TenantThirdPartyProviderClientRowMapper.getInstance().mapOrThrow(result); + TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), + result.getString("app_id"), result.getString("tenant_id")); + ThirdPartyConfig.ProviderClient providerClient = + ThirdPartyProviderClientSQLHelper.TenantThirdPartyProviderClientRowMapper.getInstance() + .mapOrThrow(result); if (!providerClientsMap.containsKey(tenantIdentifier)) { providerClientsMap.put(tenantIdentifier, new HashMap<>()); } - if(!providerClientsMap.get(tenantIdentifier).containsKey(result.getString("third_party_id"))) { + if (!providerClientsMap.get(tenantIdentifier).containsKey(result.getString("third_party_id"))) { providerClientsMap.get(tenantIdentifier).put(result.getString("third_party_id"), new HashMap<>()); } - providerClientsMap.get(tenantIdentifier).get(result.getString("third_party_id")).put(providerClient.clientType, providerClient); + providerClientsMap.get(tenantIdentifier).get(result.getString("third_party_id")) + .put(providerClient.clientType, providerClient); } return null; }); return providerClientsMap; } - public static void create(Start start, Connection sqlCon, TenantConfig tenantConfig, ThirdPartyConfig.Provider provider, ThirdPartyConfig.ProviderClient providerClient) + public static void create(Start start, Connection sqlCon, TenantConfig tenantConfig, + ThirdPartyConfig.Provider provider, ThirdPartyConfig.ProviderClient providerClient) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + getConfig(start).getTenantThirdPartyProviderClientsTable() - + "(connection_uri_domain, app_id, tenant_id, third_party_id, client_type, client_id, client_secret, scope, force_pkce, additional_config)" + + + "(connection_uri_domain, app_id, tenant_id, third_party_id, client_type, client_id, client_secret, " + + "scope, force_pkce, additional_config)" + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; Array scopeArray; diff --git a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderSQLHelper.java b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderSQLHelper.java index 3f2b6645..321f80d5 100644 --- a/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderSQLHelper.java +++ b/src/main/java/io/supertokens/storage/postgresql/queries/multitenancy/ThirdPartyProviderSQLHelper.java @@ -40,7 +40,8 @@ private TenantThirdPartyProviderRowMapper(ThirdPartyConfig.ProviderClient[] clie this.clients = clients; } - public static ThirdPartyProviderSQLHelper.TenantThirdPartyProviderRowMapper getInstance(ThirdPartyConfig.ProviderClient[] clients) { + public static ThirdPartyProviderSQLHelper.TenantThirdPartyProviderRowMapper getInstance( + ThirdPartyConfig.ProviderClient[] clients) { return new ThirdPartyProviderSQLHelper.TenantThirdPartyProviderRowMapper(clients); } @@ -82,21 +83,36 @@ public ThirdPartyConfig.Provider map(ResultSet result) throws StorageQueryExcept } } - public static HashMap> selectAll(Start start, HashMap>> providerClientsMap) + public static HashMap> selectAll(Start start, + HashMap>> providerClientsMap) throws SQLException, StorageQueryException { HashMap> providerMap = new HashMap<>(); - String QUERY = "SELECT connection_uri_domain, app_id, tenant_id, third_party_id, name, authorization_endpoint, authorization_endpoint_query_params, token_endpoint, token_endpoint_body_params, user_info_endpoint, user_info_endpoint_query_params, user_info_endpoint_headers, jwks_uri, oidc_discovery_endpoint, require_email, user_info_map_from_id_token_payload_user_id, user_info_map_from_id_token_payload_email, user_info_map_from_id_token_payload_email_verified, user_info_map_from_user_info_endpoint_user_id, user_info_map_from_user_info_endpoint_email, user_info_map_from_user_info_endpoint_email_verified FROM " - + getConfig(start).getTenantThirdPartyProvidersTable() + ";"; + String QUERY = + "SELECT connection_uri_domain, app_id, tenant_id, third_party_id, name, authorization_endpoint, " + + "authorization_endpoint_query_params, token_endpoint, token_endpoint_body_params, " + + "user_info_endpoint, user_info_endpoint_query_params, user_info_endpoint_headers, jwks_uri, " + + "oidc_discovery_endpoint, require_email, user_info_map_from_id_token_payload_user_id, " + + "user_info_map_from_id_token_payload_email, " + + "user_info_map_from_id_token_payload_email_verified, " + + "user_info_map_from_user_info_endpoint_user_id, user_info_map_from_user_info_endpoint_email, " + + "user_info_map_from_user_info_endpoint_email_verified FROM " + + getConfig(start).getTenantThirdPartyProvidersTable() + ";"; - execute(start, QUERY, pst -> {}, result -> { + execute(start, QUERY, pst -> { + }, result -> { while (result.next()) { - TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), result.getString("app_id"), result.getString("tenant_id")); + TenantIdentifier tenantIdentifier = new TenantIdentifier(result.getString("connection_uri_domain"), + result.getString("app_id"), result.getString("tenant_id")); ThirdPartyConfig.ProviderClient[] clients = null; - if (providerClientsMap.containsKey(tenantIdentifier) && providerClientsMap.get(tenantIdentifier).containsKey(result.getString("third_party_id"))) { - clients = providerClientsMap.get(tenantIdentifier).get(result.getString("third_party_id")).values().toArray(new ThirdPartyConfig.ProviderClient[0]); + if (providerClientsMap.containsKey(tenantIdentifier) && + providerClientsMap.get(tenantIdentifier).containsKey(result.getString("third_party_id"))) { + clients = providerClientsMap.get(tenantIdentifier).get(result.getString("third_party_id")).values() + .toArray(new ThirdPartyConfig.ProviderClient[0]); } - ThirdPartyConfig.Provider provider = ThirdPartyProviderSQLHelper.TenantThirdPartyProviderRowMapper.getInstance(clients).mapOrThrow(result); + ThirdPartyConfig.Provider provider = + ThirdPartyProviderSQLHelper.TenantThirdPartyProviderRowMapper.getInstance( + clients).mapOrThrow(result); if (!providerMap.containsKey(tenantIdentifier)) { providerMap.put(tenantIdentifier, new HashMap<>()); @@ -108,10 +124,19 @@ public static HashMap { pst.setString(1, tenantConfig.tenantIdentifier.getConnectionUriDomain()); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/ConfigTest.java b/src/test/java/io/supertokens/storage/postgresql/test/ConfigTest.java index 6891f739..755b6720 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/ConfigTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/ConfigTest.java @@ -662,9 +662,12 @@ public void testAllConfigsHaveAnAnnotation() throws Exception { continue; } - if (!(field.isAnnotationPresent(UserPoolProperty.class) || field.isAnnotationPresent(ConnectionPoolProperty.class) || field.isAnnotationPresent( + if (!(field.isAnnotationPresent(UserPoolProperty.class) || + field.isAnnotationPresent(ConnectionPoolProperty.class) || field.isAnnotationPresent( NotConflictingWithinUserPool.class))) { - fail(field.getName() + " does not have UserPoolProperty, ConnectionPoolProperty or NotConflictingWithinUserPool annotation"); + fail(field.getName() + + " does not have UserPoolProperty, ConnectionPoolProperty or NotConflictingWithinUserPool " + + "annotation"); } } } diff --git a/src/test/java/io/supertokens/storage/postgresql/test/DbConnectionPoolTest.java b/src/test/java/io/supertokens/storage/postgresql/test/DbConnectionPoolTest.java index 470e6ce0..2a8aa753 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/DbConnectionPoolTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/DbConnectionPoolTest.java @@ -154,14 +154,15 @@ public void testDownTimeWhenChangingConnectionPoolSize() throws Exception { try { TenantIdentifier t1 = new TenantIdentifier(null, null, "t1"); Storage t1Storage = (StorageLayer.getStorage(t1, process.getProcess())); - ThirdParty.signInUp(t1, t1Storage, process.getProcess(), "google", "googleid"+ finalI, "user" + + ThirdParty.signInUp(t1, t1Storage, process.getProcess(), "google", "googleid" + finalI, "user" + finalI + "@example.com"); if (firstErrorTime.get() != -1 && successAfterErrorTime.get() == -1) { successAfterErrorTime.set(System.currentTimeMillis()); } } catch (StorageQueryException e) { - if (e.getMessage().contains("Connection is closed") || e.getMessage().contains("has been closed")) { + if (e.getMessage().contains("Connection is closed") || + e.getMessage().contains("has been closed")) { if (firstErrorTime.get() == -1) { firstErrorTime.set(System.currentTimeMillis()); } @@ -355,7 +356,7 @@ public void testIdleConnectionTimeout() throws Exception { try { TenantIdentifier t1 = new TenantIdentifier(null, null, "t1"); Storage t1Storage = (StorageLayer.getStorage(t1, process.getProcess())); - ThirdParty.signInUp(t1, t1Storage, process.getProcess(), "google", "googleid"+ finalI, "user" + + ThirdParty.signInUp(t1, t1Storage, process.getProcess(), "google", "googleid" + finalI, "user" + finalI + "@example.com"); } catch (StorageQueryException e) { diff --git a/src/test/java/io/supertokens/storage/postgresql/test/DeadlockTest.java b/src/test/java/io/supertokens/storage/postgresql/test/DeadlockTest.java index 22fe29bb..f86faadf 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/DeadlockTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/DeadlockTest.java @@ -263,9 +263,11 @@ public void testCodeCreationRapidlyWithDifferentEmails() throws Exception { System.out.println("Durations: " + durations.toString()); assertNull(process - .checkOrWaitForEventInPlugin(io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_NOT_RESOLVED)); + .checkOrWaitForEventInPlugin( + io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_NOT_RESOLVED)); assertNotNull(process - .checkOrWaitForEventInPlugin(io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); + .checkOrWaitForEventInPlugin( + io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); assert (pass.get()); @@ -627,7 +629,8 @@ public void testLinkAccountsInParallel() throws Exception { for (int i = 0; i < 3000; i++) { es.execute(() -> { try { - AuthRecipe.linkAccounts(process.getProcess(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); + AuthRecipe.linkAccounts(process.getProcess(), user2.getSupertokensUserId(), + user1.getSupertokensUserId()); AuthRecipe.unlinkAccounts(process.getProcess(), user2.getSupertokensUserId()); } catch (Exception e) { if (e.getMessage().toLowerCase().contains("the transaction might succeed if retried")) { @@ -642,9 +645,11 @@ public void testLinkAccountsInParallel() throws Exception { assert (pass.get()); assertNull(process - .checkOrWaitForEventInPlugin(io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_NOT_RESOLVED)); + .checkOrWaitForEventInPlugin( + io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_NOT_RESOLVED)); assertNotNull(process - .checkOrWaitForEventInPlugin(io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); + .checkOrWaitForEventInPlugin( + io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); process.kill(); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); @@ -685,9 +690,11 @@ public void testCreatePrimaryInParallel() throws Exception { assert (pass.get()); assertNull(process - .checkOrWaitForEventInPlugin(io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_NOT_RESOLVED)); + .checkOrWaitForEventInPlugin( + io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_NOT_RESOLVED)); assertNotNull(process - .checkOrWaitForEventInPlugin(io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); + .checkOrWaitForEventInPlugin( + io.supertokens.storage.postgresql.ProcessState.PROCESS_STATE.DEADLOCK_FOUND)); process.kill(); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/LogLevelTest.java b/src/test/java/io/supertokens/storage/postgresql/test/LogLevelTest.java index 996ed4d2..e675c765 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/LogLevelTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/LogLevelTest.java @@ -52,7 +52,7 @@ public void beforeEach() { public void testLogLevelNoneOutput() throws Exception { { Utils.setValueInConfig("log_level", "NONE"); - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); @@ -96,7 +96,7 @@ public void testLogLevelNoneOutput() throws Exception { public void testLogLevelErrorOutput() throws Exception { { Utils.setValueInConfig("log_level", "ERROR"); - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); @@ -150,7 +150,7 @@ public void testLogLevelErrorOutput() throws Exception { public void testLogLevelWarnOutput() throws Exception { { Utils.setValueInConfig("log_level", "WARN"); - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); @@ -204,7 +204,7 @@ public void testLogLevelWarnOutput() throws Exception { public void testLogLevelInfoOutput() throws Exception { { Utils.setValueInConfig("log_level", "INFO"); - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); @@ -258,7 +258,7 @@ public void testLogLevelInfoOutput() throws Exception { public void testLogLevelDebugOutput() throws Exception { { Utils.setValueInConfig("log_level", "DEBUG"); - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/LoggingTest.java b/src/test/java/io/supertokens/storage/postgresql/test/LoggingTest.java index 8aeddc0e..52602c2c 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/LoggingTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/LoggingTest.java @@ -64,7 +64,7 @@ public void beforeEach() { @Test public void defaultLogging() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; StorageLayer.close(); TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); @@ -108,7 +108,7 @@ public void defaultLogging() throws Exception { @Test public void customLogging() throws Exception { try { - String[] args = { "../" }; + String[] args = {"../"}; Utils.setValueInConfig("info_log_path", "\"tempLogging/info.log\""); Utils.setValueInConfig("error_log_path", "\"tempLogging/error.log\""); @@ -159,7 +159,7 @@ public void customLogging() throws Exception { @Test public void confirmLoggerClosed() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; StorageLayer.close(); TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); @@ -187,7 +187,7 @@ public void confirmLoggerClosed() throws Exception { @Test public void testStandardOutLoggingWithNullStr() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; ByteArrayOutputStream stdOutput = new ByteArrayOutputStream(); ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); @@ -223,7 +223,7 @@ public void testStandardOutLoggingWithNullStr() throws Exception { @Test public void testStandardOutLoggingWithNull() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; ByteArrayOutputStream stdOutput = new ByteArrayOutputStream(); ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); @@ -260,7 +260,7 @@ public void testStandardOutLoggingWithNull() throws Exception { @Test public void confirmHikariLoggerClosedOnlyWhenProcessEnds() throws Exception { StorageLayer.close(); - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); FeatureFlagTestContent.getInstance(process.getProcess()) .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY}); @@ -314,7 +314,7 @@ public void confirmHikariLoggerClosedOnlyWhenProcessEnds() throws Exception { @Test public void testDBPasswordMaskingOnDBConnectionFailUsingConnectionUri() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; String dbUser = "db_user"; String dbPassword = "db_password"; @@ -346,7 +346,7 @@ public void testDBPasswordMaskingOnDBConnectionFailUsingConnectionUri() throws E @Test public void testDBPasswordMaskingOnDBConnectionFailUsingCredentials() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; String dbUser = "db_user"; String dbPassword = "db_password"; @@ -380,7 +380,7 @@ public void testDBPasswordMaskingOnDBConnectionFailUsingCredentials() throws Exc @Test public void testDBPasswordMasking() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; ByteArrayOutputStream stdOutput = new ByteArrayOutputStream(); ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); @@ -415,7 +415,7 @@ public void testDBPasswordMasking() throws Exception { @Test public void testDBPasswordIsNotLoggedWhenProcessStartsEnds() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; Utils.setValueInConfig("error_log_path", "null"); Utils.setValueInConfig("info_log_path", "null"); @@ -478,7 +478,7 @@ public void testDBPasswordIsNotLoggedWhenProcessStartsEnds() throws Exception { @Test public void testDBPasswordIsNotLoggedWhenTenantIsCreated() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; Utils.setValueInConfig("error_log_path", "null"); Utils.setValueInConfig("info_log_path", "null"); @@ -504,8 +504,8 @@ public void testDBPasswordIsNotLoggedWhenTenantIsCreated() throws Exception { Main main = process.getProcess(); FeatureFlagTestContent.getInstance(main) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[] { - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY }); + .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ + EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); JsonObject config = new JsonObject(); TenantIdentifier tenantIdentifier = new TenantIdentifier(null, "a1", null); @@ -547,8 +547,8 @@ public void testDBPasswordIsNotLoggedWhenTenantIsCreated() throws Exception { Main main = process.getProcess(); FeatureFlagTestContent.getInstance(main) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[] { - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY }); + .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ + EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); TenantIdentifier tenantIdentifier = new TenantIdentifier(null, "a1", null); JsonObject config = new JsonObject(); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/OneMillionUsersTest.java b/src/test/java/io/supertokens/storage/postgresql/test/OneMillionUsersTest.java index 37346a11..5f55bcf1 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/OneMillionUsersTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/OneMillionUsersTest.java @@ -107,7 +107,8 @@ private void createEmailPasswordUsers(Main main) throws Exception { String userId = io.supertokens.utils.Utils.getUUID(); long timeJoined = System.currentTimeMillis(); - storage.signUp(TenantIdentifier.BASE_TENANT, userId, "eptest" + finalI + "@example.com", combinedPasswordHash, + storage.signUp(TenantIdentifier.BASE_TENANT, userId, "eptest" + finalI + "@example.com", + combinedPasswordHash, timeJoined); synchronized (lock) { allUserIds.add(userId); @@ -116,7 +117,7 @@ private void createEmailPasswordUsers(Main main) throws Exception { throw new RuntimeException(e); } if (finalI % 10000 == 9999) { - System.out.println("Created " + ((finalI +1)) + " users"); + System.out.println("Created " + ((finalI + 1)) + " users"); } }); } @@ -137,7 +138,8 @@ private void createPasswordlessUsersWithEmail(Main main) throws Exception { String userId = io.supertokens.utils.Utils.getUUID(); long timeJoined = System.currentTimeMillis(); try { - storage.createUser(TenantIdentifier.BASE_TENANT, userId, "pltest" + finalI + "@example.com", null, timeJoined); + storage.createUser(TenantIdentifier.BASE_TENANT, userId, "pltest" + finalI + "@example.com", null, + timeJoined); synchronized (lock) { allUserIds.add(userId); } @@ -146,7 +148,7 @@ private void createPasswordlessUsersWithEmail(Main main) throws Exception { } if (finalI % 10000 == 9999) { - System.out.println("Created " + ((finalI +1)) + " users"); + System.out.println("Created " + ((finalI + 1)) + " users"); } }); } @@ -176,7 +178,7 @@ private void createPasswordlessUsersWithPhone(Main main) throws Exception { } if (finalI % 10000 == 9999) { - System.out.println("Created " + ((finalI +1)) + " users"); + System.out.println("Created " + ((finalI + 1)) + " users"); } }); } @@ -198,7 +200,8 @@ private void createThirdpartyUsers(Main main) throws Exception { long timeJoined = System.currentTimeMillis(); try { - storage.signUp(TenantIdentifier.BASE_TENANT, userId, "tptest" + finalI + "@example.com", new LoginMethod.ThirdParty("google", "googleid" + finalI), timeJoined ); + storage.signUp(TenantIdentifier.BASE_TENANT, userId, "tptest" + finalI + "@example.com", + new LoginMethod.ThirdParty("google", "googleid" + finalI), timeJoined); synchronized (lock) { allUserIds.add(userId); } @@ -207,7 +210,7 @@ private void createThirdpartyUsers(Main main) throws Exception { } if (finalI % 10000 == 9999) { - System.out.println("Created " + (finalI +1) + " users"); + System.out.println("Created " + (finalI + 1) + " users"); } }); } @@ -646,7 +649,8 @@ private void sanityCheckAPIs(Main main) throws Exception { JsonArray userRolesArr = response.getAsJsonArray("roles"); assertEquals(1, userRolesArr.size()); assertTrue( - userRolesArr.get(0).getAsString().equals("admin") || userRolesArr.get(0).getAsString().equals("user") + userRolesArr.get(0).getAsString().equals("admin") || + userRolesArr.get(0).getAsString().equals("user") ); } @@ -791,7 +795,8 @@ private void measureOperations(Main main) throws Exception { int finalI = i; es.execute(() -> { try { - ThirdParty.signInUp(main, "twitter", "twitterid" + finalI, "twitter" + finalI + "@example.com"); + ThirdParty.signInUp(main, "twitter", "twitterid" + finalI, + "twitter" + finalI + "@example.com"); } catch (Exception e) { errorCount.incrementAndGet(); throw new RuntimeException(e); @@ -817,7 +822,8 @@ private void measureOperations(Main main) throws Exception { int finalI = i; es.execute(() -> { try { - ThirdParty.signInUp(main, "twitter", "twitterid" + finalI, "twitter" + finalI + "@example.com"); + ThirdParty.signInUp(main, "twitter", "twitterid" + finalI, + "twitter" + finalI + "@example.com"); } catch (Exception e) { errorCount.incrementAndGet(); throw new RuntimeException(e); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/PostgresSQLConfigTest.java b/src/test/java/io/supertokens/storage/postgresql/test/PostgresSQLConfigTest.java index 21064f15..21a86f60 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/PostgresSQLConfigTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/PostgresSQLConfigTest.java @@ -56,14 +56,14 @@ public void beforeEach() { @Test public void testMatchConfigPropertiesDescription() throws Exception { - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); // Skipping postgresql_config_version because it doesn't // have a description in the config.yaml file - String[] ignoredProperties = { "postgresql_config_version" }; + String[] ignoredProperties = {"postgresql_config_version"}; // Match the descriptions in the config.yaml file with the descriptions in the // CoreConfig class @@ -144,8 +144,10 @@ private void matchYamlAndConfigDescriptions(String path, String[] ignoreProperti } String descriptionInConfig = field.getAnnotation(DashboardInfo.class).description(); - descriptionInConfig = "(DIFFERENT_ACROSS_TENANTS" + (field.getAnnotation(DashboardInfo.class).isOptional() ? " | OPTIONAL" : " | COMPULSORY") - + (field.getAnnotation(DashboardInfo.class).isOptional() ? " | Default: " + field.getAnnotation(DashboardInfo.class).defaultValue() : "") + descriptionInConfig = "(DIFFERENT_ACROSS_TENANTS" + + (field.getAnnotation(DashboardInfo.class).isOptional() ? " | OPTIONAL" : " | COMPULSORY") + + (field.getAnnotation(DashboardInfo.class).isOptional() ? + " | Default: " + field.getAnnotation(DashboardInfo.class).defaultValue() : "") + ") " + valueInfo + " " + descriptionInConfig; diff --git a/src/test/java/io/supertokens/storage/postgresql/test/StorageLayerTest.java b/src/test/java/io/supertokens/storage/postgresql/test/StorageLayerTest.java index 8f6d1699..e2ee74f2 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/StorageLayerTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/StorageLayerTest.java @@ -115,13 +115,18 @@ public void testLinkedAccountUser() throws Exception { AuthRecipeUserInfo user1 = EmailPassword.signUp(process.getProcess(), "test1@example.com", "password"); Thread.sleep(50); - AuthRecipeUserInfo user2 = ThirdParty.signInUp(process.getProcess(), "google", "googleid", "test2@example.com").user; + AuthRecipeUserInfo user2 = ThirdParty.signInUp(process.getProcess(), "google", "googleid", + "test2@example.com").user; Thread.sleep(50); - Passwordless.CreateCodeResponse code1 = Passwordless.createCode(process.getProcess(), "test3@example.com", null, null, null); - AuthRecipeUserInfo user3 = Passwordless.consumeCode(process.getProcess(), code1.deviceId, code1.deviceIdHash, code1.userInputCode, null).user; + Passwordless.CreateCodeResponse code1 = Passwordless.createCode(process.getProcess(), "test3@example.com", null, + null, null); + AuthRecipeUserInfo user3 = Passwordless.consumeCode(process.getProcess(), code1.deviceId, code1.deviceIdHash, + code1.userInputCode, null).user; Thread.sleep(50); - Passwordless.CreateCodeResponse code2 = Passwordless.createCode(process.getProcess(), null, "+919876543210", null, null); - AuthRecipeUserInfo user4 = Passwordless.consumeCode(process.getProcess(), code2.deviceId, code2.deviceIdHash, code2.userInputCode, null).user; + Passwordless.CreateCodeResponse code2 = Passwordless.createCode(process.getProcess(), null, "+919876543210", + null, null); + AuthRecipeUserInfo user4 = Passwordless.consumeCode(process.getProcess(), code2.deviceId, code2.deviceIdHash, + code2.userInputCode, null).user; AuthRecipe.createPrimaryUser(process.getProcess(), user3.getSupertokensUserId()); AuthRecipe.linkAccounts(process.getProcess(), user1.getSupertokensUserId(), user3.getSupertokensUserId()); @@ -135,8 +140,9 @@ public void testLinkedAccountUser() throws Exception { user4.getSupertokensUserId() }; - for (String userId : userIds){ - AuthRecipeUserInfo primaryUser = ((AuthRecipeStorage) StorageLayer.getStorage(process.getProcess())).getPrimaryUserById( + for (String userId : userIds) { + AuthRecipeUserInfo primaryUser = ((AuthRecipeStorage) StorageLayer.getStorage( + process.getProcess())).getPrimaryUserById( new AppIdentifier(null, null), userId); assertEquals(user3.getSupertokensUserId(), primaryUser.getSupertokensUserId()); assertEquals(4, primaryUser.loginMethods.length); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/SuperTokensSaaSSecretTest.java b/src/test/java/io/supertokens/storage/postgresql/test/SuperTokensSaaSSecretTest.java index 51673061..eb135240 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/SuperTokensSaaSSecretTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/SuperTokensSaaSSecretTest.java @@ -86,11 +86,12 @@ public void testThatTenantCannotSetDatabaseRelatedConfigIfSuperTokensSaaSSecretI try { JsonObject j = new JsonObject(); j.addProperty(PROTECTED_DB_CONFIG[i], ""); - Multitenancy.addNewOrUpdateAppOrTenant(process.main, new TenantConfig(new TenantIdentifier(null, null, "t1"), new EmailPasswordConfig(false), - new ThirdPartyConfig(false, new ThirdPartyConfig.Provider[0]), - new PasswordlessConfig(false), - null, null, - j), true); + Multitenancy.addNewOrUpdateAppOrTenant(process.main, + new TenantConfig(new TenantIdentifier(null, null, "t1"), new EmailPasswordConfig(false), + new ThirdPartyConfig(false, new ThirdPartyConfig.Provider[0]), + new PasswordlessConfig(false), + null, null, + j), true); fail(); } catch (BadPermissionException e) { assertEquals(e.getMessage(), "Not allowed to modify DB related configs."); @@ -162,12 +163,13 @@ public void testThatTenantCanSetDatabaseRelatedConfigIfSuperTokensSaaSSecretIsNo } else if (PROTECTED_DB_CONFIG_VALUES[i] instanceof Integer) { j.addProperty(PROTECTED_DB_CONFIG[i], (Integer) PROTECTED_DB_CONFIG_VALUES[i]); } - Multitenancy.addNewOrUpdateAppOrTenant(process.main, new TenantConfig(new TenantIdentifier(null, null, "t1"), - new EmailPasswordConfig(false), - new ThirdPartyConfig(false, new ThirdPartyConfig.Provider[0]), - new PasswordlessConfig(false), - null, null, - j), false); + Multitenancy.addNewOrUpdateAppOrTenant(process.main, + new TenantConfig(new TenantIdentifier(null, null, "t1"), + new EmailPasswordConfig(false), + new ThirdPartyConfig(false, new ThirdPartyConfig.Provider[0]), + new PasswordlessConfig(false), + null, null, + j), false); } JsonObject coreConfig = new JsonObject(); @@ -224,7 +226,8 @@ public void testThatTenantCannotGetDatabaseRelatedConfigIfSuperTokensSaaSSecretI { JsonObject response = HttpRequestForTesting.sendJsonRequest(process.getProcess(), "", - HttpRequestForTesting.getMultitenantUrl(TenantIdentifier.BASE_TENANT, "/recipe/multitenancy/tenant/list"), + HttpRequestForTesting.getMultitenantUrl(TenantIdentifier.BASE_TENANT, + "/recipe/multitenancy/tenant/list"), null, 1000, 1000, null, SemVer.v3_0.get(), "GET", apiKey, "multitenancy"); @@ -245,7 +248,8 @@ public void testThatTenantCannotGetDatabaseRelatedConfigIfSuperTokensSaaSSecretI { JsonObject response = HttpRequestForTesting.sendJsonRequest(process.getProcess(), "", - HttpRequestForTesting.getMultitenantUrl(TenantIdentifier.BASE_TENANT, "/recipe/multitenancy/tenant/list"), + HttpRequestForTesting.getMultitenantUrl(TenantIdentifier.BASE_TENANT, + "/recipe/multitenancy/tenant/list"), null, 1000, 1000, null, SemVer.v3_0.get(), "GET", saasSecret, "multitenancy"); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/TableCreationTest.java b/src/test/java/io/supertokens/storage/postgresql/test/TableCreationTest.java index f215a4c0..81f989c8 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/TableCreationTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/TableCreationTest.java @@ -45,7 +45,7 @@ public void beforeEach() { @Test public void checkingCreationOfNewTable() throws InterruptedException { - String[] args = { "../" }; + String[] args = {"../"}; TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/TestMainThread.java b/src/test/java/io/supertokens/storage/postgresql/test/TestMainThread.java index 5dec4454..4c3f6e25 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/TestMainThread.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/TestMainThread.java @@ -75,8 +75,9 @@ public void testThatMainThreadIsSameThroughout() throws Exception { JsonObject requestBody = new JsonObject(); requestBody.addProperty("appId", "a1"); requestBody.add("coreConfig", config); - HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "", "http://localhost:3567/recipe/multitenancy/app", - requestBody, 1000, 2500, null, "3.0", "multitenancy"); + HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/multitenancy/app", + requestBody, 1000, 2500, null, "3.0", "multitenancy"); Storage storage2 = StorageLayer.getStorage(new TenantIdentifier(null, "a1", null), process.getProcess()); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/httpRequest/HttpRequestForTesting.java b/src/test/java/io/supertokens/storage/postgresql/test/httpRequest/HttpRequestForTesting.java index 5ca0aa3e..52e1f7cf 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/httpRequest/HttpRequestForTesting.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/httpRequest/HttpRequestForTesting.java @@ -62,7 +62,8 @@ private static boolean isJsonValid(String jsonInString) { @SuppressWarnings("unchecked") public static T sendGETRequest(Main main, String requestID, String url, Map params, - int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, String rid) + int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, + String rid) throws IOException, HttpResponseException { StringBuilder paramBuilder = new StringBuilder(); @@ -198,101 +199,107 @@ public static T sendJsonRequest(Main main, String requestID, String url, Jso } public static T sendJsonPOSTRequest(Main main, String requestID, String url, JsonElement requestBody, - int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, String rid) + int connectionTimeoutMS, int readTimeoutMS, Integer version, + String cdiVersion, String rid) throws IOException, HttpResponseException { return sendJsonRequest(main, requestID, url, requestBody, connectionTimeoutMS, readTimeoutMS, version, cdiVersion, "POST", null, rid); } public static T sendJsonPOSTRequest(Main main, String requestID, String url, JsonElement requestBody, - int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, String apiKey, String rid) + int connectionTimeoutMS, int readTimeoutMS, Integer version, + String cdiVersion, String apiKey, String rid) throws IOException, HttpResponseException { return sendJsonRequest(main, requestID, url, requestBody, connectionTimeoutMS, readTimeoutMS, version, cdiVersion, "POST", apiKey, rid); } public static T sendJsonPUTRequest(Main main, String requestID, String url, JsonElement requestBody, - int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, String rid) + int connectionTimeoutMS, int readTimeoutMS, Integer version, + String cdiVersion, String rid) throws IOException, HttpResponseException { return sendJsonRequest(main, requestID, url, requestBody, connectionTimeoutMS, readTimeoutMS, version, cdiVersion, "PUT", null, rid); } public static T sendJsonDELETERequest(Main main, String requestID, String url, JsonElement requestBody, - int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, String rid) + int connectionTimeoutMS, int readTimeoutMS, Integer version, + String cdiVersion, String rid) throws IOException, HttpResponseException { return sendJsonRequest(main, requestID, url, requestBody, connectionTimeoutMS, readTimeoutMS, version, cdiVersion, "DELETE", null, rid); } @SuppressWarnings("unchecked") - public static T sendJsonDELETERequestWithQueryParams(Main main, String requestID, String url, Map params, - int connectionTimeoutMS, int readTimeoutMS, Integer version, String cdiVersion, String rid) + public static T sendJsonDELETERequestWithQueryParams(Main main, String requestID, String url, + Map params, + int connectionTimeoutMS, int readTimeoutMS, + Integer version, String cdiVersion, String rid) throws IOException, HttpResponseException { - StringBuilder paramBuilder = new StringBuilder(); + StringBuilder paramBuilder = new StringBuilder(); - if (params != null) { - for (Map.Entry entry : params.entrySet()) { - paramBuilder.append(entry.getKey()).append("=") - .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)).append("&"); - } - } - String paramsStr = paramBuilder.toString(); - if (!paramsStr.equals("")) { - paramsStr = paramsStr.substring(0, paramsStr.length() - 1); - url = url + "?" + paramsStr; + if (params != null) { + for (Map.Entry entry : params.entrySet()) { + paramBuilder.append(entry.getKey()).append("=") + .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)).append("&"); + } + } + String paramsStr = paramBuilder.toString(); + if (!paramsStr.equals("")) { + paramsStr = paramsStr.substring(0, paramsStr.length() - 1); + url = url + "?" + paramsStr; + } + URL obj = getURL(main, requestID, url); + InputStream inputStream = null; + HttpURLConnection con = null; + + try { + con = (HttpURLConnection) obj.openConnection(); + con.setRequestMethod("DELETE"); + con.setConnectTimeout(connectionTimeoutMS); + con.setReadTimeout(readTimeoutMS + 1000); + if (version != null) { + con.setRequestProperty("api-version", version + ""); + } + if (cdiVersion != null) { + con.setRequestProperty("cdi-version", cdiVersion); + } + if (rid != null) { + con.setRequestProperty("rId", rid); + } + + int responseCode = con.getResponseCode(); + + if (responseCode < STATUS_CODE_ERROR_THRESHOLD) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + StringBuilder response = new StringBuilder(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); } - URL obj = getURL(main, requestID, url); - InputStream inputStream = null; - HttpURLConnection con = null; - - try { - con = (HttpURLConnection) obj.openConnection(); - con.setRequestMethod("DELETE"); - con.setConnectTimeout(connectionTimeoutMS); - con.setReadTimeout(readTimeoutMS + 1000); - if (version != null) { - con.setRequestProperty("api-version", version + ""); - } - if (cdiVersion != null) { - con.setRequestProperty("cdi-version", cdiVersion); - } - if (rid != null) { - con.setRequestProperty("rId", rid); - } - - int responseCode = con.getResponseCode(); - - if (responseCode < STATUS_CODE_ERROR_THRESHOLD) { - inputStream = con.getInputStream(); - } else { - inputStream = con.getErrorStream(); - } - - StringBuilder response = new StringBuilder(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - } - if (responseCode < STATUS_CODE_ERROR_THRESHOLD) { - if (!isJsonValid(response.toString())) { - return (T) response.toString(); - } - return (T) (new JsonParser().parse(response.toString())); - } - throw new HttpResponseException(responseCode, response.toString()); - } finally { - if (inputStream != null) { - inputStream.close(); - } - - if (con != null) { - con.disconnect(); - } + } + if (responseCode < STATUS_CODE_ERROR_THRESHOLD) { + if (!isJsonValid(response.toString())) { + return (T) response.toString(); } + return (T) (new JsonParser().parse(response.toString())); + } + throw new HttpResponseException(responseCode, response.toString()); + } finally { + if (inputStream != null) { + inputStream.close(); + } + + if (con != null) { + con.disconnect(); + } } + } public static String getMultitenantUrl(TenantIdentifier tenantIdentifier, String path) { StringBuilder sb = new StringBuilder(); diff --git a/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/StorageLayerTest.java b/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/StorageLayerTest.java index 77204865..257fb60e 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/StorageLayerTest.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/StorageLayerTest.java @@ -328,7 +328,8 @@ public void mergingTenantWithBaseConfigWithConflictingConfigsThrowsError() fail(); } catch (InvalidConfigException e) { assertEquals(e.getMessage(), - "You cannot set different values for postgresql_thirdparty_users_table_name for the same user pool"); + "You cannot set different values for postgresql_thirdparty_users_table_name for the same user " + + "pool"); } process.kill(); @@ -805,7 +806,8 @@ public void testTenantCreationAndThenDbDownDbThrowsErrorInRecipesAndDoesntAffect tenantConfigJson); StorageLayer.getMultitenancyStorage(process.getProcess()).createTenant(tenantConfig); - MultitenancyHelper.getInstance(process.getProcess()).refreshTenantsInCoreBasedOnChangesInCoreConfigOrIfTenantListChanged(true); + MultitenancyHelper.getInstance(process.getProcess()) + .refreshTenantsInCoreBasedOnChangesInCoreConfigOrIfTenantListChanged(true); try { EmailPassword.signIn(tid, (StorageLayer.getStorage(tid, process.getProcess())), diff --git a/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/TestForNoCrashDuringStartup.java b/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/TestForNoCrashDuringStartup.java index b8635224..801737fd 100644 --- a/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/TestForNoCrashDuringStartup.java +++ b/src/test/java/io/supertokens/storage/postgresql/test/multitenancy/TestForNoCrashDuringStartup.java @@ -107,7 +107,8 @@ public void testThatCUDRecoversWhenItFailsToAddEntryDuringCreation() throws Exce assertEquals(2, allTenants.length); // should have the new CUD try { - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); fail(); } catch (HttpResponseException e) { // ignore @@ -117,14 +118,16 @@ public void testThatCUDRecoversWhenItFailsToAddEntryDuringCreation() throws Exce MultitenancyQueries.simulateErrorInAddingTenantIdInTargetStorage_forTesting = false; // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); } @Test public void testThatCUDRecoversWhenTheDbIsDownDuringCreationButDbComesUpLater() throws Exception { Start start = ((Start) StorageLayer.getBaseStorage(process.getProcess())); try { - update(start, "DROP DATABASE st5000;", pst -> {}); + update(start, "DROP DATABASE st5000;", pst -> { + }); } catch (Exception e) { // ignore } @@ -147,24 +150,30 @@ public void testThatCUDRecoversWhenTheDbIsDownDuringCreationButDbComesUpLater() fail(); } catch (StorageQueryException e) { // ignore - assertEquals("java.sql.SQLException: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: FATAL: database \"st5000\" does not exist", e.getMessage()); + assertEquals( + "java.sql.SQLException: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to " + + "initialize pool: FATAL: database \"st5000\" does not exist", + e.getMessage()); } TenantConfig[] allTenants = MultitenancyHelper.getInstance(process.getProcess()).getAllTenants(); assertEquals(2, allTenants.length); // should have the new CUD try { - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); fail(); } catch (HttpResponseException e) { // ignore assertTrue(e.getMessage().contains("Internal Error")); // db is still down } - update(start, "CREATE DATABASE st5000;", pst -> {}); + update(start, "CREATE DATABASE st5000;", pst -> { + }); // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); } @Test @@ -260,7 +269,8 @@ public void testThatCoreDoesNotCrashDuringStartupWhenCUDCreationFailedToAddEntry MultitenancyQueries.simulateErrorInAddingTenantIdInTargetStorage_forTesting = false; // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); } @Test @@ -291,7 +301,8 @@ public void testThatCoreDoesNotCrashDuringStartupWhenTenantEntryIsInconsistentIn assertEquals(2, allTenants.length); // should have the new CUD Start start = (Start) StorageLayer.getBaseStorage(process.getProcess()); - update(start, "DELETE FROM apps;", pst -> {}); + update(start, "DELETE FROM apps;", pst -> { + }); process.kill(false); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); @@ -306,13 +317,15 @@ public void testThatCoreDoesNotCrashDuringStartupWhenTenantEntryIsInconsistentIn MultitenancyQueries.simulateErrorInAddingTenantIdInTargetStorage_forTesting = false; // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); Session.createNewSession(process.getProcess(), "userid", new JsonObject(), new JsonObject()); } @Test - public void testThatCoreDoesNotCrashDuringStartupWhenAppCreationFailedToAddEntryInTheBaseTenantStorage() throws Exception { + public void testThatCoreDoesNotCrashDuringStartupWhenAppCreationFailedToAddEntryInTheBaseTenantStorage() + throws Exception { JsonObject coreConfig = new JsonObject(); TenantIdentifier tenantIdentifier = new TenantIdentifier(null, "a1", null); @@ -354,7 +367,8 @@ public void testThatCoreDoesNotCrashDuringStartupWhenAppCreationFailedToAddEntry assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); Session.createNewSession( new TenantIdentifier(null, "a1", null), @@ -364,7 +378,8 @@ public void testThatCoreDoesNotCrashDuringStartupWhenAppCreationFailedToAddEntry } @Test - public void testThatCoreDoesNotCrashDuringStartupWhenCUDCreationFailedToAddTenantEntryInTargetStorageWithLoadOnlyCUDConfig() throws Exception { + public void testThatCoreDoesNotCrashDuringStartupWhenCUDCreationFailedToAddTenantEntryInTargetStorageWithLoadOnlyCUDConfig() + throws Exception { JsonObject coreConfig = new JsonObject(); TenantIdentifier tenantIdentifier = new TenantIdentifier("127.0.0.1", null, null); @@ -442,10 +457,12 @@ public void testThatCoreDoesNotCrashDuringStartupWhenCUDCreationFailedToAddTenan assertEquals(2, allTenants.length); // should have the new CUD // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); try { - tpSignInUpAndGetResponse(new TenantIdentifier("localhost", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("localhost", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); fail(); } catch (HttpResponseException e) { // ignore @@ -465,9 +482,11 @@ public void testThatCoreDoesNotCrashDuringStartupWhenCUDCreationFailedToAddTenan assertEquals(2, allTenants.length); // should have the new CUD // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("localhost", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("localhost", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); try { - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); fail(); } catch (HttpResponseException e) { // ignore @@ -488,7 +507,8 @@ public void testThatCoreDoesNotCrashDuringStartupWhenCUDCreationFailedToAddTenan public void testThatTenantComesToLifeOnceTheTargetDbIsUpAfterCoreRestart() throws Exception { Start start = ((Start) StorageLayer.getBaseStorage(process.getProcess())); try { - update(start, "DROP DATABASE st5000;", pst -> {}); + update(start, "DROP DATABASE st5000;", pst -> { + }); } catch (Exception e) { // ignore } @@ -511,14 +531,18 @@ public void testThatTenantComesToLifeOnceTheTargetDbIsUpAfterCoreRestart() throw fail(); } catch (StorageQueryException e) { // ignore - assertEquals("java.sql.SQLException: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: FATAL: database \"st5000\" does not exist", e.getMessage()); + assertEquals( + "java.sql.SQLException: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to " + + "initialize pool: FATAL: database \"st5000\" does not exist", + e.getMessage()); } TenantConfig[] allTenants = MultitenancyHelper.getInstance(process.getProcess()).getAllTenants(); assertEquals(2, allTenants.length); // should have the new CUD try { - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); fail(); } catch (HttpResponseException e) { // ignore @@ -537,13 +561,16 @@ public void testThatTenantComesToLifeOnceTheTargetDbIsUpAfterCoreRestart() throw // the process should start successfully even though the db is down start = ((Start) StorageLayer.getBaseStorage(process.getProcess())); - update(start, "CREATE DATABASE st5000;", pst -> {}); + update(start, "CREATE DATABASE st5000;", pst -> { + }); // this should succeed now - tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", "test@example.com", process.getProcess(), SemVer.v5_0); + tpSignInUpAndGetResponse(new TenantIdentifier("127.0.0.1", null, null), "google", "googleid1", + "test@example.com", process.getProcess(), SemVer.v5_0); } - public static JsonObject tpSignInUpAndGetResponse(TenantIdentifier tenantIdentifier, String thirdPartyId, String thirdPartyUserId, String email, Main main, SemVer version) + public static JsonObject tpSignInUpAndGetResponse(TenantIdentifier tenantIdentifier, String thirdPartyId, + String thirdPartyUserId, String email, Main main, SemVer version) throws HttpResponseException, IOException { JsonObject emailObject = new JsonObject(); emailObject.addProperty("id", email);