Simple Node Express to Upload Files

Posted on Sunday, December 20, 2015




I had an odd need the other day create a quick temporary web page to allow someone to upload a file.

After poking around this is what I came up with.   (It's not very fancy, and I would not say it's good for an ongoing production system, but maybe it will help someone out there)






Install Node/NPM on Ubuntu 14.04


I am going to start this from the beginning….  All I have is a freshly installed Ubuntu… no Node Installed no NPM.

Purge (just in case)


  > sudo apt-get --purge remove nodejs
  > sudo apt-get --purge remove npm


Update and install node


  > sudo apt-get update
  > sudo apt-get install nodejs npm


This install nodejs at /usr/bin/nodejs, I would rather have it at /usr/bin/node so I need to make a link.


  > sudo ln -s /usr/bin/nodejs /usr/bin/node




Check the versions


  > node -v
  > npm -v









Make Self Signed SSL certs


I want to run this on https just to add some security while uploading stuff over the internet.

Here is how you make a simple self-signed cert on Ubuntu 14.04 see



  > mkdir ssl
  > cd ssl
  > openssl genrsa -des3 -out mytest.key 1024





When it asks for a passphrase give it a simple 'password'  For example 1234




  > openssl req -new -key mytest.key -out mytest.csr





Enter the passphrase




Enter in info when asked like Country code, state, etc…. you can leave them blank if you wish.


Backup the key and remove the pass phrase


  > cp mytest.key mytest.key.BACK
  > openssl rsa -in mytest.key.BACK -out mytest.key





Enter your passphrase


Sign it, I set it to be good for 365 days.


  > openssl x509 -req -days 365 -in mytest.csr -signkey mytest.key -out mytest.crt




 



 

Here are the two you need the .csr and .key file.





Simple Express page


I like to start simple…   Just get a basic Express page working.

Create a folder to run your express app from.


  > cd
  > mkdir myUploadServer
  > cd myUploadServer




Initialize the program



  > npm init






The only important thing I change is to change index.js to app.js

Install Express




  > npm install --save express




Create simple hello world



  > vi app.js


And put the following in it.  (tweaked from  http://expressjs.com/starter/hello-world.html [2])


var express = require('express');
var app = express();

//Set Environment
app.set('port', 3000);

app.get('/', function (req, res) {
    res.
send('Hello World!');
   
console.log("Responded to request " + req.hostname);
});

app.listen(app.get('port'), function () {
   
console.log("Express Server Started Listening on port " app.get('port'));
});




Save it and run it


  > node app.js






Now open up a web page and point to that server (In my case it's at local IP 192.168.0.195 so I will open http://192.168.0.195:3000/ )




OK simple web app is working  J





Add in SSL and run on port 443


I found one good site that gave some insight on how to run express in ssl 'mode'


Install https



  > npm install --save https
  > npm install --save fs




Update app.js


  > vi app.js



var https = require('https');
var fs = require('fs');
var express = require('express');
var app = express();

var options = {
    key: fs.readFileSync('ssl/mytest.key'),
    cert: fs.readFileSync('ssl/mytest.crt'),
    requestCert: false,
    rejectUnauthorized: false
};

//Set Environment
app.set('port', 443);

app.get('/', function (req, res) {
    res.send('Hello World!');
    console.log("Responded to request " + req.hostname);
});

var server = https.createServer(options, app).listen(app.get('port'), function(){
    console.log("server started at port " + app.get('port'));
});




Save it and run it (have to run as sudo since it now is taking a privileged  port < 1024)


  > sudo node app.js


fs.js:432
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);

Oops got an error
v




Oh I forgot to move my ssl certs I made earlier…

Copy the ssl certs



  > mkdir ssl
  > cp ~/ssl/*.crt ssl/
  > cp ~/ssl/*.key ssl/




Try it again


  > sudo node app.js





Now open the https version of the site.







You should get this warning since it is not signed.

Click on Advanced







And click Proceed






And its working we have https working in express







Upload a file using multer



Now to create a page that allows us to upload a file to the server.  (This will not be fancy….)

Their github page is at https://github.com/expressjs/multer  [4]

I found a few pages going over how to use it.



Here is what I came up with based on these.

First install multer


  > npm install --save multer




Create a simple upload.html file



  > vi upload.html




<form id        =  "uploadForm"
     enctype   =  "multipart/form-data"
     action    =  "/api/upload"
     method    =  "post"
> 
<input type="file" name="upload-file" />
<input type="submit" value="Upload File" name="submit">
</form>




Update app.js


  > vi app.js




var https = require('https');
var multer = require('multer');
var fs = require('fs');
var express = require('express');
var app = express();
var upload = multer({ dest: 'uploads/'});

var options = {
    key: fs.readFileSync('ssl/mytest.key'),
    cert: fs.readFileSync('ssl/mytest.crt'),
    requestCert: false,
    rejectUnauthorized: false
};

var type = upload.single('upload-file');

app.post('/api/upload', type, function (req,res) {

  console.log("Testing\n " + req.file.originalname);
  console.log(req.file.path);

  /** When using the "single"
      data come in "req.file" regardless of the attribute "name". **/
  var tmp_path = req.file.path;

  /** The original name of the uploaded file
      stored in the variable "originalname". **/
  var target_path = 'uploads/' + req.file.originalname;

  /** A better way to copy the uploaded file. **/
  var src = fs.createReadStream(tmp_path);
  var dest = fs.createWriteStream(target_path);
  src.pipe(dest);
  src.on('end', function() { res.send('complete'); });
  src.on('error', function(err) { res.send('error'); });

});

//Set Environment
app.set('port', 443);


app.get('/upload',function(req,res){
      res.sendFile(__dirname + "/upload.html");
});

var server = https.createServer(options, app).listen(app.get('port'), function(){
    console.log("server started at port " + app.get('port'));
});





OK try and run it



  > sudo node app.js





Now open

https://192.168.0.195/upload   which should open upload.html




Now choose a file and click upload.








When it is done it says complete.


Nothing fancy


If I look in the uploads folder


  > ls -alh uploads





I see two files

The file with the long random name is the uploading file… Once the file is uploaded it copies it to a named file.  


That be it.

Although it is using https for secure transmission it does not block anyone from uploading files via this node service.






Simple Procedure


Putting this all together here is a simple procedure to go from nothing on an Ubuntu 14.04 server to a simple node website using a simple self-signed certificate to upload files.  (nothing fancy, no user accounts not passwords)

Install Node (purge)


  > sudo apt-get update
  > sudo apt-get --purge remove nodejs npm
  > sudo apt-get install nodejs npm



This install nodejs at /usr/bin/nodejs, I would rather have it at /usr/bin/node so I need to make a link.


  > sudo ln -s /usr/bin/nodejs /usr/bin/node


Check the versions


  > node -v
  > npm -v








Create node express projects


  > mkdir myUploadServer
  > cd myUploadServer


Edit package.json


  > vi package.json


Place the following in it


{
  "name": "myUploadServer",
  "version": "0.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "BSD-2-Clause",
  "dependencies": {
    "express": "~4.13.3",
    "https": "~1.0.0",
    "fs": "0.0.2",
    "multer": "~1.1.0"
  }
}


Run npm install to grab express/https/fs


  > npm Install






Create app.js


  > vi app.js


And place the following in it.


var https = require('https');
var multer = require('multer');
var fs = require('fs');
var express = require('express');
var app = express();
var upload = multer({ dest: 'uploads/'});

var options = {
    key: fs.readFileSync('ssl/mytest.key'),
    cert: fs.readFileSync('ssl/mytest.crt'),
    requestCert: false,
    rejectUnauthorized: false
};

var type = upload.single('upload-file');

app.post('/api/upload', type, function (req,res) {

  console.log("Testing\n " + req.file.originalname);
  console.log(req.file.path);

  /** When using the "single"
      data come in "req.file" regardless of the attribute "name". **/
  var tmp_path = req.file.path;

  /** The original name of the uploaded file
      stored in the variable "originalname". **/
  var target_path = 'uploads/' + req.file.originalname;

  /** A better way to copy the uploaded file. **/
  var src = fs.createReadStream(tmp_path);
  var dest = fs.createWriteStream(target_path);
  src.pipe(dest);
  src.on('end', function() { res.send('complete'); });
  src.on('error', function(err) { res.send('error'); });

});

//Set Environment
app.set('port', 443);


app.get('/upload',function(req,res){
      res.sendFile(__dirname + "/upload.html");
});

var server = https.createServer(options, app).listen(app.get('port'), function(){
    console.log("server started at port " + app.get('port'));
});





Create a simple upload.html file


  > vi upload.html




<form id        =  "uploadForm"
     enctype   =  "multipart/form-data"
     action    =  "/api/upload"
     method    =  "post"
> 
<input type="file" name="upload-file" />
<input type="submit" value="Upload File" name="submit">
</form>




Set up ssl  (Self signed)


  > mkdir ssl
  > cd ssl
  > openssl genrsa -des3 -out mytest.key 1024


Enter passphrease 1234


  > openssl req -new -key mytest.key -out mytest.csr


Enter passphrase and information you want in SSL key


  > cp mytest.key mytest.key.BACK
  > openssl rsa -in mytest.key.BACK -out mytest.key


Enter passphrase


  > openssl x509 -req -days 365 -in mytest.csr -signkey mytest.key -out mytest.crt
  > cd ..




Run it



  > sudo node app.js





Now open it in my case



And it works! 




Making it prettier with more Feedback?


I used it recently to upload some very large files.  It worked!   I was even able to upload multiple large files at the same time.  But while they were being uploaded I had no feedback from the web page.

I could go to the server and see that the files were getting larger but I had no feedback on the web page itself.

Is there a simple way to fix this?  I would like to have a very simple node program for uploading large files that I can track…


I poked around and found a few things.  I do not have time at the moment to fight with it but I thought I would make notes here so I can figure it out in a month or two… or the next time I have a need for a tool like this.










Looks nice enough…

Here is their github page

Now how to integrate it….


Looks like they have a minimal setup guide
https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin [9]
Oh wait a little more poking led me to npm 
https://www.npmjs.com/package/blueimp-file-upload [10] The blueimp-file-upload

which then led to
https://www.npmjs.com/package/blueimp-file-upload-expressjs   [11] blueimp-file-upload-expressjs

That looks very promising!

Oh he made a how to page http://thejackalofjavascript.com/uploading-files-made-fun [12]  That looks like the place to go figure out how to make it look nicer.

I also found this page on Express-generator


OK that is it for research and links…   Some day when if I come back to this I will probably make a nice example in github anyone can grab and just use.





References

[1]        How to create a self-signed certificate
                Accessed 12/2015
[2]        Hello World Example
                Accessed 12/2015
[3]        Create a self-signed SSL cert for local host
                Accessed 12/2015
[4]        Multer github page
                Accessed 12/2015
[5]        File Upload using Nodejs
                Accessed 12/2015
[6]        Error after 1.0.0
                Accessed 12/2015
[7]        BlueImp JQuery File Upload page
                Accessed 12/2015
[8]        BlueImp JQuery File Upload github page
                Accessed 12/2015
[9]        Minimal setup guide JQuery upload 
                Accessed 12/2015
[10]      blueimp file upload npm page
                Accessed 12/2015
[11]      blueimp file upload expressjs npm page
                Accessed 12/2015
[12]      Uploading file made fun with Express js and Blueimp
                Accessed 12/2015
[13]      Express Application Generator

                Accessed 12/2015 

No comments:

Post a Comment