node-red-contrib-redis-variable 1.0.0

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.
@@ -0,0 +1,731 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType("redis-variable-config", {
3
+ category: "config",
4
+ defaults: {
5
+ name: { value: "" },
6
+ cluster: { value: false },
7
+ host: { value: "localhost" },
8
+ hostType: { value: "str" },
9
+ hostContext: { value: "" },
10
+ port: { value: 6379 },
11
+ portType: { value: "str" },
12
+ portContext: { value: "" },
13
+ database: { value: 0 },
14
+ databaseType: { value: "str" },
15
+ databaseContext: { value: "" },
16
+ passwordType: { value: "str" },
17
+ passwordContext: { value: "" },
18
+ usernameType: { value: "str" },
19
+ usernameContext: { value: "" },
20
+ // SSL Configuration
21
+ enableTLS: { value: false },
22
+ tlsRejectUnauthorized: { value: true },
23
+ tlsCertType: { value: "str" },
24
+ tlsCertContext: { value: "" },
25
+ tlsKeyType: { value: "str" },
26
+ tlsKeyContext: { value: "" },
27
+ tlsCaType: { value: "str" },
28
+ tlsCaContext: { value: "" },
29
+ options: { value: "{}" },
30
+ optionsType: { value: "json" },
31
+ optionsContext: { value: "" }
32
+ },
33
+ credentials: {
34
+ password: { type: "password" },
35
+ username: { type: "text" },
36
+ tlsCert: { type: "password" },
37
+ tlsKey: { type: "password" },
38
+ tlsCa: { type: "password" }
39
+ },
40
+ label: function () {
41
+ return this.name || "Redis Config (" + (this.host || "localhost") + ":" + (this.port || 6379) + ")";
42
+ },
43
+ oneditprepare: function() {
44
+ var stdTypes = ['str', 'flow', 'global', 'env'];
45
+ var numTypes = ['str', 'flow', 'global', 'env', 'num'];
46
+ var jsonTypes = ['str', 'flow', 'global', 'env', 'json'];
47
+
48
+ // Initialize typedInput for Host
49
+ $("#node-config-input-host-typed").typedInput({
50
+ default: 'str',
51
+ types: stdTypes,
52
+ typeField: "#node-config-input-hostType"
53
+ });
54
+ $("#node-config-input-host-typed").typedInput('type', this.hostType || 'str');
55
+
56
+ if (this.hostType === 'str') {
57
+ $("#node-config-input-host-typed").typedInput('value', this.host || 'localhost');
58
+ } else {
59
+ $("#node-config-input-host-typed").typedInput('value', this.hostContext || '');
60
+ }
61
+
62
+ // Initialize typedInput for Port
63
+ $("#node-config-input-port-typed").typedInput({
64
+ default: 'str',
65
+ types: numTypes,
66
+ typeField: "#node-config-input-portType"
67
+ });
68
+ $("#node-config-input-port-typed").typedInput('type', this.portType || 'str');
69
+
70
+ if (this.portType === 'str') {
71
+ $("#node-config-input-port-typed").typedInput('value', this.port || 6379);
72
+ } else {
73
+ $("#node-config-input-port-typed").typedInput('value', this.portContext || '');
74
+ }
75
+
76
+ // Initialize typedInput for Database
77
+ $("#node-config-input-database-typed").typedInput({
78
+ default: 'str',
79
+ types: numTypes,
80
+ typeField: "#node-config-input-databaseType"
81
+ });
82
+ $("#node-config-input-database-typed").typedInput('type', this.databaseType || 'str');
83
+
84
+ if (this.databaseType === 'str') {
85
+ $("#node-config-input-database-typed").typedInput('value', this.database || 0);
86
+ } else {
87
+ $("#node-config-input-database-typed").typedInput('value', this.databaseContext || '');
88
+ }
89
+
90
+ // Initialize typedInput for Options
91
+ $("#node-config-input-options-typed").typedInput({
92
+ default: 'json',
93
+ types: jsonTypes,
94
+ typeField: "#node-config-input-optionsType"
95
+ });
96
+ $("#node-config-input-options-typed").typedInput('type', this.optionsType || 'json');
97
+
98
+ if (this.optionsType === 'json') {
99
+ $("#node-config-input-options-typed").typedInput('value', this.options || '{}');
100
+ } else {
101
+ $("#node-config-input-options-typed").typedInput('value', this.optionsContext || '');
102
+ }
103
+
104
+ // Password type selection
105
+ if (this.passwordType && this.passwordType !== 'str') {
106
+ $("#node-config-input-password-type").val(this.passwordType);
107
+ $("#node-config-input-password-context").val(this.passwordContext || '');
108
+ } else {
109
+ $("#node-config-input-password-type").val('str');
110
+ }
111
+
112
+ // Username type selection
113
+ if (this.usernameType && this.usernameType !== 'str') {
114
+ $("#node-config-input-username-type").val(this.usernameType);
115
+ $("#node-config-input-username-context").val(this.usernameContext || '');
116
+ } else {
117
+ $("#node-config-input-username-type").val('str');
118
+ }
119
+
120
+ // Password field visibility logic
121
+ var updatePasswordFieldVisibility = function() {
122
+ var passwordType = $("#node-config-input-password-type").val();
123
+
124
+ if (passwordType === 'str') {
125
+ $("#password-str-row").show();
126
+ $("#password-context-row").hide();
127
+ } else {
128
+ $("#password-str-row").hide();
129
+ $("#password-context-row").show();
130
+ }
131
+ };
132
+
133
+ // Username field visibility logic
134
+ var updateUsernameFieldVisibility = function() {
135
+ var usernameType = $("#node-config-input-username-type").val();
136
+
137
+ if (usernameType === 'str') {
138
+ $("#username-str-row").show();
139
+ $("#username-context-row").hide();
140
+ } else {
141
+ $("#username-str-row").hide();
142
+ $("#username-context-row").show();
143
+ }
144
+ };
145
+
146
+ $("#node-config-input-password-type").on("change", updatePasswordFieldVisibility);
147
+ $("#node-config-input-username-type").on("change", updateUsernameFieldVisibility);
148
+
149
+ // Call immediately to set initial state
150
+ updatePasswordFieldVisibility();
151
+ updateUsernameFieldVisibility();
152
+
153
+ // Load existing credentials if available
154
+ if (this.credentials && this.credentials.password) {
155
+ $("#node-config-input-password-visible").val(this.credentials.password);
156
+ $("#node-config-input-password").val(this.credentials.password);
157
+ } else if (this.credentials && this.credentials.has_password) {
158
+ $("#node-config-input-password-visible").attr('placeholder', '••••••••••••••••••••••••••••••••••••••••');
159
+ $("#node-config-input-password-visible").val('');
160
+ }
161
+
162
+ if (this.credentials && this.credentials.username) {
163
+ $("#node-config-input-username-visible").val(this.credentials.username);
164
+ $("#node-config-input-username").val(this.credentials.username);
165
+ }
166
+
167
+ // Sync visible fields with hidden credentials fields
168
+ $("#node-config-input-password-visible").on("input", function() {
169
+ $("#node-config-input-password").val($(this).val());
170
+ });
171
+
172
+ $("#node-config-input-username-visible").on("input", function() {
173
+ $("#node-config-input-username").val($(this).val());
174
+ });
175
+
176
+ // Set cluster checkbox
177
+ $("#node-config-input-cluster").prop('checked', this.cluster === true);
178
+
179
+ // SSL Configuration
180
+ $("#node-config-input-enableTLS").prop('checked', this.enableTLS === true);
181
+ $("#node-config-input-tlsRejectUnauthorized").prop('checked', this.tlsRejectUnauthorized !== false);
182
+
183
+ // TLS Certificate type selection
184
+ if (this.tlsCertType && this.tlsCertType !== 'str') {
185
+ $("#node-config-input-tlsCert-type").val(this.tlsCertType);
186
+ $("#node-config-input-tlsCert-context").val(this.tlsCertContext || '');
187
+ } else {
188
+ $("#node-config-input-tlsCert-type").val('str');
189
+ }
190
+
191
+ // TLS Key type selection
192
+ if (this.tlsKeyType && this.tlsKeyType !== 'str') {
193
+ $("#node-config-input-tlsKey-type").val(this.tlsKeyType);
194
+ $("#node-config-input-tlsKey-context").val(this.tlsKeyContext || '');
195
+ } else {
196
+ $("#node-config-input-tlsKey-type").val('str');
197
+ }
198
+
199
+ // TLS CA type selection
200
+ if (this.tlsCaType && this.tlsCaType !== 'str') {
201
+ $("#node-config-input-tlsCa-type").val(this.tlsCaType);
202
+ $("#node-config-input-tlsCa-context").val(this.tlsCaContext || '');
203
+ } else {
204
+ $("#node-config-input-tlsCa-type").val('str');
205
+ }
206
+
207
+ // SSL field visibility logic
208
+ var updateSSLFieldsVisibility = function() {
209
+ var enableTLS = $("#node-config-input-enableTLS").is(':checked');
210
+
211
+ if (enableTLS) {
212
+ $("#ssl-config-section").show();
213
+ } else {
214
+ $("#ssl-config-section").hide();
215
+ }
216
+ };
217
+
218
+ var updateTLSCertFieldVisibility = function() {
219
+ var certType = $("#node-config-input-tlsCert-type").val();
220
+
221
+ if (certType === 'str') {
222
+ $("#tlsCert-str-row").show();
223
+ $("#tlsCert-context-row").hide();
224
+ } else {
225
+ $("#tlsCert-str-row").hide();
226
+ $("#tlsCert-context-row").show();
227
+ }
228
+ };
229
+
230
+ var updateTLSKeyFieldVisibility = function() {
231
+ var keyType = $("#node-config-input-tlsKey-type").val();
232
+
233
+ if (keyType === 'str') {
234
+ $("#tlsKey-str-row").show();
235
+ $("#tlsKey-context-row").hide();
236
+ } else {
237
+ $("#tlsKey-str-row").hide();
238
+ $("#tlsKey-context-row").show();
239
+ }
240
+ };
241
+
242
+ var updateTLSCaFieldVisibility = function() {
243
+ var caType = $("#node-config-input-tlsCa-type").val();
244
+
245
+ if (caType === 'str') {
246
+ $("#tlsCa-str-row").show();
247
+ $("#tlsCa-context-row").hide();
248
+ } else {
249
+ $("#tlsCa-str-row").hide();
250
+ $("#tlsCa-context-row").show();
251
+ }
252
+ };
253
+
254
+ $("#node-config-input-enableTLS").on("change", updateSSLFieldsVisibility);
255
+ $("#node-config-input-tlsCert-type").on("change", updateTLSCertFieldVisibility);
256
+ $("#node-config-input-tlsKey-type").on("change", updateTLSKeyFieldVisibility);
257
+ $("#node-config-input-tlsCa-type").on("change", updateTLSCaFieldVisibility);
258
+
259
+ // Call immediately to set initial state
260
+ updateSSLFieldsVisibility();
261
+ updateTLSCertFieldVisibility();
262
+ updateTLSKeyFieldVisibility();
263
+ updateTLSCaFieldVisibility();
264
+
265
+ // Load existing TLS credentials if available
266
+ if (this.credentials && this.credentials.tlsCert) {
267
+ $("#node-config-input-tlsCert-visible").val(this.credentials.tlsCert);
268
+ $("#node-config-input-tlsCert").val(this.credentials.tlsCert);
269
+ }
270
+
271
+ if (this.credentials && this.credentials.tlsKey) {
272
+ $("#node-config-input-tlsKey-visible").val(this.credentials.tlsKey);
273
+ $("#node-config-input-tlsKey").val(this.credentials.tlsKey);
274
+ }
275
+
276
+ if (this.credentials && this.credentials.tlsCa) {
277
+ $("#node-config-input-tlsCa-visible").val(this.credentials.tlsCa);
278
+ $("#node-config-input-tlsCa").val(this.credentials.tlsCa);
279
+ }
280
+
281
+ // Sync visible TLS fields with hidden credentials fields
282
+ $("#node-config-input-tlsCert-visible").on("input", function() {
283
+ $("#node-config-input-tlsCert").val($(this).val());
284
+ });
285
+
286
+ $("#node-config-input-tlsKey-visible").on("input", function() {
287
+ $("#node-config-input-tlsKey").val($(this).val());
288
+ });
289
+
290
+ $("#node-config-input-tlsCa-visible").on("input", function() {
291
+ $("#node-config-input-tlsCa").val($(this).val());
292
+ });
293
+ },
294
+ oneditsave: function() {
295
+ // Save basic configuration
296
+ this.name = $("#node-config-input-name").val();
297
+ this.cluster = $("#node-config-input-cluster").is(':checked');
298
+
299
+ // Handle Host (TypedInput logic)
300
+ var hostType = $("#node-config-input-hostType").val();
301
+ var hostValue = $("#node-config-input-host-typed").typedInput('value');
302
+
303
+ this.hostType = hostType;
304
+ if (hostType === 'str') {
305
+ this.host = hostValue || 'localhost';
306
+ this.hostContext = '';
307
+ } else {
308
+ this.host = 'localhost';
309
+ this.hostContext = hostValue || '';
310
+ }
311
+
312
+ // Handle Port (TypedInput logic)
313
+ var portType = $("#node-config-input-portType").val();
314
+ var portValue = $("#node-config-input-port-typed").typedInput('value');
315
+
316
+ this.portType = portType;
317
+ if (portType === 'str') {
318
+ this.port = portValue || 6379;
319
+ this.portContext = '';
320
+ } else {
321
+ this.port = 6379;
322
+ this.portContext = portValue || '';
323
+ }
324
+
325
+ // Handle Database (TypedInput logic)
326
+ var databaseType = $("#node-config-input-databaseType").val();
327
+ var databaseValue = $("#node-config-input-database-typed").typedInput('value');
328
+
329
+ this.databaseType = databaseType;
330
+ if (databaseType === 'str') {
331
+ this.database = databaseValue || 0;
332
+ this.databaseContext = '';
333
+ } else {
334
+ this.database = 0;
335
+ this.databaseContext = databaseValue || '';
336
+ }
337
+
338
+ // Handle Options (TypedInput logic)
339
+ var optionsType = $("#node-config-input-optionsType").val();
340
+ var optionsValue = $("#node-config-input-options-typed").typedInput('value');
341
+
342
+ this.optionsType = optionsType;
343
+ if (optionsType === 'json') {
344
+ this.options = optionsValue || '{}';
345
+ this.optionsContext = '';
346
+ } else {
347
+ this.options = '{}';
348
+ this.optionsContext = optionsValue || '';
349
+ }
350
+
351
+ // Handle Password based on type
352
+ var passwordType = $("#node-config-input-password-type").val();
353
+ this.passwordType = passwordType;
354
+
355
+ if (passwordType === 'str') {
356
+ this.passwordContext = '';
357
+ var visiblePassword = $("#node-config-input-password-visible").val();
358
+ if (visiblePassword) {
359
+ $("#node-config-input-password").val(visiblePassword);
360
+ }
361
+ } else {
362
+ var passwordValue = $("#node-config-input-password-context").val();
363
+ this.passwordContext = passwordValue || '';
364
+ $("#node-config-input-password").val('');
365
+ }
366
+
367
+ // Handle Username based on type
368
+ var usernameType = $("#node-config-input-username-type").val();
369
+ this.usernameType = usernameType;
370
+
371
+ if (usernameType === 'str') {
372
+ this.usernameContext = '';
373
+ var visibleUsername = $("#node-config-input-username-visible").val();
374
+ if (visibleUsername) {
375
+ $("#node-config-input-username").val(visibleUsername);
376
+ }
377
+ } else {
378
+ var usernameValue = $("#node-config-input-username-context").val();
379
+ this.usernameContext = usernameValue || '';
380
+ $("#node-config-input-username").val('');
381
+ }
382
+
383
+ // Handle SSL Configuration
384
+ this.enableTLS = $("#node-config-input-enableTLS").is(':checked');
385
+ this.tlsRejectUnauthorized = $("#node-config-input-tlsRejectUnauthorized").is(':checked');
386
+
387
+ // Handle TLS Certificate based on type
388
+ var tlsCertType = $("#node-config-input-tlsCert-type").val();
389
+ this.tlsCertType = tlsCertType;
390
+
391
+ if (tlsCertType === 'str') {
392
+ this.tlsCertContext = '';
393
+ var visibleTlsCert = $("#node-config-input-tlsCert-visible").val();
394
+ if (visibleTlsCert) {
395
+ $("#node-config-input-tlsCert").val(visibleTlsCert);
396
+ }
397
+ } else {
398
+ var tlsCertValue = $("#node-config-input-tlsCert-context").val();
399
+ this.tlsCertContext = tlsCertValue || '';
400
+ $("#node-config-input-tlsCert").val('');
401
+ }
402
+
403
+ // Handle TLS Key based on type
404
+ var tlsKeyType = $("#node-config-input-tlsKey-type").val();
405
+ this.tlsKeyType = tlsKeyType;
406
+
407
+ if (tlsKeyType === 'str') {
408
+ this.tlsKeyContext = '';
409
+ var visibleTlsKey = $("#node-config-input-tlsKey-visible").val();
410
+ if (visibleTlsKey) {
411
+ $("#node-config-input-tlsKey").val(visibleTlsKey);
412
+ }
413
+ } else {
414
+ var tlsKeyValue = $("#node-config-input-tlsKey-context").val();
415
+ this.tlsKeyContext = tlsKeyValue || '';
416
+ $("#node-config-input-tlsKey").val('');
417
+ }
418
+
419
+ // Handle TLS CA based on type
420
+ var tlsCaType = $("#node-config-input-tlsCa-type").val();
421
+ this.tlsCaType = tlsCaType;
422
+
423
+ if (tlsCaType === 'str') {
424
+ this.tlsCaContext = '';
425
+ var visibleTlsCa = $("#node-config-input-tlsCa-visible").val();
426
+ if (visibleTlsCa) {
427
+ $("#node-config-input-tlsCa").val(visibleTlsCa);
428
+ }
429
+ } else {
430
+ var tlsCaValue = $("#node-config-input-tlsCa-context").val();
431
+ this.tlsCaContext = tlsCaValue || '';
432
+ $("#node-config-input-tlsCa").val('');
433
+ }
434
+ }
435
+ });
436
+ </script>
437
+
438
+ <script type="text/html" data-template-name="redis-variable-config">
439
+ <div class="form-row">
440
+ <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
441
+ <input type="text" id="node-config-input-name" placeholder="Configuration Name" style="width: 70%;">
442
+ </div>
443
+
444
+ <div class="form-row">
445
+ <label for="node-config-input-cluster"><i class="fa fa-sitemap"></i> Cluster Mode</label>
446
+ <input type="checkbox" id="node-config-input-cluster" style="display: inline-block; width: auto; vertical-align: middle;">
447
+ <span style="margin-left: 5px; vertical-align: middle;">Enable Redis Cluster mode</span>
448
+ </div>
449
+
450
+ <div class="form-row">
451
+ <label for="node-config-input-host-typed"><i class="fa fa-server"></i> Host</label>
452
+ <input type="text" id="node-config-input-host-typed" style="width: 70%;">
453
+ <input type="hidden" id="node-config-input-hostType">
454
+ </div>
455
+
456
+ <div class="form-row">
457
+ <label for="node-config-input-port-typed"><i class="fa fa-plug"></i> Port</label>
458
+ <input type="text" id="node-config-input-port-typed" style="width: 70%;">
459
+ <input type="hidden" id="node-config-input-portType">
460
+ </div>
461
+
462
+ <div class="form-row">
463
+ <label for="node-config-input-database-typed"><i class="fa fa-database"></i> Database</label>
464
+ <input type="text" id="node-config-input-database-typed" style="width: 70%;">
465
+ <input type="hidden" id="node-config-input-databaseType">
466
+ </div>
467
+
468
+ <div class="form-row">
469
+ <label for="node-config-input-username-type"><i class="fa fa-user"></i> Username Type</label>
470
+ <select id="node-config-input-username-type" style="width: 70%;">
471
+ <option value="str">Direct Username (secure)</option>
472
+ <option value="flow">Flow Context</option>
473
+ <option value="global">Global Context</option>
474
+ <option value="env">Environment Variable</option>
475
+ </select>
476
+ </div>
477
+
478
+ <div class="form-row" id="username-str-row">
479
+ <label for="node-config-input-username-visible"><i class="fa fa-user"></i> Username</label>
480
+ <input type="text" id="node-config-input-username-visible" style="width: 70%;" placeholder="Redis username (optional)">
481
+ </div>
482
+
483
+ <div class="form-row" id="username-context-row" style="display: none;">
484
+ <label for="node-config-input-username-context"><i class="fa fa-code"></i> Username Variable</label>
485
+ <input type="text" id="node-config-input-username-context" style="width: 70%;" placeholder="Variable name for username">
486
+ </div>
487
+
488
+ <div class="form-row">
489
+ <label for="node-config-input-password-type"><i class="fa fa-key"></i> Password Type</label>
490
+ <select id="node-config-input-password-type" style="width: 70%;">
491
+ <option value="str">Direct Password (secure)</option>
492
+ <option value="flow">Flow Context</option>
493
+ <option value="global">Global Context</option>
494
+ <option value="env">Environment Variable</option>
495
+ </select>
496
+ </div>
497
+
498
+ <div class="form-row" id="password-str-row">
499
+ <label for="node-config-input-password-visible"><i class="fa fa-key"></i> Password</label>
500
+ <input type="password" id="node-config-input-password-visible" style="width: 70%;" placeholder="Redis password (optional)">
501
+ </div>
502
+
503
+ <div class="form-row" id="password-context-row" style="display: none;">
504
+ <label for="node-config-input-password-context"><i class="fa fa-code"></i> Password Variable</label>
505
+ <input type="text" id="node-config-input-password-context" style="width: 70%;" placeholder="Variable name for password">
506
+ </div>
507
+
508
+ <!-- SSL/TLS Configuration -->
509
+ <div class="form-row">
510
+ <label for="node-config-input-enableTLS"><i class="fa fa-lock"></i> Enable SSL/TLS</label>
511
+ <input type="checkbox" id="node-config-input-enableTLS" style="display: inline-block; width: auto; vertical-align: middle;">
512
+ <span style="margin-left: 5px; vertical-align: middle;">Enable secure SSL/TLS connection</span>
513
+ </div>
514
+
515
+ <div id="ssl-config-section" style="display: none;">
516
+ <div class="form-row">
517
+ <label for="node-config-input-tlsRejectUnauthorized"><i class="fa fa-shield"></i> Verify Certificate</label>
518
+ <input type="checkbox" id="node-config-input-tlsRejectUnauthorized" style="display: inline-block; width: auto; vertical-align: middle;" checked>
519
+ <span style="margin-left: 5px; vertical-align: middle;">Reject unauthorized certificates (recommended)</span>
520
+ </div>
521
+
522
+ <div class="form-row">
523
+ <label for="node-config-input-tlsCert-type"><i class="fa fa-certificate"></i> Client Certificate Type</label>
524
+ <select id="node-config-input-tlsCert-type" style="width: 70%;">
525
+ <option value="str">Direct Certificate (secure)</option>
526
+ <option value="flow">Flow Context</option>
527
+ <option value="global">Global Context</option>
528
+ <option value="env">Environment Variable</option>
529
+ </select>
530
+ </div>
531
+
532
+ <div class="form-row" id="tlsCert-str-row">
533
+ <label for="node-config-input-tlsCert-visible"><i class="fa fa-certificate"></i> Client Certificate</label>
534
+ <textarea id="node-config-input-tlsCert-visible" style="width: 70%; height: 80px;" placeholder="-----BEGIN CERTIFICATE-----&#10;...&#10;-----END CERTIFICATE-----"></textarea>
535
+ </div>
536
+
537
+ <div class="form-row" id="tlsCert-context-row" style="display: none;">
538
+ <label for="node-config-input-tlsCert-context"><i class="fa fa-code"></i> Certificate Variable</label>
539
+ <input type="text" id="node-config-input-tlsCert-context" style="width: 70%;" placeholder="Variable name for client certificate">
540
+ </div>
541
+
542
+ <div class="form-row">
543
+ <label for="node-config-input-tlsKey-type"><i class="fa fa-key"></i> Private Key Type</label>
544
+ <select id="node-config-input-tlsKey-type" style="width: 70%;">
545
+ <option value="str">Direct Key (secure)</option>
546
+ <option value="flow">Flow Context</option>
547
+ <option value="global">Global Context</option>
548
+ <option value="env">Environment Variable</option>
549
+ </select>
550
+ </div>
551
+
552
+ <div class="form-row" id="tlsKey-str-row">
553
+ <label for="node-config-input-tlsKey-visible"><i class="fa fa-key"></i> Private Key</label>
554
+ <textarea id="node-config-input-tlsKey-visible" style="width: 70%; height: 80px;" placeholder="-----BEGIN PRIVATE KEY-----&#10;...&#10;-----END PRIVATE KEY-----"></textarea>
555
+ </div>
556
+
557
+ <div class="form-row" id="tlsKey-context-row" style="display: none;">
558
+ <label for="node-config-input-tlsKey-context"><i class="fa fa-code"></i> Private Key Variable</label>
559
+ <input type="text" id="node-config-input-tlsKey-context" style="width: 70%;" placeholder="Variable name for private key">
560
+ </div>
561
+
562
+ <div class="form-row">
563
+ <label for="node-config-input-tlsCa-type"><i class="fa fa-shield"></i> CA Certificate Type</label>
564
+ <select id="node-config-input-tlsCa-type" style="width: 70%;">
565
+ <option value="str">Direct CA Certificate (secure)</option>
566
+ <option value="flow">Flow Context</option>
567
+ <option value="global">Global Context</option>
568
+ <option value="env">Environment Variable</option>
569
+ </select>
570
+ </div>
571
+
572
+ <div class="form-row" id="tlsCa-str-row">
573
+ <label for="node-config-input-tlsCa-visible"><i class="fa fa-shield"></i> CA Certificate</label>
574
+ <textarea id="node-config-input-tlsCa-visible" style="width: 70%; height: 80px;" placeholder="-----BEGIN CERTIFICATE-----&#10;...&#10;-----END CERTIFICATE----- (optional)"></textarea>
575
+ </div>
576
+
577
+ <div class="form-row" id="tlsCa-context-row" style="display: none;">
578
+ <label for="node-config-input-tlsCa-context"><i class="fa fa-code"></i> CA Certificate Variable</label>
579
+ <input type="text" id="node-config-input-tlsCa-context" style="width: 70%;" placeholder="Variable name for CA certificate">
580
+ </div>
581
+ </div>
582
+
583
+ <div class="form-row">
584
+ <label for="node-config-input-options-typed"><i class="fa fa-cogs"></i> Advanced Options</label>
585
+ <input type="text" id="node-config-input-options-typed" style="width: 70%;">
586
+ <input type="hidden" id="node-config-input-optionsType">
587
+ </div>
588
+
589
+ <!-- Hidden fields for Node-RED credentials system -->
590
+ <input type="text" id="node-config-input-username" style="display: none;">
591
+ <input type="password" id="node-config-input-password" style="display: none;">
592
+ <input type="text" id="node-config-input-usernameContext" style="display: none;">
593
+ <input type="text" id="node-config-input-passwordContext" style="display: none;">
594
+ <input type="password" id="node-config-input-tlsCert" style="display: none;">
595
+ <input type="password" id="node-config-input-tlsKey" style="display: none;">
596
+ <input type="password" id="node-config-input-tlsCa" style="display: none;">
597
+ <input type="text" id="node-config-input-tlsCertContext" style="display: none;">
598
+ <input type="text" id="node-config-input-tlsKeyContext" style="display: none;">
599
+ <input type="text" id="node-config-input-tlsCaContext" style="display: none;">
600
+ </script>
601
+
602
+ <script type="text/x-red" data-help-name="redis-variable-config">
603
+ <p>Redis configuration node with flexible connection management:</p>
604
+
605
+ <h3>Connection Settings</h3>
606
+ <ul>
607
+ <li><b>Host</b>: Redis server hostname or IP address</li>
608
+ <li><b>Port</b>: Redis server port (default: 6379)</li>
609
+ <li><b>Database</b>: Redis database number (default: 0)</li>
610
+ <li><b>Cluster Mode</b>: Enable for Redis Cluster deployments</li>
611
+ </ul>
612
+
613
+ <h3>Authentication</h3>
614
+ <ul>
615
+ <li><b>Username</b>: Redis username (Redis 6.0+ ACL support)</li>
616
+ <li><b>Password</b>: Redis password for authentication</li>
617
+ </ul>
618
+
619
+ <h3>Credential Sources</h3>
620
+ <p>All connection parameters support multiple input types:</p>
621
+ <ul>
622
+ <li><b>String</b>: Direct value stored securely in Node-RED credentials</li>
623
+ <li><b>Flow Context</b>: Retrieved from flow context variables</li>
624
+ <li><b>Global Context</b>: Retrieved from global context variables</li>
625
+ <li><b>Environment Variable</b>: Retrieved from environment variables</li>
626
+ </ul>
627
+
628
+ <h3>Advanced Options</h3>
629
+ <p>JSON object with additional ioredis connection options:</p>
630
+ <pre>{
631
+ "connectTimeout": 10000,
632
+ "lazyConnect": true,
633
+ "keepAlive": 30000,
634
+ "family": 4,
635
+ "retryDelayOnFailover": 100
636
+ }</pre>
637
+
638
+ <h3>SSL/TLS Configuration</h3>
639
+ <ul>
640
+ <li><b>Enable SSL/TLS</b>: Enable secure connection to Redis server</li>
641
+ <li><b>Verify Certificate</b>: Validate server certificates (recommended for production)</li>
642
+ <li><b>Client Certificate</b>: Client certificate for mutual TLS authentication</li>
643
+ <li><b>Private Key</b>: Private key corresponding to client certificate</li>
644
+ <li><b>CA Certificate</b>: Certificate Authority certificate for custom CAs</li>
645
+ </ul>
646
+
647
+ <h3>SSL Examples</h3>
648
+ <p><b>Basic SSL (server verification only):</b></p>
649
+ <ul>
650
+ <li>Enable SSL/TLS: ✓</li>
651
+ <li>Verify Certificate: ✓</li>
652
+ <li>Client Certificate: (empty)</li>
653
+ </ul>
654
+
655
+ <p><b>Mutual TLS (client + server authentication):</b></p>
656
+ <ul>
657
+ <li>Enable SSL/TLS: ✓</li>
658
+ <li>Verify Certificate: ✓</li>
659
+ <li>Client Certificate: Your client certificate</li>
660
+ <li>Private Key: Your private key</li>
661
+ <li>CA Certificate: Custom CA if needed</li>
662
+ </ul>
663
+
664
+ <p><b>Self-signed certificates:</b></p>
665
+ <ul>
666
+ <li>Enable SSL/TLS: ✓</li>
667
+ <li>Verify Certificate: ✗ (disable for self-signed)</li>
668
+ <li>CA Certificate: Your self-signed CA</li>
669
+ </ul>
670
+
671
+ <h3>Security Notes</h3>
672
+ <ul>
673
+ <li>String credentials are stored encrypted in Node-RED's credentials store</li>
674
+ <li>Context types only store variable names, actual credentials retrieved at runtime</li>
675
+ <li>Use environment variables for containerized deployments</li>
676
+ <li>Enable Redis AUTH and use strong passwords</li>
677
+ <li>Consider using Redis ACLs for fine-grained access control</li>
678
+ <li><b>SSL/TLS is highly recommended for production environments</b></li>
679
+ <li>Always verify certificates in production unless using trusted self-signed CAs</li>
680
+ <li>Store certificates and keys securely, preferably in environment variables</li>
681
+ </ul>
682
+
683
+ <h3>Examples</h3>
684
+ <p><b>Environment-based configuration:</b></p>
685
+ <ul>
686
+ <li>Host: Environment Variable → <code>REDIS_HOST</code></li>
687
+ <li>Password: Environment Variable → <code>REDIS_PASSWORD</code></li>
688
+ </ul>
689
+
690
+ <p><b>Context-based configuration:</b></p>
691
+ <ul>
692
+ <li>Host: Global Context → <code>redis_config.host</code></li>
693
+ <li>Port: Global Context → <code>redis_config.port</code></li>
694
+ </ul>
695
+ </script>
696
+
697
+ <style>
698
+ .form-row {
699
+ margin-bottom: 10px;
700
+ }
701
+ .form-row label {
702
+ display: inline-block;
703
+ width: 120px;
704
+ vertical-align: top;
705
+ margin-top: 6px;
706
+ }
707
+ .form-row input[type="text"],
708
+ .form-row input[type="password"],
709
+ .form-row select {
710
+ width: 70%;
711
+ }
712
+ .form-row input[type="checkbox"] {
713
+ width: auto;
714
+ margin: 0;
715
+ vertical-align: middle;
716
+ }
717
+ .help-text {
718
+ font-size: 0.8em;
719
+ color: #666;
720
+ margin-top: 4px;
721
+ margin-left: 125px;
722
+ }
723
+ .error-text {
724
+ color: #d00;
725
+ font-size: 0.8em;
726
+ margin-top: 4px;
727
+ }
728
+ .input-error {
729
+ border-color: #d00 !important;
730
+ }
731
+ </style>