mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
25 Commits
improve-me
...
sync-dev-2
Author | SHA1 | Date | |
---|---|---|---|
|
13ee8cec24 | ||
|
a977b87cb3 | ||
|
14dfb9aef8 | ||
|
d520cde57a | ||
|
70167d7d1d | ||
|
ac6a4945cb | ||
|
fd1a001a23 | ||
|
f3c561cd86 | ||
|
edc5e88d5a | ||
|
47bf166a6e | ||
|
cf26209790 | ||
|
e55ebde170 | ||
|
d706c9cb37 | ||
|
20d2450cac | ||
|
34345461f1 | ||
|
aa372a1707 | ||
|
08927dfb55 | ||
|
b27483de9c | ||
|
211d420fb2 | ||
|
b8ca4665c1 | ||
|
960af87fb0 | ||
|
de7339ae97 | ||
|
0995af62b6 | ||
|
c2e03a40b4 | ||
|
c855050bcf |
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18, 20]
|
||||
node-version: [18, 20, 22]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
|
@@ -123,6 +123,6 @@
|
||||
"supertest": "6.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=18.5"
|
||||
}
|
||||
}
|
||||
|
@@ -205,9 +205,10 @@ function genericStrategy(adminApp,strategy) {
|
||||
passport.use(new strategy.strategy(options, verify));
|
||||
|
||||
adminApp.get('/auth/strategy',
|
||||
passport.authenticate(strategy.name, {session:false,
|
||||
passport.authenticate(strategy.name, {
|
||||
session:false,
|
||||
failureMessage: true,
|
||||
failureRedirect: settings.httpAdminRoot
|
||||
failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
|
||||
}),
|
||||
completeGenerateStrategyAuth,
|
||||
handleStrategyError
|
||||
@@ -221,7 +222,7 @@ function genericStrategy(adminApp,strategy) {
|
||||
passport.authenticate(strategy.name, {
|
||||
session:false,
|
||||
failureMessage: true,
|
||||
failureRedirect: settings.httpAdminRoot
|
||||
failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
|
||||
}),
|
||||
completeGenerateStrategyAuth,
|
||||
handleStrategyError
|
||||
|
@@ -624,7 +624,10 @@ RED.deploy = (function() {
|
||||
}
|
||||
});
|
||||
RED.nodes.eachSubflow(function (subflow) {
|
||||
subflow.changed = false;
|
||||
if (subflow.changed) {
|
||||
subflow.changed = false;
|
||||
RED.events.emit("subflows:change", subflow);
|
||||
}
|
||||
});
|
||||
RED.nodes.eachWorkspace(function (ws) {
|
||||
if (ws.changed || ws.added) {
|
||||
|
@@ -1721,8 +1721,8 @@ RED.editor = (function() {
|
||||
}
|
||||
|
||||
if (!isSameObj(old_env, new_env)) {
|
||||
editing_node.env = new_env;
|
||||
editState.changes.env = editing_node.env;
|
||||
editing_node.env = new_env;
|
||||
editState.changed = true;
|
||||
}
|
||||
|
||||
|
@@ -514,7 +514,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
_monaco.languages.json.jsonDefaults.setDiagnosticsOptions(diagnosticOptions);
|
||||
if(modeConfiguration) { _monaco.languages.json.jsonDefaults.setModeConfiguration(modeConfiguration); }
|
||||
} catch (error) {
|
||||
console.warn("monaco - Error setting up json options", err)
|
||||
console.warn("monaco - Error setting up json options", error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
if(htmlDefaults) { _monaco.languages.html.htmlDefaults.setOptions(htmlDefaults); }
|
||||
if(handlebarDefaults) { _monaco.languages.html.handlebarDefaults.setOptions(handlebarDefaults); }
|
||||
} catch (error) {
|
||||
console.warn("monaco - Error setting up html options", err)
|
||||
console.warn("monaco - Error setting up html options", error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
if(lessDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(lessDefaults_modeConfiguration); }
|
||||
if(scssDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(scssDefaults_modeConfiguration); }
|
||||
} catch (error) {
|
||||
console.warn("monaco - Error setting up CSS/SCSS/LESS options", err)
|
||||
console.warn("monaco - Error setting up CSS/SCSS/LESS options", error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -76,7 +76,7 @@ declare namespace RED {
|
||||
*/
|
||||
function compareObjects(obj1: any, obj2: any): boolean;
|
||||
/**
|
||||
* Generates a psuedo-unique-random id.
|
||||
* Generates a pseudo-unique-random id.
|
||||
* @return {string} a random-ish id
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
|
@@ -103,7 +103,7 @@
|
||||
<h4>Automatic mode</h4>
|
||||
<p>Automatic mode uses the <code>parts</code> property of incoming messages to
|
||||
determine how the sequence should be joined. This allows it to automatically
|
||||
reverse the action of a <b>split</b> node.
|
||||
reverse the action of a <b>split</b> node.</p>
|
||||
|
||||
<h4>Manual mode</h4>
|
||||
<p>When configured to join in manual mode, the node is able to join sequences
|
||||
|
@@ -28,11 +28,6 @@ let installEnabled = true;
|
||||
let installAllowList = ['*'];
|
||||
let installDenyList = [];
|
||||
|
||||
let IMPORT_SUPPORTED = true;
|
||||
const nodeVersionParts = process.versions.node.split(".").map(v => parseInt(v));
|
||||
if (nodeVersionParts[0] < 12 || (nodeVersionParts[0] === 12 && nodeVersionParts[1] < 17)) {
|
||||
IMPORT_SUPPORTED = false;
|
||||
}
|
||||
|
||||
function getInstallDir() {
|
||||
return path.resolve(settings.userDir || process.env.NODE_RED_HOME || ".");
|
||||
@@ -110,18 +105,6 @@ function requireModule(module) {
|
||||
return require(moduleDir);
|
||||
}
|
||||
function importModule(module) {
|
||||
if (!IMPORT_SUPPORTED) {
|
||||
// On Node < 12.17 - fall back to try a require
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const mod = requireModule(module);
|
||||
resolve(mod);
|
||||
} catch(err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!registryUtil.checkModuleAllowed( module, null,installAllowList,installDenyList)) {
|
||||
const e = new Error("Module not allowed");
|
||||
e.code = "module_not_allowed";
|
||||
|
@@ -56,7 +56,6 @@
|
||||
"refresh-interval": "Erneuerung der https-Einstellungen erfolgt alle __interval__ Stunden",
|
||||
"settings-refreshed": "https-Einstellungen wurden erneuert",
|
||||
"refresh-failed": "Erneuerung der https-Einstellungen fehlgeschlagen: __message__",
|
||||
"nodejs-version": "httpsRefreshInterval erfordert Node.js 11 oder höher",
|
||||
"function-required": "httpsRefreshInterval erfordert die https-Eigenschaft in Form einer Funktion"
|
||||
}
|
||||
},
|
||||
|
@@ -58,7 +58,6 @@
|
||||
"refresh-interval": "Refreshing https settings every __interval__ hours",
|
||||
"settings-refreshed": "Server https settings have been refreshed",
|
||||
"refresh-failed": "Failed to refresh https settings: __message__",
|
||||
"nodejs-version": "httpsRefreshInterval requires Node.js 11 or later",
|
||||
"function-required": "httpsRefreshInterval requires https property to be a function"
|
||||
}
|
||||
},
|
||||
|
@@ -57,7 +57,6 @@
|
||||
"refresh-interval": "Actualizando la configuración HTTPS cada __interval__ horas",
|
||||
"settings-refreshed": "La configuración HTTPS del servidor se ha actualizado",
|
||||
"refresh-failed": "No se pudo actualizar la configuración HTTPS: __message__",
|
||||
"nodejs-version": "httpsRefreshInterval requiere Node.js 11 o superior",
|
||||
"function-required": "httpsRefreshInterval requiere que la propiedad HTTPS sea una función"
|
||||
}
|
||||
},
|
||||
|
@@ -58,7 +58,6 @@
|
||||
"refresh-interval": "Actualisation des paramètres https toutes les __interval__ heures",
|
||||
"settings-refreshed": "Les paramètres https du serveur ont été actualisés",
|
||||
"refresh-failed": "Échec de l'actualisation des paramètres https : __message__",
|
||||
"nodejs-version": "httpsRefreshInterval nécessite Node.js 11 ou version ultérieure",
|
||||
"function-required": "httpsRefreshInterval nécessite que la propriété https soit une fonction"
|
||||
}
|
||||
},
|
||||
|
@@ -58,7 +58,6 @@
|
||||
"refresh-interval": "__interval__ 時間毎にhttps設定を更新します",
|
||||
"settings-refreshed": "サーバのhttps設定が更新されました",
|
||||
"refresh-failed": "https設定の更新で失敗しました: __message__",
|
||||
"nodejs-version": "httpsRefreshIntervalにはNode.js 11以降が必要です",
|
||||
"function-required": "httpsRefreshIntervalでは、httpsプロパティはfunctionである必要があります"
|
||||
}
|
||||
},
|
||||
|
@@ -57,7 +57,6 @@
|
||||
"refresh-interval": "Atualizando as configurações de https a cada __interval__ hora(s)",
|
||||
"settings-refreshed": "As configurações https do servidor foram atualizadas",
|
||||
"refresh-failed": "Falha ao atualizar as configurações https: __message__",
|
||||
"nodejs-version": "httpsRefreshInterval requer Node.js 11 ou posterior",
|
||||
"function-required": "httpsRefreshInterval requer que a propriedade https seja uma função"
|
||||
}
|
||||
},
|
||||
|
@@ -55,7 +55,6 @@
|
||||
"refresh-interval": "Обновление настроек https каждые __interval__ часов",
|
||||
"settings-refreshed": "Настройки сервера https обновлены",
|
||||
"refresh-failed": "Не удалось обновить настройки https: __message__",
|
||||
"nodejs-version": "httpsRefreshInterval требует Node.js 11 или выше",
|
||||
"function-required": "httpsRefreshInterval требует, чтобы свойство https было функцией"
|
||||
}
|
||||
},
|
||||
|
@@ -27,7 +27,7 @@ const util = require("util");
|
||||
const { hasOwnProperty } = Object.prototype;
|
||||
const log = require("./log")
|
||||
/**
|
||||
* Safely returns the object construtor name.
|
||||
* Safely returns the object constructor name.
|
||||
* @return {String} the name of the object constructor if it exists, empty string otherwise.
|
||||
*/
|
||||
function constructorName(obj) {
|
||||
@@ -37,7 +37,7 @@ function constructorName(obj) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a psuedo-unique-random id.
|
||||
* Generates a pseudo-unique-random id.
|
||||
* @return {String} a random-ish id
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
|
8
packages/node_modules/node-red/lib/red.js
vendored
8
packages/node_modules/node-red/lib/red.js
vendored
@@ -25,11 +25,9 @@ var api = require("@node-red/editor-api");
|
||||
var server = null;
|
||||
var apiEnabled = false;
|
||||
|
||||
const NODE_MAJOR_VERSION = process.versions.node.split('.')[0];
|
||||
if (NODE_MAJOR_VERSION >= 16) {
|
||||
const dns = require('dns');
|
||||
dns.setDefaultResultOrder('ipv4first');
|
||||
}
|
||||
// Ensure ipv4 results are returned first: https://github.com/node-red/node-red/issues/4010
|
||||
const dns = require('dns');
|
||||
dns.setDefaultResultOrder('ipv4first');
|
||||
|
||||
function checkVersion(userSettings) {
|
||||
var semver = require('semver');
|
||||
|
2
packages/node_modules/node-red/package.json
vendored
2
packages/node_modules/node-red/package.json
vendored
@@ -47,6 +47,6 @@
|
||||
"bcrypt": "5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=18.5"
|
||||
}
|
||||
}
|
||||
|
53
packages/node_modules/node-red/red.js
vendored
53
packages/node_modules/node-red/red.js
vendored
@@ -240,39 +240,34 @@ httpsPromise.then(function(startupHttps) {
|
||||
// Max value based on (2^31-1)ms - the max that setInterval can accept
|
||||
httpsRefreshInterval = 596;
|
||||
}
|
||||
// Check whether setSecureContext is available (Node.js 11+)
|
||||
if (server.setSecureContext) {
|
||||
// Check whether `http` is a callable function
|
||||
if (typeof settings.https === "function") {
|
||||
delayedLogItems.push({type:"info", id:"server.https.refresh-interval", params:{interval:httpsRefreshInterval}});
|
||||
setInterval(function () {
|
||||
try {
|
||||
// Get the result of the function, because createServer doesn't accept functions as input
|
||||
Promise.resolve(settings.https()).then(function(refreshedHttps) {
|
||||
if (refreshedHttps) {
|
||||
// The key/cert needs to be updated in the NodeJs http(s) server, when no key/cert is yet available or when the key/cert has changed.
|
||||
// Note that the refreshed key/cert can be supplied as a string or a buffer.
|
||||
var updateKey = (server.key == undefined || (Buffer.isBuffer(server.key) && !server.key.equals(refreshedHttps.key)) || (typeof server.key == "string" && server.key != refreshedHttps.key));
|
||||
var updateCert = (server.cert == undefined || (Buffer.isBuffer(server.cert) && !server.cert.equals(refreshedHttps.cert)) || (typeof server.cert == "string" && server.cert != refreshedHttps.cert));
|
||||
// Check whether `http` is a callable function
|
||||
if (typeof settings.https === "function") {
|
||||
delayedLogItems.push({type:"info", id:"server.https.refresh-interval", params:{interval:httpsRefreshInterval}});
|
||||
setInterval(function () {
|
||||
try {
|
||||
// Get the result of the function, because createServer doesn't accept functions as input
|
||||
Promise.resolve(settings.https()).then(function(refreshedHttps) {
|
||||
if (refreshedHttps) {
|
||||
// The key/cert needs to be updated in the NodeJs http(s) server, when no key/cert is yet available or when the key/cert has changed.
|
||||
// Note that the refreshed key/cert can be supplied as a string or a buffer.
|
||||
var updateKey = (server.key == undefined || (Buffer.isBuffer(server.key) && !server.key.equals(refreshedHttps.key)) || (typeof server.key == "string" && server.key != refreshedHttps.key));
|
||||
var updateCert = (server.cert == undefined || (Buffer.isBuffer(server.cert) && !server.cert.equals(refreshedHttps.cert)) || (typeof server.cert == "string" && server.cert != refreshedHttps.cert));
|
||||
|
||||
// Only update the credentials in the server when key or cert has changed
|
||||
if(updateKey || updateCert) {
|
||||
server.setSecureContext(refreshedHttps);
|
||||
RED.log.info(RED.log._("server.https.settings-refreshed"));
|
||||
}
|
||||
// Only update the credentials in the server when key or cert has changed
|
||||
if(updateKey || updateCert) {
|
||||
server.setSecureContext(refreshedHttps);
|
||||
RED.log.info(RED.log._("server.https.settings-refreshed"));
|
||||
}
|
||||
}).catch(function(err) {
|
||||
RED.log.error(RED.log._("server.https.refresh-failed",{message:err}));
|
||||
});
|
||||
} catch(err) {
|
||||
}
|
||||
}).catch(function(err) {
|
||||
RED.log.error(RED.log._("server.https.refresh-failed",{message:err}));
|
||||
}
|
||||
}, httpsRefreshInterval*60*60*1000);
|
||||
} else {
|
||||
delayedLogItems.push({type:"warn", id:"server.https.function-required"});
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
RED.log.error(RED.log._("server.https.refresh-failed",{message:err}));
|
||||
}
|
||||
}, httpsRefreshInterval*60*60*1000);
|
||||
} else {
|
||||
delayedLogItems.push({type:"warn", id:"server.https.nodejs-version"});
|
||||
delayedLogItems.push({type:"warn", id:"server.https.function-required"});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@@ -2509,69 +2509,59 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
|
||||
describe('should parse broken headers', function() {
|
||||
let port = testPort++
|
||||
|
||||
const versions = process.versions.node.split('.')
|
||||
let server;
|
||||
|
||||
if (( versions[0] == 14 && versions[1] >= 20 ) ||
|
||||
( versions[0] == 16 && versions[1] >= 16 ) ||
|
||||
( versions[0] == 18 && versions[1] >= 5 ) ||
|
||||
( versions[0] > 18)) {
|
||||
// only test if on new enough NodeJS version
|
||||
before(function() {
|
||||
server = net.createServer(function (socket) {
|
||||
socket.write("HTTP/1.0 200\nContent-Type: text/plain\n\nHelloWorld")
|
||||
socket.end()
|
||||
})
|
||||
|
||||
let port = testPort++
|
||||
server.listen(port,'127.0.0.1', function(err) {
|
||||
})
|
||||
});
|
||||
|
||||
let server;
|
||||
after(function() {
|
||||
server.close()
|
||||
});
|
||||
|
||||
before(function() {
|
||||
server = net.createServer(function (socket) {
|
||||
socket.write("HTTP/1.0 200\nContent-Type: text/plain\n\nHelloWorld")
|
||||
socket.end()
|
||||
it('should accept broken headers', function (done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:`http://localhost:${port}/`, insecureHTTPParser: true},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on('input', function(msg) {
|
||||
try {
|
||||
msg.payload.should.equal('HelloWorld')
|
||||
done()
|
||||
} catch (err) {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
n1.receive({payload: 'foo'})
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(port,'127.0.0.1', function(err) {
|
||||
it('should reject broken headers', function (done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:`http://localhost:${port}/`},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on('input', function(msg) {
|
||||
try{
|
||||
msg.payload.should.match(/RequestError: Parse Error/)
|
||||
done()
|
||||
} catch (err) {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
});
|
||||
n1.receive({payload: 'foo'})
|
||||
|
||||
after(function() {
|
||||
server.close()
|
||||
});
|
||||
|
||||
it('should accept broken headers', function (done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:`http://localhost:${port}/`, insecureHTTPParser: true},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on('input', function(msg) {
|
||||
try {
|
||||
msg.payload.should.equal('HelloWorld')
|
||||
done()
|
||||
} catch (err) {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
n1.receive({payload: 'foo'})
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject broken headers', function (done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:`http://localhost:${port}/`},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on('input', function(msg) {
|
||||
try{
|
||||
msg.payload.should.match(/RequestError: Parse Error/)
|
||||
done()
|
||||
} catch (err) {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
n1.receive({payload: 'foo'})
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user