1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Restrict project file access to inside the project directory

This commit is contained in:
Nick O'Leary 2021-02-01 13:39:39 +00:00
parent 7bde7f0cfd
commit 74db3e17d0
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 36 additions and 3 deletions

View File

@ -305,6 +305,9 @@ Project.prototype.update = function (user, data) {
return Promise.reject("Invalid package file: "+data.files.package) return Promise.reject("Invalid package file: "+data.files.package)
} }
var root = data.files.package.substring(0,data.files.package.length-12); var root = data.files.package.substring(0,data.files.package.length-12);
if (/^\.\./.test(fspath.relative(this.path,fspath.join(this.path,data.files.package)))) {
return Promise.reject("Invalid package file: "+data.files.package)
}
this.paths.root = root; this.paths.root = root;
this.paths['package.json'] = data.files.package; this.paths['package.json'] = data.files.package;
globalProjectSettings.projects[this.name].rootPath = root; globalProjectSettings.projects[this.name].rootPath = root;
@ -322,12 +325,18 @@ Project.prototype.update = function (user, data) {
} }
if (data.files.hasOwnProperty('flow') && this.package['node-red'].settings.flowFile !== data.files.flow.substring(this.paths.root.length)) { if (data.files.hasOwnProperty('flow') && this.package['node-red'].settings.flowFile !== data.files.flow.substring(this.paths.root.length)) {
if (/^\.\./.test(fspath.relative(this.path,fspath.join(this.path,data.files.flow)))) {
return Promise.reject("Invalid flow file: "+data.files.flow)
}
this.paths.flowFile = data.files.flow; this.paths.flowFile = data.files.flow;
this.package['node-red'].settings.flowFile = data.files.flow.substring(this.paths.root.length); this.package['node-red'].settings.flowFile = data.files.flow.substring(this.paths.root.length);
savePackage = true; savePackage = true;
flowFilesChanged = true; flowFilesChanged = true;
} }
if (data.files.hasOwnProperty('credentials') && this.package['node-red'].settings.credentialsFile !== data.files.credentials.substring(this.paths.root.length)) { if (data.files.hasOwnProperty('credentials') && this.package['node-red'].settings.credentialsFile !== data.files.credentials.substring(this.paths.root.length)) {
if (/^\.\./.test(fspath.relative(this.path,fspath.join(this.path,data.files.credentials)))) {
return Promise.reject("Invalid credentials file: "+data.files.credentials)
}
this.paths.credentialsFile = data.files.credentials; this.paths.credentialsFile = data.files.credentials;
this.package['node-red'].settings.credentialsFile = data.files.credentials.substring(this.paths.root.length); this.package['node-red'].settings.credentialsFile = data.files.credentials.substring(this.paths.root.length);
// Don't know if the credSecret is invalid or not so clear the flag // Don't know if the credSecret is invalid or not so clear the flag
@ -490,6 +499,10 @@ Project.prototype.getFile = function (filePath,treeish) {
if (treeish !== "_") { if (treeish !== "_") {
return gitTools.getFile(this.path, filePath, treeish); return gitTools.getFile(this.path, filePath, treeish);
} else { } else {
let fullPath = fspath.join(this.path,filePath);
if (/^\.\./.test(fspath.relative(this.path,fullPath))) {
throw new Error("Invalid file name")
}
return fs.readFile(fspath.join(this.path,filePath),"utf8"); return fs.readFile(fspath.join(this.path,filePath),"utf8");
} }
}; };
@ -639,6 +652,11 @@ Project.prototype.pull = function (user,remoteBranchName,setRemote,allowUnrelate
Project.prototype.resolveMerge = function (file,resolutions) { Project.prototype.resolveMerge = function (file,resolutions) {
var filePath = fspath.join(this.path,file); var filePath = fspath.join(this.path,file);
if (/^\.\./.test(fspath.relative(this.path,filePath))) {
throw new Error("Invalid file name")
}
var self = this; var self = this;
if (typeof resolutions === 'string') { if (typeof resolutions === 'string') {
return util.writeFile(filePath, resolutions).then(function() { return util.writeFile(filePath, resolutions).then(function() {
@ -1062,7 +1080,7 @@ function loadProject(projectPath) {
function init(_settings, _runtime) { function init(_settings, _runtime) {
settings = _settings; settings = _settings;
runtime = _runtime; runtime = _runtime;
projectsDir = fspath.join(settings.userDir,"projects"); projectsDir = fspath.resolve(fspath.join(settings.userDir,"projects"));
authCache.init(); authCache.init();
} }

View File

@ -110,7 +110,7 @@ function init(_settings, _runtime) {
globalGitUser = gitConfig.user; globalGitUser = gitConfig.user;
Projects.init(settings,runtime); Projects.init(settings,runtime);
sshTools.init(settings); sshTools.init(settings);
projectsDir = fspath.join(settings.userDir,"projects"); projectsDir = fspath.resolve(fspath.join(settings.userDir,"projects"));
if (!settings.readOnly) { if (!settings.readOnly) {
return fs.ensureDir(projectsDir) return fs.ensureDir(projectsDir)
//TODO: this is accessing settings from storage directly as settings //TODO: this is accessing settings from storage directly as settings
@ -207,9 +207,16 @@ function getBackupFilename(filename) {
} }
function loadProject(name) { function loadProject(name) {
let fullPath = fspath.resolve(fspath.join(projectsDir,name));
var projectPath = name; var projectPath = name;
if (projectPath.indexOf(fspath.sep) === -1) { if (projectPath.indexOf(fspath.sep) === -1) {
projectPath = fspath.join(projectsDir,name); projectPath = fullPath;
} else {
// Ensure this project dir is under projectsDir;
let relativePath = fspath.relative(projectsDir,fullPath);
if (/^\.\./.test(relativePath)) {
throw new Error("Invalid project name")
}
} }
return Projects.load(projectPath).then(function(project) { return Projects.load(projectPath).then(function(project) {
activeProject = project; activeProject = project;
@ -234,6 +241,10 @@ function deleteProject(user, name) {
throw e; throw e;
} }
var projectPath = fspath.join(projectsDir,name); var projectPath = fspath.join(projectsDir,name);
let relativePath = fspath.relative(projectsDir,projectPath);
if (/^\.\./.test(relativePath)) {
throw new Error("Invalid project name")
}
return Projects.delete(user, projectPath); return Projects.delete(user, projectPath);
} }
@ -392,6 +403,10 @@ function createProject(user, metadata) {
metadata.files.credentialSecret = currentEncryptionKey; metadata.files.credentialSecret = currentEncryptionKey;
} }
metadata.path = fspath.join(projectsDir,metadata.name); metadata.path = fspath.join(projectsDir,metadata.name);
if (/^\.\./.test(fspath.relative(projectsDir,metadata.path))) {
throw new Error("Invalid project name")
}
return Projects.create(user, metadata).then(function(p) { return Projects.create(user, metadata).then(function(p) {
return setActiveProject(user, p.name); return setActiveProject(user, p.name);
}).then(function() { }).then(function() {