Facility to set admin password from interface

I'd like to suggest a facility to set an admin password from the front end.

I've recently been trying to deploy Node-Red via an AWS lightsail container (great, they handle nearly everything including readable endpoint addresses, SSL, etc). The issue is that the Node-Red docker container doesn't contain an active SSH client + text editor. I cannot remote into the alpine linux instance to modify a config file to set the password. I can't set the password from the front end. So, my only recourse is to build from scratch.

To be fair, I've tried docker desktop on 2 high end work centres and one laptop, with a variety of failure messages on each. I'll now be attempting to pull the docker image and rebuilt it at home, just so I can secure the workflow creation screen / settings screens.

There's a few old topics that want for this facility, eg:

Not strictly true.

You could add a flow that reads your settings.js & presents it to an end point that provides a code editor for you edit and post back to your node-red instance where it can be saved. e.g...

The flow

What you see when you access http://IPorHOST:port/settings.js

The demo flow...

[{"id":"dcba6627.393f68","type":"http in","z":"553814a2.1248ec","name":"","url":"/settings.js","method":"get","upload":false,"swaggerDoc":"","x":460,"y":1640,"wires":[["b5c4e3f5.703f2"]]},{"id":"3abb312.de8d1ce","type":"template","z":"553814a2.1248ec","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n    <head>\n        <script src=\"https://unpkg.com/monaco-editor@0.23.0/min/vs/loader.js\"></script>\n        <style>\n            .editor{\n                height: 90%;\n            } \n        </style>\n    </head>\n    <body>\n\n        <div id=\"container\" class=\"editor\"></div>\n        <button id='saveSettings' onclick=\"saveSettings()\">Save settings</button>\n        \n        <script>\n        require.config({ paths: { 'vs': 'https://unpkg.com/monaco-editor@0.23.0/min/vs' }});\n        window.MonacoEnvironment = { getWorkerUrl: () => proxy };\n        var settings = {{{payload}}};\n        let proxy = URL.createObjectURL(new Blob([`\n            self.MonacoEnvironment = {\n                baseUrl: 'https://unpkg.com/monaco-editor@0.23.0/min/'\n            };\n            importScripts('https://unpkg.com/monaco-editor@0.23.0/min/vs/base/worker/workerMain.js');\n        `], { type: 'text/javascript' }));\n\n        require([\"vs/editor/editor.main\"], function () {\n            window.editor = monaco.editor.create(document.getElementById('container'), {\n                value: settings.code,\n                language: 'javascript',\n                theme: 'vs-dark',\n            scrollBeyondLastLine: true,\n            roundedSelection: true,\n            autoIndent: true,\n            cursorStyle: \"line\",\n            fontWeight: 400,\n            automaticLayout: true\n            });\n\n        });\n        function saveSettings() {\n            let newSettings = window.editor.getValue();\n\n            const data = { code: newSettings };\n\n            fetch('/upsettings', {\n                method: 'POST', // or 'PUT'\n                headers: {\n                    'Content-Type': 'application/json',\n                },\n                body: JSON.stringify(data),\n            })\n            .then(response => response.json())\n            .then(data => {\n                alert('Settings sent to node-red :)');\n            })\n            .catch((error) => {\n                alert('Error:' + error.message); \n            });\n\n            console.log(newSettings);\n        }\n        </script>\n\n    </body>\n</html>\n","output":"str","x":1240,"y":1640,"wires":[["1fa0de6f.8f7bb2"]]},{"id":"1fa0de6f.8f7bb2","type":"http response","z":"553814a2.1248ec","name":"","statusCode":"","headers":{"content-type":"text/html","Access-Control-Allow-Origin":"*"},"x":1370,"y":1640,"wires":[]},{"id":"b5c4e3f5.703f2","type":"file in","z":"553814a2.1248ec","name":"","filename":"settings.js","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":620,"y":1640,"wires":[["4c9dce0c.f807e"]]},{"id":"4c9dce0c.f807e","type":"change","z":"553814a2.1248ec","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t    \"code\": payload\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":960,"y":1640,"wires":[["eaaf7a35.9ceef8"]]},{"id":"eaaf7a35.9ceef8","type":"json","z":"553814a2.1248ec","name":"","property":"payload","action":"","pretty":false,"x":1110,"y":1640,"wires":[["3abb312.de8d1ce"]]},{"id":"d43c53d7.fe247","type":"http in","z":"553814a2.1248ec","name":"","url":"upsettings","method":"post","upload":false,"swaggerDoc":"","x":460,"y":1680,"wires":[["93673240.88549"]]},{"id":"d26fc95.3c58d38","type":"http response","z":"553814a2.1248ec","name":"","statusCode":"","headers":{},"x":1370,"y":1680,"wires":[]},{"id":"cc743046.c87b4","type":"function","z":"553814a2.1248ec","name":"replace me with a file out node to save settings","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":1680,"wires":[["c98025ff.ed40e8"]]},{"id":"93673240.88549","type":"change","z":"553814a2.1248ec","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.code","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":1680,"wires":[["cc743046.c87b4","52e16f44.3fd56"]]},{"id":"52e16f44.3fd56","type":"debug","z":"553814a2.1248ec","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":850,"y":1720,"wires":[]},{"id":"c98025ff.ed40e8","type":"change","z":"553814a2.1248ec","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1200,"y":1680,"wires":[["d26fc95.3c58d38"]]}]

NOTES

  • Dont leave this code running once you have this set
  • Any mistakes will cause node-red to not start
  • Assumes settings.js is writable and persisted between reboots
  • The editing browser needs internet access (for the editor CDN)
  • I have deliberately NOT put the file out node in (for safety purposes) I'll leave that to you Mr Future Reader :slight_smile:
1 Like

Well now, I'm going to have to go and try this right away!

Perhaps I'm missing something here @Steve-Mcl, when I import that demo flow on either my Win 10 (NR 1.1.2), or Docker (nodered/node-red:latest v1.3.4) Node-Red installs, visiting http://localhost:1880 works, but http://localhost:1880/settings.js just causes the page to hang/timeout. Just an infinite spinning wheel.

I have observed, however, that visiting http://localhost:1880/settings causes a json file to display which contains some settings, which is a little concerning.

Edit(s)
On windows changing the input file to /.node-red/settings.js results in Error: Cannot get settings.js

  • does the computer where you are accessing this URL have internet access?
  • attach a debug to the "file in" node - is it reading the settings.js file (you might need to put full path in e.g. /some/path/settings.js or c:/users/user/.node-red/settings.js)

This is normal.

I'm a potato. I changed it in the http-in, and not in the file-in.

The windows version is working. I just need to track down the file path for the docker image now.

Edit:
Windows path with a default install /.node-red/settings.js
Docker path with default install: /data/settings.js

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