handle content script host permission errors

This commit is contained in:
Jonathan Prusik 2024-04-25 16:58:28 -04:00
parent d7f491d920
commit 4d1c54e9c2
No known key found for this signature in database
GPG Key ID: 83CF2DF735A5EC35
8 changed files with 66 additions and 12 deletions

View File

@ -12,6 +12,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { EventType } from "@bitwarden/common/enums";
import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import {
@ -74,9 +75,10 @@ describe("AutofillService", () => {
const logService = mock<LogService>();
const userVerificationService = mock<UserVerificationService>();
const billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
const platformUtilsService = mock<PlatformUtilsService>();
beforeEach(() => {
scriptInjectorService = new BrowserScriptInjectorService();
scriptInjectorService = new BrowserScriptInjectorService(platformUtilsService, logService);
autofillService = new AutofillService(
cipherService,
autofillSettingsService,

View File

@ -806,7 +806,10 @@ export default class MainBackground {
);
this.totpService = new TotpService(this.cryptoFunctionService, this.logService);
this.scriptInjectorService = new BrowserScriptInjectorService();
this.scriptInjectorService = new BrowserScriptInjectorService(
this.platformUtilsService,
this.logService,
);
this.autofillService = new AutofillService(
this.cipherService,
this.autofillSettingsService,

View File

@ -51,7 +51,6 @@
"default_popup": "popup/index.html"
},
"permissions": [
"<all_urls>",
"tabs",
"contextMenus",
"storage",
@ -63,7 +62,7 @@
"offscreen"
],
"optional_permissions": ["nativeMessaging", "privacy"],
"host_permissions": ["<all_urls>"],
"host_permissions": ["https://*/*", "http://*/*"],
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'",
"sandbox": "sandbox allow-scripts; script-src 'self'"

View File

@ -1,10 +1,20 @@
import {
LogServiceInitOptions,
logServiceFactory,
} from "../../background/service-factories/log-service.factory";
import { BrowserScriptInjectorService } from "../../services/browser-script-injector.service";
import { CachedServices, FactoryOptions, factory } from "./factory-options";
import {
PlatformUtilsServiceInitOptions,
platformUtilsServiceFactory,
} from "./platform-utils-service.factory";
type BrowserScriptInjectorServiceOptions = FactoryOptions;
export type BrowserScriptInjectorServiceInitOptions = BrowserScriptInjectorServiceOptions;
export type BrowserScriptInjectorServiceInitOptions = BrowserScriptInjectorServiceOptions &
PlatformUtilsServiceInitOptions &
LogServiceInitOptions;
export function browserScriptInjectorServiceFactory(
cache: { browserScriptInjectorService?: BrowserScriptInjectorService } & CachedServices,
@ -14,6 +24,10 @@ export function browserScriptInjectorServiceFactory(
cache,
"browserScriptInjectorService",
opts,
async () => new BrowserScriptInjectorService(),
async () =>
new BrowserScriptInjectorService(
await platformUtilsServiceFactory(cache, opts),
await logServiceFactory(cache, opts),
),
);
}

View File

@ -1,3 +1,8 @@
import { mock } from "jest-mock-extended";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { BrowserApi } from "../browser/browser-api";
import {
@ -20,9 +25,11 @@ describe("ScriptInjectorService", () => {
let scriptInjectorService: BrowserScriptInjectorService;
jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation();
jest.spyOn(BrowserApi, "isManifestVersion");
const platformUtilsService = mock<PlatformUtilsService>();
const logService = mock<LogService>();
beforeEach(() => {
scriptInjectorService = new BrowserScriptInjectorService();
scriptInjectorService = new BrowserScriptInjectorService(platformUtilsService, logService);
});
describe("inject", () => {

View File

@ -1,3 +1,6 @@
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { BrowserApi } from "../browser/browser-api";
import {
@ -7,6 +10,13 @@ import {
} from "./abstractions/script-injector.service";
export class BrowserScriptInjectorService extends ScriptInjectorService {
constructor(
private readonly platformUtilsService: PlatformUtilsService,
private readonly logService: LogService,
) {
super();
}
/**
* Facilitates the injection of a script into a tab context. Will adjust
* behavior between manifest v2 and v3 based on the passed configuration.
@ -23,9 +33,24 @@ export class BrowserScriptInjectorService extends ScriptInjectorService {
const injectionDetails = this.buildInjectionDetails(injectDetails, file);
if (BrowserApi.isManifestVersion(3)) {
await BrowserApi.executeScriptInTab(tabId, injectionDetails, {
world: mv3Details?.world ?? "ISOLATED",
});
try {
await BrowserApi.executeScriptInTab(tabId, injectionDetails, {
world: mv3Details?.world ?? "ISOLATED",
});
} catch ({ message }) {
// Swallow errors for host permissions, since this is believed to be a Manifest V3 Chrome bug
// @TODO remove when the bugged behaviour is resolved
if (
message ===
"Cannot access contents of the page. Extension manifest must request permission to access the respective host."
) {
if (this.platformUtilsService.isDev()) {
this.logService.warning(
`BrowserApi.executeScriptInTab exception for ${injectDetails.file} in tab ${tabId}: ${message}`,
);
}
}
}
return;
}

View File

@ -310,7 +310,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({
provide: ScriptInjectorService,
useClass: BrowserScriptInjectorService,
deps: [],
deps: [PlatformUtilsService, LogService],
}),
safeProvider({
provide: KeyConnectorService,

View File

@ -5,6 +5,8 @@ import { PolicyService } from "@bitwarden/common/admin-console/services/policy/p
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { Importer, ImportResult, ImportServiceAbstraction } from "@bitwarden/importer/core";
@ -38,10 +40,12 @@ describe("FilelessImporterBackground ", () => {
const notificationBackground = mock<NotificationBackground>();
const importService = mock<ImportServiceAbstraction>();
const syncService = mock<SyncService>();
const platformUtilsService = mock<PlatformUtilsService>();
const logService = mock<LogService>();
let scriptInjectorService: BrowserScriptInjectorService;
beforeEach(() => {
scriptInjectorService = new BrowserScriptInjectorService();
scriptInjectorService = new BrowserScriptInjectorService(platformUtilsService, logService);
filelessImporterBackground = new FilelessImporterBackground(
configService,
authService,