From 9a484bec07d55e51aa46a22ed3539e71fa317887 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Wed, 15 Feb 2023 14:26:41 -0500 Subject: [PATCH] [SG-147] Organization Domain Claiming Feature (#2704) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [SG-696] Organization Domain Claiming DB Objects and Migrations (#2394) * model organization domain claiming * Added migration scripts and db objects for mssql * create and implement sql repository abstraction * Added ef migrations for mysql and postgres. Removed time without timezone in previous migration * made update on sql migration to use create or alter statement * removed active column from OrganizationDomain table and decided to go with the hard delete approach * Ran dotnet restore evaluate * created DNS service verification using DNSClient (#2401) * [SG-678] Api Endpoints for Domain Claiming (#2430) * Added stored procedure to read claimed domains * Updated Organization Domain Repository to include method to get claimed domains * Updated domain entity and added request model * Implemented organization domain respository and regsitered it in the various extensions * Added create endpoint, request, responses and command * Added endpoint to get domain by domain entry id * Ran lint fix * Added new stored procedure to get domains by organizattion id * Moved migration scripts to init migration and added new procedure * Renamed from domainId to Id * Added and implemented GetDomainByOrganizationId * Completed GetDomainByOrgId endpoint and started work on verify domain endpoint * Updated the OrganizationDomain update procedure * Added delete command and include other endpoints in the controller * Remove test item from controller * Remove test item from controller * Changed access to allow admin, owners and manage sso roles * changed logic for setting the initial value for the NextRunCount * Renamed NextRunCount to JobRunCount * Renamed NextRunCount to JobRunCount on mysql * Renamed NextRunCount to JobRunCount on postgres * Removed chaining pattern and added logic to get next run date * Lint fix * Added stored procedure to get organization sso details by email address * Added endpoint to get sso details of an organization with email * Added organizationDomainRepository to OrganizationController test * merged with master and fixed conflicts * [SG-661] Background Domain Verification Service (#2455) * Added stored procedure to read claimed domains * Updated Organization Domain Repository to include method to get claimed domains * Updated domain entity and added request model * Implemented organization domain respository and regsitered it in the various extensions * Added create endpoint, request, responses and command * Added endpoint to get domain by domain entry id * Ran lint fix * Added new stored procedure to get domains by organizattion id * Moved migration scripts to init migration and added new procedure * Renamed from domainId to Id * Added and implemented GetDomainByOrganizationId * Completed GetDomainByOrgId endpoint and started work on verify domain endpoint * Updated the OrganizationDomain update procedure * Added delete command and include other endpoints in the controller * Remove test item from controller * Remove test item from controller * Changed access to allow admin, owners and manage sso roles * Added stored procedure to get unverified domains by nextrundate * Renamed stored procedure name * Added domain verification service interface * Added GetManyByNextRunDate to repository * Added verification domain service implementation * changed logic for setting the initial value for the NextRunCount * This commit should be signed using my SSH key * Renamed NextRunCount to JobRunCount * Renamed NextRunCount to JobRunCount on mysql * Renamed NextRunCount to JobRunCount on postgres * Removed chaining pattern and added logic to get next run date * Lint fix * Implemented EF core version on the repository * Created background job implementation and logic * popped stash * Updated stored procedure and EF script * Lint fix * Added logic to set next job count and the next run date when a verification is false * Added logic to set next job count and the next run date when a verification is false * Updated stored procedure name on repository * Removed test trigger * Lint fix * Added trigger for job * Added job count update after successful domain verification * Lint fix * Lint fix * [SG-682] Add Event Log Entries to Organization Domain (#2492) * Added domain name property to Event related objects * Added organization domain claiming event types * Created migration script and updated related event scripts to include domanName * Added EF Migrations * Renamed postres script file extension * Added DomainName property to response model * Added abstraction to interface * Added system name to enum * dotnet formattinfg fix * Added events to organization domain actions * Added LastCheckedDate property to domain * Migrations and stored procedure updates with new column * Added new stored procedure to get domain by org id and domain name * Log organization domain event abstract method * Ef migrattion to add new LastCheckedDate column * Added duplicate domain exception * Modified create command to include domain verification and last checked date and renamed methods used * removed variable * changed service lifetime * Renamed trigger * Initialed property in constructor * Ensured domain name is stored as lower case * Fixed suggestions from review * Fixed suggestions from review * Return Conflict Status on Organization Domain APIs (#2498) * Added conflict response to end point to help translate error message on the client better * Added conflict response to end point to help translate error message on the client better * Set message with exception message or generic message * Added last check date to response model (#2499) * Fix/Check to throw exception when domain is claimed by another organization (#2503) * Added check to ensure domain claimed by another organization cannot be verified * Made error message consistent * [SG-660] Organization Domain Maintenance (#2502) * Added email template * Mail service abstraction and implementation * Mail template model * Initial delete job commit * Added SPs to get all unverifed domains after 72 hours and another to delete unverified domains after 7 days * Moved all organization domain scripts to single file * Added new scripts implementation for sqlserver and EF core * Renamed service * Formatting fix * Added background service to send warning email and delete expired domains * Renamed variable * Added implementation for email warning to organization admins and for deleting expired domains after 7 days * Added formatting * Modified read if expired script to limit result to 4 days * Added send mail abstract method and implementation * Model used in build mail body * Completed maintenace service * Added comment to make logic clear * Fixed cron expression (#2505) * Modified procedure and methods to handle flexible verification adn expiration period (#2517) * Merged with master * [SG-908] Unit Tests for Organization Domain Claiming Feature (#2522) * added test controlleer class * added unit test for create command * Added query tests * Added tests for delete and verify command * Formated code and added some more unit tests * Fixed lint * Added log event assertion to create command tests * Added log event assertion to delete command tests * Added unit tests for organization domain controller * Added unit tests for organization domain service * Modified test after merge * fixed comment * fixed comment * fixed lint * Defect/SG-977 - Org domain event logs missing details (#2573) * SG-977 - (1) Refactor EventSystemUser.SSO to be EventSystemUser.DomainVerification to better match SCIM property and for easier display and translation on web client (2) Add new DeviceType of Server to be used on SCIM and Domain Verification logs so event log will show Server as client. * SG-977 - SCIM bugfix - Restoring / Revoking user access via Jumpcloud activation / suspension did not properly log the events as SCIM events so the client side showed Unknown for both Client and Member. * Run autoformat to fix lint errors * SG-977 - Fixed broken test due to new device type logic in event service * SG-976 - Add admin log and clean up log verbiage for domain verification (#2574) * SG-976 - Add admin log and clean up log verbiage for domain verification * SG-976 - (1) Use logInformation extension without exception (2) Clarify verbiage of logs * SG-955 - On domain verification error or failure, set last checked da… (#2541) * SG-955 - On domain verification error or failure, set last checked date on the org domain. * SG-955 - Refactoring VerifyOrganizationDomain event logging to avoid duplication and increase efficiency (based on Gbubemi's PR feedback) * Org Domain Background Verification service - set last checked date (#2599) * Refactored OrganizationDomain repository to work with latest changes on code base * Fixed formatting * [SG-957] Cannot Delete Organizations due to FK Constraint (#2602) * Added stored procedure to fix FX contstraint issue when deleting an organization * Update stored procedures related to organization delete with OrganizationDomain_OrganizationDelete SP * Fixed formatting * Updated SP * SG-990 - Log expired domains that are going to be deleted. * Fix lint errors with auto format * /home/runner/work/server/server/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs(107,2): error FINALNEWLINE: Fix final newline. Insert '\n'. * Added missing bracket to fix compile error. * Added imports for Domain Claiming classes that were lost on merge. * Fixing broken unit tests + adding proper behavior for newly added SCIM logic changing device type * Fix lint errors again * Included domain name set in constructor (#2618) * [SG-1001] Error Thrown When Verifying Sub Domains (#2621) * Renamed exception to a more generic name that receives error message from the dns client and also added updates to job count and next run date * Improved error logs by adding dns client error message * Fixed formatting * [SG-1001] Added event logs when a domain is not verified due to thrown exception (#2623) * Added eevent logs when a domain is not verified due to thrown exception * Fixed formatting * Org Domain Verification - Small refactor to improve method/model name… (#2641) * Org Domain Verification - Small refactor to improve method/model names and method locations - required refactoring of controller routes (I confirmed all behavior still functional) * Fixed organization test controller issue * Fixed lint * Autoformat org domain controller * Removing whitespace for lint argh, why does Rider not do this. --------- Co-authored-by: gbubemismith * Tweak name of Request model to match Response model for ClaimedOrgDomain call * [SG-1009] Users with Custom Role and "Manage SSO" permission don't receive verification failed email (#2645) * Modified condition to pick up unverified domains after said period * Fix to get emails of custom users with manage sso rights * Formatted code * Removed return that made background job exit on successful validation (#2648) * [SG-1014] Unit Tests for Get Organization Sso Details (#2655) * Added unit tests for GetOrgDomainSsoDetails * renamed variable * Adjust OrganizationDomainSsoDetails_ReadByEmail to use outer join so … (#2657) * Adjust OrganizationDomainSsoDetails_ReadByEmail to use outer join so that claimed domain results will come back if an org has not yet setup a policy * Removed migration as not needed * Updated OrganizationDomainSsoDetails_ReadByEmail from original creation migration to use outer join & handle null policy results (and still return results) * Fixed lint formatting --------- Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Co-authored-by: Jared Snider Co-authored-by: Todd Martin --- .../src/Commercial.Core/packages.lock.json | 9 + .../packages.lock.json | 9 + .../Scim/Controllers/v2/UsersController.cs | 4 +- bitwarden_license/src/Scim/packages.lock.json | 9 + bitwarden_license/src/Sso/packages.lock.json | 9 + .../Commercial.Core.Test/packages.lock.json | 9 + .../Scim.IntegrationTest/packages.lock.json | 9 + .../test/Scim.Test/packages.lock.json | 9 + perf/MicroBenchmarks/packages.lock.json | 9 + .../DeleteUnverifiedOrganizationDomainsJob.cs | 31 + src/Admin/Jobs/JobsHostedService.cs | 7 + src/Admin/packages.lock.json | 9 + .../OrganizationDomainController.cs | 143 ++ .../Controllers/OrganizationsController.cs | 31 +- src/Api/Jobs/JobsHostedService.cs | 10 +- src/Api/Jobs/ValidateOrganizationDomainJob.cs | 30 + .../Request/OrganizationDomainRequestModel.cs | 12 + ...rganizationDomainSsoDetailsRequestModel.cs | 10 + src/Api/Models/Response/EventResponseModel.cs | 2 + .../OrganizationDomainResponseModel.cs | 36 + ...ganizationDomainSsoDetailsResponseModel.cs | 28 + .../ExceptionHandlerFilterAttribute.cs | 5 + src/Api/packages.lock.json | 9 + src/Billing/packages.lock.json | 9 + src/Core/Core.csproj | 1 + src/Core/Entities/Event.cs | 3 + src/Core/Entities/OrganizationDomain.cs | 48 + src/Core/Enums/DeviceType.cs | 2 + src/Core/Enums/EventSystemUser.cs | 3 +- src/Core/Enums/EventType.cs | 5 + src/Core/Exceptions/ConflictException.cs | 6 +- src/Core/Exceptions/DnsQueryException.cs | 7 + src/Core/Exceptions/DomainClaimedException.cs | 10 + .../Exceptions/DomainVerifiedException.cs | 10 + .../Exceptions/DuplicateDomainException.cs | 10 + .../OrganizationDomainUnverified.html.hbs | 27 + .../OrganizationDomainUnverified.text.hbs | 10 + src/Core/Models/Data/EventMessage.cs | 1 + src/Core/Models/Data/EventTableEntity.cs | 2 + src/Core/Models/Data/IEvent.cs | 1 + .../OrganizationDomainSsoDetailsData.cs | 16 + .../OrganizationUserUserDetails.cs | 6 + .../OrganizationDomainUnverifiedViewModel.cs | 7 + .../CreateOrganizationDomainCommand.cs | 76 + .../DeleteOrganizationDomainCommand.cs | 32 + .../GetOrganizationDomainByIdQuery.cs | 18 + ...OrganizationDomainByOrganizationIdQuery.cs | 18 + .../ICreateOrganizationDomainCommand.cs | 8 + .../IDeleteOrganizationDomainCommand.cs | 6 + .../IGetOrganizationDomainByIdQuery.cs | 8 + ...OrganizationDomainByOrganizationIdQuery.cs | 8 + .../IVerifyOrganizationDomainCommand.cs | 8 + .../VerifyOrganizationDomainCommand.cs | 73 + ...OrganizationServiceCollectionExtensions.cs | 12 + .../IOrganizationDomainRepository.cs | 15 + src/Core/Services/IDnsResolverService.cs | 6 + src/Core/Services/IEventService.cs | 2 + src/Core/Services/IMailService.cs | 1 + .../Services/IOrganizationDomainService.cs | 7 + .../Implementations/DnsResolverService.cs | 21 + .../Services/Implementations/EventService.cs | 72 +- .../Implementations/HandlebarsMailService.cs | 13 + .../OrganizationDomainService.cs | 139 ++ .../NoopImplementations/NoopEventService.cs | 13 + .../NoopImplementations/NoopMailService.cs | 5 + src/Core/Settings/GlobalSettings.cs | 7 + .../Settings/IDomainVerificationSettings.cs | 7 + src/Core/Settings/IGlobalSettings.cs | 1 + src/Core/packages.lock.json | 9 + src/Events/packages.lock.json | 9 + src/EventsProcessor/packages.lock.json | 9 + src/Icons/packages.lock.json | 9 + src/Identity/packages.lock.json | 9 + .../DapperServiceCollectionExtensions.cs | 1 + .../OrganizationDomainRepository.cs | 110 ++ src/Infrastructure.Dapper/packages.lock.json | 9 + ...ityFrameworkServiceCollectionExtensions.cs | 1 + .../Models/Organization.cs | 1 + .../Models/OrganizationDomain.cs | 16 + .../Repositories/DatabaseContext.cs | 4 + .../OrganizationDomainRepository.cs | 147 ++ .../packages.lock.json | 9 + src/Notifications/packages.lock.json | 9 + .../Utilities/ServiceCollectionExtensions.cs | 2 + src/SharedWeb/packages.lock.json | 9 + src/Sql/Sql.sqlproj | 16 + .../dbo/Stored Procedures/Event_Create.sql | 9 +- ...ganizationDomainSsoDetails_ReadByEmail.sql | 29 + .../OrganizationDomain_Create.sql | 39 + .../OrganizationDomain_DeleteById.sql | 12 + .../OrganizationDomain_DeleteIfExpired.sql | 10 + ...OrganizationDomain_OrganizationDeleted.sql | 12 + ...OrganizationDomain_ReadByClaimedDomain.sql | 15 + .../OrganizationDomain_ReadById.sql | 13 + .../OrganizationDomain_ReadByNextRunDate.sql | 25 + ...rganizationDomain_ReadByOrganizationId.sql | 13 + ...nDomain_ReadDomainByOrgIdAndDomainName.sql | 16 + .../OrganizationDomain_ReadIfExpired.sql | 13 + .../OrganizationDomain_Update.sql | 28 + .../Organization_DeleteById.sql | 1 + src/Sql/dbo/Tables/Event.sql | 1 + src/Sql/dbo/Tables/OrganizationDomain.sql | 15 + src/Sql/dbo/Views/OrganizationDomainView.sql | 6 + test/Api.IntegrationTest/packages.lock.json | 9 + .../OrganizationDomainControllerTests.cs | 268 +++ .../OrganizationsControllerTests.cs | 1 + test/Api.Test/packages.lock.json | 9 + test/Billing.Test/packages.lock.json | 9 + test/Common/packages.lock.json | 9 + .../CreateOrganizationDomainCommandTests.cs | 130 ++ .../DeleteOrganizationDomainCommandTests.cs | 47 + .../GetOrganizationDomainByIdQueryTests.cs | 22 + ...izationDomainByOrganizationIdQueryTests.cs | 22 + .../VerifyOrganizationDomainCommandTests.cs | 135 ++ test/Core.Test/Services/EventServiceTests.cs | 36 +- .../OrganizationDomainServiceTests.cs | 83 + test/Core.Test/packages.lock.json | 9 + test/Icons.Test/packages.lock.json | 9 + .../packages.lock.json | 9 + test/Identity.Test/packages.lock.json | 9 + .../packages.lock.json | 9 + .../packages.lock.json | 9 + test/IntegrationTestCommon/packages.lock.json | 9 + .../2022-11-03_00_OrganizationDomainInit.sql | 285 +++ .../2022-12-08_00_EventsDomainName.sql | 95 + ...1_18_00_FixOrganizationDeleteOrgDomain.sql | 114 ++ util/Migrator/packages.lock.json | 9 + .../2022-11-03_00_OrganizationDomainClaim.sql | 21 + ...anizationDomainClaimRenameNextRunCount.sql | 8 + .../2022-12-08_00_EventsDomainName.sql | 9 + ...9_00_OrganizationDomainLastCheckedDate.sql | 9 + ...202829_OrganizationDomainClaim.Designer.cs | 1722 ++++++++++++++++ .../20221114202829_OrganizationDomainClaim.cs | 49 + ...nDomainClaimRenameNextRunCount.Designer.cs | 1725 ++++++++++++++++ ...ganizationDomainClaimRenameNextRunCount.cs | 24 + ...0221209015017_EventsDomainName.Designer.cs | 1731 ++++++++++++++++ .../20221209015017_EventsDomainName.cs | 25 + ...anizationDomainLastCheckedDate.Designer.cs | 1734 ++++++++++++++++ ...92355_OrganizationDomainLastCheckedDate.cs | 24 + .../DatabaseContextModelSnapshot.cs | 53 + util/MySqlMigrations/packages.lock.json | 9 + ...2022-11-03_00_OrganizationDomainClaim.psql | 21 + ...nizationDomainClaimRenameNextRunCount.psql | 8 + .../2022-12-08_00_EventsDomainName.psql | 9 + ..._00_OrganizationDomainLastCheckedDate.psql | 9 + ...ssAuthRequestAddApprovedColumn.Designer.cs | 108 +- ...192912_OrganizationDomainClaim.Designer.cs | 1733 ++++++++++++++++ .../20221114192912_OrganizationDomainClaim.cs | 46 + ...nDomainClaimRenameNextRunCount.Designer.cs | 1736 ++++++++++++++++ ...ganizationDomainClaimRenameNextRunCount.cs | 24 + ...0221209020447_EventsDomainName.Designer.cs | 1742 ++++++++++++++++ .../20221209020447_EventsDomainName.cs | 24 + ...anizationDomainLastCheckedDate.Designer.cs | 1745 +++++++++++++++++ ...94623_OrganizationDomainLastCheckedDate.cs | 24 + .../DatabaseContextModelSnapshot.cs | 53 + util/PostgresMigrations/packages.lock.json | 9 + util/Setup/packages.lock.json | 9 + util/SqlServerEFScaffold/packages.lock.json | 9 + util/SqliteMigrations/packages.lock.json | 9 + 159 files changed, 17539 insertions(+), 103 deletions(-) create mode 100644 src/Admin/Jobs/DeleteUnverifiedOrganizationDomainsJob.cs create mode 100644 src/Api/Controllers/OrganizationDomainController.cs create mode 100644 src/Api/Jobs/ValidateOrganizationDomainJob.cs create mode 100644 src/Api/Models/Request/OrganizationDomainRequestModel.cs create mode 100644 src/Api/Models/Request/Organizations/OrganizationDomainSsoDetailsRequestModel.cs create mode 100644 src/Api/Models/Response/Organizations/OrganizationDomainResponseModel.cs create mode 100644 src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs create mode 100644 src/Core/Entities/OrganizationDomain.cs create mode 100644 src/Core/Exceptions/DnsQueryException.cs create mode 100644 src/Core/Exceptions/DomainClaimedException.cs create mode 100644 src/Core/Exceptions/DomainVerifiedException.cs create mode 100644 src/Core/Exceptions/DuplicateDomainException.cs create mode 100644 src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.html.hbs create mode 100644 src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.text.hbs create mode 100644 src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs create mode 100644 src/Core/Models/Mail/OrganizationDomainUnverifiedViewModel.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommand.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommand.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQuery.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQuery.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/ICreateOrganizationDomainCommand.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IDeleteOrganizationDomainCommand.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByIdQuery.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByOrganizationIdQuery.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IVerifyOrganizationDomainCommand.cs create mode 100644 src/Core/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs create mode 100644 src/Core/Repositories/IOrganizationDomainRepository.cs create mode 100644 src/Core/Services/IDnsResolverService.cs create mode 100644 src/Core/Services/IOrganizationDomainService.cs create mode 100644 src/Core/Services/Implementations/DnsResolverService.cs create mode 100644 src/Core/Services/Implementations/OrganizationDomainService.cs create mode 100644 src/Core/Settings/IDomainVerificationSettings.cs create mode 100644 src/Infrastructure.Dapper/Repositories/OrganizationDomainRepository.cs create mode 100644 src/Infrastructure.EntityFramework/Models/OrganizationDomain.cs create mode 100644 src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_Create.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteById.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteIfExpired.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_OrganizationDeleted.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByClaimedDomain.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadById.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByNextRunDate.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByOrganizationId.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadDomainByOrgIdAndDomainName.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadIfExpired.sql create mode 100644 src/Sql/dbo/Stored Procedures/OrganizationDomain_Update.sql create mode 100644 src/Sql/dbo/Tables/OrganizationDomain.sql create mode 100644 src/Sql/dbo/Views/OrganizationDomainView.sql create mode 100644 test/Api.Test/Controllers/OrganizationDomainControllerTests.cs create mode 100644 test/Core.Test/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommandTests.cs create mode 100644 test/Core.Test/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommandTests.cs create mode 100644 test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQueryTests.cs create mode 100644 test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQueryTests.cs create mode 100644 test/Core.Test/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs create mode 100644 test/Core.Test/Services/OrganizationDomainServiceTests.cs create mode 100644 util/Migrator/DbScripts/2022-11-03_00_OrganizationDomainInit.sql create mode 100644 util/Migrator/DbScripts/2022-12-08_00_EventsDomainName.sql create mode 100644 util/Migrator/DbScripts/2023_01_18_00_FixOrganizationDeleteOrgDomain.sql create mode 100644 util/MySqlMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.sql create mode 100644 util/MySqlMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.sql create mode 100644 util/MySqlMigrations/HelperScripts/2022-12-08_00_EventsDomainName.sql create mode 100644 util/MySqlMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.sql create mode 100644 util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.Designer.cs create mode 100644 util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.cs create mode 100644 util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.Designer.cs create mode 100644 util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.cs create mode 100644 util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.Designer.cs create mode 100644 util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.cs create mode 100644 util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.Designer.cs create mode 100644 util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.cs create mode 100644 util/PostgresMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.psql create mode 100644 util/PostgresMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.psql create mode 100644 util/PostgresMigrations/HelperScripts/2022-12-08_00_EventsDomainName.psql create mode 100644 util/PostgresMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.psql create mode 100644 util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.Designer.cs create mode 100644 util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.cs create mode 100644 util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.Designer.cs create mode 100644 util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.cs create mode 100644 util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.Designer.cs create mode 100644 util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.cs create mode 100644 util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.Designer.cs create mode 100644 util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.cs diff --git a/bitwarden_license/src/Commercial.Core/packages.lock.json b/bitwarden_license/src/Commercial.Core/packages.lock.json index a13ec7e69..3bd4c03af 100644 --- a/bitwarden_license/src/Commercial.Core/packages.lock.json +++ b/bitwarden_license/src/Commercial.Core/packages.lock.json @@ -126,6 +126,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2553,6 +2561,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/packages.lock.json b/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/packages.lock.json index 3803bc704..9a1d2310a 100644 --- a/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/packages.lock.json +++ b/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/packages.lock.json @@ -144,6 +144,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2726,6 +2734,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs b/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs index ea58a90af..b198ff79e 100644 --- a/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs +++ b/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs @@ -97,11 +97,11 @@ public class UsersController : Controller if (model.Active && orgUser.Status == OrganizationUserStatusType.Revoked) { - await _organizationService.RestoreUserAsync(orgUser, null, _userService); + await _organizationService.RestoreUserAsync(orgUser, EventSystemUser.SCIM, _userService); } else if (!model.Active && orgUser.Status != OrganizationUserStatusType.Revoked) { - await _organizationService.RevokeUserAsync(orgUser, null); + await _organizationService.RevokeUserAsync(orgUser, EventSystemUser.SCIM); } // Have to get full details object for response model diff --git a/bitwarden_license/src/Scim/packages.lock.json b/bitwarden_license/src/Scim/packages.lock.json index 3e79e8b6d..a68dd3d1e 100644 --- a/bitwarden_license/src/Scim/packages.lock.json +++ b/bitwarden_license/src/Scim/packages.lock.json @@ -157,6 +157,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -3002,6 +3010,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/bitwarden_license/src/Sso/packages.lock.json b/bitwarden_license/src/Sso/packages.lock.json index 7a7952f43..679027d57 100644 --- a/bitwarden_license/src/Sso/packages.lock.json +++ b/bitwarden_license/src/Sso/packages.lock.json @@ -160,6 +160,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2872,6 +2880,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/bitwarden_license/test/Commercial.Core.Test/packages.lock.json b/bitwarden_license/test/Commercial.Core.Test/packages.lock.json index 9302ac09e..5699c2e8a 100644 --- a/bitwarden_license/test/Commercial.Core.Test/packages.lock.json +++ b/bitwarden_license/test/Commercial.Core.Test/packages.lock.json @@ -203,6 +203,14 @@ "System.Xml.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -2822,6 +2830,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/bitwarden_license/test/Scim.IntegrationTest/packages.lock.json b/bitwarden_license/test/Scim.IntegrationTest/packages.lock.json index 74555c686..00e5f26b9 100644 --- a/bitwarden_license/test/Scim.IntegrationTest/packages.lock.json +++ b/bitwarden_license/test/Scim.IntegrationTest/packages.lock.json @@ -246,6 +246,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3406,6 +3414,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/bitwarden_license/test/Scim.Test/packages.lock.json b/bitwarden_license/test/Scim.Test/packages.lock.json index e89d8735f..8c8143f8f 100644 --- a/bitwarden_license/test/Scim.Test/packages.lock.json +++ b/bitwarden_license/test/Scim.Test/packages.lock.json @@ -234,6 +234,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3251,6 +3259,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/perf/MicroBenchmarks/packages.lock.json b/perf/MicroBenchmarks/packages.lock.json index 49a034c09..d19999b14 100644 --- a/perf/MicroBenchmarks/packages.lock.json +++ b/perf/MicroBenchmarks/packages.lock.json @@ -156,6 +156,14 @@ "resolved": "2.4.3", "contentHash": "U2FC9Y8NyIxxU6MpFFdWWu1xwiqz/61v/Doou7kmVjpeIEMLWyiNNkzNlSE84kyJ0O1LKApuEj5z48Ow0Hi4OQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2660,6 +2668,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Admin/Jobs/DeleteUnverifiedOrganizationDomainsJob.cs b/src/Admin/Jobs/DeleteUnverifiedOrganizationDomainsJob.cs new file mode 100644 index 000000000..0d2f2d860 --- /dev/null +++ b/src/Admin/Jobs/DeleteUnverifiedOrganizationDomainsJob.cs @@ -0,0 +1,31 @@ +using Bit.Core; +using Bit.Core.Jobs; +using Bit.Core.Services; +using Quartz; + +namespace Bit.Admin.Jobs; + +public class DeleteUnverifiedOrganizationDomainsJob : BaseJob +{ + private readonly IServiceProvider _serviceProvider; + + public DeleteUnverifiedOrganizationDomainsJob( + IServiceProvider serviceProvider, + ILogger logger) + : base(logger) + { + _serviceProvider = serviceProvider; + } + + protected override async Task ExecuteJobAsync(IJobExecutionContext context) + { + _logger.LogInformation(Constants.BypassFiltersEventId, "Execute job task: DeleteUnverifiedOrganizationDomainsJob: Start"); + using (var serviceScope = _serviceProvider.CreateScope()) + { + var organizationDomainService = + serviceScope.ServiceProvider.GetRequiredService(); + await organizationDomainService.OrganizationDomainMaintenanceAsync(); + } + _logger.LogInformation(Constants.BypassFiltersEventId, "Execute job task: DeleteUnverifiedOrganizationDomainsJob: End"); + } +} diff --git a/src/Admin/Jobs/JobsHostedService.cs b/src/Admin/Jobs/JobsHostedService.cs index fd83e07af..5aa770bef 100644 --- a/src/Admin/Jobs/JobsHostedService.cs +++ b/src/Admin/Jobs/JobsHostedService.cs @@ -64,6 +64,11 @@ public class JobsHostedService : BaseJobsHostedService .StartNow() .WithCronSchedule("0 */15 * ? * *") .Build(); + var everyDayAtTwoAmUtcTrigger = TriggerBuilder.Create() + .WithIdentity("EveryDayAtTwoAmUtcTrigger") + .StartNow() + .WithCronSchedule("0 0 2 ? * * *") + .Build(); var jobs = new List> { @@ -74,6 +79,7 @@ public class JobsHostedService : BaseJobsHostedService new Tuple(typeof(DeleteCiphersJob), everyDayAtMidnightUtc), new Tuple(typeof(DatabaseExpiredSponsorshipsJob), everyMondayAtMidnightTrigger), new Tuple(typeof(DeleteAuthRequestsJob), everyFifteenMinutesTrigger), + new Tuple(typeof(DeleteUnverifiedOrganizationDomainsJob), everyDayAtTwoAmUtcTrigger), }; if (!_globalSettings.SelfHosted) @@ -98,5 +104,6 @@ public class JobsHostedService : BaseJobsHostedService services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } } diff --git a/src/Admin/packages.lock.json b/src/Admin/packages.lock.json index 3c4729d2a..cf58d395f 100644 --- a/src/Admin/packages.lock.json +++ b/src/Admin/packages.lock.json @@ -199,6 +199,14 @@ "dbup-core": "4.5.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -3314,6 +3322,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Api/Controllers/OrganizationDomainController.cs b/src/Api/Controllers/OrganizationDomainController.cs new file mode 100644 index 000000000..23e4f51bc --- /dev/null +++ b/src/Api/Controllers/OrganizationDomainController.cs @@ -0,0 +1,143 @@ +using Bit.Api.Models.Request; +using Bit.Api.Models.Request.Organizations; +using Bit.Api.Models.Response; +using Bit.Api.Models.Response.Organizations; +using Bit.Core.Context; +using Bit.Core.Entities; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Bit.Api.Controllers; + +[Route("organizations")] +[Authorize("Application")] +public class OrganizationDomainController : Controller +{ + private readonly ICreateOrganizationDomainCommand _createOrganizationDomainCommand; + private readonly IVerifyOrganizationDomainCommand _verifyOrganizationDomainCommand; + private readonly IDeleteOrganizationDomainCommand _deleteOrganizationDomainCommand; + private readonly IGetOrganizationDomainByIdQuery _getOrganizationDomainByIdQuery; + private readonly IGetOrganizationDomainByOrganizationIdQuery _getOrganizationDomainByOrganizationIdQuery; + private readonly ICurrentContext _currentContext; + private readonly IOrganizationRepository _organizationRepository; + private readonly IOrganizationDomainRepository _organizationDomainRepository; + + public OrganizationDomainController( + ICreateOrganizationDomainCommand createOrganizationDomainCommand, + IVerifyOrganizationDomainCommand verifyOrganizationDomainCommand, + IDeleteOrganizationDomainCommand deleteOrganizationDomainCommand, + IGetOrganizationDomainByIdQuery getOrganizationDomainByIdQuery, + IGetOrganizationDomainByOrganizationIdQuery getOrganizationDomainByOrganizationIdQuery, + ICurrentContext currentContext, + IOrganizationRepository organizationRepository, + IOrganizationDomainRepository organizationDomainRepository) + { + _createOrganizationDomainCommand = createOrganizationDomainCommand; + _verifyOrganizationDomainCommand = verifyOrganizationDomainCommand; + _deleteOrganizationDomainCommand = deleteOrganizationDomainCommand; + _getOrganizationDomainByIdQuery = getOrganizationDomainByIdQuery; + _getOrganizationDomainByOrganizationIdQuery = getOrganizationDomainByOrganizationIdQuery; + _currentContext = currentContext; + _organizationRepository = organizationRepository; + _organizationDomainRepository = organizationDomainRepository; + } + + [HttpGet("{orgId}/domain")] + public async Task> Get(string orgId) + { + var orgIdGuid = new Guid(orgId); + await ValidateOrganizationAccessAsync(orgIdGuid); + + var domains = await _getOrganizationDomainByOrganizationIdQuery + .GetDomainsByOrganizationId(orgIdGuid); + var response = domains.Select(x => new OrganizationDomainResponseModel(x)).ToList(); + return new ListResponseModel(response); + } + + [HttpGet("{orgId}/domain/{id}")] + public async Task Get(string orgId, string id) + { + var orgIdGuid = new Guid(orgId); + var IdGuid = new Guid(id); + await ValidateOrganizationAccessAsync(orgIdGuid); + + var domain = await _getOrganizationDomainByIdQuery.GetOrganizationDomainById(IdGuid); + if (domain is null) + { + throw new NotFoundException(); + } + + return new OrganizationDomainResponseModel(domain); + } + + [HttpPost("{orgId}/domain")] + public async Task Post(string orgId, + [FromBody] OrganizationDomainRequestModel model) + { + var orgIdGuid = new Guid(orgId); + await ValidateOrganizationAccessAsync(orgIdGuid); + + var organizationDomain = new OrganizationDomain + { + OrganizationId = orgIdGuid, + Txt = model.Txt, + DomainName = model.DomainName.ToLower() + }; + + var domain = await _createOrganizationDomainCommand.CreateAsync(organizationDomain); + return new OrganizationDomainResponseModel(domain); + } + + [HttpPost("{orgId}/domain/{id}/verify")] + public async Task Verify(string orgId, string id) + { + var orgIdGuid = new Guid(orgId); + var idGuid = new Guid(id); + await ValidateOrganizationAccessAsync(orgIdGuid); + + var domain = await _verifyOrganizationDomainCommand.VerifyOrganizationDomain(idGuid); + return new OrganizationDomainResponseModel(domain); + } + + [HttpDelete("{orgId}/domain/{id}")] + [HttpPost("{orgId}/domain/{id}/remove")] + public async Task RemoveDomain(string orgId, string id) + { + var orgIdGuid = new Guid(orgId); + var idGuid = new Guid(id); + await ValidateOrganizationAccessAsync(orgIdGuid); + + await _deleteOrganizationDomainCommand.DeleteAsync(idGuid); + } + + [AllowAnonymous] + [HttpPost("domain/sso/details")] // must be post to accept email cleanly + public async Task GetOrgDomainSsoDetails( + [FromBody] OrganizationDomainSsoDetailsRequestModel model) + { + var ssoResult = await _organizationDomainRepository.GetOrganizationDomainSsoDetailsAsync(model.Email); + if (ssoResult is null) + { + throw new NotFoundException("Claimed org domain not found"); + } + + return new OrganizationDomainSsoDetailsResponseModel(ssoResult); + } + + private async Task ValidateOrganizationAccessAsync(Guid orgIdGuid) + { + if (!await _currentContext.ManageSso(orgIdGuid)) + { + throw new UnauthorizedAccessException(); + } + + var organization = await _organizationRepository.GetByIdAsync(orgIdGuid); + if (organization == null) + { + throw new NotFoundException(); + } + } +} diff --git a/src/Api/Controllers/OrganizationsController.cs b/src/Api/Controllers/OrganizationsController.cs index baf0dbfaa..f616d6529 100644 --- a/src/Api/Controllers/OrganizationsController.cs +++ b/src/Api/Controllers/OrganizationsController.cs @@ -135,6 +135,7 @@ public class OrganizationsController : Controller { throw new NotFoundException(); } + return new OrganizationSubscriptionResponseModel(organization, subscriptionInfo); } else @@ -255,7 +256,7 @@ public class OrganizationsController : Controller } var updateBilling = !_globalSettings.SelfHosted && (model.BusinessName != organization.BusinessName || - model.BillingEmail != organization.BillingEmail); + model.BillingEmail != organization.BillingEmail); var hasRequiredPermissions = updateBilling ? await _currentContext.ManageBilling(orgIdGuid) @@ -304,11 +305,7 @@ public class OrganizationsController : Controller } var result = await _organizationService.UpgradePlanAsync(orgIdGuid, model.ToOrganizationUpgrade()); - return new PaymentResponseModel - { - Success = result.Item1, - PaymentIntentClientSecret = result.Item2 - }; + return new PaymentResponseModel { Success = result.Item1, PaymentIntentClientSecret = result.Item2 }; } [HttpPost("{id}/subscription")] @@ -335,11 +332,7 @@ public class OrganizationsController : Controller } var result = await _organizationService.AdjustSeatsAsync(orgIdGuid, model.SeatAdjustment.Value); - return new PaymentResponseModel - { - Success = true, - PaymentIntentClientSecret = result - }; + return new PaymentResponseModel { Success = true, PaymentIntentClientSecret = result }; } [HttpPost("{id}/storage")] @@ -353,11 +346,7 @@ public class OrganizationsController : Controller } var result = await _organizationService.AdjustStorageAsync(orgIdGuid, model.StorageGbAdjustment.Value); - return new PaymentResponseModel - { - Success = true, - PaymentIntentClientSecret = result - }; + return new PaymentResponseModel { Success = true, PaymentIntentClientSecret = result }; } [HttpPost("{id}/verify-bank")] @@ -548,7 +537,8 @@ public class OrganizationsController : Controller } [HttpGet("{id}/api-key-information/{type?}")] - public async Task> ApiKeyInformation(Guid id, [FromRoute] OrganizationApiKeyType? type) + public async Task> ApiKeyInformation(Guid id, + [FromRoute] OrganizationApiKeyType? type) { if (!await HasApiKeyAccessAsync(id, type)) { @@ -577,8 +567,8 @@ public class OrganizationsController : Controller } var organizationApiKey = await _getOrganizationApiKeyQuery - .GetOrganizationApiKeyAsync(organization.Id, model.Type) ?? - await _createOrganizationApiKeyCommand.CreateAsync(organization.Id, model.Type); + .GetOrganizationApiKeyAsync(organization.Id, model.Type) ?? + await _createOrganizationApiKeyCommand.CreateAsync(organization.Id, model.Type); var user = await _userService.GetUserByPrincipalAsync(User); if (user == null) @@ -679,7 +669,8 @@ public class OrganizationsController : Controller throw new UnauthorizedAccessException(); } - var org = await _organizationService.UpdateOrganizationKeysAsync(new Guid(id), model.PublicKey, model.EncryptedPrivateKey); + var org = await _organizationService.UpdateOrganizationKeysAsync(new Guid(id), model.PublicKey, + model.EncryptedPrivateKey); return new OrganizationKeysResponseModel(org); } diff --git a/src/Api/Jobs/JobsHostedService.cs b/src/Api/Jobs/JobsHostedService.cs index 241a01242..eb35556ab 100644 --- a/src/Api/Jobs/JobsHostedService.cs +++ b/src/Api/Jobs/JobsHostedService.cs @@ -47,6 +47,12 @@ public class JobsHostedService : BaseJobsHostedService .WithIntervalInHours(24) .RepeatForever()) .Build(); + var validateOrganizationDomainTrigger = TriggerBuilder.Create() + .WithIdentity("ValidateOrganizationDomainTrigger") + .StartNow() + .WithCronSchedule("0 0 * * * ?") + .Build(); + var jobs = new List> { @@ -54,7 +60,8 @@ public class JobsHostedService : BaseJobsHostedService new Tuple(typeof(EmergencyAccessNotificationJob), emergencyAccessNotificationTrigger), new Tuple(typeof(EmergencyAccessTimeoutJob), emergencyAccessTimeoutTrigger), new Tuple(typeof(ValidateUsersJob), everyTopOfTheSixthHourTrigger), - new Tuple(typeof(ValidateOrganizationsJob), everyTwelfthHourAndThirtyMinutesTrigger) + new Tuple(typeof(ValidateOrganizationsJob), everyTwelfthHourAndThirtyMinutesTrigger), + new Tuple(typeof(ValidateOrganizationDomainJob), validateOrganizationDomainTrigger), }; if (_globalSettings.SelfHosted && _globalSettings.EnableCloudCommunication) @@ -78,5 +85,6 @@ public class JobsHostedService : BaseJobsHostedService services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } } diff --git a/src/Api/Jobs/ValidateOrganizationDomainJob.cs b/src/Api/Jobs/ValidateOrganizationDomainJob.cs new file mode 100644 index 000000000..3d0f2d76c --- /dev/null +++ b/src/Api/Jobs/ValidateOrganizationDomainJob.cs @@ -0,0 +1,30 @@ +using Bit.Core; +using Bit.Core.Jobs; +using Bit.Core.Services; +using Quartz; + +namespace Bit.Api.Jobs; + +public class ValidateOrganizationDomainJob : BaseJob +{ + private readonly IServiceProvider _serviceProvider; + public ValidateOrganizationDomainJob( + IServiceProvider serviceProvider, + ILogger logger) + : base(logger) + { + _serviceProvider = serviceProvider; + } + + protected override async Task ExecuteJobAsync(IJobExecutionContext context) + { + _logger.LogInformation(Constants.BypassFiltersEventId, "Execute job task: ValidateOrganizationDomainJob: Start"); + using (var serviceScope = _serviceProvider.CreateScope()) + { + var organizationDomainService = + serviceScope.ServiceProvider.GetRequiredService(); + await organizationDomainService.ValidateOrganizationsDomainAsync(); + } + _logger.LogInformation(Constants.BypassFiltersEventId, "Execute job task: ValidateOrganizationDomainJob: End"); + } +} diff --git a/src/Api/Models/Request/OrganizationDomainRequestModel.cs b/src/Api/Models/Request/OrganizationDomainRequestModel.cs new file mode 100644 index 000000000..28786bf58 --- /dev/null +++ b/src/Api/Models/Request/OrganizationDomainRequestModel.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Bit.Api.Models.Request; + +public class OrganizationDomainRequestModel +{ + [Required] + public string Txt { get; set; } + + [Required] + public string DomainName { get; set; } +} diff --git a/src/Api/Models/Request/Organizations/OrganizationDomainSsoDetailsRequestModel.cs b/src/Api/Models/Request/Organizations/OrganizationDomainSsoDetailsRequestModel.cs new file mode 100644 index 000000000..9f9db5b34 --- /dev/null +++ b/src/Api/Models/Request/Organizations/OrganizationDomainSsoDetailsRequestModel.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace Bit.Api.Models.Request.Organizations; + +public class OrganizationDomainSsoDetailsRequestModel +{ + [Required] + [EmailAddress] + public string Email { get; set; } +} diff --git a/src/Api/Models/Response/EventResponseModel.cs b/src/Api/Models/Response/EventResponseModel.cs index e9ef73a57..bd94dd171 100644 --- a/src/Api/Models/Response/EventResponseModel.cs +++ b/src/Api/Models/Response/EventResponseModel.cs @@ -31,6 +31,7 @@ public class EventResponseModel : ResponseModel IpAddress = ev.IpAddress; InstallationId = ev.InstallationId; SystemUser = ev.SystemUser; + DomainName = ev.DomainName; } public EventType Type { get; set; } @@ -50,4 +51,5 @@ public class EventResponseModel : ResponseModel public DeviceType? DeviceType { get; set; } public string IpAddress { get; set; } public EventSystemUser? SystemUser { get; set; } + public string DomainName { get; set; } } diff --git a/src/Api/Models/Response/Organizations/OrganizationDomainResponseModel.cs b/src/Api/Models/Response/Organizations/OrganizationDomainResponseModel.cs new file mode 100644 index 000000000..b05a732ee --- /dev/null +++ b/src/Api/Models/Response/Organizations/OrganizationDomainResponseModel.cs @@ -0,0 +1,36 @@ +using Bit.Core.Entities; +using Bit.Core.Models.Api; + +namespace Bit.Api.Models.Response.Organizations; + +public class OrganizationDomainResponseModel : ResponseModel +{ + public OrganizationDomainResponseModel(OrganizationDomain organizationDomain, string obj = "organizationDomain") + : base(obj) + { + if (organizationDomain == null) + { + throw new ArgumentNullException(nameof(organizationDomain)); + } + + Id = organizationDomain.Id.ToString(); + OrganizationId = organizationDomain.OrganizationId.ToString(); + Txt = organizationDomain.Txt; + DomainName = organizationDomain.DomainName; + CreationDate = organizationDomain.CreationDate; + NextRunDate = organizationDomain.NextRunDate; + JobRunCount = organizationDomain.JobRunCount; + VerifiedDate = organizationDomain.VerifiedDate; + LastCheckedDate = organizationDomain.LastCheckedDate; + } + + public string Id { get; set; } + public string OrganizationId { get; set; } + public string Txt { get; set; } + public string DomainName { get; set; } + public DateTime CreationDate { get; set; } + public DateTime NextRunDate { get; set; } + public int JobRunCount { get; set; } + public DateTime? VerifiedDate { get; set; } + public DateTime? LastCheckedDate { get; set; } +} diff --git a/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs b/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs new file mode 100644 index 000000000..44c4acea9 --- /dev/null +++ b/src/Api/Models/Response/Organizations/OrganizationDomainSsoDetailsResponseModel.cs @@ -0,0 +1,28 @@ +using Bit.Core.Models.Api; +using Bit.Core.Models.Data.Organizations; + +namespace Bit.Api.Models.Response.Organizations; + +public class OrganizationDomainSsoDetailsResponseModel : ResponseModel +{ + public OrganizationDomainSsoDetailsResponseModel(OrganizationDomainSsoDetailsData data, string obj = "organizationDomainSsoDetails") + : base(obj) + { + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + SsoAvailable = data.SsoAvailable; + DomainName = data.DomainName; + OrganizationIdentifier = data.OrganizationIdentifier; + SsoRequired = data.SsoRequired; + VerifiedDate = data.VerifiedDate; + } + + public bool SsoAvailable { get; private set; } + public string DomainName { get; private set; } + public string OrganizationIdentifier { get; private set; } + public bool SsoRequired { get; private set; } + public DateTime? VerifiedDate { get; private set; } +} diff --git a/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs b/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs index 60506e46d..4dadedeb3 100644 --- a/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs +++ b/src/Api/Utilities/ExceptionHandlerFilterAttribute.cs @@ -92,6 +92,11 @@ public class ExceptionHandlerFilterAttribute : ExceptionFilterAttribute errorMessage = "Unauthorized."; context.HttpContext.Response.StatusCode = 401; } + else if (exception is ConflictException) + { + errorMessage = exception.Message; + context.HttpContext.Response.StatusCode = 409; + } else if (exception is AggregateException aggregateException) { context.HttpContext.Response.StatusCode = 400; diff --git a/src/Api/packages.lock.json b/src/Api/packages.lock.json index 4df2bb85a..e540064cd 100644 --- a/src/Api/packages.lock.json +++ b/src/Api/packages.lock.json @@ -171,6 +171,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2798,6 +2806,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Billing/packages.lock.json b/src/Billing/packages.lock.json index 96fdbe7b7..dc46ffb62 100644 --- a/src/Billing/packages.lock.json +++ b/src/Billing/packages.lock.json @@ -160,6 +160,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -3249,6 +3257,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 0f4768125..1ddc93a95 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Core/Entities/Event.cs b/src/Core/Entities/Event.cs index 6800b1120..5fa484a0f 100644 --- a/src/Core/Entities/Event.cs +++ b/src/Core/Entities/Event.cs @@ -28,6 +28,7 @@ public class Event : ITableObject, IEvent IpAddress = e.IpAddress; ActingUserId = e.ActingUserId; SystemUser = e.SystemUser; + DomainName = e.DomainName; } public Guid Id { get; set; } @@ -49,6 +50,8 @@ public class Event : ITableObject, IEvent public string IpAddress { get; set; } public Guid? ActingUserId { get; set; } public EventSystemUser? SystemUser { get; set; } + public string DomainName { get; set; } + public void SetNewId() { diff --git a/src/Core/Entities/OrganizationDomain.cs b/src/Core/Entities/OrganizationDomain.cs new file mode 100644 index 000000000..d275d075b --- /dev/null +++ b/src/Core/Entities/OrganizationDomain.cs @@ -0,0 +1,48 @@ +using System.ComponentModel.DataAnnotations; +using Bit.Core.Utilities; + +namespace Bit.Core.Entities; + +public class OrganizationDomain : ITableObject +{ + public Guid Id { get; set; } + public Guid OrganizationId { get; set; } + public string Txt { get; set; } + [MaxLength(255)] + public string DomainName { get; set; } + public DateTime CreationDate { get; set; } = DateTime.UtcNow; + public DateTime? VerifiedDate { get; private set; } + public DateTime NextRunDate { get; private set; } + public DateTime? LastCheckedDate { get; private set; } + public int JobRunCount { get; private set; } + public void SetNewId() => Id = CoreHelpers.GenerateComb(); + + public void SetNextRunDate(int interval) + { + //verification can take up to 72 hours + //1st job runs after 12hrs, 2nd after 24hrs and 3rd after 36hrs + NextRunDate = JobRunCount == 0 + ? CreationDate.AddHours(interval) + : NextRunDate.AddHours((JobRunCount + 1) * interval); + } + + public void SetJobRunCount() + { + if (JobRunCount == 3) + { + return; + } + + JobRunCount++; + } + + public void SetVerifiedDate() + { + VerifiedDate = DateTime.UtcNow; + } + + public void SetLastCheckedDate() + { + LastCheckedDate = DateTime.UtcNow; + } +} diff --git a/src/Core/Enums/DeviceType.cs b/src/Core/Enums/DeviceType.cs index 596a43b03..9534cfd71 100644 --- a/src/Core/Enums/DeviceType.cs +++ b/src/Core/Enums/DeviceType.cs @@ -48,4 +48,6 @@ public enum DeviceType : byte SafariExtension = 20, [Display(Name = "SDK")] SDK = 21, + [Display(Name = "Server")] + Server = 22 } diff --git a/src/Core/Enums/EventSystemUser.cs b/src/Core/Enums/EventSystemUser.cs index 0f19d126c..09c4e68f4 100644 --- a/src/Core/Enums/EventSystemUser.cs +++ b/src/Core/Enums/EventSystemUser.cs @@ -2,5 +2,6 @@ public enum EventSystemUser : byte { - SCIM = 1 + SCIM = 1, + DomainVerification = 2 } diff --git a/src/Core/Enums/EventType.cs b/src/Core/Enums/EventType.cs index 09a1afffd..da3b64fdb 100644 --- a/src/Core/Enums/EventType.cs +++ b/src/Core/Enums/EventType.cs @@ -75,4 +75,9 @@ public enum EventType : int ProviderOrganization_Added = 1901, ProviderOrganization_Removed = 1902, ProviderOrganization_VaultAccessed = 1903, + + OrganizationDomain_Added = 1904, + OrganizationDomain_Removed = 1905, + OrganizationDomain_Verified = 1906, + OrganizationDomain_NotVerified = 1907 } diff --git a/src/Core/Exceptions/ConflictException.cs b/src/Core/Exceptions/ConflictException.cs index 8a3186ac8..27b90a657 100644 --- a/src/Core/Exceptions/ConflictException.cs +++ b/src/Core/Exceptions/ConflictException.cs @@ -1,3 +1,7 @@ namespace Bit.Core.Exceptions; -public class ConflictException : Exception { } +public class ConflictException : Exception +{ + public ConflictException() : base("Conflict.") { } + public ConflictException(string message) : base(message) { } +} diff --git a/src/Core/Exceptions/DnsQueryException.cs b/src/Core/Exceptions/DnsQueryException.cs new file mode 100644 index 000000000..57b2c56da --- /dev/null +++ b/src/Core/Exceptions/DnsQueryException.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Exceptions; + +public class DnsQueryException : Exception +{ + public DnsQueryException(string message) + : base(message) { } +} diff --git a/src/Core/Exceptions/DomainClaimedException.cs b/src/Core/Exceptions/DomainClaimedException.cs new file mode 100644 index 000000000..09ccb3d0d --- /dev/null +++ b/src/Core/Exceptions/DomainClaimedException.cs @@ -0,0 +1,10 @@ +namespace Bit.Core.Exceptions; + +public class DomainClaimedException : Exception +{ + public DomainClaimedException() + : base("The domain is not available to be claimed.") + { + + } +} diff --git a/src/Core/Exceptions/DomainVerifiedException.cs b/src/Core/Exceptions/DomainVerifiedException.cs new file mode 100644 index 000000000..d3a3fd4de --- /dev/null +++ b/src/Core/Exceptions/DomainVerifiedException.cs @@ -0,0 +1,10 @@ +namespace Bit.Core.Exceptions; + +public class DomainVerifiedException : Exception +{ + public DomainVerifiedException() + : base("Domain has already been verified.") + { + + } +} diff --git a/src/Core/Exceptions/DuplicateDomainException.cs b/src/Core/Exceptions/DuplicateDomainException.cs new file mode 100644 index 000000000..8d347dda5 --- /dev/null +++ b/src/Core/Exceptions/DuplicateDomainException.cs @@ -0,0 +1,10 @@ +namespace Bit.Core.Exceptions; + +public class DuplicateDomainException : Exception +{ + public DuplicateDomainException() + : base("A domain already exists for this organization.") + { + + } +} diff --git a/src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.html.hbs b/src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.html.hbs new file mode 100644 index 000000000..11b482acd --- /dev/null +++ b/src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.html.hbs @@ -0,0 +1,27 @@ +{{#>FullHtmlLayout}} + + + + + + + + + + + + + +
+ The domain {{DomainName}} in your Bitwarden organization could not be verified. +
+ Check the corresponding record in your domain host. Then reverify this domain in Bitwarden to use it for your organization. +
+ The domain will be removed from your organization in 7 days if it is not verified. +
+ + Manage Domains + +
+
+{{/FullHtmlLayout}} \ No newline at end of file diff --git a/src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.text.hbs b/src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.text.hbs new file mode 100644 index 000000000..f056bf26c --- /dev/null +++ b/src/Core/MailTemplates/Handlebars/OrganizationDomainUnverified.text.hbs @@ -0,0 +1,10 @@ +{{#>BasicTextLayout}} +The domain {{DomainName}} in your Bitwarden organization could not be verified. + +Check the corresponding record in your domain host. Then reverify this domain in Bitwarden to use it for your organization. + +The domain will be removed from your organization in 7 days if it is not verified. + +{{Url}} + +{{/BasicTextLayout}} \ No newline at end of file diff --git a/src/Core/Models/Data/EventMessage.cs b/src/Core/Models/Data/EventMessage.cs index d140a86cd..c969df53d 100644 --- a/src/Core/Models/Data/EventMessage.cs +++ b/src/Core/Models/Data/EventMessage.cs @@ -32,4 +32,5 @@ public class EventMessage : IEvent public string IpAddress { get; set; } public Guid? IdempotencyId { get; private set; } = Guid.NewGuid(); public EventSystemUser? SystemUser { get; set; } + public string DomainName { get; set; } } diff --git a/src/Core/Models/Data/EventTableEntity.cs b/src/Core/Models/Data/EventTableEntity.cs index 0668fdc1d..9e49d3f68 100644 --- a/src/Core/Models/Data/EventTableEntity.cs +++ b/src/Core/Models/Data/EventTableEntity.cs @@ -27,6 +27,7 @@ public class EventTableEntity : TableEntity, IEvent IpAddress = e.IpAddress; ActingUserId = e.ActingUserId; SystemUser = e.SystemUser; + DomainName = e.DomainName; } public DateTime Date { get; set; } @@ -46,6 +47,7 @@ public class EventTableEntity : TableEntity, IEvent public string IpAddress { get; set; } public Guid? ActingUserId { get; set; } public EventSystemUser? SystemUser { get; set; } + public string DomainName { get; set; } public override IDictionary WriteEntity(OperationContext operationContext) { diff --git a/src/Core/Models/Data/IEvent.cs b/src/Core/Models/Data/IEvent.cs index 290b9e66e..5c2e4b836 100644 --- a/src/Core/Models/Data/IEvent.cs +++ b/src/Core/Models/Data/IEvent.cs @@ -21,4 +21,5 @@ public interface IEvent string IpAddress { get; set; } DateTime Date { get; set; } EventSystemUser? SystemUser { get; set; } + string DomainName { get; set; } } diff --git a/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs b/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs new file mode 100644 index 000000000..66b6081f1 --- /dev/null +++ b/src/Core/Models/Data/Organizations/OrganizationDomainSsoDetailsData.cs @@ -0,0 +1,16 @@ +using Bit.Core.Enums; + +namespace Bit.Core.Models.Data.Organizations; + +public class OrganizationDomainSsoDetailsData +{ + public Guid OrganizationId { get; set; } + public string OrganizationName { get; set; } + public string DomainName { get; set; } + public bool SsoAvailable { get; set; } + public string OrganizationIdentifier { get; set; } + public bool SsoRequired { get; set; } + public PolicyType PolicyType { get; set; } + public DateTime? VerifiedDate { get; set; } + public bool OrganizationEnabled { get; set; } +} diff --git a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs index 74e06182b..0576904cd 100644 --- a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs +++ b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs @@ -68,4 +68,10 @@ public class OrganizationUserUserDetails : IExternal, ITwoFactorProvidersUser return Status != OrganizationUserStatusType.Revoked; } } + + public Permissions GetPermissions() + { + return string.IsNullOrWhiteSpace(Permissions) ? null + : CoreHelpers.LoadClassFromJsonData(Permissions); + } } diff --git a/src/Core/Models/Mail/OrganizationDomainUnverifiedViewModel.cs b/src/Core/Models/Mail/OrganizationDomainUnverifiedViewModel.cs new file mode 100644 index 000000000..a0547ed3a --- /dev/null +++ b/src/Core/Models/Mail/OrganizationDomainUnverifiedViewModel.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Models.Mail; + +public class OrganizationDomainUnverifiedViewModel +{ + public string Url { get; set; } + public string DomainName { get; set; } +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommand.cs b/src/Core/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommand.cs new file mode 100644 index 000000000..e5aa4a09a --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommand.cs @@ -0,0 +1,76 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Core.Settings; +using Microsoft.Extensions.Logging; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains; + +public class CreateOrganizationDomainCommand : ICreateOrganizationDomainCommand +{ + private readonly IOrganizationDomainRepository _organizationDomainRepository; + private readonly IEventService _eventService; + private readonly IDnsResolverService _dnsResolverService; + private readonly ILogger _logger; + private readonly IGlobalSettings _globalSettings; + + public CreateOrganizationDomainCommand( + IOrganizationDomainRepository organizationDomainRepository, + IEventService eventService, + IDnsResolverService dnsResolverService, + ILogger logger, + IGlobalSettings globalSettings) + { + _organizationDomainRepository = organizationDomainRepository; + _eventService = eventService; + _dnsResolverService = dnsResolverService; + _logger = logger; + _globalSettings = globalSettings; + } + + public async Task CreateAsync(OrganizationDomain organizationDomain) + { + //Domains claimed and verified by an organization cannot be claimed + var claimedDomain = + await _organizationDomainRepository.GetClaimedDomainsByDomainNameAsync(organizationDomain.DomainName); + if (claimedDomain.Any()) + { + throw new ConflictException("The domain is not available to be claimed."); + } + + //check for duplicate domain entry for an organization + var duplicateOrgDomain = + await _organizationDomainRepository.GetDomainByOrgIdAndDomainNameAsync(organizationDomain.OrganizationId, + organizationDomain.DomainName); + if (duplicateOrgDomain is not null) + { + throw new ConflictException("A domain already exists for this organization."); + } + + try + { + if (await _dnsResolverService.ResolveAsync(organizationDomain.DomainName, organizationDomain.Txt)) + { + organizationDomain.SetVerifiedDate(); + } + } + catch (Exception e) + { + _logger.LogError("Error verifying Organization domain.", e); + } + + organizationDomain.SetNextRunDate(_globalSettings.DomainVerification.VerificationInterval); + organizationDomain.SetLastCheckedDate(); + + var orgDomain = await _organizationDomainRepository.CreateAsync(organizationDomain); + + await _eventService.LogOrganizationDomainEventAsync(orgDomain, EventType.OrganizationDomain_Added); + await _eventService.LogOrganizationDomainEventAsync(orgDomain, + orgDomain.VerifiedDate != null ? EventType.OrganizationDomain_Verified : EventType.OrganizationDomain_NotVerified); + + return orgDomain; + } +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommand.cs b/src/Core/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommand.cs new file mode 100644 index 000000000..c42060913 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommand.cs @@ -0,0 +1,32 @@ +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; +using Bit.Core.Services; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains; + +public class DeleteOrganizationDomainCommand : IDeleteOrganizationDomainCommand +{ + private readonly IOrganizationDomainRepository _organizationDomainRepository; + private readonly IEventService _eventService; + + public DeleteOrganizationDomainCommand(IOrganizationDomainRepository organizationDomainRepository, + IEventService eventService) + { + _organizationDomainRepository = organizationDomainRepository; + _eventService = eventService; + } + + public async Task DeleteAsync(Guid id) + { + var domain = await _organizationDomainRepository.GetByIdAsync(id); + if (domain is null) + { + throw new NotFoundException(); + } + + await _organizationDomainRepository.DeleteAsync(domain); + await _eventService.LogOrganizationDomainEventAsync(domain, EventType.OrganizationDomain_Removed); + } +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQuery.cs b/src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQuery.cs new file mode 100644 index 000000000..8037fa8ec --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQuery.cs @@ -0,0 +1,18 @@ +using Bit.Core.Entities; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains; + +public class GetOrganizationDomainByIdQuery : IGetOrganizationDomainByIdQuery +{ + private readonly IOrganizationDomainRepository _organizationDomainRepository; + + public GetOrganizationDomainByIdQuery(IOrganizationDomainRepository organizationDomainRepository) + { + _organizationDomainRepository = organizationDomainRepository; + } + + public async Task GetOrganizationDomainById(Guid id) + => await _organizationDomainRepository.GetByIdAsync(id); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQuery.cs b/src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQuery.cs new file mode 100644 index 000000000..6b94dbf17 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQuery.cs @@ -0,0 +1,18 @@ +using Bit.Core.Entities; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains; + +public class GetOrganizationDomainByOrganizationIdQuery : IGetOrganizationDomainByOrganizationIdQuery +{ + private readonly IOrganizationDomainRepository _organizationDomainRepository; + + public GetOrganizationDomainByOrganizationIdQuery(IOrganizationDomainRepository organizationDomainRepository) + { + _organizationDomainRepository = organizationDomainRepository; + } + + public async Task> GetDomainsByOrganizationId(Guid orgId) + => await _organizationDomainRepository.GetDomainsByOrganizationIdAsync(orgId); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/ICreateOrganizationDomainCommand.cs b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/ICreateOrganizationDomainCommand.cs new file mode 100644 index 000000000..79df45396 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/ICreateOrganizationDomainCommand.cs @@ -0,0 +1,8 @@ +using Bit.Core.Entities; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; + +public interface ICreateOrganizationDomainCommand +{ + Task CreateAsync(OrganizationDomain organizationDomain); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IDeleteOrganizationDomainCommand.cs b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IDeleteOrganizationDomainCommand.cs new file mode 100644 index 000000000..4a5cc1c55 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IDeleteOrganizationDomainCommand.cs @@ -0,0 +1,6 @@ +namespace Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; + +public interface IDeleteOrganizationDomainCommand +{ + Task DeleteAsync(Guid id); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByIdQuery.cs b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByIdQuery.cs new file mode 100644 index 000000000..765007f42 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByIdQuery.cs @@ -0,0 +1,8 @@ +using Bit.Core.Entities; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; + +public interface IGetOrganizationDomainByIdQuery +{ + Task GetOrganizationDomainById(Guid id); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByOrganizationIdQuery.cs b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByOrganizationIdQuery.cs new file mode 100644 index 000000000..1377cb48f --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IGetOrganizationDomainByOrganizationIdQuery.cs @@ -0,0 +1,8 @@ +using Bit.Core.Entities; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; + +public interface IGetOrganizationDomainByOrganizationIdQuery +{ + Task> GetDomainsByOrganizationId(Guid orgId); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IVerifyOrganizationDomainCommand.cs b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IVerifyOrganizationDomainCommand.cs new file mode 100644 index 000000000..1d070cf3c --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/Interfaces/IVerifyOrganizationDomainCommand.cs @@ -0,0 +1,8 @@ +using Bit.Core.Entities; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; + +public interface IVerifyOrganizationDomainCommand +{ + Task VerifyOrganizationDomain(Guid id); +} diff --git a/src/Core/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs b/src/Core/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs new file mode 100644 index 000000000..a2b38a357 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs @@ -0,0 +1,73 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Microsoft.Extensions.Logging; + +namespace Bit.Core.OrganizationFeatures.OrganizationDomains; + +public class VerifyOrganizationDomainCommand : IVerifyOrganizationDomainCommand +{ + private readonly IOrganizationDomainRepository _organizationDomainRepository; + private readonly IDnsResolverService _dnsResolverService; + private readonly IEventService _eventService; + private readonly ILogger _logger; + + public VerifyOrganizationDomainCommand( + IOrganizationDomainRepository organizationDomainRepository, + IDnsResolverService dnsResolverService, + IEventService eventService, + ILogger logger) + { + _organizationDomainRepository = organizationDomainRepository; + _dnsResolverService = dnsResolverService; + _eventService = eventService; + _logger = logger; + } + + public async Task VerifyOrganizationDomain(Guid id) + { + var domain = await _organizationDomainRepository.GetByIdAsync(id); + if (domain is null) + { + throw new NotFoundException(); + } + + if (domain.VerifiedDate is not null) + { + domain.SetLastCheckedDate(); + await _organizationDomainRepository.ReplaceAsync(domain); + throw new ConflictException("Domain has already been verified."); + } + + var claimedDomain = + await _organizationDomainRepository.GetClaimedDomainsByDomainNameAsync(domain.DomainName); + if (claimedDomain.Any()) + { + domain.SetLastCheckedDate(); + await _organizationDomainRepository.ReplaceAsync(domain); + throw new ConflictException("The domain is not available to be claimed."); + } + + try + { + if (await _dnsResolverService.ResolveAsync(domain.DomainName, domain.Txt)) + { + domain.SetVerifiedDate(); + } + } + catch (Exception e) + { + _logger.LogError("Error verifying Organization domain. {errorMessage}", e.Message); + } + + domain.SetLastCheckedDate(); + await _organizationDomainRepository.ReplaceAsync(domain); + + await _eventService.LogOrganizationDomainEventAsync(domain, + domain.VerifiedDate != null ? EventType.OrganizationDomain_Verified : EventType.OrganizationDomain_NotVerified); + return domain; + } +} diff --git a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs index b8e2a775e..0eaf16045 100644 --- a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs +++ b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs @@ -7,6 +7,8 @@ using Bit.Core.OrganizationFeatures.OrganizationCollections; using Bit.Core.OrganizationFeatures.OrganizationCollections.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationConnections; using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; +using Bit.Core.OrganizationFeatures.OrganizationDomains; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationLicenses; using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise; @@ -35,6 +37,7 @@ public static class OrganizationServiceCollectionExtensions services.AddOrganizationCollectionCommands(); services.AddOrganizationGroupCommands(); services.AddOrganizationLicenseCommandQueries(); + services.AddOrganizationDomainCommandsQueries(); } private static void AddOrganizationConnectionCommands(this IServiceCollection services) @@ -94,6 +97,15 @@ public static class OrganizationServiceCollectionExtensions services.AddScoped(); } + private static void AddOrganizationDomainCommandsQueries(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + } + private static void AddTokenizers(this IServiceCollection services) { services.AddSingleton>(serviceProvider => diff --git a/src/Core/Repositories/IOrganizationDomainRepository.cs b/src/Core/Repositories/IOrganizationDomainRepository.cs new file mode 100644 index 000000000..dfe535854 --- /dev/null +++ b/src/Core/Repositories/IOrganizationDomainRepository.cs @@ -0,0 +1,15 @@ +using Bit.Core.Entities; +using Bit.Core.Models.Data.Organizations; + +namespace Bit.Core.Repositories; + +public interface IOrganizationDomainRepository : IRepository +{ + Task> GetClaimedDomainsByDomainNameAsync(string domainName); + Task> GetDomainsByOrganizationIdAsync(Guid orgId); + Task> GetManyByNextRunDateAsync(DateTime date); + Task GetOrganizationDomainSsoDetailsAsync(string email); + Task GetDomainByOrgIdAndDomainNameAsync(Guid orgId, string domainName); + Task> GetExpiredOrganizationDomainsAsync(); + Task DeleteExpiredAsync(int expirationPeriod); +} diff --git a/src/Core/Services/IDnsResolverService.cs b/src/Core/Services/IDnsResolverService.cs new file mode 100644 index 000000000..17e4edee9 --- /dev/null +++ b/src/Core/Services/IDnsResolverService.cs @@ -0,0 +1,6 @@ +namespace Bit.Core.Services; + +public interface IDnsResolverService +{ + Task ResolveAsync(string domain, string txtRecord, CancellationToken cancellationToken = default); +} diff --git a/src/Core/Services/IEventService.cs b/src/Core/Services/IEventService.cs index 68c0acfc6..ec05c6943 100644 --- a/src/Core/Services/IEventService.cs +++ b/src/Core/Services/IEventService.cs @@ -23,4 +23,6 @@ public interface IEventService Task LogProviderUserEventAsync(ProviderUser providerUser, EventType type, DateTime? date = null); Task LogProviderUsersEventAsync(IEnumerable<(ProviderUser, EventType, DateTime?)> events); Task LogProviderOrganizationEventAsync(ProviderOrganization providerOrganization, EventType type, DateTime? date = null); + Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, DateTime? date = null); + Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, EventSystemUser systemUser, DateTime? date = null); } diff --git a/src/Core/Services/IMailService.cs b/src/Core/Services/IMailService.cs index 3af89108c..a53ac63d2 100644 --- a/src/Core/Services/IMailService.cs +++ b/src/Core/Services/IMailService.cs @@ -54,4 +54,5 @@ public interface IMailService Task SendOTPEmailAsync(string email, string token); Task SendFailedLoginAttemptsEmailAsync(string email, DateTime utcNow, string ip); Task SendFailedTwoFactorAttemptsEmailAsync(string email, DateTime utcNow, string ip); + Task SendUnverifiedOrganizationDomainEmailAsync(IEnumerable adminEmails, string organizationId, string domainName); } diff --git a/src/Core/Services/IOrganizationDomainService.cs b/src/Core/Services/IOrganizationDomainService.cs new file mode 100644 index 000000000..87e7668ea --- /dev/null +++ b/src/Core/Services/IOrganizationDomainService.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Services; + +public interface IOrganizationDomainService +{ + Task ValidateOrganizationsDomainAsync(); + Task OrganizationDomainMaintenanceAsync(); +} diff --git a/src/Core/Services/Implementations/DnsResolverService.cs b/src/Core/Services/Implementations/DnsResolverService.cs new file mode 100644 index 000000000..c47bd2e58 --- /dev/null +++ b/src/Core/Services/Implementations/DnsResolverService.cs @@ -0,0 +1,21 @@ +using Bit.Core.Exceptions; +using DnsClient; + +namespace Bit.Core.Services; + +public class DnsResolverService : IDnsResolverService +{ + public async Task ResolveAsync(string domain, string txtRecord, CancellationToken cancellationToken = default) + { + var lookup = new LookupClient(); + var result = await lookup.QueryAsync(new DnsQuestion(domain, QueryType.TXT), cancellationToken); + if (!result.HasError) + { + return result.Answers.TxtRecords() + .Select(t => t?.EscapedText?.FirstOrDefault()) + .Any(t => t == txtRecord); + } + + throw new DnsQueryException(result.ErrorMessage); + } +} diff --git a/src/Core/Services/Implementations/EventService.cs b/src/Core/Services/Implementations/EventService.cs index 82b6658e0..f86cff76f 100644 --- a/src/Core/Services/Implementations/EventService.cs +++ b/src/Core/Services/Implementations/EventService.cs @@ -181,7 +181,7 @@ public class EventService : IEventService continue; } - eventMessages.Add(new EventMessage(_currentContext) + var e = new EventMessage(_currentContext) { OrganizationId = group.OrganizationId, GroupId = group.Id, @@ -190,12 +190,20 @@ public class EventService : IEventService ProviderId = await GetProviderIdAsync(group.OrganizationId), SystemUser = systemUser, Date = date.GetValueOrDefault(DateTime.UtcNow) - }); + }; + + if (systemUser is EventSystemUser.SCIM) + { + // System user only used for SCIM logs in this method + // and we want event logs to report server instead of unknown + e.DeviceType = DeviceType.Server; + } + + eventMessages.Add(e); } await _eventWriteService.CreateManyAsync(eventMessages); } - public async Task LogPolicyEventAsync(Policy policy, EventType type, DateTime? date = null) { var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); @@ -247,7 +255,7 @@ public class EventService : IEventService continue; } - eventMessages.Add(new EventMessage(_currentContext) + var e = new EventMessage(_currentContext) { OrganizationId = organizationUser.OrganizationId, UserId = organizationUser.UserId, @@ -257,7 +265,16 @@ public class EventService : IEventService ActingUserId = _currentContext?.UserId, Date = date.GetValueOrDefault(DateTime.UtcNow), SystemUser = systemUser - }); + }; + + if (systemUser is EventSystemUser.SCIM) + { + // System user only used for SCIM logs in this method + // and we want event logs to report server instead of unknown + e.DeviceType = DeviceType.Server; + } + + eventMessages.Add(e); } await _eventWriteService.CreateManyAsync(eventMessages); @@ -331,6 +348,49 @@ public class EventService : IEventService await _eventWriteService.CreateAsync(e); } + public async Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, + DateTime? date = null) + { + var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); + if (!CanUseEvents(orgAbilities, organizationDomain.OrganizationId)) + { + return; + } + + var e = new EventMessage(_currentContext) + { + OrganizationId = organizationDomain.OrganizationId, + Type = type, + ActingUserId = _currentContext?.UserId, + DomainName = organizationDomain.DomainName, + Date = date.GetValueOrDefault(DateTime.UtcNow) + }; + await _eventWriteService.CreateAsync(e); + } + + public async Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, + EventSystemUser systemUser, + DateTime? date = null) + { + var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); + if (!CanUseEvents(orgAbilities, organizationDomain.OrganizationId)) + { + return; + } + + var e = new EventMessage(_currentContext) + { + OrganizationId = organizationDomain.OrganizationId, + Type = type, + ActingUserId = _currentContext?.UserId, + DomainName = organizationDomain.DomainName, + SystemUser = systemUser, + Date = date.GetValueOrDefault(DateTime.UtcNow), + DeviceType = DeviceType.Server + }; + await _eventWriteService.CreateAsync(e); + } + private async Task GetProviderIdAsync(Guid? orgId) { if (_currentContext == null || !orgId.HasValue) @@ -360,6 +420,6 @@ public class EventService : IEventService private bool CanUseProviderEvents(IDictionary providerAbilities, Guid providerId) { return providerAbilities != null && providerAbilities.ContainsKey(providerId) && - providerAbilities[providerId].Enabled && providerAbilities[providerId].UseEvents; + providerAbilities[providerId].Enabled && providerAbilities[providerId].UseEvents; } } diff --git a/src/Core/Services/Implementations/HandlebarsMailService.cs b/src/Core/Services/Implementations/HandlebarsMailService.cs index 3688c8f15..f4190593d 100644 --- a/src/Core/Services/Implementations/HandlebarsMailService.cs +++ b/src/Core/Services/Implementations/HandlebarsMailService.cs @@ -881,6 +881,19 @@ public class HandlebarsMailService : IMailService await _mailDeliveryService.SendEmailAsync(message); } + public async Task SendUnverifiedOrganizationDomainEmailAsync(IEnumerable adminEmails, string organizationId, string domainName) + { + var message = CreateDefaultMessage("Domain not verified", adminEmails); + var model = new OrganizationDomainUnverifiedViewModel + { + Url = $"{_globalSettings.BaseServiceUri.VaultWithHash}/organizations/{organizationId}/settings/domain-verification", + DomainName = domainName + }; + await AddMessageContentAsync(message, "OrganizationDomainUnverified", model); + message.Category = "UnverifiedOrganizationDomain"; + await _mailDeliveryService.SendEmailAsync(message); + } + private static string GetUserIdentifier(string email, string userName) { return string.IsNullOrEmpty(userName) ? email : CoreHelpers.SanitizeForEmail(userName, false); diff --git a/src/Core/Services/Implementations/OrganizationDomainService.cs b/src/Core/Services/Implementations/OrganizationDomainService.cs new file mode 100644 index 000000000..ba342ce03 --- /dev/null +++ b/src/Core/Services/Implementations/OrganizationDomainService.cs @@ -0,0 +1,139 @@ +using Bit.Core.Enums; +using Bit.Core.Repositories; +using Bit.Core.Settings; +using Microsoft.Extensions.Logging; + +namespace Bit.Core.Services; + +public class OrganizationDomainService : IOrganizationDomainService +{ + private readonly IOrganizationDomainRepository _domainRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; + private readonly IDnsResolverService _dnsResolverService; + private readonly IEventService _eventService; + private readonly IMailService _mailService; + private readonly ILogger _logger; + private readonly IGlobalSettings _globalSettings; + + public OrganizationDomainService( + IOrganizationDomainRepository domainRepository, + IOrganizationUserRepository organizationUserRepository, + IDnsResolverService dnsResolverService, + IEventService eventService, + IMailService mailService, + ILogger logger, + IGlobalSettings globalSettings) + { + _domainRepository = domainRepository; + _organizationUserRepository = organizationUserRepository; + _dnsResolverService = dnsResolverService; + _eventService = eventService; + _mailService = mailService; + _logger = logger; + _globalSettings = globalSettings; + } + + public async Task ValidateOrganizationsDomainAsync() + { + //Date should be set 1 hour behind to ensure it selects all domains that should be verified + var runDate = DateTime.UtcNow.AddHours(-1); + + var verifiableDomains = await _domainRepository.GetManyByNextRunDateAsync(runDate); + + _logger.LogInformation(Constants.BypassFiltersEventId, "Validating {verifiableDomainsCount} domains.", verifiableDomains.Count); + + foreach (var domain in verifiableDomains) + { + try + { + _logger.LogInformation(Constants.BypassFiltersEventId, "Attempting verification for organization {OrgId} with domain {Domain}", domain.OrganizationId, domain.DomainName); + + var status = await _dnsResolverService.ResolveAsync(domain.DomainName, domain.Txt); + if (status) + { + _logger.LogInformation(Constants.BypassFiltersEventId, "Successfully validated domain"); + + //update entry on OrganizationDomain table + domain.SetLastCheckedDate(); + domain.SetVerifiedDate(); + domain.SetJobRunCount(); + await _domainRepository.ReplaceAsync(domain); + + await _eventService.LogOrganizationDomainEventAsync(domain, EventType.OrganizationDomain_Verified, + EventSystemUser.DomainVerification); + } + else + { + //update entry on OrganizationDomain table + domain.SetLastCheckedDate(); + domain.SetJobRunCount(); + domain.SetNextRunDate(_globalSettings.DomainVerification.VerificationInterval); + await _domainRepository.ReplaceAsync(domain); + + await _eventService.LogOrganizationDomainEventAsync(domain, EventType.OrganizationDomain_NotVerified, + EventSystemUser.DomainVerification); + _logger.LogInformation(Constants.BypassFiltersEventId, "Verification for organization {OrgId} with domain {Domain} failed", + domain.OrganizationId, domain.DomainName); + } + } + catch (Exception ex) + { + //update entry on OrganizationDomain table + domain.SetLastCheckedDate(); + domain.SetJobRunCount(); + domain.SetNextRunDate(_globalSettings.DomainVerification.VerificationInterval); + await _domainRepository.ReplaceAsync(domain); + + await _eventService.LogOrganizationDomainEventAsync(domain, EventType.OrganizationDomain_NotVerified, + EventSystemUser.DomainVerification); + + _logger.LogError(ex, "Verification for organization {OrgId} with domain {Domain} threw an exception: {errorMessage}", + domain.OrganizationId, domain.DomainName, ex.Message); + } + } + } + + public async Task OrganizationDomainMaintenanceAsync() + { + try + { + //Get domains that have not been verified within 72 hours + var expiredDomains = await _domainRepository.GetExpiredOrganizationDomainsAsync(); + + _logger.LogInformation(Constants.BypassFiltersEventId, + "Attempting email reminder for {expiredDomainCount} expired domains.", expiredDomains.Count); + + foreach (var domain in expiredDomains) + { + //get admin emails of organization + var adminEmails = await GetAdminEmailsAsync(domain.OrganizationId); + + //Send email to administrators + if (adminEmails.Count > 0) + { + await _mailService.SendUnverifiedOrganizationDomainEmailAsync(adminEmails, + domain.OrganizationId.ToString(), domain.DomainName); + } + + _logger.LogInformation(Constants.BypassFiltersEventId, "Expired domain: {domainName}", domain.DomainName); + } + //delete domains that have not been verified within 7 days + var status = await _domainRepository.DeleteExpiredAsync(_globalSettings.DomainVerification.ExpirationPeriod); + _logger.LogInformation(Constants.BypassFiltersEventId, "Delete status {status}", status); + } + catch (Exception ex) + { + _logger.LogError(ex, "Organization domain maintenance failed"); + } + } + + private async Task> GetAdminEmailsAsync(Guid organizationId) + { + var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId); + var emailList = orgUsers.Where(o => o.Type <= OrganizationUserType.Admin + || o.GetPermissions()?.ManageSso == true) + .Select(a => a.Email).Distinct().ToList(); + + return emailList; + } +} diff --git a/src/Core/Services/NoopImplementations/NoopEventService.cs b/src/Core/Services/NoopImplementations/NoopEventService.cs index 7f9d02b94..a44fdf3e2 100644 --- a/src/Core/Services/NoopImplementations/NoopEventService.cs +++ b/src/Core/Services/NoopImplementations/NoopEventService.cs @@ -68,6 +68,19 @@ public class NoopEventService : IEventService return Task.FromResult(0); } + public Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, + DateTime? date = null) + { + return Task.FromResult(0); + } + + public Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, + EventSystemUser systemUser, + DateTime? date = null) + { + return Task.FromResult(0); + } + public Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type, DateTime? date = null) { return Task.FromResult(0); diff --git a/src/Core/Services/NoopImplementations/NoopMailService.cs b/src/Core/Services/NoopImplementations/NoopMailService.cs index cee8c91f4..36fb175ab 100644 --- a/src/Core/Services/NoopImplementations/NoopMailService.cs +++ b/src/Core/Services/NoopImplementations/NoopMailService.cs @@ -237,4 +237,9 @@ public class NoopMailService : IMailService { return Task.FromResult(0); } + + public Task SendUnverifiedOrganizationDomainEmailAsync(IEnumerable adminEmails, string organizationId, string domainName) + { + return Task.FromResult(0); + } } diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index 53261fa2a..6a1198fc1 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -77,6 +77,7 @@ public class GlobalSettings : IGlobalSettings public virtual DistributedIpRateLimitingSettings DistributedIpRateLimiting { get; set; } = new DistributedIpRateLimitingSettings(); public virtual IPasswordlessAuthSettings PasswordlessAuth { get; set; } = new PasswordlessAuthSettings(); + public virtual IDomainVerificationSettings DomainVerification { get; set; } = new DomainVerificationSettings(); public string BuildExternalUri(string explicitValue, string name) { @@ -537,4 +538,10 @@ public class GlobalSettings : IGlobalSettings { public bool KnownDevicesOnly { get; set; } = true; } + + public class DomainVerificationSettings : IDomainVerificationSettings + { + public int VerificationInterval { get; set; } = 12; + public int ExpirationPeriod { get; set; } = 7; + } } diff --git a/src/Core/Settings/IDomainVerificationSettings.cs b/src/Core/Settings/IDomainVerificationSettings.cs new file mode 100644 index 000000000..aac6c7004 --- /dev/null +++ b/src/Core/Settings/IDomainVerificationSettings.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Settings; + +public interface IDomainVerificationSettings +{ + public int VerificationInterval { get; set; } + public int ExpirationPeriod { get; set; } +} diff --git a/src/Core/Settings/IGlobalSettings.cs b/src/Core/Settings/IGlobalSettings.cs index 9ed58669c..724c59529 100644 --- a/src/Core/Settings/IGlobalSettings.cs +++ b/src/Core/Settings/IGlobalSettings.cs @@ -17,4 +17,5 @@ public interface IGlobalSettings ISsoSettings Sso { get; set; } ILogLevelSettings MinLogLevel { get; set; } IPasswordlessAuthSettings PasswordlessAuth { get; set; } + IDomainVerificationSettings DomainVerification { get; set; } } diff --git a/src/Core/packages.lock.json b/src/Core/packages.lock.json index 8af14081d..3d85dc378 100644 --- a/src/Core/packages.lock.json +++ b/src/Core/packages.lock.json @@ -93,6 +93,15 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Direct", + "requested": "[1.7.0, )", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2.AspNet": { "type": "Direct", "requested": "[3.0.1, )", diff --git a/src/Events/packages.lock.json b/src/Events/packages.lock.json index 51058788b..bfb0051b1 100644 --- a/src/Events/packages.lock.json +++ b/src/Events/packages.lock.json @@ -148,6 +148,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2730,6 +2738,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/EventsProcessor/packages.lock.json b/src/EventsProcessor/packages.lock.json index 51058788b..bfb0051b1 100644 --- a/src/EventsProcessor/packages.lock.json +++ b/src/EventsProcessor/packages.lock.json @@ -148,6 +148,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2730,6 +2738,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Icons/packages.lock.json b/src/Icons/packages.lock.json index 7ff4b356d..a09e93cb2 100644 --- a/src/Icons/packages.lock.json +++ b/src/Icons/packages.lock.json @@ -158,6 +158,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2740,6 +2748,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Identity/packages.lock.json b/src/Identity/packages.lock.json index 6ae150fce..cb0378ca9 100644 --- a/src/Identity/packages.lock.json +++ b/src/Identity/packages.lock.json @@ -157,6 +157,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2752,6 +2760,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs b/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs index 7d1231190..44e67f261 100644 --- a/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs +++ b/src/Infrastructure.Dapper/DapperServiceCollectionExtensions.cs @@ -38,6 +38,7 @@ public static class DapperServiceCollectionExtensions services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); if (selfHosted) { diff --git a/src/Infrastructure.Dapper/Repositories/OrganizationDomainRepository.cs b/src/Infrastructure.Dapper/Repositories/OrganizationDomainRepository.cs new file mode 100644 index 000000000..c46c994a3 --- /dev/null +++ b/src/Infrastructure.Dapper/Repositories/OrganizationDomainRepository.cs @@ -0,0 +1,110 @@ +using System.Data; +using Bit.Core.Entities; +using Bit.Core.Models.Data.Organizations; +using Bit.Core.Repositories; +using Bit.Core.Settings; +using Dapper; +using Microsoft.Data.SqlClient; + +namespace Bit.Infrastructure.Dapper.Repositories; + +public class OrganizationDomainRepository : Repository, IOrganizationDomainRepository +{ + public OrganizationDomainRepository(GlobalSettings globalSettings) + : this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString) + { } + + public OrganizationDomainRepository(string connectionString, string readOnlyConnectionString) + : base(connectionString, readOnlyConnectionString) + { } + + public async Task> GetClaimedDomainsByDomainNameAsync(string domainName) + { + using (var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[{Schema}].[OrganizationDomain_ReadByClaimedDomain]", + new { DomainName = domainName }, + commandType: CommandType.StoredProcedure); + + return results.ToList(); + } + } + + public async Task> GetDomainsByOrganizationIdAsync(Guid orgId) + { + using (var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[{Schema}].[OrganizationDomain_ReadByOrganizationId]", + new { OrganizationId = orgId }, + commandType: CommandType.StoredProcedure); + + return results.ToList(); + } + } + + public async Task> GetManyByNextRunDateAsync(DateTime date) + { + using var connection = new SqlConnection(ConnectionString); + var results = await connection.QueryAsync( + $"[{Schema}].[OrganizationDomain_ReadByNextRunDate]", + new { Date = date }, commandType: CommandType.StoredProcedure + ); + + return results.ToList(); + } + + public async Task GetOrganizationDomainSsoDetailsAsync(string email) + { + using (var connection = new SqlConnection(ConnectionString)) + { + var results = await connection + .QueryAsync( + $"[{Schema}].[OrganizationDomainSsoDetails_ReadByEmail]", + new { Email = email }, + commandType: CommandType.StoredProcedure); + + return results.SingleOrDefault(); + } + } + + public async Task GetDomainByOrgIdAndDomainNameAsync(Guid orgId, string domainName) + { + using (var connection = new SqlConnection(ConnectionString)) + { + var results = await connection + .QueryAsync( + $"[{Schema}].[OrganizationDomain_ReadDomainByOrgIdAndDomainName]", + new { OrganizationId = orgId, DomainName = domainName }, + commandType: CommandType.StoredProcedure); + + return results.SingleOrDefault(); + } + } + + public async Task> GetExpiredOrganizationDomainsAsync() + { + using (var connection = new SqlConnection(ConnectionString)) + { + var results = await connection + .QueryAsync( + $"[{Schema}].[OrganizationDomain_ReadIfExpired]", + null, + commandType: CommandType.StoredProcedure); + + return results.ToList(); + } + } + + public async Task DeleteExpiredAsync(int expirationPeriod) + { + using (var connection = new SqlConnection(ConnectionString)) + { + return await connection.ExecuteAsync( + $"[{Schema}].[OrganizationDomain_DeleteIfExpired]", + new { ExpirationPeriod = expirationPeriod }, + commandType: CommandType.StoredProcedure) > 0; + } + } +} diff --git a/src/Infrastructure.Dapper/packages.lock.json b/src/Infrastructure.Dapper/packages.lock.json index e0adb36cb..7b050ad0f 100644 --- a/src/Infrastructure.Dapper/packages.lock.json +++ b/src/Infrastructure.Dapper/packages.lock.json @@ -132,6 +132,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2559,6 +2567,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs index d40c770da..2ec4fca7e 100644 --- a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs +++ b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs @@ -73,6 +73,7 @@ public static class EntityFrameworkServiceCollectionExtensions services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); if (selfHosted) { diff --git a/src/Infrastructure.EntityFramework/Models/Organization.cs b/src/Infrastructure.EntityFramework/Models/Organization.cs index c1969cab0..49f9ff422 100644 --- a/src/Infrastructure.EntityFramework/Models/Organization.cs +++ b/src/Infrastructure.EntityFramework/Models/Organization.cs @@ -13,6 +13,7 @@ public class Organization : Core.Entities.Organization public virtual ICollection Transactions { get; set; } public virtual ICollection ApiKeys { get; set; } public virtual ICollection Connections { get; set; } + public virtual ICollection Domains { get; set; } } public class OrganizationMapperProfile : Profile diff --git a/src/Infrastructure.EntityFramework/Models/OrganizationDomain.cs b/src/Infrastructure.EntityFramework/Models/OrganizationDomain.cs new file mode 100644 index 000000000..bef7ba2af --- /dev/null +++ b/src/Infrastructure.EntityFramework/Models/OrganizationDomain.cs @@ -0,0 +1,16 @@ +using AutoMapper; + +namespace Bit.Infrastructure.EntityFramework.Models; + +public class OrganizationDomain : Core.Entities.OrganizationDomain +{ + public virtual Organization Organization { get; set; } +} + +public class OrganizationDomainMapperProfile : Profile +{ + public OrganizationDomainMapperProfile() + { + CreateMap().ReverseMap(); + } +} diff --git a/src/Infrastructure.EntityFramework/Repositories/DatabaseContext.cs b/src/Infrastructure.EntityFramework/Repositories/DatabaseContext.cs index 9aeb18dc1..e782960d8 100644 --- a/src/Infrastructure.EntityFramework/Repositories/DatabaseContext.cs +++ b/src/Infrastructure.EntityFramework/Repositories/DatabaseContext.cs @@ -56,6 +56,7 @@ public class DatabaseContext : DbContext public DbSet Transactions { get; set; } public DbSet Users { get; set; } public DbSet AuthRequests { get; set; } + public DbSet OrganizationDomains { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -95,6 +96,7 @@ public class DatabaseContext : DbContext var eOrganizationApiKey = builder.Entity(); var eOrganizationConnection = builder.Entity(); var eAuthRequest = builder.Entity(); + var eOrganizationDomain = builder.Entity(); eCipher.Property(c => c.Id).ValueGeneratedNever(); eCollection.Property(c => c.Id).ValueGeneratedNever(); @@ -116,6 +118,7 @@ public class DatabaseContext : DbContext eOrganizationApiKey.Property(c => c.Id).ValueGeneratedNever(); eOrganizationConnection.Property(c => c.Id).ValueGeneratedNever(); eAuthRequest.Property(ar => ar.Id).ValueGeneratedNever(); + eOrganizationDomain.Property(ar => ar.Id).ValueGeneratedNever(); eCollectionCipher.HasKey(cc => new { cc.CollectionId, cc.CipherId }); eCollectionUser.HasKey(cu => new { cu.CollectionId, cu.OrganizationUserId }); @@ -167,6 +170,7 @@ public class DatabaseContext : DbContext eOrganizationApiKey.ToTable(nameof(OrganizationApiKey)); eOrganizationConnection.ToTable(nameof(OrganizationConnection)); eAuthRequest.ToTable(nameof(AuthRequest)); + eOrganizationDomain.ToTable(nameof(OrganizationDomain)); ConfigureDateTimeUtcQueries(builder); } diff --git a/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs b/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs new file mode 100644 index 000000000..daafd7c95 --- /dev/null +++ b/src/Infrastructure.EntityFramework/Repositories/OrganizationDomainRepository.cs @@ -0,0 +1,147 @@ +using System.Net.Mail; +using AutoMapper; +using Bit.Core.Enums; +using Bit.Core.Models.Data.Organizations; +using Bit.Core.Repositories; +using Bit.Infrastructure.EntityFramework.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace Bit.Infrastructure.EntityFramework.Repositories; + +public class OrganizationDomainRepository : Repository, IOrganizationDomainRepository +{ + public OrganizationDomainRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper) + : base(serviceScopeFactory, mapper, (DatabaseContext context) => context.OrganizationDomains) + { + } + + public async Task> GetClaimedDomainsByDomainNameAsync( + string domainName) + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + var claimedDomains = await dbContext.OrganizationDomains + .Where(x => x.DomainName == domainName + && x.VerifiedDate != null) + .AsNoTracking() + .ToListAsync(); + return Mapper.Map>(claimedDomains); + } + + public async Task> GetDomainsByOrganizationIdAsync(Guid orgId) + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + var domains = await dbContext.OrganizationDomains + .Where(x => x.OrganizationId == orgId) + .AsNoTracking() + .ToListAsync(); + return Mapper.Map>(domains); + } + + public async Task> GetManyByNextRunDateAsync(DateTime date) + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + + var domains = await dbContext.OrganizationDomains + .Where(x => x.VerifiedDate == null + && x.JobRunCount != 3 + && x.NextRunDate.Year == date.Year + && x.NextRunDate.Month == date.Month + && x.NextRunDate.Day == date.Day + && x.NextRunDate.Hour == date.Hour) + .AsNoTracking() + .ToListAsync(); + + //Get records that have ignored/failed by the background service + var pastDomains = dbContext.OrganizationDomains + .AsEnumerable() + .Where(x => (date - x.NextRunDate).TotalHours > 36 + && x.VerifiedDate == null + && x.JobRunCount != 3) + .ToList(); + + var results = domains.Union(pastDomains); + + return Mapper.Map>(results); + } + + public async Task GetOrganizationDomainSsoDetailsAsync(string email) + { + var domainName = new MailAddress(email).Host; + + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + var ssoDetails = await dbContext.Organizations + .Join(dbContext.OrganizationDomains, o => o.Id, od => od.OrganizationId, + (organization, domain) => new { resOrganization = organization, resDomain = domain }) + .Join(dbContext.Policies, o => o.resOrganization.Id, p => p.OrganizationId, + (combinedOrgDomain, policy) + => new + { + Organization = combinedOrgDomain.resOrganization, + Domain = combinedOrgDomain.resDomain, + Policy = policy + }) + .Select(x => new OrganizationDomainSsoDetailsData + { + OrganizationId = x.Organization.Id, + OrganizationName = x.Organization.Name, + SsoAvailable = x.Organization.UseSso, + OrganizationIdentifier = x.Organization.Identifier, + SsoRequired = x.Policy.Enabled, + VerifiedDate = x.Domain.VerifiedDate, + PolicyType = x.Policy.Type, + DomainName = x.Domain.DomainName, + OrganizationEnabled = x.Organization.Enabled + }) + .Where(y => y.DomainName == domainName + && y.OrganizationEnabled == true + && y.PolicyType.Equals(PolicyType.RequireSso)) + .AsNoTracking() + .SingleOrDefaultAsync(); + + return ssoDetails; + } + + public async Task GetDomainByOrgIdAndDomainNameAsync(Guid orgId, string domainName) + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + var domain = await dbContext.OrganizationDomains + .Where(x => x.OrganizationId == orgId && x.DomainName == domainName) + .AsNoTracking() + .FirstOrDefaultAsync(); + + return Mapper.Map(domain); + } + + public async Task> GetExpiredOrganizationDomainsAsync() + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + + //Get domains that have not been verified after 72 hours + var domains = dbContext.OrganizationDomains + .AsEnumerable() + .Where(x => (DateTime.UtcNow - x.CreationDate).Days >= 4 + && x.VerifiedDate == null) + .ToList(); + + return Mapper.Map>(domains); + } + + public async Task DeleteExpiredAsync(int expirationPeriod) + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + + var expiredDomains = await dbContext.OrganizationDomains + .Where(x => x.LastCheckedDate < DateTime.UtcNow.AddDays(-expirationPeriod)) + .ToListAsync(); + dbContext.OrganizationDomains.RemoveRange(expiredDomains); + return await dbContext.SaveChangesAsync() > 0; + } +} diff --git a/src/Infrastructure.EntityFramework/packages.lock.json b/src/Infrastructure.EntityFramework/packages.lock.json index 436512dac..5a1316b52 100644 --- a/src/Infrastructure.EntityFramework/packages.lock.json +++ b/src/Infrastructure.EntityFramework/packages.lock.json @@ -207,6 +207,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2732,6 +2740,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Notifications/packages.lock.json b/src/Notifications/packages.lock.json index 9def1f8d3..42fef7467 100644 --- a/src/Notifications/packages.lock.json +++ b/src/Notifications/packages.lock.json @@ -169,6 +169,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2780,6 +2788,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs index 95537a10c..e86ae3121 100644 --- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs +++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs @@ -124,6 +124,7 @@ public static class ServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddLoginServices(); + services.AddScoped(); } public static void AddTokenizers(this IServiceCollection services) @@ -173,6 +174,7 @@ public static class ServiceCollectionExtensions services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddTokenizers(); if (CoreHelpers.SettingHasValue(globalSettings.ServiceBus.ConnectionString) && diff --git a/src/SharedWeb/packages.lock.json b/src/SharedWeb/packages.lock.json index 6ba839fea..fef8c5d43 100644 --- a/src/SharedWeb/packages.lock.json +++ b/src/SharedWeb/packages.lock.json @@ -148,6 +148,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2730,6 +2738,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index 9d7db8137..366026063 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -454,4 +454,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/Event_Create.sql b/src/Sql/dbo/Stored Procedures/Event_Create.sql index 99525ed0d..910e0e598 100644 --- a/src/Sql/dbo/Stored Procedures/Event_Create.sql +++ b/src/Sql/dbo/Stored Procedures/Event_Create.sql @@ -16,7 +16,8 @@ @DeviceType SMALLINT, @IpAddress VARCHAR(50), @Date DATETIME2(7), - @SystemUser TINYINT = null + @SystemUser TINYINT = null, + @DomainName VARCHAR(256) AS BEGIN SET NOCOUNT ON @@ -40,7 +41,8 @@ BEGIN [DeviceType], [IpAddress], [Date], - [SystemUser] + [SystemUser], + [DomainName] ) VALUES ( @@ -61,6 +63,7 @@ BEGIN @DeviceType, @IpAddress, @Date, - @SystemUser + @SystemUser, + @DomainName ) END diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql new file mode 100644 index 000000000..0a2964d65 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomainSsoDetails_ReadByEmail.sql @@ -0,0 +1,29 @@ +CREATE PROCEDURE [dbo].[OrganizationDomainSsoDetails_ReadByEmail] + @Email NVARCHAR(256) +AS +BEGIN + SET NOCOUNT ON + + DECLARE @Domain NVARCHAR(256) + + SELECT @Domain = SUBSTRING(@Email, CHARINDEX( '@', @Email) + 1, LEN(@Email)) + + SELECT + O.Id AS OrganizationId, + O.[Name] AS OrganizationName, + O.UseSso AS SsoAvailable, + P.Enabled AS SsoRequired, + O.Identifier AS OrganizationIdentifier, + OD.VerifiedDate, + P.[Type] AS PolicyType, + OD.DomainName + FROM + [dbo].[OrganizationView] O + INNER JOIN [dbo].[OrganizationDomainView] OD + ON O.Id = OD.OrganizationId + LEFT JOIN [dbo].[PolicyView] P + ON O.Id = P.OrganizationId + WHERE OD.DomainName = @Domain + AND O.Enabled = 1 + AND (P.Id is NULL OR (P.Id IS NOT NULL AND P.[Type] = 4)) -- SSO Type +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_Create.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_Create.sql new file mode 100644 index 000000000..af6f5848a --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_Create.sql @@ -0,0 +1,39 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_Create] + @Id UNIQUEIDENTIFIER OUTPUT, + @OrganizationId UNIQUEIDENTIFIER, + @Txt VARCHAR(MAX), + @DomainName NVARCHAR(255), + @CreationDate DATETIME2(7), + @VerifiedDate DATETIME2(7), + @LastCheckedDate DATETIME2(7), + @NextRunDate DATETIME2(7), + @JobRunCount TINYINT +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[OrganizationDomain] + ( + [Id], + [OrganizationId], + [Txt], + [DomainName], + [CreationDate], + [VerifiedDate], + [LastCheckedDate], + [NextRunDate], + [JobRunCount] + ) + VALUES + ( + @Id, + @OrganizationId, + @Txt, + @DomainName, + @CreationDate, + @VerifiedDate, + @LastCheckedDate, + @NextRunDate, + @JobRunCount + ) +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteById.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteById.sql new file mode 100644 index 000000000..e7637b95b --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteById.sql @@ -0,0 +1,12 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_DeleteById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + DELETE + FROM + [dbo].[OrganizationDomain] + WHERE + [Id] = @Id +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteIfExpired.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteIfExpired.sql new file mode 100644 index 000000000..3e42b9bc6 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_DeleteIfExpired.sql @@ -0,0 +1,10 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_DeleteIfExpired] + @ExpirationPeriod TINYINT +AS +BEGIN + SET NOCOUNT OFF + + DELETE FROM [dbo].[OrganizationDomain] + WHERE DATEDIFF(DAY, [LastCheckedDate], GETUTCDATE()) >= @ExpirationPeriod + AND [VerifiedDate] IS NULL +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_OrganizationDeleted.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_OrganizationDeleted.sql new file mode 100644 index 000000000..8800a31c2 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_OrganizationDeleted.sql @@ -0,0 +1,12 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_OrganizationDeleted] + @OrganizationId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + DELETE + FROM + [dbo].[OrganizationDomain] + WHERE + [OrganizationId] = @OrganizationId +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByClaimedDomain.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByClaimedDomain.sql new file mode 100644 index 000000000..3dd242437 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByClaimedDomain.sql @@ -0,0 +1,15 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_ReadByClaimedDomain] + @DomainName NVARCHAR(255) +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[OrganizationDomain] + WHERE + [DomainName] = @DomainName + AND + [VerifiedDate] IS NOT NULL +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadById.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadById.sql new file mode 100644 index 000000000..ae6f98bfd --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadById.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_ReadById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[OrganizationDomain] + WHERE + [Id] = @Id +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByNextRunDate.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByNextRunDate.sql new file mode 100644 index 000000000..7dc51c77d --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByNextRunDate.sql @@ -0,0 +1,25 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_ReadByNextRunDate] + @Date DATETIME2(7) +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[OrganizationDomain] + WHERE [VerifiedDate] IS NULL + AND [JobRunCount] != 3 + AND DATEPART(year, [NextRunDate]) = DATEPART(year, @Date) + AND DATEPART(month, [NextRunDate]) = DATEPART(month, @Date) + AND DATEPART(day, [NextRunDate]) = DATEPART(day, @Date) + AND DATEPART(hour, [NextRunDate]) = DATEPART(hour, @Date) + UNION + SELECT + * + FROM + [dbo].[OrganizationDomain] + WHERE DATEDIFF(hour, [NextRunDate], @Date) > 36 + AND [VerifiedDate] IS NULL + AND [JobRunCount] != 3 +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByOrganizationId.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByOrganizationId.sql new file mode 100644 index 000000000..e9e723ab6 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadByOrganizationId.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_ReadByOrganizationId] + @OrganizationId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[OrganizationDomain] + WHERE + [OrganizationId] = @OrganizationId +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadDomainByOrgIdAndDomainName.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadDomainByOrgIdAndDomainName.sql new file mode 100644 index 000000000..6cc19f965 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadDomainByOrgIdAndDomainName.sql @@ -0,0 +1,16 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_ReadDomainByOrgIdAndDomainName] + @OrganizationId UNIQUEIDENTIFIER, + @DomainName NVARCHAR(255) +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE + [OrganizationId] = @OrganizationId + AND + [DomainName] = @DomainName +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadIfExpired.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadIfExpired.sql new file mode 100644 index 000000000..d548c97b9 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_ReadIfExpired.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_ReadIfExpired] +AS +BEGIN + SET NOCOUNT OFF + + SELECT + * + FROM + [dbo].[OrganizationDomain] + WHERE + DATEDIFF(DAY, [CreationDate], GETUTCDATE()) >= 4 --Get domains that have not been verified after 3 days (72 hours) + AND + [VerifiedDate] IS NULL \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationDomain_Update.sql b/src/Sql/dbo/Stored Procedures/OrganizationDomain_Update.sql new file mode 100644 index 000000000..7318f9afb --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationDomain_Update.sql @@ -0,0 +1,28 @@ +CREATE PROCEDURE [dbo].[OrganizationDomain_Update] + @Id UNIQUEIDENTIFIER OUTPUT, + @OrganizationId UNIQUEIDENTIFIER, + @Txt VARCHAR(MAX), + @DomainName NVARCHAR(255), + @CreationDate DATETIME2(7), + @VerifiedDate DATETIME2(7), + @LastCheckedDate DATETIME2(7), + @NextRunDate DATETIME2(7), + @JobRunCount TINYINT +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[OrganizationDomain] + SET + [OrganizationId] = @OrganizationId, + [Txt] = @Txt, + [DomainName] = @DomainName, + [CreationDate] = @CreationDate, + [VerifiedDate] = @VerifiedDate, + [LastCheckedDate] = @LastCheckedDate + [NextRunDate] = @NextRunDate, + [JobRunCount] = @JobRunCount + WHERE + [Id] = @Id +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/Organization_DeleteById.sql b/src/Sql/dbo/Stored Procedures/Organization_DeleteById.sql index c54a08c02..2c911ea76 100644 --- a/src/Sql/dbo/Stored Procedures/Organization_DeleteById.sql +++ b/src/Sql/dbo/Stored Procedures/Organization_DeleteById.sql @@ -60,6 +60,7 @@ BEGIN EXEC [dbo].[OrganizationApiKey_OrganizationDeleted] @Id EXEC [dbo].[OrganizationConnection_OrganizationDeleted] @Id EXEC [dbo].[OrganizationSponsorship_OrganizationDeleted] @Id + EXEC [dbo].[OrganizationDomain_OrganizationDeleted] @Id DELETE FROM diff --git a/src/Sql/dbo/Tables/Event.sql b/src/Sql/dbo/Tables/Event.sql index 9972f4129..5181d6768 100644 --- a/src/Sql/dbo/Tables/Event.sql +++ b/src/Sql/dbo/Tables/Event.sql @@ -17,6 +17,7 @@ [ProviderUserId] UNIQUEIDENTIFIER NULL, [ProviderOrganizationId] UNIQUEIDENTIFIER NULL, [SystemUser] TINYINT NULL, + [DomainName] VARCHAR(256) NULL CONSTRAINT [PK_Event] PRIMARY KEY CLUSTERED ([Id] ASC) ); diff --git a/src/Sql/dbo/Tables/OrganizationDomain.sql b/src/Sql/dbo/Tables/OrganizationDomain.sql new file mode 100644 index 000000000..d7585167a --- /dev/null +++ b/src/Sql/dbo/Tables/OrganizationDomain.sql @@ -0,0 +1,15 @@ +CREATE TABLE [dbo].[OrganizationDomain] ( + [Id] UNIQUEIDENTIFIER NOT NULL, + [OrganizationId] UNIQUEIDENTIFIER NOT NULL, + [Txt] VARCHAR(MAX) NOT NULL, + [DomainName] NVARCHAR(255) NOT NULL, + [CreationDate] DATETIME2(7) NOT NULL, + [VerifiedDate] DATETIME2(7) NULL, + [LastCheckedDate] DATETIME2(7) NULL, + [NextRunDate] DATETIME2(7) NOT NULL, + [JobRunCount] TINYINT NOT NULL + CONSTRAINT [PK_OrganizationDomain] PRIMARY KEY CLUSTERED ([Id] ASC), + CONSTRAINT [FK_OrganzationDomain_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) +); + +GO \ No newline at end of file diff --git a/src/Sql/dbo/Views/OrganizationDomainView.sql b/src/Sql/dbo/Views/OrganizationDomainView.sql new file mode 100644 index 000000000..c5d484866 --- /dev/null +++ b/src/Sql/dbo/Views/OrganizationDomainView.sql @@ -0,0 +1,6 @@ +CREATE VIEW [dbo].[OrganizationDomainView] +AS +SELECT + * +FROM + [dbo].[OrganizationDomain] \ No newline at end of file diff --git a/test/Api.IntegrationTest/packages.lock.json b/test/Api.IntegrationTest/packages.lock.json index a711f7562..97e7c7b97 100644 --- a/test/Api.IntegrationTest/packages.lock.json +++ b/test/Api.IntegrationTest/packages.lock.json @@ -235,6 +235,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3193,6 +3201,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Api.Test/Controllers/OrganizationDomainControllerTests.cs b/test/Api.Test/Controllers/OrganizationDomainControllerTests.cs new file mode 100644 index 000000000..678b38776 --- /dev/null +++ b/test/Api.Test/Controllers/OrganizationDomainControllerTests.cs @@ -0,0 +1,268 @@ +using Bit.Api.Controllers; +using Bit.Api.Models.Request; +using Bit.Api.Models.Request.Organizations; +using Bit.Api.Models.Response; +using Bit.Api.Models.Response.Organizations; +using Bit.Core.Context; +using Bit.Core.Exceptions; +using Bit.Core.Models.Data.Organizations; +using Bit.Core.OrganizationFeatures.OrganizationDomains.Interfaces; +using Bit.Core.Repositories; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Xunit; +using Organization = Bit.Core.Entities.Organization; +using OrganizationDomain = Bit.Core.Entities.OrganizationDomain; + +namespace Bit.Api.Test.Controllers; + +[ControllerCustomize(typeof(OrganizationDomainController))] +[SutProviderCustomize] +public class OrganizationDomainControllerTests +{ + [Theory, BitAutoData] + public async Task Get_ShouldThrowUnauthorized_WhenOrgIdCannotManageSso(Guid orgId, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(false); + + var requestAction = async () => await sutProvider.Sut.Get(orgId.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Get_ShouldNotFound_WhenOrganizationDoesNotExist(Guid orgId, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.Get(orgId.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Get_ShouldReturnOrganizationDomainList_WhenOrgIdIsValid(Guid orgId, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).Returns(new Organization()); + sutProvider.GetDependency() + .GetDomainsByOrganizationId(orgId).Returns(new List + { + new() + { + Id = Guid.NewGuid(), + OrganizationId = orgId, + CreationDate = DateTime.UtcNow.AddDays(-7), + DomainName = "test.com", + Txt = "btw+12342" + } + }); + + var result = await sutProvider.Sut.Get(orgId.ToString()); + + Assert.IsType>(result); + Assert.Equal(orgId.ToString(), result.Data.Select(x => x.OrganizationId).FirstOrDefault()); + } + + [Theory, BitAutoData] + public async Task GetByOrgIdAndId_ShouldThrowUnauthorized_WhenOrgIdCannotManageSso(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(false); + + var requestAction = async () => await sutProvider.Sut.Get(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task GetByOrgIdAndId_ShouldThrowNotFound_WhenOrganizationDoesNotExist(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.Get(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task GetByOrgIdAndId_ShouldThrowNotFound_WhenOrganizationDomainEntryNotExist(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).Returns(new Organization()); + sutProvider.GetDependency().GetOrganizationDomainById(id).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.Get(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Get_ShouldReturnOrganizationDomain_WhenOrgIdAndIdAreValid(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).Returns(new Organization()); + sutProvider.GetDependency().GetOrganizationDomainById(id) + .Returns(new OrganizationDomain + { + Id = Guid.NewGuid(), + OrganizationId = orgId, + CreationDate = DateTime.UtcNow.AddDays(-7), + DomainName = "test.com", + Txt = "btw+12342" + }); + + var result = await sutProvider.Sut.Get(orgId.ToString(), id.ToString()); + + Assert.IsType(result); + Assert.Equal(orgId.ToString(), result.OrganizationId); + } + + [Theory, BitAutoData] + public async Task Post_ShouldThrowUnauthorized_OrgIdCannotManageSso(Guid orgId, OrganizationDomainRequestModel model, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(false); + + var requestAction = async () => await sutProvider.Sut.Post(orgId.ToString(), model); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Post_ShouldThrowNotFound_WhenOrganizationDoesNotExist(Guid orgId, OrganizationDomainRequestModel model, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.Post(orgId.ToString(), model); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Post_ShouldCreateEntry_WhenRequestIsValid(Guid orgId, OrganizationDomainRequestModel model, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).Returns(new Organization()); + sutProvider.GetDependency().CreateAsync(Arg.Any()) + .Returns(new OrganizationDomain()); + + var result = await sutProvider.Sut.Post(orgId.ToString(), model); + + await sutProvider.GetDependency().ReceivedWithAnyArgs(1) + .CreateAsync(Arg.Any()); + Assert.IsType(result); + } + + [Theory, BitAutoData] + public async Task Verify_ShouldThrowUnauthorized_WhenOrgIdCannotManageSso(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(false); + + var requestAction = async () => await sutProvider.Sut.Verify(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Verify_ShouldThrowNotFound_WhenOrganizationDoesNotExist(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.Verify(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task Verify_WhenRequestIsValid(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).Returns(new Organization()); + sutProvider.GetDependency().VerifyOrganizationDomain(id) + .Returns(new OrganizationDomain()); + + var result = await sutProvider.Sut.Verify(orgId.ToString(), id.ToString()); + + await sutProvider.GetDependency().Received(1) + .VerifyOrganizationDomain(id); + Assert.IsType(result); + } + + [Theory, BitAutoData] + public async Task RemoveDomain_ShouldThrowUnauthorized_OrgIdCannotManageSso(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(false); + + var requestAction = async () => await sutProvider.Sut.RemoveDomain(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task RemoveDomain_ShouldThrowNotFound_WhenOrganizationDoesNotExist(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.RemoveDomain(orgId.ToString(), id.ToString()); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task RemoveDomain_WhenRequestIsValid(Guid orgId, Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().ManageSso(orgId).Returns(true); + sutProvider.GetDependency().GetByIdAsync(orgId).Returns(new Organization()); + + await sutProvider.Sut.RemoveDomain(orgId.ToString(), id.ToString()); + + await sutProvider.GetDependency().Received(1) + .DeleteAsync(id); + } + + [Theory, BitAutoData] + public async Task GetOrgDomainSsoDetails_ShouldThrowNotFound_WhenEmailHasNotClaimedDomain( + OrganizationDomainSsoDetailsRequestModel model, SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetOrganizationDomainSsoDetailsAsync(model.Email).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.GetOrgDomainSsoDetails(model); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task GetOrgDomainSsoDetails_ShouldReturnOrganizationDomainSsoDetails_WhenEmailHasClaimedDomain( + OrganizationDomainSsoDetailsRequestModel model, OrganizationDomainSsoDetailsData ssoDetailsData, SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetOrganizationDomainSsoDetailsAsync(model.Email).Returns(ssoDetailsData); + + var result = await sutProvider.Sut.GetOrgDomainSsoDetails(model); + + Assert.IsType(result); + } +} diff --git a/test/Api.Test/Controllers/OrganizationsControllerTests.cs b/test/Api.Test/Controllers/OrganizationsControllerTests.cs index f056beea8..875538821 100644 --- a/test/Api.Test/Controllers/OrganizationsControllerTests.cs +++ b/test/Api.Test/Controllers/OrganizationsControllerTests.cs @@ -32,6 +32,7 @@ public class OrganizationsControllerTests : IDisposable private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository; private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery; private readonly ICreateOrganizationApiKeyCommand _createOrganizationApiKeyCommand; + private readonly IOrganizationDomainRepository _organizationDomainRepository; private readonly OrganizationsController _sut; diff --git a/test/Api.Test/packages.lock.json b/test/Api.Test/packages.lock.json index de91a9924..6ca00e3af 100644 --- a/test/Api.Test/packages.lock.json +++ b/test/Api.Test/packages.lock.json @@ -245,6 +245,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3072,6 +3080,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Billing.Test/packages.lock.json b/test/Billing.Test/packages.lock.json index 52ad5d31d..f9b1fef1f 100644 --- a/test/Billing.Test/packages.lock.json +++ b/test/Billing.Test/packages.lock.json @@ -235,6 +235,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3502,6 +3510,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Common/packages.lock.json b/test/Common/packages.lock.json index 93c85ee02..ca1cee843 100644 --- a/test/Common/packages.lock.json +++ b/test/Common/packages.lock.json @@ -218,6 +218,14 @@ "System.Xml.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -2793,6 +2801,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Core.Test/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommandTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommandTests.cs new file mode 100644 index 000000000..70773d38e --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationDomains/CreateOrganizationDomainCommandTests.cs @@ -0,0 +1,130 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using NSubstitute.ExceptionExtensions; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationDomains; + +[SutProviderCustomize] +public class CreateOrganizationDomainCommandTests +{ + [Theory, BitAutoData] + public async Task CreateAsync_ShouldCreateOrganizationDomainAndLogEvent_WhenDetailsAreValid(OrganizationDomain orgDomain, SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(orgDomain.DomainName) + .Returns(new List()); + sutProvider.GetDependency() + .GetDomainByOrgIdAndDomainNameAsync(orgDomain.OrganizationId, orgDomain.DomainName) + .ReturnsNull(); + sutProvider.GetDependency() + .ResolveAsync(orgDomain.DomainName, orgDomain.Txt) + .Returns(false); + orgDomain.SetNextRunDate(12); + sutProvider.GetDependency() + .CreateAsync(orgDomain) + .Returns(orgDomain); + + + var result = await sutProvider.Sut.CreateAsync(orgDomain); + + Assert.Equal(orgDomain.Id, result.Id); + Assert.Equal(orgDomain.OrganizationId, result.OrganizationId); + Assert.NotNull(result.LastCheckedDate); + Assert.Equal(orgDomain.NextRunDate, result.NextRunDate); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), EventType.OrganizationDomain_Added); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), Arg.Is(x => x == EventType.OrganizationDomain_NotVerified)); + } + + [Theory, BitAutoData] + public async Task CreateAsync_ShouldThrowConflictException_WhenDomainIsClaimed(OrganizationDomain orgDomain, + SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(orgDomain.DomainName) + .Returns(new List() + { + orgDomain + }); + + var requestAction = async () => await sutProvider.Sut.CreateAsync(orgDomain); + + var exception = await Assert.ThrowsAsync(requestAction); + Assert.Contains("The domain is not available to be claimed.", exception.Message); + } + + [Theory, BitAutoData] + public async Task CreateAsync_ShouldThrowConflictException_WhenEntryIsDuplicatedForOrganization(OrganizationDomain orgDomain, + SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(orgDomain.DomainName) + .Returns(new List()); + sutProvider.GetDependency() + .GetDomainByOrgIdAndDomainNameAsync(orgDomain.OrganizationId, orgDomain.DomainName) + .Returns(orgDomain); + + var requestAction = async () => await sutProvider.Sut.CreateAsync(orgDomain); + + var exception = await Assert.ThrowsAsync(requestAction); + Assert.Contains("A domain already exists for this organization.", exception.Message); + } + + [Theory, BitAutoData] + public async Task CreateAsync_ShouldNotSetVerifiedDate_WhenDomainCannotBeResolved(OrganizationDomain orgDomain, + SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(orgDomain.DomainName) + .Returns(new List()); + sutProvider.GetDependency() + .GetDomainByOrgIdAndDomainNameAsync(orgDomain.OrganizationId, orgDomain.DomainName) + .ReturnsNull(); + sutProvider.GetDependency() + .ResolveAsync(orgDomain.DomainName, orgDomain.Txt) + .Throws(new DnsQueryException("")); + sutProvider.GetDependency() + .CreateAsync(orgDomain) + .Returns(orgDomain); + + await sutProvider.Sut.CreateAsync(orgDomain); + + Assert.Null(orgDomain.VerifiedDate); + } + + [Theory, BitAutoData] + public async Task CreateAsync_ShouldSetVerifiedDateAndLogEvent_WhenDomainIsResolved(OrganizationDomain orgDomain, + SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(orgDomain.DomainName) + .Returns(new List()); + sutProvider.GetDependency() + .GetDomainByOrgIdAndDomainNameAsync(orgDomain.OrganizationId, orgDomain.DomainName) + .ReturnsNull(); + sutProvider.GetDependency() + .ResolveAsync(orgDomain.DomainName, orgDomain.Txt) + .Returns(true); + sutProvider.GetDependency() + .CreateAsync(orgDomain) + .Returns(orgDomain); + + var result = await sutProvider.Sut.CreateAsync(orgDomain); + + Assert.NotNull(result.VerifiedDate); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), EventType.OrganizationDomain_Added); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), Arg.Is(x => x == EventType.OrganizationDomain_Verified)); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommandTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommandTests.cs new file mode 100644 index 000000000..b9201d35a --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationDomains/DeleteOrganizationDomainCommandTests.cs @@ -0,0 +1,47 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationDomains; + +[SutProviderCustomize] +public class DeleteOrganizationDomainCommandTests +{ + [Theory, BitAutoData] + public async Task DeleteAsync_ShouldThrowNotFoundException_WhenIdDoesNotExist(Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency().GetByIdAsync(id).ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.DeleteAsync(id); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task DeleteAsync_Success(Guid id, SutProvider sutProvider) + { + var expected = new OrganizationDomain + { + Id = id, + OrganizationId = Guid.NewGuid(), + DomainName = "Test Domain", + Txt = "btw+test18383838383" + }; + sutProvider.GetDependency().GetByIdAsync(id).Returns(expected); + + await sutProvider.Sut.DeleteAsync(id); + + await sutProvider.GetDependency().Received(1).DeleteAsync(expected); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), EventType.OrganizationDomain_Removed); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQueryTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQueryTests.cs new file mode 100644 index 000000000..0cb77d243 --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByIdQueryTests.cs @@ -0,0 +1,22 @@ +using Bit.Core.OrganizationFeatures.OrganizationDomains; +using Bit.Core.Repositories; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationDomains; + +[SutProviderCustomize] +public class GetOrganizationDomainByIdQueryTests +{ + [Theory, BitAutoData] + public async Task GetOrganizationDomainById_CallsGetByIdAsync(Guid id, + SutProvider sutProvider) + { + await sutProvider.Sut.GetOrganizationDomainById(id); + + await sutProvider.GetDependency().Received(1) + .GetByIdAsync(id); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQueryTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQueryTests.cs new file mode 100644 index 000000000..964a3a76d --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationDomains/GetOrganizationDomainByOrganizationIdQueryTests.cs @@ -0,0 +1,22 @@ +using Bit.Core.OrganizationFeatures.OrganizationDomains; +using Bit.Core.Repositories; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationDomains; + +[SutProviderCustomize] +public class GetOrganizationDomainByOrganizationIdQueryTests +{ + [Theory, BitAutoData] + public async Task GetDomainsByOrganizationId_CallsGetDomainsByOrganizationIdAsync(Guid orgId, + SutProvider sutProvider) + { + await sutProvider.Sut.GetDomainsByOrganizationId(orgId); + + await sutProvider.GetDependency().Received(1) + .GetDomainsByOrganizationIdAsync(orgId); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs new file mode 100644 index 000000000..54783982a --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs @@ -0,0 +1,135 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationDomains; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using NSubstitute.ReceivedExtensions; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationDomains; + +[SutProviderCustomize] +public class VerifyOrganizationDomainCommandTests +{ + [Theory, BitAutoData] + public async Task VerifyOrganizationDomain_ShouldThrowNotFound_WhenDomainDoesNotExist(Guid id, + SutProvider sutProvider) + { + sutProvider.GetDependency() + .GetByIdAsync(id) + .ReturnsNull(); + + var requestAction = async () => await sutProvider.Sut.VerifyOrganizationDomain(id); + + await Assert.ThrowsAsync(requestAction); + } + + [Theory, BitAutoData] + public async Task VerifyOrganizationDomain_ShouldThrowConflict_WhenDomainHasBeenClaimed(Guid id, + SutProvider sutProvider) + { + var expected = new OrganizationDomain + { + Id = id, + OrganizationId = Guid.NewGuid(), + DomainName = "Test Domain", + Txt = "btw+test18383838383" + }; + expected.SetVerifiedDate(); + sutProvider.GetDependency() + .GetByIdAsync(id) + .Returns(expected); + + var requestAction = async () => await sutProvider.Sut.VerifyOrganizationDomain(id); + + var exception = await Assert.ThrowsAsync(requestAction); + Assert.Contains("Domain has already been verified.", exception.Message); + } + + [Theory, BitAutoData] + public async Task VerifyOrganizationDomain_ShouldThrowConflict_WhenDomainHasBeenClaimedByAnotherOrganization(Guid id, + SutProvider sutProvider) + { + var expected = new OrganizationDomain + { + Id = id, + OrganizationId = Guid.NewGuid(), + DomainName = "Test Domain", + Txt = "btw+test18383838383" + }; + sutProvider.GetDependency() + .GetByIdAsync(id) + .Returns(expected); + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(expected.DomainName) + .Returns(new List { expected }); + + var requestAction = async () => await sutProvider.Sut.VerifyOrganizationDomain(id); + + var exception = await Assert.ThrowsAsync(requestAction); + Assert.Contains("The domain is not available to be claimed.", exception.Message); + } + + [Theory, BitAutoData] + public async Task VerifyOrganizationDomain_ShouldVerifyDomainUpdateAndLogEvent_WhenTxtRecordExists(Guid id, + SutProvider sutProvider) + { + var expected = new OrganizationDomain + { + Id = id, + OrganizationId = Guid.NewGuid(), + DomainName = "Test Domain", + Txt = "btw+test18383838383" + }; + sutProvider.GetDependency() + .GetByIdAsync(id) + .Returns(expected); + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(expected.DomainName) + .Returns(new List()); + sutProvider.GetDependency() + .ResolveAsync(expected.DomainName, Arg.Any()) + .Returns(true); + + var result = await sutProvider.Sut.VerifyOrganizationDomain(id); + + Assert.NotNull(result.VerifiedDate); + await sutProvider.GetDependency().Received(1) + .ReplaceAsync(Arg.Any()); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), EventType.OrganizationDomain_Verified); + } + + [Theory, BitAutoData] + public async Task VerifyOrganizationDomain_ShouldNotSetVerifiedDate_WhenTxtRecordDoesNotExist(Guid id, + SutProvider sutProvider) + { + var expected = new OrganizationDomain + { + Id = id, + OrganizationId = Guid.NewGuid(), + DomainName = "Test Domain", + Txt = "btw+test18383838383" + }; + sutProvider.GetDependency() + .GetByIdAsync(id) + .Returns(expected); + sutProvider.GetDependency() + .GetClaimedDomainsByDomainNameAsync(expected.DomainName) + .Returns(new List()); + sutProvider.GetDependency() + .ResolveAsync(expected.DomainName, Arg.Any()) + .Returns(false); + + var result = await sutProvider.Sut.VerifyOrganizationDomain(id); + + Assert.Null(result.VerifiedDate); + await sutProvider.GetDependency().Received(1) + .LogOrganizationDomainEventAsync(Arg.Any(), EventType.OrganizationDomain_NotVerified); + } +} diff --git a/test/Core.Test/Services/EventServiceTests.cs b/test/Core.Test/Services/EventServiceTests.cs index cd3498f30..8454f05f5 100644 --- a/test/Core.Test/Services/EventServiceTests.cs +++ b/test/Core.Test/Services/EventServiceTests.cs @@ -71,19 +71,26 @@ public class EventServiceTests await sutProvider.Sut.LogGroupEventAsync(group, eventType, eventSystemUser, date); + var eventMessage = new EventMessage() + { + IpAddress = ipAddress, + DeviceType = deviceType, + OrganizationId = group.OrganizationId, + GroupId = group.Id, + Type = eventType, + ActingUserId = actingUserId, + ProviderId = providerId, + Date = date, + SystemUser = eventSystemUser + }; + + if (eventSystemUser is EventSystemUser.SCIM) + { + eventMessage.DeviceType = DeviceType.Server; + } + var expected = new List() { - new EventMessage() - { - IpAddress = ipAddress, - DeviceType = deviceType, - OrganizationId = group.OrganizationId, - GroupId = group.Id, - Type = eventType, - ActingUserId = actingUserId, - ProviderId = providerId, - Date = date, - SystemUser = eventSystemUser - } + eventMessage }; await sutProvider.GetDependency().Received(1).CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual(expected, new[] { "IdempotencyId" }))); @@ -143,7 +150,7 @@ public class EventServiceTests [Theory, BitAutoData] public async Task LogOrganizationUserEvent_WithEventSystemUser_LogsRequiredInfo(OrganizationUser orgUser, EventType eventType, EventSystemUser eventSystemUser, DateTime date, - Guid actingUserId, Guid providerId, string ipAddress, DeviceType deviceType, SutProvider sutProvider) + Guid actingUserId, Guid providerId, string ipAddress, SutProvider sutProvider) { var orgAbilities = new Dictionary() { @@ -153,7 +160,6 @@ public class EventServiceTests sutProvider.GetDependency().UserId.Returns(actingUserId); sutProvider.GetDependency().IpAddress.Returns(ipAddress); sutProvider.GetDependency().ProviderIdForOrg(Arg.Any()).Returns(providerId); - sutProvider.GetDependency().DeviceType.Returns(deviceType); await sutProvider.Sut.LogOrganizationUserEventAsync(orgUser, eventType, eventSystemUser, date); @@ -161,7 +167,7 @@ public class EventServiceTests new EventMessage() { IpAddress = ipAddress, - DeviceType = deviceType, + DeviceType = DeviceType.Server, OrganizationId = orgUser.OrganizationId, UserId = orgUser.UserId, OrganizationUserId = orgUser.Id, diff --git a/test/Core.Test/Services/OrganizationDomainServiceTests.cs b/test/Core.Test/Services/OrganizationDomainServiceTests.cs new file mode 100644 index 000000000..b6f299b3a --- /dev/null +++ b/test/Core.Test/Services/OrganizationDomainServiceTests.cs @@ -0,0 +1,83 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using Xunit; + +namespace Bit.Core.Test.Services; + +[SutProviderCustomize] +public class OrganizationDomainServiceTests +{ + + [Theory, BitAutoData] + public async Task ValidateOrganizationsDomainAsync_CallsDnsResolverServiceAndReplace(SutProvider sutProvider) + { + var domains = new List + { + new() + { + Id = Guid.NewGuid(), + OrganizationId = Guid.NewGuid(), + CreationDate = DateTime.UtcNow, + DomainName = "test.com", + Txt = "btw+12345", + }, + new() + { + Id = Guid.NewGuid(), + OrganizationId = Guid.NewGuid(), + CreationDate = DateTime.UtcNow, + DomainName = "test2.com", + Txt = "btw+6789" + } + }; + sutProvider.GetDependency().GetManyByNextRunDateAsync(default) + .ReturnsForAnyArgs(domains); + + await sutProvider.Sut.ValidateOrganizationsDomainAsync(); + + await sutProvider.GetDependency().ReceivedWithAnyArgs(2) + .ResolveAsync(default, default); + await sutProvider.GetDependency().ReceivedWithAnyArgs(2) + .ReplaceAsync(default); + await sutProvider.GetDependency().ReceivedWithAnyArgs(2) + .LogOrganizationDomainEventAsync(default, EventType.OrganizationDomain_NotVerified, + EventSystemUser.DomainVerification); + } + + [Theory, BitAutoData] + public async Task OrganizationDomainMaintenanceAsync_CallsDeleteExpiredAsync_WhenExpiredDomainsExist( + SutProvider sutProvider) + { + var expiredDomains = new List + { + new() + { + Id = Guid.NewGuid(), + OrganizationId = Guid.NewGuid(), + CreationDate = DateTime.UtcNow, + DomainName = "test.com", + Txt = "btw+12345", + }, + new() + { + Id = Guid.NewGuid(), + OrganizationId = Guid.NewGuid(), + CreationDate = DateTime.UtcNow, + DomainName = "test2.com", + Txt = "btw+6789" + } + }; + sutProvider.GetDependency().GetExpiredOrganizationDomainsAsync() + .Returns(expiredDomains); + + await sutProvider.Sut.OrganizationDomainMaintenanceAsync(); + + await sutProvider.GetDependency().ReceivedWithAnyArgs(1) + .DeleteExpiredAsync(7); + } +} diff --git a/test/Core.Test/packages.lock.json b/test/Core.Test/packages.lock.json index 0f54629a5..f955a523a 100644 --- a/test/Core.Test/packages.lock.json +++ b/test/Core.Test/packages.lock.json @@ -234,6 +234,14 @@ "System.Xml.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -2821,6 +2829,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Icons.Test/packages.lock.json b/test/Icons.Test/packages.lock.json index 3222145cc..9748de731 100644 --- a/test/Icons.Test/packages.lock.json +++ b/test/Icons.Test/packages.lock.json @@ -216,6 +216,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2915,6 +2923,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Identity.IntegrationTest/packages.lock.json b/test/Identity.IntegrationTest/packages.lock.json index 520d2901c..e1cbb115a 100644 --- a/test/Identity.IntegrationTest/packages.lock.json +++ b/test/Identity.IntegrationTest/packages.lock.json @@ -246,6 +246,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3140,6 +3148,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Identity.Test/packages.lock.json b/test/Identity.Test/packages.lock.json index 223f29551..40b0b4f5d 100644 --- a/test/Identity.Test/packages.lock.json +++ b/test/Identity.Test/packages.lock.json @@ -235,6 +235,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3007,6 +3015,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Infrastructure.EFIntegration.Test/packages.lock.json b/test/Infrastructure.EFIntegration.Test/packages.lock.json index 0194056cd..6c4e327eb 100644 --- a/test/Infrastructure.EFIntegration.Test/packages.lock.json +++ b/test/Infrastructure.EFIntegration.Test/packages.lock.json @@ -246,6 +246,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -2997,6 +3005,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/Infrastructure.IntegrationTest/packages.lock.json b/test/Infrastructure.IntegrationTest/packages.lock.json index 876a4117e..87b67248d 100644 --- a/test/Infrastructure.IntegrationTest/packages.lock.json +++ b/test/Infrastructure.IntegrationTest/packages.lock.json @@ -220,6 +220,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2845,6 +2853,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/test/IntegrationTestCommon/packages.lock.json b/test/IntegrationTestCommon/packages.lock.json index e65cbeb55..df6bebf4e 100644 --- a/test/IntegrationTestCommon/packages.lock.json +++ b/test/IntegrationTestCommon/packages.lock.json @@ -222,6 +222,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fare": { "type": "Transitive", "resolved": "2.1.1", @@ -3126,6 +3134,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/util/Migrator/DbScripts/2022-11-03_00_OrganizationDomainInit.sql b/util/Migrator/DbScripts/2022-11-03_00_OrganizationDomainInit.sql new file mode 100644 index 000000000..94c04c321 --- /dev/null +++ b/util/Migrator/DbScripts/2022-11-03_00_OrganizationDomainInit.sql @@ -0,0 +1,285 @@ +-- Create Organization Domain table +IF OBJECT_ID('[dbo].[OrganizationDomain]') IS NOT NULL +BEGIN + DROP TABLE [dbo].[OrganizationDomain] +END +GO + +IF OBJECT_ID('[dbo].[OrganizationDomain]') IS NULL +BEGIN +CREATE TABLE [dbo].[OrganizationDomain] ( + [Id] UNIQUEIDENTIFIER NOT NULL, + [OrganizationId] UNIQUEIDENTIFIER NOT NULL, + [Txt] VARCHAR(MAX) NOT NULL, + [DomainName] NVARCHAR(255) NOT NULL, + [CreationDate] DATETIME2(7) NOT NULL, + [VerifiedDate] DATETIME2(7) NULL, + [LastCheckedDate] DATETIME2(7) NULL, + [NextRunDate] DATETIME2(7) NOT NULL, + [JobRunCount] TINYINT NOT NULL + CONSTRAINT [PK_OrganizationDomain] PRIMARY KEY CLUSTERED ([Id] ASC), + CONSTRAINT [FK_OrganzationDomain_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) +) +END +GO + +-- Create View +CREATE OR ALTER VIEW [dbo].[OrganizationDomainView] +AS +SELECT + * +FROM + [dbo].[OrganizationDomain] +GO + +-- Organization Domain CRUD SPs +-- Create +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_Create] + @Id UNIQUEIDENTIFIER OUTPUT, + @OrganizationId UNIQUEIDENTIFIER, + @Txt VARCHAR(MAX), + @DomainName NVARCHAR(255), + @CreationDate DATETIME2(7), + @VerifiedDate DATETIME2(7), + @LastCheckedDate DATETIME2(7), + @NextRunDate DATETIME2(7), + @JobRunCount TINYINT +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[OrganizationDomain] + ( + [Id], + [OrganizationId], + [Txt], + [DomainName], + [CreationDate], + [VerifiedDate], + [LastCheckedDate], + [NextRunDate], + [JobRunCount] + ) + VALUES + ( + @Id, + @OrganizationId, + @Txt, + @DomainName, + @CreationDate, + @VerifiedDate, + @LastCheckedDate, + @NextRunDate, + @JobRunCount + ) +END +GO + +--Update +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_Update] + @Id UNIQUEIDENTIFIER OUTPUT, + @OrganizationId UNIQUEIDENTIFIER, + @Txt VARCHAR(MAX), + @DomainName NVARCHAR(255), + @CreationDate DATETIME2(7), + @VerifiedDate DATETIME2(7), + @LastCheckedDate DATETIME2(7), + @NextRunDate DATETIME2(7), + @JobRunCount TINYINT +AS +BEGIN + SET NOCOUNT ON + +UPDATE + [dbo].[OrganizationDomain] +SET + [OrganizationId] = @OrganizationId, + [Txt] = @Txt, + [DomainName] = @DomainName, + [CreationDate] = @CreationDate, + [VerifiedDate] = @VerifiedDate, + [LastCheckedDate] = @LastCheckedDate, + [NextRunDate] = @NextRunDate, + [JobRunCount] = @JobRunCount +WHERE + [Id] = @Id +END +GO + +--Read +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_ReadById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE + [Id] = @Id +END +GO + +--Delete +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_DeleteById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + +DELETE +FROM + [dbo].[OrganizationDomain] +WHERE + [Id] = @Id +END +GO + +-- SP to get claimed domain by domain name +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_ReadByClaimedDomain] + @DomainName NVARCHAR(255) +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE + [DomainName] = @DomainName + AND + [VerifiedDate] IS NOT NULL +END +GO + +-- SP to get domains by OrganizationId +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_ReadByOrganizationId] + @OrganizationId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE + [OrganizationId] = @OrganizationId +END +GO + +--SP to get domain by organizationId and domainName +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_ReadDomainByOrgIdAndDomainName] + @OrganizationId UNIQUEIDENTIFIER, + @DomainName NVARCHAR(255) +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE + [OrganizationId] = @OrganizationId + AND + [DomainName] = @DomainName +END +GO + +--SP Read by nextRunDate +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_ReadByNextRunDate] + @Date DATETIME2(7) +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE [VerifiedDate] IS NULL + AND [JobRunCount] != 3 + AND DATEPART(year, [NextRunDate]) = DATEPART(year, @Date) + AND DATEPART(month, [NextRunDate]) = DATEPART(month, @Date) + AND DATEPART(day, [NextRunDate]) = DATEPART(day, @Date) + AND DATEPART(hour, [NextRunDate]) = DATEPART(hour, @Date) +UNION +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE DATEDIFF(hour, [NextRunDate], @Date) > 36 + AND [VerifiedDate] IS NULL + AND [JobRunCount] != 3 +END +GO + +-- SP to get all domains that have not been verified within 72 hours +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_ReadIfExpired] +AS +BEGIN + SET NOCOUNT OFF + +SELECT + * +FROM + [dbo].[OrganizationDomain] +WHERE + DATEDIFF(DAY, [CreationDate], GETUTCDATE()) >= 4 --Get domains that have not been verified after 3 days (72 hours) + AND + [VerifiedDate] IS NULL +END +GO + +-- SP to delete domains that have been left unverified for 7 days +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_DeleteIfExpired] + @ExpirationPeriod TINYINT +AS +BEGIN + SET NOCOUNT OFF + +DELETE FROM [dbo].[OrganizationDomain] +WHERE DATEDIFF(DAY, [LastCheckedDate], GETUTCDATE()) >= @ExpirationPeriod + AND [VerifiedDate] IS NULL +END +GO + +-- SP to get Organization SSO Provider details by Email +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomainSsoDetails_ReadByEmail] + @Email NVARCHAR(256) +AS +BEGIN + SET NOCOUNT ON + + DECLARE @Domain NVARCHAR(256) + +SELECT @Domain = SUBSTRING(@Email, CHARINDEX( '@', @Email) + 1, LEN(@Email)) + +SELECT + O.Id AS OrganizationId, + O.[Name] AS OrganizationName, + O.UseSso AS SsoAvailable, + P.Enabled AS SsoRequired, + O.Identifier AS OrganizationIdentifier, + OD.VerifiedDate, + P.[Type] AS PolicyType, + OD.DomainName +FROM + [dbo].[OrganizationView] O + INNER JOIN [dbo].[OrganizationDomainView] OD +ON O.Id = OD.OrganizationId + -- use left join instead of inner join so that results + -- come back even if org doesn't have a policy yet for + -- requiring SSO + LEFT JOIN [dbo].[PolicyView] P + ON O.Id = P.OrganizationId +WHERE OD.DomainName = @Domain + AND O.Enabled = 1 + -- Handle null results + AND (P.Id is NULL OR (P.Id IS NOT NULL AND P.[Type] = 4)) -- SSO Type +END +GO \ No newline at end of file diff --git a/util/Migrator/DbScripts/2022-12-08_00_EventsDomainName.sql b/util/Migrator/DbScripts/2022-12-08_00_EventsDomainName.sql new file mode 100644 index 000000000..c04bf0691 --- /dev/null +++ b/util/Migrator/DbScripts/2022-12-08_00_EventsDomainName.sql @@ -0,0 +1,95 @@ +--Add column DomainName to Event table +IF COL_LENGTH('[dbo].[Event]', 'DomainName') IS NULL + BEGIN + ALTER TABLE + [dbo].[Event] + ADD + [DomainName] VARCHAR(256) NULL; + END +GO + +-- Recreate EventView +IF OBJECT_ID('[dbo].[EventView]') IS NOT NULL +BEGIN + DROP VIEW [dbo].[EventView] +END +GO + +CREATE VIEW [dbo].[EventView] +AS +SELECT + * +FROM + [dbo].[Event] +GO + +CREATE OR ALTER PROCEDURE [dbo].[Event_Create] + @Id UNIQUEIDENTIFIER OUTPUT, + @Type INT, + @UserId UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @InstallationId UNIQUEIDENTIFIER, + @ProviderId UNIQUEIDENTIFIER, + @CipherId UNIQUEIDENTIFIER, + @CollectionId UNIQUEIDENTIFIER, + @PolicyId UNIQUEIDENTIFIER, + @GroupId UNIQUEIDENTIFIER, + @OrganizationUserId UNIQUEIDENTIFIER, + @ProviderUserId UNIQUEIDENTIFIER, + @ProviderOrganizationId UNIQUEIDENTIFIER = null, + @ActingUserId UNIQUEIDENTIFIER, + @DeviceType SMALLINT, + @IpAddress VARCHAR(50), + @Date DATETIME2(7), + @SystemUser TINYINT = null, + @DomainName VARCHAR(256) +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[Event] + ( + [Id], + [Type], + [UserId], + [OrganizationId], + [InstallationId], + [ProviderId], + [CipherId], + [CollectionId], + [PolicyId], + [GroupId], + [OrganizationUserId], + [ProviderUserId], + [ProviderOrganizationId], + [ActingUserId], + [DeviceType], + [IpAddress], + [Date], + [SystemUser], + [DomainName] + ) + VALUES + ( + @Id, + @Type, + @UserId, + @OrganizationId, + @InstallationId, + @ProviderId, + @CipherId, + @CollectionId, + @PolicyId, + @GroupId, + @OrganizationUserId, + @ProviderUserId, + @ProviderOrganizationId, + @ActingUserId, + @DeviceType, + @IpAddress, + @Date, + @SystemUser, + @DomainName + ) +END +GO \ No newline at end of file diff --git a/util/Migrator/DbScripts/2023_01_18_00_FixOrganizationDeleteOrgDomain.sql b/util/Migrator/DbScripts/2023_01_18_00_FixOrganizationDeleteOrgDomain.sql new file mode 100644 index 000000000..eeea4ea7c --- /dev/null +++ b/util/Migrator/DbScripts/2023_01_18_00_FixOrganizationDeleteOrgDomain.sql @@ -0,0 +1,114 @@ +-- Create OrganizationDomain delete by OrganizationId +CREATE OR ALTER PROCEDURE [dbo].[OrganizationDomain_OrganizationDeleted] + @OrganizationId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + +DELETE +FROM + [dbo].[OrganizationDomain] +WHERE + [OrganizationId] = @OrganizationId +END +GO + +-- Update Organization Delete By Id to include OrganizationDomain_OrganizationDeleted +CREATE OR ALTER PROCEDURE [dbo].[Organization_DeleteById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @Id + + DECLARE @BatchSize INT = 100 + WHILE @BatchSize > 0 +BEGIN +BEGIN TRANSACTION Organization_DeleteById_Ciphers + + DELETE TOP(@BatchSize) + FROM + [dbo].[Cipher] + WHERE + [UserId] IS NULL + AND [OrganizationId] = @Id + + SET @BatchSize = @@ROWCOUNT + + COMMIT TRANSACTION Organization_DeleteById_Ciphers +END + +BEGIN TRANSACTION Organization_DeleteById + +DELETE +FROM + [dbo].[SsoUser] +WHERE + [OrganizationId] = @Id + +DELETE +FROM + [dbo].[SsoConfig] +WHERE + [OrganizationId] = @Id + +DELETE CU + FROM + [dbo].[CollectionUser] CU + INNER JOIN + [dbo].[OrganizationUser] OU ON [CU].[OrganizationUserId] = [OU].[Id] + WHERE + [OU].[OrganizationId] = @Id + +DELETE +FROM + [dbo].[OrganizationUser] +WHERE + [OrganizationId] = @Id + +DELETE +FROM + [dbo].[ProviderOrganization] +WHERE + [OrganizationId] = @Id + + EXEC [dbo].[OrganizationApiKey_OrganizationDeleted] @Id + EXEC [dbo].[OrganizationConnection_OrganizationDeleted] @Id + EXEC [dbo].[OrganizationSponsorship_OrganizationDeleted] @Id + EXEC [dbo].[OrganizationDomain_OrganizationDeleted] @Id + +DELETE +FROM + [dbo].[Project] +WHERE + [OrganizationId] = @Id + +DELETE +FROM + [dbo].[Secret] +WHERE + [OrganizationId] = @Id + +DELETE AK + FROM + [dbo].[ApiKey] AK + INNER JOIN + [dbo].[ServiceAccount] SA ON [AK].[ServiceAccountId] = [SA].[Id] + WHERE + [SA].[OrganizationId] = @Id + +DELETE +FROM + [dbo].[ServiceAccount] +WHERE + [OrganizationId] = @Id + +DELETE +FROM + [dbo].[Organization] +WHERE + [Id] = @Id + + COMMIT TRANSACTION Organization_DeleteById +END \ No newline at end of file diff --git a/util/Migrator/packages.lock.json b/util/Migrator/packages.lock.json index 02ea2191b..a55fa2a08 100644 --- a/util/Migrator/packages.lock.json +++ b/util/Migrator/packages.lock.json @@ -159,6 +159,14 @@ "System.Diagnostics.TraceSource": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2613,6 +2621,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/util/MySqlMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.sql b/util/MySqlMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.sql new file mode 100644 index 000000000..49279dac9 --- /dev/null +++ b/util/MySqlMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.sql @@ -0,0 +1,21 @@ +START TRANSACTION; + +CREATE TABLE `OrganizationDomain` ( + `Id` char(36) COLLATE ascii_general_ci NOT NULL, + `OrganizationId` char(36) COLLATE ascii_general_ci NOT NULL, + `Txt` longtext CHARACTER SET utf8mb4 NULL, + `DomainName` varchar(255) CHARACTER SET utf8mb4 NULL, + `CreationDate` datetime(6) NOT NULL, + `VerifiedDate` datetime(6) NULL, + `NextRunDate` datetime(6) NOT NULL, + `NextRunCount` int NOT NULL, + CONSTRAINT `PK_OrganizationDomain` PRIMARY KEY (`Id`), + CONSTRAINT `FK_OrganizationDomain_Organization_OrganizationId` FOREIGN KEY (`OrganizationId`) REFERENCES `Organization` (`Id`) ON DELETE CASCADE +) CHARACTER SET=utf8mb4; + +CREATE INDEX `IX_OrganizationDomain_OrganizationId` ON `OrganizationDomain` (`OrganizationId`); + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20221108015516_OrganizationDomainClaim', '6.0.4'); + +COMMIT; \ No newline at end of file diff --git a/util/MySqlMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.sql b/util/MySqlMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.sql new file mode 100644 index 000000000..49d35fc00 --- /dev/null +++ b/util/MySqlMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.sql @@ -0,0 +1,8 @@ +START TRANSACTION; + +ALTER TABLE `OrganizationDomain` RENAME COLUMN `NextRunCount` TO `JobRunCount`; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20221129004644_OrganizationDomainClaimRenameNextRunCount', '6.0.4'); + +COMMIT; \ No newline at end of file diff --git a/util/MySqlMigrations/HelperScripts/2022-12-08_00_EventsDomainName.sql b/util/MySqlMigrations/HelperScripts/2022-12-08_00_EventsDomainName.sql new file mode 100644 index 000000000..bba4fe72f --- /dev/null +++ b/util/MySqlMigrations/HelperScripts/2022-12-08_00_EventsDomainName.sql @@ -0,0 +1,9 @@ +START TRANSACTION; + +ALTER TABLE `Event` ADD `DomainName` longtext CHARACTER SET utf8mb4 NULL; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20221209015017_EventsDomainName', '6.0.4'); + +COMMIT; + diff --git a/util/MySqlMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.sql b/util/MySqlMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.sql new file mode 100644 index 000000000..5204026f9 --- /dev/null +++ b/util/MySqlMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.sql @@ -0,0 +1,9 @@ +START TRANSACTION; + +ALTER TABLE `OrganizationDomain` ADD `LastCheckedDate` datetime(6) NULL; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20221209192355_OrganizationDomainLastCheckedDate', '6.0.4'); + +COMMIT; + diff --git a/util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.Designer.cs b/util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.Designer.cs new file mode 100644 index 000000000..9df3c72b4 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.Designer.cs @@ -0,0 +1,1722 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221114202829_OrganizationDomainClaim")] + partial class OrganizationDomainClaim + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("varchar(25)"); + + b.Property("Approved") + .HasColumnType("tinyint(1)"); + + b.Property("AuthenticationDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MasterPasswordHash") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("RequestFingerprint") + .HasColumnType("longtext"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ResponseDate") + .HasColumnType("datetime(6)"); + + b.Property("ResponseDeviceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("GranteeId") + .HasColumnType("char(36)"); + + b.Property("GrantorId") + .HasColumnType("char(36)"); + + b.Property("KeyEncrypted") + .HasColumnType("longtext"); + + b.Property("LastNotificationDate") + .HasColumnType("datetime(6)"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("WaitTimeDays") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ActingUserId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("DeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("InstallationId") + .HasColumnType("char(36)"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("PolicyId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("ProviderOrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlanType") + .HasColumnType("tinyint unsigned"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Seats") + .HasColumnType("int"); + + b.Property("SelfHost") + .HasColumnType("tinyint(1)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("Use2fa") + .HasColumnType("tinyint(1)"); + + b.Property("UseApi") + .HasColumnType("tinyint(1)"); + + b.Property("UseDirectory") + .HasColumnType("tinyint(1)"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.Property("UseGroups") + .HasColumnType("tinyint(1)"); + + b.Property("UseKeyConnector") + .HasColumnType("tinyint(1)"); + + b.Property("UsePolicies") + .HasColumnType("tinyint(1)"); + + b.Property("UseResetPassword") + .HasColumnType("tinyint(1)"); + + b.Property("UseScim") + .HasColumnType("tinyint(1)"); + + b.Property("UseSso") + .HasColumnType("tinyint(1)"); + + b.Property("UseTotp") + .HasColumnType("tinyint(1)"); + + b.Property("UsersGetPremium") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("NextRunCount") + .HasColumnType("int"); + + b.Property("NextRunDate") + .HasColumnType("datetime(6)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Txt") + .HasColumnType("longtext"); + + b.Property("VerifiedDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasColumnType("longtext"); + + b.Property("BusinessAddress1") + .HasColumnType("longtext"); + + b.Property("BusinessAddress2") + .HasColumnType("longtext"); + + b.Property("BusinessAddress3") + .HasColumnType("longtext"); + + b.Property("BusinessCountry") + .HasColumnType("longtext"); + + b.Property("BusinessName") + .HasColumnType("longtext"); + + b.Property("BusinessTaxNumber") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.cs b/util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.cs new file mode 100644 index 000000000..93c5c522b --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221114202829_OrganizationDomainClaim.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations; + +public partial class OrganizationDomainClaim : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "OrganizationDomain", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + OrganizationId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Txt = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + DomainName = table.Column(type: "varchar(255)", maxLength: 255, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + CreationDate = table.Column(type: "datetime(6)", nullable: false), + VerifiedDate = table.Column(type: "datetime(6)", nullable: true), + NextRunDate = table.Column(type: "datetime(6)", nullable: false), + NextRunCount = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrganizationDomain", x => x.Id); + table.ForeignKey( + name: "FK_OrganizationDomain_Organization_OrganizationId", + column: x => x.OrganizationId, + principalTable: "Organization", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_OrganizationDomain_OrganizationId", + table: "OrganizationDomain", + column: "OrganizationId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OrganizationDomain"); + } +} diff --git a/util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.Designer.cs b/util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.Designer.cs new file mode 100644 index 000000000..0d0694ef5 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.Designer.cs @@ -0,0 +1,1725 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221129004644_OrganizationDomainClaimRenameNextRunCount")] + partial class OrganizationDomainClaimRenameNextRunCount + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("varchar(25)"); + + b.Property("Approved") + .HasColumnType("tinyint(1)"); + + b.Property("AuthenticationDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MasterPasswordHash") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("RequestFingerprint") + .HasColumnType("longtext"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ResponseDate") + .HasColumnType("datetime(6)"); + + b.Property("ResponseDeviceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("GranteeId") + .HasColumnType("char(36)"); + + b.Property("GrantorId") + .HasColumnType("char(36)"); + + b.Property("KeyEncrypted") + .HasColumnType("longtext"); + + b.Property("LastNotificationDate") + .HasColumnType("datetime(6)"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("WaitTimeDays") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ActingUserId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("DeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("InstallationId") + .HasColumnType("char(36)"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("PolicyId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("ProviderOrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("SystemUser") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlanType") + .HasColumnType("tinyint unsigned"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Seats") + .HasColumnType("int"); + + b.Property("SelfHost") + .HasColumnType("tinyint(1)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("Use2fa") + .HasColumnType("tinyint(1)"); + + b.Property("UseApi") + .HasColumnType("tinyint(1)"); + + b.Property("UseDirectory") + .HasColumnType("tinyint(1)"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.Property("UseGroups") + .HasColumnType("tinyint(1)"); + + b.Property("UseKeyConnector") + .HasColumnType("tinyint(1)"); + + b.Property("UsePolicies") + .HasColumnType("tinyint(1)"); + + b.Property("UseResetPassword") + .HasColumnType("tinyint(1)"); + + b.Property("UseScim") + .HasColumnType("tinyint(1)"); + + b.Property("UseSso") + .HasColumnType("tinyint(1)"); + + b.Property("UseTotp") + .HasColumnType("tinyint(1)"); + + b.Property("UsersGetPremium") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("JobRunCount") + .HasColumnType("int"); + + b.Property("NextRunDate") + .HasColumnType("datetime(6)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Txt") + .HasColumnType("longtext"); + + b.Property("VerifiedDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasColumnType("longtext"); + + b.Property("BusinessAddress1") + .HasColumnType("longtext"); + + b.Property("BusinessAddress2") + .HasColumnType("longtext"); + + b.Property("BusinessAddress3") + .HasColumnType("longtext"); + + b.Property("BusinessCountry") + .HasColumnType("longtext"); + + b.Property("BusinessName") + .HasColumnType("longtext"); + + b.Property("BusinessTaxNumber") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.cs b/util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.cs new file mode 100644 index 000000000..a6b2f4c10 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221129004644_OrganizationDomainClaimRenameNextRunCount.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations; + +public partial class OrganizationDomainClaimRenameNextRunCount : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "NextRunCount", + table: "OrganizationDomain", + newName: "JobRunCount"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "JobRunCount", + table: "OrganizationDomain", + newName: "NextRunCount"); + } +} diff --git a/util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.Designer.cs b/util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.Designer.cs new file mode 100644 index 000000000..2a2ef90cc --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.Designer.cs @@ -0,0 +1,1731 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221209015017_EventsDomainName")] + partial class EventsDomainName + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("varchar(25)"); + + b.Property("Approved") + .HasColumnType("tinyint(1)"); + + b.Property("AuthenticationDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MasterPasswordHash") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("RequestFingerprint") + .HasColumnType("longtext"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ResponseDate") + .HasColumnType("datetime(6)"); + + b.Property("ResponseDeviceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("GranteeId") + .HasColumnType("char(36)"); + + b.Property("GrantorId") + .HasColumnType("char(36)"); + + b.Property("KeyEncrypted") + .HasColumnType("longtext"); + + b.Property("LastNotificationDate") + .HasColumnType("datetime(6)"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("WaitTimeDays") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ActingUserId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("DeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("InstallationId") + .HasColumnType("char(36)"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("PolicyId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("ProviderOrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("SystemUser") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlanType") + .HasColumnType("tinyint unsigned"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Seats") + .HasColumnType("int"); + + b.Property("SelfHost") + .HasColumnType("tinyint(1)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("Use2fa") + .HasColumnType("tinyint(1)"); + + b.Property("UseApi") + .HasColumnType("tinyint(1)"); + + b.Property("UseCustomPermissions") + .HasColumnType("tinyint(1)"); + + b.Property("UseDirectory") + .HasColumnType("tinyint(1)"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.Property("UseGroups") + .HasColumnType("tinyint(1)"); + + b.Property("UseKeyConnector") + .HasColumnType("tinyint(1)"); + + b.Property("UsePolicies") + .HasColumnType("tinyint(1)"); + + b.Property("UseResetPassword") + .HasColumnType("tinyint(1)"); + + b.Property("UseScim") + .HasColumnType("tinyint(1)"); + + b.Property("UseSso") + .HasColumnType("tinyint(1)"); + + b.Property("UseTotp") + .HasColumnType("tinyint(1)"); + + b.Property("UsersGetPremium") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("JobRunCount") + .HasColumnType("int"); + + b.Property("NextRunDate") + .HasColumnType("datetime(6)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Txt") + .HasColumnType("longtext"); + + b.Property("VerifiedDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasColumnType("longtext"); + + b.Property("BusinessAddress1") + .HasColumnType("longtext"); + + b.Property("BusinessAddress2") + .HasColumnType("longtext"); + + b.Property("BusinessAddress3") + .HasColumnType("longtext"); + + b.Property("BusinessCountry") + .HasColumnType("longtext"); + + b.Property("BusinessName") + .HasColumnType("longtext"); + + b.Property("BusinessTaxNumber") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.cs b/util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.cs new file mode 100644 index 000000000..8b006a63e --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221209015017_EventsDomainName.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations; + +public partial class EventsDomainName : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DomainName", + table: "Event", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DomainName", + table: "Event"); + } +} diff --git a/util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.Designer.cs b/util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.Designer.cs new file mode 100644 index 000000000..5dc49bb67 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.Designer.cs @@ -0,0 +1,1734 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221209192355_OrganizationDomainLastCheckedDate")] + partial class OrganizationDomainLastCheckedDate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("varchar(25)"); + + b.Property("Approved") + .HasColumnType("tinyint(1)"); + + b.Property("AuthenticationDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MasterPasswordHash") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("RequestFingerprint") + .HasColumnType("longtext"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ResponseDate") + .HasColumnType("datetime(6)"); + + b.Property("ResponseDeviceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("GranteeId") + .HasColumnType("char(36)"); + + b.Property("GrantorId") + .HasColumnType("char(36)"); + + b.Property("KeyEncrypted") + .HasColumnType("longtext"); + + b.Property("LastNotificationDate") + .HasColumnType("datetime(6)"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("WaitTimeDays") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ActingUserId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("DeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("InstallationId") + .HasColumnType("char(36)"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("PolicyId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("ProviderOrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("SystemUser") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlanType") + .HasColumnType("tinyint unsigned"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Seats") + .HasColumnType("int"); + + b.Property("SelfHost") + .HasColumnType("tinyint(1)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("Use2fa") + .HasColumnType("tinyint(1)"); + + b.Property("UseApi") + .HasColumnType("tinyint(1)"); + + b.Property("UseCustomPermissions") + .HasColumnType("tinyint(1)"); + + b.Property("UseDirectory") + .HasColumnType("tinyint(1)"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.Property("UseGroups") + .HasColumnType("tinyint(1)"); + + b.Property("UseKeyConnector") + .HasColumnType("tinyint(1)"); + + b.Property("UsePolicies") + .HasColumnType("tinyint(1)"); + + b.Property("UseResetPassword") + .HasColumnType("tinyint(1)"); + + b.Property("UseScim") + .HasColumnType("tinyint(1)"); + + b.Property("UseSso") + .HasColumnType("tinyint(1)"); + + b.Property("UseTotp") + .HasColumnType("tinyint(1)"); + + b.Property("UsersGetPremium") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("JobRunCount") + .HasColumnType("int"); + + b.Property("LastCheckedDate") + .HasColumnType("datetime(6)"); + + b.Property("NextRunDate") + .HasColumnType("datetime(6)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Txt") + .HasColumnType("longtext"); + + b.Property("VerifiedDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasColumnType("longtext"); + + b.Property("BusinessAddress1") + .HasColumnType("longtext"); + + b.Property("BusinessAddress2") + .HasColumnType("longtext"); + + b.Property("BusinessAddress3") + .HasColumnType("longtext"); + + b.Property("BusinessCountry") + .HasColumnType("longtext"); + + b.Property("BusinessName") + .HasColumnType("longtext"); + + b.Property("BusinessTaxNumber") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.cs b/util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.cs new file mode 100644 index 000000000..f6884cb5c --- /dev/null +++ b/util/MySqlMigrations/Migrations/20221209192355_OrganizationDomainLastCheckedDate.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations; + +public partial class OrganizationDomainLastCheckedDate : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastCheckedDate", + table: "OrganizationDomain", + type: "datetime(6)", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastCheckedDate", + table: "OrganizationDomain"); + } +} diff --git a/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs index 5496ae1ea..4c9aac6f5 100644 --- a/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -318,6 +318,9 @@ namespace Bit.MySqlMigrations.Migrations b.Property("DeviceType") .HasColumnType("tinyint unsigned"); + b.Property("DomainName") + .HasColumnType("longtext"); + b.Property("GroupId") .HasColumnType("char(36)"); @@ -702,6 +705,43 @@ namespace Bit.MySqlMigrations.Migrations b.ToTable("OrganizationConnection", (string)null); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("JobRunCount") + .HasColumnType("int"); + + b.Property("LastCheckedDate") + .HasColumnType("datetime(6)"); + + b.Property("NextRunDate") + .HasColumnType("datetime(6)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Txt") + .HasColumnType("longtext"); + + b.Property("VerifiedDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => { b.Property("Id") @@ -1780,6 +1820,17 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("Organization"); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") @@ -2076,6 +2127,8 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("Connections"); + b.Navigation("Domains"); + b.Navigation("Groups"); b.Navigation("OrganizationUsers"); diff --git a/util/MySqlMigrations/packages.lock.json b/util/MySqlMigrations/packages.lock.json index 996841866..209f5237d 100644 --- a/util/MySqlMigrations/packages.lock.json +++ b/util/MySqlMigrations/packages.lock.json @@ -153,6 +153,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2740,6 +2748,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/util/PostgresMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.psql b/util/PostgresMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.psql new file mode 100644 index 000000000..a493c3373 --- /dev/null +++ b/util/PostgresMigrations/HelperScripts/2022-11-03_00_OrganizationDomainClaim.psql @@ -0,0 +1,21 @@ +START TRANSACTION; + +CREATE TABLE "OrganizationDomain" ( + "Id" uuid NOT NULL, + "OrganizationId" uuid NOT NULL, + "Txt" text NULL, + "DomainName" character varying(255) NULL, + "CreationDate" timestamp with time zone NOT NULL, + "VerifiedDate" timestamp with time zone NULL, + "NextRunDate" timestamp with time zone NOT NULL, + "NextRunCount" integer NOT NULL, + CONSTRAINT "PK_OrganizationDomain" PRIMARY KEY ("Id"), + CONSTRAINT "FK_OrganizationDomain_Organization_OrganizationId" FOREIGN KEY ("OrganizationId") REFERENCES "Organization" ("Id") ON DELETE CASCADE +); + +CREATE INDEX "IX_OrganizationDomain_OrganizationId" ON "OrganizationDomain" ("OrganizationId"); + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20221108020928_OrganizationDomainClaim', '6.0.4'); + +COMMIT; \ No newline at end of file diff --git a/util/PostgresMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.psql b/util/PostgresMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.psql new file mode 100644 index 000000000..357a596a2 --- /dev/null +++ b/util/PostgresMigrations/HelperScripts/2022-11-28_00_OrganizationDomainClaimRenameNextRunCount.psql @@ -0,0 +1,8 @@ +START TRANSACTION; + +ALTER TABLE "OrganizationDomain" RENAME COLUMN "NextRunCount" TO "JobRunCount"; + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20221129032517_OrganizationDomainClaimRenameNextRunCount', '6.0.4'); + +COMMIT; \ No newline at end of file diff --git a/util/PostgresMigrations/HelperScripts/2022-12-08_00_EventsDomainName.psql b/util/PostgresMigrations/HelperScripts/2022-12-08_00_EventsDomainName.psql new file mode 100644 index 000000000..5143d998d --- /dev/null +++ b/util/PostgresMigrations/HelperScripts/2022-12-08_00_EventsDomainName.psql @@ -0,0 +1,9 @@ +START TRANSACTION; + +ALTER TABLE "Event" ADD "DomainName" text NULL; + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20221209020447_EventsDomainName', '6.0.4'); + +COMMIT; + diff --git a/util/PostgresMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.psql b/util/PostgresMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.psql new file mode 100644 index 000000000..ff099eee6 --- /dev/null +++ b/util/PostgresMigrations/HelperScripts/2022-12-09_00_OrganizationDomainLastCheckedDate.psql @@ -0,0 +1,9 @@ +START TRANSACTION; + +ALTER TABLE "OrganizationDomain" ADD "LastCheckedDate" timestamp with time zone NULL; + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20221209194623_OrganizationDomainLastCheckedDate', '6.0.4'); + +COMMIT; + diff --git a/util/PostgresMigrations/Migrations/20221025033204_PasswordlessAuthRequestAddApprovedColumn.Designer.cs b/util/PostgresMigrations/Migrations/20221025033204_PasswordlessAuthRequestAddApprovedColumn.Designer.cs index 936ab4648..478ea452e 100644 --- a/util/PostgresMigrations/Migrations/20221025033204_PasswordlessAuthRequestAddApprovedColumn.Designer.cs +++ b/util/PostgresMigrations/Migrations/20221025033204_PasswordlessAuthRequestAddApprovedColumn.Designer.cs @@ -38,10 +38,10 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("boolean"); b.Property("AuthenticationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Key") .HasColumnType("text"); @@ -67,7 +67,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(50)"); b.Property("ResponseDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("ResponseDeviceId") .HasColumnType("uuid"); @@ -96,13 +96,13 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Data") .HasColumnType("text"); b.Property("DeletedDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Favorites") .HasColumnType("text"); @@ -117,7 +117,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("smallint"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Type") .HasColumnType("smallint"); @@ -140,7 +140,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("ExternalId") .HasMaxLength(300) @@ -153,7 +153,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.HasKey("Id"); @@ -231,7 +231,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Identifier") .HasMaxLength(50) @@ -246,7 +246,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(255)"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Type") .HasColumnType("smallint"); @@ -267,7 +267,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Email") .HasMaxLength(256) @@ -283,13 +283,13 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("LastNotificationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("RecoveryInitiatedDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Status") .HasColumnType("smallint"); @@ -324,7 +324,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("Date") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("DeviceType") .HasColumnType("smallint"); @@ -374,13 +374,13 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Name") .HasColumnType("text"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("UserId") .HasColumnType("uuid"); @@ -403,10 +403,10 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(200)"); b.Property("ConsumedDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Data") .HasColumnType("text"); @@ -416,7 +416,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(200)"); b.Property("ExpirationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("SessionId") .HasMaxLength(100) @@ -444,7 +444,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("boolean"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("ExternalId") .HasMaxLength(300) @@ -458,7 +458,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.HasKey("Id"); @@ -493,7 +493,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Email") .HasMaxLength(256) @@ -545,13 +545,13 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(30)"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Enabled") .HasColumnType("boolean"); b.Property("ExpirationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Gateway") .HasColumnType("smallint"); @@ -587,7 +587,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(50)"); b.Property("OwnersNotifiedOfAutoscaling") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Plan") .HasMaxLength(50) @@ -606,7 +606,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Seats") .HasColumnType("integer"); @@ -674,7 +674,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Type") .HasColumnType("smallint"); @@ -720,7 +720,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(256)"); b.Property("LastSyncDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("OfferedToEmail") .HasMaxLength(256) @@ -742,7 +742,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("boolean"); b.Property("ValidUntil") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.HasKey("Id"); @@ -762,7 +762,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("boolean"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Email") .HasMaxLength(256) @@ -785,7 +785,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Status") .HasColumnType("smallint"); @@ -811,7 +811,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Data") .HasColumnType("text"); @@ -823,7 +823,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Type") .HasColumnType("smallint"); @@ -862,7 +862,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Enabled") .HasColumnType("boolean"); @@ -871,7 +871,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Status") .HasColumnType("smallint"); @@ -890,7 +890,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Key") .HasColumnType("text"); @@ -902,7 +902,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Settings") .HasColumnType("text"); @@ -922,7 +922,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Email") .HasColumnType("text"); @@ -937,7 +937,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Status") .HasColumnType("smallint"); @@ -966,19 +966,19 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("integer"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Data") .HasColumnType("text"); b.Property("DeletionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Disabled") .HasColumnType("boolean"); b.Property("ExpirationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("HideEmail") .HasColumnType("boolean"); @@ -997,7 +997,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(300)"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Type") .HasColumnType("smallint"); @@ -1023,7 +1023,7 @@ namespace Bit.PostgresMigrations.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Data") .HasColumnType("text"); @@ -1035,7 +1035,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.HasKey("Id"); @@ -1053,7 +1053,7 @@ namespace Bit.PostgresMigrations.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("ExternalId") .HasMaxLength(50) @@ -1113,7 +1113,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("numeric"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Details") .HasMaxLength(100) @@ -1159,7 +1159,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("uuid"); b.Property("AccountRevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("ApiKey") .IsRequired() @@ -1167,7 +1167,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("character varying(30)"); b.Property("CreationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("Culture") .HasMaxLength(10) @@ -1215,7 +1215,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("LastFailedLoginDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("LicenseKey") .HasMaxLength(100) @@ -1240,7 +1240,7 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("boolean"); b.Property("PremiumExpirationDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("PrivateKey") .HasColumnType("text"); @@ -1252,10 +1252,10 @@ namespace Bit.PostgresMigrations.Migrations .HasColumnType("text"); b.Property("RenewalReminderDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("RevisionDate") - .HasColumnType("timestamp without time zone"); + .HasColumnType("timestamp with time zone"); b.Property("SecurityStamp") .IsRequired() diff --git a/util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.Designer.cs b/util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.Designer.cs new file mode 100644 index 000000000..bf669a7fa --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.Designer.cs @@ -0,0 +1,1733 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221114192912_OrganizationDomainClaim")] + partial class OrganizationDomainClaim + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("Approved") + .HasColumnType("boolean"); + + b.Property("AuthenticationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MasterPasswordHash") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("smallint"); + + b.Property("RequestFingerprint") + .HasColumnType("text"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResponseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ResponseDeviceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp with time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("NextRunCount") + .HasColumnType("integer"); + + b.Property("NextRunDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Txt") + .HasColumnType("text"); + + b.Property("VerifiedDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.cs b/util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.cs new file mode 100644 index 000000000..c94070b19 --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221114192912_OrganizationDomainClaim.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations; + +public partial class OrganizationDomainClaim : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "OrganizationDomain", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + OrganizationId = table.Column(type: "uuid", nullable: false), + Txt = table.Column(type: "text", nullable: true), + DomainName = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + CreationDate = table.Column(type: "timestamp with time zone", nullable: false), + VerifiedDate = table.Column(type: "timestamp with time zone", nullable: true), + NextRunDate = table.Column(type: "timestamp with time zone", nullable: false), + NextRunCount = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_OrganizationDomain", x => x.Id); + table.ForeignKey( + name: "FK_OrganizationDomain_Organization_OrganizationId", + column: x => x.OrganizationId, + principalTable: "Organization", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_OrganizationDomain_OrganizationId", + table: "OrganizationDomain", + column: "OrganizationId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OrganizationDomain"); + } +} diff --git a/util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.Designer.cs b/util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.Designer.cs new file mode 100644 index 000000000..b648dde8f --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.Designer.cs @@ -0,0 +1,1736 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221129032517_OrganizationDomainClaimRenameNextRunCount")] + partial class OrganizationDomainClaimRenameNextRunCount + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("Approved") + .HasColumnType("boolean"); + + b.Property("AuthenticationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MasterPasswordHash") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("smallint"); + + b.Property("RequestFingerprint") + .HasColumnType("text"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResponseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ResponseDeviceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("SystemUser") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp with time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("JobRunCount") + .HasColumnType("integer"); + + b.Property("NextRunDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Txt") + .HasColumnType("text"); + + b.Property("VerifiedDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.cs b/util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.cs new file mode 100644 index 000000000..65f845ebe --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221129032517_OrganizationDomainClaimRenameNextRunCount.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations; + +public partial class OrganizationDomainClaimRenameNextRunCount : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "NextRunCount", + table: "OrganizationDomain", + newName: "JobRunCount"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "JobRunCount", + table: "OrganizationDomain", + newName: "NextRunCount"); + } +} diff --git a/util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.Designer.cs b/util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.Designer.cs new file mode 100644 index 000000000..5de458084 --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.Designer.cs @@ -0,0 +1,1742 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221209020447_EventsDomainName")] + partial class EventsDomainName + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("Approved") + .HasColumnType("boolean"); + + b.Property("AuthenticationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MasterPasswordHash") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("smallint"); + + b.Property("RequestFingerprint") + .HasColumnType("text"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResponseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ResponseDeviceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("DomainName") + .HasColumnType("text"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("SystemUser") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp with time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseCustomPermissions") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("JobRunCount") + .HasColumnType("integer"); + + b.Property("NextRunDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Txt") + .HasColumnType("text"); + + b.Property("VerifiedDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.cs b/util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.cs new file mode 100644 index 000000000..c5fb22bcf --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221209020447_EventsDomainName.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations; + +public partial class EventsDomainName : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DomainName", + table: "Event", + type: "text", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DomainName", + table: "Event"); + } +} diff --git a/util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.Designer.cs b/util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.Designer.cs new file mode 100644 index 000000000..a0520d308 --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.Designer.cs @@ -0,0 +1,1745 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20221209194623_OrganizationDomainLastCheckedDate")] + partial class OrganizationDomainLastCheckedDate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("Approved") + .HasColumnType("boolean"); + + b.Property("AuthenticationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MasterPasswordHash") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("smallint"); + + b.Property("RequestFingerprint") + .HasColumnType("text"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResponseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ResponseDeviceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("DomainName") + .HasColumnType("text"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("SystemUser") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp with time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseCustomPermissions") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("JobRunCount") + .HasColumnType("integer"); + + b.Property("LastCheckedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("NextRunDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Txt") + .HasColumnType("text"); + + b.Property("VerifiedDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Domains"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.cs b/util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.cs new file mode 100644 index 000000000..0c6b7c2fc --- /dev/null +++ b/util/PostgresMigrations/Migrations/20221209194623_OrganizationDomainLastCheckedDate.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations; + +public partial class OrganizationDomainLastCheckedDate : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastCheckedDate", + table: "OrganizationDomain", + type: "timestamp without time zone", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastCheckedDate", + table: "OrganizationDomain"); + } +} diff --git a/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs index d0f836c48..ae95db8f1 100644 --- a/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -322,6 +322,9 @@ namespace Bit.PostgresMigrations.Migrations b.Property("DeviceType") .HasColumnType("smallint"); + b.Property("DomainName") + .HasColumnType("text"); + b.Property("GroupId") .HasColumnType("uuid"); @@ -707,6 +710,43 @@ namespace Bit.PostgresMigrations.Migrations b.ToTable("OrganizationConnection", (string)null); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DomainName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("JobRunCount") + .HasColumnType("integer"); + + b.Property("LastCheckedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("NextRunDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Txt") + .HasColumnType("text"); + + b.Property("VerifiedDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationDomain", (string)null); + }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => { b.Property("Id") @@ -1791,6 +1831,17 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("Organization"); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationDomain", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Domains") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") @@ -2087,6 +2138,8 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("Connections"); + b.Navigation("Domains"); + b.Navigation("Groups"); b.Navigation("OrganizationUsers"); diff --git a/util/PostgresMigrations/packages.lock.json b/util/PostgresMigrations/packages.lock.json index 996841866..209f5237d 100644 --- a/util/PostgresMigrations/packages.lock.json +++ b/util/PostgresMigrations/packages.lock.json @@ -153,6 +153,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2740,6 +2748,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/util/Setup/packages.lock.json b/util/Setup/packages.lock.json index a9543d781..2dd02b8b6 100644 --- a/util/Setup/packages.lock.json +++ b/util/Setup/packages.lock.json @@ -173,6 +173,14 @@ "dbup-core": "4.5.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2619,6 +2627,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/util/SqlServerEFScaffold/packages.lock.json b/util/SqlServerEFScaffold/packages.lock.json index 63f387a6b..313559801 100644 --- a/util/SqlServerEFScaffold/packages.lock.json +++ b/util/SqlServerEFScaffold/packages.lock.json @@ -168,6 +168,14 @@ "resolved": "2.0.123", "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2822,6 +2830,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )", diff --git a/util/SqliteMigrations/packages.lock.json b/util/SqliteMigrations/packages.lock.json index 996841866..209f5237d 100644 --- a/util/SqliteMigrations/packages.lock.json +++ b/util/SqliteMigrations/packages.lock.json @@ -153,6 +153,14 @@ "System.Xml.XPath.XmlDocument": "4.3.0" } }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "2hrXR83b5g6/ZMJOA36hXp4t56yb7G1mF3Hg6IkrHxvtyaoXRn2WVdgDPN3V8+GugOlUBbTWXgPaka4dXw1QIg==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + } + }, "Fido2": { "type": "Transitive", "resolved": "3.0.1", @@ -2740,6 +2748,7 @@ "Azure.Storage.Queues": "[12.12.0, )", "BitPay.Light": "[1.0.1907, )", "Braintree": "[5.12.0, )", + "DnsClient": "[1.7.0, )", "Fido2.AspNet": "[3.0.1, )", "Handlebars.Net": "[2.1.2, )", "IdentityServer4": "[4.1.2, )",