1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

Delete everything related to misc-utils (#13395)

This commit is contained in:
Justin Baur
2025-02-14 15:59:14 -05:00
committed by GitHub
parent c6176ed8a2
commit 8d8c4eb29b
9 changed files with 1 additions and 253 deletions

View File

@@ -1,39 +0,0 @@
import { BrowserApi } from "../../platform/browser/browser-api";
import { ClearClipboard } from "./clear-clipboard";
describe("clearClipboard", () => {
describe("run", () => {
it("Does not clear clipboard when no active tabs are retrieved", async () => {
jest.spyOn(BrowserApi, "getActiveTabs").mockResolvedValue([] as any);
jest.spyOn(BrowserApi, "sendTabsMessage").mockReturnValue();
await ClearClipboard.run();
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).not.toHaveBeenCalled();
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).not.toHaveBeenCalledWith(1, {
command: "clearClipboard",
});
});
it("Sends a message to the content script to clear the clipboard", async () => {
jest.spyOn(BrowserApi, "getActiveTabs").mockResolvedValue([
{
id: 1,
},
] as any);
jest.spyOn(BrowserApi, "sendTabsMessage").mockReturnValue();
await ClearClipboard.run();
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledTimes(1);
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledWith(1, {
command: "clearClipboard",
});
});
});
});

View File

@@ -1,22 +0,0 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { BrowserApi } from "../../platform/browser/browser-api";
export class ClearClipboard {
/**
We currently rely on an active tab with an injected content script (`../content/misc-utils.ts`) to clear the clipboard via `window.navigator.clipboard.writeText(text)`
With https://bugs.chromium.org/p/chromium/issues/detail?id=1160302 it was said that service workers,
would have access to the clipboard api and then we could migrate to a simpler solution
*/
static async run() {
const activeTabs = await BrowserApi.getActiveTabs();
if (!activeTabs || activeTabs.length === 0) {
return;
}
BrowserApi.sendTabsMessage(activeTabs[0].id, {
command: "clearClipboard",
});
}
}

View File

@@ -1,17 +0,0 @@
import { BrowserApi } from "../../platform/browser/browser-api";
/**
* Copies text to the clipboard in a MV3 safe way.
* @param tab - The tab that the text will be sent to so that it can be copied to the users clipboard this needs to be an active tab or the DOM won't be able to be used to do the action. The tab sent in here should be from a user started action or queried for active tabs.
* @param text - The text that you want added to the users clipboard.
*/
export const copyToClipboard = async (tab: chrome.tabs.Tab, text: string) => {
if (tab.id == null) {
throw new Error("Cannot copy text to clipboard with a tab that does not have an id.");
}
BrowserApi.sendTabsMessage(tab.id, {
command: "copyText",
text: text,
});
};

View File

@@ -1,97 +0,0 @@
import { mock, MockProxy } from "jest-mock-extended";
import { firstValueFrom, Subscription } from "rxjs";
import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { ScheduledTaskNames } from "@bitwarden/common/platform/scheduling";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { BrowserApi } from "../../platform/browser/browser-api";
import { BrowserTaskSchedulerService } from "../../platform/services/abstractions/browser-task-scheduler.service";
import { ClearClipboard } from "./clear-clipboard";
import { GeneratePasswordToClipboardCommand } from "./generate-password-to-clipboard-command";
jest.mock("rxjs", () => {
const actual = jest.requireActual("rxjs");
return {
...actual,
firstValueFrom: jest.fn(),
};
});
describe("GeneratePasswordToClipboardCommand", () => {
let passwordGenerationService: MockProxy<PasswordGenerationServiceAbstraction>;
let autofillSettingsService: MockProxy<AutofillSettingsService>;
let browserTaskSchedulerService: MockProxy<BrowserTaskSchedulerService>;
let sut: GeneratePasswordToClipboardCommand;
beforeEach(() => {
passwordGenerationService = mock<PasswordGenerationServiceAbstraction>();
autofillSettingsService = mock<AutofillSettingsService>();
browserTaskSchedulerService = mock<BrowserTaskSchedulerService>({
setTimeout: jest.fn((taskName, timeoutInMs) => {
const timeoutHandle = setTimeout(() => {
if (taskName === ScheduledTaskNames.generatePasswordClearClipboardTimeout) {
void ClearClipboard.run();
}
}, timeoutInMs);
return new Subscription(() => clearTimeout(timeoutHandle));
}),
});
passwordGenerationService.getOptions.mockResolvedValue([{ length: 8 }, {} as any]);
passwordGenerationService.generatePassword.mockResolvedValue("PASSWORD");
jest.spyOn(BrowserApi, "sendTabsMessage").mockReturnValue();
sut = new GeneratePasswordToClipboardCommand(
passwordGenerationService,
autofillSettingsService,
browserTaskSchedulerService,
);
});
afterEach(() => {
jest.resetAllMocks();
});
describe("generatePasswordToClipboard", () => {
it("has clear clipboard value", async () => {
jest.useFakeTimers();
jest.spyOn(ClearClipboard, "run");
(firstValueFrom as jest.Mock).mockResolvedValue(2 * 60); // 2 minutes
await sut.generatePasswordToClipboard({ id: 1 } as any);
jest.advanceTimersByTime(2 * 60 * 1000);
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledTimes(1);
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledWith(1, {
command: "copyText",
text: "PASSWORD",
});
expect(browserTaskSchedulerService.setTimeout).toHaveBeenCalledTimes(1);
expect(browserTaskSchedulerService.setTimeout).toHaveBeenCalledWith(
ScheduledTaskNames.generatePasswordClearClipboardTimeout,
expect.any(Number),
);
expect(ClearClipboard.run).toHaveBeenCalledTimes(1);
});
it("does not have clear clipboard value", async () => {
jest.spyOn(sut as any, "getClearClipboard").mockImplementation(() => null);
await sut.generatePasswordToClipboard({ id: 1 } as any);
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledTimes(1);
expect(jest.spyOn(BrowserApi, "sendTabsMessage")).toHaveBeenCalledWith(1, {
command: "copyText",
text: "PASSWORD",
});
expect(browserTaskSchedulerService.setTimeout).not.toHaveBeenCalled();
});
});
});

View File

@@ -1,48 +0,0 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { firstValueFrom, Subscription } from "rxjs";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { TaskSchedulerService, ScheduledTaskNames } from "@bitwarden/common/platform/scheduling";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { ClearClipboard } from "./clear-clipboard";
import { copyToClipboard } from "./copy-to-clipboard-command";
export class GeneratePasswordToClipboardCommand {
private clearClipboardSubscription: Subscription;
constructor(
private passwordGenerationService: PasswordGenerationServiceAbstraction,
private autofillSettingsService: AutofillSettingsServiceAbstraction,
private taskSchedulerService: TaskSchedulerService,
) {
this.taskSchedulerService.registerTaskHandler(
ScheduledTaskNames.generatePasswordClearClipboardTimeout,
() => ClearClipboard.run(),
);
}
async getClearClipboard() {
return await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$);
}
async generatePasswordToClipboard(tab: chrome.tabs.Tab) {
const [options] = await this.passwordGenerationService.getOptions();
const password = await this.passwordGenerationService.generatePassword(options);
await copyToClipboard(tab, password);
const clearClipboardDelayInSeconds = await this.getClearClipboard();
if (!clearClipboardDelayInSeconds) {
return;
}
const timeoutInMs = clearClipboardDelayInSeconds * 1000;
this.clearClipboardSubscription?.unsubscribe();
this.clearClipboardSubscription = this.taskSchedulerService.setTimeout(
ScheduledTaskNames.generatePasswordClearClipboardTimeout,
timeoutInMs,
);
}
}

View File

@@ -1,3 +0,0 @@
export * from "./clear-clipboard";
export * from "./copy-to-clipboard-command";
export * from "./generate-password-to-clipboard-command";

View File

@@ -1,23 +0,0 @@
import { TabMessage } from "../../types/tab-messages";
async function copyText(text: string) {
await window.navigator.clipboard.writeText(text);
}
async function onMessageListener(
msg: TabMessage,
sender: chrome.runtime.MessageSender,
responseCallback: (response: unknown) => void,
) {
switch (msg.command) {
case "copyText":
await copyText(msg.text);
break;
case "clearClipboard":
await copyText("\u0000");
break;
default:
}
}
chrome.runtime.onMessage.addListener(onMessageListener);

View File

@@ -26,7 +26,7 @@
{
"all_frames": true,
"css": ["content/autofill.css"],
"js": ["content/trigger-autofill-script-injection.js", "content/misc-utils.js"],
"js": ["content/trigger-autofill-script-injection.js"],
"matches": ["*://*/*", "file:///*"],
"exclude_matches": ["*://*/*.xml*", "file:///*.xml*"],
"run_at": "document_start"

View File

@@ -319,9 +319,6 @@ if (manifestVersion == 2) {
} else {
// Firefox does not use the offscreen API
if (browser !== "firefox") {
// Manifest v3 needs an extra helper for utilities in the content script.
// The javascript output of this should be added to manifest.v3.json
mainConfig.entry["content/misc-utils"] = "./src/autofill/content/misc-utils.ts";
mainConfig.entry["offscreen-document/offscreen-document"] =
"./src/platform/offscreen-document/offscreen-document.ts";