Compare commits

...

25 Commits

Author SHA1 Message Date
Nick O'Leary
13ee8cec24 Merge branch 'master' into sync-dev-2 2024-05-14 17:22:42 +01:00
Nick O'Leary
a977b87cb3 Merge pull request #4692 from node-red/improve-conflict-handling
Improve background-deploy notification handling
2024-05-14 16:04:58 +01:00
Nick O'Leary
14dfb9aef8 Merge pull request #4695 from node-red/improve-merge-diff-view
Improve diff view display of nodes that have only moved
2024-05-14 16:04:27 +01:00
Nick O'Leary
d520cde57a Merge pull request #4314 from Rotzbua/remove_outdated_node_check
fix: remove outdated Node 11+ check
2024-05-14 13:54:15 +01:00
Nick O'Leary
70167d7d1d Merge pull request #4694 from Rotzbua/test_add_node_22
feat(ci): add new nodejs v22
2024-05-14 13:52:34 +01:00
Nick O'Leary
ac6a4945cb Merge pull request #4690 from Rotzbua/fix_node_requirement
fix(node): increase required node >=18.5
2024-05-14 13:29:52 +01:00
Rotzbua
fd1a001a23 feat(ci): add new nodejs v22 2024-05-14 13:39:32 +02:00
Rotzbua
f3c561cd86 fix(node): increase required node >=18.5
Statement can be simplified by increasing the required minor version.
2024-05-14 12:27:38 +02:00
Nick O'Leary
edc5e88d5a Merge pull request #4689 from Rotzbua/fix_workaroud_dns
fix(dns): remove outdated node check
2024-05-13 14:41:35 +01:00
Nick O'Leary
47bf166a6e Update packages/node_modules/node-red/lib/red.js 2024-05-13 14:41:24 +01:00
Nick O'Leary
cf26209790 Merge pull request #4688 from Rotzbua/remove_import_polyfill
fix(polyfill): remove import module polyfill
2024-05-13 14:39:33 +01:00
Nick O'Leary
e55ebde170 Merge pull request #4686 from Rotzbua/fix_typo
Fix typo
2024-05-13 14:38:35 +01:00
Rotzbua
d706c9cb37 fix: remove outdated Node 11+ check 2024-05-12 22:51:05 +02:00
Rotzbua
20d2450cac fix(polyfill): remove import module polyfill
Was required for node <12.17.
2024-05-12 22:38:03 +02:00
Rotzbua
34345461f1 fix(dns): remove outdated node check
Add reference to issue for this workaround.
2024-05-12 22:25:39 +02:00
Rotzbua
aa372a1707 Fix typo in source code comment 2024-05-12 18:25:08 +02:00
Nick O'Leary
08927dfb55 Merge pull request #4684 from node-red/4363-autoLogin-redirect-loop
Avoid login loops when autoLogin enabled but login fails
2024-05-08 15:48:21 +01:00
Nick O'Leary
b27483de9c Avoid login loops when autoLogin enabled but login fails
Fixes #4363
2024-05-08 15:09:51 +01:00
Nick O'Leary
211d420fb2 Merge pull request #4667 from node-red/fix-subflow-property-undo
Fix undo of subflow env property edits
2024-04-23 23:45:46 +02:00
Nick O'Leary
b8ca4665c1 Merge pull request #4660 from JoshuaCWebDeveloper/patch-1
Fix three error typos in monaco.js
2024-04-23 23:45:16 +02:00
Nick O'Leary
960af87fb0 Ensure subflow change state is cleared after deploy 2024-04-23 21:17:35 +02:00
Nick O'Leary
de7339ae97 Fix undo of subflow env property edits 2024-04-23 20:39:14 +02:00
Stephen McLaughlin
0995af62b6 Merge pull request #4664 from ZJvandeWeg/patch-3
docs: Add closing paragraph tag
2024-04-20 13:54:37 +01:00
Zeger-Jan van de Weg
c2e03a40b4 docs: Add closing paragraph tag
Minor change that only improves xpath parsing.
2024-04-20 14:20:59 +02:00
Joshua Carter
c855050bcf Fix three error typos in monaco.js 2024-04-15 08:09:26 -07:00
21 changed files with 90 additions and 127 deletions

View File

@@ -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 }}

View File

@@ -123,6 +123,6 @@
"supertest": "6.3.3"
},
"engines": {
"node": ">=18"
"node": ">=18.5"
}
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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)
}
}

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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";

View File

@@ -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"
}
},

View File

@@ -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"
}
},

View File

@@ -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"
}
},

View File

@@ -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"
}
},

View File

@@ -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である必要があります"
}
},

View File

@@ -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"
}
},

View File

@@ -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 было функцией"
}
},

View File

@@ -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
*/

View File

@@ -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');

View File

@@ -47,6 +47,6 @@
"bcrypt": "5.1.0"
},
"engines": {
"node": ">=18"
"node": ">=18.5"
}
}

View File

@@ -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 {

View File

@@ -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'})
});
});
}
});
});
});