Commit Graph

982 Commits

Author SHA1 Message Date
Rui Tomé
9e4bef5ee7 [PM-34776/PM-37797] Add invite link email domain validation endpoint (#7683)
* Add email domain validation to OrganizationInviteLink

- Introduced IsEmailDomainAllowed method to check if an email's domain is permitted based on allowed domains.
- Added necessary using directives for MailAddress and domain sanitization utilities.

* Refactor OrganizationInviteLink by removing email domain validation

- Removed the IsEmailDomainAllowed method and associated using directives for MailAddress.
- Cleaned up the code by eliminating unused methods related to email domain validation.

* Add InviteLinkDomainValidator for email domain validation

- Introduced InviteLinkDomainValidator class with IsEmailDomainAllowed method to validate if an email's domain is in the list of allowed domains.
- Utilized MailAddress for email parsing and added domain sanitization logic.

* Add email domain validation endpoint for organization invite links

- Implemented ValidateEmailDomain method in OrganizationInviteLinksController to check if an email's domain is allowed based on the invite link's permitted domains.
- Created OrganizationInviteLinkValidateEmailDomainRequestModel for request validation and OrganizationInviteLinkValidateEmailDomainResponseModel for response formatting.
- Integrated IOrganizationInviteLinkRepository to retrieve invite link details by code.

* Add unit tests for InviteLinkDomainValidator

- Created InviteLinkDomainValidatorTests class to validate email domain functionality.
- Added tests for various scenarios including invalid emails, empty domain lists, and matching domains.
- Ensured comprehensive coverage of the IsEmailDomainAllowed method's behavior.

* Add integration test for email domain validation in OrganizationInviteLinksController

- Implemented a test to validate that an allowed email domain returns the expected result when checked against an organization invite link.
- Ensured the test verifies the creation of an invite link and the subsequent validation of an email domain against the allowed domains list.

* Add validation query and interface for organization invite link email domain

- Introduced ValidateOrganizationInviteLinkEmailDomainQuery class to validate if an email's domain is allowed based on the invite link's permitted domains.
- Created IValidateOrganizationInviteLinkEmailDomainQuery interface to define the validation method.
- Added unit tests for the validation query to ensure correct behavior for various scenarios, including link not found and domain matching.

* Refactor OrganizationInviteLinksController to use validation query for email domain

- Updated ValidateEmailDomain method to utilize IValidateOrganizationInviteLinkEmailDomainQuery for domain validation instead of directly accessing the repository.
- Removed unnecessary repository dependency and streamlined the response handling for validation results.
- Registered the new validation query in OrganizationServiceCollectionExtensions for dependency injection.

* Refactor InviteLinkDomainValidator and replace MailAddress usage with existing email validation method
2026-05-29 12:23:15 +01:00
Dave
8b2cb89390 [PM-35394] MasterPasswordService Admin Console Integration (#7629)
* test(org-user-request-model): Add model validation tests.

* feat(request-models): Add Authentication and Unlock Data fields with annotations.

* test(recover-command): Add tests for Authentication and Unlock Data payload signature.

* feat(recover-command): Add overload for Authentication and Unlock Data payload signature.

* test(recover-command): Add tests for behavior with authentication and unlock data.

* feat(recover-command): Add impl for hash and key, authentication and unlock data inputs.

* test(org-users-controller): Add controller tests for dispatch.

* feat(org-users-controller): Add controller impl for dispatch for both request payload variants.

* chore: lint.

* fix(request-model): Validation method drifted in base; rename.

* test(request-model): Update validation tests.

* feat(request-model): Support 2FA-only validation at the boundary.

* test(request-model): Express handling of v1 vs v2 requests.

* PM-35394 - Per reviewer's request, mark  AdminRecoverAccountCommand.RecoverAccountAsync that doesn't accept new models obselete

* PM-35394 - Fix using directive after model namespace move

Merge from main moved OrganizationUserResetPasswordRequestModel to the
AdminConsole namespace; update the test's using directive to match,
restoring both the build and dotnet format checks.

---------

Co-authored-by: Jared Snider <jsnider@bitwarden.com>
2026-05-28 16:37:43 -04:00
Nik Gilmore
e10eb5e0fb PM-37727: Fix exceptions when serialzing blob-encrypted ciphers (#7667) 2026-05-27 16:17:55 -07:00
Ike
fa850390c4 [PM-35830] Add ChangeEmailCommand (#7650)
feat: add ChangeEmailCommand [PM-35830]

- Add ChangeEmailCommand to encapsulate core email change logic 
- Add OrganizationDomainAllowEmailChangeQuery returning OrganizationDomainAllowEmailChangeDenialReason enum so callers can branch on the specific denial reason, if any
- Surface tailored BadRequestException messages per denial reason via a switch expression that fails closed on unknown values
- Push sync-only notification (no logout)
- Add unit tests covering denial reasons, domain case invariance, and the null-customerId-with-gateway path
2026-05-27 17:06:05 -04:00
Maciej Zieniuk
c57d220e04 [PM-31191] Move KDF from Auth to KM constants (#7709)
* Move KDF from Auth to KM constants

* formatting
2026-05-27 12:00:29 -05:00
Stephon Brown
5d96a614ba [PM-37820] Update Missing Tax Logic for US Customers (#7719)
* fix(billing): guard US customers from missing tax ID warning when automatic tax flag is enabled

  US has no customer-facing VAT/Tax ID equivalent, so the warning should never appear for US customers regardless of the PM37597 flag state.

* fix(billing): fix provider warnings test asserting buggy US tax ID warning behavior
2026-05-27 11:27:13 -04:00
Rui Tomé
705995d790 [PM-25691] Create OrganizationUpdateCollectionManagementCommand (#7682)
* Implement UpdateCollectionManagementSettingsCommand and associated interface for managing organization collection settings

* Add UpdateCollectionManagementSettingsCommand to handle updates to organization collection management settings.
* Create IUpdateCollectionManagementSettingsCommand interface to define the update method.
* Implement unit tests for UpdateCollectionManagementSettingsCommand to verify event logging and exception handling.

* Add IUpdateCollectionManagementSettingsCommand to service collection

* Register IUpdateCollectionManagementSettingsCommand and its implementation, UpdateCollectionManagementSettingsCommand, in the service collection for managing organization collection settings.

* Rename command

* Update OrganizationsController to use IOrganizationUpdateCollectionManagementCommand

* Added IOrganizationUpdateCollectionManagementCommand to the OrganizationsController for managing collection settings updates.
* Updated the constructor to inject the new command and modified the PutCollectionManagement method to utilize it.
* Adjusted unit tests to reflect the changes in the command used for updating collection management settings.

* Refactor IOrganizationService and OrganizationService to remove UpdateCollectionManagementSettingsAsync method

* Removed the UpdateCollectionManagementSettingsAsync method from IOrganizationService and its implementation in OrganizationService.
* Cleaned up unused usings related to collection management settings in both service files.
* Updated unit tests to reflect the removal of the collection management settings update functionality.
2026-05-27 14:10:02 +01:00
cyprain-okeke
d07a941896 [PM-37092] feat: Add business plan migration handler to SubscriptionUpdatedHandler (#7707)
* feat(billing): add Organization.ChangePlan extension for structural plan shape

Pure helper that writes plan-derived structural columns (PlanType, Plan,
Use* capability flags, UsersGetPremium, MaxCollections) without touching
customer-purchase columns. Preserves the existing UseKeyConnector carve-out.
Behavior-preserving extraction of the field-copy block at lines 287-310
of UpgradeOrganizationPlanCommand.UpgradePlanAsync.

* refactor(billing): use Organization.ChangePlan in UpgradePlanAsync

Replaces the inline structural field-copy block with a call to the new
ChangePlan helper. Customer-purchase columns (Seats, MaxStorageGb,
Enabled, UseSecretsManager) and the PremiumAccessAddon override on
UsersGetPremium stay inline at the call site. Behavior-preserving.

* feat(billing): register Teams 2020 -> current migration paths

Appends Teams2020AnnualToCurrent (byte 3) and Teams2020MonthlyToCurrent
(byte 4) to MigrationPathId and the MigrationPaths registry. Required for
the business migration handler to resolve cohorts mapped to Teams source
plans; without these entries MigrationPaths.FromId returns null and the
handler no-ops on Teams orgs in Cohort A1. Snapshot tests updated.

* chore(billing): inject migration cohort repositories into SubscriptionUpdatedHandler

Adds IOrganizationPlanMigrationCohortRepository and
IOrganizationPlanMigrationCohortAssignmentRepository as constructor
dependencies in preparation for HandleScheduleTriggeredBusinessMigrationAsync.
No behavior change.

* feat(billing): scaffold business plan Phase-2 migration handler

Adds HandleScheduleTriggeredBusinessMigrationAsync as a sibling call in
HandleAsync's organization branch, gated on PM35215_BusinessPlanPriceMigration.
Initial implementation short-circuits when ScheduleId is null. Locks the
no-op behaviour with NoScheduleId + FeatureFlagOff tests. Full handler body
lands in subsequent commits.

* feat(billing): gate business migration handler on registered source price IDs

Builds the source-price allowlist from MigrationPaths.All, using the
seat-vs-non-seat pattern (HasNonSeatBasedPasswordManagerPlan). All four
Track A 2020 plans register automatically. Skips when the previous
subscription items don't include any registered 2020 source price.

* feat(billing): resolve cohort via assignment row for business migration handler

Reads assignment by organization id (DB is source of truth), then resolves
the cohort and migration path. Stripe subscription.Metadata['migration_cohort_id']
remains stamped by PriceIncreaseScheduler for dashboard attribution but is
not consulted by the handler. Skips with a warning when the assignment is
missing, the cohort is missing, or MigrationPathId references an unregistered
path. Idempotent: skips with info-level log when assignment.MigratedDate is
already set, before any further DB reads.

* feat(billing): defensive target-price sanity check for business migration

After resolving the target plan from cohort.MigrationPath.ToPlan, verifies
the current subscription items contain the target's PM price ID (seat-aware).
Skips with a warning on mismatch to protect against operator data errors or
off-path schedule transitions.

* feat(billing): apply plan shape and mark assignment migrated on Phase 2

Completes HandleScheduleTriggeredBusinessMigrationAsync: loads the org,
calls Organization.ChangePlan(targetPlan), persists via ReplaceAsync, and
sets assignment.MigratedDate + RevisionDate before persisting the
assignment. Happy-path coverage for all four Track A pairs (Teams +
Enterprise, monthly + annual). Teams tests assert the UseScim flip - the
load-bearing capability gain for Teams 2020 -> current.

* Add more unit test

* fix: add UTF-8 BOM to .cs files for editorconfig charset compliance

* Add exception handle

* Code refactoring

* Add more unit testing

* Resolve the pr comment
2026-05-27 10:51:44 +00:00
Stephon Brown
ee07462d28 [PM-37084] Business Aware Schedule Recovery and Cancellation (#7686)
* feat(billing): introduce unified subscription price increase scheduler API

* feat(billing): implement unified subscription price increase scheduler logic

* refactor(billing): update subscription handlers to use unified scheduler

* feat(billing): extend price migration feature flag checks

* test(billing): add and update tests for unified price increase scheduler

* fix(billing): run dotnet format

* feat(billing): expand customer and customer.discount on subscription fetch

* refactor(ReinstateSubscriptionCommandTests): rename test method for broader scope

* feat(billing): expand customer.discount in update handler

* test(billing): update test name

* feat(billing): add test clock waiting mechanism for upcoming invoices

* feat(billing): introduce cancelling user ID metadata key

* feat(billing): store cancelling user ID on subscription cancellation

* feat(billing): clear cancelling user ID on subscription reinstatement

* test(billing): update subscriber service tests for cancelling user ID

* style(SubscriberService): use 'is not null' pattern matching

* feat(SubscriberService): add PM35215 migration cohort metadata handling

* feat(SubscriberService): extend price migration deferral to PM35215

* test(SubscriberService): add and update tests for PM35215 feature

* feat(billing): Introduce OrganizationPriceIncreaseOptions

* refactor(billing): Centralize price increase eligibility in scheduler

* refactor(billing): Delegate price increase validation from UpcomingInvoiceHandler

* feat(billing): Manage price increase schedules during subscription lifecycle events

* test(billing): Update UpcomingInvoiceHandlerTests for centralized validation

* test(billing): Add PriceIncreaseScheduler tests for SkipIfAlreadyScheduled option

* test(billing): Add SubscriberService tests for price increase schedule management

* fix(billing): run dotnet format

* fix(billing): remove redundant customer expansion

* fix(billing): expand discounts for customer and subscription

* refactor(billing): Rename method to clarify dispatching role for organization scheduling

* fix(billing): Prevent clearing migration cohort metadata on cancellation

* fix(billing): Fallback to standard email when price increase migration fails

* feat(billing): improve observability for missing migration path data

* refactor(billing): simplify business plan type identification
2026-05-26 17:16:18 -04:00
Jimmy Vo
fa1397d6ff [PM-34502] Remove the IPolicyValidator pattern (#7714) 2026-05-26 14:59:34 -04:00
cyprain-okeke
81bec7cfff [PM 35227](server) Extend checkout endpoint for browser/desktop platforms (#7550)
* Implementation desktop and browser checkout

* Fixed the failing test

* Add a logger to see gobal settings in qa

* Add log

* fix the lint error

* Removed the log
2026-05-26 15:12:20 +01:00
John Harrington
0dd51376e9 [PM-36563] Send access event logs (#7679)
* added event type and control flow

* add EventType, control flow, and test coverage

* fix failing test and de-dupe enums

* access event log traps on auth and anon endpoints

* prioritize FF check in conditional statements
2026-05-26 07:09:50 -07:00
Rui Tomé
a56946fd13 [PM-37486] Remove IPolicyService and associated dead code (#7672)
* Refactor InitPendingOrganizationValidator to remove IPolicyService dependency and replace with IPolicyRequirementQuery for policy checks. Update related tests to reflect changes in policy validation logic.

* Refactor AccountsController and related validators to replace IPolicyService with IPolicyRequirementQuery for policy checks. Update tests accordingly to reflect changes in policy validation logic.

* Remove IPolicyService and related implementations from the codebase, updating PolicyServiceCollectionExtensions and deleting associated tests. This change streamlines policy management by relying on IPolicyRequirementQuery for policy checks.

* Refactor OrganizationUserRepository to remove GetByUserIdWithPolicyDetailsAsync method and associated tests.

* Remove unused stored procedures: OrganizationUser_ReadByUserIdWithPolicyDetails and PolicyDetails_ReadByUserId, as they are no longer called in the codebase.

* Remove OrganizationUserPolicyDetails class and associated test fixtures, as they are no longer needed in the codebase.

* Refactor BaseRequestValidatorTests to replace IPolicyService with IPolicyRequirementQuery for SSO validation checks. Update related test logic to ensure accurate policy validation outcomes. Clean up unused test fixtures in PolicyFixtures.cs to streamline the codebase.

* Refactor BaseRequestValidator and SsoRequestValidator to improve readability by storing policy requirement results in local variables before returning values. This change enhances code clarity while maintaining existing functionality.

* Refactor AccountsController to improve clarity by storing the result of the policy requirement query in a local variable before returning the enforced options. This change enhances code readability while preserving existing functionality.

* Revert "Remove unused stored procedures: OrganizationUser_ReadByUserIdWithPolicyDetails and PolicyDetails_ReadByUserId, as they are no longer called in the codebase."

This reverts commit 0f4fdca6e7.
2026-05-25 14:27:47 +01:00
Alex Morask
b1395aafbe [PM-37083] feat: Add per-phase price resolution to UpdateOrganizationSubscriptionCommand (#7695)
* [PM-37083] feat: Add per-phase price resolution to UpdateOrganizationSubscriptionCommand

Resolve source vs. target plan pricing per schedule phase so item changes
target the correct phase-specific price ID. Move cohort metadata onto the
schedule phases themselves to avoid Stripe normalization triggered by
direct subscription metadata updates. Filter the schedule-aware update
path to phases where EndDate > now, and drop the feature-flag gate on
PriceIncreaseScheduler.Release so schedule existence is the gate.

* Add defensive guard for source-priced single-phase migration schedules
2026-05-22 11:32:13 -05:00
rr-bw
dcf4c486b2 [PM-35401] Update exception handling in CreateAuthRequestAsync() and PostAdminRequest() (#7615)
Adds a BadRequestException case to CreateAuthRequestAsync() and PostAdminRequest().
2026-05-21 10:49:16 -07:00
renovate[bot]
c27eebbcff [deps]: Update dotnet monorepo to v10 (major) (#6634)
* [deps]: Update dotnet monorepo to v10

* fix up pins causing downgrades

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Derek Nance <dnance@bitwarden.com>
2026-05-21 11:28:32 -05:00
Rui Tomé
7180015ed6 [PM-37251] Add public invite link GET status endpoint (#7656)
* Implement GetOrganizationInviteLinkStatusQuery to retrieve invite link status

- Added GetOrganizationInviteLinkStatusQuery class to handle fetching the status of an organization invite link based on its code.
- Introduced OrganizationInviteLinkStatus and OrganizationInviteLinkSsoStatus records to encapsulate the invite link status and SSO information.
- Created IGetOrganizationInviteLinkStatusQuery interface to define the contract for the query implementation.

* Add unit tests for GetOrganizationInviteLinkStatusQuery

- Introduced comprehensive unit tests for GetOrganizationInviteLinkStatusQuery to validate various scenarios including successful retrieval of invite link status, handling of not found errors, and seat availability checks.
- Utilized Xunit and NSubstitute for testing and mocking dependencies, ensuring robust coverage of the query's functionality.

* Add IGetOrganizationInviteLinkStatusQuery to service collection

- Registered IGetOrganizationInviteLinkStatusQuery with the service collection to enable retrieval of organization invite link status.
- This addition supports the recently implemented GetOrganizationInviteLinkStatusQuery functionality.

* Add OrganizationInviteLinksPublicController and response models

- Introduced OrganizationInviteLinksPublicController to handle requests for organization invite link status.
- Implemented GetStatus endpoint to retrieve the status of an invite link using its GUID code.
- Added OrganizationInviteLinkStatusResponseModel and OrganizationInviteLinkSsoResponseModel to structure the response data for the invite link status.
- Ensured the endpoint is accessible to anonymous users while requiring application authorization for other actions.

* Add integration tests for OrganizationInviteLinksPublicController

- Introduced integration tests for OrganizationInviteLinksPublicController to validate the GetStatus endpoint functionality.
- Implemented tests to ensure correct handling of existing invite links and appropriate responses for valid and not found scenarios.
- Utilized Xunit and NSubstitute for testing and mocking dependencies, enhancing test coverage for invite link status retrieval.

* Updated GetOrganizationInviteLinkStatusQuery to return SSO status based on organization settings, including UseSso and UsePolicies

* Move status endpoint into OrganizationInviteLinksController as POST

* Refactor OrganizationInviteLinkStatusResponseModel and OrganizationInviteLinkStatus to remove OrganizationId property

- Removed OrganizationId property from both OrganizationInviteLinkStatusResponseModel and OrganizationInviteLinkStatus records to streamline the data model.
- Updated constructors accordingly to reflect the changes in the response models.

* Refactor GetOrganizationInviteLinkStatusQuery to simplify organization checks

- Updated the logic in GetOrganizationInviteLinkStatusQuery to streamline organization validation by combining null and enabled checks.
- Removed the dependency on IApplicationCacheService and adjusted the seat availability logic to enhance clarity and efficiency.
- Modified the return statement to use organization name directly instead of organization ID.

* Add integration tests for OrganizationInviteLinksController

- Introduced a new test method to validate the GetStatus functionality for existing invite links in OrganizationInviteLinksControllerTests.
- Enhanced existing tests to ensure correct responses for valid and not found scenarios.
- Removed OrganizationInviteLinksPublicControllerTests as its functionality is now covered in the OrganizationInviteLinksControllerTests.

* Refactor OrganizationInviteLinksControllerTests

- Updated test methods in OrganizationInviteLinksControllerTests to utilize GetOrganizationInviteLinkStatusRequestModel instead of individual parameters.
- Added a new test case to handle scenarios where the invite link status is not available, returning a BadRequest response.
- Enhanced existing tests to ensure consistent handling of valid and not found scenarios.

* Update GetOrganizationInviteLinkStatusQueryTests to enable organization for invite link tests
2026-05-21 16:27:54 +01:00
cyprain-okeke
761d8d055a [PM-36964] Add per-org migration cohort assignment to the Admin portal (#7681)
* [PM-36949] Add OrganizationPlanMigrationCohort schema and Core domain types

Add the foundation for cohort-based plan migrations:
- Two tables: OrganizationPlanMigrationCohort and OrganizationPlanMigrationCohortAssignment
- Two views and nine stored procedures (four CRUD on cohort, four CRUD plus
  ReadByOrganizationId on assignment)
- Single Migrator script for MSSQL deployment
- Core entities, MigrationPath value object and its registry, and bare repository
  interfaces under Bit.Core.Billing.Organizations.PlanMigration

The cohort table holds the human-managed metadata (name, discount coupons,
MigrationPathId byte) and the assignment table records each organization's
position in the migration lifecycle (scheduled, migrated, churn-mitigated).
Both Update SPs follow the accept-but-don't-assign pattern: immutable columns
(OrganizationId, CohortId, CreatedAt) are parameters but not SET clauses.

* [PM-36949] Add Dapper repositories for plan migration cohort tables

OrganizationPlanMigrationCohortRepository inherits the base Repository<T, TId>
CRUD methods unchanged. OrganizationPlanMigrationCohortAssignmentRepository
also relies on the base for CRUD and adds GetByOrganizationIdAsync which
returns at most one row (the UNIQUE constraint on OrganizationId at the
database layer guarantees this).

* [PM-36949] Add EF Core configurations, repositories, and provider migrations for plan migration cohort tables

- EF models wrap the Core entities; the assignment model exposes nav properties
  for Organization and Cohort so the FK + cascade-delete is inferred by EF.
- EntityTypeConfiguration classes pin ID generation to application code
  (ValueGeneratedNever) and declare the UNIQUE indexes plus the composite
  (CohortId, ScheduledAt, MigratedAt) index.
- Repositories follow the OrganizationInstallationRepository template; the
  assignment repo adds GetByOrganizationIdAsync to mirror the SP exposed on
  the MSSQL side.
- DatabaseContext gets two DbSet properties; auto-discovery picks up the
  configuration classes.
- Generated migrations for MySQL, Postgres, and SQLite create matching schemas;
  EF truncates FK and index names on providers with 64-char identifier limits,
  which is consistent with the rest of the codebase.

* [PM-36949] Wire up DI and add tests for plan migration cohort repositories

Register both Dapper and EF Core repositories in their respective service
collection extensions, following the existing AddSingleton convention in
these files.

Add tests:
- MigrationPathIdsSnapshotTests guards the immortal byte IDs that downstream
  code pins on. The class- and method-level comments document why these
  values can never be renumbered.
- MigrationPathTests covers the FromId round-trip and the null-on-unknown
  behavior the registry promises to callers.
- OrganizationPlanMigrationCohortRepositoryTests exercises CRUD, the UNIQUE
  Name constraint, and verifies that ReplaceAsync ignores CreatedAt
  mutations (per the accept-but-don't-assign Update SP).
- OrganizationPlanMigrationCohortAssignmentRepositoryTests exercises CRUD,
  GetByOrganizationIdAsync, the UNIQUE OrganizationId constraint,
  cascade-delete from both Organization and Cohort, and verifies that
  ReplaceAsync ignores OrganizationId, CohortId, and CreatedAt mutations.

* [PM-36949] Use PlanType and MigrationPathId enums on MigrationPath

Replace the byte Id with a byte-backed MigrationPathId enum and replace
the string FromPlan/ToPlan fields with PlanType. Persistence is
unchanged -- EF normalises enum-backed properties to their underlying
type in the model snapshot, and Dapper handles enum-to-byte parameter
mapping automatically.

* [PM-36949] Add *.lscache to .gitignore

* [PM-36949] fix: Override ReplaceAsync on EF cohort repositories for immutability parity

The Dapper _Update SPs accept-but-don't-assign certain columns (CreatedAt
on cohort; OrganizationId, CohortId, and CreatedAt on assignment), but
the base EF Repository<T,TEntity,Guid>.ReplaceAsync uses SetValues which
writes every scalar. Override on both repos and mark the immutable
properties as IsModified = false so MySQL/Postgres/Sqlite match MSSQL
behavior. Mirrors the existing DeviceRepository.ReplaceAsync pattern.

* [PM-36949] fix: Bound cohort string columns and widen Name to 255 chars

Add [MaxLength] attributes to the three cohort string properties so the
EF providers (MySQL/Postgres/Sqlite) enforce the same limits as MSSQL,
where the columns were already NVARCHAR-capped. Widen Name from 64 to
255 chars across MSSQL DDL, both _Create/_Update SP signatures, the
Migrator script, the entity, and all three regenerated EF migrations.
Coupon codes stay at 64 (Stripe IDs are short).

* [PM-36949] test: Lock FromPlan and ToPlan per MigrationPath

The snapshot test class doc says "byte N means a specific FromPlan ->
ToPlan transition forever", but only the byte value was being asserted.
A silent refactor of the registry's PlanType references would not have
been caught. Add per-path FromPlan/ToPlan assertions to close the gap.

* [PM-36949] chore: Apply dotnet format

* [PM-36949] test: Use LaxDateTimeComparer for round-tripped DateTimes

Postgres timestamp and MySQL datetime(6) store microsecond precision (6
fractional digits), but .NET DateTime is 100ns ticks (7 digits). Exact
Assert.Equal fails by a single tick on round-trip. Switch the three
DateTime comparisons in ReplaceAsync_UpdatesMutableColumns_AndIgnoresImmutableOnes
to LaxDateTimeComparer.Default -- the same 2ms-tolerance comparer used
by SendRepositoryTests and InstallationRepositoryTests for the same
precision issue.

* Add implementation for dropdown

* Reconcile dropdown work with renamed PM-36949 schema

After merging origin/main, the cohort schema now uses *Date suffixes
(ScheduledDate / MigratedDate / ChurnDiscountAppliedDate / CreationDate).
Rename references in the dropdown work, restore IsLocked() on the merged
entity, and re-add GetManyAsync() to the cohort repository (interface +
Dapper + EF) since the merge took main's pre-dropdown versions.

Also remove the six superseded provider migration files (20260515*) -- the
20260518* renames from origin/main are now the only cohort migrations.

* Fix UTF-8 BOM on cohort assignment unit test file

* Resolve the FF and permission issue

* Extract migration cohort resolution into a helper

Addresses PR feedback to keep the Edit action focused: the cohort
resolution/validation now lives in ResolveMigrationCohortAssignmentChangeAsync
and returns a MigrationCohortAssignmentChange record. The endpoint still
owns the page return.

---------

Co-authored-by: Alex Morask <amorask@bitwarden.com>
Co-authored-by: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com>
2026-05-21 15:17:00 +01:00
Jared McCannon
acf0c48a00 [PM-37259] - Update Sso Request Validator (#7676)
* Updated SsoRequestValidator to leverage OrgId from req

* Undoing unrelated change

* Updating tests. Removed unused query and tests. Updated SsoRequestValidator to leverage OrgId and retain multiple match hardening.

* updated xml. updated ssoorgids to orgids

* fixing some issues
2026-05-21 08:16:57 -05:00
Jimmy Vo
8540c6f0c1 [PM-36678] Add custom user check (#7675) 2026-05-20 14:38:34 -04:00
Alex Morask
34d4b6b3f6 [PM-37068] feat: Add business plan cohort branch to UpcomingInvoiceHandler (#7678)
* [PM-37068] feat: Add business plan cohort branch to UpcomingInvoiceHandler

Wires the caller side of the Teams/Enterprise 2020 → current price
migration. AlignOrganizationSubscriptionConcernsAsync becomes a
ProductTier dispatcher; the new business branch loads the cohort
assignment, runs eligibility guards (assignment unscheduled, cohort
active, org PlanType matches cohort source), and invokes PM-37064's
ScheduleBusinessPriceIncrease. The renewal email is a placeholder until
PM-37070 lands.

Also expands subscriptions.data.customer on the customer load so
PM-37064 can preserve customer-level discounts into Phase 2.

Incidentally strips pre-existing #region markers in
UpcomingInvoiceHandlerTests.cs per the no-regions rule.

* Apply review feedback: gate FF in handler, split MigrationPath checks, silence scheduler churn-only warning

* Add cohort metadata to subscription on migration schedule

---------

Co-authored-by: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com>
2026-05-20 11:40:50 -05:00
Dave
25e78ceba3 [PM-35393] MasterPasswordService auth integration (#7575)
* feat(mp-service) Wire commands to MasterPasswordService.

* feat(self-service) Add logout-and-log to self-service command.

* feat(mp-service) Add dual-path request models and wire controller
routing.

Add structured cryptographic data support to all Auth password endpoints,
routing new payloads to MasterPasswordService-backed commands while
preserving legacy paths for backward compatibility (PM-33141 removal).

* refactor(mp-service) Mark legacy password entry points [Obsolete].

* test(mp-service) Add testing.

* refactor(mp-service) Rename ReplaceTemporaryPasswordAsync to be more descriptive.

* refactor(mp-service) Add variant validator and tests.

* fix(mp-service) Adjust payload variance validation.

* test(mp-service) Update integration tests to support payload variants and model validation returns.

* fix(password-request): Restore KDF regression guard.

* refactor(data-models): Collapse RequestHasNewDataTypes into local check.

* test(emergency-access): Update Emergency Access tests.

* refactor(mp-payload-variant-validator): Move to Auth utilities.

* test(self-service): Combine side-effects and password change into single test.

* feat(validation): Add kdf-salt agreement-only validation.

* refactor(password-request-model): consolidate onto ValidateKdfAndSaltAgreement.

* test(auth): Cover ValidateKdfAndSaltAgreement and enshrine legacy KDF acceptance.

* feat(validate-exclusivity): Throw on both payload variants present.

* test(accounts-controller): Update tests for exclusivity validation at the boundary.

* fix(request-models): Request models must accept both payload variants.

* PM-35393 - Add V2 dual-payload integration tests for password-modification flows

End-to-end coverage for the new AuthenticationData / UnlockData payload
across every endpoint that mutates a master password:

- POST /accounts/password — legacy-KDF acceptance, mismatch rejection,
  auth, current-password check.
- PUT /accounts/update-temp-password — legacy-KDF acceptance, mismatch
  rejection, auth, ForcePasswordReset precondition.
- PUT /accounts/update-tde-offboarding-password — sub-minimum KDF
  rejection (this flow intentionally enforces range), mismatch rejection,
  auth.
- POST /emergency-access/{id}/password — legacy-KDF acceptance, mismatch
  rejection, no-payload rejection, non-RecoveryApproved precondition.

Also extracts BuildAuthData / BuildUnlockData / BuildMismatchedAuthAndUnlock
helpers in AccountsControllerTest and rewrites the existing PostKdf_* tests
to use them (no behavior change).

15 new test methods, 41 cases. 155/155 controller-suite tests pass.

---------

Co-authored-by: Jared Snider <jsnider@bitwarden.com>
Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>
2026-05-20 12:28:30 -04:00
Stephon Brown
779320aabe [PM-37598] Update Tax Id Warning Logic with Feature Flag (#7677)
* feat(billing): inject feature service into billing warning queries

* test(billing): add provider tax warning tests for automatic tax flag

* test(billing): add organization tax warning tests for automatic tax flag

* feat(billing): modify provider tax id warning based on automatic tax feature flag

* feat(billing): modify organization tax id warning based on automatic tax feature flag

* refactor(billing): clean up unused usings and file encoding

* test(billing): add tax id verification warnings for providers

* test(billing): add tax id verification warnings for organizations
2026-05-20 10:02:51 -04:00
Alex Morask
466bf01148 [PM-37064] feat: Add ScheduleBusinessPriceIncrease scheduler entry point (#7665)
* [PM-37064] feat: Add ScheduleBusinessPriceIncrease scheduler entry point

Extends PriceIncreaseScheduler (PM-32645) with a parallel entry point for
Teams/Enterprise 2020 → current plan migrations under epic PM-35215. The
business path consumes a cohort directly, preserves existing discounts,
optionally appends the cohort's proactive coupon, and stamps ScheduledDate
on the assignment row on success.

Existing Schedule renames to SchedulePersonalPriceIncrease across four
call sites; ResolvePhase2Async becomes private. Shared concerns extract
into ActiveScheduleExistsAsync and CreateAndConfigureScheduleAsync helpers.

ScheduleBusinessPriceIncrease has zero production callers — the
UpcomingInvoiceHandler dispatcher branch lands in a follow-up. The new
PM35215_BusinessPlanPriceMigration feature flag defaults off.

* Address PR review: prevent orphan schedules and fix Release flag gate
2026-05-19 14:14:30 -05:00
Stephon Brown
e5419a7662 [PM-37597] Set Automatic Tax and Prevent Tax Exempt Mutations (#7662)
* feat(billing): add feature flag for automatic tax enforcement

* refactor(billing): remove unused SubscriptionUpdateOptionsExtensions

* refactor(billing): inject IFeatureService into billing services and commands

* feat(billing): conditionalize customer tax exemption logic with feature flag

* feat(billing): conditionally enable Stripe automatic tax in OrganizationBillingService

* test(billing): add unit tests for Stripe automatic tax feature flag

* fix(billing): Run dotnet format

* test(Premium): use class-level IFeatureService mock in UpgradePremiumToOrganizationCommandTests

* refactor(billing): consolidate customer return conditions for automatic tax

* refactor(billing): broaden postal code validation for organization creation

* refactor(billing): remove PM37597 feature flag for automatic tax logic

* Revert "refactor(billing): broaden postal code validation for organization creation"

This reverts commit cddbda838c.

* fix(test): remove outdated test
2026-05-19 13:18:06 -05:00
Alex Morask
d009a52f43 [PM-36949] feat: Add OrganizationPlanMigrationCohort and Assignment tables with bare repositories (#7644)
* [PM-36949] Add OrganizationPlanMigrationCohort schema and Core domain types

Add the foundation for cohort-based plan migrations:
- Two tables: OrganizationPlanMigrationCohort and OrganizationPlanMigrationCohortAssignment
- Two views and nine stored procedures (four CRUD on cohort, four CRUD plus
  ReadByOrganizationId on assignment)
- Single Migrator script for MSSQL deployment
- Core entities, MigrationPath value object and its registry, and bare repository
  interfaces under Bit.Core.Billing.Organizations.PlanMigration

The cohort table holds the human-managed metadata (name, discount coupons,
MigrationPathId byte) and the assignment table records each organization's
position in the migration lifecycle (scheduled, migrated, churn-mitigated).
Both Update SPs follow the accept-but-don't-assign pattern: immutable columns
(OrganizationId, CohortId, CreatedAt) are parameters but not SET clauses.

* [PM-36949] Add Dapper repositories for plan migration cohort tables

OrganizationPlanMigrationCohortRepository inherits the base Repository<T, TId>
CRUD methods unchanged. OrganizationPlanMigrationCohortAssignmentRepository
also relies on the base for CRUD and adds GetByOrganizationIdAsync which
returns at most one row (the UNIQUE constraint on OrganizationId at the
database layer guarantees this).

* [PM-36949] Add EF Core configurations, repositories, and provider migrations for plan migration cohort tables

- EF models wrap the Core entities; the assignment model exposes nav properties
  for Organization and Cohort so the FK + cascade-delete is inferred by EF.
- EntityTypeConfiguration classes pin ID generation to application code
  (ValueGeneratedNever) and declare the UNIQUE indexes plus the composite
  (CohortId, ScheduledAt, MigratedAt) index.
- Repositories follow the OrganizationInstallationRepository template; the
  assignment repo adds GetByOrganizationIdAsync to mirror the SP exposed on
  the MSSQL side.
- DatabaseContext gets two DbSet properties; auto-discovery picks up the
  configuration classes.
- Generated migrations for MySQL, Postgres, and SQLite create matching schemas;
  EF truncates FK and index names on providers with 64-char identifier limits,
  which is consistent with the rest of the codebase.

* [PM-36949] Wire up DI and add tests for plan migration cohort repositories

Register both Dapper and EF Core repositories in their respective service
collection extensions, following the existing AddSingleton convention in
these files.

Add tests:
- MigrationPathIdsSnapshotTests guards the immortal byte IDs that downstream
  code pins on. The class- and method-level comments document why these
  values can never be renumbered.
- MigrationPathTests covers the FromId round-trip and the null-on-unknown
  behavior the registry promises to callers.
- OrganizationPlanMigrationCohortRepositoryTests exercises CRUD, the UNIQUE
  Name constraint, and verifies that ReplaceAsync ignores CreatedAt
  mutations (per the accept-but-don't-assign Update SP).
- OrganizationPlanMigrationCohortAssignmentRepositoryTests exercises CRUD,
  GetByOrganizationIdAsync, the UNIQUE OrganizationId constraint,
  cascade-delete from both Organization and Cohort, and verifies that
  ReplaceAsync ignores OrganizationId, CohortId, and CreatedAt mutations.

* [PM-36949] Use PlanType and MigrationPathId enums on MigrationPath

Replace the byte Id with a byte-backed MigrationPathId enum and replace
the string FromPlan/ToPlan fields with PlanType. Persistence is
unchanged -- EF normalises enum-backed properties to their underlying
type in the model snapshot, and Dapper handles enum-to-byte parameter
mapping automatically.

* [PM-36949] Add *.lscache to .gitignore

* [PM-36949] fix: Override ReplaceAsync on EF cohort repositories for immutability parity

The Dapper _Update SPs accept-but-don't-assign certain columns (CreatedAt
on cohort; OrganizationId, CohortId, and CreatedAt on assignment), but
the base EF Repository<T,TEntity,Guid>.ReplaceAsync uses SetValues which
writes every scalar. Override on both repos and mark the immutable
properties as IsModified = false so MySQL/Postgres/Sqlite match MSSQL
behavior. Mirrors the existing DeviceRepository.ReplaceAsync pattern.

* [PM-36949] fix: Bound cohort string columns and widen Name to 255 chars

Add [MaxLength] attributes to the three cohort string properties so the
EF providers (MySQL/Postgres/Sqlite) enforce the same limits as MSSQL,
where the columns were already NVARCHAR-capped. Widen Name from 64 to
255 chars across MSSQL DDL, both _Create/_Update SP signatures, the
Migrator script, the entity, and all three regenerated EF migrations.
Coupon codes stay at 64 (Stripe IDs are short).

* [PM-36949] test: Lock FromPlan and ToPlan per MigrationPath

The snapshot test class doc says "byte N means a specific FromPlan ->
ToPlan transition forever", but only the byte value was being asserted.
A silent refactor of the registry's PlanType references would not have
been caught. Add per-path FromPlan/ToPlan assertions to close the gap.

* [PM-36949] chore: Apply dotnet format

* [PM-36949] test: Use LaxDateTimeComparer for round-tripped DateTimes

Postgres timestamp and MySQL datetime(6) store microsecond precision (6
fractional digits), but .NET DateTime is 100ns ticks (7 digits). Exact
Assert.Equal fails by a single tick on round-trip. Switch the three
DateTime comparisons in ReplaceAsync_UpdatesMutableColumns_AndIgnoresImmutableOnes
to LaxDateTimeComparer.Default -- the same 2ms-tolerance comparer used
by SendRepositoryTests and InstallationRepositoryTests for the same
precision issue.

* [PM-36949] refactor: Rename DateTime columns to Date suffix per naming convention

Addresses PR review feedback. Also tightens DATETIME2(7) / NVARCHAR(N) spacing
per the SQL style guide, drops *.lscache from .gitignore (handled by #7648),
and regenerates EF migrations for MySQL, Postgres, and SQLite.

* Apply dotnet format to regenerated migrations

* [PM-36949] chore: Align NULL/NOT NULL columns in cohort tables
2026-05-18 12:34:55 -05:00
Stephon Brown
4224933c62 [PM-35357] Update Trial Length Parameter (#7597)
* test(billing): Add unit tests for TrialInitiationCache

* feat(billing): Add trial initiation cache interface and implementation

* feat(billing): Register trial initiation cache services

* feat(core): Add trial properties to OrganizationSignup model

* feat(mail): Update trial verification email model and services for TrialInitiationId

* feat(billing): Enhance TrialSendVerificationEmailRequestModel validation

* test(billing): Add tests for TrialSendVerificationEmailRequestModel validation

* feat(billing): Introduce default trial length constant

* refactor(identity): Use constant for default trial length in AccountsController

* test(identity): Update accounts controller tests for default trial length constant

* feat(billing): Integrate trial initiation into email sending command

* feat(billing): Add TrialLength to SubscriptionSetup model

* feat(billing): Map TrialLength in OrganizationSale creation

* feat(billing): Allow custom trial length in organization billing service

* feat(admin-console): Add TrialLength and TrialInitiationId to organization creation requests

* feat(admin-console): Validate trial length during cloud organization signup

* test(admin-console): Add tests for organization create request trial properties

* test(admin-console): Add tests for CloudOrganizationSignUpCommand trial length validation

* refactor(TrialInitiationCache): change validation method to retrieval

* test(TrialInitiationCache): update tests for GetAndRemoveAsync

* feat(OrganizationSignUp): refactor trial validation to command

* test(OrganizationSignUp): add trial validation scenarios

* test(OrganizationSignUp): nullify TrialLength in unrelated tests

* fix(billing): dotnet format

* refactor: remove `TrialInitiationId` property from data models
refactor: update mail service interfaces and implementations

* refactor: remove `ITrialInitiationCache` infrastructure
test: update `CloudOrganizationSignUpCommandTests` for trial validation

* refactor: update `SendTrialInitiationEmailForRegistrationCommand`

* refactor: update `CloudOrganizationSignUpCommand` trial length validation

* test(organization): fix plan call in tests

* test(billing): fix test settings
2026-05-18 09:32:04 -04:00
Mike Amirault
85dc94a15e [PM-32743] Add ability to create folders during import to orgs (#7568)
* [PM-32743] Add ability to create folders during import to orgs

* Address PR comments

* Fix tests and lint

* Address AI review comments
2026-05-15 14:02:30 -07:00
John Harrington
d5bd9f3e63 Send creation logging (#7602) 2026-05-15 07:28:17 -07:00
Jared Snider
450159a1e2 Auth/PM-37166 - Devices - add client version (#7632)
* PM-37166 - Add ClientVersion to Device entity and repository contract

* PM-37166 - Add ClientVersion SQL schema and refactor bump stored procedures

* PM-37166 - Implement combined bump in repositories and add EF migrations

EF snapshot regeneration also absorbs Collection / CollectionGroup /
CollectionUser namespace moves (Bit.Infrastructure.EntityFramework.Models
-> Bit.Infrastructure.EntityFramework.AdminConsole.Models) that were left
un-regenerated by PR #7523 (PM-35489). Namespace-only, no SQL impact;
flagged with the AC team for awareness.

* PM-37166 - Replace DeviceLastActivityCacheService with DeviceDataCacheService

* PM-37166 - Replace BumpDeviceLastActivityDateCommand with BumpDeviceDataCommand

* PM-37166 - Pass ClientVersion through identity request validators

* PM-37166 - Align migration script with SQL style guide

Refresh Device_ReadBy* sprocs after DeviceView change so their cached
schema picks up ClientVersion, swap retired-sproc drops to
DROP PROCEDURE IF EXISTS, and tighten the ALTER TABLE indent in step 1.

* PM-37166 - Rename BumpData to UpdateLastActivity across device write pathway

The "BumpData" naming was vague — "data" named a category, not the thing
being written. Rename to "UpdateLastActivity" everywhere: SP, repositories,
command, cache, validators, tests. "Last activity" names the event of the
device's most recent appearance; LastActivityDate (when) and ClientVersion
(what was running) are facts we observed about that event. ClientVersion is
treated as a property of the activity event rather than an independent value,
so future last-observed properties (last IP, OS, etc.) slot in without renaming.

The SQL layer uses Update* per architect guidance on bitwarden/server#7302;
the Bump* SPs in this codebase are legacy and not being extended. The
extensibility note lives on IUpdateDeviceLastActivityCommand with short
pointers from the SP, repo, and cache.

Cache key prefix changes from device:data: to device:last-activity: — safe
because the cache is only a write-suppression optimization (SP guards ensure
correctness) and entries TTL out within 24h.

Migration renamed to 2026-05-14 to reflect the rewrite.

* PM-37166 - Add UTF-8 BOM to device last activity cache files

Aligns file encoding with the repo's .editorconfig (charset = utf-8-bom for .cs) so dotnet format --verify-no-changes passes.

* PM-37166 - Compare LastActivityDate at second precision in device creation test

GetManyByUserIdWithDeviceAuth_ReturnsLastActivityDate_ForNewDeviceAsync was
flaking on SqlServer: Dapper binds DateTime params as legacy `datetime`
(~3.33ms granularity), so the entity initializer's UtcNow can be rounded a
few ms earlier than the in-memory `beforeCreation` capture, making a strict
>= comparison occasionally false. Truncate both sides to the second to
absorb that drift while still rejecting stale or defaulted values.

* PM-37166 - Rename Device.ClientVersion EF migration

Renames migration class/files from AddDeviceClientVersionRefactorDeviceDataBump
to AddDeviceClientVersion to drop stale "Bump" terminology and the misleading
"RefactorDeviceData" prefix. The EF migration only adds the ClientVersion
column; the BumpData -> UpdateLastActivity SP refactor lives in MSSQL .sql
files and has no EF representation.

* PM-37166 - Document null-is-no-op semantics for ClientVersion on IUpdateDeviceLastActivityCommand

Tighten the interface-level summary and add a <param> note clarifying that
a null clientVersion is treated as "no opinion" and will not clear an
existing stored value.

* PM-37166 - Regenerate Device.ClientVersion EF migration on post-#7634 baseline

PR #7634 merged AddLastApiKeyRotationDateToUserTable into main while this
branch was open. The prior AddDeviceClientVersion migration's frozen model
snapshot (its .Designer.cs) was generated before that PR landed, so it did
not include User.LastApiKeyRotationDate. Applying migrations incrementally
against that stale snapshot would produce an inconsistent model graph.

Regenerated AddDeviceClientVersion on top of the merged-from-main baseline
so the new .Designer.cs files include both columns. The migration body
itself still only adds Device.ClientVersion; the top-level
DatabaseContextModelSnapshot.cs files were already correct from git's
three-way merge.

New timestamps (20260514192xxx) come after the User migration
(20260514011xxx), preserving migration order.

* PM-37166 - util/Migrator/DbScripts/2026-05-14_00_AddDeviceClientVersionAndUpdateLastActivitySp.sql - fix wrong comment

* PM-37166 - Bump Device.ClientVersion column width from 20 to 43

43 is the upper bound of Version.ToString() for any input parseable by
Version.TryParse — four Int32 components (Int32.MaxValue = 10 digits)
joined by 3 dots. Sizing to the type's mathematical max prevents
SQL Server error 8152 on malformed/hostile Bitwarden-Client-Version
headers without paying the cost of normalization at the call sites.

Real Bitwarden CalVer (YYYY.M.B) remains well within bounds at ~9 chars.

- Device.cs [MaxLength] + entity doc comment
- SSDT table + 4 stored procedures
- Cloud migration ALTER TABLE + SP parameters
- EF migrations regenerated for MySQL / Postgres / SQLite

* PM-37166 - Defer dropping old single-column UpdateLastActivityDate SPs to follow-up

Server and DB deploys are decoupled, so dropping the old SPs in the same migration that
introduces the new combined ones would break server rollback. Per discussion on PR #7632:

- Remove DROP PROCEDURE statements from the migration; replace with a note explaining the deferral.
- Restore the old Device_UpdateLastActivityDate{ById,ByIdentifierUserId}.sql files in src/Sql/dbo
  so the SSDT source-of-truth stays aligned with deployed schema (EDD).

A follow-up ticket will drop the old SPs and delete the .sql files together once we're
confident no deployed server version still calls them.

* PM-37166 - Pass @LastActivityDate into Device_UpdateLastActivity SPs

Bitwarden convention is to compute timestamps in the application layer
and pass them as DATETIME2(7) params, not call GETUTCDATE() inside SPs.
Dapper repo now computes DateTime.UtcNow locally (matching the EF repo
and UserRepository.cs precedent) and passes LastActivityDate through.
2026-05-14 20:22:13 -04:00
Jared Snider
f3e4f5cd4e Auth/PM-37165 - Add Last API Key Rotated Date to User (#7634)
* PM-37165 - Add LastApiKeyRotationDate column to User

Adds a nullable DATETIME2(7) LastApiKeyRotationDate column on the User
table alongside the other Last*Date audit columns. Covers the MSSQL
table, view, User_Create / User_Update stored procedures (new optional
parameter, EDD-safe with default NULL), the SSDT source-of-truth, and
EF migrations for MySql, Postgres, and Sqlite.

Repository round-trip integration tests verify that CreateAsync
defaults the column to NULL and ReplaceAsync persists it across all
four providers.

* PM-37165 - Add RotateUserApiKeyCommand under Auth/UserFeatures

Extracts user API key rotation out of UserService into a new CQS
command at src/Core/Auth/UserFeatures/UserApiKey/, mirroring the
existing decomposition pattern for other Auth user features. The
command generates a new 30-char ApiKey, bumps RevisionDate, sets
LastApiKeyRotationDate, and persists via IUserRepository.ReplaceAsync.

Adds the PM37165_RotateUserApiKeyCommand feature flag so the new path
can be rolled out behind a flag in a follow-up commit. Registers the
command via AddUserApiKeyCommands inside AddUserServices.

Unit tests verify the command assigns a fresh key, updates both
RevisionDate and LastApiKeyRotationDate to the same recent UTC value,
and calls ReplaceAsync exactly once.

* PM-37165 - Flag-gate rotate-api-key endpoint to new command

Wires AccountsController.RotateApiKey to dispatch between
IRotateUserApiKeyCommand (flag on) and the legacy
UserService.RotateApiKeyAsync (flag off) based on
PM37165_RotateUserApiKeyCommand. Both paths preserve the existing
auth and secret-verification guards, which run before the flag
branch.

Marks IUserService.RotateApiKeyAsync and its implementation [Obsolete]
pointing callers at IRotateUserApiKeyCommand, with TODOs tying their
removal to the flag cleanup. The body of the legacy method is
deliberately unchanged so it does NOT write LastApiKeyRotationDate
while the flag is off; that genuinely gates the new behavior so the
ramp is observable and reversible. The single remaining call site
(the controller fallback) is wrapped in #pragma warning disable
CS0618 so the attribute continues to flag any new callers.

Tests:
- AccountsControllerTests: dispatch tests for both flag states; the
  auth and bad-secret guard tests are parameterized over flag state.
  Pre-existing typo in two tests that called _sut.ApiKey() instead of
  _sut.RotateApiKey() is fixed.
- UserServiceTests: regression test locks in the legacy non-write
  behavior so it cannot drift before the flag is removed.
- AccountsControllerTest (integration): three endpoint tests cover
  flag-off (LastApiKeyRotationDate stays NULL), flag-on (column is
  populated), and bad-secret over both flag states (no rotation
  occurs).

Each flag-state-specific test carries a TODO breadcrumb describing
the exact rename or deletion when the flag is cleaned up.

* PM-37165 - Tweak comment

* PM-37165 - Move LastApiKeyRotationDate to end of User schema

Append the new column to the end of User.sql, UserView.sql, the
matching CREATE OR ALTER VIEW in the migrator script, and the User
entity so SSDT mirrors what ALTER TABLE ADD produces in production.
2026-05-14 14:31:16 -04:00
cyprain-okeke
b0dd1c9d16 [PM 34174]Do not show renewal reminder banners to exempt organizations (#7483)
* expose the ExemptFromBillingAutomation to client

* Fix the failing database

* Rename the file to resolve chronological order error

* Renamed the migration file name

* fix the failing database

* Suppress warnings for exempt orgs at the query level

Gate InactiveSubscription and ResellerRenewal warnings inside
GetOrganizationWarningsQuery on Organization.ExemptFromBillingAutomation
instead of plumbing the field through the profile response, view models,
EF queries, and SQL views.

* Add the ExemptFromBillingAutomation property

---------

Co-authored-by: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com>
2026-05-14 18:22:08 +01:00
Maciej Zieniuk
9548272fce Allow key rotation for Key Connector users (#7618) 2026-05-14 18:46:34 +02:00
Alex Morask
316f7cdc6c [PM-36613] Void open invoices for unpaid subscriptions (#7589)
* fix(billing): void open invoices when subscription is deleted

* refactor(billing): gate invoice voiding on subscription deletion

* feat(billing): clear pending unpaid cancellation on subscriber re-enable

* feat(billing): schedule unpaid cancellation on subscriber disable

* fix(billing): respect subscription test clock when scheduling cancellation
2026-05-12 21:29:57 +00:00
Vijay Oommen
a26afd1813 PM-34680 serialize values to prevent injection (#7593) 2026-05-12 13:33:28 -05:00
Graham Walker
d905e821b9 PM-31923 adding the whole report endpoints v2 (#7228)
* PM-31923 adding the whole report endpoints v2

* PM-31923 changing approach to match others in codebase

* 31923 updating code to now use the ReportFile field

* add feature flag for welcome dialog no ext prompt (#7144)

* [PM-32249] Allow custom desktop protocol in CORS (#7080)

* Disabling Claude attribution (#7146)

* [PM-33140] Correct Non-Seat Plan Intial Seat Setting for Upgrade (#7140)

* refactor(billing): update seat logic

* test(billing): update tests for seat logic

* [PM-28531] Remove old proc and use new one (#7110)

* Update PoliciesController.Put to forward all behavior to VNext (#7130)

* PM-31923 adding request size attributes

* [deps]: Update actions/checkout action to v6.0.2 (#6904)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Return WebAuthn credential record in create response (#7145)

* Return WebAuthn credential record in create response

* Make CreateWebAuthnLoginCredentialCommand null-safe

* [PM-32594] Add authorization to admin-initiated sponsorship endpoints (#7095)

* [PM-28519] Remove Emergency Access Contacts for AutoConfirm Org Flows (#7123)

* Remove emergency access from all organization users on policy enable, or when accepted/restored

* Use correct policy save system

* Add additional tests

* Implement both PreUpsert and OnSave side effects

* Add coupon support to invoice preview and subscription creation (#6994)

* Add coupon support to invoice preview and subscription creation

* Fix the build lint error

* Resolve the initial review comments

* fix  the failing test

* fix the build lint error

* Fix the failing test

* Resolve the unaddressed issues

* Fixed the deconstruction error

* Fix the lint issue

* Fix the lint error

* Fix the lint error

* Fix the build lint error

* lint error resolved

* remove the setting file

* rename the variable name  validatedCoupon

* Remove the owner property

* Update OrganizationBillingService tests to align with recent refactoring

- Remove GetMetadata tests as method no longer exists
- Remove Owner property references from OrganizationSale (removed in d7613365ed)
- Update coupon validation to use SubscriptionDiscountRepository instead of SubscriptionDiscountService
- Add missing imports for SubscriptionDiscount entities
- Rename test for clarity: Finalize_WithNullOwner_SkipsValidation → Finalize_WithCouponOutsideDateRange_IgnoresCouponAndProceeds

All tests passing (14/14)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix the lint error

* Making the owner non nullable

* fix the failing unit test

* Make the owner nullable

* Fix the bug for coupon in Stripe with no audience restrictions(PM-32756)

* Return validation message for invalid coupon

* Update the valid token message

* Fix the failing unit test

* Remove the duplicate method

* Fix the failing build and test

* Resolve the failing test

* Add delete of invalid coupon

* Add the expired error message

* Delete on invalid coupon in stripe

* Fix the lint errors

* return null if we get exception from stripe

* remove the auto-delete change

* fix the failing test

* Fix the lint build error

---------

Co-authored-by: Claude <noreply@anthropic.com>

* [PM-21925] Add MasterPasswordSalt Column to User Table (#6950)

feat: add MasterPasswordSalt column to User table

- Add MasterPasswordSalt column to User table in both Dapper and EF implementations
- Update User stored procedures (Create, Update, UpdateMasterPassword) to handle salt column
- Add EF migrations and update UserView with dependent views
- Set MaxLength constraint on MasterPasswordSalt column
- Update UserRepository implementations to manage salt field
- Add comprehensive test coverage for salt handling and normalization

* PM-31923 fixing all the endpoints

* PM-31923 remove claude change

* PM-31923 fixing feature flag name

* PM-21720 - RegisterFinishResponseModel - clean up deprecated CaptchaBypassToken (#7098)

* chore(deps): Add Renovate ownership of MessagePack pinned transitive dependency

* PM-31923 fixing path traversal vuln and cleaned up null references

* PM-31923 fixing unit test

* PM-31923 fixing issues found by reviewer

* PM-31923 addressing pr comments

* [PM-33219] Resolve silent auth removal on Sends (#7160)

* remove null assignment to auth props and update tests

* update PutRemoveAuth comment for clarity and assign null to empty email list allowing future client side changes to remove ALL emails

* update test to match email removal expectation

* implement expected behavior and update tests

---------

Co-authored-by: Alex Dragovich <46065570+itsadrago@users.noreply.github.com>

* PM-31923 fixing issues based on review

* PM-31923 removing settings.json

* Bumped version to 2026.3.0

* [PM-33091] Add optional Targeting Rules data resource configuration (#7137)

* add fillAssistRules to environment URIs in config

* add tests

* do not include json file specification in path

* fix warnings

* fix(feature-flag): [PM-27085] Account Register Uses New Data Types - Removed unnneded feature flag. (#7127)

* PM-31923 fixing unit tests

* Auth/PM-32416 - Add MultiClientPasswordManagement feature flag (#7169)

* chore(flags): [PM-32554] Remove pm-24579-prevent-sso-on-existing-non-compliant-users feature flag

* Remove flag.

* Removed unneccessary dependency

* Remove unnecessary dependency.

* Removed additional temporary test fixtures.

---------

Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>

* [PM-25860] Rid of bulk delete error (#6925)

* Rid of bulk delete error

* Fix test

* Fix for test

* Update src/Core/Dirt/Services/Implementations/EventService.cs

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Fix formatting issues in DeleteCollectionCommandTests.cs by removing hidden characters and ensuring proper using directives.

* Update src/Core/Dirt/Services/Implementations/EventService.cs

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update src/Core/Dirt/Services/Implementations/EventService.cs

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Refactor DeleteCollectionCommandTests.cs to remove hidden characters and improve argument matching for GetManyByManyIdsAsync method.

* Fix deletion error happening in Postgres by utilizing OrganizationId which is always populated by the table row

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* [deps]: Update MarkDig to 0.45.0 (#7117)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* [PM-18236] - Use Single Org Requirement (#6999)

* Added new methods and ff for single org req

* Changed req messages and added new method for creating orgs

* Updated Requirement and Tests.

* Updated commands and requirement to take a list of org users

* Updated xml docs and renamed to be consistent

* Changes from Code Review

* Removed feature flag check for policy requirements around single org. Aligned error message with what other commands were returning.

* Fixed test names. Updated error messages to be specific for each caller.

* Updated tests to clean up details consturction

* Added test for confirmed accepted user in another org.

* fixed tests to use new factory

* Update test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/RestoreUser/RestoreOrganizationUserCommandTests.cs

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Fixed tests by adding no op for req.

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Auth/PM-32487 - Emergency Access - invite or update - require min value of 1 for wait time in days. (#7168)

* Auth/PM-32821 - Finish cleaning up old registration endpoint (#7097)

* Revert "Revert "refactor(IdentityTokenResponse): [Auth/PM-3287] Remove deprec…" (#7152)

This reverts commit e6c97bd850.

* [PM-32424] Send Access Enumeration protection (#7166)

feat: add enumeration protection to email protected sends

- Implement enumeration protection for email-based protected sends
- Update SendAccess validator with new protection logic
- Change OTP generation failure logging from warning to error level
- Remove unused constants and update validator tests

* [PM-27864] Add PQC TLS Support (#6547)

* Add PQC TLS Support

* Update util/Setup/NginxConfigBuilder.cs

Co-authored-by: Addison Beck <github@addisonbeck.com>

* Update util/Setup/NginxConfigBuilder.cs

Co-authored-by: Addison Beck <github@addisonbeck.com>

* Update util/Setup/NginxConfigBuilder.cs

Co-authored-by: Addison Beck <github@addisonbeck.com>

* Update util/Setup/NginxConfigBuilder.cs

Co-authored-by: Addison Beck <github@addisonbeck.com>

* Update util/Setup/Templates/NginxConfig.hbs

Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>

---------

Co-authored-by: Addison Beck <github@addisonbeck.com>
Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>

* [PM-33061] Tax Id Should Be Added When Upgrading to Teams or Enterprise (#7131)

* refactor(billing): change billing address request type

* feat(billing): add tax id support for international business plans

* feat(billing): add billing address tax id handling

* test: add tests for tax id handling during upgrade

* fix(billing): run dotnet format

* fix(billing): remove extra line

* fix(billing): modify return type of HandleAsync

* test(billing): update tests to reflect updated command signature

* fix(billing): run dotnet format

* tests(billing): fix tests

* test(billing): format

* [PM-32581] Refactor organization subscription update process (#7132)

* chore: add CLAUDE.local.md and .worktrees to gitignore

* feat(billing): add Stripe interval and payment behavior constants and feature flag

* feat(billing): add OrganizationSubscriptionChangeSet model and unit tests

* refactor(billing): rename UpdateOrganizationSubscriptionCommand to BulkUpdateOrganizationSubscriptionsCommand

* feat(billing): add UpdateOrganizationSubscriptionCommand with tests

* feat(billing): use UpdateOrganizationSubscriptionCommand in BulkUpdateOrganizationSubscriptions behind feature flag

* feat(billing): use UpdateOrganizationSubscriptionCommand in SetUpSponsorshipCommand behind feature flag

* feat(billing): add UpgradeOrganizationPlanVNextCommand with tests and feature flag gate

* feat(billing): use UpdateOrganizationSubscriptionCommand in OrganizationService.AdjustSeatsAsync behind feature flag

* feat(billing): use UpdateOrganizationSubscriptionCommand in UpdateSecretsManagerSubscriptionCommand behind feature flag

* feat(billing): use UpdateOrganizationSubscriptionCommand in BillingHelpers.AdjustStorageAsync behind feature flag

* chore: run dotnet format

* fix(billing): missed optional owner in OrganizationBillingService.Finalize after merge

* refactor(billing): address PR feedback on UpdateOrganizationSubscription

* remove flagged logic (#7179)

* Update UseMyItems to use dedicated plan feature (#7101)

* Reorganize seeder presets into purpose-based folders and remove obsolete presets (#7176)

* PM-31923 fixing architecture to make it clean

* PM-31923 adding XML docs to controllers

* Existing device scene (#7155)

* Existing device scene

* Prefer usings

* Require namespaces

* Return the device id that is created

* [deps]: Update MarkDig to v1 (#7120)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com>

* remove feature flag (#7180)

* [PM-32666] Fixes endpoint issue where you can update another by providing a valid org ID (#7185)

* fix(controller): add null check for provider organization ID in ProviderClientsController

* feat(tests): add test for updating provider organization with different provider ID

* fix(OrganizationsController): Remove unused GetPlanType method to streamline organization management (#7177)

* added pm-31697-premium-upgrade-path feature flag (#7162)

* Seeder - Adding density distributions  (#7191)

* chore(flags): Remove pm-19394-send-access-control feature flag

* Remove feature flag.

* Fixed import statements.

* Fixed constructor.

* [deps] Billing: Update coverlet.collector to v8 (#7118)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* [PM-32597] - create short-lived signed attachment URL for self-hosted instances (#7100)

* create short-lived signed attachment URL for self-hosted instances

* move local attachment logic to service

* remove comment

* remove unusued var. add happy-path test for file download

* [PM-30584] Add support for key-connector-migration setting key (#7136)

* Add key-connector enrollment

* Fix tests

* Update src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Move validation to request model

* Add tests

* Fix build

* Attempt to fix build

* Attempt to fix remaining tests

* Fix tests

* Format

---------

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* [PM-33040] Add new interface methods to IApplicationCacheService (#7187)

* Refactor email confirmation logic to remove legacy mail service usage and streamline organization confirmation process (#7192)

* Fixes swagger authentication (#7197)

* Add 9 scale presets and consolidated seeder docs (#7193)

* Add 9 scale presets and consolidated seeder docs

* PM-31923 updated property names for metrics

* Restrict users from sending altered project name/value and it being saved to the database as an invalid encrypted value. (#6853)

* chore(flags): Remove obsolete client flags

* Add density profiles to Seeder CLI (#7205)

* feat(emergency-access): [PM-29585] Prevent New EA Invitations or Acceptance (#6940)

* feat(emergency-access): [PM-29585] Prevent New EA Invitations or Acceptance - Initial implementation

* fix(emergency-access): [PM-29585] Prevent New EA Invitations or Acceptance - Changes in a good place. Need to write tests.

* test(emergency-access): [PM-29585] Prevent New EA Invitations or Acceptance - Service tests have been added.

* fix(emergency-access): [PM-29585] Prevent New EA Invitations or Acceptance - Fixed comment.

* [PM-31820] added a null check to the id/partial route (#7066)

* PM-31923 removed  the file size validation check

* Fixed invalid syntax in OrganizationUser_UpdateMany (#6923)

* [PM-32665] Fix Cross-Organization IDOR in Bulk User Revoke (#7206)

* Decouple seeder cipher encryption from internal vault crates (#7211)

* [deps] BRE: Update mariadb Docker tag to v12 (#7119)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* [PM-19143] Refactor public API MembersController POST to use CommandResult pattern (#7182)

* Add CommandResultRefactor constant to FeatureFlagKeys in Constants.cs

* Add method to convert MemberCreateRequestModel to InviteOrganizationUsersRequest

- Introduced ToInviteRequest method for transforming MemberCreateRequestModel into InviteOrganizationUsersRequest.
- Enhanced model with additional using directives for improved functionality.

* Update GetInviterEmailAsync method to include a check for Guid.Empty to prevent unnecessary DB lookups

* Feature flag MembersController POST to use InviteOrganizationUsersCommand

Add a new code path behind the CommandResultRefactor feature flag that
replaces the legacy InviteUserAsync call with the InviteOrganizationUsersCommand.
Integration tests verify both paths produce identical results.

* Refactor feature flag for member invites from CommandResultRefactor to PublicMembersInviteRefactor in MembersController and update related tests.

* [PM-31657] Address Overwriting Attachments  (#7053)

* check permissions when uploading attachment for self hosted users to remove possibility of overwriting an existing attachment.

* expose `ValidateCipherEditForAttachmentAsync`

* add additional logic to support admin users

* add unit tests for new edit checks

* SHOT-71: Migrate self-host ownership over to SHOT (#7213)

* Migrate self-host ownership over to SHOT

* Set devcontainers to multi owner

* Update CODEOWNERS for docker-compose.yml

* We already have a multiple owner section

* create new dockerfile for SeederApi (#7072)

* create new dockerfile for SeederApi

* troubleshoot cargo issues

* troubleshoot cargo issues

* Ensure Rustup run on build env for appropriate target

* Musl targets do not support cdylibs

* Ensure default triple set to target

* Set target triple rather than update default host

* Change build platforms per project

* Switch to debian since we can't use musl

* Debian build for seeder should work with arm targets

* Move app stage to distroless

* remove SeederApi from server publish section

* suppress unrelated warnings"

* ruling out builds as error source

* override platforms for SeederApi

* troubleshoot matrix

* add extra step for evaluating platforms

* fix syntax error

* exclude unrelated error

* exclude unrelated error

* exclude unrelated error

* exclude unrelated error

* exclude unrelated error

* temporarily reduce number of builds

* exclude unrelated error

* remove temporary block on other builds

* remove unused builds from dockerfile

* add nginx location for seeder, wrap it behind an if check defaulting to false. This was discuss with Matt G, as this will enable QA usage of it without repetitive intervention with config files and reloading the nginx service etc. Handlebars will continously overwrite the nginx conf file on update

* opted to remove conditional location to seederApi, instead include additional conf files in the same directory allowing for extensibility and not directly placing the non-prod seeder location in the config builder

---------

Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
Co-authored-by: AJ Mabry <81774843+aj-bw@users.noreply.github.com>

* introduce feature flag pm-31885-send-controls (#7134)

* chore(flags:): [PM-30245] Remove locked and inactive notifications feature flags from server

* pin image to sha (#7215)

* PM-33591 - Parallelize CreateUsersStep and GeneratePersonalCiphersStep (#7226)

* [PM-31923] Remove Unused Sprocs (#7060)

* Remove old/unused sprocs

* Consistency

* PM-31923 fixing fileData validation check

* PM-31923 fixing summaryData by date range to include all data points

* PM-31923 adding download report route for organization report self-hosted verison

* PM-31923 fixing security issues from pr review

* PM-31923 updating GET methods to fit migration logic on front end

* PM-31923 fixing unit test

* 31923 fixing redudnant code, unit tests, and creating documentation

* 31923 remove unused endpoints, fix unit tests, and create documentation

* PM-31923 adding renew and delete endpoints

* PM-31923 fixing code based on PR comments

* PM-31923 fixing delete scenario with orphaned db record

* PM-31923 fixing IDOR issue, adding unit tests, and making code more DRY

* PM-31923 making update endpoint required

* PM-31923 add FileUploadType to GET endpoints

* PM-31923 fixing dead code

---------

Co-authored-by: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
Co-authored-by: Mick Letofsky <mletofsky@bitwarden.com>
Co-authored-by: Stephon Brown <sbrown@livefront.com>
Co-authored-by: Vijay Oommen <voommen@livefront.com>
Co-authored-by: sven-bitwarden <svernyi@bitwarden.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Isaiah Inuwa <iinuwa@bitwarden.com>
Co-authored-by: Conner Turnbull <133619638+cturnbull-bitwarden@users.noreply.github.com>
Co-authored-by: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ike <137194738+ike-kottlowski@users.noreply.github.com>
Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>
Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com>
Co-authored-by: John Harrington <84741727+harr1424@users.noreply.github.com>
Co-authored-by: Alex Dragovich <46065570+itsadrago@users.noreply.github.com>
Co-authored-by: Github Actions <actions@github.com>
Co-authored-by: Jonathan Prusik <jprusik@users.noreply.github.com>
Co-authored-by: Patrick-Pimentel-Bitwarden <ppimentel@bitwarden.com>
Co-authored-by: Jared <TheWolfBadger@gmail.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Jared McCannon <jmccannon@bitwarden.com>
Co-authored-by: Samuel Warfield <samuel.warfield2@gmail.com>
Co-authored-by: Addison Beck <github@addisonbeck.com>
Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>
Co-authored-by: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com>
Co-authored-by: Brandon Treston <btreston@bitwarden.com>
Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
Co-authored-by: mpbw2 <59324545+mpbw2@users.noreply.github.com>
Co-authored-by: Bernd Schoolmann <mail@quexten.com>
Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
Co-authored-by: Jimmy Vo <huynhmaivo82@gmail.com>
Co-authored-by: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com>
Co-authored-by: Jason Ng <jcory.ng@gmail.com>
Co-authored-by: mkincaid-bw <mkincaid@bitwarden.com>
Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com>
Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com>
Co-authored-by: MtnBurrit0 <77340197+mimartin12@users.noreply.github.com>
Co-authored-by: Amy Galles <9685081+AmyLGalles@users.noreply.github.com>
Co-authored-by: AJ Mabry <81774843+aj-bw@users.noreply.github.com>
2026-05-11 14:02:41 -05:00
Rui Tomé
1323d0fb6a [PM-25690] Create UpdateUserResetPasswordEnrollment command (#7594)
* Implement UpdateUserResetPasswordEnrollment command and interface for managing user password reset enrollment in organizations

* Add unit tests for UpdateUserResetPasswordEnrollmentCommand to validate user enrollment and error handling

* Add IUpdateUserResetPasswordEnrollmentCommand to service collection for user password reset enrollment management

* Add integration tests for OrganizationUsersController reset password enrollment functionality

* Refactor OrganizationUsersController to use IUpdateUserResetPasswordEnrollmentCommand for password reset enrollment updates

* Remove UpdateUserResetPasswordEnrollmentAsync method and related dependencies from IOrganizationService and OrganizationService implementations

* Update IUpdateUserResetPasswordEnrollmentCommand and UpdateUserResetPasswordEnrollmentCommand to support nullable resetPasswordKey

* Refactor unit tests for UpdateUserResetPasswordEnrollmentCommand to improve naming conventions and enhance clarity in test cases
2026-05-11 16:22:57 +01:00
Jared McCannon
3d76e94012 [PM-34150] - RequireSSO Applies to Accepted (#7603)
* Moved accepted to RequireSso property in the create method.

* added feature check
2026-05-11 08:08:38 -05:00
Rui Tomé
3d08eec6c2 [PM-34389] Add refresh endpoint for organization invite links (#7588)
* [PM-34389] Add RefreshOrganizationInviteLinkRequestModel for handling invite link refresh requests

* [PM-34389] Add RefreshOrganizationInviteLinkRequest and IRefreshOrganizationInviteLinkCommand interface for invite link refresh functionality

* [PM-34389] Refactor IRefreshOrganizationInviteLinkCommand interface documentation for clarity and conciseness

* [PM-34389] Add InviteLinkEncryptedKeyRequired error for handling missing encrypted invite keys in invite link requests.

* [PM-34389] Remove InviteLinkEncryptedKeyRequired error from InviteLinks error handling.

* [PM-34389] Remove redundant key check in RefreshOrganizationInviteLinkCommand

* [PM-34389] Add IRefreshOrganizationInviteLinkCommand registration to service collection

* [PM-34389] Add unit tests for RefreshOrganizationInviteLinkCommand to validate invite link refresh functionality, including scenarios for valid input, missing links, and insufficient permissions.

* [PM-34389] Implement Refresh endpoint in OrganizationInviteLinksController to handle invite link refresh requests

* [PM-34389] Add integration tests for Refresh endpoint in OrganizationInviteLinksController, validating link replacement and domain consistency.

* [PM-34389] Implement RefreshAsync method in OrganizationInviteLinkRepository for atomic link replacement, ensuring transactional integrity during updates.

* [PM-34389] Add integration tests for RefreshAsync method in OrganizationInviteLinkRepository, verifying link replacement and rollback behavior on unique constraint violations.

* [PM-34389] Refactor RefreshOrganizationInviteLinkCommand to use RefreshAsync method for atomic link updates, simplifying invite link management.
2026-05-08 14:31:25 +01:00
Alex Morask
4b9cb8c26d [PM-33473] Remove pm-29594-update-individual-subscription-page feature flag (#7519)
* chore: [PM-33473] remove pm-29594-update-individual-subscription-page feature flag

* chore: dotnet format — add UTF-8 BOM to new response model files
2026-05-08 07:44:50 -05:00
Jared
dd19dd8c06 [PM-35201] Enhance AdminRecoverAccountValidator to include Accepted status (#7579)
* Enhance AdminRecoverAccountValidator to include Accepted status for organization users

- Updated validation logic to allow organization users with Accepted status to reset their passwords or two-factor authentication.
- Added unit tests to cover scenarios for Accepted users, ensuring correct validation behavior for account recovery requests.

* Refactor AdminRecoverAccountValidatorTests to include NSubstitute and Xunit

- Removed unused AutoFixture import and added NSubstitute and Xunit for improved testing capabilities.
- Prepared the test file for enhanced unit testing of account recovery validation logic.

* Added AutoFixture import to AdminRecoverAccountValidatorTests for enhanced test data generation
2026-05-07 18:32:41 +00:00
renovate[bot]
3227cf4f14 [deps] Tools: Pin dependencies (#6204)
* [deps] Tools: Pin dependencies

* [PM-24840] updated dependencies that are required with Net 10 switch

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Alex Dragovich <adragovich@bitwarden.com>
Co-authored-by: Alex Dragovich <46065570+itsadrago@users.noreply.github.com>
Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
2026-05-07 10:06:10 -07:00
Rui Tomé
ab00d4f452 [PM-34392] Add delete invite link endpoint (#7591)
* Add IDeleteOrganizationInviteLinkCommand interface for managing organization invite links

* Add DeleteOrganizationInviteLinkCommand and corresponding unit tests for invite link deletion functionality

* Add IDeleteOrganizationInviteLinkCommand to service collection for invite link deletion

* Add Delete endpoint to OrganizationInviteLinksController and corresponding integration test
2026-05-06 19:44:03 +01:00
Alex Morask
869cd3a34e [PM-35909] Preserve existing discounts during price migration (#7561)
* fix(billing): preserve existing discounts in price migration schedules

* refactor(billing): source cart discounts from schedule phase 2 when attached
2026-05-06 07:57:27 -05:00
Thomas Avery
9865fc3ad2 [PM-30852] Add support for TDE user key rotation (#7565)
* Add support for TDE user key rotation

* Add test coverage
2026-05-05 09:56:55 -05:00
Rui Tomé
5289a5fd8c [PM-34388] Add organization invite link update endpoint (#7560)
* Add InviteLinkDomainSanitizer utility for domain normalization

- Introduced InviteLinkDomainSanitizer class to normalize invite link domains by converting them to lowercase and removing blank entries.
- The SanitizeDomains method processes a list of domains, ensuring clean and valid entries for further use.

* Refactor CreateOrganizationInviteLinkCommand to use InviteLinkDomainSanitizer

* Add UpdateOrganizationInviteLinkRequest record for managing invite link updates

- Introduced a new record, UpdateOrganizationInviteLinkRequest, to encapsulate the data required for updating organization invite links.
- The record includes properties for OrganizationId and AllowedDomains, ensuring structured data handling for invite link modifications.

* Add UpdateOrganizationInviteLinkRequestModel for invite link updates

- Introduced UpdateOrganizationInviteLinkRequestModel class to facilitate the update of organization invite links.
- The model includes a required property for AllowedDomains, ensuring validation and structured data handling for invite link modifications.

* Add tests for UpdateOrganizationInviteLinkRequestModel validation

* Add unit tests for UpdateOrganizationInviteLinkCommand

- Introduced comprehensive tests for the UpdateOrganizationInviteLinkCommand, covering scenarios such as successful updates, handling of non-existing links, and validation of allowed domains.
- Ensured that the command behaves correctly under various conditions, including ability checks and input validation.

* Add UpdateOrganizationInviteLinkCommand and IUpdateOrganizationInviteLinkCommand interface

- Implemented UpdateOrganizationInviteLinkCommand to handle updates for organization invite links, including validation of allowed domains and organization abilities.
- Created IUpdateOrganizationInviteLinkCommand interface to define the contract for updating invite links, ensuring structured handling of update requests.

* Add IUpdateOrganizationInviteLinkCommand registration to service collection

- Registered the IUpdateOrganizationInviteLinkCommand interface with the service collection, enabling dependency injection for the UpdateOrganizationInviteLinkCommand functionality.

* Add Update endpoint to OrganizationInviteLinksController

- Implemented the Update method in OrganizationInviteLinksController to handle updates for organization invite links.
- The method utilizes the IUpdateOrganizationInviteLinkCommand to process update requests and returns the appropriate response model.
- Enhanced the controller's functionality to support invite link modifications, ensuring better management of organization invite links.

* Add unit tests for Update method in OrganizationInviteLinksController

- Implemented multiple test cases for the Update method, covering scenarios such as successful updates, handling of non-existing invite links, and validation errors for allowed domains.
- Ensured comprehensive coverage of the Update functionality to validate correct behavior and response models in various conditions.

* Add integration test for updating organization invite links

* fix(invite-link): add [MinLength(1)] to Update request model and matching test
2026-05-04 16:46:40 +01:00
Jimmy Vo
0868a749f8 [PM-32100] Implement Multi-Provider Ability Lookup (#7552) 2026-05-04 11:06:53 -04:00
Rui Tomé
5ae857002c [PM-34774] Add GET endpoint for organization invite links (#7534)
* Add Get method to OrganizationInviteLinksController for retrieving invite links by organization ID

- Implemented a new GET endpoint to fetch an invite link based on the organization ID.
- Integrated IOrganizationInviteLinkRepository to handle data retrieval.
- Updated tests to validate the new functionality, ensuring correct responses for existing and non-existing links.
- Refactored service registration for invite link commands to improve clarity.

* Add GetOrganizationInviteLinkQuery and IGetOrganizationInviteLinkQuery interface

- Implemented GetOrganizationInviteLinkQuery to retrieve invite links for organizations.
- Added IGetOrganizationInviteLinkQuery interface defining the contract for fetching invite links.
- Included error handling for cases where invite links are not available or do not exist.

* Add unit tests for GetOrganizationInviteLinkQuery

- Created GetOrganizationInviteLinkQueryTests to validate the functionality of retrieving organization invite links.
- Implemented tests for successful retrieval, handling cases where no link exists, and scenarios with insufficient permissions or null abilities.
- Ensured proper error handling and assertions for various outcomes in the query execution.

* Add InviteLinkNotFound error type for handling missing invite links

- Introduced InviteLinkNotFound record to represent a not found error for invite links.
- Enhanced error handling in the InviteLinks feature to provide clearer feedback when an invite link is not found.

* Add IGetOrganizationInviteLinkQuery to service collection

- Registered IGetOrganizationInviteLinkQuery with the service collection to enable dependency injection for retrieving organization invite links.
- This addition supports the functionality introduced in the GetOrganizationInviteLinkQuery implementation.

* Refactor OrganizationInviteLinksController to use IGetOrganizationInviteLinkQuery

- Updated OrganizationInviteLinksController to replace IOrganizationInviteLinkRepository with IGetOrganizationInviteLinkQuery for retrieving invite links.
- Enhanced the Get method to handle results more effectively, returning appropriate responses based on the query outcome.
- Modified unit tests to align with the new query implementation, ensuring proper handling of both found and not found scenarios.

* Set AllowedDomains for invite link in OrganizationInviteLinksControllerTests
2026-05-04 14:13:39 +01:00
Derek Nance
74e0441a5e [PM-28727] Upgrade to .NET 10 (#7171)
Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>
2026-05-01 11:53:00 -05:00
Rui Tomé
2a52362d33 [PM-34387] Add organization invite link creation endpoint (#7477)
* Add ConflictError type

* Add generic Handle<T> and extract MapError on BaseAdminConsoleController

* Initialize Code property with a new GUID in OrganizationInviteLink class

* Add ICreateOrganizationInviteLinkCommand interface

* Add CreateOrganizationInviteLinkRequest record for invite link creation

* Add OrganizationInviteLink request and response models for invite link management

* Refactor ICreateOrganizationInviteLinkCommand interface to use CreateOrganizationInviteLinkRequest for invite link creation

* Add CreateOrganizationInviteLinkCommand class to handle invite link creation logic, including domain sanitization and validation checks.

* Add error handling for invite link creation with specific conflict and validation errors

* Add OrganizationInviteLink service commands to OrganizationServiceCollectionExtensions

* Add OrganizationInviteLinksController to manage invite link creation for organizations

* Add integration tests for OrganizationInviteLinksController and CreateOrganizationInviteLinkCommand to validate invite link creation logic, including success and error scenarios.

* Remove unnecessary blank line in OrganizationInviteLinksControllerTests class

* Refactor CreateOrganizationInviteLinkRequestModel to use required properties for AllowedDomains and EncryptedInviteKey

* Update CreateOrganizationInviteLinkCommand to validate allowed domains by using DomainNameValidator

* Add encryption validation attributes to CreateOrganizationInviteLinkRequestModel and implement unit tests for model validation

* Refactor OrganizationInviteLink to encapsulate AllowedDomains serialization logic within methods. Update OrganizationInviteLinkResponseModel to utilize new GetAllowedDomains method for improved clarity and maintainability.

* Enhance domain sanitization in CreateOrganizationInviteLinkCommand by converting domains to lowercase during trimming for improved consistency.

* Update OrganizationInviteLinksControllerTests to use a valid encrypted invite key constant for consistency in test cases.

* Add ability check for organization invite links in CreateOrganizationInviteLinkCommand

- Introduced a new method to verify if an organization can use invite links based on its ability.
- Added a new error type for cases where invite links are not available due to organizational plan restrictions.
- Updated tests to cover scenarios where the organization lacks the ability to create invite links.

* Add documentation for Code property in OrganizationInviteLink class

- Added XML summary comments to the Code property to clarify its purpose and generation method.
- Explained the choice of using Guid.NewGuid for the Code to avoid predictability and ensure uniqueness.

* Implement domain validation in CreateOrganizationInviteLinkRequestModel

- Added IValidatableObject implementation to CreateOrganizationInviteLinkRequestModel for domain validation.
- Introduced Validate method to check the format of allowed domains and return appropriate validation results.
- Updated tests to cover scenarios for invalid domain formats and mixed valid/invalid domains.
- Removed redundant domain validation logic from CreateOrganizationInviteLinkCommand.

* Remove outdated tests from CreateOrganizationInviteLinkRequestModelTests

- Deleted tests for validating EncryptedInviteKey and EncryptedOrgKey as they are no longer relevant.
- Cleaned up the test class to focus on current validation logic for allowed domains.

* Refactor GetAllowedDomains method in OrganizationInviteLink class

- Updated the GetAllowedDomains method to return an empty array instead of throwing a JsonException when deserialization fails.
- This change improves the method's resilience by providing a default value for invalid or missing allowed domains.

* Remove unused InviteLinkInvalidDomains error type from Errors.cs

- Deleted the InviteLinkInvalidDomains record as it is no longer needed.
- This cleanup aligns with recent changes in domain validation logic and improves code maintainability.

* Update OrganizationServiceCollectionExtensions to use TryAddScoped for command registration

- Changed the registration of ICreateOrganizationInviteLinkCommand to use TryAddScoped instead of AddScoped.

* Mock organization ability retrieval in OrganizationInviteLinksControllerTests

* Add ValidateSequenceAttribute for collection validation and corresponding unit tests

* Refactor CreateOrganizationInviteLinkRequestModel to use ValidateSequenceAttribute for domain validation and update unit tests for improved error handling.

* Enhance ValidateSequenceAttribute to handle null values and improve error messaging format

* Add empty line

* Refactor ValidateSequenceAttribute to support IEnumerable interface for improved type handling

* Refactor ValidateSequenceAttribute to improve validation logic and error handling for IEnumerable types

* Remove unused using directive for Microsoft.AspNetCore.Http.HttpResults in BaseAdminConsoleController.cs

* Add MinLength validation to AllowedDomains in CreateOrganizationInviteLinkRequestModel and implement unit test for empty AllowedDomains scenario

* Refactor CreateOrganizationInviteLinkCommandTests to move SetupAbility method for better organization and readability

* Add error handling methods in BaseAdminConsoleController for improved response management

* Update CreateOrganizationInviteLinkRequestModelTests to use array initialization syntax for AllowedDomains so that MinLength attribute works

* Refactor OrganizationInviteLinkResponseModel constructor for improved readability
2026-05-01 14:23:56 +01:00