Skip to content

Instantly share code, notes, and snippets.

@Steve-Mcl
Last active January 9, 2024 17:28
Show Gist options
  • Save Steve-Mcl/db68bd4934cf46f39e6e453a348bc419 to your computer and use it in GitHub Desktop.
Save Steve-Mcl/db68bd4934cf46f39e6e453a348bc419 to your computer and use it in GitHub Desktop.
Download a file from node-red using standard nodes

About...

A flow demonstrating how to download a file from your server using standard node-red nodes and without needing to modify settings.js

This flow creates a HTTP endpoint set to '/files/:fn'

This endpoint is accessible by constructing a url pointing to your node red server e.g. http://localhost:1880/files/log.log

The base path of this flow is set to c:\temp. This means the file c:\temp\log.log will be read from the node-red server file system and returned to the requester as an attachment/download.

Notes...

  • The base folder on your server is setup in the function node Set base path. Adjust this to point at the folder from where the files you wish to server are saved.
  • The flow uses node-red dashboard to present the download links. If you have or don't want to use dashboard, simply delete the ui_template node before deploying.

Screenshot...

image

[{"id":"f31a598d.9fd2c8","type":"function","z":"56fa9896.d15ed8","name":"Set base path","func":"//restrict to c:\\temp\\\nvar basePath = \"c:\\\\temp\\\\\";\nvar filename = msg.req.params.fn;\n\n\nif(filename.includes(\"..\\\\\")){\n msg.payload = \"Illegal file path\";\n msg.statusCode = 405;//not allowed\n return [null, msg];//fire output 2\n} else if(filename.includes(\"../\")){\n msg.payload = \"Illegal file path\";\n msg.statusCode = 405;//not allowed\n return [null, msg];//fire output 2\n} \n//TODO: add more checks\n\nmsg.filename = basePath + filename;\nreturn [msg, null];//fire output 1\n\n\n","outputs":2,"noerr":0,"x":320,"y":300,"wires":[["34dc99e5.495466"],["98261154.3006"]]},{"id":"98261154.3006","type":"http response","z":"56fa9896.d15ed8","name":"","statusCode":"","headers":{},"x":670,"y":340,"wires":[]},{"id":"34dc99e5.495466","type":"file in","z":"56fa9896.d15ed8","name":"","filename":"","format":"","chunk":false,"sendError":false,"encoding":"none","x":510,"y":280,"wires":[["98261154.3006"]]},{"id":"38d65d59.1d8aa2","type":"catch","z":"56fa9896.d15ed8","name":"","scope":null,"uncaught":false,"x":140,"y":380,"wires":[["3b8014a.86ad8ec","5b18a8e7.fb8da8"]]},{"id":"3b8014a.86ad8ec","type":"function","z":"56fa9896.d15ed8","name":"Set 404","func":"msg.payload = msg.error;\nmsg.statusCode = 404;//resource not found\nreturn msg;","outputs":1,"noerr":0,"x":520,"y":380,"wires":[["98261154.3006"]]},{"id":"5b18a8e7.fb8da8","type":"debug","z":"56fa9896.d15ed8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":170,"y":420,"wires":[]},{"id":"a8c2985e.d23ad8","type":"ui_template","z":"56fa9896.d15ed8","group":"dfb4a60f.d788f8","name":"ui_temlplate - present download links on dashboard","order":0,"width":0,"height":0,"format":"<div >\n <a href=\"/files/log.log\">download log.log</a>\n <a href=\"/files/log2.log\">download log2.log</a>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":510,"y":460,"wires":[[]]},{"id":"5de7cbb4.fa21a4","type":"comment","z":"56fa9896.d15ed8","name":"Create http endpoint <nodered>/files/xxx where xxx is the file name to download","info":"","x":360,"y":240,"wires":[]},{"id":"67ecfa7f.3f0e24","type":"http in","z":"56fa9896.d15ed8","name":"","url":"/files/:fn","method":"get","upload":false,"swaggerDoc":"","x":150,"y":300,"wires":[["f31a598d.9fd2c8"]]},{"id":"dfb4a60f.d788f8","type":"ui_group","z":"","name":"Data Export","tab":"48418b79.0f5834","disp":true,"width":"12"},{"id":"48418b79.0f5834","type":"ui_tab","z":"","name":"Dashboard","icon":"dashboard","order":1}]
@MiLaak
Copy link

MiLaak commented Apr 7, 2020

Would it work just to have :
if(filename.includes(".."))
in the function node instead of
if(filename.includes("../"))
Or does it expose some security issue which I do not see?

@Nodi-Rubrum
Copy link

Nodi-Rubrum commented Aug 8, 2020

Not sure if this is right place to ask this, but since you don't have an issues queue? Feature request, can you add wildcard support to the paths allowed 'file' and 'file in' nodes? For example, I have a path I need to query in Node Red, sometimes the path is down a leaf that is iio:device0, sometimes down a leaf that is iio:device1. I don't know ahead of time which it will be 0 or 1. But it will be one or the other. In standard Linux path resolution I can use wildcards, but in your nodes that does not seem to be allowed? I want to do the following, example below.

For...
/sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0040/iio:device0/input_temp_in
and...
/sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0040/iio:device1/in_temp_input

Reference...
/sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0040/iio:device*/in_temp_input

Note the * (or wildcard). The Linux CLI allows for this. For example...

# ls -l /sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0040/iio:device*/in_temp_input
-rw-r--r-- 1 root root 4096 Aug 8 22:10 /sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0040/iio:device0/in_temp_input

# cat /sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0040/iio:device*/in_temp_input
26091

@zaid894
Copy link

zaid894 commented Mar 8, 2022

Great help, thank you so much

@proscandg
Copy link

I would like to use a ui-button instead of a link. Because I have a file creation action to do before downloading could you help me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment