mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 14:23:32 +00:00
[PM-20643] - [Vault] [Desktop] Front End Changes to Enforce "Remove card item type policy" (#15176)
* add restricted item types to legacy vault components * filter out restricted item types from new menu item in desktop * use CIPHER_MENU_ITEMS * use CIPHER_MENU_ITEMS. move restricted cipher service to common * use move restricted item types service to libs. re-use cipher menu items * add shareReplay. change variable name * move restricted filter to search service. remove unecessary import * add reusable service method * clean up spec * add optional chain * remove duplicate import * move isCipherViewRestricted to service module * fix logic * fix logic * remove extra space --------- Co-authored-by: SmithThe4th <gsmith@bitwarden.com>
This commit is contained in:
@@ -1922,6 +1922,9 @@
|
|||||||
"typeSshKey": {
|
"typeSshKey": {
|
||||||
"message": "SSH key"
|
"message": "SSH key"
|
||||||
},
|
},
|
||||||
|
"typeNote": {
|
||||||
|
"message": "Note"
|
||||||
|
},
|
||||||
"newItemHeader": {
|
"newItemHeader": {
|
||||||
"message": "New $TYPE$",
|
"message": "New $TYPE$",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import {
|
import {
|
||||||
CardComponent,
|
CardComponent,
|
||||||
CheckboxModule,
|
CheckboxModule,
|
||||||
@@ -58,7 +59,6 @@ import {
|
|||||||
SelectModule,
|
SelectModule,
|
||||||
TypographyModule,
|
TypographyModule,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service";
|
import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service";
|
||||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|||||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
import {
|
||||||
|
RestrictedCipherType,
|
||||||
|
RestrictedItemTypesService,
|
||||||
|
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components";
|
import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components";
|
||||||
import { RestrictedCipherType, RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
import { BrowserApi } from "../../../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import { map, Observable } from "rxjs";
|
|||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
|
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { CipherMenuItem, CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
import { CipherMenuItem, CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
||||||
import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components";
|
import { ButtonModule, DialogService, MenuModule, NoItemsModule } from "@bitwarden/components";
|
||||||
import { AddEditFolderDialogComponent, RestrictedItemTypesService } from "@bitwarden/vault";
|
import { AddEditFolderDialogComponent } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { BrowserApi } from "../../../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../../../platform/browser/browser-api";
|
||||||
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../../../../../platform/popup/browser-popup-utils";
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folde
|
|||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||||
import { RestrictedCipherType, RestrictedItemTypesService } from "@bitwarden/vault";
|
import {
|
||||||
|
RestrictedCipherType,
|
||||||
|
RestrictedItemTypesService,
|
||||||
|
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CachedFilterState,
|
CachedFilterState,
|
||||||
|
|||||||
@@ -39,9 +39,12 @@ import { ITreeNodeObject, TreeNode } from "@bitwarden/common/vault/models/domain
|
|||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||||
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
||||||
|
import {
|
||||||
|
isCipherViewRestricted,
|
||||||
|
RestrictedItemTypesService,
|
||||||
|
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
import { CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
||||||
import { ChipSelectOption } from "@bitwarden/components";
|
import { ChipSelectOption } from "@bitwarden/components";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
const FILTER_VISIBILITY_KEY = new KeyDefinition<boolean>(VAULT_SETTINGS_DISK, "filterVisibility", {
|
const FILTER_VISIBILITY_KEY = new KeyDefinition<boolean>(VAULT_SETTINGS_DISK, "filterVisibility", {
|
||||||
deserializer: (obj) => obj,
|
deserializer: (obj) => obj,
|
||||||
@@ -227,18 +230,8 @@ export class VaultPopupListFiltersService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if cipher type is restricted (with organization exemptions)
|
// Check if cipher type is restricted (with organization exemptions)
|
||||||
if (restrictions && restrictions.length > 0) {
|
if (isCipherViewRestricted(cipher, restrictions)) {
|
||||||
const isRestricted = restrictions.some(
|
return false;
|
||||||
(restrictedType) =>
|
|
||||||
restrictedType.cipherType === cipher.type &&
|
|
||||||
(cipher.organizationId
|
|
||||||
? !restrictedType.allowViewOrgIds.includes(cipher.organizationId)
|
|
||||||
: restrictedType.allowViewOrgIds.length === 0),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isRestricted) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.cipherType !== null && cipher.type !== filters.cipherType) {
|
if (filters.cipherType !== null && cipher.type !== filters.cipherType) {
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
"typeIdentity": {
|
"typeIdentity": {
|
||||||
"message": "Identity"
|
"message": "Identity"
|
||||||
},
|
},
|
||||||
|
"typeNote": {
|
||||||
|
"message": "Note"
|
||||||
|
},
|
||||||
"typeSecureNote": {
|
"typeSecureNote": {
|
||||||
"message": "Secure note"
|
"message": "Secure note"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
||||||
<label for="type">{{ "type" | i18n }}</label>
|
<label for="type">{{ "type" | i18n }}</label>
|
||||||
<select id="type" name="Type" [(ngModel)]="cipher.type" (change)="typeChange()">
|
<select id="type" name="Type" [(ngModel)]="cipher.type" (change)="typeChange()">
|
||||||
<option *ngFor="let o of typeOptions" [ngValue]="o.value">{{ o.name }}</option>
|
<option *ngFor="let item of menuItems$ | async" [ngValue]="item.type">
|
||||||
|
{{ item.labelKey | i18n }}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { DatePipe } from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import { Component, NgZone, OnChanges, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
import { Component, NgZone, OnChanges, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||||
import { NgForm } from "@angular/forms";
|
import { NgForm } from "@angular/forms";
|
||||||
|
import { map, shareReplay } from "rxjs";
|
||||||
|
|
||||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||||
@@ -22,6 +23,8 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
|||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
import { CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
import { DialogService, ToastService } from "@bitwarden/components";
|
||||||
import { PasswordRepromptService, SshImportPromptService } from "@bitwarden/vault";
|
import { PasswordRepromptService, SshImportPromptService } from "@bitwarden/vault";
|
||||||
|
|
||||||
@@ -35,6 +38,18 @@ const BroadcasterSubscriptionId = "AddEditComponent";
|
|||||||
export class AddEditComponent extends BaseAddEditComponent implements OnInit, OnChanges, OnDestroy {
|
export class AddEditComponent extends BaseAddEditComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
@ViewChild("form")
|
@ViewChild("form")
|
||||||
private form: NgForm;
|
private form: NgForm;
|
||||||
|
menuItems$ = this.restrictedItemTypesService.restricted$.pipe(
|
||||||
|
map((restrictedItemTypes) =>
|
||||||
|
// Filter out restricted item types from the default CIPHER_MENU_ITEMS array
|
||||||
|
CIPHER_MENU_ITEMS.filter(
|
||||||
|
(typeOption) =>
|
||||||
|
!restrictedItemTypes.some(
|
||||||
|
(restrictedType) => restrictedType.cipherType === typeOption.type,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
shareReplay({ bufferSize: 1, refCount: true }),
|
||||||
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
@@ -59,6 +74,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
|
|||||||
cipherAuthorizationService: CipherAuthorizationService,
|
cipherAuthorizationService: CipherAuthorizationService,
|
||||||
sdkService: SdkService,
|
sdkService: SdkService,
|
||||||
sshImportPromptService: SshImportPromptService,
|
sshImportPromptService: SshImportPromptService,
|
||||||
|
protected restrictedItemTypesService: RestrictedItemTypesService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
cipherService,
|
cipherService,
|
||||||
|
|||||||
@@ -20,78 +20,20 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<ul id="type-filters" *ngIf="!isCollapsed" class="filter-options">
|
<ul id="type-filters" *ngIf="!isCollapsed" class="filter-options">
|
||||||
<li
|
@for (typeFilter of typeFilters$ | async; track typeFilter) {
|
||||||
class="filter-option"
|
<li class="filter-option" [ngClass]="{ active: activeFilter.cipherType === typeFilter.type }">
|
||||||
[ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.Login }"
|
<span class="filter-buttons">
|
||||||
>
|
<button
|
||||||
<span class="filter-buttons">
|
type="button"
|
||||||
<button
|
class="filter-button"
|
||||||
type="button"
|
(click)="applyFilter(typeFilter.type)"
|
||||||
class="filter-button"
|
[attr.aria-pressed]="activeFilter.cipherType === typeFilter.type"
|
||||||
(click)="applyFilter(cipherTypeEnum.Login)"
|
>
|
||||||
[attr.aria-pressed]="activeFilter.cipherType === cipherTypeEnum.Login"
|
<i class="bwi bwi-fw {{ typeFilter.icon }}" aria-hidden="true"></i> {{
|
||||||
>
|
typeFilter.labelKey | i18n
|
||||||
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i> {{ "typeLogin" | i18n }}
|
}}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="filter-option" [ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.Card }">
|
}
|
||||||
<span class="filter-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="filter-button"
|
|
||||||
(click)="applyFilter(cipherTypeEnum.Card)"
|
|
||||||
[attr.aria-pressed]="activeFilter.cipherType === cipherTypeEnum.Card"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i> {{ "typeCard" | i18n }}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
class="filter-option"
|
|
||||||
[ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.Identity }"
|
|
||||||
>
|
|
||||||
<span class="filter-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="filter-button"
|
|
||||||
(click)="applyFilter(cipherTypeEnum.Identity)"
|
|
||||||
[attr.aria-pressed]="activeFilter.cipherType === cipherTypeEnum.Identity"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i> {{ "typeIdentity" | i18n }}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
class="filter-option"
|
|
||||||
[ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.SecureNote }"
|
|
||||||
>
|
|
||||||
<span class="filter-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="filter-button"
|
|
||||||
(click)="applyFilter(cipherTypeEnum.SecureNote)"
|
|
||||||
[attr.aria-pressed]="activeFilter.cipherType === cipherTypeEnum.SecureNote"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i> {{
|
|
||||||
"typeSecureNote" | i18n
|
|
||||||
}}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
class="filter-option"
|
|
||||||
[ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.SshKey }"
|
|
||||||
>
|
|
||||||
<span class="filter-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="filter-button"
|
|
||||||
(click)="applyFilter(cipherTypeEnum.SshKey)"
|
|
||||||
[attr.aria-pressed]="activeFilter.cipherType === cipherTypeEnum.SshKey"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-key" aria-hidden="true"></i> {{ "typeSshKey" | i18n }}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
import { map, shareReplay } from "rxjs";
|
||||||
|
|
||||||
import { TypeFilterComponent as BaseTypeFilterComponent } from "@bitwarden/angular/vault/vault-filter/components/type-filter.component";
|
import { TypeFilterComponent as BaseTypeFilterComponent } from "@bitwarden/angular/vault/vault-filter/components/type-filter.component";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
import { CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-type-filter",
|
selector: "app-type-filter",
|
||||||
@@ -8,7 +11,22 @@ import { TypeFilterComponent as BaseTypeFilterComponent } from "@bitwarden/angul
|
|||||||
standalone: false,
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class TypeFilterComponent extends BaseTypeFilterComponent {
|
export class TypeFilterComponent extends BaseTypeFilterComponent {
|
||||||
constructor() {
|
protected typeFilters$ = this.restrictedItemTypesService.restricted$.pipe(
|
||||||
|
map((restrictedItemTypes) =>
|
||||||
|
// Filter out restricted item types from the typeFilters array
|
||||||
|
CIPHER_MENU_ITEMS.filter(
|
||||||
|
(typeFilter) =>
|
||||||
|
!restrictedItemTypes.some(
|
||||||
|
(restrictedType) =>
|
||||||
|
restrictedType.allowViewOrgIds.length === 0 &&
|
||||||
|
restrictedType.cipherType === typeFilter.type,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
shareReplay({ bufferSize: 1, refCount: true }),
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(private restrictedItemTypesService: RestrictedItemTypesService) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,25 +72,11 @@
|
|||||||
<i class="bwi bwi-plus bwi-lg" aria-hidden="true"></i>
|
<i class="bwi bwi-plus bwi-lg" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<bit-menu #addCipherMenu>
|
<bit-menu #addCipherMenu>
|
||||||
<button type="button" bitMenuItem (click)="addCipher(CipherType.Login)">
|
@for (itemTypes of itemTypes$ | async; track itemTypes.type) {
|
||||||
<i class="bwi bwi-globe tw-mr-1" aria-hidden="true"></i>
|
<button type="button" bitMenuItem (click)="addCipher(itemTypes.type)">
|
||||||
{{ "typeLogin" | i18n }}
|
<i class="bwi {{ itemTypes.icon }} tw-mr-1" aria-hidden="true"></i>
|
||||||
</button>
|
{{ itemTypes.labelKey | i18n }}
|
||||||
<button type="button" bitMenuItem (click)="addCipher(CipherType.Card)">
|
</button>
|
||||||
<i class="bwi bwi-credit-card tw-mr-1" aria-hidden="true"></i>
|
}
|
||||||
{{ "typeCard" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button type="button" bitMenuItem (click)="addCipher(CipherType.Identity)">
|
|
||||||
<i class="bwi bwi-id-card tw-mr-1" aria-hidden="true"></i>
|
|
||||||
{{ "typeIdentity" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button type="button" bitMenuItem (click)="addCipher(CipherType.SecureNote)">
|
|
||||||
<i class="bwi bwi-sticky-note tw-mr-1" aria-hidden="true"></i>
|
|
||||||
{{ "typeSecureNote" | i18n }}
|
|
||||||
</button>
|
|
||||||
<button type="button" bitMenuItem (click)="addCipher(CipherType.SshKey)">
|
|
||||||
<i class="bwi bwi-key tw-mr-1" aria-hidden="true"></i>
|
|
||||||
{{ "typeSshKey" | i18n }}
|
|
||||||
</button>
|
|
||||||
</bit-menu>
|
</bit-menu>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { MenuModule } from "@bitwarden/components";
|
import { MenuModule } from "@bitwarden/components";
|
||||||
|
|
||||||
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
|
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
|
||||||
@@ -25,8 +26,9 @@ export class VaultItemsV2Component extends BaseVaultItemsComponent {
|
|||||||
private readonly searchBarService: SearchBarService,
|
private readonly searchBarService: SearchBarService,
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
accountService: AccountService,
|
accountService: AccountService,
|
||||||
|
restrictedItemTypesService: RestrictedItemTypesService,
|
||||||
) {
|
) {
|
||||||
super(searchService, cipherService, accountService);
|
super(searchService, cipherService, accountService, restrictedItemTypesService);
|
||||||
|
|
||||||
this.searchBarService.searchText$
|
this.searchBarService.searchText$
|
||||||
.pipe(distinctUntilChanged(), takeUntilDestroyed())
|
.pipe(distinctUntilChanged(), takeUntilDestroyed())
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
|
||||||
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
|
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
|
||||||
|
|
||||||
@@ -22,8 +23,9 @@ export class VaultItemsComponent extends BaseVaultItemsComponent {
|
|||||||
searchBarService: SearchBarService,
|
searchBarService: SearchBarService,
|
||||||
cipherService: CipherService,
|
cipherService: CipherService,
|
||||||
accountService: AccountService,
|
accountService: AccountService,
|
||||||
|
protected restrictedItemTypesService: RestrictedItemTypesService,
|
||||||
) {
|
) {
|
||||||
super(searchService, cipherService, accountService);
|
super(searchService, cipherService, accountService, restrictedItemTypesService);
|
||||||
|
|
||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||||
searchBarService.searchText$.pipe(distinctUntilChanged()).subscribe((searchText) => {
|
searchBarService.searchText$.pipe(distinctUntilChanged()).subscribe((searchText) => {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
import { DialogService, ToastService } from "@bitwarden/components";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
import { VaultFilterComponent as BaseVaultFilterComponent } from "../../../../vault/individual-vault/vault-filter/components/vault-filter.component";
|
import { VaultFilterComponent as BaseVaultFilterComponent } from "../../../../vault/individual-vault/vault-filter/components/vault-filter.component";
|
||||||
import { VaultFilterService } from "../../../../vault/individual-vault/vault-filter/services/abstractions/vault-filter.service";
|
import { VaultFilterService } from "../../../../vault/individual-vault/vault-filter/services/abstractions/vault-filter.service";
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|||||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||||
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
||||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { LayoutComponent } from "@bitwarden/components";
|
import { LayoutComponent } from "@bitwarden/components";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
import { GroupView } from "../../../admin-console/organizations/core";
|
import { GroupView } from "../../../admin-console/organizations/core";
|
||||||
import { PreloadedEnglishI18nModule } from "../../../core/tests";
|
import { PreloadedEnglishI18nModule } from "../../../core/tests";
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
import { DialogService, ToastService } from "@bitwarden/components";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
import { TrialFlowService } from "../../../../billing/services/trial-flow.service";
|
import { TrialFlowService } from "../../../../billing/services/trial-flow.service";
|
||||||
import { VaultFilterService } from "../services/abstractions/vault-filter.service";
|
import { VaultFilterService } from "../services/abstractions/vault-filter.service";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { Unassigned } from "@bitwarden/admin-console/common";
|
import { Unassigned } from "@bitwarden/admin-console/common";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { RestrictedCipherType } from "@bitwarden/vault";
|
import { RestrictedCipherType } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
|
||||||
import { createFilterFunction } from "./filter-function";
|
import { createFilterFunction } from "./filter-function";
|
||||||
import { All } from "./routed-vault-filter.model";
|
import { All } from "./routed-vault-filter.model";
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { Unassigned } from "@bitwarden/admin-console/common";
|
import { Unassigned } from "@bitwarden/admin-console/common";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { RestrictedCipherType } from "@bitwarden/vault";
|
import {
|
||||||
|
isCipherViewRestricted,
|
||||||
|
RestrictedCipherType,
|
||||||
|
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
|
||||||
import { All, RoutedVaultFilterModel } from "./routed-vault-filter.model";
|
import { All, RoutedVaultFilterModel } from "./routed-vault-filter.model";
|
||||||
|
|
||||||
@@ -83,24 +86,9 @@ export function createFilterFunction(
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restricted types
|
// Restricted types
|
||||||
if (restrictedTypes && restrictedTypes.length > 0) {
|
if (restrictedTypes && isCipherViewRestricted(cipher, restrictedTypes)) {
|
||||||
// Filter the cipher if that type is restricted unless
|
return false;
|
||||||
// - The cipher belongs to an organization and that organization allows viewing the cipher type
|
|
||||||
// OR
|
|
||||||
// - The cipher belongs to the user's personal vault and at least one other organization does not restrict that type
|
|
||||||
if (
|
|
||||||
restrictedTypes.some(
|
|
||||||
(restrictedType) =>
|
|
||||||
restrictedType.cipherType === cipher.type &&
|
|
||||||
(cipher.organizationId
|
|
||||||
? !restrictedType.allowViewOrgIds.includes(cipher.organizationId)
|
|
||||||
: restrictedType.allowViewOrgIds.length === 0),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import {
|
import {
|
||||||
BreadcrumbsModule,
|
BreadcrumbsModule,
|
||||||
DialogService,
|
DialogService,
|
||||||
MenuModule,
|
MenuModule,
|
||||||
SimpleDialogOptions,
|
SimpleDialogOptions,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { RestrictedItemTypesService } from "@bitwarden/vault";
|
|
||||||
|
|
||||||
import { CollectionDialogTabType } from "../../../admin-console/organizations/shared/components/collection-dialog";
|
import { CollectionDialogTabType } from "../../../admin-console/organizations/shared/components/collection-dialog";
|
||||||
import { HeaderModule } from "../../../layouts/header/header.module";
|
import { HeaderModule } from "../../../layouts/header/header.module";
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-repromp
|
|||||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { filterOutNullish } from "@bitwarden/common/vault/utils/observable-utilities";
|
import { filterOutNullish } from "@bitwarden/common/vault/utils/observable-utilities";
|
||||||
import { DialogRef, DialogService, Icons, ToastService } from "@bitwarden/components";
|
import { DialogRef, DialogService, Icons, ToastService } from "@bitwarden/components";
|
||||||
import {
|
import {
|
||||||
@@ -79,7 +80,6 @@ import {
|
|||||||
DecryptionFailureDialogComponent,
|
DecryptionFailureDialogComponent,
|
||||||
DefaultCipherFormConfigService,
|
DefaultCipherFormConfigService,
|
||||||
PasswordRepromptService,
|
PasswordRepromptService,
|
||||||
RestrictedItemTypesService,
|
|
||||||
} from "@bitwarden/vault";
|
} from "@bitwarden/vault";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -294,6 +294,7 @@ import { DefaultCipherEncryptionService } from "@bitwarden/common/vault/services
|
|||||||
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
|
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
|
||||||
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
|
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
|
||||||
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
|
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||||
import { VaultSettingsService } from "@bitwarden/common/vault/services/vault-settings/vault-settings.service";
|
import { VaultSettingsService } from "@bitwarden/common/vault/services/vault-settings/vault-settings.service";
|
||||||
import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks";
|
import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks";
|
||||||
@@ -680,6 +681,11 @@ const safeProviders: SafeProvider[] = [
|
|||||||
KdfConfigService,
|
KdfConfigService,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
safeProvider({
|
||||||
|
provide: RestrictedItemTypesService,
|
||||||
|
useClass: RestrictedItemTypesService,
|
||||||
|
deps: [ConfigService, AccountService, OrganizationServiceAbstraction, PolicyServiceAbstraction],
|
||||||
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: PasswordStrengthServiceAbstraction,
|
provide: PasswordStrengthServiceAbstraction,
|
||||||
useClass: PasswordStrengthService,
|
useClass: PasswordStrengthService,
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
showCardNumber = false;
|
showCardNumber = false;
|
||||||
showCardCode = false;
|
showCardCode = false;
|
||||||
cipherType = CipherType;
|
cipherType = CipherType;
|
||||||
typeOptions: any[];
|
|
||||||
cardBrandOptions: any[];
|
cardBrandOptions: any[];
|
||||||
cardExpMonthOptions: any[];
|
cardExpMonthOptions: any[];
|
||||||
identityTitleOptions: any[];
|
identityTitleOptions: any[];
|
||||||
@@ -139,13 +138,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
protected sdkService: SdkService,
|
protected sdkService: SdkService,
|
||||||
private sshImportPromptService: SshImportPromptService,
|
private sshImportPromptService: SshImportPromptService,
|
||||||
) {
|
) {
|
||||||
this.typeOptions = [
|
|
||||||
{ name: i18nService.t("typeLogin"), value: CipherType.Login },
|
|
||||||
{ name: i18nService.t("typeCard"), value: CipherType.Card },
|
|
||||||
{ name: i18nService.t("typeIdentity"), value: CipherType.Identity },
|
|
||||||
{ name: i18nService.t("typeSecureNote"), value: CipherType.SecureNote },
|
|
||||||
];
|
|
||||||
|
|
||||||
this.cardBrandOptions = [
|
this.cardBrandOptions = [
|
||||||
{ name: "-- " + i18nService.t("select") + " --", value: null },
|
{ name: "-- " + i18nService.t("select") + " --", value: null },
|
||||||
{ name: "Visa", value: "Visa" },
|
{ name: "Visa", value: "Visa" },
|
||||||
@@ -215,8 +207,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.writeableCollections = await this.loadCollections();
|
this.writeableCollections = await this.loadCollections();
|
||||||
this.canUseReprompt = await this.passwordRepromptService.enabled();
|
this.canUseReprompt = await this.passwordRepromptService.enabled();
|
||||||
|
|
||||||
this.typeOptions.push({ name: this.i18nService.t("typeSshKey"), value: CipherType.SshKey });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import {
|
|||||||
combineLatest,
|
combineLatest,
|
||||||
filter,
|
filter,
|
||||||
from,
|
from,
|
||||||
|
map,
|
||||||
of,
|
of,
|
||||||
|
shareReplay,
|
||||||
switchMap,
|
switchMap,
|
||||||
takeUntil,
|
takeUntil,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
@@ -20,6 +22,11 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
|||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
import {
|
||||||
|
isCipherViewRestricted,
|
||||||
|
RestrictedItemTypesService,
|
||||||
|
} from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
|
import { CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class VaultItemsComponent implements OnInit, OnDestroy {
|
export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||||
@@ -35,6 +42,19 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
|||||||
organization: Organization;
|
organization: Organization;
|
||||||
CipherType = CipherType;
|
CipherType = CipherType;
|
||||||
|
|
||||||
|
protected itemTypes$ = this.restrictedItemTypesService.restricted$.pipe(
|
||||||
|
map((restrictedItemTypes) =>
|
||||||
|
// Filter out restricted item types
|
||||||
|
CIPHER_MENU_ITEMS.filter(
|
||||||
|
(itemType) =>
|
||||||
|
!restrictedItemTypes.some(
|
||||||
|
(restrictedType) => restrictedType.cipherType === itemType.type,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
shareReplay({ bufferSize: 1, refCount: true }),
|
||||||
|
);
|
||||||
|
|
||||||
protected searchPending = false;
|
protected searchPending = false;
|
||||||
|
|
||||||
/** Construct filters as an observable so it can be appended to the cipher stream. */
|
/** Construct filters as an observable so it can be appended to the cipher stream. */
|
||||||
@@ -62,6 +82,7 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
|||||||
protected searchService: SearchService,
|
protected searchService: SearchService,
|
||||||
protected cipherService: CipherService,
|
protected cipherService: CipherService,
|
||||||
protected accountService: AccountService,
|
protected accountService: AccountService,
|
||||||
|
protected restrictedItemTypesService: RestrictedItemTypesService,
|
||||||
) {
|
) {
|
||||||
this.subscribeToCiphers();
|
this.subscribeToCiphers();
|
||||||
}
|
}
|
||||||
@@ -143,18 +164,22 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
|||||||
this._searchText$,
|
this._searchText$,
|
||||||
this._filter$,
|
this._filter$,
|
||||||
of(userId),
|
of(userId),
|
||||||
|
this.restrictedItemTypesService.restricted$,
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
switchMap(([indexedCiphers, failedCiphers, searchText, filter, userId]) => {
|
switchMap(([indexedCiphers, failedCiphers, searchText, filter, userId, restricted]) => {
|
||||||
let allCiphers = indexedCiphers ?? [];
|
let allCiphers = indexedCiphers ?? [];
|
||||||
const _failedCiphers = failedCiphers ?? [];
|
const _failedCiphers = failedCiphers ?? [];
|
||||||
|
|
||||||
allCiphers = [..._failedCiphers, ...allCiphers];
|
allCiphers = [..._failedCiphers, ...allCiphers];
|
||||||
|
|
||||||
|
const restrictedTypeFilter = (cipher: CipherView) =>
|
||||||
|
isCipherViewRestricted(cipher, restricted);
|
||||||
|
|
||||||
return this.searchService.searchCiphers(
|
return this.searchService.searchCiphers(
|
||||||
userId,
|
userId,
|
||||||
searchText,
|
searchText,
|
||||||
[filter, this.deletedFilter],
|
[filter, this.deletedFilter, restrictedTypeFilter],
|
||||||
allCiphers,
|
allCiphers,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
|
|
||||||
import { ITreeNodeObject, TreeNode } from "./models/domain/tree-node";
|
import { ITreeNodeObject, TreeNode } from "./models/domain/tree-node";
|
||||||
|
|
||||||
export class ServiceUtils {
|
export class ServiceUtils {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { TestBed } from "@angular/core/testing";
|
|
||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
import { firstValueFrom, of } from "rxjs";
|
import { firstValueFrom, of } from "rxjs";
|
||||||
|
|
||||||
@@ -49,19 +48,16 @@ describe("RestrictedItemTypesService", () => {
|
|||||||
fakeAccount = { id: Utils.newGuid() as UserId } as Account;
|
fakeAccount = { id: Utils.newGuid() as UserId } as Account;
|
||||||
accountService.activeAccount$ = of(fakeAccount);
|
accountService.activeAccount$ = of(fakeAccount);
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [
|
|
||||||
{ provide: PolicyService, useValue: policyService },
|
|
||||||
{ provide: OrganizationService, useValue: organizationService },
|
|
||||||
{ provide: AccountService, useValue: accountService },
|
|
||||||
{ provide: ConfigService, useValue: configService },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
configService.getFeatureFlag$.mockReturnValue(of(true));
|
configService.getFeatureFlag$.mockReturnValue(of(true));
|
||||||
organizationService.organizations$.mockReturnValue(of([org1, org2]));
|
organizationService.organizations$.mockReturnValue(of([org1, org2]));
|
||||||
policyService.policiesByType$.mockReturnValue(of([]));
|
policyService.policiesByType$.mockReturnValue(of([]));
|
||||||
service = TestBed.inject(RestrictedItemTypesService);
|
|
||||||
|
service = new RestrictedItemTypesService(
|
||||||
|
configService,
|
||||||
|
accountService,
|
||||||
|
organizationService,
|
||||||
|
policyService,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("emits empty array when feature flag is disabled", async () => {
|
it("emits empty array when feature flag is disabled", async () => {
|
||||||
@@ -106,7 +102,6 @@ describe("RestrictedItemTypesService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns empty allowViewOrgIds when all orgs restrict the same type", async () => {
|
it("returns empty allowViewOrgIds when all orgs restrict the same type", async () => {
|
||||||
configService.getFeatureFlag$.mockReturnValue(of(true));
|
|
||||||
organizationService.organizations$.mockReturnValue(of([org1, org2]));
|
organizationService.organizations$.mockReturnValue(of([org1, org2]));
|
||||||
policyService.policiesByType$.mockReturnValue(of([policyOrg1, policyOrg2]));
|
policyService.policiesByType$.mockReturnValue(of([policyOrg1, policyOrg2]));
|
||||||
|
|
||||||
@@ -117,7 +112,6 @@ describe("RestrictedItemTypesService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("aggregates multiple types and computes allowViewOrgIds correctly", async () => {
|
it("aggregates multiple types and computes allowViewOrgIds correctly", async () => {
|
||||||
configService.getFeatureFlag$.mockReturnValue(of(true));
|
|
||||||
organizationService.organizations$.mockReturnValue(of([org1, org2]));
|
organizationService.organizations$.mockReturnValue(of([org1, org2]));
|
||||||
policyService.policiesByType$.mockReturnValue(
|
policyService.policiesByType$.mockReturnValue(
|
||||||
of([
|
of([
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
import { combineLatest, map, of, Observable } from "rxjs";
|
import { combineLatest, map, of, Observable } from "rxjs";
|
||||||
import { switchMap, distinctUntilChanged, shareReplay } from "rxjs/operators";
|
import { switchMap, distinctUntilChanged, shareReplay } from "rxjs/operators";
|
||||||
|
|
||||||
@@ -10,13 +9,13 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
|||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
|
||||||
export type RestrictedCipherType = {
|
export type RestrictedCipherType = {
|
||||||
cipherType: CipherType;
|
cipherType: CipherType;
|
||||||
allowViewOrgIds: string[];
|
allowViewOrgIds: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({ providedIn: "root" })
|
|
||||||
export class RestrictedItemTypesService {
|
export class RestrictedItemTypesService {
|
||||||
/**
|
/**
|
||||||
* Emits an array of RestrictedCipherType objects:
|
* Emits an array of RestrictedCipherType objects:
|
||||||
@@ -78,3 +77,25 @@ export class RestrictedItemTypesService {
|
|||||||
private policyService: PolicyService,
|
private policyService: PolicyService,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that returns whether a cipher is restricted from being viewed by the user
|
||||||
|
* Criteria:
|
||||||
|
* - the cipher's type is restricted by at least one org
|
||||||
|
* UNLESS
|
||||||
|
* - the cipher belongs to an organization and that organization does not restrict that type
|
||||||
|
* OR
|
||||||
|
* - the cipher belongs to the user's personal vault and at least one other organization does not restrict that type
|
||||||
|
*/
|
||||||
|
export function isCipherViewRestricted(
|
||||||
|
cipher: CipherView,
|
||||||
|
restrictedTypes: RestrictedCipherType[],
|
||||||
|
) {
|
||||||
|
return restrictedTypes.some(
|
||||||
|
(restrictedType) =>
|
||||||
|
restrictedType.cipherType === cipher.type &&
|
||||||
|
(cipher.organizationId
|
||||||
|
? !restrictedType.allowViewOrgIds.includes(cipher.organizationId)
|
||||||
|
: restrictedType.allowViewOrgIds.length === 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -19,6 +19,6 @@ export const CIPHER_MENU_ITEMS = Object.freeze([
|
|||||||
{ type: CipherType.Login, icon: "bwi-globe", labelKey: "typeLogin" },
|
{ type: CipherType.Login, icon: "bwi-globe", labelKey: "typeLogin" },
|
||||||
{ type: CipherType.Card, icon: "bwi-credit-card", labelKey: "typeCard" },
|
{ type: CipherType.Card, icon: "bwi-credit-card", labelKey: "typeCard" },
|
||||||
{ type: CipherType.Identity, icon: "bwi-id-card", labelKey: "typeIdentity" },
|
{ type: CipherType.Identity, icon: "bwi-id-card", labelKey: "typeIdentity" },
|
||||||
{ type: CipherType.SecureNote, icon: "bwi-sticky-note", labelKey: "note" },
|
{ type: CipherType.SecureNote, icon: "bwi-sticky-note", labelKey: "typeNote" },
|
||||||
{ type: CipherType.SshKey, icon: "bwi-key", labelKey: "typeSshKey" },
|
{ type: CipherType.SshKey, icon: "bwi-key", labelKey: "typeSshKey" },
|
||||||
] as const) satisfies readonly CipherMenuItem[];
|
] as const) satisfies readonly CipherMenuItem[];
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ export * as VaultIcons from "./icons";
|
|||||||
|
|
||||||
export { DefaultSshImportPromptService } from "./services/default-ssh-import-prompt.service";
|
export { DefaultSshImportPromptService } from "./services/default-ssh-import-prompt.service";
|
||||||
export { SshImportPromptService } from "./services/ssh-import-prompt.service";
|
export { SshImportPromptService } from "./services/ssh-import-prompt.service";
|
||||||
export {
|
|
||||||
RestrictedItemTypesService,
|
|
||||||
RestrictedCipherType,
|
|
||||||
} from "./services/restricted-item-types.service";
|
|
||||||
|
|
||||||
export * from "./abstractions/change-login-password.service";
|
export * from "./abstractions/change-login-password.service";
|
||||||
export * from "./services/default-change-login-password.service";
|
export * from "./services/default-change-login-password.service";
|
||||||
|
|||||||
Reference in New Issue
Block a user