mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'master' into dev
This commit is contained in:
commit
f5da2eb633
20
CHANGELOG.md
20
CHANGELOG.md
@ -1,3 +1,23 @@
|
||||
### 1.2.8: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Ensure subflow help is picked up for palette tooltip Fixes #2834
|
||||
- Improve Ru locale (#2826) @alexk111
|
||||
- Fix scrollbars (#2825) @alexk111
|
||||
|
||||
Runtime
|
||||
|
||||
- Restrict project file access to inside the project directory
|
||||
- Validate user-provided language parameter before passing to i18n
|
||||
- Fix grunt release mkdir issue on Node.js 14 (#2827) @alexk111
|
||||
- Prevent crash when coreNodesDir is empty (#2831) @hardillb
|
||||
|
||||
Nodes
|
||||
|
||||
- Batch node: Fixing minor typo in node's documentation (#2848) @matthiasradde
|
||||
- Split node: Handle out of order messages as long as one of the messages has msg.parts.count set to the proper value (#2748) @s4ke
|
||||
|
||||
### 1.2.7: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
@ -106,7 +106,7 @@
|
||||
"marked": "1.2.7",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "^5.2.0",
|
||||
"node-red-node-test-helper": "^0.2.5",
|
||||
"node-red-node-test-helper": "^0.2.6",
|
||||
"node-sass": "^4.14.1",
|
||||
"nodemon": "2.0.6",
|
||||
"should": "13.2.3",
|
||||
|
@ -20,19 +20,18 @@
|
||||
<p>Es gibt drei Modi für die Erstellung von Nachrichtensequenzen:</p>
|
||||
<dl>
|
||||
<dt>Anzahl der Nachrichten</dt>
|
||||
<dd>Die Nachrichten werden zu Sequenzen einer bestimmten Länge gruppiert. Die Option <b>Überlappung</b>>
|
||||
<dd>Die Nachrichten werden zu Sequenzen einer bestimmten Länge gruppiert. Die Option <b>Überlappung</b>
|
||||
gibt an, wie viele Nachrichten vom Ende einer Sequenz am Anfang der nächsten Sequenz wiederholt werden sollen.</dd>
|
||||
|
||||
<dt>Zeitintervall</dt>
|
||||
<dd>Gruppiert Nachrichten, die innerhalb des angegebenen Intervalls eingehen. Wenn keine Nachrichten
|
||||
innerhalb des Intervalls ankommen, kann der Node optional eine leere Nachricht senden.</dd>
|
||||
|
||||
<dt>Sequenzesn verketten/dt>
|
||||
<dt>Sequenzen verketten/dt>
|
||||
<dd>Erzeugt eine Nachrichtensequenz durch die Verkettung eingehender Sequenzen. Jede Nachricht muss eine <code>msg.topic</code>
|
||||
und eine <code>msg.parts</code> Eigenschaft haben, um die Sequenz identifizieren zu können.
|
||||
Der Node ist mit einer Liste von <code>topic</code> konfiguriert,
|
||||
mit der die Reihnmefolge der Verkettung der Sequenzen definiert wird.
|
||||
</dd>
|
||||
mit der die Reihenfolge der Verkettung der Sequenzen definiert wird.</dd>
|
||||
|
||||
</dl>
|
||||
<h4>Speichern der Nachrichten</h4>
|
||||
|
@ -305,6 +305,9 @@ Project.prototype.update = async function (user, data) {
|
||||
return new Error("Invalid package file: "+data.files.package)
|
||||
}
|
||||
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['package.json'] = data.files.package;
|
||||
globalProjectSettings.projects[this.name].rootPath = root;
|
||||
@ -322,12 +325,18 @@ Project.prototype.update = async function (user, data) {
|
||||
}
|
||||
|
||||
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.package['node-red'].settings.flowFile = data.files.flow.substring(this.paths.root.length);
|
||||
savePackage = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
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.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
|
||||
@ -490,6 +499,10 @@ Project.prototype.getFile = function (filePath,treeish) {
|
||||
if (treeish !== "_") {
|
||||
return gitTools.getFile(this.path, filePath, treeish);
|
||||
} 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");
|
||||
}
|
||||
};
|
||||
@ -639,6 +652,11 @@ Project.prototype.pull = function (user,remoteBranchName,setRemote,allowUnrelate
|
||||
|
||||
Project.prototype.resolveMerge = function (file,resolutions) {
|
||||
var filePath = fspath.join(this.path,file);
|
||||
|
||||
if (/^\.\./.test(fspath.relative(this.path,filePath))) {
|
||||
throw new Error("Invalid file name")
|
||||
}
|
||||
|
||||
var self = this;
|
||||
if (typeof resolutions === 'string') {
|
||||
return util.writeFile(filePath, resolutions).then(function() {
|
||||
@ -1047,12 +1065,10 @@ function loadProject(projectPath) {
|
||||
function init(_settings, _runtime) {
|
||||
settings = _settings;
|
||||
runtime = _runtime;
|
||||
projectsDir = fspath.join(settings.userDir,"projects");
|
||||
|
||||
projectsDir = fspath.resolve(fspath.join(settings.userDir,"projects"));
|
||||
if(settings.editorTheme.projects.path) {
|
||||
projectsDir = settings.editorTheme.projects.path;
|
||||
}
|
||||
|
||||
authCache.init();
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,8 @@ function init(_settings, _runtime) {
|
||||
globalGitUser = gitConfig.user;
|
||||
Projects.init(settings,runtime);
|
||||
sshTools.init(settings);
|
||||
projectsDir = fspath.join(settings.userDir,"projects");
|
||||
|
||||
projectsDir = fspath.resolve(fspath.join(settings.userDir,"projects"));
|
||||
|
||||
if(settings.editorTheme.projects.path) {
|
||||
projectsDir = settings.editorTheme.projects.path;
|
||||
@ -215,9 +216,16 @@ function getBackupFilename(filename) {
|
||||
}
|
||||
|
||||
function loadProject(name) {
|
||||
let fullPath = fspath.resolve(fspath.join(projectsDir,name));
|
||||
var projectPath = name;
|
||||
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) {
|
||||
activeProject = project;
|
||||
@ -241,6 +249,10 @@ function deleteProject(user, name) {
|
||||
throw e;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -399,6 +411,10 @@ function createProject(user, metadata) {
|
||||
metadata.files.credentialSecret = currentEncryptionKey;
|
||||
}
|
||||
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 setActiveProject(user, p.name);
|
||||
}).then(function() {
|
||||
|
@ -53,6 +53,49 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should send returned message using send()', function(done) {
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"node.send(msg);"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should do something with the catch node', function(done) {
|
||||
var flow = [{"id":"funcNode","type":"function","wires":[["goodNode"]],"func":"node.error('This is an error', msg);"},{"id":"goodNode","type":"helper"},{"id":"badNode","type":"helper"},{"id":"catchNode","type":"catch","scope":null,"uncaught":false,"wires":[["badNode"]]}];
|
||||
var catchNodeModule = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js")
|
||||
helper.load([catchNodeModule, functionNode], flow, function() {
|
||||
var funcNode = helper.getNode("funcNode");
|
||||
var catchNode = helper.getNode("catchNode");
|
||||
var goodNode = helper.getNode("goodNode");
|
||||
var badNode = helper.getNode("badNode");
|
||||
|
||||
badNode.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
msg.should.have.property('error');
|
||||
msg.error.should.have.property('message',"This is an error");
|
||||
msg.error.should.have.property('source');
|
||||
msg.error.source.should.have.property('id', "funcNode");
|
||||
done();
|
||||
});
|
||||
funcNode.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"function", name: "function" }];
|
||||
helper.load(functionNode, flow, function() {
|
||||
@ -1560,4 +1603,5 @@ describe('function node', function() {
|
||||
});
|
||||
|
||||
})
|
||||
*/
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user