1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-21 10:43:35 +00:00

Ps 976 moving of read only organization collection items to different folder not possible (#3474)

* PS-976 - when user has cipher readonly permissions, prevent user from editing cipher fields and make separate api call that only updates Favorite and Folder values

* PS-976 - in the readonly edit cipher view, hide non-operable buttons and display select values as readonly input text

* PS-976 - update failing test

* PS-976 - split cipher saveWithServer call into Create and Update calls

* PS-976 - replace property with function call to get the card expiration month for the readonly view

* MM-976 - when user has readonly permissions hide "delete" button on View Item view, hide generate username/password buttons on Edit Item view

* PS-976 - rename cipherPartialRequest file to align with new naming convention
This commit is contained in:
dgoodman-bw
2022-10-25 12:24:21 -07:00
committed by GitHub
parent d9542c45d9
commit 41d6b6bd21
19 changed files with 382 additions and 96 deletions

View File

@@ -394,7 +394,7 @@ export default class NotificationBackground {
}
const cipher = await this.cipherService.encrypt(model);
await this.cipherService.saveWithServer(cipher);
await this.cipherService.createWithServer(cipher);
}
private async getDecryptedCipherById(cipherId: string) {
@@ -409,7 +409,7 @@ export default class NotificationBackground {
if (cipher != null && cipher.type === CipherType.Login) {
cipher.login.password = newPassword;
const newCipher = await this.cipherService.encrypt(cipher);
await this.cipherService.saveWithServer(newCipher);
await this.cipherService.updateWithServer(newCipher);
}
}

View File

@@ -19,6 +19,7 @@
appStopClick
(click)="removeField(f)"
appA11yTitle="{{ 'remove' | i18n }}"
*ngIf="!(!cipher.edit && editMode)"
>
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i>
</button>
@@ -33,6 +34,7 @@
class="row-label"
placeholder="{{ 'name' | i18n }}"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
<!-- Text -->
<input
@@ -44,6 +46,7 @@
placeholder="{{ 'value' | i18n }}"
appInputVerbatim
attr.aria-describedby="fieldName{{ i }}"
[readonly]="!cipher.edit && editMode"
/>
<!-- Hidden -->
<input
@@ -57,6 +60,7 @@
placeholder="{{ 'value' | i18n }}"
[disabled]="!cipher.viewPassword && !f.newField"
attr.aria-describedby="fieldName{{ i }}"
[readonly]="!cipher.edit && editMode"
/>
<!-- Linked -->
<select
@@ -80,6 +84,7 @@
trueValue="true"
falseValue="false"
attr.aria-describedby="fieldName{{ i }}"
[readonly]="!cipher.edit && editMode"
/>
<div
class="action-buttons"
@@ -100,13 +105,22 @@
></i>
</button>
</div>
<div class="drag-handle" appA11yTitle="{{ 'dragToSort' | i18n }}" cdkDragHandle>
<div
class="drag-handle"
appA11yTitle="{{ 'dragToSort' | i18n }}"
*ngIf="!(!cipher.edit && editMode)"
cdkDragHandle
>
<i class="bwi bwi-hamburger" aria-hidden="true"></i>
</div>
</div>
</div>
<!-- Add new custom field -->
<div class="box-content-row box-content-row-newmulti" appBoxRow>
<div
class="box-content-row box-content-row-newmulti"
*ngIf="!(!cipher.edit && editMode)"
appBoxRow
>
<button type="button" appStopClick (click)="addField()">
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
{{ "newCustomField" | i18n }}

View File

@@ -30,7 +30,13 @@
</div>
<div class="box-content-row" appBoxRow>
<label for="name">{{ "name" | i18n }}</label>
<input id="name" type="text" name="Name" [(ngModel)]="cipher.name" />
<input
id="name"
type="text"
name="Name"
[(ngModel)]="cipher.name"
[readonly]="!cipher.edit && editMode"
/>
</div>
<!-- Login -->
<div *ngIf="cipher.type === cipherType.Login">
@@ -44,6 +50,7 @@
[(ngModel)]="cipher.login.username"
inputmode="email"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="action-buttons">
@@ -53,6 +60,7 @@
appStopClick
appA11yTitle="{{ 'generateUsername' | i18n }}"
(click)="generateUsername()"
*ngIf="!(!cipher.edit && editMode)"
>
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
</button>
@@ -69,6 +77,7 @@
[(ngModel)]="cipher.login.password"
appInputVerbatim
[disabled]="!cipher.viewPassword"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="action-buttons">
@@ -114,7 +123,7 @@
appStopClick
appA11yTitle="{{ 'generatePassword' | i18n }}"
(click)="generatePassword()"
*ngIf="cipher.viewPassword"
*ngIf="cipher.viewPassword && !(!cipher.edit && editMode)"
>
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
</button>
@@ -130,6 +139,7 @@
[(ngModel)]="cipher.login.totp"
appInputVerbatim
[disabled]="!cipher.viewPassword"
[readonly]="!cipher.edit && editMode"
/>
</div>
</div>
@@ -142,6 +152,7 @@
type="text"
name="Card.CardCardholderName"
[(ngModel)]="cipher.card.cardholderName"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row box-content-row-flex" appBoxRow>
@@ -154,6 +165,7 @@
name="Card.Number"
[(ngModel)]="cipher.card.number"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="action-buttons">
@@ -175,17 +187,39 @@
</div>
<div class="box-content-row" appBoxRow>
<label for="cardBrand">{{ "brand" | i18n }}</label>
<select id="cardBrand" name="Card.Brand" [(ngModel)]="cipher.card.brand">
<option *ngFor="let o of cardBrandOptions" [ngValue]="o.value">{{ o.name }}</option>
</select>
<span *ngIf="!(!cipher.edit && editMode); else readonlyCardBrand">
<select id="cardBrand" name="Card.Brand" [(ngModel)]="cipher.card.brand">
<option *ngFor="let o of cardBrandOptions" [ngValue]="o.value">{{ o.name }}</option>
</select>
</span>
<ng-template #readonlyCardBrand>
<input
id="cardBrand"
name="Card.Brand"
type="text"
[readonly]="true"
[value]="cipher.card.brand"
/>
</ng-template>
</div>
<div class="box-content-row" appBoxRow>
<label for="cardExpMonth">{{ "expirationMonth" | i18n }}</label>
<select id="cardExpMonth" name="Card.ExpMonth" [(ngModel)]="cipher.card.expMonth">
<option *ngFor="let o of cardExpMonthOptions" [ngValue]="o.value">
{{ o.name }}
</option>
</select>
<span *ngIf="!(!cipher.edit && editMode); else readonlyCardExpMonth">
<select id="cardExpMonth" name="Card.ExpMonth" [(ngModel)]="cipher.card.expMonth">
<option *ngFor="let o of cardExpMonthOptions" [ngValue]="o.value">
{{ o.name }}
</option>
</select>
</span>
<ng-template #readonlyCardExpMonth>
<input
id="cardExpMonth"
name="Card.ExpMonth"
type="text"
[readonly]="true"
[value]="getCardExpMonthDisplay()"
/>
</ng-template>
</div>
<div class="box-content-row" appBoxRow>
<label for="cardExpYear">{{ "expirationYear" | i18n }}</label>
@@ -195,6 +229,7 @@
name="Card.ExpYear"
[(ngModel)]="cipher.card.expYear"
placeholder="{{ 'ex' | i18n }} {{ currentDate | date: 'yyyy' }}"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row box-content-row-flex" appBoxRow>
@@ -207,6 +242,7 @@
name="Card.Code"
[(ngModel)]="cipher.card.code"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="action-buttons">
@@ -231,11 +267,22 @@
<div *ngIf="cipher.type === cipherType.Identity">
<div class="box-content-row" appBoxRow>
<label for="idTitle">{{ "title" | i18n }}</label>
<select id="idTitle" name="Identity.Title" [(ngModel)]="cipher.identity.title">
<option *ngFor="let o of identityTitleOptions" [ngValue]="o.value">
{{ o.name }}
</option>
</select>
<span *ngIf="!(!cipher.edit && editMode); else readonlyIdTitle">
<select id="idTitle" name="Identity.Title" [(ngModel)]="cipher.identity.title">
<option *ngFor="let o of identityTitleOptions" [ngValue]="o.value">
{{ o.name }}
</option>
</select>
</span>
<ng-template #readonlyIdTitle>
<input
id="idTitle"
name="Identity.Title"
type="text"
[readonly]="true"
[value]="cipher.identity.title"
/>
</ng-template>
</div>
<div class="box-content-row" appBoxRow>
<label for="idFirstName">{{ "firstName" | i18n }}</label>
@@ -244,6 +291,7 @@
type="text"
name="Identity.FirstName"
[(ngModel)]="cipher.identity.firstName"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -253,6 +301,7 @@
type="text"
name="Identity.MiddleName"
[(ngModel)]="cipher.identity.middleName"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -262,6 +311,7 @@
type="text"
name="Identity.LastName"
[(ngModel)]="cipher.identity.lastName"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -272,6 +322,7 @@
name="Identity.Username"
[(ngModel)]="cipher.identity.username"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -281,6 +332,7 @@
type="text"
name="Identity.Company"
[(ngModel)]="cipher.identity.company"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -291,6 +343,7 @@
name="Identity.SSN"
[(ngModel)]="cipher.identity.ssn"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -301,6 +354,7 @@
name="Identity.PassportNumber"
[(ngModel)]="cipher.identity.passportNumber"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -311,6 +365,7 @@
name="Identity.LicenseNumber"
[(ngModel)]="cipher.identity.licenseNumber"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -321,6 +376,7 @@
name="Identity.Email"
[(ngModel)]="cipher.identity.email"
appInputVerbatim
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -330,6 +386,7 @@
type="text"
name="Identity.Phone"
[(ngModel)]="cipher.identity.phone"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -339,6 +396,7 @@
type="text"
name="Identity.Address1"
[(ngModel)]="cipher.identity.address1"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -348,6 +406,7 @@
type="text"
name="Identity.Address2"
[(ngModel)]="cipher.identity.address2"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -357,6 +416,7 @@
type="text"
name="Identity.Address3"
[(ngModel)]="cipher.identity.address3"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -366,6 +426,7 @@
type="text"
name="Identity.City"
[(ngModel)]="cipher.identity.city"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -375,6 +436,7 @@
type="text"
name="Identity.State"
[(ngModel)]="cipher.identity.state"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -384,6 +446,7 @@
type="text"
name="Identity.PostalCode"
[(ngModel)]="cipher.identity.postalCode"
[readonly]="!cipher.edit && editMode"
/>
</div>
<div class="box-content-row" appBoxRow>
@@ -393,6 +456,7 @@
type="text"
name="Identity.Country"
[(ngModel)]="cipher.identity.country"
[readonly]="!cipher.edit && editMode"
/>
</div>
</div>
@@ -484,6 +548,7 @@
appStopClick
(click)="addUri()"
class="box-content-row box-content-row-newmulti"
*ngIf="!(!cipher.edit && editMode)"
>
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i> {{ "newUri" | i18n }}
</button>
@@ -535,6 +600,7 @@
name="PasswordPrompt"
[ngModel]="reprompt"
(change)="repromptChanged()"
[disabled]="!cipher.edit && editMode"
/>
</div>
<button
@@ -574,11 +640,18 @@
</h2>
<div class="box-content">
<div class="box-content-row" appBoxRow>
<textarea id="notes" name="Notes" rows="6" [(ngModel)]="cipher.notes"></textarea>
<textarea
id="notes"
name="Notes"
rows="6"
[(ngModel)]="cipher.notes"
[readonly]="!cipher.edit && editMode"
></textarea>
</div>
</div>
</div>
<app-vault-add-edit-custom-fields
*ngIf="!(!cipher.hasFields && !cipher.edit && editMode)"
[cipher]="cipher"
[thisCipherType]="cipher.type"
[editMode]="editMode"
@@ -628,7 +701,7 @@
</div>
</div>
</div>
<div class="box list" *ngIf="editMode && !cloneMode">
<div class="box list" *ngIf="editMode && !cloneMode && !(!cipher.edit && editMode)">
<div class="box-content single-line">
<button
type="button"

View File

@@ -620,7 +620,13 @@
<span>{{ "restoreItem" | i18n }}</span>
</div>
</button>
<button type="button" class="box-content-row" appStopClick (click)="delete()">
<button
type="button"
class="box-content-row"
appStopClick
(click)="delete()"
*ngIf="cipher.edit"
>
<div class="row-main text-danger">
<div class="icon text-danger" aria-hidden="true">
<i class="bwi bwi-trash bwi-lg bwi-fw"></i>

View File

@@ -218,7 +218,7 @@ export class ViewComponent extends BaseViewComponent {
try {
const cipher: Cipher = await this.cipherService.encrypt(this.cipher);
await this.cipherService.saveWithServer(cipher);
await this.cipherService.updateWithServer(cipher);
this.platformUtilsService.showToast(
"success",
null,