Open In App

File Sharing Platform with Node.js and Express.js

Last Updated : 25 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In today’s digital age, the need for efficient File sharing platforms has become increasingly prevalent. Whether it’s sharing documents for collaboration or distributing media files, having a reliable solution can greatly enhance productivity and convenience. In this article, we’ll explore how to create a file-sharing platform using Node.js and Express.js, two powerful technologies for building web applications.

Output Preview:

File sharing platform using node - preview

Preview of Final Application

Prerequisites:

Approach

  • Initialize an Express.js server to handle HTTP requests and responses.
  • Use Multer middleware to handle file uploads and store uploaded files in a designated directory.
  • Define a Mongoose schema for storing file metadata including path, original name, password (if protected), and download count.
  • Create routes for uploading files, encrypting passwords using bcrypt, and handling password-protected file downloads.
  • Set up EJS templates to render HTML views for file upload form, password prompt, and success/error messages.
  • Implement security measures such as validating input data, handling errors gracefully, and protecting sensitive information.

Steps to Create the Project

Step 1: Type the following command in the terminal to initialize the nodejs project.

npm init -y

Step 2: Install the necessary packages:

npm i bcrypt nodemon express multer dotenv ejs mongoose

Step 3: Define the start scripts in package.json file:

"scripts": {
"start": "nodemon server.js"
},

Step 4: Create a .env file and add the mongo db connection URI as well as define your PORT. I have kept it 3000.

MONGO = your mongodb URI
PORT = 3000

Project Structure:

Screenshot-2024-04-07-001246

Folder structure

The updated dependencies in package.json file will look like:

"dependencies": {
"bcrypt": "^5.1.1",
"dotenv": "^16.4.5",
"ejs": "^3.1.9",
"express": "^4.19.2",
"mongoose": "^8.3.1",
"multer": "^1.4.5-lts.1",
"nodemon": "^3.1.0",
"pug": "^3.0.2"
}

Example: Implementation to show the code for file sharing platform

HTML
<!-- index.ejs -->

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" 
          content="IE=edge">
    <meta name="viewport" 
          content="width=device-width, initial-scale=1.0">
    <title>File Share</title>
</head>

<body>
    <h1 style="text-align: center; 
               margin-bottom: 50px;">
        File Sharing Application
    </h1>
    <% if(locals.fileLink !=null) { %>
        <div style="margin-bottom: 1rem;">
            Your file is uploaded
            <a href="<%= locals.fileLink %>">
                <%= locals.fileLink %>
            </a>
        </div>
        <% } %>
            <form action="/upload" method="post"
                  style="display: grid; gap: 0.5rem; 
                         grid-template-columns: auto 1fr; 
                         max-width: 500px; margin: 0 auto;"
                  enctype="multipart/form-data">
                <label for="file">File:</label>
                <input type="file" name="file" id="file" required>
                <label for="password">Password:</label>
                <input type="password" name="password" 
                       id="password" required>
                <button style="grid-column: span 2;" type="submit">
                  Share
                  </button>
            </form>
</body>

</html>
HTML
<!-- password.ejs -->

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" 
          content="width=device-width, initial-scale=1.0">
    <title>File Share</title>
</head>

<body>
    <h1 style="text-align: center; 
               margin-bottom: 50px;">
        Enter Password
    </h1>

    <% if(locals.error) { %>
        <div style="color: red; margin-bottom: 1rem;">
            Incorrect password
        </div>
        <% } %>

            <form method="post" 
                  style="display: grid; gap: 0.5rem; 
                          grid-template-columns: auto 1fr; 
                         max-width: 500px; margin: 0 auto;">
                <label for="password">Password:</label>
                <input type="password" name="password" 
                       id="password" required>
                <button style="grid-column: span 2;" 
                        type="submit">
                    Download
                </button>
            </form>
</body>

</html>
JavaScript
// server.js

const express = require("express")
const multer = require("multer")
const app = express()
app.use(express.urlencoded({ extended: true }));
const mongoose = require("mongoose")
require("dotenv").config()
const upload = multer({ dest: "uploads" })
const bcrypt = require("bcrypt")
const File = require("./models/File.js")

mongoose.connect(process.env.MONGO)

app.set("view engine", "ejs")

app.get("/", (req, res) => {
    res.render("index")
})

app.post("/upload",
    upload.single("file"), async (req, res) => {
        const fileData = {
            path: req.file.path,
            originalName: req.file.originalname
        }
        if (req.body.password != null &&
            req.body.password !== "") {
            fileData.password =
                await bcrypt.hash(req.body.password, 10)
        }

        const file = await File.create(fileData)
        res.render("index",
            { fileLink: `${req.headers.origin}/file/${file.id}` })
    })


app.get("/file/:id", handleDownload)
app.post("/file/:id", handleDownload)

async function handleDownload(req, res) {
    const file = await File.findById(req.params.id)

    if (file.password != null) {
        if (req.body.password == null) {
            res.render("password")
            return
        }

        if (!(await bcrypt.compare(
            req.body.password, file.password))) {
            res.render("password", { error: true })
            return
        }
    }

    file.downloadCount++
    await file.save()
    res.download(file.path, file.originalName)
}
app.listen(process.env.PORT)
JavaScript
// File.js

const mongoose = require("mongoose")

const File = new mongoose.Schema({
    path: {
        type: String,
        required: true
    },
    originalName: {
        type: String,
        required: true
    },
    password: String,
    downloadCount: {
        type: Number,
        required: true,
        default: 0
    }
})

module.exports = mongoose.model("File", File)

Step to Run Application: Run the application using the following command from the root directory of the project

node server.js

Output: Your project will be shown in the URL http://localhost:3000/

File sharing platform using node

Final preview of Platform




Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads