Add Chrome extension management functionality and update .gitignore

This commit is contained in:
Arma-Damna-Dillo 2025-03-15 20:07:56 -05:00
parent f11841c1a2
commit 71b407c211
12 changed files with 588 additions and 47 deletions

BIN
.DS_Store vendored

Binary file not shown.

View file

@ -0,0 +1,9 @@
---
description:
globs:
---
# Your rule content
- You can @ files here
- You can use markdown but dont have to

9
.gitignore vendored
View file

@ -2,4 +2,11 @@ node_modules
seedium-linux-x64
sneedium-win32-x64
seedium-linux-arm64
sneedium-win32-arm64
sneedium-win32-arm64
sneedium-darwin-x64
sneedium-darwin-arm64
out/
dist/
.DS_Store
.env
*.log

View file

@ -1,7 +1,7 @@
<img src="https://github.com/Sneed-Group/sneedium/blob/master/logo.png?raw=true" align="right" width="15%"/>
# Sneedium
A basic web browser in Electron. ***With a functioning adblocker and privacy redirection technologies!***
A basic web browser in Electron. ***With a functioning adblocker, privacy redirection technologies, and Chrome extension support!***
[![Download latest build.](https://sneedgit.nodemixaholic.com/Sneed-Group/sneedium/raw/branch/master/download.png)](https://sneedgit.nodemixaholic.com/Sneed-Group/sneedium/releases)
@ -14,6 +14,8 @@ To clone and run this repository you'll need [Node.js](https://nodejs.org/en/dow
npm install
# Run the app
npm start
# Run in development mode (with dev tools)
npm run dev
```
Supports compiling via electron packager. Install and run it with:
@ -32,6 +34,17 @@ A basic Electron application needs just these files:
- `index.html` - A web page to render. This is the app's **renderer process**.
- `preload.js` - A content script that runs before the renderer process loads.
## Chrome Extension Support
Sneedium now supports loading and using Chrome extensions. Extensions are managed through a dedicated Extension Manager interface:
1. Click the extension button (🧩) in the browser toolbar to open the extension manager
2. Install extensions by clicking the "Install Extension" button and selecting a .crx file
3. Extensions are stored in the `SneedExtensions` folder in your home directory
4. You can also manually install extensions by unpacking them into subdirectories of the `SneedExtensions` folder
Note: Not all Chrome extensions may work perfectly due to API differences between Chrome and Electron. Features like sync and Chrome Web Store integration are not supported.
## License
[SPL-R5](https://github.com/Sneed-Group/sneedium/blob/master/LICENSE.md)

112
crx-extractor.js Normal file
View file

@ -0,0 +1,112 @@
/**
* CRX Extractor - Utility for handling Chrome extension files
* This module provides functions to extract and install Chrome extensions from CRX files
*/
const fs = require('fs');
const path = require('path');
const AdmZip = require('adm-zip');
/**
* Extracts a CRX file to the specified directory
*
* @param {string} crxFilePath - Path to the CRX file
* @param {string} outputDir - Directory to extract the CRX file to
* @returns {Promise<Object>} Result of the extraction
*/
async function extractCrxFile(crxFilePath, outputDir) {
return new Promise((resolve, reject) => {
try {
// Read the CRX file
const crxData = fs.readFileSync(crxFilePath);
// Check CRX header (Chrome extensions start with "Cr24")
if (crxData.slice(0, 4).toString() !== 'Cr24') {
return reject(new Error('Invalid CRX file format'));
}
// CRX format:
// [0-3] "Cr24" (Chrome extension signature)
// [4-7] Version number (uint32)
// [8-11] Public key length (uint32)
// [12-15] Signature length (uint32)
// Extract header information
const publicKeyLength = crxData.readUInt32LE(8);
const signatureLength = crxData.readUInt32LE(12);
// ZIP data starts after the header, public key, and signature
const zipStartOffset = 16 + publicKeyLength + signatureLength;
// Extract the ZIP portion of the CRX file
const zipData = crxData.slice(zipStartOffset);
// Write the ZIP data to a temporary file
const tempZipPath = path.join(require('os').tmpdir(), `${path.basename(crxFilePath, '.crx')}.zip`);
fs.writeFileSync(tempZipPath, zipData);
// Extract the ZIP file using AdmZip
const zip = new AdmZip(tempZipPath);
zip.extractAllTo(outputDir, true);
// Clean up the temporary ZIP file
fs.unlinkSync(tempZipPath);
// Check if manifest.json exists in the extracted files
const manifestPath = path.join(outputDir, 'manifest.json');
if (!fs.existsSync(manifestPath)) {
return reject(new Error('No manifest.json found in the extension'));
}
// Read the manifest.json file to get extension information
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
resolve({
success: true,
manifest,
extensionId: manifest.name ? manifest.name.replace(/[^a-zA-Z0-9]/g, '').toLowerCase() : null
});
} catch (error) {
reject(error);
}
});
}
/**
* Installs a Chrome extension from a CRX file
*
* @param {string} crxFilePath - Path to the CRX file
* @param {string} extensionsDir - Directory where extensions are stored
* @returns {Promise<Object>} Result of the installation
*/
async function installCrxExtension(crxFilePath, extensionsDir) {
try {
const extensionId = path.basename(crxFilePath, '.crx');
const extractPath = path.join(extensionsDir, extensionId);
// Create directory if it doesn't exist
if (!fs.existsSync(extractPath)) {
fs.mkdirSync(extractPath, { recursive: true });
}
// Extract the CRX file
const extractResult = await extractCrxFile(crxFilePath, extractPath);
return {
success: true,
message: 'Extension installed successfully',
extensionId,
manifest: extractResult.manifest
};
} catch (error) {
return {
success: false,
message: `Failed to install extension: ${error.message}`
};
}
}
module.exports = {
extractCrxFile,
installCrxExtension
};

17
extensions-preload.js Normal file
View file

@ -0,0 +1,17 @@
// Preload script for the extensions management page
const { contextBridge, ipcRenderer } = require('electron');
// Expose extension management functions to the renderer process
contextBridge.exposeInMainWorld('extensionsAPI', {
// Get list of installed extensions
getExtensions: () => ipcRenderer.invoke('get-extensions-list'),
// Install a new extension (from CRX file)
installExtension: (crxPath) => ipcRenderer.invoke('install-extension', crxPath),
// Remove an extension
removeExtension: (extensionId) => ipcRenderer.invoke('remove-extension', extensionId),
// Open file dialog to select CRX file
openFileDialog: () => ipcRenderer.invoke('install-extension')
});

164
extensions.html Normal file
View file

@ -0,0 +1,164 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Extension Manager</title>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<link rel="stylesheet" href="styles.css">
<style>
.extension-container {
display: flex;
flex-direction: column;
padding: 10px;
}
.extension-card {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
margin-bottom: 10px;
background-color: #f9f9f9;
}
.extension-info {
flex: 1;
}
.extension-actions {
display: flex;
gap: 10px;
}
.extension-card h3 {
margin-top: 0;
margin-bottom: 5px;
}
.extension-card p {
margin-top: 5px;
margin-bottom: 0;
color: #666;
}
.version {
color: #999;
font-size: 0.8em;
}
.button {
padding: 5px 10px;
border-radius: 4px;
border: none;
cursor: pointer;
font-weight: bold;
}
.install-btn {
background-color: #4CAF50;
color: white;
}
.remove-btn {
background-color: #f44336;
color: white;
}
.no-extensions {
text-align: center;
color: #666;
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid #ddd;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="header">
<h1>Extension Manager</h1>
<button id="install-extension" class="button install-btn">Install Extension</button>
</div>
<div class="extension-container" id="extensions-list">
<div class="no-extensions">No extensions installed</div>
</div>
<script>
// Get extensions list
async function loadExtensions() {
try {
const extensions = await window.extensionsAPI.getExtensions();
const extensionsList = document.getElementById('extensions-list');
// Clear current list
extensionsList.innerHTML = '';
if (extensions.length === 0) {
extensionsList.innerHTML = '<div class="no-extensions">No extensions installed</div>';
return;
}
// Populate list with extension cards
extensions.forEach(extension => {
const card = document.createElement('div');
card.className = 'extension-card';
card.innerHTML = `
<div class="extension-info">
<h3>${extension.name || 'Unknown Extension'}</h3>
<p class="version">Version: ${extension.version || 'unknown'}</p>
<p>${extension.description || 'No description available'}</p>
</div>
<div class="extension-actions">
<button class="button remove-btn" data-id="${extension.id}">Remove</button>
</div>
`;
extensionsList.appendChild(card);
});
// Add event listeners to remove buttons
document.querySelectorAll('.remove-btn').forEach(button => {
button.addEventListener('click', async (e) => {
const extensionId = e.target.getAttribute('data-id');
const result = await window.extensionsAPI.removeExtension(extensionId);
if (result.success) {
loadExtensions(); // Refresh list
} else {
alert('Failed to remove extension: ' + (result.message || 'Unknown error'));
}
});
});
} catch (error) {
console.error('Error loading extensions:', error);
alert('Failed to load extensions: ' + error.message);
}
}
// Install button click handler
document.getElementById('install-extension').addEventListener('click', async () => {
try {
const result = await window.extensionsAPI.openFileDialog();
if (result.success) {
loadExtensions(); // Refresh list
} else if (result.message) {
alert(result.message);
}
} catch (error) {
console.error('Error installing extension:', error);
alert('Failed to install extension: ' + error.message);
}
});
// Load extensions when page loads
document.addEventListener('DOMContentLoaded', loadExtensions);
</script>
</body>
</html>

View file

@ -17,6 +17,7 @@
<button onclick="back(); return false;" id="backBtn">⬅️</button>
<button onclick="forward(); return false;" id="forwardBtn">➡️</button>
<button id="camBtn">🎦</button>
<button id="extBtn" title="Manage Extensions">🧩</button>
</div>
<div id="whProtection">
<tab-group new-tab-button="true" sortable="true">

240
main.js
View file

@ -1,5 +1,5 @@
// Modules to control application life and create native browser window
const {app, BrowserWindow, session, ipcMain, systemPreferences} = require('electron')
const {app, BrowserWindow, session, ipcMain, systemPreferences, dialog} = require('electron')
const path = require('path')
const fetch = require("cross-fetch")
const { ElectronChromeExtensions } = require('electron-chrome-extensions')
@ -8,9 +8,107 @@ const http = require('http');
const fs = require('fs');
const { createProxy } = require('proxy');
const buildChromeContextMenu = require('electron-chrome-context-menu').default
const { installCrxExtension } = require('./crx-extractor');
var extensions
var mic
var cam
// Define extension directory path
const homePath = app.getPath('home');
const extensionsDir = path.join(homePath, 'SneedExtensions');
// Ensure extensions directory exists
if (!fs.existsSync(extensionsDir)) {
fs.mkdirSync(extensionsDir, { recursive: true });
}
// IPC handlers for extension management
ipcMain.handle('get-extensions-list', async () => {
try {
const extensionFolders = fs.readdirSync(extensionsDir, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => {
const extPath = path.join(extensionsDir, dirent.name);
let manifest = {};
try {
const manifestPath = path.join(extPath, 'manifest.json');
if (fs.existsSync(manifestPath)) {
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
}
} catch (e) {
console.error(`Error reading manifest for extension ${dirent.name}:`, e);
}
return {
id: dirent.name,
name: manifest.name || dirent.name,
version: manifest.version || 'unknown',
description: manifest.description || '',
path: extPath
};
});
return extensionFolders;
} catch (error) {
console.error('Error getting extensions list:', error);
return [];
}
});
ipcMain.handle('install-extension', async (event, crxPath) => {
try {
// If no path provided, open dialog to select CRX file
if (!crxPath) {
const result = await dialog.showOpenDialog({
properties: ['openFile'],
filters: [{ name: 'Chrome Extension', extensions: ['crx'] }]
});
if (result.canceled || result.filePaths.length === 0) {
return { success: false, message: 'No file selected' };
}
crxPath = result.filePaths[0];
}
// Use the CRX extractor to install the extension
const installResult = await installCrxExtension(crxPath, extensionsDir);
// If installation was successful, reload the extension
if (installResult.success && extensions) {
try {
const loadResult = extensions.loadExtension(path.join(extensionsDir, installResult.extensionId));
console.log(`Loaded extension ${installResult.extensionId}:`, loadResult);
} catch (loadError) {
console.error(`Error loading extension ${installResult.extensionId}:`, loadError);
}
}
return installResult;
} catch (error) {
console.error('Error installing extension:', error);
return { success: false, message: error.message };
}
});
ipcMain.handle('remove-extension', async (event, extensionId) => {
try {
const extensionPath = path.join(extensionsDir, extensionId);
if (fs.existsSync(extensionPath)) {
fs.rmSync(extensionPath, { recursive: true, force: true });
return { success: true };
} else {
return { success: false, message: 'Extension not found' };
}
} catch (error) {
console.error('Error removing extension:', error);
return { success: false, message: error.message };
}
});
// Handle opening extension management page
ipcMain.on('open-extensions-page', (event) => {
createExtensionsWindow();
});
app.on('web-contents-created', (event, webContents) => {
webContents.on('context-menu', (e, params) => {
const menu = buildChromeContextMenu({
@ -25,7 +123,24 @@ app.on('web-contents-created', (event, webContents) => {
})
})
// Create an extensions management window
function createExtensionsWindow() {
const extensionsWindow = new BrowserWindow({
width: 800,
height: 600,
title: 'Extension Manager',
webPreferences: {
preload: path.join(__dirname, 'extensions-preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
extensionsWindow.loadFile('extensions.html');
extensionsWindow.setMenuBarVisibility(false);
}
// Original IPC handlers
ipcMain.on('windowmaker', (event, arg) => {
createWindow();
})
@ -40,23 +155,34 @@ proxy.listen(3129)
//Function to enable AD Blocking...
let blocker = undefined
async function enableGoodies(s) {
blocker = await ElectronBlocker.fromLists(fetch, [
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/ubol-filters.txt",
'https://easylist.to/easylist/easylist.txt',
'https://secure.fanboy.co.nz/fanboy-annoyance.txt',
'https://easylist.to/easylist/easyprivacy.txt',
'https://easylist-downloads.adblockplus.org/antiadblockfilters.txt',
'https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/nocoin.txt',
'https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/pro.plus.txt',
"https://github.com/yokoffing/filterlists/raw/refs/heads/main/youtube_clear_view.txt",
"https://pgl.yoyo.org/as/serverlist.php?showintro=0;hostformat=adblock",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/unbreak.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/quick-fixes.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/privacy.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/badware.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/filters.txt"
])
blocker.enableBlockingInSession(s);
try {
if (!s) {
console.log("No session provided to enableGoodies, using default session");
s = session.defaultSession;
}
blocker = await ElectronBlocker.fromLists(fetch, [
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/ubol-filters.txt",
'https://easylist.to/easylist/easylist.txt',
'https://secure.fanboy.co.nz/fanboy-annoyance.txt',
'https://easylist.to/easylist/easyprivacy.txt',
'https://easylist-downloads.adblockplus.org/antiadblockfilters.txt',
'https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/nocoin.txt',
'https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/pro.plus.txt',
"https://github.com/yokoffing/filterlists/raw/refs/heads/main/youtube_clear_view.txt",
"https://pgl.yoyo.org/as/serverlist.php?showintro=0;hostformat=adblock",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/unbreak.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/quick-fixes.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/privacy.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/badware.txt",
"https://github.com/uBlockOrigin/uAssets/raw/refs/heads/master/filters/filters.txt"
]);
blocker.enableBlockingInSession(s);
console.log("AD blocking enabled successfully");
} catch (error) {
console.error("Error enabling AD blocking:", error);
}
}
// 0.0.0.0 day fix
@ -71,10 +197,19 @@ function isLocal(url) {
function createWindow () {
try {
extensions = new ElectronChromeExtensions()
} catch {
console.log("Creating a new window in the same extension session...")
// Initialize extensions once if not already initialized
if (!extensions) {
extensions = new ElectronChromeExtensions({
// Specify extension session
session: session.defaultSession,
// Set to true to enable background pages for extensions
createBackgroundPages: true
});
}
} catch (error) {
console.error("Error initializing extensions:", error);
}
const mainWindow = new BrowserWindow({
width: 1220,
height: 600,
@ -83,29 +218,27 @@ function createWindow () {
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
webviewTag: true,
devTools: false,
// Enable devTools for development
devTools: process.env.NODE_ENV === 'development',
nodeIntegration: false,
sandbox: true,
contextIsolation: true
contextIsolation: true,
// Enable Chrome extension support
additionalArguments: ['--enable-features=ExtensionsToolbarMenu'],
// Allow access to chrome:// URLs for extensions
allowRunningInsecureContent: false,
webSecurity: true
}
})
const homePath = app.getPath('home');
const extensionsDir = path.join(homePath, 'SneedExtensions');
// Load installed extensions
loadExtensions(extensions);
if (!fs.existsSync(extensionsDir)) {
fs.mkdirSync(extensionsDir, { recursive: true });
// Register window with extensions system
if (extensions) {
extensions.addTab(mainWindow.webContents, mainWindow);
}
const extensionFolders = fs.readdirSync(extensionsDir, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => path.join(extensionsDir, dirent.name));
for (const extensionPath of extensionFolders) {
extensions.loadExtension(extensionPath);
}
extensions.addTab(mainWindow.webContents, mainWindow)
mainWindow.setMinimumSize(1000, 300)
@ -211,12 +344,45 @@ const regexPatterns = [
return mainWindow;
}
// Function to load all extensions from the extensions directory
function loadExtensions(extensionsInstance) {
if (!extensionsInstance) return;
try {
// Get list of extension directories
const extensionFolders = fs.readdirSync(extensionsDir, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => path.join(extensionsDir, dirent.name));
// Load each extension
for (const extensionPath of extensionFolders) {
try {
if (fs.existsSync(path.join(extensionPath, 'manifest.json'))) {
const loadResult = extensionsInstance.loadExtension(extensionPath);
console.log(`Loaded extension from ${extensionPath}`, loadResult);
} else {
console.warn(`Missing manifest.json in extension directory: ${extensionPath}`);
}
} catch (extError) {
console.error(`Failed to load extension at ${extensionPath}:`, extError);
}
}
} catch (error) {
console.error('Error loading extensions:', error);
}
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
let x = createWindow()
enableGoodies().then()
enableGoodies(session.defaultSession).then(() => {
console.log("Goodies enabled");
}).catch(error => {
console.error("Error enabling goodies:", error);
});
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.

30
package-lock.json generated
View file

@ -11,6 +11,7 @@
"dependencies": {
"@ghostery/adblocker": "^2.1.1",
"@ghostery/adblocker-electron": "^2.1.1",
"adm-zip": "^0.5.16",
"cross-fetch": "^3.1.5",
"electron-chrome-context-menu": "^1.1.0",
"electron-chrome-extensions": "^3.10.0",
@ -25,6 +26,7 @@
"@electron-forge/maker-rpm": "^6.0.5",
"@electron-forge/maker-squirrel": "^6.0.5",
"@electron-forge/maker-zip": "^6.0.5",
"cross-env": "^7.0.3",
"electron": "^31.0.1",
"electron-forge-maker-appimage": "^24.6.3",
"electron-packager": "^17.1.2"
@ -1350,6 +1352,15 @@
"dev": true,
"license": "ISC"
},
"node_modules/adm-zip": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
"integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
"license": "MIT",
"engines": {
"node": ">=12.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@ -2481,6 +2492,25 @@
"license": "MIT",
"optional": true
},
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.1"
},
"bin": {
"cross-env": "src/bin/cross-env.js",
"cross-env-shell": "src/bin/cross-env-shell.js"
},
"engines": {
"node": ">=10.14",
"npm": ">=6",
"yarn": ">=1"
}
},
"node_modules/cross-fetch": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",

View file

@ -1,13 +1,14 @@
{
"name": "sneedium",
"version": "1.0.0",
"description": "A Electron browser",
"description": "A Electron browser with Chrome extension support",
"main": "main.js",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "npx electron-packager --platform linux,win32 --arch x64,arm64 .",
"make-mac": "npx electron-packager --platform darwin --arch x64,arm64 ."
"make-mac": "npx electron-packager --platform darwin --arch x64,arm64 .",
"dev": "cross-env NODE_ENV=development electron ."
},
"repository": "https://github.com/Sneed-Group/sneedium",
"keywords": [
@ -15,7 +16,9 @@
"quick",
"start",
"tutorial",
"demo"
"demo",
"browser",
"extension"
],
"author": "Sneed Group",
"license": "SPL-R5",
@ -26,6 +29,7 @@
"@electron-forge/maker-rpm": "^6.0.5",
"@electron-forge/maker-squirrel": "^6.0.5",
"@electron-forge/maker-zip": "^6.0.5",
"cross-env": "^7.0.3",
"electron": "^31.0.1",
"electron-forge-maker-appimage": "^24.6.3",
"electron-packager": "^17.1.2"
@ -33,6 +37,7 @@
"dependencies": {
"@ghostery/adblocker": "^2.1.1",
"@ghostery/adblocker-electron": "^2.1.1",
"adm-zip": "^0.5.16",
"cross-fetch": "^3.1.5",
"electron-chrome-context-menu": "^1.1.0",
"electron-chrome-extensions": "^3.10.0",

View file

@ -10,6 +10,11 @@ const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
enforceDomainRestrictions: (url) => ipcRenderer.sendSync('check-domain', url),
// Add extension management functionality
extensions: {
openExtensionsPage: () => ipcRenderer.send('open-extensions-page'),
getExtensionsList: () => ipcRenderer.invoke('get-extensions-list')
}
});
@ -32,12 +37,24 @@ window.addEventListener('DOMContentLoaded', () => {
})
//button and its event listener
const makeWindowButton = document.getElementById('nwBtn');
makeWindowButton.addEventListener('click', () => {
if (makeWindowButton) {
makeWindowButton.addEventListener('click', () => {
ipcRenderer.send('windowmaker', 'ping')
})
});
}
const camButton = document.getElementById('camBtn');
camButton.addEventListener('click', () => {
ipcRenderer.send('allowCam', 'ping')
})
if (camButton) {
camButton.addEventListener('click', () => {
ipcRenderer.send('allowCam', 'ping')
});
}
// Add extension management button event listener
const extensionsButton = document.getElementById('extBtn');
if (extensionsButton) {
extensionsButton.addEventListener('click', () => {
ipcRenderer.send('open-extensions-page');
});
}
})