mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 22:16:01 +00:00
SYNC: security fixes
This commit is contained in:
committed by
Diflow
parent
3f37b2b728
commit
cf3f95c952
@@ -12,6 +12,7 @@ const getMapExport = require('../utility/getMapExport');
|
|||||||
const dbgateApi = require('../shell');
|
const dbgateApi = require('../shell');
|
||||||
const { getLogger } = require('dbgate-tools');
|
const { getLogger } = require('dbgate-tools');
|
||||||
const platformInfo = require('../utility/platformInfo');
|
const platformInfo = require('../utility/platformInfo');
|
||||||
|
const { checkSecureFilePaths, checkSecureDirectories } = require('../utility/security');
|
||||||
const logger = getLogger('files');
|
const logger = getLogger('files');
|
||||||
|
|
||||||
function serialize(format, data) {
|
function serialize(format, data) {
|
||||||
@@ -26,25 +27,6 @@ function deserialize(format, text) {
|
|||||||
throw new Error(`Invalid format: ${format}`);
|
throw new Error(`Invalid format: ${format}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkSecureFilePaths(...filePaths) {
|
|
||||||
for (const filePath of filePaths) {
|
|
||||||
if (filePath.includes('..') || filePath.includes('/') || filePath.includes('\\')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkSecureDirectories(...filePaths) {
|
|
||||||
for (const filePath of filePaths) {
|
|
||||||
const directory = path.dirname(filePath);
|
|
||||||
if (directory != filesdir() && directory != uploadsdir() && directory != archivedir() && directory != appdir()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
list_meta: true,
|
list_meta: true,
|
||||||
async list({ folder }, req) {
|
async list({ folder }, req) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const {
|
|||||||
const { handleProcessCommunication } = require('../utility/processComm');
|
const { handleProcessCommunication } = require('../utility/processComm');
|
||||||
const processArgs = require('../utility/processArgs');
|
const processArgs = require('../utility/processArgs');
|
||||||
const platformInfo = require('../utility/platformInfo');
|
const platformInfo = require('../utility/platformInfo');
|
||||||
|
const { checkSecureDirectories, checkSecureDirectoriesInScript } = require('../utility/security');
|
||||||
const logger = getLogger('runners');
|
const logger = getLogger('runners');
|
||||||
|
|
||||||
function extractPlugins(script) {
|
function extractPlugins(script) {
|
||||||
@@ -273,6 +274,12 @@ module.exports = {
|
|||||||
const runid = crypto.randomUUID();
|
const runid = crypto.randomUUID();
|
||||||
|
|
||||||
if (script.type == 'json') {
|
if (script.type == 'json') {
|
||||||
|
if (!platformInfo.isElectron) {
|
||||||
|
if (!checkSecureDirectoriesInScript(script)) {
|
||||||
|
return { errorMessage: 'Unallowed directories in script' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const js = await jsonScriptToJavascript(script);
|
const js = await jsonScriptToJavascript(script);
|
||||||
return this.startCore(runid, scriptTemplate(js, false));
|
return this.startCore(runid, scriptTemplate(js, false));
|
||||||
}
|
}
|
||||||
@@ -317,6 +324,11 @@ module.exports = {
|
|||||||
|
|
||||||
loadReader_meta: true,
|
loadReader_meta: true,
|
||||||
async loadReader({ functionName, props }) {
|
async loadReader({ functionName, props }) {
|
||||||
|
if (!platformInfo.isElectron) {
|
||||||
|
if (props?.fileName && !checkSecureDirectories(props.fileName)) {
|
||||||
|
return { errorMessage: 'Unallowed file' };
|
||||||
|
}
|
||||||
|
}
|
||||||
const prefix = extractShellApiPlugins(functionName)
|
const prefix = extractShellApiPlugins(functionName)
|
||||||
.map(packageName => `// @require ${packageName}\n`)
|
.map(packageName => `// @require ${packageName}\n`)
|
||||||
.join('');
|
.join('');
|
||||||
|
|||||||
52
packages/api/src/utility/security.js
Normal file
52
packages/api/src/utility/security.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { filesdir, archivedir, uploadsdir, appdir } = require('../utility/directories');
|
||||||
|
|
||||||
|
function checkSecureFilePaths(...filePaths) {
|
||||||
|
for (const filePath of filePaths) {
|
||||||
|
if (filePath.includes('..') || filePath.includes('/') || filePath.includes('\\')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkSecureDirectories(...filePaths) {
|
||||||
|
for (const filePath of filePaths) {
|
||||||
|
if (!filePath.includes('/') && !filePath.includes('\\')) {
|
||||||
|
// If the filePath does not contain any directory separators, it is considered secure
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const directory = path.dirname(filePath);
|
||||||
|
if (directory != filesdir() && directory != uploadsdir() && directory != archivedir() && directory != appdir()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDisallowedFileNames(node, isAllowed, trace = '$', out = []) {
|
||||||
|
if (node && typeof node === 'object') {
|
||||||
|
if (node?.props?.fileName) {
|
||||||
|
const name = node.props.fileName;
|
||||||
|
const ok = isAllowed(name);
|
||||||
|
if (!ok) out.push({ path: `${trace}.props.fileName`, value: name });
|
||||||
|
}
|
||||||
|
|
||||||
|
// depth-first scan of every property / array index
|
||||||
|
for (const [key, val] of Object.entries(node)) {
|
||||||
|
findDisallowedFileNames(val, isAllowed, `${trace}.${key}`, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkSecureDirectoriesInScript(script) {
|
||||||
|
const disallowed = findDisallowedFileNames(script, checkSecureDirectories);
|
||||||
|
return disallowed.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
checkSecureDirectories,
|
||||||
|
checkSecureFilePaths,
|
||||||
|
checkSecureDirectoriesInScript,
|
||||||
|
};
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
import ToolStripSaveButton from '../buttons/ToolStripSaveButton.svelte';
|
import ToolStripSaveButton from '../buttons/ToolStripSaveButton.svelte';
|
||||||
import uuidv1 from 'uuid/v1';
|
import uuidv1 from 'uuid/v1';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
|
import { showSnackbarError } from '../utility/snackbar';
|
||||||
|
|
||||||
let busy = false;
|
let busy = false;
|
||||||
let executeNumber = 0;
|
let executeNumber = 0;
|
||||||
@@ -200,6 +201,11 @@
|
|||||||
} else {
|
} else {
|
||||||
let runid = runnerId;
|
let runid = runnerId;
|
||||||
const resp = await apiCall('runners/start', { script });
|
const resp = await apiCall('runners/start', { script });
|
||||||
|
if (resp.errorMessage) {
|
||||||
|
busy = false;
|
||||||
|
showSnackbarError(resp.errorMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
runid = resp.runid;
|
runid = resp.runid;
|
||||||
runnerId = runid;
|
runnerId = runid;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user