1
0
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:
Daniel Riera
2025-03-14 16:01:15 -04:00
committed by GitHub
parent 2d4ffe6eb6
commit 8abb74d598
2 changed files with 82 additions and 35 deletions

View File

@@ -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;

View File

@@ -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 templates 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");
if (closeButton) {
closeButton.title = i18n.close; 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",