fixed the credentials .
and added the ability to use it in functions direction!
Check it out and see if this is better. Updated the instructions in README too, so be sure to check that.
https://www.npmjs.com/package/node-red-contrib-settings-vault
fixed the credentials .
and added the ability to use it in functions direction!
Check it out and see if this is better. Updated the instructions in README too, so be sure to check that.
https://www.npmjs.com/package/node-red-contrib-settings-vault
Wow this is glorious and you even update it so fast!
Hi @hoolahoous
Thanks for fixing that as it now behaves the same as the "credential" input in the flow's environment variables.
And great for adding the access through function
May be you intended it, or not, but it also works in JSONata !
Here environment comes from msg.environment
By the way, your doc say that we can create vault from the configuration node tab but I don't seem to find that "Add" button in my NR UI.
I just proceed how I always had by creating a configuration from the node that uses it.
Did I missed something in the NR UI ?
Amazing work
Many Many Thanks
I made this little demo flow which I believe shows most capabilities:
Assuming 2 config nodes prod and staging, each with 2 groups Service1 and Service2, and each service have 2 properties username and token
[{"id":"d6a7d74b825fea2b","type":"vault","z":"bbbd97e84cc4a26b","name":"Test Vault Production","vault":"307c1273d2d00458","properties":[{"group":"Service1","property":"username","output":"msg.credentials.username"},{"group":"Service1","property":"token","output":"msg.credentials.token"}],"x":3480,"y":340,"wires":[["69ad4f113de36c9e"]]},{"id":"09cc571a36870b02","type":"inject","z":"bbbd97e84cc4a26b","name":"test prod","props":[{"p":"environment","v":"prod","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":2940,"y":420,"wires":[["2a5369de27ce31f2"]]},{"id":"ef7b85b23313e2dd","type":"vault","z":"bbbd97e84cc4a26b","name":"Test Vault Staging","vault":"fe409fdb82a36d07","properties":[{"group":"Service1","property":"username","output":"msg.credentials.username"},{"group":"Service1","property":"token","output":"msg.credentials.token"}],"x":3470,"y":380,"wires":[["69ad4f113de36c9e"]]},{"id":"635e6e3c8f56e290","type":"switch","z":"bbbd97e84cc4a26b","name":"Environment ?","property":"environment","propertyType":"msg","rules":[{"t":"eq","v":"prod","vt":"str"},{"t":"eq","v":"staging","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":3220,"y":360,"wires":[["d6a7d74b825fea2b"],["ef7b85b23313e2dd"]]},{"id":"5d9cfe1a6d5a67f9","type":"inject","z":"bbbd97e84cc4a26b","name":"test staging","props":[{"p":"environment","v":"staging","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":2930,"y":460,"wires":[["2a5369de27ce31f2"]]},{"id":"5f320f6664329c81","type":"function","z":"bbbd97e84cc4a26b","name":"vault in function","func":"let v = this.vault(msg.environment)\nconst { username, token } = v.getGroup(\"Service2\")\nmsg.credentials = {\n username: username,\n token: token\n}\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nthis.vault = global.get('vault')\n","finalize":"","libs":[],"x":3224.2766847610474,"y":441.61103320121765,"wires":[["8e8d0df0c613647b"]]},{"id":"4aa828e0ed5b417c","type":"change","z":"bbbd97e84cc4a26b","name":"credentials","rules":[{"t":"set","p":"credentials","pt":"msg","to":"{\t \"username\": $globalContext('vault')(environment).getGroup('Service1').username,\t \"token\": $globalContext('vault')(environment).getGroup('Service1').token\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":3214.2766847610474,"y":521.6110332012177,"wires":[["529e18b03d130929"]]},{"id":"8e8d0df0c613647b","type":"debug","z":"bbbd97e84cc4a26b","name":"JS function","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"credentials","targetType":"msg","statusVal":"","statusType":"auto","x":3790,"y":440,"wires":[]},{"id":"a6ccd66e54e9adea","type":"debug","z":"bbbd97e84cc4a26b","name":"vault node","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"credentials","targetType":"msg","statusVal":"","statusType":"auto","x":3790,"y":360,"wires":[]},{"id":"529e18b03d130929","type":"debug","z":"bbbd97e84cc4a26b","name":"JSONata","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"credentials","targetType":"msg","statusVal":"","statusType":"auto","x":3780,"y":520,"wires":[]},{"id":"69ad4f113de36c9e","type":"junction","z":"bbbd97e84cc4a26b","x":3660,"y":360,"wires":[["a6ccd66e54e9adea"]]},{"id":"2a5369de27ce31f2","type":"junction","z":"bbbd97e84cc4a26b","x":3080,"y":440,"wires":[["635e6e3c8f56e290","5f320f6664329c81","4aa828e0ed5b417c"]]},{"id":"307c1273d2d00458","type":"vault-config","name":"prod","structure":{"Service1":["username","token"],"Service2":["username","token"]}},{"id":"fe409fdb82a36d07","type":"vault-config","name":"staging","structure":{"Service1":["username","token"],"Service2":["username","token"]}},{"id":"b468db89e0b3c49d","type":"global-config","env":[],"modules":{"node-red-contrib-settings-vault":"2.0.0"}}]
thanks for catching the readme issue. i updated the readme.
meanwhile, you don't technically need a switch node to switch environment, you should be able to use jsoanta in change node to read the current environment name from settings and get values for that environment.
example flow where just by changing the config node's currentEnviornment variable you can have flow load different values. No need to touch the flow, directly change the behavior of flow by just changing the config in vault :
Config node :
And your regular flow
which has jsonata like this one
( $env := $globalContext('vault')('Settings').getGroup('config').currentEnvironment; $globalContext('vault')('Settings').getGroup($env).username )
Here is full flow
[
{
"id": "1707752c25e0d42e",
"type": "inject",
"z": "22b50258caf28e95",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 180,
"y": 380,
"wires": [
[
"03753624e723fe05"
]
]
},
{
"id": "03753624e723fe05",
"type": "change",
"z": "22b50258caf28e95",
"name": "JSonata",
"rules": [
{
"t": "set",
"p": "username",
"pt": "msg",
"to": "( $env := $globalContext('vault')('Settings').getGroup('config').currentEnvironment; $globalContext('vault')('Settings').getGroup($env).username )",
"tot": "jsonata"
},
{
"t": "set",
"p": "password",
"pt": "msg",
"to": "( $env := $globalContext('vault')('Settings').getGroup('config').currentEnvironment; $globalContext('vault')('Settings').getGroup($env).password )",
"tot": "jsonata"
},
{
"t": "set",
"p": "endpoint",
"pt": "msg",
"to": "( $env := $globalContext('vault')('Settings').getGroup('config').currentEnvironment; $globalContext('vault')('Settings').getGroup($env).endpoint )",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 360,
"y": 380,
"wires": [
[
"90ac2f5c826e31b7"
]
]
},
{
"id": "90ac2f5c826e31b7",
"type": "debug",
"z": "22b50258caf28e95",
"name": "debug 2",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 540,
"y": 380,
"wires": []
}
]
I'm not sure to understand your J: expressions for password and endpoint
Why are they different from the username one ?
Isn't there an extra indirection ?
You seem to get the value of the password/endpoints properties and use those values to read another property ![]()
Your first flow where you inject environment and have a switch node to check the environment and then load that environment's property can be even more abstracted. Here is what i was recommending
The advantage of this setup is, you do not need to modify your flow (or multiple flows which uses same structure). Just by flipping the the value of currentEnvironment variable you instantly switch all flows to use different environment's setting.
This will allow you to build complex flows using test settings, and when you are happy, just flip one variable in settings to switch to prod.
edit: i found the copy paste error in my flow export. fixed it.
we are live in node-red library - node-red-contrib-settings-vault (node) - Node-RED
Hi. This looks to be shaping up nicely.
In case you weren't aware, you can add your demo flows to the package by adding them as JSON files in a directory named examples and they will be accessible to users inside node-red via the import dialog (CTRL-I -> examples -> node-name)
thanks. i had no idea! (using node-red for 10+ years) ![]()
The name of the file becomes the label in the import menu.
…and you can have spaces in the example flow name to make it more readable.
Such as ‘Typical usage example.json’ would display as ‘Typical usage example’
just pushed new release with examples.
also fixed theme so it will follow current node-red theme.
Nice work @hoolahoous ![]()
The extra work that you've put into the detailed documentation is also appreciated.
A sidenote, while doing some reasearch on Oauth2 (single sign on), it seems that it too shares a secret code (when establiblishing JWT to a service) in the url? This is a short-lived temporary code that is part of redirect to service after login.
Great work! But... the Library shows there's a naming conflict (of the config node) with an existing contrib node.
Nowadays it's recommended to use a scoped name for new packages, something like this:
@carefulcomputer/node-red-settings-vault
Yes, that is standard. Noting that it is short-lived. That is the key for exchanging tokens where no other session management is in place to validate that tokens are being used by the client that should have them (for example, by including other information in the JWT such as IP address, etc).
the module scoping is the new recommended naming convention however the type name clash wont be resolved by that. The name using in registerType is what creates the conflict.
If the author doesnt want to change the type names to something more individual then your only option is to not use this node or remove the other node that it conflicts with.
I will not the using the other node, so it's not a problem for me personally. I just looked at the scorecard, where the issue was mentioned.
Yeah, i was wondering about why it shows the conflict too since there was no other contrib with this name.
So if I understand correctly, the name of the node itself is conflicting. Is that right ? If that is correct, is there a way to search for node names in some kind of global repository ? I can see how it could cause confusion if there are two nodes with same name in editor pallet.