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:
@@ -22,6 +22,8 @@ export type OptionalInitialValues = {
|
||||
organizationId?: OrganizationId;
|
||||
collectionIds?: CollectionId[];
|
||||
loginUri?: string;
|
||||
username?: string;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 || "",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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: [],
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -48,7 +48,7 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService {
|
||||
|
||||
return {
|
||||
mode,
|
||||
cipherType,
|
||||
cipherType: cipher?.type ?? cipherType ?? CipherType.Login,
|
||||
admin: false,
|
||||
allowPersonalOwnership,
|
||||
originalCipher: cipher,
|
||||
|
||||
Reference in New Issue
Block a user