Add Credential Files to Configuration Node

Hi,

I developed my first configuration node, following Configuration nodes.

Similar to the MQTT node, I need to store TLS certificates. So, in the mask it is e.g.
<input type="file" id="node-config-input-rootCrt">

And as usual in defaults i guess
rootCrt: { value: '' },

But once I select a file and close the dialog, Node-RED don't let me open the configuration any more.
I think I have to handle file attachments differently. But how? What's Node-RED's way to upload a file and store it in the configuration?

At the end I need the certificate as a buffer.
Any hint on this?

Could you just use the core TLS config (tls-config) node rather than reimplement it? It was written to be a generally reusable config node for anything that needs TLS configuration.

If for some reasons you really need to do your own thing, then have a look at the source of the TLS node to see how it handles file upload of TLS certs.

Everything is better than re-inventing the wheel. :slight_smile:
I didn't know this config and will give it a try.

May I ask you for another advice, please?

I now have a definition for TLS in the defaults of my configuration node:
tls: { value: '', type: 'tls-config' }

The dialog opens, allows me to select and store my certificates. Very well, I now have a new tls configuration node, that is internally linked to my own configuration node. But how can I access it and especially retrieve the buffered certification data?

RED.nodes.createNode(this, config);

this.conf = RED.nodes.getNode(config.database);

this.conf now has all other configuration fields.

I'd expected, that the tls definition should be something in this.conf.tls, to that I can access its configuration again via
this.tls = RED.nodes.getNode(this.conf.tls);

But this.conf.tls is nothing. so, looks like this link is done somehow different.

If you defined defaults as

        defaults: {
            name: { value: '', required:true },
            tls: { value: '', type: 'tls-config' }
        },

you should be able to access this with

RED.nodes.createNode(this, config);
let tls_config = RED.nodes.getNode(config.tls);
console.log(tls_config); // log the properties of the tls-config node

I'm yet questioning the fact that

What's the definition of database in your node's config?

Thanks Ralph,

yes, my defaults looks like in your example. I have additional fields like 'data', but I didn't want to spoil the example. But probably I didn't explain myself very well.

So, I have a node "createRecords". That's the one that is supposed to do the work and appears in the flow as a node. It internally references a configuration node for the database, or server to access.
So in "createRecords":

defaults: {
	name: { value: '' },
	database: { value: '', type: 'my-server' },
	data: { value: '' }
}

"my-server" is a configuration node containing server address, port etc. It also contains a configuration node of "tls-config":

category: 'config',
defaults: {
	name: { value: '' },
	server: { value: 'localhost', required: true },
	port: { value: '1234', required: true, validate: RED.validators.number() },
	tls: { value: '', type: 'tls-config' }
}

This works so far. I can define all data. For TLS a separate configuration mask opens and let me select my certificates. I can save, deploy and re-open. The list of configuration nodes now shows one definition of 'my-server' and one of 'tls-config'. - Looks fine to me. :grinning:

So, execution in createRecords.js is what stopps me now:

module.exports = function (RED) {
	function createRecordsNode(config) {
        	RED.nodes.createNode(this, config);
		this.conf = RED.nodes.getNode(config.database);  // access to 'my-server'
		node.warn(this.conf.server);                     // message of server content
		this.tls = RED.nodes.getNode(this.conf.tls);     // is undefined

Change the last line to:

this.tls = RED.nodes.getNode(config.tls);  

Thanks Nick, I now have:

this.conf = RED.nodes.getNode(config.database);
this.warn(this.conf.server);
this.tls = RED.nodes.getNode(config.tls);
this.warn(this.tls);

this.tls is null. It should be at least [object Object] (or at least something with content). I think it's null in this particular case, because config is linked to "createRecords" and does not have field "tls". As mentioned: I have a TLS configuration in "my-server" as it belongs to the "my-server"-definition.

It's similar to the "mqtt"-node: mqtt allows to select/define a "mqtt-broker", that than allows to select/define a "tls-config".
For me it's a "createRecords"-node: it allows to select/define a "my-server", than than allows to select/define a "tls-config".

"tls-config" is logically part of "my-server", like it is to "mqtt-broker". This is why I thought that I simply use this.conf.tls to fetch the "tls-config". But unfortunate it's not defined.

The TLS field is part of the configuration node of "my-server" and therefore the field is created with -config-. Like this:
<input type="text" id="node-config-input-tls">


(enhancment) I just opened the JSON definition of the flow. The 'my-server' definition looks like this:
{
	"id": "e3aabbb8aea8cc4e",
	"type": "my-server",
	"name": "Test Server",
	"server": "localhost",
	"port": "1234",
	"tls": "d422a1a578db850c"
},

There is a field "tls" pointing to the correct definition:

{
	"id": "d422a1a578db850c",
	"type": "tls-config",
	"name": "Test Certs",
	"cert": "",
	"key": "",
	"ca": "",
	"certname": "Client.crt",
	"keyname": "Client.key",
	"caname": "RootCA.crt",
	"servername": "",
	"verifyservercert": true,
	"alpnprotocol": ""
}

So, how can I get id "d422a1a578db850c" from the "my-server" configuration node, if "tls" returns nothing?

That's not what you're doing:

This tries to get the node who's id is config.tls - which returns undefined.
I'm pretty convinced though, that node.warn(config.tls) will give you the shown id. It looks like the (second) config node yet was not created so far...

Hi Ralph,

no, the two configuration nodes are in the flows.json exactly as shown above (my previous note before, right after enhancement)! There you see, that "my-server" contains a reference to "tls" with value "d422a1a578db850c".

When printing out the config.

this.conf = RED.nodes.getNode(config.database);
this.warn(JSON.stringify(this.conf));

This is what I get. There is no tsl in the object and therefore it can't be opened:

{
    "id": "e3aabbb8aea8cc4e",
    "type": "my-server",
    "_closeCallbacks": [],
    "_inputCallback": null,
    "_inputCallbacks": null,
    "name": "Test Server",
    "wires": [],
    "_wireCount": 0,
    "server": "localhost",
    "port": "1234",
}

So, how can I create it? It is in flows.json, it is linked to "my-server", I can open and modify via the masks, but I cannot not receive it in Javascript.

Ok, after all I found the reason. It must have been something very simple.
Silly me: I forgot to list the tls-config field to the registration.

this.server = config.server || 'localhost';
this.port = config.port || '1234';
this.tls = config.tls;  // this was missing  :-(

Thanks a lot to Ralph and Nick for you help. Really appreciate this. :heart:

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.