mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 23:33:31 +00:00
[PM-4566] Fix santization check issue found with webVaulUrl in notification bar (#7737)
* [PM-673] Safari Notification Bar Does Not Show Folders * [PM-673] Refactoring Context Menu Implementations to Ensure Pages with No Logins Can Dismiss Notification Bar * [PM-673] Refactoring typing information for the LockedVaultPendingNotificationsItem typing * [PM-673] Refactoring typing information for notification background * [PM-673] Finishing out typing for potential extension messages to the notification bar; * [PM-673] Working through implementation details for the notification background * [PM-673] Fixing issues present with messaging re-implementation * [PM-673] Fixing issue with folders not populating within Safari notification bar * [PM-673] Fixing jest test issues present within implementation * [PM-673] Fixing issue present with webVaultUrl vulnerability * [PM-673] Fixing XSS Vulnerability within Notification Bar; * [PM-5670] Putting together a partial implementation for having messages appear on network error within the notification bar * [PM-673] Incorporating status update for when user has successfully saved credentials * [PM-673] Incorporating status update for when user has successfully saved credentials * [PM-5949] Refactor typing information for notification bar * [PM-5949] Fix jest tests for overlay background * [PM-5949] Removing unnused typing data * [PM-5949] Fixing lint error * [PM-5949] Adding jest tests for convertAddLoginQueueMessageToCipherView method * [PM-5949] Fixing jest test for overlay * [PM-5950] Fix Context Menu Update Race Condition and Refactor Implementation * [PM-5950] Adding jest test for cipherContextMenu.update method * [PM-5950] Adding documentation for method within MainContextMenuHandler * [PM-5950] Adding jest tests for the mainContextMenuHandler * [PM-673] Stripping unnecessary work for network drop issue * [PM-673] Stripping unnecessary work for network drop issue * [PM-2753] Prompt to Save New Login Credentials Silently Drops Data on Network Error * [PM-673] Stripping out work done for another ticket * [PM-4566] Fix santization check issue found with webVaulUrl in notification bar * [PM-4566] Refactoring implementation * [PM-5950] Removing unnecessary return value from MainContextMenuHandler.create method * [PM-673] Implementing unit test coverage for newly introduced logic * [PM-673] Implementing unit test coverage for newly introduced logic * [PM-673] Implementing unit test coverage for newly introduced logic * [PM-673] Implementing unit test coverage for newly introduced logic * [PM-2753] Implementing jest tests to validate logic changes * [PM-2753] Implementing jest tests to validate logic changes * [PM-2753] Implementing jest tests to validate logic changes * [PM-2753] Implementing jest tests to validate logic changes * [PM-2753] Incorporating addition of green and red borders when success or error events occur * [PM-4566] Adding jest test to validate changes within the notification background * [PM-5950] Fixing unawaited context menu promise * [PM-673] Merging changes in from main and fixing merge conflicts * [PM-2753] Merging work in from main and resolving merge conflicts * [PM-6122] Rework `window` call within NotificationBackground to function within content script * [PM-4566] Incorporating a more fleshed out implementation to remove queryParams from the notification bar url entirely * [PM-673] Fixing issue where updates to the added login were not triggering correctly * [PM-673] Merging changes in from main and fixing merge conflicts
This commit is contained in:
@@ -109,6 +109,7 @@ type NotificationBackgroundExtensionMessageHandlers = {
|
|||||||
bgReopenUnlockPopout: ({ sender }: BackgroundSenderParam) => Promise<void>;
|
bgReopenUnlockPopout: ({ sender }: BackgroundSenderParam) => Promise<void>;
|
||||||
checkNotificationQueue: ({ sender }: BackgroundSenderParam) => Promise<void>;
|
checkNotificationQueue: ({ sender }: BackgroundSenderParam) => Promise<void>;
|
||||||
collectPageDetailsResponse: ({ message }: BackgroundMessageParam) => Promise<void>;
|
collectPageDetailsResponse: ({ message }: BackgroundMessageParam) => Promise<void>;
|
||||||
|
getWebVaultUrlForNotification: () => string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -1332,5 +1332,23 @@ describe("NotificationBackground", () => {
|
|||||||
expect(openUnlockWindowSpy).toHaveBeenCalled();
|
expect(openUnlockWindowSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getWebVaultUrlForNotification", () => {
|
||||||
|
it("returns the web vault url", async () => {
|
||||||
|
const message: NotificationBackgroundExtensionMessage = {
|
||||||
|
command: "getWebVaultUrlForNotification",
|
||||||
|
};
|
||||||
|
const webVaultUrl = "https://example.com";
|
||||||
|
const environmentServiceSpy = jest
|
||||||
|
.spyOn(environmentService, "getWebVaultUrl")
|
||||||
|
.mockReturnValueOnce(webVaultUrl);
|
||||||
|
|
||||||
|
sendExtensionRuntimeMessage(message);
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
expect(environmentServiceSpy).toHaveBeenCalled();
|
||||||
|
expect(environmentServiceSpy).toHaveReturnedWith(webVaultUrl);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
|||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
@@ -58,6 +57,7 @@ export default class NotificationBackground {
|
|||||||
bgUnlockPopoutOpened: ({ message, sender }) => this.unlockVault(message, sender.tab),
|
bgUnlockPopoutOpened: ({ message, sender }) => this.unlockVault(message, sender.tab),
|
||||||
checkNotificationQueue: ({ sender }) => this.checkNotificationQueue(sender.tab),
|
checkNotificationQueue: ({ sender }) => this.checkNotificationQueue(sender.tab),
|
||||||
bgReopenUnlockPopout: ({ sender }) => this.openUnlockPopout(sender.tab),
|
bgReopenUnlockPopout: ({ sender }) => this.openUnlockPopout(sender.tab),
|
||||||
|
getWebVaultUrlForNotification: () => this.getWebVaultUrl(),
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -134,11 +134,9 @@ export default class NotificationBackground {
|
|||||||
notificationQueueMessage: NotificationQueueMessageItem,
|
notificationQueueMessage: NotificationQueueMessageItem,
|
||||||
) {
|
) {
|
||||||
const notificationType = notificationQueueMessage.type;
|
const notificationType = notificationQueueMessage.type;
|
||||||
const webVaultURL = this.environmentService.getWebVaultUrl();
|
|
||||||
const typeData: Record<string, any> = {
|
const typeData: Record<string, any> = {
|
||||||
isVaultLocked: notificationQueueMessage.wasVaultLocked,
|
isVaultLocked: notificationQueueMessage.wasVaultLocked,
|
||||||
theme: await this.getCurrentTheme(),
|
theme: await this.stateService.getTheme(),
|
||||||
webVaultURL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (notificationType) {
|
switch (notificationType) {
|
||||||
@@ -158,18 +156,6 @@ export default class NotificationBackground {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getCurrentTheme() {
|
|
||||||
const theme = await this.stateService.getTheme();
|
|
||||||
|
|
||||||
if (theme !== ThemeType.System) {
|
|
||||||
return theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
||||||
? ThemeType.Dark
|
|
||||||
: ThemeType.Light;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any login messages from the notification queue that
|
* Removes any login messages from the notification queue that
|
||||||
* are associated with the specified tab.
|
* are associated with the specified tab.
|
||||||
@@ -636,6 +622,10 @@ export default class NotificationBackground {
|
|||||||
return await firstValueFrom(this.folderService.folderViews$);
|
return await firstValueFrom(this.folderService.folderViews$);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getWebVaultUrl(): string {
|
||||||
|
return this.environmentService.getWebVaultUrl();
|
||||||
|
}
|
||||||
|
|
||||||
private async removeIndividualVault(): Promise<boolean> {
|
private async removeIndividualVault(): Promise<boolean> {
|
||||||
return await firstValueFrom(
|
return await firstValueFrom(
|
||||||
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership),
|
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
} from "../background/abstractions/notification.background";
|
} from "../background/abstractions/notification.background";
|
||||||
import AutofillField from "../models/autofill-field";
|
import AutofillField from "../models/autofill-field";
|
||||||
import { WatchedForm } from "../models/watched-form";
|
import { WatchedForm } from "../models/watched-form";
|
||||||
|
import { NotificationBarIframeInitData } from "../notification/abstractions/notification-bar";
|
||||||
import { FormData } from "../services/abstractions/autofill.service";
|
import { FormData } from "../services/abstractions/autofill.service";
|
||||||
import { GlobalSettings, UserSettings } from "../types";
|
import { GlobalSettings, UserSettings } from "../types";
|
||||||
import { getFromLocalStorage, setupExtensionDisconnectAction } from "../utils";
|
import { getFromLocalStorage, setupExtensionDisconnectAction } from "../utils";
|
||||||
@@ -856,33 +857,36 @@ async function loadNotificationBar() {
|
|||||||
|
|
||||||
// Notification Bar Functions (open, close, height adjustment, etc.)
|
// Notification Bar Functions (open, close, height adjustment, etc.)
|
||||||
function closeExistingAndOpenBar(type: string, typeData: any) {
|
function closeExistingAndOpenBar(type: string, typeData: any) {
|
||||||
const barQueryParams = {
|
const notificationBarInitData: NotificationBarIframeInitData = {
|
||||||
type,
|
type,
|
||||||
isVaultLocked: typeData.isVaultLocked,
|
isVaultLocked: typeData.isVaultLocked,
|
||||||
theme: typeData.theme,
|
theme: typeData.theme,
|
||||||
removeIndividualVault: typeData.removeIndividualVault,
|
removeIndividualVault: typeData.removeIndividualVault,
|
||||||
webVaultURL: typeData.webVaultURL,
|
|
||||||
importType: typeData.importType,
|
importType: typeData.importType,
|
||||||
};
|
};
|
||||||
const barQueryString = new URLSearchParams(barQueryParams).toString();
|
const notificationBarUrl = "notification/bar.html";
|
||||||
const barPage = "notification/bar.html?" + barQueryString;
|
|
||||||
|
|
||||||
const frame = document.getElementById("bit-notification-bar-iframe") as HTMLIFrameElement;
|
const frame = document.getElementById("bit-notification-bar-iframe") as HTMLIFrameElement;
|
||||||
if (frame != null && frame.src.indexOf(barPage) >= 0) {
|
if (frame != null && frame.src.indexOf(notificationBarUrl) >= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
closeBar(false);
|
closeBar(false);
|
||||||
openBar(type, barPage);
|
openBar(type, notificationBarUrl, notificationBarInitData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openBar(type: string, barPage: string) {
|
function openBar(
|
||||||
|
type: string,
|
||||||
|
barPage: string,
|
||||||
|
notificationBarInitData: NotificationBarIframeInitData,
|
||||||
|
) {
|
||||||
barType = type;
|
barType = type;
|
||||||
|
|
||||||
if (document.body == null) {
|
if (document.body == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupInitNotificationBarMessageListener(notificationBarInitData);
|
||||||
const barPageUrl: string = chrome.runtime.getURL(barPage);
|
const barPageUrl: string = chrome.runtime.getURL(barPage);
|
||||||
|
|
||||||
notificationBarIframe = document.createElement("iframe");
|
notificationBarIframe = document.createElement("iframe");
|
||||||
@@ -901,7 +905,30 @@ async function loadNotificationBar() {
|
|||||||
document.body.appendChild(frameDiv);
|
document.body.appendChild(frameDiv);
|
||||||
|
|
||||||
(notificationBarIframe.contentWindow.location as any) = barPageUrl;
|
(notificationBarIframe.contentWindow.location as any) = barPageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupInitNotificationBarMessageListener(initData: NotificationBarIframeInitData) {
|
||||||
|
const handleInitNotificationBarMessage = (event: MessageEvent) => {
|
||||||
|
const { source, data } = event;
|
||||||
|
if (
|
||||||
|
source !== notificationBarIframe.contentWindow ||
|
||||||
|
data?.command !== "initNotificationBar"
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationBarIframe.contentWindow.postMessage(
|
||||||
|
{ command: "initNotificationBar", initData },
|
||||||
|
"*",
|
||||||
|
);
|
||||||
|
injectSpacer();
|
||||||
|
window.removeEventListener("message", handleInitNotificationBarMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("message", handleInitNotificationBarMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function injectSpacer() {
|
||||||
const spacer = document.createElement("div");
|
const spacer = document.createElement("div");
|
||||||
spacer.id = "bit-notification-bar-spacer";
|
spacer.id = "bit-notification-bar-spacer";
|
||||||
spacer.style.cssText = "height: 42px;";
|
spacer.style.cssText = "height: 42px;";
|
||||||
|
|||||||
@@ -1,13 +1,26 @@
|
|||||||
import { SaveOrUpdateCipherResult } from "../../background/abstractions/notification.background";
|
type NotificationBarIframeInitData = {
|
||||||
|
type?: string;
|
||||||
|
isVaultLocked?: boolean;
|
||||||
|
theme?: string;
|
||||||
|
removeIndividualVault?: boolean;
|
||||||
|
importType?: string;
|
||||||
|
};
|
||||||
|
|
||||||
type NotificationBarWindowMessage = {
|
type NotificationBarWindowMessage = {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
command: string;
|
command: string;
|
||||||
|
error?: string;
|
||||||
|
initData?: NotificationBarIframeInitData;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NotificationBarWindowMessageHandlers = {
|
type NotificationBarWindowMessageHandlers = {
|
||||||
[key: string]: CallableFunction;
|
[key: string]: CallableFunction;
|
||||||
saveCipherAttemptCompleted: ({ message }: { message: SaveOrUpdateCipherResult }) => void;
|
initNotificationBar: ({ message }: { message: NotificationBarWindowMessage }) => void;
|
||||||
|
saveCipherAttemptCompleted: ({ message }: { message: NotificationBarWindowMessage }) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { NotificationBarWindowMessage, NotificationBarWindowMessageHandlers };
|
export {
|
||||||
|
NotificationBarIframeInitData,
|
||||||
|
NotificationBarWindowMessage,
|
||||||
|
NotificationBarWindowMessageHandlers,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,37 +1,42 @@
|
|||||||
|
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
||||||
import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||||
|
|
||||||
import { FilelessImportPort, FilelessImportType } from "../../tools/enums/fileless-import.enums";
|
import { FilelessImportPort, FilelessImportType } from "../../tools/enums/fileless-import.enums";
|
||||||
import {
|
import { AdjustNotificationBarMessageData } from "../background/abstractions/notification.background";
|
||||||
AdjustNotificationBarMessageData,
|
|
||||||
SaveOrUpdateCipherResult,
|
|
||||||
} from "../background/abstractions/notification.background";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NotificationBarWindowMessageHandlers,
|
NotificationBarWindowMessageHandlers,
|
||||||
NotificationBarWindowMessage,
|
NotificationBarWindowMessage,
|
||||||
|
NotificationBarIframeInitData,
|
||||||
} from "./abstractions/notification-bar";
|
} from "./abstractions/notification-bar";
|
||||||
|
|
||||||
require("./bar.scss");
|
require("./bar.scss");
|
||||||
|
|
||||||
const logService = new ConsoleLogService(false);
|
const logService = new ConsoleLogService(false);
|
||||||
|
let notificationBarIframeInitData: NotificationBarIframeInitData = {};
|
||||||
let windowMessageOrigin: string;
|
let windowMessageOrigin: string;
|
||||||
const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers = {
|
const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers = {
|
||||||
|
initNotificationBar: ({ message }) => initNotificationBar(message),
|
||||||
saveCipherAttemptCompleted: ({ message }) => handleSaveCipherAttemptCompletedMessage(message),
|
saveCipherAttemptCompleted: ({ message }) => handleSaveCipherAttemptCompletedMessage(message),
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
globalThis.addEventListener("load", load);
|
||||||
// delay 50ms so that we get proper body dimensions
|
|
||||||
setTimeout(load, 50);
|
|
||||||
});
|
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
setupWindowMessageListener();
|
setupWindowMessageListener();
|
||||||
|
postMessageToParent({ command: "initNotificationBar" });
|
||||||
|
}
|
||||||
|
|
||||||
const theme = getQueryVariable("theme");
|
function initNotificationBar(message: NotificationBarWindowMessage) {
|
||||||
document.documentElement.classList.add("theme_" + theme);
|
const { initData } = message;
|
||||||
|
if (!initData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationBarIframeInitData = initData;
|
||||||
|
const { isVaultLocked } = notificationBarIframeInitData;
|
||||||
|
setNotificationBarTheme();
|
||||||
|
|
||||||
const isVaultLocked = getQueryVariable("isVaultLocked") == "true";
|
|
||||||
(document.getElementById("logo") as HTMLImageElement).src = isVaultLocked
|
(document.getElementById("logo") as HTMLImageElement).src = isVaultLocked
|
||||||
? chrome.runtime.getURL("images/icon38_locked.png")
|
? chrome.runtime.getURL("images/icon38_locked.png")
|
||||||
: chrome.runtime.getURL("images/icon38.png");
|
: chrome.runtime.getURL("images/icon38.png");
|
||||||
@@ -55,16 +60,7 @@ function load() {
|
|||||||
startFilelessImport: chrome.i18n.getMessage("startFilelessImport"),
|
startFilelessImport: chrome.i18n.getMessage("startFilelessImport"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoLink = document.getElementById("logo-link") as HTMLAnchorElement;
|
setupLogoLink(i18n);
|
||||||
logoLink.title = i18n.appName;
|
|
||||||
|
|
||||||
// Update logo link to user's regional domain
|
|
||||||
const webVaultURL = getQueryVariable("webVaultURL");
|
|
||||||
const newVaultURL = webVaultURL && decodeURIComponent(webVaultURL);
|
|
||||||
|
|
||||||
if (newVaultURL && newVaultURL !== logoLink.href) {
|
|
||||||
logoLink.href = newVaultURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// i18n for "Add" template
|
// i18n for "Add" template
|
||||||
const addTemplate = document.getElementById("template-add") as HTMLTemplateElement;
|
const addTemplate = document.getElementById("template-add") as HTMLTemplateElement;
|
||||||
@@ -106,7 +102,7 @@ function load() {
|
|||||||
unlockTemplate.content.getElementById("unlock-text").textContent = i18n.notificationUnlockDesc;
|
unlockTemplate.content.getElementById("unlock-text").textContent = i18n.notificationUnlockDesc;
|
||||||
|
|
||||||
// i18n for "Fileless Import" (fileless-import) template
|
// i18n for "Fileless Import" (fileless-import) template
|
||||||
const isLpImport = getQueryVariable("importType") === FilelessImportType.LP;
|
const isLpImport = initData.importType === FilelessImportType.LP;
|
||||||
const importTemplate = document.getElementById("template-fileless-import") as HTMLTemplateElement;
|
const importTemplate = document.getElementById("template-fileless-import") as HTMLTemplateElement;
|
||||||
|
|
||||||
const startImportButton = importTemplate.content.getElementById("start-fileless-import");
|
const startImportButton = importTemplate.content.getElementById("start-fileless-import");
|
||||||
@@ -125,13 +121,14 @@ function load() {
|
|||||||
const closeButton = document.getElementById("close-button");
|
const closeButton = document.getElementById("close-button");
|
||||||
closeButton.title = i18n.close;
|
closeButton.title = i18n.close;
|
||||||
|
|
||||||
if (getQueryVariable("type") === "add") {
|
const notificationType = initData.type;
|
||||||
|
if (initData.type === "add") {
|
||||||
handleTypeAdd();
|
handleTypeAdd();
|
||||||
} else if (getQueryVariable("type") === "change") {
|
} else if (notificationType === "change") {
|
||||||
handleTypeChange();
|
handleTypeChange();
|
||||||
} else if (getQueryVariable("type") === "unlock") {
|
} else if (notificationType === "unlock") {
|
||||||
handleTypeUnlock();
|
handleTypeUnlock();
|
||||||
} else if (getQueryVariable("type") === "fileless-import") {
|
} else if (notificationType === "fileless-import") {
|
||||||
handleTypeFilelessImport();
|
handleTypeFilelessImport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,20 +143,6 @@ function load() {
|
|||||||
adjustHeight();
|
adjustHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getQueryVariable(variable: string) {
|
|
||||||
const query = window.location.search.substring(1);
|
|
||||||
const vars = query.split("&");
|
|
||||||
|
|
||||||
for (let i = 0; i < vars.length; i++) {
|
|
||||||
const pair = vars[i].split("=");
|
|
||||||
if (pair[0] === variable) {
|
|
||||||
return pair[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTypeAdd() {
|
function handleTypeAdd() {
|
||||||
setContent(document.getElementById("template-add") as HTMLTemplateElement);
|
setContent(document.getElementById("template-add") as HTMLTemplateElement);
|
||||||
|
|
||||||
@@ -219,7 +202,7 @@ function sendSaveCipherMessage(edit: boolean, folder?: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSaveCipherAttemptCompletedMessage(message: SaveOrUpdateCipherResult) {
|
function handleSaveCipherAttemptCompletedMessage(message: NotificationBarWindowMessage) {
|
||||||
const addSaveButtonContainers = document.querySelectorAll(".add-change-cipher-buttons");
|
const addSaveButtonContainers = document.querySelectorAll(".add-change-cipher-buttons");
|
||||||
const notificationBarOuterWrapper = document.getElementById("notification-bar-outer-wrapper");
|
const notificationBarOuterWrapper = document.getElementById("notification-bar-outer-wrapper");
|
||||||
if (message?.error) {
|
if (message?.error) {
|
||||||
@@ -233,7 +216,9 @@ function handleSaveCipherAttemptCompletedMessage(message: SaveOrUpdateCipherResu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const messageName =
|
const messageName =
|
||||||
getQueryVariable("type") === "add" ? "saveCipherAttemptSuccess" : "updateCipherAttemptSuccess";
|
notificationBarIframeInitData.type === "add"
|
||||||
|
? "saveCipherAttemptSuccess"
|
||||||
|
: "updateCipherAttemptSuccess";
|
||||||
|
|
||||||
addSaveButtonContainers.forEach((element) => {
|
addSaveButtonContainers.forEach((element) => {
|
||||||
element.textContent = chrome.i18n.getMessage(messageName);
|
element.textContent = chrome.i18n.getMessage(messageName);
|
||||||
@@ -261,7 +246,7 @@ function handleTypeUnlock() {
|
|||||||
* the Bitwarden vault.
|
* the Bitwarden vault.
|
||||||
*/
|
*/
|
||||||
function handleTypeFilelessImport() {
|
function handleTypeFilelessImport() {
|
||||||
const importType = getQueryVariable("importType");
|
const importType = notificationBarIframeInitData.importType;
|
||||||
const port = chrome.runtime.connect({ name: FilelessImportPort.NotificationBar });
|
const port = chrome.runtime.connect({ name: FilelessImportPort.NotificationBar });
|
||||||
setContent(document.getElementById("template-fileless-import") as HTMLTemplateElement);
|
setContent(document.getElementById("template-fileless-import") as HTMLTemplateElement);
|
||||||
|
|
||||||
@@ -349,7 +334,7 @@ function getSelectedFolder(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeIndividualVault(): boolean {
|
function removeIndividualVault(): boolean {
|
||||||
return getQueryVariable("removeIndividualVault") == "true";
|
return notificationBarIframeInitData.removeIndividualVault;
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustHeight() {
|
function adjustHeight() {
|
||||||
@@ -383,3 +368,30 @@ function handleWindowMessage(event: MessageEvent) {
|
|||||||
|
|
||||||
handler({ message });
|
handler({ message });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupLogoLink(i18n: Record<string, string>) {
|
||||||
|
const logoLink = document.getElementById("logo-link") as HTMLAnchorElement;
|
||||||
|
logoLink.title = i18n.appName;
|
||||||
|
const setWebVaultUrlLink = (webVaultURL: string) => {
|
||||||
|
const newVaultURL = webVaultURL && decodeURIComponent(webVaultURL);
|
||||||
|
if (newVaultURL && newVaultURL !== logoLink.href) {
|
||||||
|
logoLink.href = newVaultURL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sendPlatformMessage({ command: "getWebVaultUrlForNotification" }, setWebVaultUrlLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNotificationBarTheme() {
|
||||||
|
let theme = notificationBarIframeInitData.theme;
|
||||||
|
if (theme === ThemeType.System) {
|
||||||
|
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
|
? ThemeType.Dark
|
||||||
|
: ThemeType.Light;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.documentElement.classList.add(`theme_${theme}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function postMessageToParent(message: NotificationBarWindowMessage) {
|
||||||
|
window.parent.postMessage(message, windowMessageOrigin || "*");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user