1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-27 04:03:00 +02:00
bitwarden-browser/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

222 lines
7.1 KiB
TypeScript
Raw Normal View History

import { mock, MockProxy } from "jest-mock-extended";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
Auth/ps 2298 reorg auth (#4564) * Move auth service factories to Auth team * Move authentication componenets to Auth team * Move auth guard services to Auth team * Move Duo content script to Auth team * Move auth CLI commands to Auth team * Move Desktop Account components to Auth Team * Move Desktop guards to Auth team * Move two-factor provider images to Auth team * Move web Accounts components to Auth Team * Move web settings components to Auth Team * Move web two factor images to Auth Team * Fix missed import changes for Auth Team * Fix Linting errors * Fix missed CLI imports * Fix missed Desktop imports * Revert images move * Fix missed imports in Web * Move angular lib components to Auth Team * Move angular auth guards to Auth team * Move strategy specs to Auth team * Update .eslintignore for new paths * Move lib common abstractions to Auth team * Move services to Auth team * Move common lib enums to Auth team * Move webauthn iframe to Auth team * Move lib common domain models to Auth team * Move common lib requests to Auth team * Move response models to Auth team * Clean up whitelist * Move bit web components to Auth team * Move SSO and SCIM files to Auth team * Revert move SCIM to Auth team SCIM belongs to Admin Console team * Move captcha to Auth team * Move key connector to Auth team * Move emergency access to auth team * Delete extra file * linter fixes * Move kdf config to auth team * Fix whitelist * Fix duo autoformat * Complete two factor provider request move * Fix whitelist names * Fix login capitalization * Revert hint dependency reordering * Revert hint dependency reordering * Revert hint component This components is being picked up as a move between clients * Move web hint component to Auth team * Move new files to auth team * Fix desktop build * Fix browser build
2023-02-06 22:53:37 +01:00
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
[SG-998] and [SG-999] Vault and Autofill team refactor (#4542) * Move DeprecatedVaultFilterService to vault folder * [libs] move VaultItemsComponent * [libs] move AddEditComponent * [libs] move AddEditCustomFields * [libs] move attachmentsComponent * [libs] folderAddEditComponent * [libs] IconComponent * [libs] PasswordRepormptComponent * [libs] PremiumComponent * [libs] ViewCustomFieldsComponent * [libs] ViewComponent * [libs] PasswordRepromptService * [libs] Move FolderService and FolderApiService abstractions * [libs] FolderService imports * [libs] PasswordHistoryComponent * [libs] move Sync and SyncNotifier abstractions * [libs] SyncService imports * [libs] fix file casing for passwordReprompt abstraction * [libs] SyncNotifier import fix * [libs] CipherServiceAbstraction * [libs] PasswordRepromptService abstraction * [libs] Fix file casing for angular passwordReprompt service * [libs] fix file casing for SyncNotifierService * [libs] CipherRepromptType * [libs] rename CipherRepromptType * [libs] CipherType * [libs] Rename CipherType * [libs] CipherData * [libs] FolderData * [libs] PasswordHistoryData * [libs] AttachmentData * [libs] CardData * [libs] FieldData * [libs] IdentityData * [libs] LocalData * [libs] LoginData * [libs] SecureNoteData * [libs] LoginUriData * [libs] Domain classes * [libs] SecureNote * [libs] Request models * [libs] Response models * [libs] View part 1 * [libs] Views part 2 * [libs] Move folder services * [libs] Views fixes * [libs] Move sync services * [libs] cipher service * [libs] Types * [libs] Sync file casing * [libs] Fix folder service import * [libs] Move spec files * [libs] casing fixes on spec files * [browser] Autofill background, clipboard, commands * [browser] Fix ContextMenusBackground casing * [browser] Rename fix * [browser] Autofill content * [browser] autofill.js * [libs] enpass importer spec fix * [browser] autofill models * [browser] autofill manifest path updates * [browser] Autofill notification files * [browser] autofill services * [browser] Fix file casing * [browser] Vault popup loose components * [browser] Vault components * [browser] Manifest fixes * [browser] Vault services * [cli] vault commands and models * [browser] File capitilization fixes * [desktop] Vault components and services * [web] vault loose components * [web] Vault components * [browser] Fix misc-utils import * [libs] Fix psono spec imports * [fix] Add comments to address lint rules
2023-01-31 22:08:37 +01:00
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import {
AUTOFILL_ID,
COPY_PASSWORD_ID,
COPY_USERNAME_ID,
COPY_VERIFICATIONCODE_ID,
GENERATE_PASSWORD_ID,
NOOP_COMMAND_SUFFIX,
} from "../constants";
import {
CopyToClipboardAction,
ContextMenuClickedHandler,
CopyToClipboardOptions,
GeneratePasswordToClipboardAction,
2023-02-14 14:14:51 +01:00
AutofillAction,
} from "./context-menu-clicked-handler";
describe("ContextMenuClickedHandler", () => {
const createData = (
menuItemId: chrome.contextMenus.OnClickData["menuItemId"],
parentMenuItemId?: chrome.contextMenus.OnClickData["parentMenuItemId"]
): chrome.contextMenus.OnClickData => {
return {
menuItemId: menuItemId,
parentMenuItemId: parentMenuItemId,
editable: false,
pageUrl: "something",
};
};
const createCipher = (data?: {
id?: CipherView["id"];
username?: CipherView["login"]["username"];
password?: CipherView["login"]["password"];
totp?: CipherView["login"]["totp"];
}): CipherView => {
const { id, username, password, totp } = data || {};
const cipherView = new CipherView(
new Cipher({
id: id ?? "1",
type: CipherType.Login,
} as any)
);
cipherView.login.username = username ?? "USERNAME";
cipherView.login.password = password ?? "PASSWORD";
cipherView.login.totp = totp ?? "TOTP";
return cipherView;
};
let copyToClipboard: CopyToClipboardAction;
let generatePasswordToClipboard: GeneratePasswordToClipboardAction;
2023-02-14 14:14:51 +01:00
let autofill: AutofillAction;
let authService: MockProxy<AuthService>;
let cipherService: MockProxy<CipherService>;
let stateService: MockProxy<StateService>;
let totpService: MockProxy<TotpService>;
let eventCollectionService: MockProxy<EventCollectionService>;
let userVerificationService: MockProxy<UserVerificationService>;
let sut: ContextMenuClickedHandler;
beforeEach(() => {
copyToClipboard = jest.fn<void, [CopyToClipboardOptions]>();
generatePasswordToClipboard = jest.fn<Promise<void>, [tab: chrome.tabs.Tab]>();
2023-02-14 14:14:51 +01:00
autofill = jest.fn<Promise<void>, [tab: chrome.tabs.Tab, cipher: CipherView]>();
authService = mock();
cipherService = mock();
stateService = mock();
totpService = mock();
eventCollectionService = mock();
sut = new ContextMenuClickedHandler(
copyToClipboard,
generatePasswordToClipboard,
2023-02-14 14:14:51 +01:00
autofill,
authService,
cipherService,
stateService,
totpService,
eventCollectionService,
userVerificationService
);
});
afterEach(() => jest.resetAllMocks());
describe("run", () => {
it("can generate password", async () => {
await sut.run(createData(GENERATE_PASSWORD_ID), { id: 5 } as any);
expect(generatePasswordToClipboard).toBeCalledTimes(1);
expect(generatePasswordToClipboard).toBeCalledWith({
id: 5,
});
});
it("attempts to autofill the correct cipher", async () => {
const cipher = createCipher();
cipherService.getAllDecrypted.mockResolvedValue([cipher]);
await sut.run(createData(`${AUTOFILL_ID}_1`, AUTOFILL_ID), { id: 5 } as any);
2023-02-14 14:14:51 +01:00
expect(autofill).toBeCalledTimes(1);
2023-02-14 14:14:51 +01:00
expect(autofill).toBeCalledWith({ id: 5 }, cipher);
});
it("copies username to clipboard", async () => {
cipherService.getAllDecrypted.mockResolvedValue([
createCipher({ username: "TEST_USERNAME" }),
]);
await sut.run(createData(`${COPY_USERNAME_ID}_1`, COPY_USERNAME_ID), {
url: "https://test.com",
} as any);
expect(copyToClipboard).toBeCalledTimes(1);
expect(copyToClipboard).toHaveBeenCalledWith({
text: "TEST_USERNAME",
tab: { url: "https://test.com" },
});
});
it("copies password to clipboard", async () => {
cipherService.getAllDecrypted.mockResolvedValue([
createCipher({ password: "TEST_PASSWORD" }),
]);
await sut.run(createData(`${COPY_PASSWORD_ID}_1`, COPY_PASSWORD_ID), {
url: "https://test.com",
} as any);
expect(copyToClipboard).toBeCalledTimes(1);
expect(copyToClipboard).toHaveBeenCalledWith({
text: "TEST_PASSWORD",
tab: { url: "https://test.com" },
});
});
it("copies totp code to clipboard", async () => {
cipherService.getAllDecrypted.mockResolvedValue([createCipher({ totp: "TEST_TOTP_SEED" })]);
totpService.getCode.mockImplementation((seed) => {
if (seed === "TEST_TOTP_SEED") {
return Promise.resolve("123456");
}
return Promise.resolve("654321");
});
await sut.run(createData(`${COPY_VERIFICATIONCODE_ID}_1`, COPY_VERIFICATIONCODE_ID), {
url: "https://test.com",
} as any);
expect(totpService.getCode).toHaveBeenCalledTimes(1);
expect(copyToClipboard).toHaveBeenCalledWith({
text: "123456",
tab: { url: "https://test.com" },
});
});
it("attempts to find a cipher when noop but unlocked", async () => {
cipherService.getAllDecryptedForUrl.mockResolvedValue([
{
...createCipher({ username: "NOOP_USERNAME" }),
reprompt: CipherRepromptType.None,
} as any,
]);
await sut.run(createData(`${COPY_USERNAME_ID}_${NOOP_COMMAND_SUFFIX}`, COPY_USERNAME_ID), {
url: "https://test.com",
} as any);
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledTimes(1);
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith("https://test.com", []);
expect(copyToClipboard).toHaveBeenCalledTimes(1);
expect(copyToClipboard).toHaveBeenCalledWith({
text: "NOOP_USERNAME",
tab: { url: "https://test.com" },
});
});
it("attempts to find a cipher when noop but unlocked", async () => {
cipherService.getAllDecryptedForUrl.mockResolvedValue([
{
...createCipher({ username: "NOOP_USERNAME" }),
reprompt: CipherRepromptType.Password,
} as any,
]);
await sut.run(createData(`${COPY_USERNAME_ID}_${NOOP_COMMAND_SUFFIX}`, COPY_USERNAME_ID), {
url: "https://test.com",
} as any);
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledTimes(1);
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith("https://test.com", []);
});
});
});