diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index d91a33c6796..7781b352672 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1676,9 +1676,30 @@ "turnOffAutofill": { "message": "Turn off autofill" }, + "confirmAutofill": { + "message": "Confirm autofill" + }, + "confirmAutofillDesc": { + "message": "This site doesn't match your saved login details. Before you fill in your login credentials, make sure it's a trusted site." + }, "showInlineMenuLabel": { "message": "Show autofill suggestions on form fields" }, + "howDoesBitwardenProtectFromPhishing": { + "message": "How does Bitwarden protect your data from phishing?" + }, + "currentWebsite": { + "message": "Current website" + }, + "autofillAndAddWebsite": { + "message": "Autofill and add this website" + }, + "autofillWithoutAdding": { + "message": "Autofill without adding" + }, + "doNotAutofill": { + "message": "Do not autofill" + }, "showInlineMenuIdentitiesLabel": { "message": "Display identities as suggestions" }, diff --git a/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html b/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html new file mode 100644 index 00000000000..a8b9dab0d45 --- /dev/null +++ b/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html @@ -0,0 +1,35 @@ + + {{ "confirmAutofill" | i18n }} +
+

+ {{ "confirmAutofillDesc" | i18n }} +

+

+ {{ "currentWebsite" | i18n }} +

+ +
+ +

+ {{ "howDoesBitwardenProtectFromPhishing" | i18n }} +

+
+
+ + + +
+
+
diff --git a/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.ts b/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.ts new file mode 100644 index 00000000000..406d84b42b1 --- /dev/null +++ b/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.ts @@ -0,0 +1,71 @@ +import { CommonModule } from "@angular/common"; +import { Component, Inject } from "@angular/core"; + +import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values"; +import { + DIALOG_DATA, + DialogConfig, + DialogRef, + ButtonModule, + DialogService, + DialogModule, + TypographyModule, + CalloutComponent, +} from "@bitwarden/components"; +import { I18nPipe } from "@bitwarden/ui-common"; + +export interface AutofillConfirmationDialogParams { + savedUris?: string[]; + currentUri: string; +} + +export const AutofillConfirmationDialogResult = Object.freeze({ + AutofillAndUriAdded: "added", + AutofilledOnly: "autofilled", + Canceled: "canceled", +} as const); + +export type AutofillConfirmationDialogResultType = UnionOfValues< + typeof AutofillConfirmationDialogResult +>; + +@Component({ + selector: "autofill-confirmation-dialog", + templateUrl: "./autofill-confirmation-dialog.component.html", + imports: [CalloutComponent, CommonModule, ButtonModule, I18nPipe, DialogModule, TypographyModule], +}) +export class AutofillConfirmationDialogComponent { + AutofillConfirmationDialogResult = AutofillConfirmationDialogResult; + currentUri: string | null = null; + savedUris: string[] = []; + + constructor( + @Inject(DIALOG_DATA) protected params: AutofillConfirmationDialogParams, + private dialogRef: DialogRef, + ) { + this.currentUri = params.currentUri; + this.savedUris = params.savedUris ?? []; + } + + protected close = () => { + this.dialogRef.close(AutofillConfirmationDialogResult.Canceled); + }; + + protected autofillAndAddUri = () => { + this.dialogRef.close(AutofillConfirmationDialogResult.AutofillAndUriAdded); + }; + + protected autofillOnly = () => { + this.dialogRef.close(AutofillConfirmationDialogResult.AutofilledOnly); + }; + + static open( + dialogService: DialogService, + config: DialogConfig, + ) { + return dialogService.open( + AutofillConfirmationDialogComponent, + { ...config }, + ); + } +} diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts index ebcd8707597..58c91773d76 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts @@ -16,6 +16,7 @@ import { CipherId } from "@bitwarden/common/types/guid"; import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums"; +import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { @@ -33,6 +34,10 @@ import { PasswordRepromptService } from "@bitwarden/vault"; import { VaultPopupAutofillService } from "../../../services/vault-popup-autofill.service"; import { AddEditQueryParams } from "../add-edit/add-edit-v2.component"; +import { + AutofillConfirmationDialogComponent, + AutofillConfirmationDialogResult, +} from "../autofill-confirmation-dialog/autofill-confirmation-dialog.component"; @Component({ selector: "app-item-more-options", @@ -176,6 +181,30 @@ export class ItemMoreOptionsComponent { async doAutofillAndSave() { const cipher = await this.cipherService.getFullCipherView(this.cipher); + + const currentTab = await firstValueFrom(this.vaultPopupAutofillService.currentAutofillTab$); + const loginUri = new LoginUriView(); + loginUri.uri = currentTab.url; + const currentUri = loginUri.hostname; + + const ref = AutofillConfirmationDialogComponent.open(this.dialogService, { + data: { + currentUri, + savedUris: cipher.login?.uris?.map((u) => u.uri) ?? [], + }, + }); + + const result = await firstValueFrom(ref.closed); + + if (!result || result === AutofillConfirmationDialogResult.Canceled) { + return; + } + + if (result === AutofillConfirmationDialogResult.AutofilledOnly) { + await this.vaultPopupAutofillService.doAutofill(cipher); + return; + } + await this.vaultPopupAutofillService.doAutofillAndSave(cipher, false); } @@ -266,6 +295,8 @@ export class ItemMoreOptionsComponent { }); } + private async showConfirmAutofillDialog() {} + protected async delete() { const confirmed = await this.dialogService.openSimpleDialog({ title: { key: "deleteItem" },