DEV Community

Cover image for Building a File Encryptor with ReactJS, Express, and TailwindCSS: A Journey into Data Security
drruvari
drruvari

Posted on

Building a File Encryptor with ReactJS, Express, and TailwindCSS: A Journey into Data Security

Introduction

Hello again, fellow developers! 👋 After successfully building a web scraper inspired by an amazing list of 53 project ideas, I'm excited to share the next stop on this coding adventure: a File Encryptor built using ReactJS, Express, and TailwindCSS. In this post, I'll walk you through the process, challenges, and lessons learned while creating a tool that secures files with ease. Whether you're just starting out or you're a seasoned developer, I hope you enjoy and learn from this journey!

Why a File Encryptor?

Data security is more important than ever. With sensitive information floating around, it's crucial to protect it from unauthorized access. A file encryptor automates the process of securing data, making it an invaluable tool for anyone concerned with privacy. For this project, I aimed to create an efficient and user-friendly application to encrypt files, ensuring data remains safe.

Setting Up the Backend

Let's dive into the backend first. We'll use Express to handle file uploads and perform encryption. Here's how we set it up:

Server Code (server.js)

const express = require("express");
const multer = require("multer");
const bodyParser = require("body-parser");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const cors = require("cors");

const app = express();
const upload = multer({ dest: "uploads/" });

app.use(cors());
app.use(bodyParser.json());

const encryptFile = (filePath, callback) => {
  const algorithm = "aes-256-ctr";
  const key = crypto.randomBytes(32);
  const iv = crypto.randomBytes(16);

  const cipher = crypto.createCipheriv(algorithm, Buffer.from(key), iv);
  const input = fs.createReadStream(filePath);
  const encryptedPath = filePath + ".enc";
  const output = fs.createWriteStream(encryptedPath);

  input.pipe(cipher).pipe(output);

  output.on("finish", () => {
    callback({
      key: key.toString("hex"),
      iv: iv.toString("hex"),
      path: encryptedPath,
    });
  });
};

app.post("/encrypt", upload.single("file"), (req, res) => {
  const filePath = path.join(__dirname, req.file.path);
  encryptFile(filePath, (encryptionInfo) => {
    res.json(encryptionInfo);
  });
});

const PORT = 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Explanation

  • Import Modules: We import necessary modules like express for creating the server, multer for file uploads, body-parser for parsing request bodies, crypto for encryption, fs for file system operations, path for handling file paths, and cors for enabling cross-origin requests.
  • Initialize App: We initialize an Express app and configure it to use CORS and body-parser.
  • File Encryption Function: The encryptFile function takes a file path and a callback function. It uses the AES-256-CTR algorithm to encrypt the file. Random bytes are generated for the encryption key and initialization vector (IV). The file is read, encrypted, and written to a new file with the .enc extension. Once encryption is complete, the callback is called with the encryption details.
  • File Upload Endpoint: The /encrypt endpoint handles file uploads using multer. It calls the encryptFile function and responds with the encryption details (key, IV, and encrypted file path).
  • Start Server: The server listens on port 5000.

Creating the Frontend

Now, let's move on to the frontend. We'll build a simple React interface that allows users to upload a file and display the encryption details.

Frontend Code (client/src/App.js)

import React, { useState } from "react";
import axios from "axios";

function App() {
  const [file, setFile] = useState(null);
  const [encryptionData, setEncryptionData] = useState(null);
  const [showModal, setShowModal] = useState(false);

  const onFileChange = (event) => {
    setFile(event.target.files[0]);
  };

  const onSubmit = async (event) => {
    event.preventDefault();
    const formData = new FormData();
    formData.append("file", file);

    try {
      const response = await axios.post(
        "http://localhost:5000/encrypt",
        formData,
        {
          headers: {
            "Content-Type": "multipart/form-data",
          },
        }
      );
      setEncryptionData(response.data);
      setShowModal(true);
    } catch (error) {
      console.error("Error uploading file:", error);
    }
  };

  const closeModal = () => {
    setShowModal(false);
  };

  return (
    <div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center">
      <div className="bg-white shadow-xl rounded-lg p-8">
        <h1 className="text-3xl font-bold text-brand mb-6">File Encryptor</h1>
        <form onSubmit={onSubmit} className="space-y-4">
          <input
            type="file"
            onChange={onFileChange}
            className="file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-brand file:text-white hover:file:bg-brand-dark"
          />
          <button
            type="submit"
            className="bg-brand hover:bg-brand-dark text-white font-bold py-2 px-4 rounded transition-colors duration-150 ease-in-out"
          >
            Encrypt File
          </button>
        </form>
      </div>

      {encryptionData && (
        <button
          onClick={() => setShowModal(true)}
          className="mt-5 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition-colors duration-150 ease-in-out"
        >
          Show Key & IV
        </button>
      )}

      {showModal && (
        <div className="fixed inset-0 bg-gray-900 bg-opacity-50 flex justify-center items-center">
          <div className="bg-white p-6 rounded shadow-lg">
            <h2 className="text-xl font-bold mb-2">
              Encryption Details
              <span className="block text-sm font-normal text-gray-500">
                (Check the uploads folder for the encrypted file)
              </span>
            </h2>
            <p>
              <strong>Key:</strong> {encryptionData.key}
            </p>
            <p>
              <strong>IV:</strong> {encryptionData.iv}
            </p>
            <button
              onClick={closeModal}
              className="mt-4 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition-colors duration-150 ease-in-out"
            >
              Close
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Explanation

  • State Management: We use React's useState hook to manage the state for the selected file (file), the encryption data (encryptionData), and the visibility of the modal (showModal).
  • File Selection: The onFileChange function updates the file state when the user selects a file.
  • Form Submission: The onSubmit function prevents the default form submission, creates a FormData object with the selected file, and sends a POST request to the server using Axios. On successful encryption, it updates the encryptionData state and shows the modal.
  • Close Modal: The closeModal function hides the modal.
  • Rendering: The component renders a file upload form, a button to show the encryption details, and a modal displaying the encryption key and IV.

Styling with TailwindCSS

To give our app a clean and modern look, we'll use TailwindCSS.

Tailwind Configuration (client/tailwind.config.js)

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {
      colors: {
        brand: "#0f172a",
      },
    },
  },
  plugins: [],
};
Enter fullscreen mode Exit fullscreen mode

Installing TailwindCSS

First, ensure TailwindCSS is installed in your project:

npm install -D tailwindcss
npx tailwindcss init
Enter fullscreen mode Exit fullscreen mode

Next, add Tailwind to your CSS (client/src/index.css):

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Testing the File Encryptor

To test the file encryptor:

  1. Start the Express server by running node server.js.
  2. Run the React app using npm start in the client directory.
  3. Upload a file through the React frontend and observe the encryption details.

Conclusion

And there you have it! We've successfully built a file encryptor using ReactJS, Express, and TailwindCSS. This project not only reinforced my understanding of file handling and encryption but also showcased the power of combining these technologies to create a secure and user-friendly application. I hope you found this journey as rewarding as I did. Stay tuned for more exciting projects as I continue exploring this list of ideas. Happy coding! 🚀

Top comments (2)

Collapse
 
johnboris profile image
John

This is very helpful article.
Thank you.

Collapse
 
drruvari profile image
drruvari

Anytime