mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 14:23:32 +00:00
PM-17963 added new functions and checks in order to make file type safe (#13792)
This commit is contained in:
@@ -28,7 +28,7 @@ export function NotificationConfirmationContainer({
|
|||||||
handleCloseNotification: (e: Event) => void;
|
handleCloseNotification: (e: Event) => void;
|
||||||
handleOpenVault: (e: Event) => void;
|
handleOpenVault: (e: Event) => void;
|
||||||
} & {
|
} & {
|
||||||
error: string;
|
error?: string;
|
||||||
i18n: { [key: string]: string };
|
i18n: { [key: string]: string };
|
||||||
type: NotificationType;
|
type: NotificationType;
|
||||||
username: string;
|
username: string;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { render } from "lit";
|
import { render } from "lit";
|
||||||
|
|
||||||
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
|
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
|
||||||
@@ -72,12 +70,51 @@ function getI18n() {
|
|||||||
saveFailure: chrome.i18n.getMessage("saveFailure"),
|
saveFailure: chrome.i18n.getMessage("saveFailure"),
|
||||||
saveFailureDetails: chrome.i18n.getMessage("saveFailureDetails"),
|
saveFailureDetails: chrome.i18n.getMessage("saveFailureDetails"),
|
||||||
saveLoginPrompt: chrome.i18n.getMessage("saveLoginPrompt"),
|
saveLoginPrompt: chrome.i18n.getMessage("saveLoginPrompt"),
|
||||||
|
typeLogin: chrome.i18n.getMessage("typeLogin"),
|
||||||
updateLoginAction: chrome.i18n.getMessage("updateLoginAction"),
|
updateLoginAction: chrome.i18n.getMessage("updateLoginAction"),
|
||||||
updateLoginPrompt: chrome.i18n.getMessage("updateLoginPrompt"),
|
updateLoginPrompt: chrome.i18n.getMessage("updateLoginPrompt"),
|
||||||
view: chrome.i18n.getMessage("view"),
|
view: chrome.i18n.getMessage("view"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to locate an element by ID within a template’s content and casts it to the specified type.
|
||||||
|
*
|
||||||
|
* @param templateElement - The template whose content will be searched for the element.
|
||||||
|
* @param elementId - The ID of the element being searched for.
|
||||||
|
* @returns The typed element if found, otherwise log error.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const findElementById = <ElementType extends HTMLElement>(
|
||||||
|
templateElement: HTMLTemplateElement,
|
||||||
|
elementId: string,
|
||||||
|
): ElementType => {
|
||||||
|
const element = templateElement.content.getElementById(elementId);
|
||||||
|
if (!element) {
|
||||||
|
throw new Error(`Element with ID "${elementId}" not found in template.`);
|
||||||
|
}
|
||||||
|
return element as ElementType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text content of an element identified by ID within a template's content.
|
||||||
|
*
|
||||||
|
* @param template - The template whose content will be searched for the element.
|
||||||
|
* @param elementId - The ID of the element whose text content is to be set.
|
||||||
|
* @param text - The text content to set for the specified element.
|
||||||
|
* @returns void
|
||||||
|
*
|
||||||
|
* This function attempts to locate an element by its ID within the content of a given HTML template.
|
||||||
|
* If the element is found, it updates the element's text content with the provided text.
|
||||||
|
* If the element is not found, the function does nothing, ensuring that the operation is safe and does not throw errors.
|
||||||
|
*/
|
||||||
|
function setElementText(template: HTMLTemplateElement, elementId: string, text: string): void {
|
||||||
|
const element = template.content.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initNotificationBar(message: NotificationBarWindowMessage) {
|
function initNotificationBar(message: NotificationBarWindowMessage) {
|
||||||
const { initData } = message;
|
const { initData } = message;
|
||||||
if (!initData) {
|
if (!initData) {
|
||||||
@@ -87,7 +124,7 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
|
|||||||
notificationBarIframeInitData = initData;
|
notificationBarIframeInitData = initData;
|
||||||
const { isVaultLocked, theme } = notificationBarIframeInitData;
|
const { isVaultLocked, theme } = notificationBarIframeInitData;
|
||||||
const i18n = getI18n();
|
const i18n = getI18n();
|
||||||
const resolvedTheme = getResolvedTheme(theme);
|
const resolvedTheme = getResolvedTheme(theme ?? ThemeTypes.Light);
|
||||||
|
|
||||||
if (useComponentBar) {
|
if (useComponentBar) {
|
||||||
document.body.innerHTML = "";
|
document.body.innerHTML = "";
|
||||||
@@ -122,45 +159,47 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
|
|||||||
// i18n for "Add" template
|
// i18n for "Add" template
|
||||||
const addTemplate = document.getElementById("template-add") as HTMLTemplateElement;
|
const addTemplate = document.getElementById("template-add") as HTMLTemplateElement;
|
||||||
|
|
||||||
const neverButton = addTemplate.content.getElementById("never-save");
|
const neverButton = findElementById<HTMLButtonElement>(addTemplate, "never-save");
|
||||||
neverButton.textContent = i18n.never;
|
neverButton.textContent = i18n.never;
|
||||||
|
|
||||||
const selectFolder = addTemplate.content.getElementById("select-folder");
|
const selectFolder = findElementById<HTMLSelectElement>(addTemplate, "select-folder");
|
||||||
selectFolder.hidden = isVaultLocked || removeIndividualVault();
|
selectFolder.hidden = isVaultLocked || removeIndividualVault();
|
||||||
selectFolder.setAttribute("aria-label", i18n.folder);
|
selectFolder.setAttribute("aria-label", i18n.folder);
|
||||||
|
|
||||||
const addButton = addTemplate.content.getElementById("add-save");
|
const addButton = findElementById<HTMLButtonElement>(addTemplate, "add-save");
|
||||||
addButton.textContent = i18n.notificationAddSave;
|
addButton.textContent = i18n.notificationAddSave;
|
||||||
|
|
||||||
const addEditButton = addTemplate.content.getElementById("add-edit");
|
const addEditButton = findElementById<HTMLButtonElement>(addTemplate, "add-edit");
|
||||||
// If Remove Individual Vault policy applies, "Add" opens the edit tab, so we hide the Edit button
|
// If Remove Individual Vault policy applies, "Add" opens the edit tab, so we hide the Edit button
|
||||||
addEditButton.hidden = removeIndividualVault();
|
addEditButton.hidden = removeIndividualVault();
|
||||||
addEditButton.textContent = i18n.notificationEdit;
|
addEditButton.textContent = i18n.notificationEdit;
|
||||||
|
|
||||||
addTemplate.content.getElementById("add-text").textContent = i18n.notificationAddDesc;
|
setElementText(addTemplate, "add-text", i18n.notificationAddDesc);
|
||||||
|
|
||||||
// i18n for "Change" (update password) template
|
// i18n for "Change" (update password) template
|
||||||
const changeTemplate = document.getElementById("template-change") as HTMLTemplateElement;
|
const changeTemplate = document.getElementById("template-change") as HTMLTemplateElement;
|
||||||
|
|
||||||
const changeButton = changeTemplate.content.getElementById("change-save");
|
const changeButton = findElementById<HTMLSelectElement>(changeTemplate, "change-save");
|
||||||
changeButton.textContent = i18n.notificationChangeSave;
|
changeButton.textContent = i18n.notificationChangeSave;
|
||||||
|
|
||||||
const changeEditButton = changeTemplate.content.getElementById("change-edit");
|
const changeEditButton = findElementById<HTMLButtonElement>(changeTemplate, "change-edit");
|
||||||
changeEditButton.textContent = i18n.notificationEdit;
|
changeEditButton.textContent = i18n.notificationEdit;
|
||||||
|
|
||||||
changeTemplate.content.getElementById("change-text").textContent = i18n.notificationChangeDesc;
|
setElementText(changeTemplate, "change-text", i18n.notificationChangeDesc);
|
||||||
|
|
||||||
// i18n for "Unlock" (unlock extension) template
|
// i18n for "Unlock" (unlock extension) template
|
||||||
const unlockTemplate = document.getElementById("template-unlock") as HTMLTemplateElement;
|
const unlockTemplate = document.getElementById("template-unlock") as HTMLTemplateElement;
|
||||||
|
|
||||||
const unlockButton = unlockTemplate.content.getElementById("unlock-vault");
|
const unlockButton = findElementById<HTMLButtonElement>(unlockTemplate, "unlock-vault");
|
||||||
unlockButton.textContent = i18n.notificationUnlock;
|
unlockButton.textContent = i18n.notificationUnlock;
|
||||||
|
|
||||||
unlockTemplate.content.getElementById("unlock-text").textContent = i18n.notificationUnlockDesc;
|
setElementText(unlockTemplate, "unlock-text", i18n.notificationUnlockDesc);
|
||||||
|
|
||||||
// i18n for body content
|
// i18n for body content
|
||||||
const closeButton = document.getElementById("close-button");
|
const closeButton = document.getElementById("close-button");
|
||||||
closeButton.title = i18n.close;
|
if (closeButton) {
|
||||||
|
closeButton.title = i18n.close;
|
||||||
|
}
|
||||||
|
|
||||||
const notificationType = initData.type;
|
const notificationType = initData.type;
|
||||||
if (notificationType === "add") {
|
if (notificationType === "add") {
|
||||||
@@ -171,13 +210,13 @@ function initNotificationBar(message: NotificationBarWindowMessage) {
|
|||||||
handleTypeUnlock();
|
handleTypeUnlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeButton.addEventListener("click", handleCloseNotification);
|
closeButton?.addEventListener("click", handleCloseNotification);
|
||||||
|
|
||||||
globalThis.addEventListener("resize", adjustHeight);
|
globalThis.addEventListener("resize", adjustHeight);
|
||||||
adjustHeight();
|
adjustHeight();
|
||||||
}
|
}
|
||||||
function handleEditOrUpdateAction(e: Event) {
|
function handleEditOrUpdateAction(e: Event) {
|
||||||
const notificationType = initData.type;
|
const notificationType = initData?.type;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
notificationType === "add" ? sendSaveCipherMessage(true) : sendSaveCipherMessage(false);
|
notificationType === "add" ? sendSaveCipherMessage(true) : sendSaveCipherMessage(false);
|
||||||
}
|
}
|
||||||
@@ -202,7 +241,7 @@ function handleTypeAdd() {
|
|||||||
setContent(document.getElementById("template-add") as HTMLTemplateElement);
|
setContent(document.getElementById("template-add") as HTMLTemplateElement);
|
||||||
|
|
||||||
const addButton = document.getElementById("add-save");
|
const addButton = document.getElementById("add-save");
|
||||||
addButton.addEventListener("click", (e) => {
|
addButton?.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// If Remove Individual Vault policy applies, "Add" opens the edit tab
|
// If Remove Individual Vault policy applies, "Add" opens the edit tab
|
||||||
@@ -215,14 +254,14 @@ function handleTypeAdd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editButton = document.getElementById("add-edit");
|
const editButton = document.getElementById("add-edit");
|
||||||
editButton.addEventListener("click", (e) => {
|
editButton?.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
sendSaveCipherMessage(true, getSelectedFolder());
|
sendSaveCipherMessage(true, getSelectedFolder());
|
||||||
});
|
});
|
||||||
|
|
||||||
const neverButton = document.getElementById("never-save");
|
const neverButton = document.getElementById("never-save");
|
||||||
neverButton.addEventListener("click", (e) => {
|
neverButton?.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
sendPlatformMessage({
|
sendPlatformMessage({
|
||||||
command: "bgNeverSave",
|
command: "bgNeverSave",
|
||||||
@@ -235,14 +274,14 @@ function handleTypeAdd() {
|
|||||||
function handleTypeChange() {
|
function handleTypeChange() {
|
||||||
setContent(document.getElementById("template-change") as HTMLTemplateElement);
|
setContent(document.getElementById("template-change") as HTMLTemplateElement);
|
||||||
const changeButton = document.getElementById("change-save");
|
const changeButton = document.getElementById("change-save");
|
||||||
changeButton.addEventListener("click", (e) => {
|
changeButton?.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
sendSaveCipherMessage(false);
|
sendSaveCipherMessage(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
const editButton = document.getElementById("change-edit");
|
const editButton = document.getElementById("change-edit");
|
||||||
editButton.addEventListener("click", (e) => {
|
editButton?.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
sendSaveCipherMessage(true);
|
sendSaveCipherMessage(true);
|
||||||
@@ -264,7 +303,7 @@ function handleSaveCipherAttemptCompletedMessage(message: NotificationBarWindowM
|
|||||||
addSaveButtonContainers.forEach((element) => {
|
addSaveButtonContainers.forEach((element) => {
|
||||||
element.textContent = chrome.i18n.getMessage("saveCipherAttemptFailed");
|
element.textContent = chrome.i18n.getMessage("saveCipherAttemptFailed");
|
||||||
element.classList.add("error-message");
|
element.classList.add("error-message");
|
||||||
notificationBarOuterWrapper.classList.add("error-event");
|
notificationBarOuterWrapper?.classList.add("error-event");
|
||||||
});
|
});
|
||||||
|
|
||||||
adjustHeight();
|
adjustHeight();
|
||||||
@@ -278,7 +317,7 @@ function handleSaveCipherAttemptCompletedMessage(message: NotificationBarWindowM
|
|||||||
element.textContent = chrome.i18n.getMessage(messageName);
|
element.textContent = chrome.i18n.getMessage(messageName);
|
||||||
element.prepend(buildSvgDomElement(circleCheckIcon));
|
element.prepend(buildSvgDomElement(circleCheckIcon));
|
||||||
element.classList.add("success-message");
|
element.classList.add("success-message");
|
||||||
notificationBarOuterWrapper.classList.add("success-event");
|
notificationBarOuterWrapper?.classList.add("success-event");
|
||||||
});
|
});
|
||||||
adjustHeight();
|
adjustHeight();
|
||||||
globalThis.setTimeout(
|
globalThis.setTimeout(
|
||||||
@@ -299,7 +338,7 @@ function handleSaveCipherConfirmation(message: NotificationBarWindowMessage) {
|
|||||||
const { theme, type } = notificationBarIframeInitData;
|
const { theme, type } = notificationBarIframeInitData;
|
||||||
const { error, username, cipherId } = message;
|
const { error, username, cipherId } = message;
|
||||||
const i18n = getI18n();
|
const i18n = getI18n();
|
||||||
const resolvedTheme = getResolvedTheme(theme);
|
const resolvedTheme = getResolvedTheme(theme ?? ThemeTypes.Light);
|
||||||
|
|
||||||
globalThis.setTimeout(() => sendPlatformMessage({ command: "bgCloseNotificationBar" }), 5000);
|
globalThis.setTimeout(() => sendPlatformMessage({ command: "bgCloseNotificationBar" }), 5000);
|
||||||
|
|
||||||
@@ -311,8 +350,8 @@ function handleSaveCipherConfirmation(message: NotificationBarWindowMessage) {
|
|||||||
handleCloseNotification,
|
handleCloseNotification,
|
||||||
i18n,
|
i18n,
|
||||||
error,
|
error,
|
||||||
username,
|
username: username ?? i18n.typeLogin,
|
||||||
handleOpenVault: (e) => openViewVaultItemPopout(e, cipherId),
|
handleOpenVault: (e) => cipherId && openViewVaultItemPopout(e, cipherId),
|
||||||
}),
|
}),
|
||||||
document.body,
|
document.body,
|
||||||
);
|
);
|
||||||
@@ -322,7 +361,7 @@ function handleTypeUnlock() {
|
|||||||
setContent(document.getElementById("template-unlock") as HTMLTemplateElement);
|
setContent(document.getElementById("template-unlock") as HTMLTemplateElement);
|
||||||
|
|
||||||
const unlockButton = document.getElementById("unlock-vault");
|
const unlockButton = document.getElementById("unlock-vault");
|
||||||
unlockButton.addEventListener("click", (e) => {
|
unlockButton?.addEventListener("click", (e) => {
|
||||||
sendPlatformMessage({
|
sendPlatformMessage({
|
||||||
command: "bgReopenUnlockPopout",
|
command: "bgReopenUnlockPopout",
|
||||||
});
|
});
|
||||||
@@ -331,12 +370,12 @@ function handleTypeUnlock() {
|
|||||||
|
|
||||||
function setContent(template: HTMLTemplateElement) {
|
function setContent(template: HTMLTemplateElement) {
|
||||||
const content = document.getElementById("content");
|
const content = document.getElementById("content");
|
||||||
while (content.firstChild) {
|
while (content?.firstChild) {
|
||||||
content.removeChild(content.firstChild);
|
content?.removeChild(content.firstChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newElement = template.content.cloneNode(true) as HTMLElement;
|
const newElement = template.content.cloneNode(true) as HTMLElement;
|
||||||
content.appendChild(newElement);
|
content?.appendChild(newElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPlatformMessage(
|
function sendPlatformMessage(
|
||||||
@@ -353,13 +392,17 @@ function sendPlatformMessage(
|
|||||||
function loadFolderSelector() {
|
function loadFolderSelector() {
|
||||||
const populateFolderData = (folderData: FolderView[]) => {
|
const populateFolderData = (folderData: FolderView[]) => {
|
||||||
const select = document.getElementById("select-folder");
|
const select = document.getElementById("select-folder");
|
||||||
|
if (!select) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!folderData?.length) {
|
if (!folderData?.length) {
|
||||||
select.appendChild(new Option(chrome.i18n.getMessage("noFoldersFound"), null, true));
|
select.appendChild(new Option(chrome.i18n.getMessage("noFoldersFound"), undefined, true));
|
||||||
select.setAttribute("disabled", "true");
|
select.setAttribute("disabled", "true");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
select.appendChild(new Option(chrome.i18n.getMessage("selectFolder"), null, true));
|
select.appendChild(new Option(chrome.i18n.getMessage("selectFolder"), undefined, true));
|
||||||
folderData.forEach((folder: FolderView) => {
|
folderData.forEach((folder: FolderView) => {
|
||||||
// Select "No Folder" (id=null) folder by default
|
// Select "No Folder" (id=null) folder by default
|
||||||
select.appendChild(new Option(folder.name, folder.id || "", false));
|
select.appendChild(new Option(folder.name, folder.id || "", false));
|
||||||
@@ -374,12 +417,16 @@ function getSelectedFolder(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeIndividualVault(): boolean {
|
function removeIndividualVault(): boolean {
|
||||||
return notificationBarIframeInitData.removeIndividualVault;
|
return Boolean(notificationBarIframeInitData?.removeIndividualVault);
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustHeight() {
|
function adjustHeight() {
|
||||||
|
const body = document.querySelector("body");
|
||||||
|
if (!body) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const data: AdjustNotificationBarMessageData = {
|
const data: AdjustNotificationBarMessageData = {
|
||||||
height: document.querySelector("body").scrollHeight,
|
height: body.scrollHeight,
|
||||||
};
|
};
|
||||||
sendPlatformMessage({
|
sendPlatformMessage({
|
||||||
command: "bgAdjustNotificationBar",
|
command: "bgAdjustNotificationBar",
|
||||||
|
|||||||
Reference in New Issue
Block a user