mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
fix: Fix issue with restricted file access order (#17329)
This commit is contained in:
@@ -119,6 +119,36 @@ describe('isFilePathBlocked', () => {
|
||||
expect(isFilePathBlocked(invitePath)).toBe(true);
|
||||
expect(isFilePathBlocked(pwResetPath)).toBe(true);
|
||||
});
|
||||
|
||||
it('should block access to n8n files if restrict and block are set', () => {
|
||||
const homeVarName = process.platform === 'win32' ? 'USERPROFILE' : 'HOME';
|
||||
const userHome = process.env.N8N_USER_FOLDER ?? process.env[homeVarName] ?? process.cwd();
|
||||
|
||||
process.env[RESTRICT_FILE_ACCESS_TO] = userHome;
|
||||
process.env[BLOCK_FILE_ACCESS_TO_N8N_FILES] = 'true';
|
||||
const restrictedPath = instanceSettings.n8nFolder;
|
||||
expect(isFilePathBlocked(restrictedPath)).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow access to parent folder if restrict and block are set', () => {
|
||||
const homeVarName = process.platform === 'win32' ? 'USERPROFILE' : 'HOME';
|
||||
const userHome = process.env.N8N_USER_FOLDER ?? process.env[homeVarName] ?? process.cwd();
|
||||
|
||||
process.env[RESTRICT_FILE_ACCESS_TO] = userHome;
|
||||
process.env[BLOCK_FILE_ACCESS_TO_N8N_FILES] = 'true';
|
||||
const restrictedPath = join(userHome, 'somefile.txt');
|
||||
expect(isFilePathBlocked(restrictedPath)).toBe(false);
|
||||
});
|
||||
|
||||
it('should not block similar paths', () => {
|
||||
const homeVarName = process.platform === 'win32' ? 'USERPROFILE' : 'HOME';
|
||||
const userHome = process.env.N8N_USER_FOLDER ?? process.env[homeVarName] ?? process.cwd();
|
||||
|
||||
process.env[RESTRICT_FILE_ACCESS_TO] = userHome;
|
||||
process.env[BLOCK_FILE_ACCESS_TO_N8N_FILES] = 'true';
|
||||
const restrictedPath = join(userHome, '.n8n_x');
|
||||
expect(isFilePathBlocked(restrictedPath)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFileSystemHelperFunctions', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { safeJoinPath } from '@n8n/backend-common';
|
||||
import { isContainedWithin, safeJoinPath } from '@n8n/backend-common';
|
||||
import { Container } from '@n8n/di';
|
||||
import type { FileSystemHelperFunctions, INode } from 'n8n-workflow';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
@@ -34,52 +34,17 @@ export function isFilePathBlocked(filePath: string): boolean {
|
||||
const resolvedFilePath = resolve(filePath);
|
||||
const blockFileAccessToN8nFiles = process.env[BLOCK_FILE_ACCESS_TO_N8N_FILES] !== 'false';
|
||||
|
||||
//if allowed paths are defined, allow access only to those paths
|
||||
const restrictedPaths = blockFileAccessToN8nFiles ? getN8nRestrictedPaths() : [];
|
||||
if (
|
||||
restrictedPaths.some((restrictedPath) => isContainedWithin(restrictedPath, resolvedFilePath))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (allowedPaths.length) {
|
||||
for (const path of allowedPaths) {
|
||||
if (resolvedFilePath.startsWith(path)) {
|
||||
return false;
|
||||
}
|
||||
return !allowedPaths.some((allowedPath) => isContainedWithin(allowedPath, resolvedFilePath));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//restrict access to .n8n folder, ~/.cache/n8n/public, and other .env config related paths
|
||||
if (blockFileAccessToN8nFiles) {
|
||||
const { n8nFolder, staticCacheDir } = Container.get(InstanceSettings);
|
||||
const restrictedPaths = [n8nFolder, staticCacheDir];
|
||||
|
||||
if (process.env[CONFIG_FILES]) {
|
||||
restrictedPaths.push(...process.env[CONFIG_FILES].split(','));
|
||||
}
|
||||
|
||||
if (process.env[CUSTOM_EXTENSION_ENV]) {
|
||||
const customExtensionFolders = process.env[CUSTOM_EXTENSION_ENV].split(';');
|
||||
restrictedPaths.push(...customExtensionFolders);
|
||||
}
|
||||
|
||||
if (process.env[BINARY_DATA_STORAGE_PATH]) {
|
||||
restrictedPaths.push(process.env[BINARY_DATA_STORAGE_PATH]);
|
||||
}
|
||||
|
||||
if (process.env[UM_EMAIL_TEMPLATES_INVITE]) {
|
||||
restrictedPaths.push(process.env[UM_EMAIL_TEMPLATES_INVITE]);
|
||||
}
|
||||
|
||||
if (process.env[UM_EMAIL_TEMPLATES_PWRESET]) {
|
||||
restrictedPaths.push(process.env[UM_EMAIL_TEMPLATES_PWRESET]);
|
||||
}
|
||||
|
||||
//check if the file path is restricted
|
||||
for (const path of restrictedPaths) {
|
||||
if (resolvedFilePath.startsWith(path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//path is not restricted
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,3 +85,34 @@ export const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunct
|
||||
return await fsWriteFile(filePath, content, { encoding: 'binary', flag });
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns The restricted paths for the n8n instance.
|
||||
*/
|
||||
function getN8nRestrictedPaths() {
|
||||
const { n8nFolder, staticCacheDir } = Container.get(InstanceSettings);
|
||||
const restrictedPaths = [n8nFolder, staticCacheDir];
|
||||
|
||||
if (process.env[CONFIG_FILES]) {
|
||||
restrictedPaths.push(...process.env[CONFIG_FILES].split(','));
|
||||
}
|
||||
|
||||
if (process.env[CUSTOM_EXTENSION_ENV]) {
|
||||
const customExtensionFolders = process.env[CUSTOM_EXTENSION_ENV].split(';');
|
||||
restrictedPaths.push(...customExtensionFolders);
|
||||
}
|
||||
|
||||
if (process.env[BINARY_DATA_STORAGE_PATH]) {
|
||||
restrictedPaths.push(process.env[BINARY_DATA_STORAGE_PATH]);
|
||||
}
|
||||
|
||||
if (process.env[UM_EMAIL_TEMPLATES_INVITE]) {
|
||||
restrictedPaths.push(process.env[UM_EMAIL_TEMPLATES_INVITE]);
|
||||
}
|
||||
|
||||
if (process.env[UM_EMAIL_TEMPLATES_PWRESET]) {
|
||||
restrictedPaths.push(process.env[UM_EMAIL_TEMPLATES_PWRESET]);
|
||||
}
|
||||
|
||||
return restrictedPaths;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user