Commit Graph

74 Commits

Author SHA1 Message Date
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
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
Jared Snider
eb9c8c9aa9 Auth/PM-37621 - Fix Device.LastActivityDate surfacing legacy NULL rows as DateTime.UtcNow (#7649)
* PM-37621 - Fix Device.LastActivityDate surfacing legacy NULL rows as DateTime.UtcNow

Dapper's deserializer skips the property setter when a nullable column is
DBNull, leaving the property at its CLR default. The field initializer
`public DateTime? LastActivityDate { get; internal set; } = DateTime.UtcNow`
poisoned that default, so rows whose LastActivityDate column was NULL (e.g.
devices created before the column existed) read back as the current time.

Drop the initializer, relax `internal set` to `set`, and stamp
LastActivityDate explicitly at the two creation call sites
(DeviceValidator.GetDeviceFromRequest and DeviceRequestModel.ToDevice). Adds
an integration regression test that creates a device with an explicit null
LastActivityDate and asserts the read path surfaces null. Augments
DeviceValidatorTests.GetDeviceFromRequest_RawDeviceInfoValid_ReturnsDevice
to lock in the creation-time stamp.

* PM-37621 - DeviceSeeder - creation should set LastActivityDate
2026-05-15 16:34:08 -04: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
Vincent Salucci
9b1d82c1e9 [PM-19790] [PM-19791] Remove policy requirements feature flag references and definition (#7596)
* chore: remove ff false conditional in WebAuthnController, refs PM-19790

* chore: remove policy reqs flag ref, imports, instantiation, refs PM-19790

* chore: clean up unused imports, instantiations, refs PM-19790

* chore: remove policy reqs ff references, refs PM-19790

* remove policy reqs ff refs from SsoRequestValidatorTests, refs PM-19790

* chore: remove unused method in WebAuthnController and update imports, refs PM-19790

* fix: update WebAuthnControllerTests to account for policy reqs ff removal, refs PM-19790

* fix: update SsoRequestValidatorTests to remove IPolicyService checks, refs PM-19790

* chore: remove policy reqs ff definition, refs PM-19790

* chore: remove unused policy service constructor parameter, refs PM-19790

* chore: removed unnecessary comment about feature flag state from SsoRequestValidatorTests, refs PM-19790
2026-05-08 10:07:56 -05:00
Ike
90f451bc60 [PM-33417] WebAuthn cache (#7500)
feat: Add WebAuthn Cache
  - Add IWebAuthnChallengeCacheProvider with distributed cache implementation for storing WebAuthn Challenges
  - Inject the cache provider into AssertWebAuthnLoginCredentialCommand and WebAuthnGrantValidator so challenges can be stored
  - Use a static token lifetime for WebAuthnLoginAssertionOptionsTokenable and enable nullable reference types on the tokenable
  - Add unit tests for the cache provider, the assertion command, and the WebAuthn controller; add Identity integration and unit tests for WebAuthnGrantValidator with a FakeWebAuthnAuthenticator helper
2026-04-30 09:21:03 -04:00
Jared Snider
28902acec8 Auth/Innovation/PM-4517 - Device Management - Add Last Activity Date (#7302)
* PM-4517 - Add LastActivityDate to Device entity, interfaces, DTOs, and response models

Adds the LastActivityDate nullable DateTime property to the Device entity,
IDeviceRepository interface (BumpLastActivityDateByIdAsync and
BumpLastActivityDateByIdentifierAsync), DeviceAuthDetails DTO,
DeviceResponseModel, DeviceAuthRequestResponseModel, and the
DevicesLastActivityDate feature flag key in Constants.

* PM-4517 - Add BumpDeviceLastActivityDateCommand with distributed cache guard

Adds IBumpDeviceLastActivityDateCommand and IDeviceLastActivityCacheService
interfaces with their implementations. The cache service uses the persistent
keyed IDistributedCache (Cosmos DB in cloud, SQL Server in self-hosted) with
a 48h TTL to guard against redundant DB writes within the same calendar day.
Moves device DI registration into a consolidated AddDeviceServices() extension.

* PM-4517 - Add LastActivityDate SQL schema, stored procedures, and MSSQL migration

Adds LastActivityDate DATETIME2 column to the Device table. Updates Device_Create
and Device_Update stored procedures. Adds Device_BumpLastActivityDateById and
Device_BumpLastActivityDateByIdentifier stored procedures with a CAST AS DATE
guard as a fallback against redundant writes when the application-layer cache
is unavailable.

* PM-4517 - Implement LastActivityDate repository methods and EF migrations

Implements BumpLastActivityDateByIdAsync and BumpLastActivityDateByIdentifierAsync
in both Dapper (via stored procedures) and EF (via ExecuteUpdateAsync with a
date-level guard). Adds EF migrations for Postgres, SQLite, and MySQL.

* PM-4517 - Bump device LastActivityDate on login and refresh token

Wires IBumpDeviceLastActivityDateCommand into BaseRequestValidator (login path,
keyed on device.Id) and CustomTokenRequestValidator (refresh token path, keyed
on device identifier from subject claims). Both call sites are feature-flagged
behind DevicesLastActivityDate.

* PM-4517 - Move AddDeviceServices() to AddBaseServices alongside IDeviceService

Device services are not user features — co-locating them with IDeviceService
in AddBaseServices is more cohesive than nesting them inside AddUserServices.

* PM-4517 - Swallow transient LastActivityDate bump failures to prevent auth disruption

* PM-4517 - Fix DeviceAuthDetails Dapper constructor parameter order to match LastActivityDate column position

* PM-4517 - Add edge case tests for BumpDeviceLastActivityForRefreshAsync guard conditions

* PM-4517 - Add tests for BumpLastActivityDate flag-disabled, null-device, and happy-path cases

* PM-4517 - Add PM-34091 cleanup TODOs to all DevicesLastActivityDate feature flag sites

* PM-4517 - Refine PM-34091 cleanup TODOs and add missing feature flag disabled test for refresh path

* PM-4517 - Remove redundant LastActivityDate shadow property from DeviceAuthDetails

* PM-4517 - Use CultureInfo.InvariantCulture in date string formatting for CA1305

* PM-4517 - Make _bumpDeviceLastActivityDateCommand protected in base to remove duplicate field in derived class

* PM-4517 - Scope device last activity cache key by userId to prevent cross-user collisions

The Device table's unique constraint is (UserId, Identifier), not Identifier alone,
so two users can share the same device identifier (e.g. account switching in a browser).
Scoping the cache key to device:last-activity:{userId}:{identifier} ensures that a cache
hit for one user never suppresses a DB write for another.

Also adds userId to BumpByIdAsync signature and reorders params to be consistent with
BumpByIdentifierAsync(string identifier, Guid userId).

* PM-4517 - Widen try-catch in TryBumpDeviceLastActivityForRefreshAsync and add happy-path test

Renames BumpDeviceLastActivityForRefreshAsync to TryBumpDeviceLastActivityForRefreshAsync
to signal the swallow-on-error intent. Moves the try-catch to wrap the entire method body,
including GetSubjectId() which can throw InvalidOperationException, so no exception can
escape and disrupt token refresh. Also moves the XML doc comment to RecordActivityForInstallation
where it belongs, and adds a happy-path test verifying BumpByIdentifierAsync is called
with the correct identifier and userId.

* PM-4517 - Capture DateTime.UtcNow once in EF bump methods to ensure consistent timestamp

Avoids a minor inconsistency where the WHERE filter and SET clause could evaluate
DateTime.UtcNow at slightly different moments, aligning behavior with the SQL stored
procedures which use a single @RevisionDate parameter.

* PM-4517 - Preserve LastActivityDate on Device_Update when null to prevent regressions

Device_Update previously overwrote LastActivityDate unconditionally, meaning any unrelated
device update (push token rotation, trust changes, deactivation) could silently regress a
recently-bumped value. COALESCE preserves the existing DB value when NULL is passed, while
still allowing callers to set it in the same write by passing a non-NULL value. The EF
ReplaceAsync override applies the same semantics via IsModified = false. Integration test
added to cover the preserve-on-null behaviour across all DB providers.

* PM-4517 - Add docs

* PM-4517 - Adjust docs

* PM-4517 - Add test coverage for BumpLastActivityDateByIdentifierAsync

* PM-4517 - Per PR feedback, add docs on IDeviceLastActivityCacheService

* PM-4517 - Per PR feedback, adjust IBumpDeviceLastActivityDateCommand.BumpById to be bump by device instead b/c it has all what we need.

* PM-4517 - Per PR feedback, add tech debt ticket.

* PM-4517 - Rename BumpByIdentifierAsync to BumpByIdentifierAndUserIdAsync across the board.

* PM-4517 - Per PR feedback, adjust stored proc names to meet SQL style requirements

* PM-4517 - Replace COALESCE with CASE in Device_Update to prevent stale non-null LastActivityDate overwrites

* PM-4517 - Add EF repository feature parity for replace logic + test to ensure we don't run into this again.

* PM-4517 - Fix DB migration order after main merge.

* PM-4517 - Regenerate EF DB migrations

* PM-4517 - actually regenerate EF DB migrations

* PM-4517 - Add LastActivityDate to Device_ReadActiveWithPendingAuthRequestsByUserId and integration tests
2026-04-16 11:45:26 -04:00
Jimmy Vo
deff00b881 [PM-33043] Refactor PolicyService, CipherService, and TwoFactorAuthenticationValidator (#7214) 2026-03-26 12:10:21 -04:00
Ike
ffebc0d792 [PM- 30370] [PM-28827] Add Salt to Auth and KM DTOs (#7239)
feat: add `MasterPasswordSalt` to unlock and authentication flow

- Add optional `MasterPasswordSalt`:
    - `MasterPasswordUnlockAndAuthenticationData`
    - `RegisterFinishRequestModel`
    - `UserDecryptionOptionsBuilder`
- Add test coverage for explicit checks where appropriate in the above model updates
2026-03-25 16:02:33 -04:00
Thomas Avery
53907c2f14 [PM-33162] Refactor user key rotation (#7201)
* Refactor user key rotation to use base data composition

* Update tests
2026-03-20 10:31:25 -05:00
Thomas Rittson
99454f5fe7 [PM-33216] Finalize RequireSsoPolicyRequirement (#7173)
* Add more efficient sproc to retrieve PolicyDetails
  for a single user. This closely matches the existing sproc
  used by PolicyService and should be performant enough
  to be used in the login flow

* Maintain feature flag for this critical path
2026-03-17 08:30:51 +10:00
John Harrington
c118f23e78 [PM-32885] Fix incorrect behavior for expired sends (#7203)
* fix unexpected/randomized error response for expired Sends
2026-03-16 13:19:35 -07:00
Todd Martin
f4956349b6 chore(flags): Remove pm-19394-send-access-control feature flag
* Remove feature flag.

* Fixed import statements.

* Fixed constructor.
2026-03-10 11:40:01 -04:00
Ike
df09fb6916 [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
2026-03-09 12:46:48 -04:00
Rui Tomé
ef4f4e352f [PM-21179] Add interface to check if user is enrolled in account recovery (#6993)
* Add validation for reset password key and account recovery enrollment in OrganizationUser

* Update admin approval logic to check account recovery enrollment and add tests for reset password key validation

* Enhance UserService validation to include account recovery enrollment and add unit test for empty or whitespace reset password key handling

* Refactor OrganizationUserUserDetailsQuery to validate reset password keys and add unit tests for filtering out invalid keys

* Update AdminRecoverAccountCommand to validate account recovery enrollment and adjust tests for whitespace reset password keys

* Enhance OrganizationUserRotationValidator to validate reset password keys, including filtering out whitespace-only keys, and add corresponding unit tests for validation logic.

* Refactor OrganizationUserUserDetailsQueryTests to remove unnecessary whitespace-only test cases for account recovery key validation.

* Refactor MemberResponseModel to use OrganizationUser's validation method for ResetPasswordEnrolled status and update corresponding unit test for clarity.

* Refactor OrganizationUsersController and response models to utilize OrganizationUser's validation method for ResetPasswordKey, ensuring consistent validation across the application. Add unit tests for OrganizationUser to verify key validation logic.

* Update OrganizationUserRotationValidator to handle null reset password keys and adjust tests for client-side bug. Add comments for future migration after resolving PM-31001.

* Fix whitespace issue in UserServiceTests.cs by removing BOM character from the file header.
2026-02-24 14:16:54 +00:00
Patrick-Pimentel-Bitwarden
3dbd17f61d feat(auth-validator): [Auth/PM-22975] Client Version Validator (#6588)
* feat(auth-validator): [PM-22975] Client Version Validator - Implementation.

* test(auth-validator): [PM-22975] Client Version Validator - Added tests.
2026-02-23 15:00:10 +00:00
Alex Dragovich
6d43cc43e3 [PM-31684] Remove email hashing for send access (#6945)
* [PM-31684] Remove email hashing for send access

* [PM-31684] switching the order of migration files

* [PM-31684] adding more migrations

* [PM-31684] Removing anon access emails field  and reusing emails field

* [PM-31684] cleanup before adding migrations back

* [PM-31684] restore original snapshots

* [PM-31684] restore original postgres snapshots

* [PM-31684] adding migrations

* [PM-31684] removing encryption attributes from emails request model

* [PM-31684] adding missing stored proc alters

* [PM-31684] Improved formatting for stored proc defs

* [PM-31684] adding necessary comment back

* [PM-31684] adding case-insensitive check on the server for send auth
2026-02-09 12:58:57 -08:00
Ike
5afdfa6fd1 [PM-30563] Change error response on Send Access token request (#6911)
* feat: remove invalid email response and instead return email and OTP required to protect against enumeration attacks.

* fix: fixing tests and dotnet format
2026-02-04 09:42:32 -05:00
Todd Martin
a27eda7df6 chore(flags): [PM-30613] Remove unused mjml-based-email-templates feature flag
* Removed old method.

* Removed IFeatureService.

* Fixed test.

* Renamed the v2 endpoint.

* Removed old Handlebars templates.

* Renamed v2 templates to remove v2 suffix.
2026-02-02 11:36:39 -05:00
Alex Dragovich
0544ec41d5 [PM-31394] use email address hash for send access email verification (#6921)
* [PM-31394] use email address hash for send access email verification

* [PM-31394] fixing identity server tests for send access

* [PM-31394] fixing more identity server tests for send access
2026-01-29 11:48:12 -08:00
Anders Åberg
40e293117d PM-2035: PRF Unlock (#6401)
* Initial refactor

* Add WebauthnPRFOptions to syncResponse

* MAYBE: Use KM owned ResponseModel?

* REVERT ^- Keep using PrfUnlockOptions for simplicity

This reverts commit 5a34e7dfa8.

* UserDecryptionOptions: Only send one credential

* format

* Update UserDecryptionOptions.cs

* format

* Added feature flag (#6600)
2026-01-26 07:18:42 -08:00
Todd Martin
c37412bacb chore(flags): Remove pm-1632-redirect-on-sso-required feature flag
* Remove feature flag.

* Update test title.

* Fixed some test failures.

* Fixed tests

* Removed method that's no longer used.

* Removed unneeded directive.
2026-01-20 10:03:33 -05:00
Todd Martin
94cd6fbff6 chore(flags): [PM-28337] Remove account recovery permission feature flag
* Removed pm-24425-send-2fa-failed-email

* Remove feature flag

* Linting

* Removed tests and cleaned up comment.
2026-01-11 12:04:10 -05:00
Dave
4fdc4b1b49 refactor(base-request-validator) [PM-28621] Unwind pm-21153 Feature Flag (#6730)
* refactor(base-request-validator) [PM-28621]: Remove feature flagged logic and constant.

* refactor(base-request-validator) [PM-28621]: Update tests to reflect unwound feature flag.
2025-12-12 15:38:21 -05:00
Todd Martin
bd75c71d10 chore(feature-flag): [PM-28331] Remove pm-24425-send-2fa-failed-email feature flag
* Removed pm-24425-send-2fa-failed-email

* Removed flagged logic.
2025-12-08 13:42:54 -05:00
Ike
8a67aafbe5 [PM-1632] Redirect on SsoRequired - return SsoOrganizationIdentifier (#6597)
feat: add SSO request validation and organization identifier lookup

- Implement SsoRequestValidator to validate SSO requirements
- Add UserSsoOrganizationIdentifierQuery to fetch organization identifiers
- Create SsoOrganizationIdentifier custom response for SSO redirects
- Add feature flag (RedirectOnSsoRequired) for gradual rollout
- Register validators and queries in dependency injection
- Create RequestValidationConstants to reduce magic strings
- Add comprehensive test coverage for validation logic
- Update BaseRequestValidator to consume SsoRequestValidator
2025-11-30 16:55:47 -05:00
Dave
bda2bd8ac1 fix(base-request-validator) [PM-21153] Recovery Code Not Functioning for SSO-required Users (#6481)
* chore(feature-flag-keys) [PM-21153]: Add feature flag key for BaseRequestValidator changes.

* fix(base-request-validator) [PM-21153]: Add validation state model for composable validation scenarios.

* fix(base-request-validator) [PM-21153]: Update BaseRequestValidator to allow validation scenarios to be composable.

* fix(base-request-validator) [PM-21153]: Remove validation state object in favor of validator context, per team discussion.

* feat(base-request-validator) [PM-21153]: Update tests to use issue feature flag, both execution paths.

* fix(base-request-validator) [PM-21153]: Fix a null dictionary check.

* chore(base-request-validator) [PM-21153]: Add unit tests around behavior addressed in this feature.

* chore(base-request-validator) [PM-21153]: Update comments for clarity.

* chore(base-request-validator-tests) [PM-21153]: Update verbiage for tests.

* fix(base-request-validator) [PM-21153]: Update validators to no longer need completed scheme management, use 2FA flag for recovery scenarios.

* fix(base-request-validator-tests) [PM-21153]: Customize CustomValidatorRequestContext fixture to allow for setting of request-specific flags as part of the request validation (not eagerly truthy).
2025-11-03 12:24:00 -05:00
Ike
9ce1ecba49 [PM-25240] Send Access OTP email in MJML format (#6411)
feat: Add MJML email templates for Send Email OTP
feat: Implement MJML-based email templates for Send OTP functionality
feat: Add feature flag support for Send Email OTP v2 emails
feat: Update email view models and call sites for Send Email OTP

fix: Modify the directory structure for MJML templates to have Auth directory for better team ownership
fix: Rename `hero.js` to `mj-bw-hero.js`

---
Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com>
2025-10-22 15:13:31 -04:00
Maciej Zieniuk
6324f692b8 [PM-23249] Prevent log-out when changing KDF settings (#6349)
* Prevent log-out when changing KDF settings with feature flag.

* validate salt unchanged for user to throw bad request (400), not internal server error (500)

* change kdf integration tests

* failing tests

* iuncorrect tests wording

* conditional logout

* log out reason as enum

* explicit naming
2025-10-21 19:03:25 +02:00
Dave
629672c4b0 Add tests for ProfileService (#6466)
* feat(profile-service) [PM-24621]: Add ProfileService test fixtures.

* feat(profile-service) [PM-24621]: Add ProfileService test suite.

* feat(profile-servie) [PM-24621]: Re-spell to more consistently use constants across tests.
2025-10-20 11:45:11 -04:00
Justin Baur
c6f1acede9 [BEEEP] Fix all CA2254 occurrences (#6357)
* Fix all CA2254 occurrences

* Fix tests
2025-10-20 11:34:31 -04:00
Bernd Schoolmann
4bf7cf956b [PM-21034] Feature Branch - "User Crypto V2" (#5982)
* [PM-21034] Database changes for signature keypairs (#5906)

* Add signing key repositories, models, and sql migration scripts

* Rename UserSigningKeys table to UserSigningKey

* Rename signedpublickeyownershipclaim to signedpublickey

* Move signedPublicKey to last parameter

* Add newline at end of file

* Rename to signature key pair

* Further rename to signaturekeypair

* Rename to UserSignatureKeyPairRepository

* Add newline

* Rename more instances to UserSignatureKeyPair

* Update parameter order

* Fix order

* Add more renames

* Cleanup

* Fix sql

* Add ef migrations

* Fix difference in SQL SP compared to migration SP

* Fix difference in SQL SP vs migration

* Fix difference in SQL SP vs migration

* Attempt to fix sql

* Rename migration to start later

* Address feedback

* Move UserSignatureKeyPair to KM codeownership

* Fix build

* Fix build

* Fix build

* Move out entitytypeconfiguration

* Use view for reading usersignaturekeypairs

* Fix migration script

* Fix migration script

* Drop view if exists

* Enable nullable

* Replace with create or alter view

* Switch go generatecomb

* Switch to generatecomb

* Move signature algorithm

* Move useresignaturekeypairentitytypeconfiguration to km ownership

* Move userSignatureKeyPair model

* Unswap file names

* Move sql files to km ownership

* Add index on userid for signature keys

* Fix wrong filename

* Remove string length limit

* Regenerate EF migrations

* Undo changes to program.cs

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Rename dbset to plural

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

---------

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

* [PM-21034] Implement api changes to retreive signing keys (#5932)

* Add signing key repositories, models, and sql migration scripts

* Rename UserSigningKeys table to UserSigningKey

* Rename signedpublickeyownershipclaim to signedpublickey

* Move signedPublicKey to last parameter

* Add newline at end of file

* Rename to signature key pair

* Further rename to signaturekeypair

* Rename to UserSignatureKeyPairRepository

* Add newline

* Rename more instances to UserSignatureKeyPair

* Update parameter order

* Fix order

* Add more renames

* Cleanup

* Fix sql

* Add ef migrations

* Fix difference in SQL SP compared to migration SP

* Fix difference in SQL SP vs migration

* Fix difference in SQL SP vs migration

* Attempt to fix sql

* Rename migration to start later

* Address feedback

* Move UserSignatureKeyPair to KM codeownership

* Fix build

* Fix build

* Fix build

* Move out entitytypeconfiguration

* Use view for reading usersignaturekeypairs

* Fix migration script

* Fix migration script

* Add initial get keys endpoint

* Add sync response

* Cleanup

* Add query and fix types

* Add tests and cleanup

* Fix test

* Drop view if exists

* Add km queries

* Cleanup

* Enable nullable

* Cleanup

* Cleanup

* Enable nullable

* Fix incorrect namespace

* Remove unused using

* Fix test build

* Fix build error

* Fix build

* Attempt to fix tests

* Attempt to fix tests

* Replace with create or alter view

* Attempt to fix tests

* Attempt to fix build

* Rename to include async suffix

* Fix test

* Rename repo

* Attempt to fix tests

* Cleanup

* Test

* Undo test

* Fix tests

* Fix test

* Switch go generatecomb

* Switch to generatecomb

* Move signature algorithm

* Move useresignaturekeypairentitytypeconfiguration to km ownership

* Move userSignatureKeyPair model

* Unswap file names

* Move sql files to km ownership

* Add index on userid for signature keys

* Fix wrong filename

* Fix build

* Remove string length limit

* Regenerate EF migrations

* Undo changes to program.cs

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Rename dbset to plural

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

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

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

* Cleanup and move query to core

* Fix test

* Fix build

* Fix tests

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

* Switch away from primary constructor

* Use argumentNullException

* Add test

* Pass user account keys directly to profileresponsemodel

* Move registration to core

* Update src/Api/Startup.cs

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

* Update src/Api/Startup.cs

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

* Remove empty line

* Apply suggestions

* Fix tests

* Fix tests

---------

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

* [PM-22384] Implement key-rotation based enrollment to user-crypto v2 (#5934)

* Add signing key repositories, models, and sql migration scripts

* Rename UserSigningKeys table to UserSigningKey

* Rename signedpublickeyownershipclaim to signedpublickey

* Move signedPublicKey to last parameter

* Add newline at end of file

* Rename to signature key pair

* Further rename to signaturekeypair

* Rename to UserSignatureKeyPairRepository

* Add newline

* Rename more instances to UserSignatureKeyPair

* Update parameter order

* Fix order

* Add more renames

* Cleanup

* Fix sql

* Add ef migrations

* Fix difference in SQL SP compared to migration SP

* Fix difference in SQL SP vs migration

* Fix difference in SQL SP vs migration

* Attempt to fix sql

* Rename migration to start later

* Address feedback

* Move UserSignatureKeyPair to KM codeownership

* Fix build

* Fix build

* Fix build

* Move out entitytypeconfiguration

* Use view for reading usersignaturekeypairs

* Fix migration script

* Fix migration script

* Add initial get keys endpoint

* Add sync response

* Cleanup

* Add query and fix types

* Add tests and cleanup

* Fix test

* Drop view if exists

* Add km queries

* Cleanup

* Enable nullable

* Cleanup

* Cleanup

* Enable nullable

* Fix incorrect namespace

* Remove unused using

* Fix test build

* Fix build error

* Fix build

* Attempt to fix tests

* Attempt to fix tests

* Replace with create or alter view

* Attempt to fix tests

* Attempt to fix build

* Rename to include async suffix

* Fix test

* Rename repo

* Attempt to fix tests

* Cleanup

* Test

* Undo test

* Fix tests

* Fix test

* Switch go generatecomb

* Switch to generatecomb

* Move signature algorithm

* Move useresignaturekeypairentitytypeconfiguration to km ownership

* Move userSignatureKeyPair model

* Unswap file names

* Move sql files to km ownership

* Add index on userid for signature keys

* Fix wrong filename

* Fix build

* Remove string length limit

* Regenerate EF migrations

* Undo changes to program.cs

* Cleanup

* Add migration to user encryption v2

* Fix build

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Rename dbset to plural

* Cleanup

* Cleanup

* Fix build

* Fix test

* Add validation

* Fix test

* Apply fixes

* Fix tests

* Improve tests

* Add tests

* Add error message validation

* Fix tests

* Fix tests

* Fix test

* Add test

* Fix tests and errors

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

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

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

* Cleanup and move query to core

* Fix test

* Fix build

* Fix tests

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

* Switch away from primary constructor

* Use argumentNullException

* Add test

* Pass user account keys directly to profileresponsemodel

* Fix build

* Fix namespace

* Make signedpublickey optional

* Remove unused file

* Fix cases for request data conversion

* Revert constructor change

* Undo comments change

* Apply fixes

* Move registration to core

* Update src/Api/Startup.cs

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

* Update src/Api/Startup.cs

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

* Remove empty line

* Apply suggestions

* Fix tests

* Fix tests

* Fix build of integration tests

* Attempt to fix tests

* Add test

* Move v2 encryption user async below public functions

* Add todo

* Rename to have async suffix

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Address feedback

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test coverage

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Split up validation from rotation

* Fix tests

* Increase test coverage

* Rename tests

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test for no signature keypair data

* Fix build

* Enable nullable

* Fix build

* Clean up data model

* Fix tests

* Cleanup

---------

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

* Fix build

* [PM-22862] Account security version (#5995)

* Add signing key repositories, models, and sql migration scripts

* Rename UserSigningKeys table to UserSigningKey

* Rename signedpublickeyownershipclaim to signedpublickey

* Move signedPublicKey to last parameter

* Add newline at end of file

* Rename to signature key pair

* Further rename to signaturekeypair

* Rename to UserSignatureKeyPairRepository

* Add newline

* Rename more instances to UserSignatureKeyPair

* Update parameter order

* Fix order

* Add more renames

* Cleanup

* Fix sql

* Add ef migrations

* Fix difference in SQL SP compared to migration SP

* Fix difference in SQL SP vs migration

* Fix difference in SQL SP vs migration

* Attempt to fix sql

* Rename migration to start later

* Address feedback

* Move UserSignatureKeyPair to KM codeownership

* Fix build

* Fix build

* Fix build

* Move out entitytypeconfiguration

* Use view for reading usersignaturekeypairs

* Fix migration script

* Fix migration script

* Add initial get keys endpoint

* Add sync response

* Cleanup

* Add query and fix types

* Add tests and cleanup

* Fix test

* Drop view if exists

* Add km queries

* Cleanup

* Enable nullable

* Cleanup

* Cleanup

* Enable nullable

* Fix incorrect namespace

* Remove unused using

* Fix test build

* Fix build error

* Fix build

* Attempt to fix tests

* Attempt to fix tests

* Replace with create or alter view

* Attempt to fix tests

* Attempt to fix build

* Rename to include async suffix

* Fix test

* Rename repo

* Attempt to fix tests

* Cleanup

* Test

* Undo test

* Fix tests

* Fix test

* Switch go generatecomb

* Switch to generatecomb

* Move signature algorithm

* Move useresignaturekeypairentitytypeconfiguration to km ownership

* Move userSignatureKeyPair model

* Unswap file names

* Move sql files to km ownership

* Add index on userid for signature keys

* Fix wrong filename

* Fix build

* Remove string length limit

* Regenerate EF migrations

* Undo changes to program.cs

* Cleanup

* Add migration to user encryption v2

* Fix build

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Rename dbset to plural

* Cleanup

* Cleanup

* Fix build

* Fix test

* Add validation

* Fix test

* Apply fixes

* Fix tests

* Improve tests

* Add tests

* Add error message validation

* Fix tests

* Fix tests

* Fix test

* Add test

* Fix tests and errors

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

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

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

* Cleanup and move query to core

* Fix test

* Fix build

* Fix tests

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

* Switch away from primary constructor

* Use argumentNullException

* Add test

* Pass user account keys directly to profileresponsemodel

* Fix build

* Fix namespace

* Make signedpublickey optional

* Remove unused file

* Fix cases for request data conversion

* Revert constructor change

* Undo comments change

* Apply fixes

* Move registration to core

* Update src/Api/Startup.cs

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

* Update src/Api/Startup.cs

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

* Remove empty line

* Apply suggestions

* Fix tests

* Fix tests

* Fix build of integration tests

* Attempt to fix tests

* Add test

* Move v2 encryption user async below public functions

* Add todo

* Rename to have async suffix

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Address feedback

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test coverage

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Split up validation from rotation

* Fix tests

* Increase test coverage

* Rename tests

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test for no signature keypair data

* Fix build

* Enable nullable

* Fix build

* Clean up data model

* Fix tests

* Merge branch 'km/signing-upgrade-rotation' into km/account-security-version

* Add security state to rotation

* Update tests

* Update tests and check for security state in v2 model

* Cleanup

* Add tests

* Add security state data to integration test

* Re-sort and remove limit

* Update migrations

* Fix sql

* Fix sql

* Fix sql

* Fix fixture

* Fix test

* Fix test

* Fix test

---------

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

* [PM-22853] Add feature flag (#6090)

* Add signing key repositories, models, and sql migration scripts

* Rename UserSigningKeys table to UserSigningKey

* Rename signedpublickeyownershipclaim to signedpublickey

* Move signedPublicKey to last parameter

* Add newline at end of file

* Rename to signature key pair

* Further rename to signaturekeypair

* Rename to UserSignatureKeyPairRepository

* Add newline

* Rename more instances to UserSignatureKeyPair

* Update parameter order

* Fix order

* Add more renames

* Cleanup

* Fix sql

* Add ef migrations

* Fix difference in SQL SP compared to migration SP

* Fix difference in SQL SP vs migration

* Fix difference in SQL SP vs migration

* Attempt to fix sql

* Rename migration to start later

* Address feedback

* Move UserSignatureKeyPair to KM codeownership

* Fix build

* Fix build

* Fix build

* Move out entitytypeconfiguration

* Use view for reading usersignaturekeypairs

* Fix migration script

* Fix migration script

* Add initial get keys endpoint

* Add sync response

* Cleanup

* Add query and fix types

* Add tests and cleanup

* Fix test

* Drop view if exists

* Add km queries

* Cleanup

* Enable nullable

* Cleanup

* Cleanup

* Enable nullable

* Fix incorrect namespace

* Remove unused using

* Fix test build

* Fix build error

* Fix build

* Attempt to fix tests

* Attempt to fix tests

* Replace with create or alter view

* Attempt to fix tests

* Attempt to fix build

* Rename to include async suffix

* Fix test

* Rename repo

* Attempt to fix tests

* Cleanup

* Test

* Undo test

* Fix tests

* Fix test

* Switch go generatecomb

* Switch to generatecomb

* Move signature algorithm

* Move useresignaturekeypairentitytypeconfiguration to km ownership

* Move userSignatureKeyPair model

* Unswap file names

* Move sql files to km ownership

* Add index on userid for signature keys

* Fix wrong filename

* Fix build

* Remove string length limit

* Regenerate EF migrations

* Undo changes to program.cs

* Cleanup

* Add migration to user encryption v2

* Fix build

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Rename dbset to plural

* Cleanup

* Cleanup

* Fix build

* Fix test

* Add validation

* Fix test

* Apply fixes

* Fix tests

* Improve tests

* Add tests

* Add error message validation

* Fix tests

* Fix tests

* Fix test

* Add test

* Fix tests and errors

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

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

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

* Cleanup and move query to core

* Fix test

* Fix build

* Fix tests

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

* Switch away from primary constructor

* Use argumentNullException

* Add test

* Pass user account keys directly to profileresponsemodel

* Fix build

* Fix namespace

* Make signedpublickey optional

* Remove unused file

* Fix cases for request data conversion

* Revert constructor change

* Undo comments change

* Apply fixes

* Move registration to core

* Update src/Api/Startup.cs

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

* Update src/Api/Startup.cs

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

* Remove empty line

* Apply suggestions

* Fix tests

* Fix tests

* Fix build of integration tests

* Attempt to fix tests

* Add test

* Move v2 encryption user async below public functions

* Add todo

* Rename to have async suffix

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Address feedback

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test coverage

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Split up validation from rotation

* Fix tests

* Increase test coverage

* Rename tests

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test for no signature keypair data

* Fix build

* Enable nullable

* Fix build

* Clean up data model

* Fix tests

* Merge branch 'km/signing-upgrade-rotation' into km/account-security-version

* Add security state to rotation

* Update tests

* Add feature flag

* Update tests and check for security state in v2 model

* Cleanup

* Add tests

* Add security state data to integration test

* Re-sort and remove limit

* Update migrations

* Fix sql

* Fix sql

* Fix sql

* Fix fixture

* Fix test

* Fix test

* Fix test

---------

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

* [PM-23222] Update revision date on key rotation (#6038)

* Add signing key repositories, models, and sql migration scripts

* Rename UserSigningKeys table to UserSigningKey

* Rename signedpublickeyownershipclaim to signedpublickey

* Move signedPublicKey to last parameter

* Add newline at end of file

* Rename to signature key pair

* Further rename to signaturekeypair

* Rename to UserSignatureKeyPairRepository

* Add newline

* Rename more instances to UserSignatureKeyPair

* Update parameter order

* Fix order

* Add more renames

* Cleanup

* Fix sql

* Add ef migrations

* Fix difference in SQL SP compared to migration SP

* Fix difference in SQL SP vs migration

* Fix difference in SQL SP vs migration

* Attempt to fix sql

* Rename migration to start later

* Address feedback

* Move UserSignatureKeyPair to KM codeownership

* Fix build

* Fix build

* Fix build

* Move out entitytypeconfiguration

* Use view for reading usersignaturekeypairs

* Fix migration script

* Fix migration script

* Add initial get keys endpoint

* Add sync response

* Cleanup

* Add query and fix types

* Add tests and cleanup

* Fix test

* Drop view if exists

* Add km queries

* Cleanup

* Enable nullable

* Cleanup

* Cleanup

* Enable nullable

* Fix incorrect namespace

* Remove unused using

* Fix test build

* Fix build error

* Fix build

* Attempt to fix tests

* Attempt to fix tests

* Replace with create or alter view

* Attempt to fix tests

* Attempt to fix build

* Rename to include async suffix

* Fix test

* Rename repo

* Attempt to fix tests

* Cleanup

* Test

* Undo test

* Fix tests

* Fix test

* Switch go generatecomb

* Switch to generatecomb

* Move signature algorithm

* Move useresignaturekeypairentitytypeconfiguration to km ownership

* Move userSignatureKeyPair model

* Unswap file names

* Move sql files to km ownership

* Add index on userid for signature keys

* Fix wrong filename

* Fix build

* Remove string length limit

* Regenerate EF migrations

* Undo changes to program.cs

* Cleanup

* Add migration to user encryption v2

* Fix build

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql

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

* Rename dbset to plural

* Cleanup

* Cleanup

* Fix build

* Fix test

* Add validation

* Fix test

* Apply fixes

* Fix tests

* Improve tests

* Add tests

* Add error message validation

* Fix tests

* Fix tests

* Fix test

* Add test

* Fix tests and errors

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

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

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

* Cleanup and move query to core

* Fix test

* Fix build

* Fix tests

* Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

* Switch away from primary constructor

* Use argumentNullException

* Add test

* Pass user account keys directly to profileresponsemodel

* Fix build

* Fix namespace

* Make signedpublickey optional

* Remove unused file

* Fix cases for request data conversion

* Revert constructor change

* Undo comments change

* Apply fixes

* Move registration to core

* Update src/Api/Startup.cs

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

* Update src/Api/Startup.cs

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

* Remove empty line

* Apply suggestions

* Fix tests

* Fix tests

* Fix build of integration tests

* Attempt to fix tests

* Add test

* Move v2 encryption user async below public functions

* Add todo

* Rename to have async suffix

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Address feedback

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test coverage

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Split up validation from rotation

* Fix tests

* Increase test coverage

* Rename tests

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs

Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>

* Add test for no signature keypair data

* Fix build

* Enable nullable

* Fix build

* Clean up data model

* Fix tests

* Merge branch 'km/signing-upgrade-rotation' into km/account-security-version

* Add security state to rotation

* Update tests

* Update revision date on key rotation

* Update tests and check for security state in v2 model

* Cleanup

* Add tests

* Add security state data to integration test

* Re-sort and remove limit

* Update migrations

* Fix sql

* Fix sql

* Fix sql

* Fix fixture

* Fix test

* Fix test

* Fix test

* Add test for change date

---------

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

* Fix signing keys

* Update sql migrations

* Fix tests

* Add keys to identity token response

* Fix tests

* Fix tests

* Fix formatting

* Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

* Update src/Infrastructure.Dapper/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs

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

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

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

* Update src/Api/KeyManagement/Models/Requests/SignatureKeyPairRequestModel.cs

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

* Update src/Api/KeyManagement/Models/Requests/PublicKeyEncryptionKeyPairRequestModel.cs

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

* Update src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs

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

* Update src/Core/KeyManagement/Repositories/IUserSignatureKeyPairRepository.cs

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

* Update src/Core/KeyManagement/Queries/UserAccountKeysQuery.cs

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

* Update src/Core/KeyManagement/Models/Data/PublicKeyEncryptionKeyPairData.cs

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

* Update src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs

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

* Update src/Core/KeyManagement/Models/Data/RotateUserAccountKeysData.cs

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

* Update src/Core/KeyManagement/Models/Data/SignatureKeyPairData.cs

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

* Update src/Core/KeyManagement/Models/Data/SecurityStateData.cs

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

* Update src/Core/KeyManagement/Models/Data/UserAccountKeysData.cs

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

* Update src/Core/KeyManagement/Models/Request/SecurityStateModel.cs

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

* Update src/Core/KeyManagement/Models/Response/PrivateKeysResponseModel.cs

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

* Update src/Core/KeyManagement/Models/Response/PublicKeysResponseModel.cs

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

* Update src/Core/KeyManagement/Models/Response/PublicKeyEncryptionKeyPairResponseModel.cs

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

* Update src/Core/KeyManagement/Queries/Interfaces/IUserAcountKeysQuery.cs

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

* Update src/Core/KeyManagement/Models/Response/SignatureKeyPairResponseModel.cs

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

* Remove unnecessary file

* Add eof spacing

* Move models

* Fix build

* Move models to API subdirectory

* Rename model

* Remove migrations

* Add new ef migrations

* Remove empty line

* Only query account keys if the user has keys

* Dotnet format

* Fix test

* Update test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs

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

* Apply suggestion

* Fix whitespace

* Force camel case on response models

* Address feedback for sql files

* Fix build

* Make index unique

* Add contstraints

* Fix sql

* Fix order

* Cleanup

* Fix build

* Update migrations

* Update EF migrations

* Change parameters to nvarchar

* Update to Varchar

* Apply feedback

* Move refresh view

* Attempt to fix build

* Undo sql changes

* Apply feedback about varchar

* Apply feedback about refresh view

* Apply feedback about new lines

* Address SQL feedback

* Re-sort columns

* Fix build

* Fix order

* Fix build

---------

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
2025-10-20 12:51:08 +02:00
Dave
6466c00acd fix(user-decryption-options) [PM-23174]: ManageAccountRecovery Permission Forces Master Password Set (#6230)
* fix(user-decryption-options): ManageAccountRecovery Permission Forces MP Set - Update tests, add OrganizationUser fixture customization for Permissions

* fix(user-decryption-options): ManageAccountRecovery Permission Forces MP Set - Update hasManageResetPasswordPermission evaluation.

* PM-23174 - Add TODO for endpoint per sync discussion with Dave

* fix(user-decryption-options): ManageAccountRecovery Permission Forces MP Set - Clean up comments.

* fix(user-decryption-options): ManageAccountRecovery Permission Forces MP Set - Remove an outdated comment.

* fix(user-decryption-options): ManageAccountRecovery Permission Forces MP Set - Elaborate on comments around Organization User invite-time evaluation.

* fix(user-decryption-options): Use currentContext for Provider relationships, update comments, and feature flag the change.

* fix(user-decryption-options): Update test suite and provide additional comments for future flag removal.

---------

Co-authored-by: Jared Snider <jsnider@bitwarden.com>
2025-09-25 13:37:36 -04:00
Ike
3b54fea309 [PM-22696] send enumeration protection (#6352)
* feat: add static enumeration helper class
* test: add enumeration helper class unit tests

* feat: implement NeverAuthenticateValidator
* test: unit and integration tests SendNeverAuthenticateValidator

* test: use static class for common integration test setup for Send Access unit and integration tests
* test: update tests to use static helper
2025-09-23 06:38:22 -04:00
Ike
6d4129c6b7 [PM-20595] Add Policy for Send access (#6282)
* feat: add policy to API startup and Policies class to hold the static strings
* test: add snapshot testing for constants to help with rust mappings
* doc: add docs for send access
2025-09-05 10:36:01 -04:00
Ike
96fe09af89 [PM-25415] move files into better place for code ownership (#6275)
* chore: move files into better place for code ownership

* fix: import correct namespace
2025-09-04 10:08:03 -04:00
Ike
d2d3e0f11b [PM-22678] Send email otp authentication method (#6255)
feat(auth): email OTP validation, and generalize authentication interface

- Generalized send authentication method interface
- Made validate method async
- Added email mail support for Handlebars
- Modified email templates to match future implementation

fix(auth): update constants, naming conventions, and error handling

- Renamed constants for clarity
- Updated claims naming convention
- Fixed error message generation
- Added customResponse for Rust consumption

test(auth): add and fix tests for validators and email

- Added tests for SendEmailOtpRequestValidator
- Updated tests for SendAccessGrantValidator

chore: apply dotnet formatting
2025-09-02 16:48:57 -04:00
Ike
3097e7f223 [PM- 22675] Send password auth method (#6228)
* feat: add Passwordvalidation
* fix: update strings to constants
* fix: add customResponse for rust consumption
* test: add tests for SendPasswordValidator. fix: update tests for SendAccessGrantValidator
* feat: update send access constants.
2025-08-22 18:02:37 -04:00
renovate[bot]
50b36bda2a [deps] Auth: Update Duende.IdentityServer to 7.2.4 (#5683)
* [deps] Auth: Update Duende.IdentityServer to 7.2.4

* fix: update namespaces

* chore: dotnet format
---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Ike Kottlowski <ikottlowski@bitwarden.com>
Co-authored-by: Ike <137194738+ike-kottlowski@users.noreply.github.com>
2025-08-21 16:53:36 -04:00
Ike
43d753dcb1 [PM-20592] [PM-22737] [PM-22738] Send grant validator (#6151)
**feat**: create `SendGrantValidator` and initial `SendPasswordValidator` for Send access grants  
**feat**: add feature flag to toggle Send grant validation logic  
**feat**: add Send client to Identity and update `ApiClient` to generic `Client`  
**feat**: register Send services in DI pipeline  
**feat**: add claims management support to `ProfileService`  
**feat**: distinguish between invalid grant and invalid request in `SendAccessGrantValidator`

**fix**: update parsing of `send_id` from request  
**fix**: add early return when feature flag is disabled  
**fix**: rename and organize Send access scope and grant type  
**fix**: dotnet format

**test**: add unit and integration tests for `SendGrantValidator`  
**test**: update OpenID configuration and API resource claims

**doc**: move documentation to interfaces and update inline comments  

**chore**: add TODO for future support of `CustomGrantTypes`
2025-08-13 18:38:00 -04:00
Todd Martin
3c5de319d1 feat(2fa): [PM-24425] Add email on failed 2FA attempt
* Added email on failed 2FA attempt.

* Added tests.

* Adjusted email verbiage.

* Added feature flag.

* Undid accidental change.

* Undid unintentional change to clean up PR.

* Linting

* Added attempted method to email.

* Changes to email templates.

* Linting.

* Email format changes.

* Email formatting changes.
2025-08-11 16:39:43 -04:00
Jared Snider
000d1f2f6e refactor(DeviceValidator): [Auth/PM-24362] Misc improvements (#6152)
* PM-24362 - DeviceValidator - (1) refactor name of NewDeviceOtpRequest --> RequestHasNewDeviceVerificationOtp (2) Move auth request rejection check above normal NDV check and remove auth request check from NDV check

* PM-24362 - Update DeviceValidatorTests + add new scenario
2025-08-06 10:18:57 -04:00
Jared Snider
88463c1263 pm-24210-v3 (#6148) 2025-07-30 19:26:33 -04:00
Jared Snider
64bf17684a pm-24210-v2 (#6144) 2025-07-30 14:23:01 -04:00
Jared Snider
531af410f9 pm-24210 (#6142) 2025-07-30 12:18:27 -04:00
Maciej Zieniuk
59e7bc7438 Added MasterPasswordUnlock to UserDecryptionOptions as part of identity response (#6093) 2025-07-28 17:34:42 +02:00
Todd Martin
79ad1dbda0 fix(2fa): [PM-22323] Do not show 2FA warning for 2FA setup and login emails
* Added configuration to not display 2FA setup instruction

* Refactored to new service.

* Linting.

* Dependency injection

* Changed to scoped to have access to ICurrentContext.

* Inverted logic for EmailTotpAction

* Fixed tests.

* Fixed tests.

* More tests.

* Fixed tests.

* Linting.

* Added tests at controller level.

* Linting

* Fixed error in test.

* Review updates.

* Accidentally deleted imports.
2025-07-07 10:56:59 -04:00
Bernd Schoolmann
14e68428f6 [PM-20225] Block no-userkey legacy users (#5640)
* Block legacy users on all clients over 2025.5

* Update message

* Fix test

* Fix test

* Update blocked version
2025-06-02 22:04:01 +02:00
Justin Baur
0b2b573bd3 Add DynamicClientStore (#5670)
* Add DynamicClientStore

* Formatting

* Fix Debug assertion

* Make Identity internals visible to its unit tests

* Add installation client provider tests

* Add internal client provider tests

* Add DynamicClientStore tests

* Fix namespaces after merge

* Format

* Add docs and remove TODO comments

* Use preferred prefix for API keys

---------

Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>
2025-05-30 12:58:54 -04:00
Patrick-Pimentel-Bitwarden
8d2629fe58 Auth/pm 17111/add browser to list of approving clients (#5825)
* refactor(update-auth-approving-clients): [PM-17111] Add Browser to List of Approving Clients - Refactored how it works to fit different priorities.
2025-05-16 09:50:32 -04:00