mirror of
https://github.com/bitwarden/browser
synced 2026-02-09 05:00:10 +00:00
support url path matching for targeting rules
This commit is contained in:
@@ -21,7 +21,6 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { AutofillTargetingRulesByDomain } from "@bitwarden/common/autofill/types";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import {
|
||||
ButtonModule,
|
||||
CardComponent,
|
||||
@@ -185,46 +184,44 @@ export class AutofillTargetingRulesComponent implements AfterViewInit, OnDestroy
|
||||
const formGroup = control as FormGroup;
|
||||
const domain = formGroup.get("domain")?.value;
|
||||
|
||||
if (domain && domain !== "") {
|
||||
const validatedHost = Utils.getHostname(domain);
|
||||
const normalizedURI = this.domainSettingsService.normalizeAutofillTargetingURI(domain);
|
||||
|
||||
if (!validatedHost) {
|
||||
this.toastService.showToast({
|
||||
message: this.i18nService.t("blockedDomainsInvalidDomain", domain),
|
||||
title: "",
|
||||
variant: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!normalizedURI) {
|
||||
this.toastService.showToast({
|
||||
message: this.i18nService.t("blockedDomainsInvalidDomain", domain),
|
||||
title: "",
|
||||
variant: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const enteredUsername = formGroup.get("username")?.value;
|
||||
const enteredPassword = formGroup.get("password")?.value;
|
||||
const enteredTotp = formGroup.get("totp")?.value;
|
||||
const enteredUsername = formGroup.get("username")?.value;
|
||||
const enteredPassword = formGroup.get("password")?.value;
|
||||
const enteredTotp = formGroup.get("totp")?.value;
|
||||
|
||||
if (!enteredUsername && !enteredPassword && !enteredTotp) {
|
||||
this.toastService.showToast({
|
||||
message: "No targeting rules were specified for the URL",
|
||||
title: "",
|
||||
variant: "error",
|
||||
});
|
||||
if (!enteredUsername && !enteredPassword && !enteredTotp) {
|
||||
this.toastService.showToast({
|
||||
message: "No targeting rules were specified for the URL",
|
||||
title: "",
|
||||
variant: "error",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
newUriTargetingRulesSaveState[validatedHost] = {};
|
||||
newUriTargetingRulesSaveState[normalizedURI] = {};
|
||||
|
||||
// Only add the property to the object if it has a value
|
||||
if (enteredUsername) {
|
||||
newUriTargetingRulesSaveState[validatedHost].username = enteredUsername;
|
||||
}
|
||||
// Only add the property to the object if it has a value
|
||||
if (enteredUsername) {
|
||||
newUriTargetingRulesSaveState[normalizedURI].username = enteredUsername;
|
||||
}
|
||||
|
||||
if (enteredPassword) {
|
||||
newUriTargetingRulesSaveState[validatedHost].password = enteredPassword;
|
||||
}
|
||||
if (enteredPassword) {
|
||||
newUriTargetingRulesSaveState[normalizedURI].password = enteredPassword;
|
||||
}
|
||||
|
||||
if (enteredTotp) {
|
||||
newUriTargetingRulesSaveState[validatedHost].totp = enteredTotp;
|
||||
}
|
||||
if (enteredTotp) {
|
||||
newUriTargetingRulesSaveState[normalizedURI].totp = enteredTotp;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -123,6 +123,9 @@ export abstract class DomainSettingsService {
|
||||
* Helper function for the common resolution of a given URL against equivalent domains
|
||||
*/
|
||||
getUrlEquivalentDomains: (url: string) => Observable<Set<string>>;
|
||||
|
||||
/** URI normalization for Autofill Targeting rules URLs to ensure state is doing safe, consistent internal comparisons */
|
||||
normalizeAutofillTargetingURI: (url: chrome.tabs.Tab["url"]) => chrome.tabs.Tab["url"] | null;
|
||||
}
|
||||
|
||||
export class DefaultDomainSettingsService implements DomainSettingsService {
|
||||
@@ -205,7 +208,19 @@ export class DefaultDomainSettingsService implements DomainSettingsService {
|
||||
}
|
||||
|
||||
async setAutofillTargetingRules(newValue: AutofillTargetingRulesByDomain): Promise<void> {
|
||||
await this.autofillTargetingRulesState.update(() => newValue);
|
||||
await this.autofillTargetingRulesState.update(() => {
|
||||
const validatedNewValue = Object.keys(newValue || {}).reduce((updatingValue, valueKey) => {
|
||||
const normalizedURI = this.normalizeAutofillTargetingURI(valueKey);
|
||||
|
||||
if (normalizedURI) {
|
||||
return { ...updatingValue, [normalizedURI]: newValue[valueKey] };
|
||||
}
|
||||
|
||||
return updatingValue;
|
||||
}, {});
|
||||
|
||||
return validatedNewValue;
|
||||
});
|
||||
}
|
||||
|
||||
async setShowFavicons(newValue: boolean): Promise<void> {
|
||||
@@ -245,17 +260,33 @@ export class DefaultDomainSettingsService implements DomainSettingsService {
|
||||
return domains$;
|
||||
}
|
||||
|
||||
getUrlAutofillTargetingRules$(url: string): Observable<AutofillTargetingRules> {
|
||||
getUrlAutofillTargetingRules$(url: chrome.tabs.Tab["url"]): Observable<AutofillTargetingRules> {
|
||||
const normalizedURI = this.normalizeAutofillTargetingURI(url);
|
||||
|
||||
return this.autofillTargetingRules$.pipe(
|
||||
map((autofillTargetingRules) => {
|
||||
const domain = Utils.getHostname(url);
|
||||
|
||||
if (domain == null) {
|
||||
if (!normalizedURI) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return autofillTargetingRules?.[domain] || {};
|
||||
return autofillTargetingRules?.[normalizedURI] || {};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
normalizeAutofillTargetingURI(url: chrome.tabs.Tab["url"]) {
|
||||
if (!Utils.isNullOrWhitespace(url)) {
|
||||
const uriParts = Utils.getUrl(url);
|
||||
const validatedHostname = Utils.getHostname(url);
|
||||
|
||||
// Prevent directory traversal from malicious paths
|
||||
const pathParts = uriParts.pathname.split("?");
|
||||
const normalizedURI =
|
||||
uriParts.protocol + "//" + validatedHostname + Utils.normalizePath(pathParts[0]);
|
||||
|
||||
return normalizedURI;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user