Added validator to check if a given path is inside an open Collection (#4800)

* Refactor: Renamed `Watcher` class and instance to `CollectionWatcher`

The name `Watcher` sounds very generic, but in this case its tightly
coupled with watching Bruno Collection paths. So it makes sense to name
it accordingly.

* Added validator to check if a given path is inside an open Collection

And added an sample validation for _new-request_ IPC event.

* Review fixes
This commit is contained in:
ramki-bruno
2025-07-08 15:28:01 +05:30
committed by GitHub
parent 63a8201290
commit 215256b2fe
3 changed files with 27 additions and 9 deletions

View File

@@ -511,7 +511,7 @@ const onWatcherSetupComplete = (win, watchPath) => {
win.webContents.send('main:hydrate-app-with-ui-state-snapshot', collectionSnapshotState);
};
class Watcher {
class CollectionWatcher {
constructor() {
this.watchers = {};
}
@@ -615,6 +615,14 @@ class Watcher {
watcher?.add?.(itemPath);
}
}
getAllWatcherPaths() {
return Object.entries(this.watchers)
.filter(([path, watcher]) => !!watcher)
.map(([path, _watcher]) => path);
}
}
module.exports = Watcher;
const collectionWatcher = new CollectionWatcher();
module.exports = collectionWatcher;

View File

@@ -27,7 +27,7 @@ const LastOpenedCollections = require('./store/last-opened-collections');
const registerNetworkIpc = require('./ipc/network');
const registerCollectionsIpc = require('./ipc/collection');
const registerPreferencesIpc = require('./ipc/preferences');
const Watcher = require('./app/watcher');
const collectionWatcher = require('./app/collection-watcher');
const { loadWindowState, saveBounds, saveMaximized } = require('./utils/window');
const registerNotificationsIpc = require('./ipc/notifications');
const registerGlobalEnvironmentsIpc = require('./ipc/global-environments');
@@ -55,7 +55,6 @@ setContentSecurityPolicy(contentSecurityPolicy.join(';') + ';');
const menu = Menu.buildFromTemplate(menuTemplate);
let mainWindow;
let watcher;
// Prepare the renderer once the app is ready
app.on('ready', async () => {
@@ -131,7 +130,6 @@ app.on('ready', async () => {
);
}
});
watcher = new Watcher();
const handleBoundsChange = () => {
if (!mainWindow.isMaximized()) {
@@ -181,9 +179,9 @@ app.on('ready', async () => {
// register all ipc handlers
registerNetworkIpc(mainWindow);
registerGlobalEnvironmentsIpc(mainWindow);
registerCollectionsIpc(mainWindow, watcher, lastOpenedCollections);
registerPreferencesIpc(mainWindow, watcher, lastOpenedCollections);
registerNotificationsIpc(mainWindow, watcher);
registerCollectionsIpc(mainWindow, collectionWatcher, lastOpenedCollections);
registerPreferencesIpc(mainWindow, collectionWatcher, lastOpenedCollections);
registerNotificationsIpc(mainWindow, collectionWatcher);
});
// Quit the app once all windows are closed
@@ -191,5 +189,5 @@ app.on('window-all-closed', app.quit);
// Open collection from Recent menu (#1521)
app.on('open-file', (event, path) => {
openCollection(mainWindow, watcher, path);
openCollection(mainWindow, collectionWatcher, path);
});

View File

@@ -42,6 +42,7 @@ const { getEnvVars, getTreePathFromCollectionToItem, mergeVars, parseBruFileMeta
const { getProcessEnvVars } = require('../store/process-env');
const { getOAuth2TokenUsingAuthorizationCode, getOAuth2TokenUsingClientCredentials, getOAuth2TokenUsingPasswordCredentials, refreshOauth2Token } = require('../utils/oauth2');
const { getCertsAndProxyConfig } = require('./network');
const collectionWatcher = require('../app/collection-watcher');
const environmentSecretsStore = new EnvironmentSecretsStore();
const collectionSecurityStore = new CollectionSecurityStore();
@@ -58,6 +59,16 @@ const envHasSecrets = (environment = {}) => {
return secrets && secrets.length > 0;
};
const validatePathIsInsideCollection = (path) => {
const openCollectionPaths = collectionWatcher.getAllWatcherPaths();
const isValid = openCollectionPaths.some((collectionPath) => {
return path.startsWith(collectionPath);
});
if (!isValid) {
throw new Error(`Path: ${path} should be inside a collection`);
}
}
const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollections) => {
// browse directory
ipcMain.handle('renderer:browse-directory', async (event, pathname, request) => {
@@ -237,6 +248,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
if (!validateName(request?.filename)) {
throw new Error(`${request.filename}.bru is not a valid filename`);
}
validatePathIsInsideCollection(pathname);
const content = await jsonToBruViaWorker(request);
await writeFile(pathname, content);
} catch (error) {