Skip to content

Commit

Permalink
move all checks to NodeExecuteFunctions
Browse files Browse the repository at this point in the history
  • Loading branch information
netroy committed Jul 4, 2023
1 parent 00a2246 commit 351670f
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 15 deletions.
31 changes: 29 additions & 2 deletions packages/core/src/NodeExecuteFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ import type {
import axios from 'axios';
import url, { URL, URLSearchParams } from 'url';
import { Readable } from 'stream';
import { access as fsAccess } from 'fs/promises';
import { access as fsAccess, writeFile as fsWriteFile } from 'fs/promises';
import { createReadStream } from 'fs';

import { BinaryDataManager } from './BinaryDataManager';
Expand All @@ -129,6 +129,7 @@ import {
setAllWorkflowExecutionMetadata,
setWorkflowExecutionMetadata,
} from './WorkflowExecutionMetadata';
import { getUserN8nFolderPath } from './UserSettings';

axios.defaults.timeout = 300000;
// Prevent axios from adding x-form-www-urlencoded headers by default
Expand Down Expand Up @@ -2251,19 +2252,45 @@ const getRequestHelperFunctions = (
},
});

const restrictedPaths = (process.env.RESTRICT_FILE_ACCESS_TO ?? '')
.split(';')
.map((path) => path.trim())
.filter((path) => path)
.concat(getUserN8nFolderPath());
// TODO: add other folders here

const isFilePathBlocked = (filePath: string) => {
const absolutePath = path.resolve(filePath);
return restrictedPaths.some((dir) => !path.relative(dir, absolutePath).includes('..'));
};

const getFileSystemHelperFunctions = (node: INode): FileSystemHelperFunctions => ({
async createReadStream(filePath) {
try {
await fsAccess(filePath);
} catch (error) {
throw error.code === 'ENOENT'
? new NodeOperationError(node, error, {
message: `The file "${String(filePath)}" could not be accessed.`,
message: `The file "${filePath}" could not be accessed.`,
severity: 'warning',
})
: error;
}
if (isFilePathBlocked(filePath)) {
throw new NodeOperationError(node, `The file "${String(filePath)}" could not be accessed.`, {
severity: 'warning',
});
}
return createReadStream(filePath);
},
async writeContentToFile(filePath, content, flag) {
if (isFilePathBlocked(filePath)) {
throw new NodeOperationError(node, `The file "${String(filePath)}" is not writable.`, {
severity: 'warning',
});
}
return fsWriteFile(filePath, content, { encoding: 'binary', flag });
},
});

const getNodeHelperFunctions = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type {
INodeTypeDescription,
} from 'n8n-workflow';

import { checkFilePathAccess } from '@utils/utilities';
import { allowedPathsNotice } from '@utils/descriptions';

export class ReadBinaryFile implements INodeType {
Expand Down Expand Up @@ -71,8 +70,6 @@ export class ReadBinaryFile implements INodeType {
}

const filePath = this.getNodeParameter('filePath', itemIndex);
checkFilePathAccess(filePath);

const stream = await this.helpers.createReadStream(filePath);
const dataPropertyName = this.getNodeParameter('dataPropertyName', itemIndex);
newItem.binary![dataPropertyName] = await this.helpers.prepareBinaryData(stream, filePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {

import glob from 'fast-glob';

import { checkFilePathAccess } from '@utils/utilities';
import { allowedPathsNotice } from '@utils/descriptions';

export class ReadBinaryFiles implements INodeType {
Expand Down Expand Up @@ -62,8 +61,6 @@ export class ReadBinaryFiles implements INodeType {

const items: INodeExecutionData[] = [];
for (const filePath of files) {
checkFilePathAccess(filePath);

const stream = await this.helpers.createReadStream(filePath);
items.push({
binary: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ import type {
} from 'n8n-workflow';
import { BINARY_ENCODING } from 'n8n-workflow';

import { writeFile as fsWriteFile } from 'fs/promises';
import type { Readable } from 'stream';

import { checkFilePathAccess } from '@utils/utilities';
import { allowedPathsNotice } from '@utils/descriptions';

export class WriteBinaryFile implements INodeType {
Expand Down Expand Up @@ -77,8 +75,6 @@ export class WriteBinaryFile implements INodeType {
const dataPropertyName = this.getNodeParameter('dataPropertyName', itemIndex);

const fileName = this.getNodeParameter('fileName', itemIndex) as string;
checkFilePathAccess(fileName);

const options = this.getNodeParameter('options', 0, {});

const flag = options.append ? 'a' : 'w';
Expand All @@ -103,7 +99,7 @@ export class WriteBinaryFile implements INodeType {
}

// Write the file to disk
await fsWriteFile(fileName, fileContent, { encoding: 'binary', flag });
await this.helpers.writeContentToFile(fileName, fileContent, flag);

if (item.binary !== undefined) {
// Create a shallow copy of the binary data so that the old
Expand Down
4 changes: 2 additions & 2 deletions packages/workflow/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type { Readable } from 'stream';
import type { URLSearchParams } from 'url';
import type { OptionsWithUri, OptionsWithUrl } from 'request';
import type { RequestPromiseOptions, RequestPromiseAPI } from 'request-promise-native';
import type { PathLike } from 'fs';

import type { CODE_EXECUTION_MODES, CODE_LANGUAGES } from './Constants';
import type { IDeferredPromise } from './DeferredPromise';
Expand Down Expand Up @@ -670,7 +669,8 @@ interface JsonHelperFunctions {
}

export interface FileSystemHelperFunctions {
createReadStream(path: PathLike): Promise<Readable>;
createReadStream(path: string): Promise<Readable>;
writeContentToFile(path: string, content: Buffer | Readable, flag: 'a' | 'w'): Promise<void>;
}

export interface BinaryHelperFunctions {
Expand Down

0 comments on commit 351670f

Please sign in to comment.