Skip to content

Commit

Permalink
Remove context isolation
Browse files Browse the repository at this point in the history
I couldn't get the application to run unless I unset contextIsolation.
So here is the application split into preload and node files.

Makes iterop a bit more painful. But everything seems to work, at least
as far as I tested. I think the interop stuff makes error logging a bit
painful, so I may have missed the mark a bit. I can say for certain that
clicking notifications works as expected. The mutation observer stuff
I'm a little less clear on. (But the functions are called when I used
console.log statements).

I completely removed the profileImage stuff, it doesn't appear to be
necessary. Maybe its just Linux, but the notification rendered the
NotificationsOptions.icon that was provided by the google SPA just
fine without all the cache code.
  • Loading branch information
ElementalWarrior committed Nov 19, 2024
1 parent 68dffa3 commit a081158
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 174 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"main": "app/background.js",
"scripts": {
"start": "ELECTRON_ENABLE_LOGGING=1 ELECTRON_DEBUG_NOTIFICATIONS=true yarn build:dev && cross-env NODE_ENV=development electron --enable-logging ./app/background.js",
"start": "yarn build:dev && cross-env NODE_ENV=development electron ./app/background.js",
"dist": "yarn build && yarn package",
"build": "webpack --mode=production",
"build:dev": "webpack --mode=development",
Expand Down
10 changes: 7 additions & 3 deletions src/background.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { app, Event as ElectronEvent, ipcMain, shell } from "electron";
import { app, Event as ElectronEvent, ipcMain, ipcRenderer, shell } from "electron";
import { BrowserWindow } from "electron/main";
import path from "path";
import process from "process";
Expand All @@ -8,6 +8,7 @@ import { MenuManager } from "./helpers/menuManager";
import { setSettingsFlushEnabled, settings } from "./helpers/settings";
import { Conversation, TrayManager } from "./helpers/trayManager";
import { popupContextMenu } from "./menu/contextMenu";
import fs from "fs";

const {
autoHideMenuEnabled,
Expand Down Expand Up @@ -75,8 +76,6 @@ if (gotTheLock) {
: undefined,
titleBarStyle: IS_MAC ? "hiddenInset" : "default",
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: IS_DEV
? path.resolve(app.getAppPath(), "bridge.js")
: path.resolve(app.getAppPath(), "app", "bridge.js"),
Expand Down Expand Up @@ -197,4 +196,9 @@ if (gotTheLock) {
ipcMain.on("set-recent-conversations", (_event, data: Conversation[]) => {
trayManager.setRecentConversations(data);
});

ipcMain.handle("get-icon", () => {
var bitmap = fs.readFileSync(path.resolve(RESOURCES_PATH, "icons", "64x64.png"));
return Buffer.from(bitmap).toString('base64');
})
}
219 changes: 122 additions & 97 deletions src/bridge.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,142 @@
import { ipcRenderer } from "electron";
import path from "path";
import { contextBridge, ipcRenderer, webFrame } from "electron";

import {
INITIAL_ICON_IMAGE,
IS_MAC,
RESOURCES_PATH,
} from "./helpers/constants";
} from "./preload/constants_preload";
import {
createRecentThreadObserver,
createUnreadObserver,
focusFunctions,
recentThreadObserver,
} from "./helpers/observers";
import { getProfileImg } from "./helpers/profileImage";

window.addEventListener("load", () => {
if (IS_MAC) {
const titlebarStyle = `#amd-titlebar {
-webkit-app-region: drag;
position: fixed;
width: 100%;
height: 64px;
top: 0;
left: 0;
background: none;
pointer-events: none;
}`;
} from "./preload/observers";

document.body.appendChild(
Object.assign(document.createElement("style"), {
textContent: titlebarStyle,
})
);

const titlebar = document.createElement("div");
titlebar.id = "amd-titlebar";
document.querySelector("mw-app")?.parentNode?.prepend(titlebar);
declare global {
interface Window {
interop: any;
}

const conversationListObserver = new MutationObserver(() => {
if (document.querySelector("mws-conversations-list") != null) {
createUnreadObserver();
createRecentThreadObserver();

// keep trying to get an image that isnt blank until they load
const interval = setInterval(() => {
const conversation = document.body.querySelector(
"mws-conversation-list-item"
);
if (conversation) {
const canvas = conversation.querySelector(
"a div.avatar-container canvas"
) as HTMLCanvasElement | null;

if (canvas != null && canvas.toDataURL() != INITIAL_ICON_IMAGE) {
recentThreadObserver();
// refresh for profile image loads after letter loads.
setTimeout(recentThreadObserver, 3000);
clearInterval(interval);
}
}
}, 250);
conversationListObserver.disconnect();
}

const preload_init = () => {

if (IS_MAC) {
const titlebarStyle = `#amd-titlebar {
-webkit-app-region: drag;
position: fixed;
width: 100%;
height: 64px;
top: 0;
left: 0;
background: none;
pointer-events: none;
}`;
document.body.appendChild(
Object.assign(document.createElement("style"), {
textContent: titlebarStyle,
})
);

const titlebar = document.createElement("div");
titlebar.id = "amd-titlebar";
document.querySelector("mw-app")?.parentNode?.prepend(titlebar);
}

const conversationListObserver = new MutationObserver(() => {
if (document.querySelector("mws-conversations-list") != null) {
createUnreadObserver();
createRecentThreadObserver();

// keep trying to get an image that isnt blank until they load
const interval = setInterval(() => {
const conversation = document.body.querySelector(
"mws-conversation-list-item"
);
if (conversation) {
const canvas = conversation.querySelector(
"a div.avatar-container canvas"
) as HTMLCanvasElement | null;

if (canvas != null && canvas.toDataURL() != INITIAL_ICON_IMAGE) {
recentThreadObserver();
// refresh for profile image loads after letter loads.
setTimeout(recentThreadObserver, 3000);
clearInterval(interval);
}
}
}, 250);
conversationListObserver.disconnect();
}

const title = document.head.querySelector("title");
if (title != null) {
title.innerText = "Android Messages";
}
});

conversationListObserver.observe(document.body, {
attributes: false,
subtree: true,
childList: true,
});
}

const title = document.head.querySelector("title");
if (title != null) {
title.innerText = "Android Messages";
}
});

conversationListObserver.observe(document.body, {
attributes: false,
subtree: true,
childList: true,
});
ipcRenderer.on("focus-conversation", (event, i) => {
focusFunctions[i]();
});

const OldNotification = window.Notification;

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Notification = function (title: string, options: NotificationOptions) {
const icon = getProfileImg(title);

const hideContent = ipcRenderer.sendSync("should-hide-notification-content");

const notificationOpts: NotificationOptions = hideContent
? {
body: "Click to open",
icon: path.resolve(RESOURCES_PATH, "icons", "64x64.png"),
}
: {
icon: icon?.toDataURL(),
body: options.body || "",
};

const newTitle = hideContent ? "New Message" : title;
const notification = new OldNotification(newTitle, notificationOpts);
notification.addEventListener("click", () => {
contextBridge.exposeInMainWorld("interop", {
show_main_window: () => {
ipcRenderer.send("show-main-window");
document.dispatchEvent(new Event("focus"));
},
flash_main: () => {
ipcRenderer.send("flash-main-window-if-not-focused");
},
should_hide: () => {
return ipcRenderer.sendSync("should-hide-notification-content");
},
get_icon: async () => {
const data = await ipcRenderer.invoke("get-icon");
return `data:image/png;base64,${data}`;
},
preload_init,
});
webFrame.executeJavaScript(`
window.addEventListener("load", async () => {
window.interop.preload_init();
window.icon_data_uri = await window.interop.get_icon();
});
ipcRenderer.send("flash-main-window-if-not-focused");
return notification;
`);
webFrame.executeJavaScript(`window.OldNotification = window.Notification;
window.Notification = function (title, options) {
try {
const hideContent = window.interop.should_hide();
const notificationOpts = hideContent
? {
body: "Click to open",
icon: window.icon_data_uri
}
: {
body: options?.body || "",
icon: options?.icon
};
const newTitle = hideContent ? "New Message" : title;
const notification = new window.OldNotification(newTitle, notificationOpts);
notification.addEventListener("click", () => {
window.interop.show_main_window();
document.dispatchEvent(new Event("focus"));
});
window.interop.flash_main();
return notification;
} catch (e) {
console.error(e);
console.trace();
}
};
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
window.Notification.permission = "granted";
window.Notification.requestPermission = async () => "granted";

window.module.exports = null;

ipcRenderer.on("focus-conversation", (event, i) => {
focusFunctions[i]();
});
`);
contextBridge.exposeInMainWorld("module", {exports: null});
8 changes: 1 addition & 7 deletions src/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,4 @@ export const SETTINGS_FILE = (): string => {
*/
export const UUID_NAMESPACE = "ddf09da3-3df8-4417-ae3b-62d3ed4bfb72";

/**
* Initial image AMD loads for icons. Used to check against and ignore when populating tray context menu.
*/
export const INITIAL_ICON_IMAGE =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAAXNSR0IArs4c6QAABGJJREFUeF7t1AEJAAAMAsHZv/RyPNwSyDncOQIECEQEFskpJgECBM5geQICBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAgQdWMQCX4yW9owAAAABJRU5ErkJggg==";

export const RECENT_CONVERSATION_TRAY_COUNT = 3;
export {INITIAL_ICON_IMAGE} from "./constants_shared";
6 changes: 6 additions & 0 deletions src/helpers/constants_shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

/**
* Initial image AMD loads for icons. Used to check against and ignore when populating tray context menu.
*/
export const INITIAL_ICON_IMAGE =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAAXNSR0IArs4c6QAABGJJREFUeF7t1AEJAAAMAsHZv/RyPNwSyDncOQIECEQEFskpJgECBM5geQICBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAgQdWMQCX4yW9owAAAABJRU5ErkJggg==";
64 changes: 0 additions & 64 deletions src/helpers/profileImage.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/menu/settingsMenu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BrowserWindow, MenuItem, MenuItemConstructorOptions } from "electron";
import { BaseWindow, MenuItem, MenuItemConstructorOptions } from "electron";
import { IS_MAC } from "../helpers/constants";
import { settings } from "../helpers/settings";
import { separator } from "./items/separator";
Expand Down Expand Up @@ -27,7 +27,7 @@ export const settingsMenu: MenuItemConstructorOptions = {
label: "Auto Hide Menu Bar",
type: "checkbox",
checked: autoHideMenuEnabled.value,
click: (item: MenuItem, window?: BrowserWindow): void => {
click: (item: MenuItem, window?: BaseWindow, event?: Electron.KeyboardEvent): void => {
autoHideMenuEnabled.next(item.checked);
window?.setMenuBarVisibility(!autoHideMenuEnabled.value);
window?.setAutoHideMenuBar(autoHideMenuEnabled.value);
Expand Down
7 changes: 7 additions & 0 deletions src/preload/constants_preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Can't use constants.ts in bridge.ts because of context isolation

export const IS_MAC = window.navigator.userAgent.indexOf("Macintosh") > -1;

export const RECENT_CONVERSATION_TRAY_COUNT = 3;

export {INITIAL_ICON_IMAGE} from "../helpers/constants_shared";
Loading

0 comments on commit a081158

Please sign in to comment.