feat: call SDK for password prelogin (PM-27060)
- Add PM27060_PasswordPreloginFromSdk feature flag (default off) to gate the new behavior
- Update `DefaultPasswordPreloginService` to call the SDK for prelogin when the flag is enabled, falling back to the existing API-based path otherwise
* PM-39905 - Restructure organization-invite into subfolders with barrel imports
Split the flat feature folder into nested subfolders. Services get the
abstraction at the top with a nested implementations/ folder for the
default impl, its spec, and the state file. Models live in their own
subfolder. The state file also picks up the .state.ts naming convention.
External consumers now import through the root barrel per the auth
CLAUDE.md convention rather than deep-importing individual files.
Piggy-backed rename: OrganizationInviteService.getInvitePolicies ->
getOrgPoliciesForInvite. Mirrors getMasterPasswordPolicyOptionsForInvite
and is clearer about what the method returns.
* PM-39905 - Update organization-invite-flows doc for restructured paths + rename
Refresh the companion design doc to match this PR's changes:
- Source-file links point at the new subfolder locations (models/,
services/implementations/).
- getInvitePolicies references updated to getOrgPoliciesForInvite.
* PM-39905 - Expand organization-invite-flows doc with Key Connector SSO path
Add a third SSO subsection covering Key Connector JIT-provisioned users, plus
the corresponding member-decryption-option bullet under "The two acceptance
models". Rename "Why two cleanup points" -> "Why three cleanup points".
Also correct the MP command name to FinishSsoJitProvisionMasterPasswordCommand
(the prior SetInitialMasterPasswordCommand was renamed server-side and is now
marked [Obsolete]).
Notes the latent divergence in the KC path: neither the base component nor
the web override calls clearOrganizationInvite(), and fullSync doesn't touch
ORGANIZATION_INVITE_DISK, so the stashed invite persists on disk after
acceptance. Self-heals via subsequent overwrite or the email-mismatch guard.
---------
Co-authored-by: Patrick-Pimentel-Bitwarden <ppimentel@bitwarden.com>
GovModeService is a shared Platform service that downstream teams consume to
gate FedRAMP-specific behavior.
The MVP implementation infers the gov-mode signal from the client-side Region
(true when `env.getRegion() === Region.Gov`). PM-36520 will replace the
implementation with a server-backed check while keeping this contract stable.
The service exposes two Observable surfaces: `globalIsGovMode$` (pre-login) and
`isGovMode$(userId)` (when a UserId is in scope). Consumers needing a Promise
snapshot bridge with `firstValueFrom` at the call-site -- the synthesis memory
A5086F94 captured the decision to omit Promise overloads from the service
surface.
Registered in all four app bootstraps: Angular DI (jslib-services.module),
browser background, CLI service-container, and desktop main. Unit tests cover
all four regions (Gov, US, EU, SelfHosted) for both API surfaces.
* [PM-38392] Route password-protected Send saves through the SDK
The SDK now exposes a `hashedPassword` SendAuthType variant (PM-38391,
sdk-internal #1197, present in the pinned 0.2.0-main.872) that forwards the
client-derived keyB64 verbatim without re-applying PBKDF2. Drop the temporary
workaround that routed password-protected saves to the legacy SendApiService.
- buildSendAuth: add AuthType.Password case returning
{ type: "hashedPassword", keyB64: sendView.password }, guarded against a
missing derived key. keyB64 is a proof-of-knowledge and is never logged.
- Remove the password-protected save guards from SendApiServiceSelector and
SendSdkApiService; the new-file-send fallback is unchanged.
- Update the now-stale workaround doc comments.
- Tests: flip selector password create/edit assertions to SDK routing; add
send-sdk-api.service.spec.ts covering the hashedPassword output, the
null-key guard, the none variant, and the new-file-send guard.
* [PM-38392] Use SDK high-level password auth for password-protected sends
The prior approach forwarded the client's pre-derived keyB64 to the SDK via
the hashedPassword variant. That is broken for creates: the SDK's create
generates its own send key, so a keyB64 derived over the client's (discarded)
key yields a password the user can never satisfy (verified end-to-end: correct
password rejected on receive). A maintainer also asked to move clients onto the
higher-level password API rather than the low-level hashed variant
(sdk-internal#1197).
Route password-protected sends through the SDK's plaintext `password` auth
variant so the SDK derives the proof-of-knowledge over the key it uses,
keeping password and key consistent by construction:
- Thread an optional plaintext password through SendApiService.save (abstraction
+ selector + legacy [ignored] + SDK impl) from the four callers that hold it
at the encrypt() call (CLI create/edit, send-ui form service, angular
add-edit).
- buildSendAuth: emit { type: "password", password } when a plaintext is present
(create / password-change); emit { type: "hashedPassword", keyB64 } only for
preserve-on-edit, where the SDK reuses the existing send key so the stored
keyB64 stays valid. The existing keyB64 is recovered from stored state via
getFromState (the freshly-encrypted Send carries none on a preserving edit).
- Plaintext password and keyB64 are Protected Data; never logged.
Verified: password create via SDK -> receive with correct password decrypts,
wrong password rejected. Unit tests cover all four buildSendAuth cases.
* [PM-38392] Only recover existing send password for password-protected edits
Address review S1: the existing-keyB64 recovery via getFromState fired on
every non-create save, including name-only edits of None/Email sends, whose
result buildSendAuth then ignores. Gate the state read on
send.authType === AuthType.Password so it only runs when the preserve-on-edit
branch can actually use it.
* Update apps/cli/src/tools/send/commands/create.command.ts
Co-authored-by: John Harrington <84741727+harr1424@users.noreply.github.com>
* Update apps/cli/src/tools/send/commands/edit.command.ts
Co-authored-by: John Harrington <84741727+harr1424@users.noreply.github.com>
---------
Co-authored-by: John Harrington <84741727+harr1424@users.noreply.github.com>
* Use global environment for self-hosted env dialog and SSO URL
Both flows run before a user is authenticated, so they must read from
the global environment; the user-scoped environment isn't populated
until login completes.
* Moved SSO callback to Auth ownership.
* update KdfRequest
* update PasswordRequest
* update changePassword() to use new PasswordRequest format
* update test setup
* update KdfRequest to include current/old masterPasswordHash
* update PasswordRequest to require current hash
* remove unused postAccountKdf() from ApiService
* rename to ChangeKdfRequest
* move ChangeKdfRequest to key-management/kdf/models/
* remove extra blank line
* update postPassword test to use new PasswordRequest format
* Update libs/common/src/key-management/kdf/models/change-kdf.request.ts
Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
---------
Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
Co-authored-by: Patrick-Pimentel-Bitwarden <ppimentel@bitwarden.com>
Co-authored-by: Dave <3836813+enmande@users.noreply.github.com>
* feat(platform): add Region.Gov and Gov entry to PRODUCTION_REGIONS [PM-38018]
Adds Gov: "Gov" to the Region const object (between EU and SelfHosted)
and appends a third entry to PRODUCTION_REGIONS alongside US and EU.
The CloudRegion type (Exclude<Region, "Self-hosted">) automatically
includes Gov.
The Gov entry uses bitwarden-gov.com as its domain with all subdomain
URLs explicit. The send URL is stored bare (no trailing /#/) per the
convention established by PM-2588 — getSendUrl() appends the hash at
read time.
Region.Gov is the foundational constant for the GovMode / FedRAMP cloud
environment work tracked under PM-35087. Flag-gated visibility in the
environment selector is introduced separately in PM-38019 via
AvailableRegionsService; this commit deliberately makes the region
unconditionally returned by EnvironmentService.availableRegions().
DEFAULT_MARKETING_EMAILS_PREF_BY_REGION in registration-start.component
gets a Gov: false entry to satisfy the Record<Region, boolean> type.
* feat: introduce AvailableRegionsService for runtime region filtering
Creates AvailableRegionsService and DefaultAvailableRegionsService in
libs/common/src/platform/. The service exposes availableRegions$, a
flag-gated Observable that wraps EnvironmentService.availableRegions()
and filters Region.Gov by the FedRampGovRegion feature flag. US and EU
are always present regardless of flag state.
EnvironmentService cannot hold this filter directly: ConfigService
depends on EnvironmentService to resolve API URLs, so wiring the
feature-flag check into EnvironmentService would create a circular
dependency. AvailableRegionsService sits above both and composes them.
The implementation uses startWith(false) so Gov is hidden until the flag
value arrives from the server. This avoids a flicker where Gov would
briefly appear during cold start before the flag resolves.
Registered in the renderer Angular DI module (covers web and desktop
renderer), the browser background script, and the CLI service container.
apps/desktop/src/main.ts intentionally excludes the service: no
main-process consumer needs a flag-gated region list, and desktop main
does not construct ConfigService, so registering here would require a
feature-flag shim to satisfy a constructor dependency with no consumer.
The accompanying spec covers four behaviors: Gov inclusion when the flag
is true, Gov exclusion when the flag is false, Gov exclusion on the
initial startWith(false) seed before the flag emits, and the US/EU
invariant across both flag states. Asserts inspect the last emission of
a take(2) window rather than firstValueFrom because the startWith(false)
seed always emits first regardless of the flag value, so asserting the
first emission would falsely pass for the wrong reason.
The selector-component migration that consumes this service lands in
a follow-up commit on the same branch. Shipping both in one PR closes
the release window where Gov could leak into the environment selector
because unmigrated selectors read EnvironmentService.availableRegions()
directly and never observe the flag.
* refactor(auth): migrate environment selector components to AvailableRegionsService
Migrates the three environment-selector components from
EnvironmentService.availableRegions() to AvailableRegionsService.
availableRegions$. Each component receives AvailableRegionsService via
constructor injection and replaces the synchronous availableRegions
array with the flag-gated Observable. All three templates switch from
synchronous-field iteration to the | async pipe.
The web selector resolves currentRegion synchronously via
EnvironmentService.availableRegions() rather than the flag-gated stream,
because origin validation must succeed regardless of flag state. The dropdown
options continue to use availableRegions$ | async. This pattern matches the
JSDoc guidance on AvailableRegionsService: the service is the UI display
source, while EnvironmentService.availableRegions() is the source for URL
resolution, origin validation, and stored-region rehydration.
The shared and registration components use combineLatest to pair the
flag-gated region list with the active-environment stream so
selectedRegion$ stays in sync with changes to either source. The
registration component's Environment import becomes unused after
combineLatest infers the type that the previous map(env: Environment)
annotation required, and is removed to satisfy ESLint's
@typescript-eslint/no-unused-vars rule.
Shipping this migration in the same PR as the AvailableRegionsService
introduction closes the release window where Gov could leak into any
client's environment selector. Unmigrated selectors read
EnvironmentService.availableRegions() directly and would surface Gov
unconditionally; migrating them in this PR makes the FedRampGovRegion
flag the single gate for selector visibility.
These three components live in Auth-owned paths
(libs/angular/src/auth/, apps/web/src/app/components/, and
libs/auth/src/angular/registration/). Auth is a required reviewer on
this PR.
* fix(auth): provide AvailableRegionsService mock in stories
* fix(auth): align env-picker dropdown icon vertically
The trigger's <bit-icon bwi-angle-down> renders inline-block with
vertical-align: baseline, which hangs below the baseline of the
line box. Combined with bitLink's tw-leading-none, this clipped
the text descenders of the "Accessing:" label on desktop and
browser login footers.
Adding tw-align-middle to the icon restores normal line-box
metrics and eliminates the clipping.
Root cause latent since PR #18816 migrated the trigger icon from
<i class="bwi"> to <bit-icon>. Web is unaffected because its
trigger uses an inline-flex <a bitLink>. This fix is
flag-independent — FedRampGovRegion only gates dropdown contents,
not the trigger label.
Refs: PM-39401
* Revert "fix(auth): align env-picker dropdown icon vertically"
This reverts commit 2d51461be9.
---------
Co-authored-by: kmancusi0105 <kmancusi@bitwarden.com>
* clean up types, fix tests
* update types
* update to SDK types
* refactor to use SDK client implementation
* bump SDK version
* refresh lock file
* Revert "refresh lock file"
This reverts commit bc32946128.
* update models for milestone 3 future work
* clean up
* more clean up
* add supportConfirmation to refresh, update doc
* clean up
* remove supportsConfirmation from update code path, rename
* fix test failures
* fix story
* Remove ConfigService references from MainBackground, jslib-services.module, and DefaultAutomaticUserConfirmationService. Update related tests to reflect these changes.
* Add OrganizationService mock to SimpleTogglePolicyComponent tests
Relocate the self-hosted environment configuration dialog from
libs/auth/src/angular/self-hosted-env-config-dialog/ to
libs/angular/src/auth/self-hosted-env-config-dialog/, with a leaf
barrel matching the destination's convention.
First slice in an effort to decompose libs/auth and reduce the
circular dependencies that motivated keeping new code out of it.
Unblocks a subsequent move of the registration subtree, which
imports this dialog from registration-env-selector.
- New leaf barrel at the destination so consumers import the
feature, not the component file.
- Source barrel entry in libs/auth/src/angular/index.ts removed.
- environment-selector.component.ts switched to a same-lib relative
import; its stale no-restricted-imports suppression was cleared
by lint:fix because the import no longer crosses libs.
- registration-env-selector.component.ts switched to a cross-lib
@bitwarden/angular/auth subpath import. This becomes a same-lib
relative once registration itself moves in the follow-up PR.
* PM-35783 - Add invite MP-options primitive to OrganizationInviteService
Adds `getMasterPasswordPolicyOptionsForInvite(invite)` to the
OrganizationInviteService abstraction and default implementation. Composes the
existing `getInvitePolicies` (cached fetch) with `policyService.combinePoliciesIntoMasterPasswordPolicyOptions`
to return the MP requirements for an invite's organization.
Adds a TODO at `WebRegistrationFinishService.getMasterPasswordPolicyOptsFromOrgInvite`
flagging future consolidation onto this new primitive once invite acceptance
becomes cross-client.
* PM-35783 - Add MP-policy resolution to ChangePasswordService
Adds `resolveMasterPasswordPolicyOptions(userId)` to the ChangePasswordService
abstraction and default implementation. Combines the user's joined-org policies
(synced state via `policyService.masterPasswordPolicyOptions$`) with any
in-flight invite's policies (via `OrganizationInviteService.getMasterPasswordPolicyOptionsForInvite`)
into the strictest applicable MP requirements.
Plumbs the new `PolicyService` + `OrganizationInviteService` constructor deps
through DefaultChangePasswordService, WebChangePasswordService,
ExtensionChangePasswordService, and the three DI modules.
No consumer yet - the change-password component still uses its inline helpers.
* PM-35783 - Delegate MP-policy resolution from ChangePasswordComponent
Replaces the inline `resolveMasterPasswordPolicyOptions` + `getInviteMasterPasswordPolicyOptions`
helpers with a single call to `changePasswordService.resolveMasterPasswordPolicyOptions(userId)`.
Domain logic now lives in the service (tested) rather than the component.
Drops `PolicyService` and `OrganizationInvite` imports + constructor injection
that are no longer needed; `OrganizationInviteService` stays - it is still used
by `logOut()` to clear the stash.
* PM-35783 - Stop writing invite policies to global policy state on login
Removes `setPoliciesIntoState` and its call site. The previous behavior wrote
the invited org's policies into `policyService` + `newPolicyService` global
state as a workaround for `/change-password` only reading from state - which
overwrote the user's actual joined-org policies (populated by the preceding
full sync) and caused the invited org's policies to leak into the vault UI
when the accept failed (e.g. Single Org policy enforcement after a
server-rejected accept).
The redirect decision still happens here off the in-memory
`orgPoliciesFromInvite.enforcedPasswordPolicyOptions`. The change-password
screen now resolves its requirements via
`ChangePasswordService.resolveMasterPasswordPolicyOptions`, which composes the
user's joined-org policies from synced state with the stashed invite's policies.
* PM-35783 - Clear stashed invite on org-invite accept failure
Adds an optional `onError` hook to `AcceptFlowConfig`, invoked from
`AcceptFlowService.handleError` before the toast + redirect (fires on both
thrown handler and invalid-link paths).
`AcceptOrganizationComponent` wires this to
`organizationInviteService.clearOrganizationInvite()`. Every server-side accept
rejection (expired, revoked, already-accepted, policy violations) is a
permanent failure, so retaining the stash would let its policies bleed into
later voluntary change-password attempts via the new
`resolveMasterPasswordPolicyOptions` fallback path.
`AcceptFlowService` stays generic over `TInvite` - the org-invite-specific
cleanup is wired by the component, not the service.
* Add changes for stripe checkout
* fix the type checkimg error
* Fix premium upgrade dialog storybook providers
* [PM-38393] bypass cloud check for stripe checkout for qa (#21212)
* feat: add DebugDisableSelfHostPremiumCheck feature flag
* feat: bypass self-host check for premium checkout behind QA flag
* test: pin self-host fallback test to bypass flag off
* feat: bypass self-host check for subscription pricing behind QA flag
Gate the subscription-pricing API calls on DebugDisableSelfHostPremiumCheck
in addition to the cloud check, so a self-hosted-region client can fetch and
display prices in the premium checkout dialog when the QA flag is enabled.
---------
Co-authored-by: Kyle Denney <4227399+kdenney@users.noreply.github.com>
* PM-38298 - Add AcceptFlowService to libs/angular
Extracts the shared param-check → auth-status → handler-dispatch →
error-handling shell from BaseAcceptComponent into a reusable, generic
Angular orchestration service. Pure addition with no consumers yet.
The component migration off BaseAcceptComponent lands in a later commit.
* PM-38298 - Relocate organization-invite to libs/common feature folder
Renames libs/common/src/auth/services/organization-invite/ to
libs/common/src/auth/organization-invite/, matching the feature-folder
convention used by password-prelogin, send-access, and two-factor.
Rewrites the ~14 repo-wide import sites in lockstep and adds an index.ts
barrel. Pure rename - no logic changes. Sets up a cleaner home for the
merged service that follows in the next commit.
* PM-38298 - Merge AcceptOrganizationInviteService into DefaultOrganizationInviteService
Eliminates the artificial state/orchestration split: the apps/web
AcceptOrganizationInviteService is absorbed into the libs/common
DefaultOrganizationInviteService, which now owns state persistence,
validate-and-accept orchestration, and policy fetching.
Key changes:
- Extends the OrganizationInviteService abstract class with
validateAndAcceptInvite and getInvitePolicies.
- Folds the WebOrganizationInviteService state backing (GlobalStateProvider
+ ORGANIZATION_INVITE KeyDefinition) into the merged impl.
- Promotes the orchestration's private getPolicies to public
getInvitePolicies, keyed by invite token, and adds full cache
invalidation on setOrganizationInvitation / clearOrganizationInvitation
so the now-app-scoped instance never serves stale entries.
- Updates the OrganizationInviteService DI registration in
jslib-services.module.ts with the impl's expanded dependency list.
- Removes the apps/web WebOrganizationInviteService provider override and
deletes the file - the libs/common impl now serves all clients.
- Adds eslint suppressions for the admin-console and key-management
imports per the existing libs/common decomposition pattern.
- Adds a libs/common spec covering state, orchestration, and cache
invariants.
AcceptOrganizationInviteService in apps/web still exists at this point;
component migration off it lands in the next commit.
* PM-38298 - Migrate AcceptOrganizationComponent off BaseAcceptComponent
Drops the BaseAcceptComponent inheritance pattern for AcceptOrganization:
the component now consumes AcceptFlowService (libs/angular) for the
orchestration shell and OrganizationInviteService (libs/common) for
invite validation and acceptance, with the same authedHandler /
unauthedHandler / "Expired token." error-mapping semantics it had as a
BaseAcceptComponent subclass.
Also:
- Converts AcceptOrganizationComponent to standalone with explicit
IconModule and I18nPipe imports for the template's bit-icon and i18n
pipe usage.
- Deletes AcceptOrganizationInviteService and its spec - the
orchestration logic now lives in the merged libs/common service.
- Deletes accept-organization.module.ts (no longer needed once the
component is standalone and its only provider, the legacy service,
is removed) and drops it from auth.module.ts.
BaseAcceptComponent and its five other subclasses are out of scope; they
keep extending the base class.
* PM-38298 - Consolidate org-invite policy-fetch consumers
Routes the duplicated "fetch org policies via invite token" pattern
through OrganizationInviteService.getInvitePolicies(invite) so callers
share one cached implementation instead of each calling
policyApiService.getPoliciesByToken directly.
Migrates four call sites:
- web-login-component.service.ts (drops the now-unused
PolicyApiServiceAbstraction injection; inline email-mismatch handling
stays).
- web-registration-finish.service.ts (drops PolicyApiServiceAbstraction
and LogService injections; error logging moves into the merged
service).
- complete-trial-initiation.component.ts (drops policyApiService and
logService injections).
- core.module.ts deps arrays updated to match the trimmed constructors;
the now-orphaned PolicyApiServiceAbstraction import is removed.
Also fixes web-login-decryption-options.service.spec.ts, which had been
importing AcceptOrganizationInviteService directly as a mock target -
swapped to OrganizationInviteService to match the production wiring and
unblock the deletion in the previous commit.
Spec updates mirror the production changes: existing it() cases that
asserted against getPoliciesByToken now assert against getInvitePolicies.
* PM-38298 - Make OrganizationInvite enforce its own contract
Replaces the loose, all-optional OrganizationInvite shape with one that
matches the server contract emitted by OrganizationUserInvitedViewModel.Url:
seven fields are always present, only orgSsoIdentifier is conditional
(server emits it only when the org has SSO + the SSO-required policy on).
Key changes:
- All seven always-present fields become non-optional. orgSsoIdentifier
stays optional.
- Adds a real constructor taking a typed data object, so partial
construction is a compile error - the previous Object.assign + empty
ctor pattern silently allowed test fixtures to omit fields.
- Adds an OrganizationInviteUrlParams interface documenting the URL
query-string shape the server emits, so the contract is captured in
code (no more spelunking the C# server file). Sets up future
open-invite-link and browser-extension URL parsers to share the type.
- Adds OrganizationInvite.fromUrlParams static factory that validates +
narrows the untyped Angular Params bag into the shape and returns
null on any missing/invalid field. Replaces the private fromParams
method that previously lived on AcceptOrganizationComponent - parsing
now lives with the domain class, where the next two consumers
(open-invite-link, browser-extension invite acceptance) can reuse it.
- fromJSON rebuilt to use the constructor.
Consumer cleanup made possible by the tightened type:
- complete-trial-initiation.component.ts drops the defensive
invite.organizationId / token / email / organizationUserId truthiness
checks. The type guarantees these are present whenever invite != null.
Test fixtures across web-registration-finish.service.spec.ts,
web-login-component.service.spec.ts, and the libs/common spec helper
all updated to construct via the new ctor. Adds a new
organization-invite.spec.ts covering the ctor, fromUrlParams (happy
path, every required-param-missing case, GUID validation, boolean
coercion, optional passthrough), and fromJSON.
* PM-38298 - Remove @ts-strict-ignore from invite-related files
Three files in the org-invite refactor footprint had carry-over
@ts-strict-ignore pragmas. tsc-strict now reports them clean - drops
the pragma + FIXME comment from each:
- libs/common/src/auth/organization-invite/default-organization-invite.service.spec.ts
- apps/web/src/app/auth/core/services/registration/web-registration-finish.service.spec.ts
- apps/web/src/app/auth/organization-invite/accept-organization.component.ts
The merged DefaultOrganizationInviteService itself still carries the
pragma - removing it there requires in-file null guards for
activeAccount$ and userKey$, plus EncString.encryptedString handling,
which is a separate follow-up.
* PM-38298 - Drop dead null guards in OrganizationInviteService
After tightening OrganizationInvite to enforce required fields at its
constructor and at every typed callsite, the runtime
`if (invite == null) throw` guards in setOrganizationInvitation and
validateAndAcceptInvite became unreachable code - the abstract class
signature already rejects null at compile time, and every consumer
either constructs an invite via the typed constructor / factory, or
narrows with `if (invite != null)` before calling.
Removes:
- The two null-throw guards in DefaultOrganizationInviteService.
- The corresponding @throws JSDoc on the abstract class.
- The two "throws when invite is null" tests, which were verifying
behavior the type system now prevents (and required passing `null`
in places the signature no longer accepts it).
No behavior change for typed callsites: the only way to reach the
removed code paths was to defeat the type system with `as any`, which
is already undefined-behavior territory.
* PM-38298 - Make DefaultOrganizationInviteService type-safe
Switch getInvitePolicies to return undefined instead of null (per the
strict-mode ADR), plumb the user ID through the accept path so we no
longer have to read it from a nullable observable, and add defensive
guards around encryption outputs that the request constructors require.
Drops the now-unused AccountService dependency.
* PM-38298 - Address code review findings on org-invite refactor
Two small follow-ups from the post-refactor review:
- Document the trust-boundary asymmetry between OrganizationInvite's two
static factories. fromUrlParams validates external URL input;
fromJSON trusts persisted state because the only write path goes
through the typed constructor, which already enforces required fields.
A short JSDoc on fromJSON makes the choice explicit so readers don't
flag the missing validation as an oversight.
- Restore the end-state assertions on two validateAndAcceptInvite cases
that lost coverage when the apps/web spec was ported to libs/common:
the initOrganization=true path and the no-MP-policy accept path both
now verify the invite is cleared from state after acceptance. Brings
them in line with the other "happy-path accept" cases that already
check `expect(stored).toBeNull()`.
* PM-38298 - Fill org-invite test gaps
Cover the type-safety guards added in c475c541be and a few cache/edge
cases that were not exercised:
- DefaultOrganizationInviteService: throws when any encrypted output is
null in acceptAndInitOrganization (3 cases); throws when org keys
fetch returns null, user key is null, or the encapsulated user key is
null in the reset-password enrollment path (3 cases); getInvitePolicies
scopes its cache by invite token and does not cache null API results.
- AcceptFlowService: AuthenticationStatus.Locked routes to authedHandler;
non-Error throws fall through to the full failed-message path; null
queryParams is treated as a missing-param error.
* PM-38298 - Skip stale-invite clear when no invite is stored
* PM-38298 - Refactor AcceptFlowService to typed-parse shape
Move URL parsing into AcceptFlowService via a required parse callback
and dispatch the parsed result as a typed TInvite to both handlers.
Symmetric try/catch around authedHandler and unauthedHandler so error
handling no longer asymmetrically depends on which branch the user
lands in.
AcceptOrganizationComponent loses its requiredParameters field, its
handleInvalidInvite method, and both inline 'if (invite === null)'
guards; OrganizationInvite.fromUrlParams (validates presence + GUID
format) is now the single source of truth for invalid-link detection,
strictly stronger than the prior presence-only string-array check.
* PM-38298 - Add JSDoc to AcceptFlowService
* PM-38298 - Add JSDoc class headers to org-invite contracts
* PM-38298 - Remove dead org-invite policy lookup from trial initiation
* PM-38298 - Document policy cache in OrganizationInviteService
* PM-38298 - Rename OrganizationInvitation methods to OrganizationInvite
* PM-38298 - Document organization invite acceptance flows
* PM-38298 - Flag MP-policy logout branch for reachability investigation
* PM-38298 - Document MP-policy logout branch reachability
Replace the reachability TODO on validateAndAcceptInvite's MP-policy
logout branch with an inline explanation of the trigger (authed user
pastes the accept-invite URL into a signed-in session). Extend the
flow docs with the same scenario and align the SSO acceptance bullets
with the application's "member decryption option" terminology, plus a
scope note on the global single-slot stash.
* PM-38298 - Clarify init-organization invite scenario in flows doc
* PM-39073 - Surface ErrorResponse messages from accept flow
Recognize ErrorResponse alongside Error in AcceptFlowService's catch block
so server-side messages reach the toast instead of being dropped. ErrorResponse
extends BaseResponse, not Error, so the prior `instanceof Error` guard lost
the API message and fell back to the generic invite-failed string.
* Add state service for V2UpgradeToken
* Update clear to not write to disk every call
* Fix unit test
* Add V2UpgradeToken handling to sync
* Add passing V2UpgradeToken to SDK unlocks
* Fix new DefaultUnlockService in main background
---------
Co-authored-by: Bernd Schoolmann <mail@quexten.com>
* [CL-1046] Add no-bit-dialog-wrapper lint rule
Errors when <bit-dialog> or <bit-simple-dialog> appears inside any
parent HTML element. The dialog selector should be applied as an
attribute on the root element (e.g. <form bit-dialog>) so that the
form receives the dialog's height styling.
* Migrate admin console dialogs to new form pattern
Updates organization member, group, collection, provider, and domain verification dialogs to use <form bit-dialog> pattern following the component library updates.
* Migrate auth settings dialogs to new form pattern
Updates two-factor authentication, WebAuthn, and emergency access dialogs to use <form bit-dialog> pattern following the component library updates.
* Migrate Secrets Manager dialogs to new form pattern
Updates project, service account, access token, and secret dialogs to use <form bit-dialog> pattern following the component library updates.
* Migrate remaining dialogs to new form pattern
Applies the <form bit-dialog> / <form bit-simple-dialog> attribute selector
pattern to the rest of the codebase, satisfying the no-bit-dialog-wrapper
lint rule. 55 templates across auth, admin console, billing, vault,
key management, secrets manager, provider, dirt integrations, importer,
browser, and desktop apps.
* Migrate key rotation dialog to new form pattern
* [PM-37229] Add bwi-passport icon and wire it to the passport cipher type
* Fix icons:build script to compile style.css and avoid duplicate SCSS keys
* [PM-37229] Update passport cipher icon tests to expect bwi-passport
* Refactor password strength component for improved performance and readability
- Introduced ChangeDetectorRef to optimize rendering in response to input changes.
- Consolidated visual update logic into a separate method for clarity.
- Enhanced handling of password strength calculations and visual feedback.
- Ensured real-time updates for password strength in the input-password component.
* Enhance password strength component's ngOnChanges method for better performance
- Updated ngOnChanges to debounce rendering only for email or name changes, avoiding unnecessary renders for password updates.
- Improved clarity of the method by explicitly handling password changes.
* Update tests for PasswordStrengthV2Component to include email change handling
- Modified ngOnChanges test cases to simulate email changes using SimpleChange.
- Ensured that password score emissions are correctly tested when email input is updated.
* improve type safter for invite link, add allowed domains field, wire up local state
* clean up
* fix reactivity
* clean up
* wip
* fix 404 handling, remove redundant signal
* add shareReplay
* update tests
* fix tests
* fix template, state clearing, more guards, clean up
* clean up
* cache org link by ID
* clean up
* clean up
* fix copy
* clean up
* more clean up