@node-red/nodes 5.0.0-beta.1 → 5.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/common/25-status.js +7 -5
- package/core/common/lib/debug/debug-utils.js +57 -9
- package/core/function/89-delay.html +14 -1
- package/core/function/89-delay.js +43 -1
- package/core/network/05-tls.html +56 -6
- package/core/network/05-tls.js +26 -1
- package/core/network/21-httprequest.js +83 -53
- package/core/storage/10-file.html +2 -2
- package/locales/de/messages.json +4 -1
- package/locales/en-US/function/89-delay.html +12 -3
- package/locales/en-US/messages.json +11 -3
- package/locales/es-ES/messages.json +4 -1
- package/locales/fr/messages.json +4 -1
- package/locales/ja/messages.json +4 -1
- package/package.json +2 -2
package/core/common/25-status.js
CHANGED
|
@@ -20,13 +20,15 @@ module.exports = function(RED) {
|
|
|
20
20
|
function StatusNode(n) {
|
|
21
21
|
RED.nodes.createNode(this,n);
|
|
22
22
|
var node = this;
|
|
23
|
-
this.scope = n.scope
|
|
23
|
+
this.scope = n.scope;
|
|
24
24
|
|
|
25
25
|
// auto-filter out any directly connected nodes to avoid simple loopback
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.scope
|
|
26
|
+
if (Array.isArray(this.scope)) {
|
|
27
|
+
const w = this.wires.flat();
|
|
28
|
+
for (let i = 0; i < this.scope.length; i++) {
|
|
29
|
+
if (w.includes(this.scope[i])) {
|
|
30
|
+
this.scope.splice(i, 1);
|
|
31
|
+
}
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -32,12 +32,18 @@ RED.debug = (function() {
|
|
|
32
32
|
var numMessages = 100; // Hardcoded number of message to show in debug window scrollback
|
|
33
33
|
|
|
34
34
|
var debugNodeTreeList;
|
|
35
|
+
var debugPaused = false;
|
|
36
|
+
let debugPausedMessage
|
|
37
|
+
let debugPausedMessageCount = 0
|
|
35
38
|
|
|
36
39
|
function init(_config) {
|
|
37
40
|
config = _config;
|
|
38
41
|
|
|
39
42
|
var content = $("<div>").css({"position":"relative","height":"100%"});
|
|
40
43
|
var toolbar = $('<div class="red-ui-sidebar-header">'+
|
|
44
|
+
'<span class="button-group">'+
|
|
45
|
+
'<a id="red-ui-sidebar-debug-pause" class="red-ui-sidebar-header-button" href="#"><i class="fa fa-pause"></i></a>'+
|
|
46
|
+
'</span>'+
|
|
41
47
|
'<span class="button-group">'+
|
|
42
48
|
'<a id="red-ui-sidebar-debug-filter" style="padding-right: 5px" class="red-ui-sidebar-header-button" href="#"><i class="fa fa-filter"></i> <span></span> <i style="padding-left: 5px;" class="fa fa-caret-down"></i></a>'+
|
|
43
49
|
'</span>'+
|
|
@@ -47,6 +53,7 @@ RED.debug = (function() {
|
|
|
47
53
|
'</span></div>').appendTo(content);
|
|
48
54
|
|
|
49
55
|
var footerToolbar = $('<div>'+
|
|
56
|
+
'<span id="red-ui-sidebar-debug-info" style="float: left;"></span>' +
|
|
50
57
|
'<span class="button-group"><a id="red-ui-sidebar-debug-open" class="red-ui-footer-button" href="#"><i class="fa fa-desktop"></i></a></span> ' +
|
|
51
58
|
'</div>');
|
|
52
59
|
|
|
@@ -185,6 +192,39 @@ RED.debug = (function() {
|
|
|
185
192
|
});
|
|
186
193
|
RED.popover.tooltip(toolbar.find('#red-ui-sidebar-debug-filter'),RED._('node-red:debug.sidebar.filterLog'));
|
|
187
194
|
|
|
195
|
+
toolbar.find("#red-ui-sidebar-debug-pause").on("click", function(e) {
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
toggleDebugflow();
|
|
198
|
+
});
|
|
199
|
+
var pauseTooltip = RED.popover.tooltip(toolbar.find("#red-ui-sidebar-debug-pause"),RED._('node-red:debug.sidebar.pause'),"core:pause-debug-messages");
|
|
200
|
+
function toggleDebugflow() {
|
|
201
|
+
debugPaused = !debugPaused;
|
|
202
|
+
if (debugPaused) {
|
|
203
|
+
debugPausedMessageCount = 0
|
|
204
|
+
debugPausedMessage = $('<div class="red-ui-debug-msg red-ui-debug-msg-paused">')
|
|
205
|
+
$(`<div class="red-ui-debug-msg-meta">
|
|
206
|
+
<span class="red-ui-debug-msg-date">${getTimestamp()}</span>
|
|
207
|
+
<span class="red-ui-debug-msg-name">${RED._('node-red:debug.sidebar.paused')}</span>
|
|
208
|
+
</div>`).appendTo(debugPausedMessage);
|
|
209
|
+
$('<div class="red-ui-debug-msg-meta"><span class="red-ui-debug-msg-name"> </span></div>').appendTo(debugPausedMessage);
|
|
210
|
+
const atBottom = (sbc.scrollHeight-messageList.height()-sbc.scrollTop) < 5;
|
|
211
|
+
messageList.append(debugPausedMessage);
|
|
212
|
+
if (atBottom) {
|
|
213
|
+
messageList.scrollTop(sbc.scrollHeight);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
$("#red-ui-sidebar-debug-pause i").removeClass("fa-pause").addClass("fa-play");
|
|
217
|
+
pauseTooltip.setAction("core:resume-debug-messages");
|
|
218
|
+
pauseTooltip.setContent(RED._('node-red:debug.sidebar.resume'))
|
|
219
|
+
$("#red-ui-sidebar-debug-info").text(RED._('node-red:debug.sidebar.paused'));
|
|
220
|
+
} else {
|
|
221
|
+
$("#red-ui-sidebar-debug-pause i").removeClass("fa-play").addClass("fa-pause");
|
|
222
|
+
pauseTooltip.setAction("core:pause-debug-messages");
|
|
223
|
+
pauseTooltip.setContent(RED._('node-red:debug.sidebar.pause'))
|
|
224
|
+
$("#red-ui-sidebar-debug-info").text("");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
188
228
|
toolbar.find("#red-ui-sidebar-debug-clear").on("click", function(e) {
|
|
189
229
|
e.preventDefault();
|
|
190
230
|
var action = RED.settings.get("debug.clearType","all")
|
|
@@ -389,15 +429,20 @@ RED.debug = (function() {
|
|
|
389
429
|
var stack = [];
|
|
390
430
|
var busy = false;
|
|
391
431
|
function handleDebugMessage(o) {
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
busy
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
432
|
+
if (!debugPaused) {
|
|
433
|
+
if (o) { stack.push(o); }
|
|
434
|
+
if (!busy && (stack.length > 0)) {
|
|
435
|
+
busy = true;
|
|
436
|
+
processDebugMessage(stack.shift());
|
|
437
|
+
setTimeout(function() {
|
|
438
|
+
busy = false;
|
|
439
|
+
handleDebugMessage();
|
|
440
|
+
}, 15); // every 15mS = 66 times a second
|
|
441
|
+
if (stack.length > numMessages) { stack = stack.splice(-numMessages); }
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
debugPausedMessageCount++
|
|
445
|
+
debugPausedMessage.find('.red-ui-debug-msg-name').last().text(RED._("node-red:debug.sidebar.messagesDropped",{count:debugPausedMessageCount}));
|
|
401
446
|
}
|
|
402
447
|
}
|
|
403
448
|
|
|
@@ -598,6 +643,9 @@ RED.debug = (function() {
|
|
|
598
643
|
} else {
|
|
599
644
|
$(".red-ui-debug-msg:not(.hide)").remove();
|
|
600
645
|
}
|
|
646
|
+
if (debugPaused) {
|
|
647
|
+
messageList.append(debugPausedMessage);
|
|
648
|
+
}
|
|
601
649
|
config.clear();
|
|
602
650
|
if (!!clearFilter) {
|
|
603
651
|
clearFilterSettings();
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
<label></label>
|
|
64
64
|
<select id="node-input-rate-type" style="width:270px !important">
|
|
65
65
|
<option value="all" data-i18n="delay.limitall"></option>
|
|
66
|
+
<option value="burst" data-i18n="delay.limitburst"></option>
|
|
66
67
|
<option value="topic" data-i18n="delay.limittopic"></option>
|
|
67
68
|
</select>
|
|
68
69
|
</div>
|
|
@@ -185,6 +186,8 @@
|
|
|
185
186
|
return this._("delay.label.limit")+" "+rate;
|
|
186
187
|
} else if (this.pauseType == "timed") {
|
|
187
188
|
return this._("delay.label.limitTopic")+" "+rate;
|
|
189
|
+
} else if (this.pauseType == "burst") {
|
|
190
|
+
return this._("delay.label.burst")+" "+rate;
|
|
188
191
|
} else {
|
|
189
192
|
return this._("delay.label.limitTopic")+" "+rate;
|
|
190
193
|
}
|
|
@@ -245,6 +248,9 @@
|
|
|
245
248
|
$("#node-input-delay-action").val('rate');
|
|
246
249
|
$("#node-input-rate-type").val('topic');
|
|
247
250
|
$("#node-input-rate-topic-type").val('timed');
|
|
251
|
+
} else if (this.pauseType == "burst") {
|
|
252
|
+
$("#node-input-delay-action").val('rate');
|
|
253
|
+
$("#node-input-rate-type").val('burst');
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
if (!this.timeoutUnits) {
|
|
@@ -294,12 +300,17 @@
|
|
|
294
300
|
if (this.value === "all") {
|
|
295
301
|
$("#rate-details-per-topic").hide();
|
|
296
302
|
$("#node-input-drop-select-queue").attr('disabled', false);
|
|
303
|
+
$("#rate-override").show();
|
|
304
|
+
} else if (this.value === "burst") {
|
|
305
|
+
$("#rate-details-per-topic").hide();
|
|
306
|
+
$("#node-input-drop-select-queue").attr('disabled', true);
|
|
307
|
+
$("#rate-override").hide();
|
|
297
308
|
} else if (this.value === "topic") {
|
|
298
309
|
if ($("#node-input-drop-select").val() === "queue") {
|
|
299
|
-
$("#node-input-drop-select").val("drop");
|
|
300
310
|
}
|
|
301
311
|
$("#node-input-drop-select-queue").attr('disabled', true);
|
|
302
312
|
$("#rate-details-per-topic").show();
|
|
313
|
+
$("#rate-override").show();
|
|
303
314
|
}
|
|
304
315
|
}).trigger("change");
|
|
305
316
|
},
|
|
@@ -312,6 +323,8 @@
|
|
|
312
323
|
action = $("#node-input-rate-type").val();
|
|
313
324
|
if (action === "all") {
|
|
314
325
|
this.pauseType = "rate";
|
|
326
|
+
} else if (action === "burst") {
|
|
327
|
+
this.pauseType = "burst";
|
|
315
328
|
} else {
|
|
316
329
|
this.pauseType = $("#node-input-rate-topic-type").val();
|
|
317
330
|
}
|
|
@@ -42,6 +42,7 @@ module.exports = function(RED) {
|
|
|
42
42
|
this.timeoutUnits = n.timeoutUnits;
|
|
43
43
|
this.randomUnits = n.randomUnits;
|
|
44
44
|
this.rateUnits = n.rateUnits;
|
|
45
|
+
this.burst = n.rate;
|
|
45
46
|
|
|
46
47
|
if (n.timeoutUnits === "milliseconds") {
|
|
47
48
|
this.timeout = n.timeout;
|
|
@@ -57,12 +58,16 @@ module.exports = function(RED) {
|
|
|
57
58
|
|
|
58
59
|
if (n.rateUnits === "minute") {
|
|
59
60
|
this.rate = (60 * 1000)/n.rate;
|
|
61
|
+
this.timer = n.nbRateUnits * (60 * 1000);
|
|
60
62
|
} else if (n.rateUnits === "hour") {
|
|
61
63
|
this.rate = (60 * 60 * 1000)/n.rate;
|
|
64
|
+
this.timer = n.nbRateUnits * (60 * 60 * 1000);
|
|
62
65
|
} else if (n.rateUnits === "day") {
|
|
63
66
|
this.rate = (24 * 60 * 60 * 1000)/n.rate;
|
|
67
|
+
this.timer = n.nbRateUnits * (24 * 60 * 60 * 1000);
|
|
64
68
|
} else { // Default to seconds
|
|
65
69
|
this.rate = 1000/n.rate;
|
|
70
|
+
this.timer = n.nbRateUnits * 1000;
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
this.rate *= (n.nbRateUnits > 0 ? n.nbRateUnits : 1);
|
|
@@ -192,7 +197,8 @@ module.exports = function(RED) {
|
|
|
192
197
|
}
|
|
193
198
|
done();
|
|
194
199
|
}, delayvar, () => done());
|
|
195
|
-
|
|
200
|
+
if (Object.keys(msg).length === 2 && msg.hasOwnProperty("flush")) { id.clear(); }
|
|
201
|
+
else { node.idList.push(id); }
|
|
196
202
|
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
|
|
197
203
|
if (msg.hasOwnProperty("flush")) { flushDelayList(msg.flush); done(); }
|
|
198
204
|
if (delayvar >= 0) {
|
|
@@ -336,6 +342,42 @@ module.exports = function(RED) {
|
|
|
336
342
|
});
|
|
337
343
|
}
|
|
338
344
|
|
|
345
|
+
// Handle the burst mode
|
|
346
|
+
else if (node.pauseType === "burst") {
|
|
347
|
+
node.timers = [];
|
|
348
|
+
node.inflight = 0;
|
|
349
|
+
node.status({ fill: "green", shape: "ring", text: "" })
|
|
350
|
+
node.on("input", function(msg, send, done) {
|
|
351
|
+
if (msg.hasOwnProperty("reset")) {
|
|
352
|
+
node.timers.forEach((t) => clearTimeout(t));
|
|
353
|
+
node.timers = [];
|
|
354
|
+
node.inflight = 0;
|
|
355
|
+
node.status({ fill: "green", shape: "ring", text: "" });
|
|
356
|
+
done();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (node.inflight < node.burst) {
|
|
360
|
+
node.inflight += 1;
|
|
361
|
+
send(msg);
|
|
362
|
+
node.timers[node.inflight-1] = setTimeout(() => {
|
|
363
|
+
if (node.inflight == node.burst) {
|
|
364
|
+
node.status({ fill: "green", shape: "ring", text: "" });
|
|
365
|
+
}
|
|
366
|
+
node.inflight -= 1;
|
|
367
|
+
}, node.timer);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
if (node.outputs === 2) { send([null,msg]); }
|
|
371
|
+
node.status({ fill: "red", shape: "dot", text: "" });
|
|
372
|
+
}
|
|
373
|
+
done();
|
|
374
|
+
});
|
|
375
|
+
node.on("close", function() {
|
|
376
|
+
node.timers.forEach((t) => clearTimeout(t));
|
|
377
|
+
node.status({});
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
339
381
|
// The topic based fair queue and last arrived on all topics queue
|
|
340
382
|
else if ((node.pauseType === "queue") || (node.pauseType === "timed")) {
|
|
341
383
|
node.intervalID = setInterval(function() {
|
package/core/network/05-tls.html
CHANGED
|
@@ -15,17 +15,18 @@
|
|
|
15
15
|
-->
|
|
16
16
|
|
|
17
17
|
<script type="text/html" data-template-name="tls-config">
|
|
18
|
-
<div class="form-row" class="hide" id="node-config-row-uselocalfiles">
|
|
19
|
-
<input type="checkbox" id="node-config-input-uselocalfiles" style="display: inline-block; width: auto; vertical-align: top;">
|
|
20
|
-
<label for="node-config-input-uselocalfiles" style="width: 70%;"><span data-i18n="tls.label.use-local-files"></label>
|
|
21
|
-
</div>
|
|
22
18
|
<div class="form-row">
|
|
23
19
|
<label style="width: 120px;" for="node-config-input-certType"><i class="fa fa-bars"></i> <span data-i18n="tls.label.certtype"></label>
|
|
24
20
|
<select id="node-config-input-certType">
|
|
25
21
|
<option value="files" data-i18n="tls.label.files"></option>
|
|
26
22
|
<option value="pfx" data-i18n="tls.label.pfx"></option>
|
|
23
|
+
<option value="env" data-i18n="tls.label.env"></option>
|
|
27
24
|
</select>
|
|
28
25
|
</div>
|
|
26
|
+
<div class="form-row" class="hide" id="node-config-row-uselocalfiles">
|
|
27
|
+
<input type="checkbox" id="node-config-input-uselocalfiles" style="display: inline-block; width: auto; vertical-align: top;">
|
|
28
|
+
<label for="node-config-input-uselocalfiles" style="width: 70%;"><span data-i18n="tls.label.use-local-files"></label>
|
|
29
|
+
</div>
|
|
29
30
|
<div class="form-row" id="node-tls-conf-cer">
|
|
30
31
|
<label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label>
|
|
31
32
|
<span class="tls-config-input-data">
|
|
@@ -38,6 +39,10 @@
|
|
|
38
39
|
<input type="hidden" id="node-config-input-certdata">
|
|
39
40
|
<input class="hide tls-config-input-path" style="width: calc(100% - 170px);" type="text" id="node-config-input-cert" data-i18n="[placeholder]tls.placeholder.cert">
|
|
40
41
|
</div>
|
|
42
|
+
<div class="form-row" id="node-tls-conf-cer-env">
|
|
43
|
+
<label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label>
|
|
44
|
+
<input type="text" id="node-config-input-certEnv">
|
|
45
|
+
</div>
|
|
41
46
|
<div class="form-row" id="node-tls-conf-key">
|
|
42
47
|
<label style="width: 120px;" for="node-config-input-key"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.key"></span></label>
|
|
43
48
|
<span class="tls-config-input-data">
|
|
@@ -50,6 +55,10 @@
|
|
|
50
55
|
<input type="hidden" id="node-config-input-keydata">
|
|
51
56
|
<input class="hide tls-config-input-path" style="width: calc(100% - 170px);" type="text" id="node-config-input-key" data-i18n="[placeholder]tls.placeholder.key">
|
|
52
57
|
</div>
|
|
58
|
+
<div class="form-row" id="node-tls-conf-key-env">
|
|
59
|
+
<label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.key"></span></label>
|
|
60
|
+
<input type="text" id="node-config-input-keyEnv">
|
|
61
|
+
</div>
|
|
53
62
|
<div class="form-row" id="node-tls-conf-p12">
|
|
54
63
|
<label style="width: 120px;" for="node-config-input-p12"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.p12"></span></label>
|
|
55
64
|
<span class="tls-config-input-data">
|
|
@@ -78,6 +87,10 @@
|
|
|
78
87
|
<input type="hidden" id="node-config-input-cadata">
|
|
79
88
|
<input class="hide tls-config-input-path" style="width: calc(100% - 170px);" type="text" id="node-config-input-ca" data-i18n="[placeholder]tls.placeholder.ca">
|
|
80
89
|
</div>
|
|
90
|
+
<div class="form-row" id="node-tls-conf-ca-env">
|
|
91
|
+
<label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.ca"></span></label>
|
|
92
|
+
<input type="text" id="node-config-input-caEnv">
|
|
93
|
+
</div>
|
|
81
94
|
<div class="form-row">
|
|
82
95
|
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
|
|
83
96
|
<label for="node-config-input-verifyservercert" style="width: calc(100% - 170px);" data-i18n="tls.label.verify-server-cert"></label>
|
|
@@ -131,7 +144,10 @@
|
|
|
131
144
|
caname: {value:""},
|
|
132
145
|
servername: {value:""},
|
|
133
146
|
verifyservercert: {value: true},
|
|
134
|
-
alpnprotocol: {value: ""}
|
|
147
|
+
alpnprotocol: {value: ""},
|
|
148
|
+
certEnv: {value: ""},
|
|
149
|
+
keyEnv: {value: ""},
|
|
150
|
+
caEnv: {value: ""}
|
|
135
151
|
},
|
|
136
152
|
credentials: {
|
|
137
153
|
certdata: {type:"text"},
|
|
@@ -152,15 +168,45 @@
|
|
|
152
168
|
$("#node-tls-conf-cer").hide();
|
|
153
169
|
$("#node-tls-conf-key").hide();
|
|
154
170
|
$("#node-tls-conf-ca").hide();
|
|
171
|
+
$("#node-tls-conf-cer-env").hide();
|
|
172
|
+
$("#node-tls-conf-key-env").hide();
|
|
173
|
+
$("#node-tls-conf-ca-env").hide();
|
|
155
174
|
$("#node-tls-conf-p12").show();
|
|
175
|
+
$("#node-config-row-uselocalfiles").show();
|
|
156
176
|
}
|
|
157
|
-
else {
|
|
177
|
+
else if ($("#node-config-input-certType").val() === "env") {
|
|
178
|
+
$("#node-tls-conf-cer").hide();
|
|
179
|
+
$("#node-tls-conf-key").hide();
|
|
180
|
+
$("#node-tls-conf-ca").hide();
|
|
181
|
+
$("#node-tls-conf-cer-env").show();
|
|
182
|
+
$("#node-tls-conf-key-env").show();
|
|
183
|
+
$("#node-tls-conf-ca-env").show();
|
|
184
|
+
$("#node-tls-conf-p12").hide();
|
|
185
|
+
$("#node-config-row-uselocalfiles").hide();
|
|
186
|
+
} else {
|
|
158
187
|
$("#node-tls-conf-cer").show();
|
|
159
188
|
$("#node-tls-conf-key").show();
|
|
160
189
|
$("#node-tls-conf-ca").show();
|
|
190
|
+
$("#node-tls-conf-cer-env").hide();
|
|
191
|
+
$("#node-tls-conf-key-env").hide();
|
|
192
|
+
$("#node-tls-conf-ca-env").hide();
|
|
161
193
|
$("#node-tls-conf-p12").hide();
|
|
194
|
+
$("#node-config-row-uselocalfiles").show();
|
|
162
195
|
}
|
|
163
196
|
});
|
|
197
|
+
|
|
198
|
+
$("#node-config-input-certEnv").typedInput({
|
|
199
|
+
type:"env",
|
|
200
|
+
types:["env"]
|
|
201
|
+
});
|
|
202
|
+
$("#node-config-input-keyEnv").typedInput({
|
|
203
|
+
type:"env",
|
|
204
|
+
types:["env"]
|
|
205
|
+
});
|
|
206
|
+
$("#node-config-input-caEnv").typedInput({
|
|
207
|
+
type:"env",
|
|
208
|
+
types:["env"]
|
|
209
|
+
});
|
|
164
210
|
|
|
165
211
|
function updateFileUpload() {
|
|
166
212
|
if ($("#node-config-input-uselocalfiles").is(':checked')) {
|
|
@@ -218,15 +264,19 @@
|
|
|
218
264
|
$("#tls-config-button-cert-clear").on("click", function() {
|
|
219
265
|
clearNameData("cert");
|
|
220
266
|
});
|
|
267
|
+
RED.popover.tooltip($("#tls-config-button-cert-clear"), RED._("common.label.delete"));
|
|
221
268
|
$("#tls-config-button-key-clear").on("click", function() {
|
|
222
269
|
clearNameData("key");
|
|
223
270
|
});
|
|
271
|
+
RED.popover.tooltip($("#tls-config-button-key-clear"), RED._("common.label.delete"));
|
|
224
272
|
$("#tls-config-button-ca-clear").on("click", function() {
|
|
225
273
|
clearNameData("ca");
|
|
226
274
|
});
|
|
275
|
+
RED.popover.tooltip($("#tls-config-button-ca-clear"), RED._("common.label.delete"));
|
|
227
276
|
$("#tls-config-button-p12-clear").on("click", function() {
|
|
228
277
|
clearNameData("p12");
|
|
229
278
|
});
|
|
279
|
+
RED.popover.tooltip($("#tls-config-button-p12-clear"), RED._("common.label.delete"));
|
|
230
280
|
|
|
231
281
|
if (RED.settings.tlsConfigDisableLocalFiles) {
|
|
232
282
|
$("#node-config-row-uselocalfiles").hide();
|
package/core/network/05-tls.js
CHANGED
|
@@ -23,10 +23,14 @@ module.exports = function(RED) {
|
|
|
23
23
|
this.valid = true;
|
|
24
24
|
this.verifyservercert = n.verifyservercert;
|
|
25
25
|
var certPath, keyPath, caPath, p12Path;
|
|
26
|
+
var certEnv, keyEnv, caEnv;
|
|
26
27
|
if (n.cert) { certPath = n.cert.trim(); }
|
|
27
28
|
if (n.key) { keyPath = n.key.trim(); }
|
|
28
29
|
if (n.ca) { caPath = n.ca.trim(); }
|
|
29
30
|
if (n.p12) { p12Path = n.p12.trim(); }
|
|
31
|
+
if (n.certEnv) { certEnv = n.certEnv }
|
|
32
|
+
if (n.keyEnv) { keyEnv = n.keyEnv }
|
|
33
|
+
if (n.caEnv) { caEnv = n.caEnv }
|
|
30
34
|
this.certType = n.certType || "files";
|
|
31
35
|
this.servername = (n.servername||"").trim();
|
|
32
36
|
this.alpnprotocol = (n.alpnprotocol||"").trim();
|
|
@@ -41,13 +45,23 @@ module.exports = function(RED) {
|
|
|
41
45
|
return;
|
|
42
46
|
}
|
|
43
47
|
}
|
|
48
|
+
else if (this.certType === "env") {
|
|
49
|
+
if (certEnv) {
|
|
50
|
+
this.certEnv = Buffer.from(RED.util.evaluateNodeProperty(certEnv, 'env', this))
|
|
51
|
+
}
|
|
52
|
+
if (keyEnv) {
|
|
53
|
+
this.keyEnv = Buffer.from(RED.util.evaluateNodeProperty(keyEnv, 'env', this))
|
|
54
|
+
}
|
|
55
|
+
if (caEnv) {
|
|
56
|
+
this.caEnv = Buffer.from(RED.util.evaluateNodeProperty(caEnv, 'env', this))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
44
59
|
else if ((certPath && certPath.length > 0) || (keyPath && keyPath.length > 0) || (caPath && caPath.length > 0)) {
|
|
45
60
|
if ( (certPath && certPath.length > 0) !== (keyPath && keyPath.length > 0)) {
|
|
46
61
|
this.valid = false;
|
|
47
62
|
this.error(RED._("tls.error.missing-file"));
|
|
48
63
|
return;
|
|
49
64
|
}
|
|
50
|
-
|
|
51
65
|
try {
|
|
52
66
|
if (certPath) {
|
|
53
67
|
this.cert = fs.readFileSync(certPath);
|
|
@@ -122,6 +136,17 @@ module.exports = function(RED) {
|
|
|
122
136
|
opts.ca = this.ca;
|
|
123
137
|
}
|
|
124
138
|
}
|
|
139
|
+
else if (this.certType === "env") {
|
|
140
|
+
if (this.keyEnv) {
|
|
141
|
+
opts.key = this.keyEnv
|
|
142
|
+
}
|
|
143
|
+
if (this.certEnv) {
|
|
144
|
+
opts.cert= this.certEnv
|
|
145
|
+
}
|
|
146
|
+
if (this.caEnv) {
|
|
147
|
+
opts.ca = this.caEnv
|
|
148
|
+
}
|
|
149
|
+
}
|
|
125
150
|
else {
|
|
126
151
|
if (this.pfx) {
|
|
127
152
|
opts.pfx = this.pfx;
|
|
@@ -143,15 +143,6 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
/**
|
|
147
|
-
* @param {Object} headersObject
|
|
148
|
-
* @param {string} name
|
|
149
|
-
* @return {any} value
|
|
150
|
-
*/
|
|
151
|
-
const getHeaderValue = (headersObject, name) => {
|
|
152
|
-
const asLowercase = name.toLowercase();
|
|
153
|
-
return headersObject[Object.keys(headersObject).find(k => k.toLowerCase() === asLowercase)];
|
|
154
|
-
}
|
|
155
146
|
this.count = 0;
|
|
156
147
|
this.on("input",function(msg,nodeSend,nodeDone) {
|
|
157
148
|
node.count++;
|
|
@@ -256,34 +247,42 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
256
247
|
opts.hooks = {
|
|
257
248
|
beforeRequest: [
|
|
258
249
|
options => {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
250
|
+
try {
|
|
251
|
+
// Whilst HTTP headers are meant to be case-insensitive,
|
|
252
|
+
// in the real world, there are servers that aren't so compliant.
|
|
253
|
+
// GOT will lower case all headers given a chance, so we need
|
|
254
|
+
// to restore the case of any headers the user has set.
|
|
255
|
+
Object.keys(options.headers).forEach(h => {
|
|
256
|
+
if (originalHeaderMap[h] && originalHeaderMap[h] !== h) {
|
|
257
|
+
options.headers[originalHeaderMap[h]] = options.headers[h];
|
|
258
|
+
delete options.headers[h];
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
if (node.insecureHTTPParser) {
|
|
262
|
+
// Setting the property under _unixOptions as pretty
|
|
263
|
+
// much the only hack available to get got to apply
|
|
264
|
+
// a core http option it doesn't think we should be
|
|
265
|
+
// allowed to set
|
|
266
|
+
options._unixOptions = { ...options.unixOptions, insecureHTTPParser: true }
|
|
267
267
|
}
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
// Setting the property under _unixOptions as pretty
|
|
271
|
-
// much the only hack available to get got to apply
|
|
272
|
-
// a core http option it doesn't think we should be
|
|
273
|
-
// allowed to set
|
|
274
|
-
options._unixOptions = { ...options.unixOptions, insecureHTTPParser: true }
|
|
268
|
+
} catch (err) {
|
|
269
|
+
node.warn("Error in beforeRequest hook: " + err.message);
|
|
275
270
|
}
|
|
276
271
|
}
|
|
277
272
|
],
|
|
278
273
|
beforeRedirect: [
|
|
279
274
|
(options, response) => {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
275
|
+
try {
|
|
276
|
+
let redirectInfo = {
|
|
277
|
+
location: response.headers.location
|
|
278
|
+
}
|
|
279
|
+
if (response.headers.hasOwnProperty('set-cookie')) {
|
|
280
|
+
redirectInfo.cookies = extractCookies(response.headers['set-cookie']);
|
|
281
|
+
}
|
|
282
|
+
redirectList.push(redirectInfo)
|
|
283
|
+
} catch (err) {
|
|
284
|
+
node.warn("Error processing redirect: " + err.message);
|
|
285
285
|
}
|
|
286
|
-
redirectList.push(redirectInfo)
|
|
287
286
|
}
|
|
288
287
|
]
|
|
289
288
|
}
|
|
@@ -422,25 +421,30 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
422
421
|
let digestCreds = this.credentials;
|
|
423
422
|
let sentCreds = false;
|
|
424
423
|
opts.hooks.afterResponse = [(response, retry) => {
|
|
425
|
-
|
|
426
|
-
if (
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
424
|
+
try {
|
|
425
|
+
if (response.statusCode === 401) {
|
|
426
|
+
if (sentCreds) {
|
|
427
|
+
return response
|
|
428
|
+
}
|
|
429
|
+
const requestUrl = new URL(response.request.requestUrl);
|
|
430
|
+
const options = { headers: {} }
|
|
431
|
+
const normalisedHeaders = {};
|
|
432
|
+
Object.keys(response.headers).forEach(k => {
|
|
433
|
+
normalisedHeaders[k.toLowerCase()] = response.headers[k]
|
|
434
|
+
})
|
|
435
|
+
if (normalisedHeaders['www-authenticate']) {
|
|
436
|
+
let authHeader = buildDigestHeader(digestCreds.user,digestCreds.password, response.request.options.method, requestUrl.pathname + requestUrl.search, normalisedHeaders['www-authenticate'])
|
|
437
|
+
options.headers.Authorization = authHeader;
|
|
438
|
+
}
|
|
439
|
+
// response.request.options.merge(options)
|
|
440
|
+
sentCreds = true;
|
|
441
|
+
return retry(options);
|
|
438
442
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
443
|
+
return response
|
|
444
|
+
} catch (err) {
|
|
445
|
+
node.warn("Digest authentication failed: " + err.message);
|
|
446
|
+
return response;
|
|
442
447
|
}
|
|
443
|
-
return response
|
|
444
448
|
}];
|
|
445
449
|
} else if (this.authType === "bearer") {
|
|
446
450
|
opts.headers.Authorization = `Bearer ${this.credentials.password||""}`
|
|
@@ -688,6 +692,7 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
688
692
|
if (!sendErrorsToCatch) {
|
|
689
693
|
nodeSend(msg);
|
|
690
694
|
}
|
|
695
|
+
node.count--;
|
|
691
696
|
nodeDone();
|
|
692
697
|
});
|
|
693
698
|
});
|
|
@@ -720,13 +725,29 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
720
725
|
|
|
721
726
|
function extractCookies(setCookie) {
|
|
722
727
|
var cookies = {};
|
|
728
|
+
if (!Array.isArray(setCookie)) {
|
|
729
|
+
return cookies;
|
|
730
|
+
}
|
|
723
731
|
setCookie.forEach(function(c) {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
732
|
+
try {
|
|
733
|
+
if (typeof c !== 'string') {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
var parsedCookie = cookie.parse(c);
|
|
737
|
+
var eq_idx = c.indexOf('=');
|
|
738
|
+
if (eq_idx === -1) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
var key = c.substr(0, eq_idx).trim()
|
|
742
|
+
if (!key) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
parsedCookie.value = parsedCookie[key];
|
|
746
|
+
delete parsedCookie[key];
|
|
747
|
+
cookies[key] = parsedCookie;
|
|
748
|
+
} catch (err) {
|
|
749
|
+
// Skip malformed cookies
|
|
750
|
+
}
|
|
730
751
|
});
|
|
731
752
|
return cookies;
|
|
732
753
|
}
|
|
@@ -778,6 +799,9 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
778
799
|
}
|
|
779
800
|
|
|
780
801
|
function buildDigestHeader(user, pass, method, path, authHeader) {
|
|
802
|
+
if (!authHeader || typeof authHeader !== 'string') {
|
|
803
|
+
throw new Error("Invalid or missing WWW-Authenticate header");
|
|
804
|
+
}
|
|
781
805
|
var challenge = {}
|
|
782
806
|
var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
|
|
783
807
|
for (;;) {
|
|
@@ -787,6 +811,12 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|
|
787
811
|
}
|
|
788
812
|
challenge[match[1]] = match[2] || match[3]
|
|
789
813
|
}
|
|
814
|
+
if (!challenge.nonce) {
|
|
815
|
+
throw new Error("Invalid digest challenge: missing nonce");
|
|
816
|
+
}
|
|
817
|
+
if (!challenge.realm) {
|
|
818
|
+
throw new Error("Invalid digest challenge: missing realm");
|
|
819
|
+
}
|
|
790
820
|
var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
|
|
791
821
|
var nc = qop && '00000001'
|
|
792
822
|
var cnonce = qop && uuid().replace(/-/g, '')
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<script type="text/html" data-template-name="file">
|
|
3
3
|
<div class="form-row node-input-filename">
|
|
4
4
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
|
5
|
-
<input id="node-input-filename" type="text">
|
|
5
|
+
<input id="node-input-filename" type="text" style="width: 100% !important;">
|
|
6
6
|
<input type="hidden" id="node-input-filenameType">
|
|
7
7
|
</div>
|
|
8
8
|
<div class="form-row">
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<script type="text/html" data-template-name="file in">
|
|
39
39
|
<div class="form-row">
|
|
40
40
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
|
41
|
-
<input id="node-input-filename" type="text">
|
|
41
|
+
<input id="node-input-filename" type="text" style="width: 100% !important;">
|
|
42
42
|
<input type="hidden" id="node-input-filenameType">
|
|
43
43
|
</div>
|
|
44
44
|
<div class="form-row">
|
package/locales/de/messages.json
CHANGED
|
@@ -149,7 +149,10 @@
|
|
|
149
149
|
"openWindow": "In neuem Fenster öffnen",
|
|
150
150
|
"copyPath": "Pfad kopieren",
|
|
151
151
|
"copyPayload": "Wert kopieren",
|
|
152
|
-
"pinPath": "Angezeigt lassen (pinnen)"
|
|
152
|
+
"pinPath": "Angezeigt lassen (pinnen)",
|
|
153
|
+
"pause": "pause",
|
|
154
|
+
"paused": "Pausiert",
|
|
155
|
+
"resume": "weiter"
|
|
153
156
|
},
|
|
154
157
|
"messageMenu": {
|
|
155
158
|
"collapseAll": "Alle Pfade ausblenden",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
<script type="text/html" data-help-name="delay">
|
|
18
18
|
<p>Delays each message passing through the node or limits the rate at which they can pass.</p>
|
|
19
|
+
<p>Not all input parameters apply to all modes.</p>
|
|
19
20
|
<h3>Inputs</h3>
|
|
20
21
|
<dl class="message-properties">
|
|
21
22
|
<dt class="optional">delay <span class="property-type">number</span></dt>
|
|
@@ -47,9 +48,11 @@
|
|
|
47
48
|
Each message is delayed independently of any other message, based on
|
|
48
49
|
the time of its arrival.
|
|
49
50
|
</p>
|
|
50
|
-
<p>When configured to rate limit messages,
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
<p>When configured to rate limit messages, the node can operate in several modes.
|
|
52
|
+
By default the messages are delivered evenly spread across
|
|
53
|
+
the configured time period. e.g. 3 msgs in 12 seconds means 1 message every 4 seconds.
|
|
54
|
+
The status shows the number of messages currently in the queue.
|
|
55
|
+
It can optionally discard intermediate messages as they arrive.
|
|
53
56
|
</p>
|
|
54
57
|
<p>If set to allow override of the rate, the new rate will be applied immediately,
|
|
55
58
|
and will remain in effect until changed again, the node is reset, or the flow is restarted.</p>
|
|
@@ -59,6 +62,12 @@
|
|
|
59
62
|
the most recent message for all topics, or release the most recent message
|
|
60
63
|
for the next topic.
|
|
61
64
|
</p>
|
|
65
|
+
<p>In burst mode, messages are passed through up to the configured limit immediately,
|
|
66
|
+
any further messages will be dropped or sent to the second output until the time
|
|
67
|
+
period has elapsed. At that point the next burst of messages can be sent.
|
|
68
|
+
The status shows green when messages can be sent immediately, and red when
|
|
69
|
+
messages are blocked.
|
|
70
|
+
</p>
|
|
62
71
|
<p><b>Note</b>: In rate limit mode the maximum queue depth can be set by a property in your
|
|
63
72
|
<i>settings.js</i> file. For example <code>nodeMessageBufferMaxLength: 1000,</code></p>
|
|
64
73
|
</script>
|
|
@@ -166,7 +166,12 @@
|
|
|
166
166
|
"selectAll": "select all",
|
|
167
167
|
"selectNone": "select none",
|
|
168
168
|
"all": "all",
|
|
169
|
-
"filtered": "filtered"
|
|
169
|
+
"filtered": "filtered",
|
|
170
|
+
"pause": "pause",
|
|
171
|
+
"paused": "Paused",
|
|
172
|
+
"resume": "resume",
|
|
173
|
+
"messagesDropped": "__count__ message dropped",
|
|
174
|
+
"messagesDropped_plural": "__count__ messages dropped"
|
|
170
175
|
},
|
|
171
176
|
"messageMenu": {
|
|
172
177
|
"collapseAll": "Collapse all paths",
|
|
@@ -208,7 +213,8 @@
|
|
|
208
213
|
"certtype": "Cert Type",
|
|
209
214
|
"files": "Individual files",
|
|
210
215
|
"p12": "pfx or p12",
|
|
211
|
-
"pfx": "pfx or p12 file"
|
|
216
|
+
"pfx": "pfx or p12 file",
|
|
217
|
+
"env": "Environment Variable"
|
|
212
218
|
},
|
|
213
219
|
"placeholder": {
|
|
214
220
|
"cert": "path to certificate (PEM format)",
|
|
@@ -308,7 +314,8 @@
|
|
|
308
314
|
"delayvarmsg": "Override delay with msg.delay",
|
|
309
315
|
"randomdelay": "Random delay",
|
|
310
316
|
"limitrate": "Rate Limit",
|
|
311
|
-
"limitall": "All messages",
|
|
317
|
+
"limitall": "All messages - even spacing",
|
|
318
|
+
"limitburst": "All messages - burst mode",
|
|
312
319
|
"limittopic": "For each msg.topic",
|
|
313
320
|
"fairqueue": "Send each topic in turn",
|
|
314
321
|
"timedqueue": "Send all topics",
|
|
@@ -332,6 +339,7 @@
|
|
|
332
339
|
"label": {
|
|
333
340
|
"delay": "delay",
|
|
334
341
|
"variable": "variable",
|
|
342
|
+
"burst": "burst",
|
|
335
343
|
"limit": "limit",
|
|
336
344
|
"limitTopic": "limit topic",
|
|
337
345
|
"random": "random",
|
|
@@ -166,7 +166,10 @@
|
|
|
166
166
|
"selectAll": "seleccionar todo",
|
|
167
167
|
"selectNone": "seleccionar ninguno",
|
|
168
168
|
"all": "todo",
|
|
169
|
-
"filtered": "filtrado"
|
|
169
|
+
"filtered": "filtrado",
|
|
170
|
+
"pause": "pausa",
|
|
171
|
+
"paused": "Pausado",
|
|
172
|
+
"resume": "reanudar"
|
|
170
173
|
},
|
|
171
174
|
"messageMenu": {
|
|
172
175
|
"collapseAll": "Colapsar todas las rutas",
|
package/locales/fr/messages.json
CHANGED
|
@@ -166,7 +166,10 @@
|
|
|
166
166
|
"selectAll": "Tout sélectionner",
|
|
167
167
|
"selectNone": "Ne rien sélectionner",
|
|
168
168
|
"all": "Tout",
|
|
169
|
-
"filtered": "Filtrés"
|
|
169
|
+
"filtered": "Filtrés",
|
|
170
|
+
"pause": "pause",
|
|
171
|
+
"paused": "Interrompue",
|
|
172
|
+
"resume": "continuer"
|
|
170
173
|
},
|
|
171
174
|
"messageMenu": {
|
|
172
175
|
"collapseAll": "Réduire tous les chemins",
|
package/locales/ja/messages.json
CHANGED
|
@@ -166,7 +166,10 @@
|
|
|
166
166
|
"selectAll": "全てを選択",
|
|
167
167
|
"selectNone": "選択を外す",
|
|
168
168
|
"all": "全て",
|
|
169
|
-
"filtered": "選択したメッセージ"
|
|
169
|
+
"filtered": "選択したメッセージ",
|
|
170
|
+
"pause": "一時停止",
|
|
171
|
+
"paused": "一時停止",
|
|
172
|
+
"resume": "再開"
|
|
170
173
|
},
|
|
171
174
|
"messageMenu": {
|
|
172
175
|
"collapseAll": "全パスを折りたたむ",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-red/nodes",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"acorn": "8.15.0",
|
|
19
19
|
"acorn-walk": "8.3.4",
|
|
20
20
|
"ajv": "8.17.1",
|
|
21
|
-
"body-parser": "1.20.
|
|
21
|
+
"body-parser": "1.20.4",
|
|
22
22
|
"cheerio": "1.0.0-rc.10",
|
|
23
23
|
"content-type": "1.0.5",
|
|
24
24
|
"cookie-parser": "1.4.7",
|