mirror of
https://github.com/bitwarden/browser
synced 2026-02-07 04:03:29 +00:00
Merge branch 'main' into pm-18701-optional-payment-modal-after-signup
This commit is contained in:
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -140,6 +140,7 @@ libs/components @bitwarden/team-ui-foundation
|
||||
libs/ui @bitwarden/team-ui-foundation
|
||||
apps/browser/src/platform/popup/layout @bitwarden/team-ui-foundation
|
||||
apps/browser/src/popup/app-routing.animations.ts @bitwarden/team-ui-foundation
|
||||
apps/browser/src/popup/components/extension-anon-layout-wrapper @bitwarden/team-ui-foundation
|
||||
apps/web/src/app/layouts @bitwarden/team-ui-foundation
|
||||
|
||||
|
||||
|
||||
102
.github/workflows/repository-management.yml
vendored
102
.github/workflows/repository-management.yml
vendored
@@ -36,8 +36,7 @@ on:
|
||||
description: "New version override (leave blank for automatic calculation, example: '2024.1.0')"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
setup:
|
||||
name: Setup
|
||||
@@ -57,51 +56,11 @@ jobs:
|
||||
fi
|
||||
|
||||
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
cut_branch:
|
||||
name: Cut branch
|
||||
if: ${{ needs.setup.outputs.branch == 'rc' }}
|
||||
needs: setup
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Generate GH App token
|
||||
uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.BW_GHAPP_ID }}
|
||||
private-key: ${{ secrets.BW_GHAPP_KEY }}
|
||||
|
||||
- name: Check out target ref
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ inputs.target_ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- name: Check if ${{ needs.setup.outputs.branch }} branch exists
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.setup.outputs.branch }}
|
||||
run: |
|
||||
if [[ $(git ls-remote --heads origin $BRANCH_NAME) ]]; then
|
||||
echo "$BRANCH_NAME already exists! Please delete $BRANCH_NAME before running again." >> $GITHUB_STEP_SUMMARY
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Cut branch
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.setup.outputs.branch }}
|
||||
run: |
|
||||
git switch --quiet --create $BRANCH_NAME
|
||||
git push --quiet --set-upstream origin $BRANCH_NAME
|
||||
|
||||
|
||||
bump_version:
|
||||
name: Bump Version
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- cut_branch
|
||||
- setup
|
||||
needs: setup
|
||||
outputs:
|
||||
version_browser: ${{ steps.set-final-version-output.outputs.version_browser }}
|
||||
version_cli: ${{ steps.set-final-version-output.outputs.version_cli }}
|
||||
@@ -441,15 +400,13 @@ jobs:
|
||||
- name: Push changes
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||
run: git push
|
||||
|
||||
|
||||
cherry_pick:
|
||||
name: Cherry-Pick Commit(s)
|
||||
cut_branch:
|
||||
name: Cut branch
|
||||
if: ${{ needs.setup.outputs.branch == 'rc' }}
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- bump_version
|
||||
- setup
|
||||
- bump_version
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Generate GH App token
|
||||
uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3
|
||||
@@ -458,43 +415,24 @@ jobs:
|
||||
app-id: ${{ secrets.BW_GHAPP_ID }}
|
||||
private-key: ${{ secrets.BW_GHAPP_KEY }}
|
||||
|
||||
- name: Check out main branch
|
||||
- name: Check out target ref
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: main
|
||||
ref: ${{ inputs.target_ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- name: Configure Git
|
||||
- name: Check if ${{ needs.setup.outputs.branch }} branch exists
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.setup.outputs.branch }}
|
||||
run: |
|
||||
git config --local user.email "actions@github.com"
|
||||
git config --local user.name "Github Actions"
|
||||
if [[ $(git ls-remote --heads origin $BRANCH_NAME) ]]; then
|
||||
echo "$BRANCH_NAME already exists! Please delete $BRANCH_NAME before running again." >> $GITHUB_STEP_SUMMARY
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Perform cherry-pick(s)
|
||||
- name: Cut branch
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.setup.outputs.branch }}
|
||||
run: |
|
||||
# Function for cherry-picking
|
||||
cherry_pick () {
|
||||
local package_path="apps/$1/package.json"
|
||||
local source_branch=$2
|
||||
local destination_branch=$3
|
||||
|
||||
# Get project commit/version from source branch
|
||||
git switch $source_branch
|
||||
SOURCE_COMMIT=$(git log --reverse --pretty=format:"%H" --max-count=1 $package_path)
|
||||
SOURCE_VERSION=$(cat $package_path | jq -r '.version')
|
||||
|
||||
# Get project commit/version from destination branch
|
||||
git switch $destination_branch
|
||||
DESTINATION_VERSION=$(cat $package_path | jq -r '.version')
|
||||
|
||||
if [[ "$DESTINATION_VERSION" != "$SOURCE_VERSION" ]]; then
|
||||
git cherry-pick --strategy-option=theirs -x $SOURCE_COMMIT
|
||||
git push -u origin $destination_branch
|
||||
fi
|
||||
}
|
||||
|
||||
# Cherry-pick from 'main' into 'rc'
|
||||
cherry_pick browser main rc
|
||||
cherry_pick cli main rc
|
||||
cherry_pick desktop main rc
|
||||
cherry_pick web main rc
|
||||
git switch --quiet --create $BRANCH_NAME
|
||||
git push --quiet --set-upstream origin $BRANCH_NAME
|
||||
@@ -5062,6 +5062,9 @@
|
||||
"unlockPinSet": {
|
||||
"message": "Unlock PIN set"
|
||||
},
|
||||
"unlockBiometricSet": {
|
||||
"message": "Unlock biometrics set"
|
||||
},
|
||||
"authenticating": {
|
||||
"message": "Authenticating"
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
|
||||
import { BrowserPlatformUtilsService } from "../../../platform/services/platform-utils/browser-platform-utils.service";
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "../extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "../../../popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
|
||||
|
||||
import { ExtensionLoginComponentService } from "./extension-login-component.service";
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "../extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "../../../popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
|
||||
|
||||
@Injectable()
|
||||
export class ExtensionLoginComponentService
|
||||
|
||||
@@ -534,6 +534,11 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
|
||||
if (!successful) {
|
||||
await this.biometricStateService.setFingerprintValidated(false);
|
||||
}
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("unlockBiometricSet"),
|
||||
});
|
||||
} catch (error) {
|
||||
this.form.controls.biometric.setValue(false);
|
||||
this.validationService.showError(error);
|
||||
|
||||
@@ -88,6 +88,7 @@ export class WebauthnUtils {
|
||||
getClientExtensionResults: () => ({
|
||||
credProps: result.extensions.credProps,
|
||||
}),
|
||||
toJSON: () => Fido2Utils.createResultToJson(result),
|
||||
} as PublicKeyCredential;
|
||||
|
||||
// Modify prototype chains to fix `instanceof` calls.
|
||||
@@ -134,6 +135,7 @@ export class WebauthnUtils {
|
||||
} as AuthenticatorAssertionResponse,
|
||||
getClientExtensionResults: () => ({}),
|
||||
authenticatorAttachment: "platform",
|
||||
toJSON: () => Fido2Utils.getResultToJson(result),
|
||||
} as PublicKeyCredential;
|
||||
|
||||
// Modify prototype chains to fix `instanceof` calls.
|
||||
|
||||
@@ -105,9 +105,11 @@ export class PopupRouterCacheService {
|
||||
* Navigate back in history
|
||||
*/
|
||||
async back() {
|
||||
await this.state.update((prevState) => (prevState ? prevState.slice(0, -1) : []));
|
||||
const history = await this.state.update((prevState) =>
|
||||
prevState ? prevState.slice(0, -1) : [],
|
||||
);
|
||||
|
||||
if (this.hasNavigated) {
|
||||
if (this.hasNavigated && history.length) {
|
||||
this.location.back();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,7 @@ import {
|
||||
unauthGuardFn,
|
||||
} from "@bitwarden/angular/auth/guards";
|
||||
import {
|
||||
AnonLayoutWrapperComponent,
|
||||
AnonLayoutWrapperData,
|
||||
DevicesIcon,
|
||||
LockIcon,
|
||||
LoginComponent,
|
||||
LoginDecryptionOptionsComponent,
|
||||
LoginSecondaryContentComponent,
|
||||
@@ -41,13 +38,10 @@ import {
|
||||
UserLockIcon,
|
||||
VaultIcon,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components";
|
||||
import { LockComponent } from "@bitwarden/key-management-ui";
|
||||
|
||||
import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component";
|
||||
import {
|
||||
ExtensionAnonLayoutWrapperComponent,
|
||||
ExtensionAnonLayoutWrapperData,
|
||||
} from "../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component";
|
||||
import { fido2AuthGuard } from "../auth/popup/guards/fido2-auth.guard";
|
||||
import { SetPasswordComponent } from "../auth/popup/set-password.component";
|
||||
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
|
||||
@@ -89,6 +83,10 @@ import { TrashComponent } from "../vault/popup/settings/trash.component";
|
||||
import { VaultSettingsV2Component } from "../vault/popup/settings/vault-settings-v2.component";
|
||||
|
||||
import { RouteElevation } from "./app-routing.animations";
|
||||
import {
|
||||
ExtensionAnonLayoutWrapperComponent,
|
||||
ExtensionAnonLayoutWrapperData,
|
||||
} from "./components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component";
|
||||
import { debounceNavigationGuard } from "./services/debounce-navigation.service";
|
||||
import { TabsV2Component } from "./tabs-v2.component";
|
||||
|
||||
@@ -504,7 +502,7 @@ const routes: Routes = [
|
||||
path: "lock",
|
||||
canActivate: [lockGuard()],
|
||||
data: {
|
||||
pageIcon: LockIcon,
|
||||
pageIcon: Icons.LockIcon,
|
||||
pageTitle: {
|
||||
key: "yourVaultIsLockedV2",
|
||||
},
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
|
||||
import { AccountComponent } from "../auth/popup/account-switching/account.component";
|
||||
import { CurrentAccountComponent } from "../auth/popup/account-switching/current-account.component";
|
||||
import { ExtensionAnonLayoutWrapperComponent } from "../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component";
|
||||
import { SetPasswordComponent } from "../auth/popup/set-password.component";
|
||||
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
|
||||
import { VaultTimeoutInputComponent } from "../auth/popup/settings/vault-timeout-input.component";
|
||||
@@ -44,6 +43,7 @@ import { FilePopoutCalloutComponent } from "../tools/popup/components/file-popou
|
||||
|
||||
import { AppRoutingModule } from "./app-routing.module";
|
||||
import { AppComponent } from "./app.component";
|
||||
import { ExtensionAnonLayoutWrapperComponent } from "./components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component";
|
||||
import { UserVerificationComponent } from "./components/user-verification.component";
|
||||
import { ServicesModule } from "./services/services.module";
|
||||
import { TabsV2Component } from "./tabs-v2.component";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Observable, Subject } from "rxjs";
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
DefaultAnonLayoutWrapperDataService,
|
||||
} from "@bitwarden/auth/angular";
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { ExtensionAnonLayoutWrapperData } from "./extension-anon-layout-wrapper.component";
|
||||
|
||||
@@ -5,22 +5,23 @@ import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Data, NavigationEnd, Router, RouterModule } from "@angular/router";
|
||||
import { Subject, filter, switchMap, takeUntil, tap } from "rxjs";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import {
|
||||
Icon,
|
||||
Icons,
|
||||
IconModule,
|
||||
Translation,
|
||||
AnonLayoutComponent,
|
||||
AnonLayoutWrapperData,
|
||||
AnonLayoutWrapperDataService,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Icon, IconModule, Translation } from "@bitwarden/components";
|
||||
} from "@bitwarden/components";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
||||
import { AccountSwitcherService } from "../../../auth/popup/account-switching/services/account-switcher.service";
|
||||
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
||||
import { CurrentAccountComponent } from "../account-switching/current-account.component";
|
||||
import { AccountSwitcherService } from "../account-switching/services/account-switcher.service";
|
||||
|
||||
import { ExtensionBitwardenLogo } from "./extension-bitwarden-logo.icon";
|
||||
|
||||
export interface ExtensionAnonLayoutWrapperData extends AnonLayoutWrapperData {
|
||||
showAcctSwitcher?: boolean;
|
||||
@@ -61,7 +62,7 @@ export class ExtensionAnonLayoutWrapperComponent implements OnInit, OnDestroy {
|
||||
protected hideFooter: boolean;
|
||||
|
||||
protected theme: string;
|
||||
protected logo = ExtensionBitwardenLogo;
|
||||
protected logo = Icons.ExtensionBitwardenLogo;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
} from "@storybook/angular";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { AnonLayoutWrapperDataService, LockIcon } from "@bitwarden/auth/angular";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service";
|
||||
@@ -23,13 +22,15 @@ import {
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { ButtonModule, I18nMockService } from "@bitwarden/components";
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
ButtonModule,
|
||||
Icons,
|
||||
I18nMockService,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { RegistrationCheckEmailIcon } from "../../../../../../libs/auth/src/angular/icons/registration-check-email.icon";
|
||||
import { AccountSwitcherService } from "../../../auth/popup/account-switching/services/account-switcher.service";
|
||||
import { PopupRouterCacheService } from "../../../platform/popup/view-cache/popup-router-cache.service";
|
||||
import { AccountSwitcherService } from "../account-switching/services/account-switcher.service";
|
||||
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "./extension-anon-layout-wrapper-data.service";
|
||||
import {
|
||||
@@ -38,7 +39,7 @@ import {
|
||||
} from "./extension-anon-layout-wrapper.component";
|
||||
|
||||
export default {
|
||||
title: "Auth/Extension Anon Layout Wrapper",
|
||||
title: "Browser/Extension Anon Layout Wrapper",
|
||||
component: ExtensionAnonLayoutWrapperComponent,
|
||||
} as Meta;
|
||||
|
||||
@@ -142,6 +143,8 @@ const decorators = (options: {
|
||||
switchAccounts: "Switch accounts",
|
||||
back: "Back",
|
||||
activeAccount: "Active account",
|
||||
appLogoLabel: "app logo label",
|
||||
bitwardenAccount: "Bitwarden Account",
|
||||
});
|
||||
},
|
||||
},
|
||||
@@ -241,7 +244,7 @@ const initialData: ExtensionAnonLayoutWrapperData = {
|
||||
pageSubtitle: {
|
||||
key: "finishCreatingYourAccountBySettingAPassword",
|
||||
},
|
||||
pageIcon: LockIcon,
|
||||
pageIcon: Icons.LockIcon,
|
||||
showAcctSwitcher: true,
|
||||
showBackButton: true,
|
||||
showLogo: true,
|
||||
@@ -255,7 +258,7 @@ const changedData: ExtensionAnonLayoutWrapperData = {
|
||||
pageSubtitle: {
|
||||
key: "checkYourEmail",
|
||||
},
|
||||
pageIcon: RegistrationCheckEmailIcon,
|
||||
pageIcon: Icons.RegistrationCheckEmailIcon,
|
||||
showAcctSwitcher: false,
|
||||
showBackButton: false,
|
||||
showLogo: false,
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
} from "@bitwarden/angular/services/injection-tokens";
|
||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
LoginComponentService,
|
||||
TwoFactorAuthComponentService,
|
||||
TwoFactorAuthEmailComponentService,
|
||||
@@ -121,7 +120,12 @@ import {
|
||||
} from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||
import { CompactModeService, DialogService, ToastService } from "@bitwarden/components";
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
CompactModeService,
|
||||
DialogService,
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
import {
|
||||
BiometricsService,
|
||||
@@ -138,7 +142,6 @@ import {
|
||||
|
||||
import { AccountSwitcherService } from "../../auth/popup/account-switching/services/account-switcher.service";
|
||||
import { ForegroundLockService } from "../../auth/popup/accounts/foreground-lock.service";
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "../../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
|
||||
import { ExtensionLoginComponentService } from "../../auth/popup/login/extension-login-component.service";
|
||||
import { ExtensionSsoComponentService } from "../../auth/popup/login/extension-sso-component.service";
|
||||
import { ExtensionLogoutService } from "../../auth/popup/logout/extension-logout.service";
|
||||
@@ -181,6 +184,7 @@ import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-u
|
||||
import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service";
|
||||
import { VaultBrowserStateService } from "../../vault/services/vault-browser-state.service";
|
||||
import { VaultFilterService } from "../../vault/services/vault-filter.service";
|
||||
import { ExtensionAnonLayoutWrapperDataService } from "../components/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
|
||||
|
||||
import { DebounceNavigationService } from "./debounce-navigation.service";
|
||||
import { InitService } from "./init.service";
|
||||
|
||||
@@ -16,11 +16,8 @@ import {
|
||||
} from "@bitwarden/angular/auth/guards";
|
||||
import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route";
|
||||
import {
|
||||
AnonLayoutWrapperComponent,
|
||||
AnonLayoutWrapperData,
|
||||
LoginComponent,
|
||||
LoginSecondaryContentComponent,
|
||||
LockIcon,
|
||||
LoginViaAuthRequestComponent,
|
||||
PasswordHintComponent,
|
||||
RegistrationFinishComponent,
|
||||
@@ -42,6 +39,7 @@ import {
|
||||
DeviceVerificationIcon,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components";
|
||||
import { LockComponent } from "@bitwarden/key-management-ui";
|
||||
|
||||
import { maxAccountsGuardFn } from "../auth/guards/max-accounts.guard";
|
||||
@@ -292,7 +290,7 @@ const routes: Routes = [
|
||||
path: "lock",
|
||||
canActivate: [lockGuard()],
|
||||
data: {
|
||||
pageIcon: LockIcon,
|
||||
pageIcon: Icons.LockIcon,
|
||||
pageTitle: {
|
||||
key: "yourVaultIsLockedV2",
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
||||
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
||||
import { CalloutModule, DialogModule } from "@bitwarden/components";
|
||||
import { AssignCollectionsComponent } from "@bitwarden/vault";
|
||||
|
||||
import { DeleteAccountComponent } from "../auth/delete-account.component";
|
||||
import { LoginModule } from "../auth/login/login.module";
|
||||
@@ -55,6 +56,7 @@ import { SharedModule } from "./shared/shared.module";
|
||||
DeleteAccountComponent,
|
||||
UserVerificationComponent,
|
||||
NavComponent,
|
||||
AssignCollectionsComponent,
|
||||
VaultV2Component,
|
||||
],
|
||||
declarations: [
|
||||
|
||||
@@ -3812,5 +3812,139 @@
|
||||
"message": "Learn more about SSH agent",
|
||||
"description": "Two part message",
|
||||
"example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent"
|
||||
},
|
||||
"assignToCollections": {
|
||||
"message": "Assign to collections"
|
||||
},
|
||||
"assignToTheseCollections": {
|
||||
"message": "Assign to these collections"
|
||||
},
|
||||
"bulkCollectionAssignmentDialogDescriptionSingular": {
|
||||
"message": "Only organization members with access to these collections will be able to see the item."
|
||||
},
|
||||
"bulkCollectionAssignmentDialogDescriptionPlural": {
|
||||
"message": "Only organization members with access to these collections will be able to see the items."
|
||||
},
|
||||
"noCollectionsAssigned": {
|
||||
"message": "No collections have been assigned"
|
||||
},
|
||||
"assign": {
|
||||
"message": "Assign"
|
||||
},
|
||||
"bulkCollectionAssignmentDialogDescription": {
|
||||
"message": "Only organization members with access to these collections will be able to see the items."
|
||||
},
|
||||
"bulkCollectionAssignmentWarning": {
|
||||
"message": "You have selected $TOTAL_COUNT$ items. You cannot update $READONLY_COUNT$ of the items because you do not have edit permissions.",
|
||||
"placeholders": {
|
||||
"total_count": {
|
||||
"content": "$1",
|
||||
"example": "10"
|
||||
},
|
||||
"readonly_count": {
|
||||
"content": "$2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"selectCollectionsToAssign": {
|
||||
"message": "Select collections to assign"
|
||||
},
|
||||
"personalItemsTransferWarning": {
|
||||
"message": "$PERSONAL_ITEMS_COUNT$ will be permanently transferred to the selected organization. You will no longer own these items.",
|
||||
"placeholders": {
|
||||
"personal_items_count": {
|
||||
"content": "$1",
|
||||
"example": "2 items"
|
||||
}
|
||||
}
|
||||
},
|
||||
"personalItemsWithOrgTransferWarning": {
|
||||
"message": "$PERSONAL_ITEMS_COUNT$ will be permanently transferred to $ORG$. You will no longer own these items.",
|
||||
"placeholders": {
|
||||
"personal_items_count": {
|
||||
"content": "$1",
|
||||
"example": "2 items"
|
||||
},
|
||||
"org": {
|
||||
"content": "$2",
|
||||
"example": "Organization name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"personalItemTransferWarningSingular": {
|
||||
"message": "1 item will be permanently transferred to the selected organization. You will no longer own this item."
|
||||
},
|
||||
"personalItemWithOrgTransferWarningSingular": {
|
||||
"message": "1 item will be permanently transferred to $ORG$. You will no longer own this item.",
|
||||
"placeholders": {
|
||||
"org": {
|
||||
"content": "$1",
|
||||
"example": "Organization name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"successfullyAssignedCollections": {
|
||||
"message": "Successfully assigned collections"
|
||||
},
|
||||
"nothingSelected": {
|
||||
"message": "You have not selected anything."
|
||||
},
|
||||
"itemsMovedToOrg": {
|
||||
"message": "Items moved to $ORGNAME$",
|
||||
"placeholders": {
|
||||
"orgname": {
|
||||
"content": "$1",
|
||||
"example": "Company Name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"itemMovedToOrg": {
|
||||
"message": "Item moved to $ORGNAME$",
|
||||
"placeholders": {
|
||||
"orgname": {
|
||||
"content": "$1",
|
||||
"example": "Company Name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"movedItemsToOrg": {
|
||||
"message": "Selected items moved to $ORGNAME$",
|
||||
"placeholders": {
|
||||
"orgname": {
|
||||
"content": "$1",
|
||||
"example": "Company Name"
|
||||
}
|
||||
},
|
||||
"personalItemsTransferWarningPlural": {
|
||||
"message": "$PERSONAL_ITEMS_COUNT$ items will be permanently transferred to the selected organization. You will no longer own these items.",
|
||||
"placeholders": {
|
||||
"personal_items_count": {
|
||||
"content": "$1",
|
||||
"example": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"personalItemWithOrgTransferWarningSingular": {
|
||||
"message": "1 item will be permanently transferred to $ORG$. You will no longer own this item.",
|
||||
"placeholders": {
|
||||
"org": {
|
||||
"content": "$1",
|
||||
"example": "Organization name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"personalItemsWithOrgTransferWarningPlural": {
|
||||
"message": "$PERSONAL_ITEMS_COUNT$ items will be permanently transferred to $ORG$. You will no longer own these items.",
|
||||
"placeholders": {
|
||||
"personal_items_count": {
|
||||
"content": "$1",
|
||||
"example": "2"
|
||||
},
|
||||
"org": {
|
||||
"content": "$2",
|
||||
"example": "Organization name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<bit-dialog dialogSize="large">
|
||||
<span bitDialogTitle>
|
||||
{{ "assignToCollections" | i18n }}
|
||||
<span class="tw-text-sm tw-normal-case tw-text-muted">
|
||||
{{ editableItemCount | pluralize: ("item" | i18n) : ("items" | i18n) }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div bitDialogContent>
|
||||
<assign-collections
|
||||
[params]="params"
|
||||
[submitBtn]="assignSubmitButton"
|
||||
(onCollectionAssign)="onCollectionAssign($event)"
|
||||
(editableItemCountChange)="editableItemCount = $event"
|
||||
></assign-collections>
|
||||
</div>
|
||||
|
||||
<ng-container bitDialogFooter>
|
||||
<button
|
||||
#assignSubmitButton
|
||||
form="assign_collections_form"
|
||||
type="submit"
|
||||
bitButton
|
||||
bitFormButton
|
||||
buttonType="primary"
|
||||
>
|
||||
{{ "assign" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitButton buttonType="secondary" bitDialogClose>
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
@@ -0,0 +1,36 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { PluralizePipe } from "@bitwarden/angular/pipes/pluralize.pipe";
|
||||
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
|
||||
import {
|
||||
AssignCollectionsComponent,
|
||||
CollectionAssignmentParams,
|
||||
CollectionAssignmentResult,
|
||||
} from "@bitwarden/vault";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
templateUrl: "./assign-collections-desktop.component.html",
|
||||
imports: [AssignCollectionsComponent, PluralizePipe, DialogModule, ButtonModule, JslibModule],
|
||||
})
|
||||
export class AssignCollectionsDesktopComponent {
|
||||
protected editableItemCount: number;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) public params: CollectionAssignmentParams,
|
||||
private dialogRef: DialogRef<CollectionAssignmentResult>,
|
||||
) {}
|
||||
|
||||
protected async onCollectionAssign(result: CollectionAssignmentResult) {
|
||||
this.dialogRef.close(result);
|
||||
}
|
||||
|
||||
static open(dialogService: DialogService, config: DialogConfig<CollectionAssignmentParams>) {
|
||||
return dialogService.open<CollectionAssignmentResult, CollectionAssignmentParams>(
|
||||
AssignCollectionsDesktopComponent,
|
||||
config,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./assign-collections-desktop.component";
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ViewContainerRef,
|
||||
} from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom, Subject, takeUntil, switchMap, lastValueFrom } from "rxjs";
|
||||
import { firstValueFrom, Subject, takeUntil, switchMap, lastValueFrom, Observable } from "rxjs";
|
||||
import { filter, map, take } from "rxjs/operators";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
@@ -19,6 +19,8 @@ import { VaultViewPasswordHistoryService } from "@bitwarden/angular/services/vie
|
||||
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
@@ -57,6 +59,7 @@ import {
|
||||
CipherFormMode,
|
||||
CipherFormModule,
|
||||
CipherViewComponent,
|
||||
CollectionAssignmentResult,
|
||||
DecryptionFailureDialogComponent,
|
||||
DefaultChangeLoginPasswordService,
|
||||
DefaultCipherFormConfigService,
|
||||
@@ -69,6 +72,7 @@ import { DesktopCredentialGenerationService } from "../../../services/desktop-ci
|
||||
import { DesktopPremiumUpgradePromptService } from "../../../services/desktop-premium-upgrade-prompt.service";
|
||||
import { invokeMenu, RendererMenuItem } from "../../../utils";
|
||||
|
||||
import { AssignCollectionsDesktopComponent } from "./assign-collections";
|
||||
import { ItemFooterComponent } from "./item-footer.component";
|
||||
import { VaultFilterComponent } from "./vault-filter/vault-filter.component";
|
||||
import { VaultFilterModule } from "./vault-filter/vault-filter.module";
|
||||
@@ -142,6 +146,11 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
config: CipherFormConfig | null = null;
|
||||
isSubmitting = false;
|
||||
|
||||
private organizations$: Observable<Organization[]> = this.accountService.activeAccount$.pipe(
|
||||
map((a) => a?.id),
|
||||
switchMap((id) => this.organizationService.organizations$(id)),
|
||||
);
|
||||
|
||||
protected canAccessAttachments$ = this.accountService.activeAccount$.pipe(
|
||||
filter((account): account is Account => !!account),
|
||||
switchMap((account) =>
|
||||
@@ -151,6 +160,8 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
|
||||
private modal: ModalRef | null = null;
|
||||
private componentIsDestroyed$ = new Subject<boolean>();
|
||||
private allOrganizations: Organization[] = [];
|
||||
private allCollections: CollectionView[] = [];
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
@@ -176,6 +187,7 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
private formConfigService: CipherFormConfigService,
|
||||
private premiumUpgradePromptService: PremiumUpgradePromptService,
|
||||
private collectionService: CollectionService,
|
||||
private organizationService: OrganizationService,
|
||||
private folderService: FolderService,
|
||||
) {}
|
||||
|
||||
@@ -312,6 +324,16 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.organizations$.pipe(takeUntil(this.componentIsDestroyed$)).subscribe((orgs) => {
|
||||
this.allOrganizations = orgs;
|
||||
});
|
||||
|
||||
this.collectionService.decryptedCollections$
|
||||
.pipe(takeUntil(this.componentIsDestroyed$))
|
||||
.subscribe((collections) => {
|
||||
this.allCollections = collections;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -364,7 +386,14 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
cipher.collectionIds.includes(c.id),
|
||||
) ?? null;
|
||||
this.action = "view";
|
||||
|
||||
await this.go().catch(() => {});
|
||||
await this.eventCollectionService.collect(
|
||||
EventType.Cipher_ClientViewed,
|
||||
cipher.id,
|
||||
false,
|
||||
cipher.organizationId,
|
||||
);
|
||||
}
|
||||
|
||||
async openAttachmentsDialog() {
|
||||
@@ -420,6 +449,16 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (cipher.canAssignToCollections) {
|
||||
menu.push({
|
||||
label: this.i18nService.t("assignToCollections"),
|
||||
click: () =>
|
||||
this.functionWithChangeDetection(async () => {
|
||||
await this.shareCipher(cipher);
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
switch (cipher.type) {
|
||||
@@ -531,6 +570,36 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
await this.go().catch(() => {});
|
||||
}
|
||||
|
||||
async shareCipher(cipher: CipherView) {
|
||||
if (!cipher) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("nothingSelected"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await this.passwordReprompt(cipher))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const availableCollections = this.getAvailableCollections(cipher);
|
||||
|
||||
const dialog = AssignCollectionsDesktopComponent.open(this.dialogService, {
|
||||
data: {
|
||||
ciphers: [cipher],
|
||||
organizationId: cipher.organizationId as OrganizationId,
|
||||
availableCollections,
|
||||
},
|
||||
});
|
||||
|
||||
const result = await lastValueFrom(dialog.closed);
|
||||
if (result === CollectionAssignmentResult.Saved) {
|
||||
await this.savedCipher(cipher);
|
||||
}
|
||||
}
|
||||
|
||||
async addCipher(type: CipherType) {
|
||||
if (this.action === "add") {
|
||||
return;
|
||||
@@ -603,6 +672,16 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
||||
await this.go().catch(() => {});
|
||||
}
|
||||
|
||||
private getAvailableCollections(cipher: CipherView): CollectionView[] {
|
||||
const orgId = cipher.organizationId;
|
||||
if (!orgId || orgId === "MyVault") {
|
||||
return [];
|
||||
}
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === orgId);
|
||||
return this.allCollections.filter((c) => c.organizationId === organization?.id && !c.readOnly);
|
||||
}
|
||||
|
||||
private calculateSearchBarLocalizationString(vaultFilter: VaultFilter): string {
|
||||
if (vaultFilter.status === "favorites") {
|
||||
return "searchFavorites";
|
||||
|
||||
@@ -17,7 +17,6 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
||||
import { deepLinkGuard } from "../../auth/guards/deep-link/deep-link.guard";
|
||||
|
||||
import { VaultModule } from "./collections/vault.module";
|
||||
import { isEnterpriseOrgGuard } from "./guards/is-enterprise-org.guard";
|
||||
import { organizationPermissionsGuard } from "./guards/org-permissions.guard";
|
||||
import { organizationRedirectGuard } from "./guards/org-redirect.guard";
|
||||
import { AdminConsoleIntegrationsComponent } from "./integrations/integrations.component";
|
||||
@@ -42,10 +41,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: "integrations",
|
||||
canActivate: [
|
||||
isEnterpriseOrgGuard(false),
|
||||
organizationPermissionsGuard(canAccessIntegrations),
|
||||
],
|
||||
canActivate: [organizationPermissionsGuard(canAccessIntegrations)],
|
||||
component: AdminConsoleIntegrationsComponent,
|
||||
data: {
|
||||
titleId: "integrations",
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
import { Component, inject } from "@angular/core";
|
||||
import { Params } from "@angular/router";
|
||||
|
||||
import { BitwardenLogo } from "@bitwarden/auth/angular";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { OrganizationSponsorshipResponse } from "@bitwarden/common/admin-console/models/response/organization-sponsorship.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
import { Icons, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { BaseAcceptComponent } from "../../../common/base.accept.component";
|
||||
|
||||
@@ -22,7 +21,7 @@ import { BaseAcceptComponent } from "../../../common/base.accept.component";
|
||||
standalone: false,
|
||||
})
|
||||
export class AcceptFamilySponsorshipComponent extends BaseAcceptComponent {
|
||||
protected logo = BitwardenLogo;
|
||||
protected logo = Icons.BitwardenLogo;
|
||||
failedShortMessage = "inviteAcceptFailedShort";
|
||||
failedMessage = "inviteAcceptFailed";
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ import {
|
||||
activeAuthGuard,
|
||||
} from "@bitwarden/angular/auth/guards";
|
||||
import {
|
||||
AnonLayoutWrapperComponent,
|
||||
AnonLayoutWrapperData,
|
||||
PasswordHintComponent,
|
||||
RegistrationFinishComponent,
|
||||
RegistrationStartComponent,
|
||||
@@ -22,7 +20,6 @@ import {
|
||||
RegistrationLinkExpiredComponent,
|
||||
LoginComponent,
|
||||
LoginSecondaryContentComponent,
|
||||
LockIcon,
|
||||
TwoFactorTimeoutIcon,
|
||||
UserLockIcon,
|
||||
SsoKeyIcon,
|
||||
@@ -39,6 +36,7 @@ import {
|
||||
NewDeviceVerificationComponent,
|
||||
DeviceVerificationIcon,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components";
|
||||
import { LockComponent } from "@bitwarden/key-management-ui";
|
||||
import { VaultIcons } from "@bitwarden/vault";
|
||||
|
||||
@@ -399,7 +397,7 @@ const routes: Routes = [
|
||||
pageTitle: {
|
||||
key: "yourVaultIsLockedV2",
|
||||
},
|
||||
pageIcon: LockIcon,
|
||||
pageIcon: Icons.LockIcon,
|
||||
showReadonlyHostname: true,
|
||||
} satisfies AnonLayoutWrapperData,
|
||||
},
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "@bitwarden/auth/angular";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -17,7 +16,7 @@ import { SendAccessResponse } from "@bitwarden/common/tools/send/models/response
|
||||
import { SendAccessView } from "@bitwarden/common/tools/send/models/view/send-access.view";
|
||||
import { SEND_KDF_ITERATIONS } from "@bitwarden/common/tools/send/send-kdf";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { NoItemsModule, ToastService } from "@bitwarden/components";
|
||||
import { AnonLayoutWrapperDataService, NoItemsModule, ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { ExpiredSendIcon } from "@bitwarden/send-ui";
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "@bitwarden/auth/angular";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum";
|
||||
import { AnonLayoutWrapperDataService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
BrowserExtensionPromptService,
|
||||
|
||||
@@ -2,11 +2,11 @@ import { DestroyRef, Injectable } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { BehaviorSubject, fromEvent } from "rxjs";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "@bitwarden/auth/angular";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum";
|
||||
import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values";
|
||||
import { AnonLayoutWrapperDataService } from "@bitwarden/components";
|
||||
|
||||
export const BrowserPromptState = {
|
||||
Loading: "loading",
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Params, Router } from "@angular/router";
|
||||
|
||||
import { BitwardenLogo } from "@bitwarden/auth/angular";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { ProviderUserAcceptRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-accept.request";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Icons } from "@bitwarden/components";
|
||||
import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept.component";
|
||||
|
||||
@Component({
|
||||
@@ -17,7 +17,7 @@ import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept
|
||||
standalone: false,
|
||||
})
|
||||
export class AcceptProviderComponent extends BaseAcceptComponent {
|
||||
protected logo = BitwardenLogo;
|
||||
protected logo = Icons.BitwardenLogo;
|
||||
providerName: string;
|
||||
providerId: string;
|
||||
providerUserId: string;
|
||||
|
||||
@@ -2,8 +2,8 @@ import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { authGuard } from "@bitwarden/angular/auth/guards";
|
||||
import { AnonLayoutWrapperComponent } from "@bitwarden/auth/angular";
|
||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||
import { AnonLayoutWrapperComponent } from "@bitwarden/components";
|
||||
import { FrontendLayoutComponent } from "@bitwarden/web-vault/app/layouts/frontend-layout.component";
|
||||
import { UserLayoutComponent } from "@bitwarden/web-vault/app/layouts/user-layout.component";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Params } from "@angular/router";
|
||||
|
||||
import { BitwardenLogo } from "@bitwarden/auth/angular";
|
||||
import { Icons } from "@bitwarden/components";
|
||||
import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept.component";
|
||||
|
||||
@Component({
|
||||
@@ -10,7 +10,7 @@ import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept
|
||||
standalone: false,
|
||||
})
|
||||
export class SetupProviderComponent extends BaseAcceptComponent {
|
||||
protected logo = BitwardenLogo;
|
||||
protected logo = Icons.BitwardenLogo;
|
||||
failedShortMessage = "inviteAcceptFailedShort";
|
||||
failedMessage = "inviteAcceptFailed";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { unauthGuardFn } from "@bitwarden/angular/auth/guards";
|
||||
import { AnonLayoutWrapperComponent } from "@bitwarden/auth/angular";
|
||||
import { AnonLayoutWrapperComponent } from "@bitwarden/components";
|
||||
import { deepLinkGuard } from "@bitwarden/web-vault/app/auth/guards/deep-link/deep-link.guard";
|
||||
import { RouteDataProperties } from "@bitwarden/web-vault/app/core";
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ActivatedRoute, Params, Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { filter, map, switchMap } from "rxjs/operators";
|
||||
|
||||
import { BitwardenLogo } from "@bitwarden/auth/angular";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { OrganizationBillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/organizations/organization-billing-api.service.abstraction";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
@@ -13,6 +12,7 @@ import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { ProviderKey } from "@bitwarden/common/types/key";
|
||||
import { Icons } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { BillingNotificationService } from "@bitwarden/web-vault/app/billing/services/billing-notification.service";
|
||||
import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept.component";
|
||||
@@ -22,7 +22,7 @@ import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept
|
||||
standalone: false,
|
||||
})
|
||||
export class SetupBusinessUnitComponent extends BaseAcceptComponent {
|
||||
protected bitwardenLogo = BitwardenLogo;
|
||||
protected bitwardenLogo = Icons.BitwardenLogo;
|
||||
|
||||
failedMessage = "emergencyInviteAcceptFailed";
|
||||
failedShortMessage = "emergencyInviteAcceptFailedShort";
|
||||
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
DefaultAnonLayoutWrapperDataService,
|
||||
DefaultLoginApprovalComponentService,
|
||||
DefaultLoginComponentService,
|
||||
DefaultLoginDecryptionOptionsService,
|
||||
@@ -299,7 +297,11 @@ import { FolderService } from "@bitwarden/common/vault/services/folder/folder.se
|
||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/services/vault-settings/vault-settings.service";
|
||||
import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
DefaultAnonLayoutWrapperDataService,
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
import {
|
||||
GeneratorHistoryService,
|
||||
LocalGeneratorHistoryService,
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { Injectable, inject } from "@angular/core";
|
||||
import { Observable, combineLatest, from, of } from "rxjs";
|
||||
import { catchError, map } from "rxjs/operators";
|
||||
import { catchError, switchMap } from "rxjs/operators";
|
||||
|
||||
import { VaultProfileService } from "@bitwarden/angular/vault/services/vault-profile.service";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { BiometricStateService } from "@bitwarden/key-management";
|
||||
|
||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||
@@ -21,6 +25,9 @@ export class AccountSecurityNudgeService extends DefaultSingleNudgeService {
|
||||
private logService = inject(LogService);
|
||||
private pinService = inject(PinServiceAbstraction);
|
||||
private vaultTimeoutSettingsService = inject(VaultTimeoutSettingsService);
|
||||
private biometricStateService = inject(BiometricStateService);
|
||||
private policyService = inject(PolicyService);
|
||||
private organizationService = inject(OrganizationService);
|
||||
|
||||
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
||||
@@ -36,16 +43,45 @@ export class AccountSecurityNudgeService extends DefaultSingleNudgeService {
|
||||
this.getNudgeStatus$(nudgeType, userId),
|
||||
of(Date.now() - THIRTY_DAYS_MS),
|
||||
from(this.pinService.isPinSet(userId)),
|
||||
from(this.vaultTimeoutSettingsService.isBiometricLockSet(userId)),
|
||||
this.biometricStateService.biometricUnlockEnabled$,
|
||||
this.organizationService.organizations$(userId),
|
||||
this.policyService.policiesByType$(PolicyType.RemoveUnlockWithPin, userId),
|
||||
]).pipe(
|
||||
map(([profileCreationDate, status, profileCutoff, isPinSet, isBiometricLockSet]) => {
|
||||
const profileOlderThanCutoff = profileCreationDate.getTime() < profileCutoff;
|
||||
const hideNudge = profileOlderThanCutoff || isPinSet || isBiometricLockSet;
|
||||
return {
|
||||
hasBadgeDismissed: status.hasBadgeDismissed || hideNudge,
|
||||
hasSpotlightDismissed: status.hasSpotlightDismissed || hideNudge,
|
||||
};
|
||||
}),
|
||||
switchMap(
|
||||
async ([
|
||||
profileCreationDate,
|
||||
status,
|
||||
profileCutoff,
|
||||
isPinSet,
|
||||
biometricUnlockEnabled,
|
||||
organizations,
|
||||
policies,
|
||||
]) => {
|
||||
const profileOlderThanCutoff = profileCreationDate.getTime() < profileCutoff;
|
||||
|
||||
const hasOrgWithRemovePinPolicyOn = organizations.some((org) => {
|
||||
return policies.some(
|
||||
(p) => p.type === PolicyType.RemoveUnlockWithPin && p.organizationId === org.id,
|
||||
);
|
||||
});
|
||||
|
||||
const hideNudge =
|
||||
profileOlderThanCutoff ||
|
||||
isPinSet ||
|
||||
biometricUnlockEnabled ||
|
||||
hasOrgWithRemovePinPolicyOn;
|
||||
|
||||
const acctSecurityNudgeStatus = {
|
||||
hasBadgeDismissed: status.hasBadgeDismissed || hideNudge,
|
||||
hasSpotlightDismissed: status.hasSpotlightDismissed || hideNudge,
|
||||
};
|
||||
|
||||
if (isPinSet || biometricUnlockEnabled || hasOrgWithRemovePinPolicyOn) {
|
||||
await this.setNudgeStatus(nudgeType, acctSecurityNudgeStatus, userId);
|
||||
}
|
||||
return acctSecurityNudgeStatus;
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import { firstValueFrom, of } from "rxjs";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@@ -13,6 +15,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { BiometricStateService } from "@bitwarden/key-management";
|
||||
|
||||
import { FakeStateProvider, mockAccountServiceWith } from "../../../../../libs/common/spec";
|
||||
|
||||
@@ -91,6 +94,18 @@ describe("Vault Nudges Service", () => {
|
||||
provide: VaultTimeoutSettingsService,
|
||||
useValue: mock<VaultTimeoutSettingsService>(),
|
||||
},
|
||||
{
|
||||
provide: BiometricStateService,
|
||||
useValue: mock<BiometricStateService>(),
|
||||
},
|
||||
{
|
||||
provide: PolicyService,
|
||||
useValue: mock<PolicyService>(),
|
||||
},
|
||||
{
|
||||
provide: OrganizationService,
|
||||
useValue: mock<OrganizationService>(),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
export * from "./bitwarden-logo.icon";
|
||||
export * from "./bitwarden-shield.icon";
|
||||
export * from "./devices.icon";
|
||||
export * from "./lock.icon";
|
||||
export * from "./registration-check-email.icon";
|
||||
export * from "./user-lock.icon";
|
||||
export * from "./user-verification-biometrics-fingerprint.icon";
|
||||
export * from "./wave.icon";
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
/**
|
||||
* This barrel file should only contain Angular exports
|
||||
*/
|
||||
|
||||
// anon layout
|
||||
export * from "./anon-layout/anon-layout.component";
|
||||
export * from "./anon-layout/anon-layout-wrapper.component";
|
||||
export * from "./anon-layout/anon-layout-wrapper-data.service";
|
||||
export * from "./anon-layout/default-anon-layout-wrapper-data.service";
|
||||
|
||||
// change password
|
||||
export * from "./change-password/change-password.component";
|
||||
export * from "./change-password/change-password.service.abstraction";
|
||||
|
||||
@@ -30,6 +30,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CheckboxModule,
|
||||
@@ -40,8 +41,6 @@ import {
|
||||
} from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service";
|
||||
|
||||
import { LoginDecryptionOptionsService } from "./login-decryption-options.service";
|
||||
|
||||
// FIXME: update to use a const object instead of a typescript enum
|
||||
|
||||
@@ -32,6 +32,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CheckboxModule,
|
||||
@@ -41,7 +42,6 @@ import {
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service";
|
||||
import { VaultIcon, WaveIcon } from "../icons";
|
||||
|
||||
import { LoginComponentService, PasswordPolicies } from "./login-component.service";
|
||||
|
||||
@@ -16,14 +16,13 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
import { AnonLayoutWrapperDataService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
LoginStrategyServiceAbstraction,
|
||||
LoginSuccessHandlerService,
|
||||
PasswordLoginCredentials,
|
||||
} from "../../../common";
|
||||
import { AnonLayoutWrapperDataService } from "../../anon-layout/anon-layout-wrapper-data.service";
|
||||
import {
|
||||
InputPasswordComponent,
|
||||
InputPasswordFlow,
|
||||
|
||||
@@ -14,18 +14,18 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CheckboxModule,
|
||||
FormFieldModule,
|
||||
Icons,
|
||||
IconModule,
|
||||
LinkModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { LoginEmailService } from "../../../common";
|
||||
import { AnonLayoutWrapperDataService } from "../../anon-layout/anon-layout-wrapper-data.service";
|
||||
import { RegistrationUserAddIcon } from "../../icons";
|
||||
import { RegistrationCheckEmailIcon } from "../../icons/registration-check-email.icon";
|
||||
import { RegistrationEnvSelectorComponent } from "../registration-env-selector/registration-env-selector.component";
|
||||
|
||||
// FIXME: update to use a const object instead of a typescript enum
|
||||
@@ -170,7 +170,7 @@ export class RegistrationStartComponent implements OnInit, OnDestroy {
|
||||
pageTitle: {
|
||||
key: "checkYourEmail",
|
||||
},
|
||||
pageIcon: RegistrationCheckEmailIcon,
|
||||
pageIcon: Icons.RegistrationCheckEmailIcon,
|
||||
});
|
||||
this.registrationStartStateChange.emit(this.state);
|
||||
};
|
||||
|
||||
@@ -18,6 +18,8 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
AnonLayoutWrapperData,
|
||||
AnonLayoutWrapperDataService,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
@@ -34,8 +36,6 @@ import {
|
||||
// eslint-disable-next-line import/no-restricted-paths, no-restricted-imports
|
||||
import { PreloadedEnglishI18nModule } from "../../../../../../apps/web/src/app/core/tests";
|
||||
import { LoginEmailService } from "../../../common";
|
||||
import { AnonLayoutWrapperDataService } from "../../anon-layout/anon-layout-wrapper-data.service";
|
||||
import { AnonLayoutWrapperData } from "../../anon-layout/anon-layout-wrapper.component";
|
||||
|
||||
import { RegistrationStartComponent } from "./registration-start.component";
|
||||
|
||||
|
||||
@@ -36,9 +36,7 @@ import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/sp
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service";
|
||||
import { DialogService, ToastService, AnonLayoutWrapperDataService } from "@bitwarden/components";
|
||||
|
||||
import { TwoFactorAuthComponentCacheService } from "./two-factor-auth-component-cache.service";
|
||||
import { TwoFactorAuthComponentService } from "./two-factor-auth-component.service";
|
||||
|
||||
@@ -41,6 +41,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CheckboxModule,
|
||||
@@ -49,7 +50,6 @@ import {
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service";
|
||||
import {
|
||||
TwoFactorAuthAuthenticatorIcon,
|
||||
TwoFactorAuthEmailIcon,
|
||||
|
||||
@@ -92,6 +92,27 @@ describe("FidoAuthenticatorService", () => {
|
||||
});
|
||||
|
||||
describe("createCredential", () => {
|
||||
describe("Mapping params should handle variations in input formats", () => {
|
||||
it.each([
|
||||
[true, true],
|
||||
[false, false],
|
||||
["false", false],
|
||||
["", false],
|
||||
["true", true],
|
||||
])("requireResidentKey should handle %s as boolean %s", async (input, expected) => {
|
||||
const params = createParams({
|
||||
authenticatorSelection: { requireResidentKey: input as any },
|
||||
extensions: { credProps: true },
|
||||
});
|
||||
|
||||
authenticator.makeCredential.mockResolvedValue(createAuthenticatorMakeResult());
|
||||
|
||||
const result = await client.createCredential(params, windowReference);
|
||||
|
||||
expect(result.extensions.credProps?.rk).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("input parameters validation", () => {
|
||||
// Spec: If sameOriginWithAncestors is false, return a "NotAllowedError" DOMException.
|
||||
it("should throw error if sameOriginWithAncestors is false", async () => {
|
||||
|
||||
@@ -483,11 +483,15 @@ function mapToMakeCredentialParams({
|
||||
type: credential.type,
|
||||
})) ?? [];
|
||||
|
||||
/**
|
||||
* Quirk: Accounts for the fact that some RP's mistakenly submits 'requireResidentKey' as a string
|
||||
*/
|
||||
const requireResidentKey =
|
||||
params.authenticatorSelection?.residentKey === "required" ||
|
||||
params.authenticatorSelection?.residentKey === "preferred" ||
|
||||
(params.authenticatorSelection?.residentKey === undefined &&
|
||||
params.authenticatorSelection?.requireResidentKey === true);
|
||||
(params.authenticatorSelection?.requireResidentKey === true ||
|
||||
(params.authenticatorSelection?.requireResidentKey as unknown as string) === "true"));
|
||||
|
||||
const requireUserVerification =
|
||||
params.authenticatorSelection?.userVerification === "required" ||
|
||||
|
||||
@@ -1,6 +1,45 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
import type {
|
||||
AssertCredentialResult,
|
||||
CreateCredentialResult,
|
||||
} from "../../abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
// @ts-strict-ignore
|
||||
export class Fido2Utils {
|
||||
static createResultToJson(result: CreateCredentialResult): any {
|
||||
return {
|
||||
id: result.credentialId,
|
||||
rawId: result.credentialId,
|
||||
response: {
|
||||
clientDataJSON: result.clientDataJSON,
|
||||
authenticatorData: result.authData,
|
||||
transports: result.transports,
|
||||
publicKey: result.publicKey,
|
||||
publicKeyAlgorithm: result.publicKeyAlgorithm,
|
||||
attestationObject: result.attestationObject,
|
||||
},
|
||||
authenticatorAttachment: "platform",
|
||||
clientExtensionResults: result.extensions,
|
||||
type: "public-key",
|
||||
};
|
||||
}
|
||||
|
||||
static getResultToJson(result: AssertCredentialResult): any {
|
||||
return {
|
||||
id: result.credentialId,
|
||||
rawId: result.credentialId,
|
||||
response: {
|
||||
clientDataJSON: result.clientDataJSON,
|
||||
authenticatorData: result.authenticatorData,
|
||||
signature: result.signature,
|
||||
userHandle: result.userHandle,
|
||||
},
|
||||
authenticatorAttachment: "platform",
|
||||
clientExtensionResults: {},
|
||||
type: "public-key",
|
||||
};
|
||||
}
|
||||
|
||||
static bufferToString(bufferSource: BufferSource): string {
|
||||
return Fido2Utils.fromBufferToB64(Fido2Utils.bufferSourceToUint8Array(bufferSource))
|
||||
.replace(/\+/g, "-")
|
||||
|
||||
@@ -4,13 +4,13 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Data, NavigationEnd, Router, RouterModule } from "@angular/router";
|
||||
import { Subject, filter, switchMap, takeUntil, tap } from "rxjs";
|
||||
|
||||
import { AnonLayoutComponent } from "@bitwarden/auth/angular";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Icon, Translation } from "@bitwarden/components";
|
||||
|
||||
import { Translation } from "../dialog";
|
||||
import { Icon } from "../icon";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "./anon-layout-wrapper-data.service";
|
||||
import { AnonLayoutComponent } from "./anon-layout.component";
|
||||
|
||||
export interface AnonLayoutWrapperData {
|
||||
/**
|
||||
@@ -14,24 +14,19 @@ import {
|
||||
EnvironmentService,
|
||||
Environment,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { ButtonModule } from "@bitwarden/components";
|
||||
|
||||
// FIXME: remove `/apps` import from `/libs`
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line import/no-restricted-paths, no-restricted-imports
|
||||
import { PreloadedEnglishI18nModule } from "../../../../../apps/web/src/app/core/tests";
|
||||
import { LockIcon } from "../icons";
|
||||
import { RegistrationCheckEmailIcon } from "../icons/registration-check-email.icon";
|
||||
import { ButtonModule } from "../button";
|
||||
import { LockIcon, RegistrationCheckEmailIcon } from "../icon/icons";
|
||||
import { I18nMockService } from "../utils";
|
||||
|
||||
import { AnonLayoutWrapperDataService } from "./anon-layout-wrapper-data.service";
|
||||
import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "./anon-layout-wrapper.component";
|
||||
import { DefaultAnonLayoutWrapperDataService } from "./default-anon-layout-wrapper-data.service";
|
||||
|
||||
export default {
|
||||
title: "Auth/Anon Layout Wrapper",
|
||||
title: "Component Library/Anon Layout Wrapper",
|
||||
component: AnonLayoutWrapperComponent,
|
||||
} as Meta;
|
||||
|
||||
@@ -84,13 +79,21 @@ const decorators = (options: {
|
||||
getClientType: () => options.clientType || ClientType.Web,
|
||||
} as Partial<PlatformUtilsService>,
|
||||
},
|
||||
{
|
||||
provide: I18nService,
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
setAStrongPassword: "Set a strong password",
|
||||
appLogoLabel: "app logo label",
|
||||
finishCreatingYourAccountBySettingAPassword:
|
||||
"Finish creating your account by setting a password",
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
applicationConfig({
|
||||
providers: [
|
||||
importProvidersFrom(RouterModule.forRoot(options.routes)),
|
||||
importProvidersFrom(PreloadedEnglishI18nModule),
|
||||
],
|
||||
providers: [importProvidersFrom(RouterModule.forRoot(options.routes))],
|
||||
}),
|
||||
];
|
||||
};
|
||||
@@ -102,18 +105,21 @@ type Story = StoryObj<AnonLayoutWrapperComponent>;
|
||||
@Component({
|
||||
selector: "bit-default-primary-outlet-example-component",
|
||||
template: "<p>Primary Outlet Example: <br> your primary component goes here</p>",
|
||||
standalone: false,
|
||||
})
|
||||
export class DefaultPrimaryOutletExampleComponent {}
|
||||
|
||||
@Component({
|
||||
selector: "bit-default-secondary-outlet-example-component",
|
||||
template: "<p>Secondary Outlet Example: <br> your secondary component goes here</p>",
|
||||
standalone: false,
|
||||
})
|
||||
export class DefaultSecondaryOutletExampleComponent {}
|
||||
|
||||
@Component({
|
||||
selector: "bit-default-env-selector-outlet-example-component",
|
||||
template: "<p>Env Selector Outlet Example: <br> your env selector component goes here</p>",
|
||||
standalone: false,
|
||||
})
|
||||
export class DefaultEnvSelectorOutletExampleComponent {}
|
||||
|
||||
@@ -188,6 +194,7 @@ const changedData: AnonLayoutWrapperData = {
|
||||
template: `
|
||||
<button type="button" bitButton buttonType="primary" (click)="toggleData()">Toggle Data</button>
|
||||
`,
|
||||
standalone: false,
|
||||
})
|
||||
export class DynamicContentExampleComponent {
|
||||
initialData = true;
|
||||
@@ -9,16 +9,10 @@ import { ClientType } from "@bitwarden/common/enums";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { IconModule, Icon } from "../../../../components/src/icon";
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { SharedModule } from "../../../../components/src/shared";
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { TypographyModule } from "../../../../components/src/typography";
|
||||
import { BitwardenLogo, BitwardenShield } from "../icons";
|
||||
import { IconModule, Icon } from "../icon";
|
||||
import { BitwardenLogo, BitwardenShield } from "../icon/icons";
|
||||
import { SharedModule } from "../shared";
|
||||
import { TypographyModule } from "../typography";
|
||||
|
||||
@Component({
|
||||
selector: "auth-anon-layout",
|
||||
@@ -6,8 +6,8 @@ import * as stories from "./anon-layout.stories";
|
||||
|
||||
# AnonLayout Component
|
||||
|
||||
The Auth-owned AnonLayoutComponent is to be used primarily for unauthenticated pages\*, where we
|
||||
don't know who the user is.
|
||||
The AnonLayoutComponent is to be used primarily for unauthenticated pages\*, where we don't know who
|
||||
the user is.
|
||||
|
||||
\*There will be a few exceptions to this—that is, AnonLayout will also be used for the Unlock
|
||||
and View Send pages.
|
||||
@@ -7,13 +7,9 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { ButtonModule } from "../../../../components/src/button";
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { I18nMockService } from "../../../../components/src/utils/i18n-mock.service";
|
||||
import { LockIcon } from "../icons";
|
||||
import { ButtonModule } from "../button";
|
||||
import { LockIcon } from "../icon/icons";
|
||||
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||
|
||||
import { AnonLayoutComponent } from "./anon-layout.component";
|
||||
|
||||
@@ -23,7 +19,7 @@ class MockPlatformUtilsService implements Partial<PlatformUtilsService> {
|
||||
}
|
||||
|
||||
export default {
|
||||
title: "Auth/Anon Layout",
|
||||
title: "Component Library/Anon Layout",
|
||||
component: AnonLayoutComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
@@ -38,6 +34,7 @@ export default {
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
accessing: "Accessing",
|
||||
appLogoLabel: "app logo label",
|
||||
});
|
||||
},
|
||||
},
|
||||
4
libs/components/src/anon-layout/index.ts
Normal file
4
libs/components/src/anon-layout/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./anon-layout-wrapper-data.service";
|
||||
export * from "./anon-layout-wrapper.component";
|
||||
export * from "./anon-layout.component";
|
||||
export * from "./default-anon-layout-wrapper-data.service";
|
||||
@@ -1,6 +1,4 @@
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { svgIcon } from "@bitwarden/components";
|
||||
import { svgIcon } from "../icon";
|
||||
|
||||
export const BitwardenLogo = svgIcon`
|
||||
<svg viewBox="0 0 290 45" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -1,6 +1,4 @@
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { svgIcon } from "@bitwarden/components";
|
||||
import { svgIcon } from "../icon";
|
||||
|
||||
export const BitwardenShield = svgIcon`
|
||||
<svg viewBox="0 0 120 132" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -1,4 +1,4 @@
|
||||
import { svgIcon } from "@bitwarden/components";
|
||||
import { svgIcon } from "../icon";
|
||||
|
||||
export const ExtensionBitwardenLogo = svgIcon`
|
||||
<svg
|
||||
@@ -1,8 +1,13 @@
|
||||
export * from "./search";
|
||||
export * from "./security";
|
||||
export * from "./bitwarden-logo.icon";
|
||||
export * from "./bitwarden-shield.icon";
|
||||
export * from "./extension-bitwarden-logo.icon";
|
||||
export * from "./lock.icon";
|
||||
export * from "./generator";
|
||||
export * from "./no-access";
|
||||
export * from "./no-results";
|
||||
export * from "./generator";
|
||||
export * from "./registration-check-email.icon";
|
||||
export * from "./search";
|
||||
export * from "./security";
|
||||
export * from "./send";
|
||||
export * from "./settings";
|
||||
export * from "./vault";
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { svgIcon } from "@bitwarden/components";
|
||||
import { svgIcon } from "../icon";
|
||||
|
||||
export const LockIcon = svgIcon`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 100" fill="none">
|
||||
@@ -1,6 +1,4 @@
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { svgIcon } from "@bitwarden/components";
|
||||
import { svgIcon } from "../icon";
|
||||
|
||||
export const RegistrationCheckEmailIcon = svgIcon`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 100" fill="none">
|
||||
@@ -1,5 +1,6 @@
|
||||
export { ButtonType, ButtonLikeAbstraction } from "./shared/button-like.abstraction";
|
||||
export * from "./a11y";
|
||||
export * from "./anon-layout";
|
||||
export * from "./async-actions";
|
||||
export * from "./avatar";
|
||||
export * from "./badge-list";
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
} from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { AnonLayoutWrapperDataService } from "@bitwarden/auth/angular";
|
||||
import { LogoutService, PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
@@ -42,6 +41,7 @@ import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/pass
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
AnonLayoutWrapperDataService,
|
||||
ButtonModule,
|
||||
DialogService,
|
||||
FormFieldModule,
|
||||
|
||||
60
package-lock.json
generated
60
package-lock.json
generated
@@ -85,7 +85,7 @@
|
||||
"@babel/core": "7.24.9",
|
||||
"@babel/preset-env": "7.24.8",
|
||||
"@compodoc/compodoc": "1.1.26",
|
||||
"@electron/notarize": "2.5.0",
|
||||
"@electron/notarize": "3.0.1",
|
||||
"@electron/rebuild": "3.7.2",
|
||||
"@eslint/compat": "1.2.9",
|
||||
"@lit-labs/signals": "0.1.2",
|
||||
@@ -5402,34 +5402,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz",
|
||||
"integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-3.0.1.tgz",
|
||||
"integrity": "sha512-5xzcOwvMGNjkSk7s0sPx4XcKWei9FYk4f2S5NkSorWW0ce5yktTOtlPa0W5yQHcREILh+C3JdH+t+M637g9TmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"debug": "^4.4.0",
|
||||
"promise-retry": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">= 22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/osx-sign": {
|
||||
@@ -14324,6 +14307,37 @@
|
||||
"electron-builder-squirrel-windows": "26.0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/notarize": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz",
|
||||
"integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"promise-retry": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/rebuild": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.7.0.tgz",
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"@babel/core": "7.24.9",
|
||||
"@babel/preset-env": "7.24.8",
|
||||
"@compodoc/compodoc": "1.1.26",
|
||||
"@electron/notarize": "2.5.0",
|
||||
"@electron/notarize": "3.0.1",
|
||||
"@electron/rebuild": "3.7.2",
|
||||
"@eslint/compat": "1.2.9",
|
||||
"@lit-labs/signals": "0.1.2",
|
||||
|
||||
Reference in New Issue
Block a user