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

[PM-9959] [PM-9962] Browser Refresh - Passkey Fixes (#10299)

* [PM-9959] Expose Fido2SessionData interface

* [PM-9959] Ensure cipherType is passed during passkey creation

* [PM-9959] Add beforeSubmit hook to cipherForm

* [PM-9959] Add support for Fido2 credential creation in add-edit-v2

* [PM-9959] Ensure cipherType defaults to CipherType.Login if none is available

* [PM-9959] Add support for name and username to be passed in as query params for initial form values

* [PM-9962] Hide remove passkey button when cipher has "except passwords" permissions
This commit is contained in:
Shane Melton
2024-07-29 08:13:56 -07:00
committed by GitHub
parent 00f6920a86
commit ad01a529e8
13 changed files with 166 additions and 25 deletions

View File

@@ -22,6 +22,8 @@ export type OptionalInitialValues = {
organizationId?: OrganizationId;
collectionIds?: CollectionId[];
loginUri?: string;
username?: string;
name?: string;
};
/**

View File

@@ -90,6 +90,12 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci
@Input()
submitBtn?: ButtonComponent;
/**
* Optional function to call before submitting the form. If the function returns false, the form will not be submitted.
*/
@Input()
beforeSubmit: () => Promise<boolean>;
/**
* Event emitted when the cipher is saved successfully.
*/
@@ -213,7 +219,17 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci
return;
}
await this.addEditFormService.saveCipher(this.updatedCipherView, this.config);
if (this.beforeSubmit) {
const shouldSubmit = await this.beforeSubmit();
if (!shouldSubmit) {
return;
}
}
const savedCipher = await this.addEditFormService.saveCipher(
this.updatedCipherView,
this.config,
);
this.toastService.showToast({
variant: "success",
@@ -225,6 +241,6 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci
),
});
this.cipherSaved.emit(this.updatedCipherView);
this.cipherSaved.emit(savedCipher);
};
}

View File

@@ -113,6 +113,10 @@ export class IdentitySectionComponent implements OnInit {
if (this.originalCipherView && this.originalCipherView.id) {
this.populateFormData();
} else {
this.identityForm.patchValue({
username: this.cipherFormContainer.config.initialValues?.username || "",
});
}
}

View File

@@ -165,7 +165,7 @@ export class ItemDetailsSectionComponent implements OnInit {
await this.initFromExistingCipher();
} else {
this.itemDetailsForm.setValue({
name: "",
name: this.initialValues?.name || "",
organizationId: this.initialValues?.organizationId || this.defaultOwner,
folderId: this.initialValues?.folderId || null,
collectionIds: [],

View File

@@ -67,7 +67,7 @@
bitIconButton="bwi-minus-circle"
buttonType="danger"
bitSuffix
*ngIf="loginDetailsForm.enabled"
*ngIf="loginDetailsForm.enabled && viewHiddenFields"
[bitAction]="removePasskey"
data-testid="remove-passkey-button"
[appA11yTitle]="'removePasskey' | i18n"

View File

@@ -452,6 +452,8 @@ describe("LoginDetailsSectionComponent", () => {
fixture = TestBed.createComponent(LoginDetailsSectionComponent);
component = fixture.componentInstance;
jest.spyOn(component, "viewHiddenFields", "get").mockReturnValue(true);
});
it("renders the passkey field when available", () => {
@@ -469,7 +471,7 @@ describe("LoginDetailsSectionComponent", () => {
it("renders the passkey remove button when editable", () => {
fixture.detectChanges();
expect(getRemovePasskeyBtn).not.toBeNull();
expect(getRemovePasskeyBtn()).not.toBeNull();
});
it("does not render the passkey remove button when not editable", () => {
@@ -480,6 +482,14 @@ describe("LoginDetailsSectionComponent", () => {
expect(getRemovePasskeyBtn()).toBeNull();
});
it("does not render the passkey remove button when viewHiddenFields is false", () => {
jest.spyOn(component, "viewHiddenFields", "get").mockReturnValue(false);
fixture.detectChanges();
expect(getRemovePasskeyBtn()).toBeNull();
});
it("hides the passkey field when missing a passkey", () => {
(cipherFormContainer.originalCipherView as CipherView).login.fido2Credentials = [];

View File

@@ -144,9 +144,10 @@ export class LoginDetailsSectionComponent implements OnInit {
}
private async initNewCipher() {
this.loginDetailsForm.controls.password.patchValue(
await this.generationService.generateInitialPassword(),
);
this.loginDetailsForm.patchValue({
username: this.cipherFormContainer.config.initialValues?.username || "",
password: await this.generationService.generateInitialPassword(),
});
}
captureTotp = async () => {

View File

@@ -48,7 +48,7 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService {
return {
mode,
cipherType,
cipherType: cipher?.type ?? cipherType ?? CipherType.Login,
admin: false,
allowPersonalOwnership,
originalCipher: cipher,