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}`));
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, andcors
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 theencryptFile
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;
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 thefile
state when the user selects a file. -
Form Submission: The
onSubmit
function prevents the default form submission, creates aFormData
object with the selected file, and sends a POST request to the server using Axios. On successful encryption, it updates theencryptionData
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: [],
};
Installing TailwindCSS
First, ensure TailwindCSS is installed in your project:
npm install -D tailwindcss
npx tailwindcss init
Next, add Tailwind to your CSS (client/src/index.css
):
@tailwind base;
@tailwind components;
@tailwind utilities;
Testing the File Encryptor
To test the file encryptor:
- Start the Express server by running
node server.js
. - Run the React app using
npm start
in theclient
directory. - 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)
This is very helpful article.
Thank you.
Anytime