1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

UI to upload certificates and keys for TLS, and send them to node red in configuration properties to store them in credentials file

by default upload buttons will be shown unless a cert or key path is already set
added new settings flag called 'tlsDisableLocalFiles' to disable UI for local paths for cloud hosted NR
This commit is contained in:
mblackstock 2017-02-27 13:04:19 -08:00
parent bfcd795687
commit 2bde07561f
5 changed files with 161 additions and 23 deletions

View File

@ -15,17 +15,42 @@
--> -->
<script type="text/x-red" data-template-name="tls-config"> <script type="text/x-red" data-template-name="tls-config">
<div class="form-row" class="hide" id="node-config-row-uselocalfiles">
<input type="checkbox" id="node-config-input-uselocalfiles" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-uselocalfiles" style="width: 70%;"><span data-i18n="tls.label.use-local-files"></label>
</div>
<div class="form-row"> <div class="form-row">
<label style="width: 120px;" for="node-config-input-cert"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label> <label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label>
<input style="width: 60%;" type="text" id="node-config-input-cert" data-i18n="[placeholder]tls.placeholder.cert"> <span class="tls-config-input-data">
<label class="btn ui-button" style="width: 85px; padding: 3px 0px;" for="node-config-input-certfile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" id="node-config-input-certfile">
<span id="tls-config-certname" style="width: 180px; overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
</span>
<input type="hidden" id="node-config-input-certname">
<input type="hidden" id="node-config-input-certdata">
<input class="hide tls-config-input-path" style="width: 60%;" type="text" id="node-config-input-cert" data-i18n="[placeholder]tls.placeholder.cert">
</div> </div>
<div class="form-row"> <div class="form-row">
<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> <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>
<input style="width: 60%;" type="text" id="node-config-input-key" data-i18n="[placeholder]tls.placeholder.key"> <span class="tls-config-input-data">
<label class="btn" style="width: 85px; padding: 3px 0px;" for="node-config-input-keyfile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" id="node-config-input-keyfile">
<span id="tls-config-keyname" style="width: 180px; overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
</span>
<input type="hidden" id="node-config-input-keyname">
<input type="hidden" id="node-config-input-keydata">
<input class="hide tls-config-input-path" style="width: 60%;" type="text" id="node-config-input-key" data-i18n="[placeholder]tls.placeholder.key">
</div> </div>
<div class="form-row"> <div class="form-row">
<label style="width: 120px;" for="node-config-input-ca"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.ca"></span></label> <label style="width: 120px;" for="node-config-input-ca"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.ca"></span></label>
<input style="width: 60%;" type="text" id="node-config-input-ca" data-i18n="[placeholder]tls.placeholder.ca"> <span class="tls-config-input-data">
<label class="btn" style="width: 85px; padding: 3px 0px;" for="node-config-input-cafile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" title=" " id="node-config-input-cafile">
<span id="tls-config-caname" style="width: 180px; overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
</span>
<input type="hidden" id="node-config-input-caname">
<input type="hidden" id="node-config-input-cadata">
<input class="hide tls-config-input-path" style="width: 60%;" type="text" id="node-config-input-ca" data-i18n="[placeholder]tls.placeholder.ca">
</div> </div>
<div class="form-row"> <div class="form-row">
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;"> <input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
@ -61,13 +86,85 @@
return currentCert === '' || v != ''; return currentCert === '' || v != '';
}}, }},
ca: {value:""}, ca: {value:""},
certname: {value:""},
keyname: {value:""},
caname: {value:""},
uselocalfiles: {value:true},
verifyservercert: {value: true} verifyservercert: {value: true}
}, },
credentials: {
certdata: {type:"text"},
keydata: {type:"text"},
cadata: {type:"text"}
},
label: function() { label: function() {
return this.name || this._("tls.tls"); return this.name || this._("tls.tls");
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
},
oneditprepare: function() {
function updateFileUpload() {
if ($("#node-config-input-uselocalfiles").is(':checked')) {
$(".tls-config-input-path").show();
$(".tls-config-input-data").hide();
} else {
$(".tls-config-input-data").show();
$(".tls-config-input-path").hide();
}
}
$("#node-config-input-uselocalfiles").on("click",function() {
updateFileUpload();
});
function saveFile(property, file) {
var dataInputId = "#node-config-input-"+property+"data";
var filenameInputId = "#node-config-input-"+property+"name";
var filename = file.name;
var reader = new FileReader();
reader.onload = function(event) {
$("#tls-config-"+property+"name").text(filename);
$(filenameInputId).val(filename);
$(dataInputId).val(event.target.result);
}
reader.readAsText(file,"UTF-8");
}
$("#node-config-input-certfile" ).change(function() {
saveFile("cert", this.files[0]);
});
$("#node-config-input-keyfile" ).change(function() {
saveFile("key", this.files[0]);
});
$("#node-config-input-cafile" ).change(function() {
saveFile("ca", this.files[0]);
});
if (RED.settings.tlsDisableLocalFiles) {
$("#node-config-row-uselocalfiles").hide();
} else {
$("#node-config-row-uselocalfiles").show();
}
// in case paths were set from old TLS config
if(this.cert || this.key || this.ca) {
this.uselocalfiles = true;
$("#node-config-input-uselocalfiles").prop('checked',true);
}
$("#tls-config-certname").text(this.certname);
$("#tls-config-keyname").text(this.keyname);
$("#tls-config-caname").text(this.caname);
updateFileUpload();
},
oneditsave: function() {
if ($("#node-config-input-uselocalfiles").is(':checked')) {
$("#node-config-input-cadata").val("");
$("#node-config-input-caname").val("");
$("#node-config-input-certdata").val("");
$("#node-config-input-certname").val("");
$("#node-config-input-keydata").val("");
$("#node-config-input-keyname").val("");
} else {
$("#node-config-input-ca").val("");
$("#node-config-input-cert").val("");
$("#node-config-input-key").val("");
}
} }
}); });
</script> </script>

View File

@ -21,34 +21,65 @@ module.exports = function(RED) {
function TLSConfig(n) { function TLSConfig(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.valid = true; this.valid = true;
this.verifyservercert = n.verifyservercert;
var certPath = n.cert.trim(); var certPath = n.cert.trim();
var keyPath = n.key.trim(); var keyPath = n.key.trim();
var caPath = n.ca.trim(); var caPath = n.ca.trim();
if ( (certPath.length > 0) !== (keyPath.length > 0)) { if ((certPath.length > 0) || (keyPath.length > 0)) {
this.valid = false;
this.error(RED._("tls.error.missing-file"));
return;
}
this.verifyservercert = n.verifyservercert;
try { if ( (certPath.length > 0) !== (keyPath.length > 0)) {
if (certPath) { this.valid = false;
this.cert = fs.readFileSync(certPath); this.error(RED._("tls.error.missing-file"));
return;
} }
if (keyPath) {
this.key = fs.readFileSync(keyPath); try {
if (certPath) {
this.cert = fs.readFileSync(certPath);
}
if (keyPath) {
this.key = fs.readFileSync(keyPath);
}
if (caPath) {
this.ca = fs.readFileSync(caPath);
}
} catch(err) {
this.valid = false;
this.error(err.toString());
return;
}
} else {
if (this.credentials) {
var certData = this.credentials.certdata || "";
var keyData = this.credentials.keydata || "";
var caData = this.credentials.cadata || "";
if ((certData.length > 0) !== (keyData.length > 0)) {
this.valid = false;
this.error(RED._("tls.error.missing-file"));
return;
}
if (certData) {
this.cert = certData;
}
if (keyData) {
this.key = keyData;
}
if (caData) {
this.ca = caData;
}
} }
if (caPath) {
this.ca = fs.readFileSync(caPath);
}
} catch(err) {
this.valid = false;
this.error(err.toString());
return;
} }
} }
RED.nodes.registerType("tls-config",TLSConfig); RED.nodes.registerType("tls-config", TLSConfig, {
credentials: {
certdata: {type:"text"},
keydata: {type:"text"},
cadata: {type:"text"}
}
});
TLSConfig.prototype.addTLSOptions = function(opts) { TLSConfig.prototype.addTLSOptions = function(opts) {
if (this.valid) { if (this.valid) {

View File

@ -126,6 +126,8 @@
"tls": { "tls": {
"tls": "TLS configuration", "tls": "TLS configuration",
"label": { "label": {
"use-local-files": "Use key and certificates from local files",
"upload": "Upload",
"cert": "Certificate", "cert": "Certificate",
"key": "Private Key", "key": "Private Key",
"ca": "CA Certificate", "ca": "CA Certificate",

View File

@ -43,6 +43,10 @@ module.exports = {
safeSettings.flowFilePretty = settings.flowFilePretty; safeSettings.flowFilePretty = settings.flowFilePretty;
} }
if (settings.tlsDisableLocalFiles) {
safeSettings.tlsDisableLocalFiles = settings.tlsDisableLocalFiles;
}
if (!runtime.nodes.paletteEditorEnabled()) { if (!runtime.nodes.paletteEditorEnabled()) {
safeSettings.editorTheme = safeSettings.editorTheme || {}; safeSettings.editorTheme = safeSettings.editorTheme || {};
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {};

View File

@ -47,6 +47,10 @@ module.exports = {
// The maximum length, in characters, of any message sent to the debug sidebar tab // The maximum length, in characters, of any message sent to the debug sidebar tab
debugMaxLength: 1000, debugMaxLength: 1000,
// To disable the option for using local files for storing keys and certificates in the TLS configuration
// node, set this to true
//tlsDisableLocalFiles:true,
// Colourise the console output of the debug node // Colourise the console output of the debug node
//debugUseColors: true, //debugUseColors: true,