From 843f7815767cba549b8fffd4865979fad08622aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20Sander?= Date: Sun, 7 Aug 2022 22:10:46 +0200 Subject: [PATCH] feat: Warn if UNC paths used with file API calls when Butler runs on non-Windows OS Implements #522 --- src/api/disk_utils.js | 3 +- src/globals.js | 40 +++++++++++++++++++- src/package-lock.json | 33 +++++++++++++++++ src/package.json | 1 + src/routes/disk_utils.js | 79 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) diff --git a/src/api/disk_utils.js b/src/api/disk_utils.js index 53ef00fc..60b1f584 100644 --- a/src/api/disk_utils.js +++ b/src/api/disk_utils.js @@ -71,7 +71,8 @@ const apiFileCopy = { }, }, 403: { - description: 'No approved fromDir/toDir for file copy.', + description: + 'No approved fromDir/toDir for file copy, or UNC path used when Butler is running on non-Windows operating system', type: 'object', properties: { statusCode: { type: 'number' }, diff --git a/src/globals.js b/src/globals.js index 8256b252..63fbb35a 100644 --- a/src/globals.js +++ b/src/globals.js @@ -5,6 +5,7 @@ const { IncomingWebhook } = require('ms-teams-webhook'); const si = require('systeminformation'); const os = require('os'); const crypto = require('crypto'); +const isUncPath = require('is-unc-path'); // Add dependencies const { Command, Option } = require('commander'); @@ -301,6 +302,21 @@ if (config.has('Butler.fileCopyApprovedDirectories') && config.get('Butler.fileC config.get('Butler.fileCopyApprovedDirectories').forEach((element) => { logger.verbose(`fileCopy directories from config file: ${JSON.stringify(element, null, 2)}`); + // Check if Butler is running on Linux-ish host and UNC path(s) are specified + // Warn if so + if (os.platform().toLowerCase() !== 'windows') { + if (isUncPath(element.fromDirectory) === true) { + logger.warn( + `FILE COPY CONFIG: UNC paths won't work on non-Windows OSs ("${element.fromDirectory}"). OS is "${os.platform()}".` + ); + } + if (isUncPath(element.toDirectory) === true) { + logger.warn( + `FILE COPY CONFIG: UNC paths won't work on non-Windows OSs ("${element.toDirectory}"). OS is "${os.platform()}".` + ); + } + } + const newDirCombo = { fromDir: upath.normalizeSafe(element.fromDirectory), toDir: upath.normalizeSafe(element.toDirectory), @@ -319,6 +335,21 @@ if (config.has('Butler.fileMoveApprovedDirectories') && config.get('Butler.fileM config.get('Butler.fileMoveApprovedDirectories').forEach((element) => { logger.verbose(`fileMove directories from config file: ${JSON.stringify(element, null, 2)}`); + // Check if Butler is running on Linux-ish host and UNC path(s) are specified + // Warn if so + if (os.platform().toLowerCase() !== 'windows') { + if (isUncPath(element.fromDirectory) === true) { + logger.warn( + `FILE MOVE CONFIG: UNC paths won't work on non-Windows OSs ("${element.fromDirectory}"). OS is "${os.platform()}".` + ); + } + if (isUncPath(element.toDirectory) === true) { + logger.warn( + `FILE MOVE CONFIG: UNC paths won't work on non-Windows OSs ("${element.toDirectory}"). OS is "${os.platform()}".` + ); + } + } + const newDirCombo = { fromDir: upath.normalizeSafe(element.fromDirectory), toDir: upath.normalizeSafe(element.toDirectory), @@ -337,8 +368,15 @@ if (config.has('Butler.fileDeleteApprovedDirectories') && config.get('Butler.fil config.get('Butler.fileDeleteApprovedDirectories').forEach((element) => { logger.verbose(`fileDelete directory from config file: ${element}`); - const deleteDir = upath.normalizeSafe(element); + // Check if Butler is running on Linux-ish host and UNC path(s) are specified + // Warn if so + if (os.platform().toLowerCase() !== 'windows') { + if (isUncPath(element) === true) { + logger.warn(`FILE DELETE CONFIG: UNC paths won't work on non-Windows OSs ("${element}"). OS is "${os.platform()}".`); + } + } + const deleteDir = upath.normalizeSafe(element); logger.info(`Adding normalized fileDelete directory ${deleteDir}`); fileDeleteDirectories.push(deleteDir); diff --git a/src/package-lock.json b/src/package-lock.json index 364be2da..51c691e3 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -37,6 +37,7 @@ "handlebars": "^4.7.7", "http-errors": "^2.0.0", "influx": "^5.9.3", + "is-unc-path": "^1.0.0", "js-yaml": "^4.1.0", "jshint": "^2.13.4", "lodash": "^4.17.21", @@ -4221,6 +4222,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-weakref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", @@ -6975,6 +6987,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/undici": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz", @@ -10527,6 +10547,14 @@ "has-symbols": "^1.0.2" } }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, "is-weakref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", @@ -12615,6 +12643,11 @@ "which-boxed-primitive": "^1.0.2" } }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==" + }, "undici": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz", diff --git a/src/package.json b/src/package.json index e3f6b153..36a84922 100644 --- a/src/package.json +++ b/src/package.json @@ -31,6 +31,7 @@ "handlebars": "^4.7.7", "http-errors": "^2.0.0", "influx": "^5.9.3", + "is-unc-path": "^1.0.0", "js-yaml": "^4.1.0", "jshint": "^2.13.4", "lodash": "^4.17.21", diff --git a/src/routes/disk_utils.js b/src/routes/disk_utils.js index 1c7a85d0..71994e0b 100644 --- a/src/routes/disk_utils.js +++ b/src/routes/disk_utils.js @@ -2,6 +2,8 @@ const httpErrors = require('http-errors'); const fs = require('fs-extra'); const upath = require('upath'); const mkdirp = require('mkdirp'); +const isUncPath = require('is-unc-path'); +const os = require('os'); // Load global variables and functions const globals = require('../globals'); @@ -33,6 +35,35 @@ async function handlerFileCopy(request, reply) { preserveTimestamp = true; } + // Check if Butler is running on Linux-ish host and UNC path(s) are specified + // Warn if so, then return error + if (os.platform().toLowerCase() !== 'windows') { + if (isUncPath(request.body.fromFile) === true) { + globals.logger.warn( + `FILE COPY FROM: UNC paths not supported work on non-Windows OSs ("${ + request.body.fromFile + }"). OS is "${os.platform()}".` + ); + reply.send( + httpErrors( + 400, + `UNC paths not supported for file copy operations when running Butler on non-Windows OS. Path: ${request.body.fromFile}` + ) + ); + } + if (isUncPath(request.body.toFile) === true) { + globals.logger.warn( + `FILE COPY TO: UNC paths not supported on non-Windows OSs ("${request.body.toFile}"). OS is "${os.platform()}".` + ); + reply.send( + httpErrors( + 400, + `UNC paths not supported for file copy operations when running Butler on non-Windows OS. Path: ${request.body.toFile}` + ) + ); + } + } + // Make sure that // 1. fromFile is in a valid source directory (or subdirectory thereof), // 2. toFile is in a valid associated destination directory (or subdirectory thereof) @@ -115,6 +146,34 @@ async function handlerFileMove(request, reply) { if (request.body.overwrite === 'true' || request.body.overwrite === true) { overwrite = true; } + // Check if Butler is running on Linux-ish host and UNC path(s) are specified + // Warn if so, then return error + if (os.platform().toLowerCase() !== 'windows') { + if (isUncPath(request.body.fromFile) === true) { + globals.logger.warn( + `FILE MOVE FROM: UNC paths not supported work on non-Windows OSs ("${ + request.body.fromFile + }"). OS is "${os.platform()}".` + ); + reply.send( + httpErrors( + 400, + `UNC paths not supported for file move operations when running Butler on non-Windows OS. Path: ${request.body.fromFile}` + ) + ); + } + if (isUncPath(request.body.toFile) === true) { + globals.logger.warn( + `FILE MOVE TO: UNC paths not supported on non-Windows OSs ("${request.body.toFile}"). OS is "${os.platform()}".` + ); + reply.send( + httpErrors( + 400, + `UNC paths not supported for file move operations when running Butler on non-Windows OS. Path: ${request.body.toFile}` + ) + ); + } + } // Make sure that // 1. fromFile is in a valid source directory (or subdirectory thereof), @@ -172,6 +231,26 @@ async function handlerFileDelete(request, reply) { // Required parameter is missing reply.send(httpErrors(400, 'Required parameter missing')); } else { + // Check if Butler is running on Linux-ish host and UNC path(s) are specified + // Warn if so, then return error + if (os.platform().toLowerCase() !== 'windows') { + if (isUncPath(request.body.deleteFile) === true) { + globals.logger.warn( + `FILE COPY FROM: UNC paths not supported work on non-Windows OSs ("${ + request.body.deleteFile + }"). OS is "${os.platform()}".` + ); + reply.send( + httpErrors( + 400, + `UNC paths not supported for file copy operations when running Butler on non-Windows OS. Path: ${request.body.deleteFile}` + ) + ); + + return; + } + } + // Make sure that // 1. file exists // 2. file is in a valid directoryv (or subdirectory thereof),