mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-11 10:10:25 +01:00
[PM-8338] New Autofill Settings Components (#10184)
* add v2 autofill settings component * add and update entries in message catalog for new autofill settings view * add confirmation dialogs ahead of new tabs for browser settings from autofill settings * fix autofill on page load warning styling and improper concatenation * code cleanup
This commit is contained in:
parent
d2afe221f0
commit
0ff62a5cc3
@ -108,7 +108,7 @@
|
||||
"message": "Copy security code"
|
||||
},
|
||||
"autoFill": {
|
||||
"message": "Auto-fill"
|
||||
"message": "Autofill"
|
||||
},
|
||||
"autoFillLogin": {
|
||||
"message": "Auto-fill login"
|
||||
@ -789,12 +789,18 @@
|
||||
"addLoginNotificationDescAlt": {
|
||||
"message": "Ask to add an item if one isn't found in your vault. Applies to all logged in accounts."
|
||||
},
|
||||
"showCardsInVaultView": {
|
||||
"message": "Show cards as Autofill suggestions on Vault view"
|
||||
},
|
||||
"showCardsCurrentTab": {
|
||||
"message": "Show cards on Tab page"
|
||||
},
|
||||
"showCardsCurrentTabDesc": {
|
||||
"message": "List card items on the Tab page for easy auto-fill."
|
||||
},
|
||||
"showIdentitiesInVaultView": {
|
||||
"message": "Show identifies as Autofill suggestions on Vault view"
|
||||
},
|
||||
"showIdentitiesCurrentTab": {
|
||||
"message": "Show identities on Tab page"
|
||||
},
|
||||
@ -1227,11 +1233,20 @@
|
||||
"message": "Show auto-fill menu on form fields",
|
||||
"description": "Represents the message for allowing the user to enable the auto-fill overlay"
|
||||
},
|
||||
"showAutoFillMenuOnFormFieldsDescAlt": {
|
||||
"autofillSuggestionsSectionTitle": {
|
||||
"message": "Autofill suggestions"
|
||||
},
|
||||
"showInlineMenuLabel": {
|
||||
"message": "Show autofill suggestions on form fields"
|
||||
},
|
||||
"showInlineMenuOnIconSelectionLabel": {
|
||||
"message": "Display suggestions when icon is selected"
|
||||
},
|
||||
"showInlineMenuOnFormFieldsDescAlt": {
|
||||
"message": "Applies to all logged in accounts."
|
||||
},
|
||||
"turnOffBrowserBuiltInPasswordManagerSettings": {
|
||||
"message": "Turn off your browser’s built in password manager settings to avoid conflicts."
|
||||
"message": "Turn off your browser's built in password manager settings to avoid conflicts."
|
||||
},
|
||||
"turnOffBrowserBuiltInPasswordManagerSettingsLink": {
|
||||
"message": "Edit browser settings."
|
||||
@ -1248,23 +1263,43 @@
|
||||
"message": "When auto-fill icon is selected",
|
||||
"description": "Overlay appearance select option for showing the field on click of the overlay icon"
|
||||
},
|
||||
"enableAutoFillOnPageLoadSectionTitle": {
|
||||
"message": "Autofill on page load"
|
||||
},
|
||||
"enableAutoFillOnPageLoad": {
|
||||
"message": "Auto-fill on page load"
|
||||
"message": "Autofill on page load"
|
||||
},
|
||||
"enableAutoFillOnPageLoadDesc": {
|
||||
"message": "If a login form is detected, auto-fill when the web page loads."
|
||||
"message": "If a login form is detected, autofill when the web page loads."
|
||||
},
|
||||
"autofillOnPageLoadWarning": {
|
||||
"message": "$OPENTAG$Warning:$CLOSETAG$ Compromised or untrusted websites can exploit autofill on page load.",
|
||||
"placeholders": {
|
||||
"openTag": {
|
||||
"content": "$1",
|
||||
"example": "<b>"
|
||||
},
|
||||
"closeTag": {
|
||||
"content": "$2",
|
||||
"example": "</b>"
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"experimentalFeature": {
|
||||
"message": "Compromised or untrusted websites can exploit auto-fill on page load."
|
||||
"message": "Compromised or untrusted websites can exploit autofill on page load."
|
||||
},
|
||||
"learnMoreAboutAutofillOnPageLoadLinkText": {
|
||||
"message": "Learn more about risks"
|
||||
},
|
||||
"learnMoreAboutAutofill": {
|
||||
"message": "Learn more about auto-fill"
|
||||
"message": "Learn more about autofill"
|
||||
},
|
||||
"defaultAutoFillOnPageLoad": {
|
||||
"message": "Default autofill setting for login items"
|
||||
},
|
||||
"defaultAutoFillOnPageLoadDesc": {
|
||||
"message": "You can turn off auto-fill on page load for individual login items from the item's Edit view."
|
||||
"message": "You can turn off autofill on page load for individual login items from the item's Edit view."
|
||||
},
|
||||
"itemAutoFillOnPageLoad": {
|
||||
"message": "Auto-fill on page load (if set up in Options)"
|
||||
@ -1273,10 +1308,10 @@
|
||||
"message": "Use default setting"
|
||||
},
|
||||
"autoFillOnPageLoadYes": {
|
||||
"message": "Auto-fill on page load"
|
||||
"message": "Autofill on page load"
|
||||
},
|
||||
"autoFillOnPageLoadNo": {
|
||||
"message": "Do not auto-fill on page load"
|
||||
"message": "Do not autofill on page load"
|
||||
},
|
||||
"commandOpenPopup": {
|
||||
"message": "Open vault popup"
|
||||
@ -2004,7 +2039,7 @@
|
||||
"placeholders": {
|
||||
"domain": {
|
||||
"content": "$1",
|
||||
"example": "google.com"
|
||||
"example": "duckduckgo.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2706,14 +2741,20 @@
|
||||
"autofillSettings": {
|
||||
"message": "Auto-fill settings"
|
||||
},
|
||||
"autofillKeyboardShortcutSectionTitle": {
|
||||
"message": "Autofill shortcut"
|
||||
},
|
||||
"autofillKeyboardShortcutUpdateLabel": {
|
||||
"message": "Change shortcut"
|
||||
},
|
||||
"autofillShortcut": {
|
||||
"message": "Auto-fill keyboard shortcut"
|
||||
"message": "Autofill keyboard shortcut"
|
||||
},
|
||||
"autofillShortcutNotSet": {
|
||||
"message": "The auto-fill shortcut is not set. Change this in the browser's settings."
|
||||
"message": "The autofill shortcut is not set. Change this in the browser's settings."
|
||||
},
|
||||
"autofillShortcutText": {
|
||||
"message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.",
|
||||
"message": "The autofill shortcut is: $COMMAND$. Change this in the browser's settings.",
|
||||
"placeholders": {
|
||||
"command": {
|
||||
"content": "$1",
|
||||
@ -3369,7 +3410,7 @@
|
||||
"placeholders": {
|
||||
"domain": {
|
||||
"content": "$1",
|
||||
"example": "google.com"
|
||||
"example": "duckduckgo.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -3377,12 +3418,36 @@
|
||||
"message": "Common formats",
|
||||
"description": "Label indicating the most common import formats"
|
||||
},
|
||||
"confirmContinueToBrowserSettingsTitle": {
|
||||
"message": "Continue to browser settings?",
|
||||
"description": "Title for dialog which asks if the user wants to proceed to a relevant browser settings page"
|
||||
},
|
||||
"confirmContinueToHelpCenter": {
|
||||
"message": "Continue to Help Center?",
|
||||
"description": "Title for dialog which asks if the user wants to proceed to a relevant Help Center page"
|
||||
},
|
||||
"confirmContinueToHelpCenterPasswordManagementContent": {
|
||||
"message": "Change your browser's autofill and password management settings.",
|
||||
"description": "Body content for dialog which asks if the user wants to proceed to the Help Center's page about browser password management settings"
|
||||
},
|
||||
"confirmContinueToHelpCenterKeyboardShortcutsContent": {
|
||||
"message": "You can view and set extension shortcuts in your browser's settings.",
|
||||
"description": "Body content for dialog which asks if the user wants to proceed to the Help Center's page about browser keyboard shortcut settings"
|
||||
},
|
||||
"confirmContinueToBrowserPasswordManagementSettingsContent": {
|
||||
"message": "Change your browser's autofill and password management settings.",
|
||||
"description": "Body content for dialog which asks if the user wants to proceed to the browser's password management settings page"
|
||||
},
|
||||
"confirmContinueToBrowserKeyboardShortcutSettingsContent": {
|
||||
"message": "You can view and set extension shortcuts in your browser's settings.",
|
||||
"description": "Body content for dialog which asks if the user wants to proceed to the browser's keyboard shortcut settings page"
|
||||
},
|
||||
"overrideDefaultBrowserAutofillTitle": {
|
||||
"message": "Make Bitwarden your default password manager?",
|
||||
"description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior"
|
||||
},
|
||||
"overrideDefaultBrowserAutofillDescription": {
|
||||
"message": "Ignoring this option may cause conflicts between the Bitwarden auto-fill menu and your browser's.",
|
||||
"message": "Ignoring this option may cause conflicts between Bitwarden autofill suggestions and your browser's.",
|
||||
"description": "Dialog message facilitating the ability to override a chrome browser's default autofill behavior"
|
||||
},
|
||||
"overrideDefaultBrowserAutoFillSettings": {
|
||||
|
@ -0,0 +1,221 @@
|
||||
<header>
|
||||
<div class="left">
|
||||
<button type="button" routerLink="/tabs/settings">
|
||||
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
||||
<span>{{ "back" | i18n }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<h1 class="center">
|
||||
<span class="title">{{ "autofill" | i18n }}</span>
|
||||
</h1>
|
||||
<div class="right"></div>
|
||||
</header>
|
||||
<main tabindex="-1">
|
||||
<div class="box tw-mt-4">
|
||||
<div class="box-content">
|
||||
<button
|
||||
type="button"
|
||||
class="box-content-row box-content-row-link box-content-row-flex"
|
||||
(click)="commandSettings()"
|
||||
>
|
||||
<div class="row-main">{{ "autofillShortcut" | i18n }}</div>
|
||||
<i class="bwi bwi-external-link bwi-lg bwi-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="autofillKeyboardHelp" class="box-footer">
|
||||
{{ autofillKeyboardHelperText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="autofill-overlay-settings">{{ "showAutoFillMenuOnFormFields" | i18n }}</label>
|
||||
<select
|
||||
id="autofill-overlay-settings"
|
||||
name="autofill-overlay-settings"
|
||||
[(ngModel)]="autoFillOverlayVisibility"
|
||||
(change)="updateAutoFillOverlayVisibility()"
|
||||
>
|
||||
<option *ngFor="let o of autoFillOverlayVisibilityOptions" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="box-footer" *ngIf="accountSwitcherEnabled && canOverrideBrowserAutofillSetting">
|
||||
{{ "showInlineMenuOnFormFieldsDescAlt" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-content" *ngIf="canOverrideBrowserAutofillSetting">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="overrideBrowserAutofill" class="!tw-mr-0">{{
|
||||
"overrideDefaultBrowserAutoFillSettings" | i18n
|
||||
}}</label>
|
||||
<input
|
||||
id="overrideBrowserAutofill"
|
||||
type="checkbox"
|
||||
(change)="updateDefaultBrowserAutofillDisabled()"
|
||||
[(ngModel)]="defaultBrowserAutofillDisabled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<span *ngIf="accountSwitcherEnabled">{{ "showInlineMenuOnFormFieldsDescAlt" | i18n }}</span>
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettings" | i18n }}
|
||||
<a
|
||||
[attr.href]="disablePasswordManagerLink"
|
||||
(click)="openDisablePasswordManagerLink($event)"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettingsLink" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box tw-mt-4">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="autofill">{{ "enableAutoFillOnPageLoad" | i18n }}</label>
|
||||
<input
|
||||
id="autofill"
|
||||
type="checkbox"
|
||||
aria-describedby="autofillHelp"
|
||||
(change)="updateAutoFillOnPageLoad()"
|
||||
[(ngModel)]="enableAutoFillOnPageLoad"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="autofillHelp" class="box-footer">
|
||||
{{ "enableAutoFillOnPageLoadDesc" | i18n }}
|
||||
<b>{{ "warning" | i18n }}</b
|
||||
>: {{ "experimentalFeature" | i18n }}
|
||||
<a href="https://bitwarden.com/help/auto-fill-browser/" target="_blank" rel="noreferrer">
|
||||
{{ "learnMoreAboutAutofill" | i18n }}.
|
||||
<i
|
||||
[attr.aria-label]="'opensInANewWindow' | i18n"
|
||||
class="bwi bwi-external-link bwi-sm bwi-fw"
|
||||
></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="defaultAutofill">{{ "defaultAutoFillOnPageLoad" | i18n }}</label>
|
||||
<select
|
||||
id="defaultAutofill"
|
||||
name="DefaultAutofill"
|
||||
aria-describedby="defaultAutofillHelp"
|
||||
[(ngModel)]="autoFillOnPageLoadDefault"
|
||||
(change)="updateAutoFillOnPageLoadDefault()"
|
||||
[disabled]="!enableAutoFillOnPageLoad"
|
||||
>
|
||||
<option *ngFor="let o of autoFillOnPageLoadOptions" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="defaultAutofillHelp" class="box-footer">
|
||||
{{ "defaultAutoFillOnPageLoadDesc" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h2 class="box-header">{{ "additionalOptions" | i18n }}</h2>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="context-menu">{{ "enableContextMenuItem" | i18n }}</label>
|
||||
<input
|
||||
id="context-menu"
|
||||
type="checkbox"
|
||||
aria-describedby="context-menuHelp"
|
||||
(change)="updateContextMenuItem()"
|
||||
[(ngModel)]="enableContextMenuItem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="context-menuHelp" class="box-footer">
|
||||
{{
|
||||
accountSwitcherEnabled ? ("contextMenuItemDescAlt" | i18n) : ("contextMenuItemDesc" | i18n)
|
||||
}}
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="totp">{{ "enableAutoTotpCopy" | i18n }}</label>
|
||||
<input
|
||||
id="totp"
|
||||
type="checkbox"
|
||||
aria-describedby="totpHelp"
|
||||
(change)="updateAutoTotpCopy()"
|
||||
[(ngModel)]="enableAutoTotpCopy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="totpHelp" class="box-footer">{{ "disableAutoTotpCopyDesc" | i18n }}</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="clearClipboard">{{ "clearClipboard" | i18n }}</label>
|
||||
<select
|
||||
id="clearClipboard"
|
||||
name="ClearClipboard"
|
||||
aria-describedby="clearClipboardHelp"
|
||||
[(ngModel)]="clearClipboard"
|
||||
(change)="saveClearClipboard()"
|
||||
>
|
||||
<option *ngFor="let o of clearClipboardOptions" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="clearClipboardHelp" class="box-footer">{{ "clearClipboardDesc" | i18n }}</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="defaultUriMatch">{{ "defaultUriMatchDetection" | i18n }}</label>
|
||||
<select
|
||||
id="defaultUriMatch"
|
||||
name="DefaultUriMatch"
|
||||
aria-describedby="defaultUriMatchHelp"
|
||||
[(ngModel)]="defaultUriMatch"
|
||||
(change)="saveDefaultUriMatch()"
|
||||
>
|
||||
<option *ngFor="let o of uriMatchOptions" [ngValue]="o.value">{{ o.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="defaultUriMatchHelp" class="box-footer">
|
||||
{{ "defaultUriMatchDetectionDesc" | i18n }}
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="showCardsCurrentTab">{{ "showCardsCurrentTab" | i18n }}</label>
|
||||
<input
|
||||
id="showCardsCurrentTab"
|
||||
type="checkbox"
|
||||
aria-describedby="showCardsCurrentTabHelp"
|
||||
(change)="updateShowCardsCurrentTab()"
|
||||
[(ngModel)]="showCardsCurrentTab"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="showCardsCurrentTabHelp" class="box-footer">
|
||||
{{ "showCardsCurrentTabDesc" | i18n }}
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="showIdentitiesCurrentTab">{{ "showIdentitiesCurrentTab" | i18n }}</label>
|
||||
<input
|
||||
id="showIdentitiesCurrentTab"
|
||||
type="checkbox"
|
||||
aria-describedby="showIdentitiesCurrentTabHelp"
|
||||
(change)="updateShowIdentitiesCurrentTab()"
|
||||
[(ngModel)]="showIdentitiesCurrentTab"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="showIdentitiesCurrentTabHelp" class="box-footer">
|
||||
{{ "showIdentitiesCurrentTabDesc" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
@ -0,0 +1,301 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import {
|
||||
InlineMenuVisibilitySetting,
|
||||
ClearClipboardDelaySetting,
|
||||
} from "@bitwarden/common/autofill/types";
|
||||
import {
|
||||
UriMatchStrategy,
|
||||
UriMatchStrategySetting,
|
||||
} from "@bitwarden/common/models/domain/domain-service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||
import { enableAccountSwitching } from "../../../platform/flags";
|
||||
import { AutofillService } from "../../services/abstractions/autofill.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-autofill-v1",
|
||||
templateUrl: "autofill-v1.component.html",
|
||||
})
|
||||
export class AutofillV1Component implements OnInit {
|
||||
protected canOverrideBrowserAutofillSetting = false;
|
||||
protected defaultBrowserAutofillDisabled = false;
|
||||
protected autoFillOverlayVisibility: InlineMenuVisibilitySetting;
|
||||
protected autoFillOverlayVisibilityOptions: any[];
|
||||
protected disablePasswordManagerLink: string;
|
||||
enableAutoFillOnPageLoad = false;
|
||||
autoFillOnPageLoadDefault = false;
|
||||
autoFillOnPageLoadOptions: any[];
|
||||
enableContextMenuItem = false;
|
||||
enableAutoTotpCopy = false; // TODO: Does it matter if this is set to false or true?
|
||||
clearClipboard: ClearClipboardDelaySetting;
|
||||
clearClipboardOptions: any[];
|
||||
defaultUriMatch: UriMatchStrategySetting = UriMatchStrategy.Domain;
|
||||
uriMatchOptions: any[];
|
||||
showCardsCurrentTab = false;
|
||||
showIdentitiesCurrentTab = false;
|
||||
autofillKeyboardHelperText: string;
|
||||
accountSwitcherEnabled = false;
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private domainSettingsService: DomainSettingsService,
|
||||
private autofillService: AutofillService,
|
||||
private dialogService: DialogService,
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private messagingService: MessagingService,
|
||||
private vaultSettingsService: VaultSettingsService,
|
||||
) {
|
||||
this.autoFillOverlayVisibilityOptions = [
|
||||
{
|
||||
name: i18nService.t("autofillOverlayVisibilityOff"),
|
||||
value: AutofillOverlayVisibility.Off,
|
||||
},
|
||||
{
|
||||
name: i18nService.t("autofillOverlayVisibilityOnFieldFocus"),
|
||||
value: AutofillOverlayVisibility.OnFieldFocus,
|
||||
},
|
||||
{
|
||||
name: i18nService.t("autofillOverlayVisibilityOnButtonClick"),
|
||||
value: AutofillOverlayVisibility.OnButtonClick,
|
||||
},
|
||||
];
|
||||
this.autoFillOnPageLoadOptions = [
|
||||
{ name: i18nService.t("autoFillOnPageLoadYes"), value: true },
|
||||
{ name: i18nService.t("autoFillOnPageLoadNo"), value: false },
|
||||
];
|
||||
this.clearClipboardOptions = [
|
||||
{ name: i18nService.t("never"), value: null },
|
||||
{ name: i18nService.t("tenSeconds"), value: 10 },
|
||||
{ name: i18nService.t("twentySeconds"), value: 20 },
|
||||
{ name: i18nService.t("thirtySeconds"), value: 30 },
|
||||
{ name: i18nService.t("oneMinute"), value: 60 },
|
||||
{ name: i18nService.t("twoMinutes"), value: 120 },
|
||||
{ name: i18nService.t("fiveMinutes"), value: 300 },
|
||||
];
|
||||
this.uriMatchOptions = [
|
||||
{ name: i18nService.t("baseDomain"), value: UriMatchStrategy.Domain },
|
||||
{ name: i18nService.t("host"), value: UriMatchStrategy.Host },
|
||||
{ name: i18nService.t("startsWith"), value: UriMatchStrategy.StartsWith },
|
||||
{ name: i18nService.t("regEx"), value: UriMatchStrategy.RegularExpression },
|
||||
{ name: i18nService.t("exact"), value: UriMatchStrategy.Exact },
|
||||
{ name: i18nService.t("never"), value: UriMatchStrategy.Never },
|
||||
];
|
||||
|
||||
this.accountSwitcherEnabled = enableAccountSwitching();
|
||||
this.disablePasswordManagerLink = this.getDisablePasswordManagerLink();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.canOverrideBrowserAutofillSetting =
|
||||
this.platformUtilsService.isChrome() ||
|
||||
this.platformUtilsService.isEdge() ||
|
||||
this.platformUtilsService.isOpera() ||
|
||||
this.platformUtilsService.isVivaldi();
|
||||
|
||||
this.defaultBrowserAutofillDisabled = await this.browserAutofillSettingCurrentlyOverridden();
|
||||
|
||||
this.autoFillOverlayVisibility = await firstValueFrom(
|
||||
this.autofillSettingsService.inlineMenuVisibility$,
|
||||
);
|
||||
|
||||
this.enableAutoFillOnPageLoad = await firstValueFrom(
|
||||
this.autofillSettingsService.autofillOnPageLoad$,
|
||||
);
|
||||
|
||||
this.autoFillOnPageLoadDefault = await firstValueFrom(
|
||||
this.autofillSettingsService.autofillOnPageLoadDefault$,
|
||||
);
|
||||
|
||||
this.enableContextMenuItem = await firstValueFrom(
|
||||
this.autofillSettingsService.enableContextMenu$,
|
||||
);
|
||||
|
||||
this.enableAutoTotpCopy = await firstValueFrom(this.autofillSettingsService.autoCopyTotp$);
|
||||
|
||||
this.clearClipboard = await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$);
|
||||
|
||||
const defaultUriMatch = await firstValueFrom(
|
||||
this.domainSettingsService.defaultUriMatchStrategy$,
|
||||
);
|
||||
this.defaultUriMatch = defaultUriMatch == null ? UriMatchStrategy.Domain : defaultUriMatch;
|
||||
|
||||
const command = await this.platformUtilsService.getAutofillKeyboardShortcut();
|
||||
await this.setAutofillKeyboardHelperText(command);
|
||||
|
||||
this.showCardsCurrentTab = await firstValueFrom(this.vaultSettingsService.showCardsCurrentTab$);
|
||||
|
||||
this.showIdentitiesCurrentTab = await firstValueFrom(
|
||||
this.vaultSettingsService.showIdentitiesCurrentTab$,
|
||||
);
|
||||
}
|
||||
|
||||
async updateAutoFillOverlayVisibility() {
|
||||
await this.autofillSettingsService.setInlineMenuVisibility(this.autoFillOverlayVisibility);
|
||||
await this.requestPrivacyPermission();
|
||||
}
|
||||
|
||||
async updateAutoFillOnPageLoad() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoad(this.enableAutoFillOnPageLoad);
|
||||
}
|
||||
|
||||
async updateAutoFillOnPageLoadDefault() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoadDefault(this.autoFillOnPageLoadDefault);
|
||||
}
|
||||
|
||||
async saveDefaultUriMatch() {
|
||||
await this.domainSettingsService.setDefaultUriMatchStrategy(this.defaultUriMatch);
|
||||
}
|
||||
|
||||
private async setAutofillKeyboardHelperText(command: string) {
|
||||
if (command) {
|
||||
this.autofillKeyboardHelperText = this.i18nService.t("autofillShortcutText", command);
|
||||
} else {
|
||||
this.autofillKeyboardHelperText = this.i18nService.t("autofillShortcutNotSet");
|
||||
}
|
||||
}
|
||||
|
||||
async commandSettings() {
|
||||
if (this.platformUtilsService.isChrome()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("chrome://extensions/shortcuts");
|
||||
} else if (this.platformUtilsService.isOpera()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("opera://extensions/shortcuts");
|
||||
} else if (this.platformUtilsService.isEdge()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("edge://extensions/shortcuts");
|
||||
} else if (this.platformUtilsService.isVivaldi()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("vivaldi://extensions/shortcuts");
|
||||
} else {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("https://bitwarden.com/help/keyboard-shortcuts");
|
||||
}
|
||||
}
|
||||
|
||||
private getDisablePasswordManagerLink(): string {
|
||||
if (this.platformUtilsService.isChrome()) {
|
||||
return "chrome://settings/autofill";
|
||||
}
|
||||
if (this.platformUtilsService.isOpera()) {
|
||||
return "opera://settings/autofill";
|
||||
}
|
||||
if (this.platformUtilsService.isEdge()) {
|
||||
return "edge://settings/passwords";
|
||||
}
|
||||
if (this.platformUtilsService.isVivaldi()) {
|
||||
return "vivaldi://settings/autofill";
|
||||
}
|
||||
|
||||
return "https://bitwarden.com/help/disable-browser-autofill/";
|
||||
}
|
||||
|
||||
protected openDisablePasswordManagerLink(event: Event) {
|
||||
event.preventDefault();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab(this.disablePasswordManagerLink);
|
||||
}
|
||||
|
||||
async requestPrivacyPermission() {
|
||||
if (
|
||||
this.autoFillOverlayVisibility === AutofillOverlayVisibility.Off ||
|
||||
!this.canOverrideBrowserAutofillSetting ||
|
||||
(await this.browserAutofillSettingCurrentlyOverridden())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "overrideDefaultBrowserAutofillTitle" },
|
||||
content: { key: "overrideDefaultBrowserAutofillDescription" },
|
||||
acceptButtonText: { key: "makeDefault" },
|
||||
acceptAction: async () => await this.handleOverrideDialogAccept(),
|
||||
cancelButtonText: { key: "ignore" },
|
||||
type: "info",
|
||||
});
|
||||
}
|
||||
|
||||
async updateDefaultBrowserAutofillDisabled() {
|
||||
const privacyPermissionGranted = await this.privacyPermissionGranted();
|
||||
if (!this.defaultBrowserAutofillDisabled && !privacyPermissionGranted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!privacyPermissionGranted &&
|
||||
!(await BrowserApi.requestPermission({ permissions: ["privacy"] }))
|
||||
) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "privacyPermissionAdditionNotGrantedTitle" },
|
||||
content: { key: "privacyPermissionAdditionNotGrantedDescription" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "warning",
|
||||
});
|
||||
this.defaultBrowserAutofillDisabled = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserApi.updateDefaultBrowserAutofillSettings(!this.defaultBrowserAutofillDisabled);
|
||||
}
|
||||
|
||||
private handleOverrideDialogAccept = async () => {
|
||||
this.defaultBrowserAutofillDisabled = true;
|
||||
await this.updateDefaultBrowserAutofillDisabled();
|
||||
};
|
||||
|
||||
async browserAutofillSettingCurrentlyOverridden() {
|
||||
if (!this.canOverrideBrowserAutofillSetting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(await this.privacyPermissionGranted())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await BrowserApi.browserAutofillSettingsOverridden();
|
||||
}
|
||||
|
||||
async privacyPermissionGranted(): Promise<boolean> {
|
||||
return await BrowserApi.permissionsGranted(["privacy"]);
|
||||
}
|
||||
|
||||
async updateContextMenuItem() {
|
||||
await this.autofillSettingsService.setEnableContextMenu(this.enableContextMenuItem);
|
||||
this.messagingService.send("bgUpdateContextMenu");
|
||||
}
|
||||
|
||||
async updateAutoTotpCopy() {
|
||||
await this.autofillSettingsService.setAutoCopyTotp(this.enableAutoTotpCopy);
|
||||
}
|
||||
|
||||
async saveClearClipboard() {
|
||||
await this.autofillSettingsService.setClearClipboardDelay(this.clearClipboard);
|
||||
}
|
||||
|
||||
async updateShowCardsCurrentTab() {
|
||||
await this.vaultSettingsService.setShowCardsCurrentTab(this.showCardsCurrentTab);
|
||||
}
|
||||
|
||||
async updateShowIdentitiesCurrentTab() {
|
||||
await this.vaultSettingsService.setShowIdentitiesCurrentTab(this.showIdentitiesCurrentTab);
|
||||
}
|
||||
}
|
@ -1,221 +1,234 @@
|
||||
<header>
|
||||
<div class="left">
|
||||
<button type="button" routerLink="/tabs/settings">
|
||||
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
||||
<span>{{ "back" | i18n }}</span>
|
||||
</button>
|
||||
<popup-page>
|
||||
<popup-header slot="header" pageTitle="{{ 'autofill' | i18n }}" showBackButton>
|
||||
<ng-container slot="end">
|
||||
<app-pop-out></app-pop-out>
|
||||
</ng-container>
|
||||
</popup-header>
|
||||
|
||||
<div class="tw-bg-background-alt tw-p-2">
|
||||
<bit-section>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h5">{{ "autofillSuggestionsSectionTitle" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="show-inline-menu"
|
||||
type="checkbox"
|
||||
(change)="updateInlineMenuVisibility()"
|
||||
[(ngModel)]="enableInlineMenu"
|
||||
/>
|
||||
<bit-label for="show-inline-menu">{{ "showInlineMenuLabel" | i18n }}</bit-label>
|
||||
<bit-hint
|
||||
*ngIf="accountSwitcherEnabled && canOverrideBrowserAutofillSetting"
|
||||
class="tw-text-sm"
|
||||
>
|
||||
{{ "showInlineMenuOnFormFieldsDescAlt" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-control *ngIf="enableInlineMenu" class="tw-pl-5">
|
||||
<input
|
||||
bitCheckbox
|
||||
id="show-autofill-suggestions-on-icon"
|
||||
type="checkbox"
|
||||
(change)="updateInlineMenuVisibility()"
|
||||
[(ngModel)]="enableInlineMenuOnIconSelect"
|
||||
/>
|
||||
<bit-label for="show-autofill-suggestions-on-icon">
|
||||
{{ "showInlineMenuOnIconSelectionLabel" | i18n }}
|
||||
</bit-label>
|
||||
<bit-hint class="tw-text-sm" *ngIf="!canOverrideBrowserAutofillSetting">
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettings" | i18n }}
|
||||
<a
|
||||
bitLink
|
||||
class="tw-no-underline"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
(click)="openURI($event, disablePasswordManagerURI)"
|
||||
[attr.href]="disablePasswordManagerURI"
|
||||
>
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettingsLink" | i18n }}
|
||||
</a>
|
||||
</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-control *ngIf="canOverrideBrowserAutofillSetting">
|
||||
<input
|
||||
bitCheckbox
|
||||
id="overrideBrowserAutofill"
|
||||
type="checkbox"
|
||||
(change)="updateDefaultBrowserAutofillDisabled()"
|
||||
[(ngModel)]="defaultBrowserAutofillDisabled"
|
||||
/>
|
||||
<bit-label for="overrideBrowserAutofill">{{
|
||||
"overrideDefaultBrowserAutoFillSettings" | i18n
|
||||
}}</bit-label>
|
||||
<bit-hint class="tw-text-sm">
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettings" | i18n }}
|
||||
<a
|
||||
bitLink
|
||||
class="tw-no-underline"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
(click)="openURI($event, disablePasswordManagerURI)"
|
||||
[attr.href]="disablePasswordManagerURI"
|
||||
>
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettingsLink" | i18n }}
|
||||
</a>
|
||||
</bit-hint>
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="showCardsSuggestions"
|
||||
type="checkbox"
|
||||
(change)="updateShowCardsCurrentTab()"
|
||||
[(ngModel)]="showCardsCurrentTab"
|
||||
/>
|
||||
<bit-label for="showCardsSuggestions">{{ "showCardsInVaultView" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="showIdentitiesSuggestions"
|
||||
type="checkbox"
|
||||
(change)="updateShowIdentitiesCurrentTab()"
|
||||
[(ngModel)]="showIdentitiesCurrentTab"
|
||||
/>
|
||||
<bit-label for="showIdentitiesSuggestions" class="tw-whitespace-normal">
|
||||
{{ "showIdentitiesInVaultView" | i18n }}
|
||||
</bit-label>
|
||||
</bit-form-control>
|
||||
</bit-card>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h5">{{ "autofillKeyboardShortcutSectionTitle" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-item>
|
||||
<button bit-item-content type="button" (click)="openURI($event, browserShortcutsURI)">
|
||||
<h3 bitTypography="h5">{{ "autofillKeyboardShortcutUpdateLabel" | i18n }}</h3>
|
||||
<bit-hint slot="secondary" class="tw-text-sm tw-whitespace-normal">
|
||||
{{ autofillKeyboardHelperText }}
|
||||
</bit-hint>
|
||||
<i
|
||||
appA11yTitle="{{ 'opensInANewWindow' | i18n }}"
|
||||
aria-hidden="true"
|
||||
class="bwi bwi-fw bwi-external-link bwi-lg tw-text-muted"
|
||||
slot="end"
|
||||
></i>
|
||||
</button>
|
||||
</bit-item>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h5">{{ "enableAutoFillOnPageLoadSectionTitle" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-hint class="tw-mb-6 tw-text-sm">
|
||||
{{ "enableAutoFillOnPageLoadDesc" | i18n }}
|
||||
<span [innerHTML]="'autofillOnPageLoadWarning' | i18n: '\<b>' : '\</b>'"></span>
|
||||
<a
|
||||
bitLink
|
||||
class="tw-no-underline"
|
||||
href="https://bitwarden.com/help/auto-fill-browser/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{{ "learnMoreAboutAutofillOnPageLoadLinkText" | i18n }}
|
||||
</a>
|
||||
</bit-hint>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="autofillOnPageLoad"
|
||||
type="checkbox"
|
||||
(change)="updateAutofillOnPageLoad()"
|
||||
[(ngModel)]="enableAutofillOnPageLoad"
|
||||
/>
|
||||
<bit-label for="autofillOnPageLoad">{{ "enableAutoFillOnPageLoad" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-field>
|
||||
<bit-label for="defaultAutofill">{{ "defaultAutoFillOnPageLoad" | i18n }}</bit-label>
|
||||
<select
|
||||
bitInput
|
||||
id="defaultAutofill"
|
||||
(change)="updateAutofillOnPageLoadDefault()"
|
||||
[(ngModel)]="autofillOnPageLoadDefault"
|
||||
[disabled]="!enableAutofillOnPageLoad"
|
||||
>
|
||||
<option
|
||||
*ngFor="let o of autofillOnPageLoadOptions"
|
||||
[value]="o.value"
|
||||
[label]="o.name"
|
||||
></option>
|
||||
</select>
|
||||
<bit-hint class="tw-text-sm">
|
||||
{{ "defaultAutoFillOnPageLoadDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h5">{{ "additionalOptions" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="context-menu"
|
||||
type="checkbox"
|
||||
(change)="updateContextMenuItem()"
|
||||
[(ngModel)]="enableContextMenuItem"
|
||||
/>
|
||||
<bit-label for="context-menu">{{ "enableContextMenuItem" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="totp"
|
||||
type="checkbox"
|
||||
(change)="updateAutoTotpCopy()"
|
||||
[(ngModel)]="enableAutoTotpCopy"
|
||||
/>
|
||||
<bit-label for="totp">{{ "enableAutoTotpCopy" | i18n }}</bit-label>
|
||||
</bit-form-control>
|
||||
<bit-form-field>
|
||||
<bit-label for="clearClipboard">{{ "clearClipboard" | i18n }}</bit-label>
|
||||
<select
|
||||
aria-describedby="clearClipboardHelp"
|
||||
bitInput
|
||||
id="clearClipboard"
|
||||
(change)="saveClearClipboard()"
|
||||
[(ngModel)]="clearClipboard"
|
||||
>
|
||||
<option
|
||||
*ngFor="let o of clearClipboardOptions"
|
||||
[label]="o.name"
|
||||
[value]="o.value"
|
||||
></option>
|
||||
</select>
|
||||
<bit-hint class="tw-text-sm" id="clearClipboardHelp">
|
||||
{{ "clearClipboardDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
<bit-form-field>
|
||||
<bit-label for="defaultUriMatch">{{ "defaultUriMatchDetection" | i18n }}</bit-label>
|
||||
<select
|
||||
aria-describedby="defaultUriMatchHelp"
|
||||
bitInput
|
||||
id="defaultUriMatch"
|
||||
(change)="saveDefaultUriMatch()"
|
||||
[(ngModel)]="defaultUriMatch"
|
||||
>
|
||||
<option *ngFor="let o of uriMatchOptions" [label]="o.name" [value]="o.value"></option>
|
||||
</select>
|
||||
<bit-hint class="tw-text-sm" id="defaultUriMatchHelp">
|
||||
{{ "defaultUriMatchDetectionDesc" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
</bit-card>
|
||||
</bit-section>
|
||||
</div>
|
||||
<h1 class="center">
|
||||
<span class="title">{{ "autofill" | i18n }}</span>
|
||||
</h1>
|
||||
<div class="right"></div>
|
||||
</header>
|
||||
<main tabindex="-1">
|
||||
<div class="box tw-mt-4">
|
||||
<div class="box-content">
|
||||
<button
|
||||
type="button"
|
||||
class="box-content-row box-content-row-link box-content-row-flex"
|
||||
(click)="commandSettings()"
|
||||
>
|
||||
<div class="row-main">{{ "autofillShortcut" | i18n }}</div>
|
||||
<i class="bwi bwi-external-link bwi-lg bwi-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="autofillKeyboardHelp" class="box-footer">
|
||||
{{ autofillKeyboardHelperText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="autofill-overlay-settings">{{ "showAutoFillMenuOnFormFields" | i18n }}</label>
|
||||
<select
|
||||
id="autofill-overlay-settings"
|
||||
name="autofill-overlay-settings"
|
||||
[(ngModel)]="autoFillOverlayVisibility"
|
||||
(change)="updateAutoFillOverlayVisibility()"
|
||||
>
|
||||
<option *ngFor="let o of autoFillOverlayVisibilityOptions" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="box-footer" *ngIf="accountSwitcherEnabled && canOverrideBrowserAutofillSetting">
|
||||
{{ "showAutoFillMenuOnFormFieldsDescAlt" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-content" *ngIf="canOverrideBrowserAutofillSetting">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="overrideBrowserAutofill" class="!tw-mr-0">{{
|
||||
"overrideDefaultBrowserAutoFillSettings" | i18n
|
||||
}}</label>
|
||||
<input
|
||||
id="overrideBrowserAutofill"
|
||||
type="checkbox"
|
||||
(change)="updateDefaultBrowserAutofillDisabled()"
|
||||
[(ngModel)]="defaultBrowserAutofillDisabled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<span *ngIf="accountSwitcherEnabled">{{ "showAutoFillMenuOnFormFieldsDescAlt" | i18n }}</span>
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettings" | i18n }}
|
||||
<a
|
||||
[attr.href]="disablePasswordManagerLink"
|
||||
(click)="openDisablePasswordManagerLink($event)"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ "turnOffBrowserBuiltInPasswordManagerSettingsLink" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box tw-mt-4">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="autofill">{{ "enableAutoFillOnPageLoad" | i18n }}</label>
|
||||
<input
|
||||
id="autofill"
|
||||
type="checkbox"
|
||||
aria-describedby="autofillHelp"
|
||||
(change)="updateAutoFillOnPageLoad()"
|
||||
[(ngModel)]="enableAutoFillOnPageLoad"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="autofillHelp" class="box-footer">
|
||||
{{ "enableAutoFillOnPageLoadDesc" | i18n }}
|
||||
<b>{{ "warning" | i18n }}</b
|
||||
>: {{ "experimentalFeature" | i18n }}
|
||||
<a href="https://bitwarden.com/help/auto-fill-browser/" target="_blank" rel="noreferrer">
|
||||
{{ "learnMoreAboutAutofill" | i18n }}.
|
||||
<i
|
||||
[attr.aria-label]="'opensInANewWindow' | i18n"
|
||||
class="bwi bwi-external-link bwi-sm bwi-fw"
|
||||
></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="defaultAutofill">{{ "defaultAutoFillOnPageLoad" | i18n }}</label>
|
||||
<select
|
||||
id="defaultAutofill"
|
||||
name="DefaultAutofill"
|
||||
aria-describedby="defaultAutofillHelp"
|
||||
[(ngModel)]="autoFillOnPageLoadDefault"
|
||||
(change)="updateAutoFillOnPageLoadDefault()"
|
||||
[disabled]="!enableAutoFillOnPageLoad"
|
||||
>
|
||||
<option *ngFor="let o of autoFillOnPageLoadOptions" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="defaultAutofillHelp" class="box-footer">
|
||||
{{ "defaultAutoFillOnPageLoadDesc" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h2 class="box-header">{{ "additionalOptions" | i18n }}</h2>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="context-menu">{{ "enableContextMenuItem" | i18n }}</label>
|
||||
<input
|
||||
id="context-menu"
|
||||
type="checkbox"
|
||||
aria-describedby="context-menuHelp"
|
||||
(change)="updateContextMenuItem()"
|
||||
[(ngModel)]="enableContextMenuItem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="context-menuHelp" class="box-footer">
|
||||
{{
|
||||
accountSwitcherEnabled ? ("contextMenuItemDescAlt" | i18n) : ("contextMenuItemDesc" | i18n)
|
||||
}}
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="totp">{{ "enableAutoTotpCopy" | i18n }}</label>
|
||||
<input
|
||||
id="totp"
|
||||
type="checkbox"
|
||||
aria-describedby="totpHelp"
|
||||
(change)="updateAutoTotpCopy()"
|
||||
[(ngModel)]="enableAutoTotpCopy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="totpHelp" class="box-footer">{{ "disableAutoTotpCopyDesc" | i18n }}</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="clearClipboard">{{ "clearClipboard" | i18n }}</label>
|
||||
<select
|
||||
id="clearClipboard"
|
||||
name="ClearClipboard"
|
||||
aria-describedby="clearClipboardHelp"
|
||||
[(ngModel)]="clearClipboard"
|
||||
(change)="saveClearClipboard()"
|
||||
>
|
||||
<option *ngFor="let o of clearClipboardOptions" [ngValue]="o.value">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="clearClipboardHelp" class="box-footer">{{ "clearClipboardDesc" | i18n }}</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row" appBoxRow>
|
||||
<label for="defaultUriMatch">{{ "defaultUriMatchDetection" | i18n }}</label>
|
||||
<select
|
||||
id="defaultUriMatch"
|
||||
name="DefaultUriMatch"
|
||||
aria-describedby="defaultUriMatchHelp"
|
||||
[(ngModel)]="defaultUriMatch"
|
||||
(change)="saveDefaultUriMatch()"
|
||||
>
|
||||
<option *ngFor="let o of uriMatchOptions" [ngValue]="o.value">{{ o.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="defaultUriMatchHelp" class="box-footer">
|
||||
{{ "defaultUriMatchDetectionDesc" | i18n }}
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="showCardsCurrentTab">{{ "showCardsCurrentTab" | i18n }}</label>
|
||||
<input
|
||||
id="showCardsCurrentTab"
|
||||
type="checkbox"
|
||||
aria-describedby="showCardsCurrentTabHelp"
|
||||
(change)="updateShowCardsCurrentTab()"
|
||||
[(ngModel)]="showCardsCurrentTab"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="showCardsCurrentTabHelp" class="box-footer">
|
||||
{{ "showCardsCurrentTabDesc" | i18n }}
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="showIdentitiesCurrentTab">{{ "showIdentitiesCurrentTab" | i18n }}</label>
|
||||
<input
|
||||
id="showIdentitiesCurrentTab"
|
||||
type="checkbox"
|
||||
aria-describedby="showIdentitiesCurrentTabHelp"
|
||||
(change)="updateShowIdentitiesCurrentTab()"
|
||||
[(ngModel)]="showIdentitiesCurrentTab"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="showIdentitiesCurrentTabHelp" class="box-footer">
|
||||
{{ "showIdentitiesCurrentTabDesc" | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</popup-page>
|
||||
|
@ -1,12 +1,25 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
AutofillOverlayVisibility,
|
||||
BrowserClientVendors,
|
||||
BrowserShortcutsUris,
|
||||
ClearClipboardDelay,
|
||||
DisablePasswordManagerUris,
|
||||
} from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import {
|
||||
InlineMenuVisibilitySetting,
|
||||
BrowserClientVendor,
|
||||
BrowserShortcutsUri,
|
||||
ClearClipboardDelaySetting,
|
||||
DisablePasswordManagerUri,
|
||||
InlineMenuVisibilitySetting,
|
||||
} from "@bitwarden/common/autofill/types";
|
||||
import {
|
||||
UriMatchStrategy,
|
||||
@ -16,33 +29,77 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import {
|
||||
CardComponent,
|
||||
CheckboxModule,
|
||||
DialogService,
|
||||
FormFieldModule,
|
||||
IconButtonModule,
|
||||
ItemModule,
|
||||
LinkModule,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
SelectModule,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||
import { enableAccountSwitching } from "../../../platform/flags";
|
||||
import { AutofillService } from "../../services/abstractions/autofill.service";
|
||||
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||
import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component";
|
||||
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-autofill",
|
||||
templateUrl: "autofill.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CardComponent,
|
||||
CheckboxModule,
|
||||
CommonModule,
|
||||
FormFieldModule,
|
||||
FormsModule,
|
||||
IconButtonModule,
|
||||
ItemModule,
|
||||
JslibModule,
|
||||
LinkModule,
|
||||
PopOutComponent,
|
||||
PopupFooterComponent,
|
||||
PopupHeaderComponent,
|
||||
PopupPageComponent,
|
||||
RouterModule,
|
||||
SectionComponent,
|
||||
SectionHeaderComponent,
|
||||
SelectModule,
|
||||
TypographyModule,
|
||||
],
|
||||
})
|
||||
export class AutofillComponent implements OnInit {
|
||||
/*
|
||||
* Default values set here are used in component state operations
|
||||
* until corresponding stored settings have loaded on init.
|
||||
*/
|
||||
protected canOverrideBrowserAutofillSetting = false;
|
||||
protected defaultBrowserAutofillDisabled = false;
|
||||
protected autoFillOverlayVisibility: InlineMenuVisibilitySetting;
|
||||
protected autoFillOverlayVisibilityOptions: any[];
|
||||
protected disablePasswordManagerLink: string;
|
||||
enableAutoFillOnPageLoad = false;
|
||||
autoFillOnPageLoadDefault = false;
|
||||
autoFillOnPageLoadOptions: any[];
|
||||
protected inlineMenuVisibility: InlineMenuVisibilitySetting =
|
||||
AutofillOverlayVisibility.OnFieldFocus;
|
||||
protected browserClientVendor: BrowserClientVendor = BrowserClientVendors.Unknown;
|
||||
protected disablePasswordManagerURI: DisablePasswordManagerUri =
|
||||
DisablePasswordManagerUris.Unknown;
|
||||
protected browserShortcutsURI: BrowserShortcutsUri = BrowserShortcutsUris.Unknown;
|
||||
protected browserClientIsUnknown: boolean;
|
||||
enableAutofillOnPageLoad = false;
|
||||
enableInlineMenu = false;
|
||||
enableInlineMenuOnIconSelect = false;
|
||||
autofillOnPageLoadDefault = false;
|
||||
autofillOnPageLoadOptions: { name: string; value: boolean }[];
|
||||
enableContextMenuItem = false;
|
||||
enableAutoTotpCopy = false; // TODO: Does it matter if this is set to false or true?
|
||||
enableAutoTotpCopy = false;
|
||||
clearClipboard: ClearClipboardDelaySetting;
|
||||
clearClipboardOptions: any[];
|
||||
clearClipboardOptions: { name: string; value: ClearClipboardDelaySetting }[];
|
||||
defaultUriMatch: UriMatchStrategySetting = UriMatchStrategy.Domain;
|
||||
uriMatchOptions: any[];
|
||||
showCardsCurrentTab = false;
|
||||
showIdentitiesCurrentTab = false;
|
||||
uriMatchOptions: { name: string; value: UriMatchStrategySetting }[];
|
||||
showCardsCurrentTab = true;
|
||||
showIdentitiesCurrentTab = true;
|
||||
autofillKeyboardHelperText: string;
|
||||
accountSwitcherEnabled = false;
|
||||
|
||||
@ -50,38 +107,23 @@ export class AutofillComponent implements OnInit {
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private domainSettingsService: DomainSettingsService,
|
||||
private autofillService: AutofillService,
|
||||
private dialogService: DialogService,
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private messagingService: MessagingService,
|
||||
private vaultSettingsService: VaultSettingsService,
|
||||
) {
|
||||
this.autoFillOverlayVisibilityOptions = [
|
||||
{
|
||||
name: i18nService.t("autofillOverlayVisibilityOff"),
|
||||
value: AutofillOverlayVisibility.Off,
|
||||
},
|
||||
{
|
||||
name: i18nService.t("autofillOverlayVisibilityOnFieldFocus"),
|
||||
value: AutofillOverlayVisibility.OnFieldFocus,
|
||||
},
|
||||
{
|
||||
name: i18nService.t("autofillOverlayVisibilityOnButtonClick"),
|
||||
value: AutofillOverlayVisibility.OnButtonClick,
|
||||
},
|
||||
];
|
||||
this.autoFillOnPageLoadOptions = [
|
||||
this.autofillOnPageLoadOptions = [
|
||||
{ name: i18nService.t("autoFillOnPageLoadYes"), value: true },
|
||||
{ name: i18nService.t("autoFillOnPageLoadNo"), value: false },
|
||||
];
|
||||
this.clearClipboardOptions = [
|
||||
{ name: i18nService.t("never"), value: null },
|
||||
{ name: i18nService.t("tenSeconds"), value: 10 },
|
||||
{ name: i18nService.t("twentySeconds"), value: 20 },
|
||||
{ name: i18nService.t("thirtySeconds"), value: 30 },
|
||||
{ name: i18nService.t("oneMinute"), value: 60 },
|
||||
{ name: i18nService.t("twoMinutes"), value: 120 },
|
||||
{ name: i18nService.t("fiveMinutes"), value: 300 },
|
||||
{ name: i18nService.t("never"), value: ClearClipboardDelay.Never },
|
||||
{ name: i18nService.t("tenSeconds"), value: ClearClipboardDelay.TenSeconds },
|
||||
{ name: i18nService.t("twentySeconds"), value: ClearClipboardDelay.TwentySeconds },
|
||||
{ name: i18nService.t("thirtySeconds"), value: ClearClipboardDelay.ThirtySeconds },
|
||||
{ name: i18nService.t("oneMinute"), value: ClearClipboardDelay.OneMinute },
|
||||
{ name: i18nService.t("twoMinutes"), value: ClearClipboardDelay.TwoMinutes },
|
||||
{ name: i18nService.t("fiveMinutes"), value: ClearClipboardDelay.FiveMinutes },
|
||||
];
|
||||
this.uriMatchOptions = [
|
||||
{ name: i18nService.t("baseDomain"), value: UriMatchStrategy.Domain },
|
||||
@ -92,28 +134,32 @@ export class AutofillComponent implements OnInit {
|
||||
{ name: i18nService.t("never"), value: UriMatchStrategy.Never },
|
||||
];
|
||||
|
||||
this.accountSwitcherEnabled = enableAccountSwitching();
|
||||
this.disablePasswordManagerLink = this.getDisablePasswordManagerLink();
|
||||
this.browserClientVendor = this.getBrowserClientVendor();
|
||||
this.disablePasswordManagerURI = DisablePasswordManagerUris[this.browserClientVendor];
|
||||
this.browserShortcutsURI = BrowserShortcutsUris[this.browserClientVendor];
|
||||
this.browserClientIsUnknown = this.browserClientVendor === BrowserClientVendors.Unknown;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.canOverrideBrowserAutofillSetting =
|
||||
this.platformUtilsService.isChrome() ||
|
||||
this.platformUtilsService.isEdge() ||
|
||||
this.platformUtilsService.isOpera() ||
|
||||
this.platformUtilsService.isVivaldi();
|
||||
|
||||
this.canOverrideBrowserAutofillSetting = !this.browserClientIsUnknown;
|
||||
this.defaultBrowserAutofillDisabled = await this.browserAutofillSettingCurrentlyOverridden();
|
||||
|
||||
this.autoFillOverlayVisibility = await firstValueFrom(
|
||||
this.inlineMenuVisibility = await firstValueFrom(
|
||||
this.autofillSettingsService.inlineMenuVisibility$,
|
||||
);
|
||||
|
||||
this.enableAutoFillOnPageLoad = await firstValueFrom(
|
||||
this.enableInlineMenuOnIconSelect =
|
||||
this.inlineMenuVisibility === AutofillOverlayVisibility.OnButtonClick;
|
||||
|
||||
this.enableInlineMenu =
|
||||
this.inlineMenuVisibility === AutofillOverlayVisibility.OnFieldFocus ||
|
||||
this.enableInlineMenuOnIconSelect;
|
||||
|
||||
this.enableAutofillOnPageLoad = await firstValueFrom(
|
||||
this.autofillSettingsService.autofillOnPageLoad$,
|
||||
);
|
||||
|
||||
this.autoFillOnPageLoadDefault = await firstValueFrom(
|
||||
this.autofillOnPageLoadDefault = await firstValueFrom(
|
||||
this.autofillSettingsService.autofillOnPageLoadDefault$,
|
||||
);
|
||||
|
||||
@ -140,17 +186,27 @@ export class AutofillComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
async updateAutoFillOverlayVisibility() {
|
||||
await this.autofillSettingsService.setInlineMenuVisibility(this.autoFillOverlayVisibility);
|
||||
async updateInlineMenuVisibility() {
|
||||
if (!this.enableInlineMenu) {
|
||||
this.enableInlineMenuOnIconSelect = false;
|
||||
}
|
||||
|
||||
const newInlineMenuVisibilityValue = this.enableInlineMenuOnIconSelect
|
||||
? AutofillOverlayVisibility.OnButtonClick
|
||||
: this.enableInlineMenu
|
||||
? AutofillOverlayVisibility.OnFieldFocus
|
||||
: AutofillOverlayVisibility.Off;
|
||||
|
||||
await this.autofillSettingsService.setInlineMenuVisibility(newInlineMenuVisibilityValue);
|
||||
await this.requestPrivacyPermission();
|
||||
}
|
||||
|
||||
async updateAutoFillOnPageLoad() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoad(this.enableAutoFillOnPageLoad);
|
||||
async updateAutofillOnPageLoad() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoad(this.enableAutofillOnPageLoad);
|
||||
}
|
||||
|
||||
async updateAutoFillOnPageLoadDefault() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoadDefault(this.autoFillOnPageLoadDefault);
|
||||
async updateAutofillOnPageLoadDefault() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoadDefault(this.autofillOnPageLoadDefault);
|
||||
}
|
||||
|
||||
async saveDefaultUriMatch() {
|
||||
@ -165,57 +221,81 @@ export class AutofillComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async commandSettings() {
|
||||
private getBrowserClientVendor(): BrowserClientVendor {
|
||||
if (this.platformUtilsService.isChrome()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("chrome://extensions/shortcuts");
|
||||
} else if (this.platformUtilsService.isOpera()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("opera://extensions/shortcuts");
|
||||
} else if (this.platformUtilsService.isEdge()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("edge://extensions/shortcuts");
|
||||
} else if (this.platformUtilsService.isVivaldi()) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("vivaldi://extensions/shortcuts");
|
||||
} else {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab("https://bitwarden.com/help/keyboard-shortcuts");
|
||||
return BrowserClientVendors.Chrome;
|
||||
}
|
||||
}
|
||||
|
||||
private getDisablePasswordManagerLink(): string {
|
||||
if (this.platformUtilsService.isChrome()) {
|
||||
return "chrome://settings/autofill";
|
||||
}
|
||||
if (this.platformUtilsService.isOpera()) {
|
||||
return "opera://settings/autofill";
|
||||
}
|
||||
if (this.platformUtilsService.isEdge()) {
|
||||
return "edge://settings/passwords";
|
||||
}
|
||||
if (this.platformUtilsService.isVivaldi()) {
|
||||
return "vivaldi://settings/autofill";
|
||||
return BrowserClientVendors.Opera;
|
||||
}
|
||||
|
||||
return "https://bitwarden.com/help/disable-browser-autofill/";
|
||||
if (this.platformUtilsService.isEdge()) {
|
||||
return BrowserClientVendors.Edge;
|
||||
}
|
||||
|
||||
if (this.platformUtilsService.isVivaldi()) {
|
||||
return BrowserClientVendors.Vivaldi;
|
||||
}
|
||||
|
||||
return BrowserClientVendors.Unknown;
|
||||
}
|
||||
|
||||
protected openDisablePasswordManagerLink(event: Event) {
|
||||
protected async openURI(event: Event, uri: BrowserShortcutsUri | DisablePasswordManagerUri) {
|
||||
event.preventDefault();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab(this.disablePasswordManagerLink);
|
||||
|
||||
// If the destination is a password management settings page, ask the user to confirm before proceeding
|
||||
if (uri === DisablePasswordManagerUris[this.browserClientVendor]) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
...(this.browserClientIsUnknown
|
||||
? {
|
||||
content: { key: "confirmContinueToHelpCenterPasswordManagementContent" },
|
||||
title: { key: "confirmContinueToHelpCenter" },
|
||||
}
|
||||
: {
|
||||
content: { key: "confirmContinueToBrowserPasswordManagementSettingsContent" },
|
||||
title: { key: "confirmContinueToBrowserSettingsTitle" },
|
||||
}),
|
||||
acceptButtonText: { key: "continue" },
|
||||
acceptAction: async () => {
|
||||
await BrowserApi.createNewTab(uri);
|
||||
},
|
||||
cancelButtonText: { key: "cancel" },
|
||||
type: "info",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the destination is a browser shortcut settings page, ask the user to confirm before proceeding
|
||||
if (uri === BrowserShortcutsUris[this.browserClientVendor]) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
...(this.browserClientIsUnknown
|
||||
? {
|
||||
content: { key: "confirmContinueToHelpCenterKeyboardShortcutsContent" },
|
||||
title: { key: "confirmContinueToHelpCenter" },
|
||||
}
|
||||
: {
|
||||
content: { key: "confirmContinueToBrowserKeyboardShortcutSettingsContent" },
|
||||
title: { key: "confirmContinueToBrowserSettingsTitle" },
|
||||
}),
|
||||
acceptButtonText: { key: "continue" },
|
||||
acceptAction: async () => {
|
||||
await BrowserApi.createNewTab(uri);
|
||||
},
|
||||
cancelButtonText: { key: "cancel" },
|
||||
type: "info",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await BrowserApi.createNewTab(uri);
|
||||
}
|
||||
|
||||
async requestPrivacyPermission() {
|
||||
if (
|
||||
this.autoFillOverlayVisibility === AutofillOverlayVisibility.Off ||
|
||||
this.inlineMenuVisibility === AutofillOverlayVisibility.Off ||
|
||||
!this.canOverrideBrowserAutofillSetting ||
|
||||
(await this.browserAutofillSettingCurrentlyOverridden())
|
||||
) {
|
||||
@ -225,9 +305,9 @@ export class AutofillComponent implements OnInit {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "overrideDefaultBrowserAutofillTitle" },
|
||||
content: { key: "overrideDefaultBrowserAutofillDescription" },
|
||||
acceptButtonText: { key: "makeDefault" },
|
||||
acceptButtonText: { key: "continue" },
|
||||
acceptAction: async () => await this.handleOverrideDialogAccept(),
|
||||
cancelButtonText: { key: "ignore" },
|
||||
cancelButtonText: { key: "cancel" },
|
||||
type: "info",
|
||||
});
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import { TwoFactorAuthComponent } from "../auth/popup/two-factor-auth.component"
|
||||
import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component";
|
||||
import { TwoFactorComponent } from "../auth/popup/two-factor.component";
|
||||
import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.component";
|
||||
import { AutofillV1Component } from "../autofill/popup/settings/autofill-v1.component";
|
||||
import { AutofillComponent } from "../autofill/popup/settings/autofill.component";
|
||||
import { ExcludedDomainsV1Component } from "../autofill/popup/settings/excluded-domains-v1.component";
|
||||
import { ExcludedDomainsComponent } from "../autofill/popup/settings/excluded-domains.component";
|
||||
@ -278,12 +279,11 @@ const routes: Routes = [
|
||||
canActivate: [AuthGuard],
|
||||
data: { state: "export" },
|
||||
}),
|
||||
{
|
||||
...extensionRefreshSwap(AutofillV1Component, AutofillComponent, {
|
||||
path: "autofill",
|
||||
component: AutofillComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: { state: "autofill" },
|
||||
},
|
||||
}),
|
||||
{
|
||||
path: "account-security",
|
||||
component: AccountSecurityComponent,
|
||||
|
@ -36,6 +36,7 @@ import { SsoComponent } from "../auth/popup/sso.component";
|
||||
import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component";
|
||||
import { TwoFactorComponent } from "../auth/popup/two-factor.component";
|
||||
import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.component";
|
||||
import { AutofillV1Component } from "../autofill/popup/settings/autofill-v1.component";
|
||||
import { AutofillComponent } from "../autofill/popup/settings/autofill.component";
|
||||
import { ExcludedDomainsV1Component } from "../autofill/popup/settings/excluded-domains-v1.component";
|
||||
import { ExcludedDomainsComponent } from "../autofill/popup/settings/excluded-domains.component";
|
||||
@ -93,6 +94,7 @@ import "../platform/popup/locales";
|
||||
imports: [
|
||||
A11yModule,
|
||||
AppRoutingModule,
|
||||
AutofillComponent,
|
||||
ToastModule.forRoot({
|
||||
maxOpened: 2,
|
||||
autoDismiss: true,
|
||||
@ -180,7 +182,7 @@ import "../platform/popup/locales";
|
||||
RemovePasswordComponent,
|
||||
VaultSelectComponent,
|
||||
Fido2Component,
|
||||
AutofillComponent,
|
||||
AutofillV1Component,
|
||||
EnvironmentSelectorComponent,
|
||||
AccountSwitcherComponent,
|
||||
],
|
||||
|
@ -61,3 +61,27 @@ export const AutofillOverlayVisibility = {
|
||||
OnButtonClick: 1,
|
||||
OnFieldFocus: 2,
|
||||
} as const;
|
||||
|
||||
export const BrowserClientVendors = {
|
||||
Chrome: "Chrome",
|
||||
Opera: "Opera",
|
||||
Edge: "Edge",
|
||||
Vivaldi: "Vivaldi",
|
||||
Unknown: "Unknown",
|
||||
} as const;
|
||||
|
||||
export const BrowserShortcutsUris = {
|
||||
Chrome: "chrome://extensions/shortcuts",
|
||||
Opera: "opera://extensions/shortcuts",
|
||||
Edge: "edge://extensions/shortcuts",
|
||||
Vivaldi: "vivaldi://extensions/shortcuts",
|
||||
Unknown: "https://bitwarden.com/help/keyboard-shortcuts",
|
||||
} as const;
|
||||
|
||||
export const DisablePasswordManagerUris = {
|
||||
Chrome: "chrome://settings/autofill",
|
||||
Opera: "opera://settings/autofill",
|
||||
Edge: "edge://settings/passwords",
|
||||
Vivaldi: "vivaldi://settings/autofill",
|
||||
Unknown: "https://bitwarden.com/help/disable-browser-autofill/",
|
||||
} as const;
|
||||
|
@ -1,7 +1,18 @@
|
||||
import { ClearClipboardDelay, AutofillOverlayVisibility } from "../constants";
|
||||
import {
|
||||
AutofillOverlayVisibility,
|
||||
BrowserClientVendors,
|
||||
BrowserShortcutsUris,
|
||||
ClearClipboardDelay,
|
||||
DisablePasswordManagerUris,
|
||||
} from "../constants";
|
||||
|
||||
export type ClearClipboardDelaySetting =
|
||||
(typeof ClearClipboardDelay)[keyof typeof ClearClipboardDelay];
|
||||
|
||||
export type InlineMenuVisibilitySetting =
|
||||
(typeof AutofillOverlayVisibility)[keyof typeof AutofillOverlayVisibility];
|
||||
|
||||
export type BrowserClientVendor = (typeof BrowserClientVendors)[keyof typeof BrowserClientVendors];
|
||||
export type BrowserShortcutsUri = (typeof BrowserShortcutsUris)[keyof typeof BrowserShortcutsUris];
|
||||
export type DisablePasswordManagerUri =
|
||||
(typeof DisablePasswordManagerUris)[keyof typeof DisablePasswordManagerUris];
|
||||
|
Loading…
Reference in New Issue
Block a user