DEV Community

Cover image for How I Created a File Sharing Website using Simple REACT
Varshith V Hegde
Varshith V Hegde

Posted on

How I Created a File Sharing Website using Simple REACT

Introduction

Welcome Dev Enthusiasts! In this blog, I will take you through the journey of developing FreeShare, a free online file sharing platform that allows users to share files easily with just a 5-digit code, without the need for sign-up, email, or phone number verification. We'll dive into the features, architecture, and the code behind FreeShare, explaining how it works and highlighting some of the main functionalities.To share my knowledge i have posted the code in my github Check Out Here

I had already created a file sharing application last year by just using html,css and javascript for that check this blog and Website is Named Anyshare

Background - The Need for FreeShare

Free Share

The idea of FreeShare originated from the success of the previous project, AnyShare. While AnyShare was a well-received platform for file sharing, it had some loopholes and limitations that needed to be addressed. With FreeShare, the aim was to build upon the success of AnyShare while providing a more secure and user-friendly experience. By leveraging the power of React and Firebase, we sought to create a robust platform that anyone could use without technical expertise.

Features of FreeShare

  1. Nice and Pleasant UI: FreeShare's user interface is designed to be visually appealing and easy to navigate, providing a delightful user experience.

  2. Upload and Download Files: Users can effortlessly upload and share files, as well as download shared files using a 5-digit PIN.

  3. Free to Use: FreeShare is completely free, ensuring that users can share files without any financial burden.

  4. No Email, SignUp, or Phone Number: Privacy is a top priority, so FreeShare does not require users to provide personal information during the file-sharing process.

  5. Secure File Sharing: Each file shared on FreeShare is associated with a unique 5-digit PIN, ensuring that only authorized users can access the files.

  6. Sharing Multiple Files: FreeShare allows users to upload and share multiple files at once, making it more efficient for bulk sharing.

The Technology Behind FreeShare

FreeShare utilizes a combination of technologies to provide a seamless and secure file-sharing experience:

  1. React: The user interface of FreeShare is built using React, a popular JavaScript library for building user interfaces. React allows us to create interactive and dynamic components that make the platform easy to use.

  2. Firebase: Firebase is a comprehensive platform provided by Google that offers various tools for building web and mobile applications. We use Firebase to store user data, including files and metadata, ensuring fast and reliable access to files.

Working of FreeShare

The working of FreeShare involves several key steps, which we will explain in detail:

Step 1: File Upload

When a user decides to share a file on FreeShare, they are presented with a file upload interface. Users have the option to upload a single file or multiple files simultaneously. We have implemented the DropzoneDialog from the Material-UI library to handle file uploads. Once the user selects the file(s) to upload, the upload process begins.

Step 2: File Storage with Firebase Storage

All uploaded files are stored securely in Firebase Storage. Firebase Storage provides robust security measures, including encryption in transit and at rest, ensuring that user files are protected from unauthorized access.

Step 3: Generating a Unique 5-Digit PIN

For each uploaded file, FreeShare generates a unique 5-digit PIN. This PIN acts as a secure identifier for the file and is required for users to download the shared files. To ensure uniqueness, we employ a recursive function that generates a random 5-digit PIN and checks if it already exists in the database. If it does, the function generates a new PIN until a unique one is found.

Step 4: Storing Metadata with Firebase Realtime Database

The metadata associated with each shared file, including the download URL, timestamp, and unique PIN, is stored in Firebase Realtime Database. Firebase Realtime Database allows us to create a real-time sync with the frontend, providing instant updates and a seamless user experience.

Step 5: Downloading and Sharing Files

To download a shared file, the recipient needs to enter the 5-digit PIN associated with that file. Upon entering a valid PIN, FreeShare retrieves the download URL from Firebase Realtime Database and opens the file in a new window for download. This process ensures that only authorized users can access the shared files.

Code Explanation

Now, let's take a closer look at some of the main functionalities of the FreeShare platform and the corresponding code:

File Upload and Progress Bar



// File Upload and Progress Bar
const uploadFile = (file, filename) => {
    const storageRef = dbstorageref(storage, "images/" + filename);
    const uploadTask = uploadBytesResumable(storageRef, file);

    uploadTask.on(
      "state_changed",
      (snapshot) => {
        const progress = Math.round(
          (snapshot.bytesTransferred / snapshot.totalBytes) * 100
        );
        setPercentage(progress);
      },
      (error) => {
        console.error(error);
      },
      () => {
        getDownloadURL(uploadTask.snapshot.ref)
          .then((url) => {
            setDownloadUrl(url);
            console.log("File uploaded successfully");
            console.log("Download URL:", url);
            generateUniqueNumber()
              .then((uniqueNumber) => {
                console.log("Unique Number:", uniqueNumber);
                setUniqueID(uniqueNumber);
                return storeDataInDatabase(url, uniqueNumber, filename);
              })
              .then(() => {
                console.log("URL and Unique Number are stored in the database");
              })
              .catch((error) => {
                console.error("Error storing URL and Unique Number:", error);
              });
          })
          .catch((error) => {
            console.error(error);
          });
      }
    );
  };



Enter fullscreen mode Exit fullscreen mode

The handleFileDrop function handles the file upload process. It uses the DropzoneDialog component from Material-UI to allow users to select and upload files. The progress bar displays the percentage of the file upload completion, providing real-time feedback to users.

In above code I have used Firebase Storage to upload the file . Initially I have initialzed the firebase storage references . To start the upload process , I have used uploadBytesResumable so that I will be able to display the percentage of the data or file uploaded and at the same time i have indicated that percentage in the progress bar.
If the upload is successfull then only url of the uploaded file be returned using function getDownloadURL . Then , a unique d will be created which will be shown to user.

Generating a Unique 5-Digit PIN



// Generating a Unique 5-Digit PIN
const generateUniqueNumber = () => {
  return new Promise((resolve, reject) => {
    const uniqueNumber = Math.floor(10000 + Math.random() * 90000);
    checkIfNumberExists(uniqueNumber)
      .then((exists) => {
        if (exists) {
          resolve(generateUniqueNumber());
        } else {
          resolve(uniqueNumber);
        }
      })
      .catch((error) => {
        reject(error);
      });
  });
};


Enter fullscreen mode Exit fullscreen mode

The generateUniqueNumber function generates a unique 5-digit PIN for each uploaded file. It uses a recursive approach to check if the generated PIN already exists in the database. If it does, the function generates a new PIN until a unique one is found.

Storing Metadata in Firebase Realtime Database



// Storing Metadata in Firebase Realtime Database
const storeDataInDatabase = (url, uniqueNumber, filename) => {
  return new Promise((resolve, reject) => {
    const database = getDatabase();
    const databaseRef = ref(database, "fileData");
    const newDataRef = push(databaseRef);

    set(newDataRef, {
      url: url,
      unique: uniqueNumber,
      filename: filename,
    })
      .then(() => {
        toast.success("File Uploaded Successfully");
        setShowProgress(false);
        setshowshareUniqueID(uniqueNumber);
        setShowUniqueID(true);
        resolve();
      })
      .catch((error) => {
        reject(error);
      });
  });
};


Enter fullscreen mode Exit fullscreen mode

The storeDataInDatabase function stores the metadata of the uploaded file, including the download URL, unique PIN, and filename, in Firebase Realtime Database. The function uses the set method provided by Firebase to add the data to the database.

File Download and Deletion



// File Download and Deletion
const downloadAndDeleteFile = async (downloadUrl, otp, filename) => {
  const filePath = "images/" + filename;
  const downloadWindow = window.open(downloadUrl, "_blank");
  const functions = getFunctions();
  const deleteFile = httpsCallable(functions, "Deletion");
  const response = await deleteFile({
    url: filePath,
    unique: otp,
  });
  console.log(response);
};


Enter fullscreen mode Exit fullscreen mode

Cloud Function code for Deletion in cloud



exports.Deletion = functions.https.onCall(async (data, context) => {
  try {
    const filePath = data.url;
    const password = data.unique;
    const db = admin.database();
    const fileRef = db.ref("fileData");
    const snapshot = await fileRef.once("value");
    const fileData = snapshot.val();

    const deleteRecord = async () => {
      const deletePromises = [];
      for (const [key, value] of Object.entries(fileData)) {
        if (password === value.unique) {
          deletePromises.push(fileRef.child(key).remove());
        }
      }
      await Promise.all(deletePromises);
    };

    setTimeout(async () => {
      try {
        await deleteRecord();
        await admin.storage().bucket().file(filePath).delete();
        console.log("File deleted from Firebase Storage:", filePath);
      } catch (error) {
        console.error("Error deleting file from Firebase Storage:", error);
      }
    }, 20000);

    return "Success";
  } catch (error) {
    console.error("Error scheduling file deletion:", error);
  }
});


Enter fullscreen mode Exit fullscreen mode

The downloadAndDeleteFile function handles the file download and deletion process. Upon clicking the download button and providing a valid PIN, the function opens the file in a new window for download. Additionally, it
triggers the deletion of the file from both Firebase Realtime Database and Firebase Storage using a Firebase Cloud Function.

In the Cloud Functions code , whenever a reciever downloads the file it will trigger a cloud function which will be able to delet the file after 1 minute. This way it is ensured that privacy is maintained .
In Deletion function it will recieve two data one is filePath , which file to be deleted and uniqueid , it is used to find the Firebase Realtime Data Refrence of the file is pointed.

This function will be invoked even if the User closes his or her browser or anything.

Conclusion

In this Dev Blog, we've covered the development process and main functionalities of FreeShare, a free online file sharing platform. Using React and Firebase, we've built a user-friendly and secure platform that allows users to share files effortlessly with just a 5-digit code. We explored the code behind the platform and explained key functions responsible for file uploads, PIN generation, and file download and deletion.

We hope you enjoyed this Dev Blog and gained insights into how FreeShare works. Feel free to explore the platform yourself and share files with ease!

Happy sharing!

References

Top comments (26)

Collapse
 
miketalbot profile image
Mike Talbot ⭐

Seems like a 5 digit pin would be easy for a hacker to guess, or provide by a DDoS attack, have you protected against that?

Collapse
 
varshithvhegde profile image
Varshith V Hegde

I know about it. Its only for single use only. Therefore if user uploads the file and then intended user downloads it. It will automatically delte all the related files, metadata and everything from the db.

Collapse
 
miketalbot profile image
Mike Talbot ⭐ • Edited

Yeah it's just someone could get it before the intended recipient etc. I can see the attraction of a 5 digit pin for ease of entry, just 100k combinations seems like too few.

  • You could ban IP addresses that get the wrong PIN more than x times (say 5) for a number of minutes.

  • You could rate limit IP addresses to x calls a minute.

  • You could make your PINs be alpha numeric. A 4 digit A-Z0-9 PIN would have 4.5x more combinations, a 5 digit PIN like this would have 118x more.

Also, at present you are using Math.random() - this is a sequence that is well known by hackers - by creating a few links of their own they'd have a good chance of working out the previous and subsequent PINs you were creating with minimal effort - this would negate all of these strategies. You should use a cryptographically secure method of generating randoms when used for purposes like this.

Thread Thread
 
miketalbot profile image
Mike Talbot ⭐

One more thought, you could use a What Three Words type of approach and give people a 3 or 4 word phrase - very very hard to guess by brute force (unless your candidate word list is in the open), quite easy to remember and a large number of combinations with just a few dozen words.

Thread Thread
 
varshithvhegde profile image
Varshith V Hegde

Yeah sure I will surely try to implement. Thanks for your valuable feedback.

Thread Thread
 
miketalbot profile image
Mike Talbot ⭐

Good luck with it, looks like a very cool project :)

Thread Thread
 
varshithvhegde profile image
Varshith V Hegde

Thanks

Collapse
 
varshithvhegde profile image
Varshith V Hegde • Edited

But if you have any suggestions I am open to it. And will try to implement it for sure.

Collapse
 
jcubic profile image
Jakub T. Jankiewicz • Edited

I have my own similar project created with Vanilla JavaScript. It doesn't use any storage at all. It use WebRTC and unique names to send file from one computer to the other directly. I use it all the time when I want to send files from one laptop to other or send it to my phone.

GitHub logo jcubic / webrtc-share

Application for sharing files using WebRTC

webrtc-share

Application for sharing files using WebRTC

Vector illustration with computers, file icon and arrows

License

Released with GNU AGPL 3 license

Copyright (C) 2019 Jakub T. Jankiewicz <jcubic.pl>




Collapse
 
varshithvhegde profile image
Varshith V Hegde

Its a great project. I am also developing similiar one using webrtc but its still in development. But main disadvantage is recieving side should also be ready for sending the files.

Collapse
 
vulcanwm profile image
Medea

great article and interesting project!

Collapse
 
varshithvhegde profile image
Varshith V Hegde • Edited

Yeah please check it out and your feedback is valuable to me freeshare.vercel.app/

Collapse
 
vulcanwm profile image
Medea

dude this is amazing.
it would be nice if instead of having to input the id in the form, you can just share a url which automatically links to a file.
also maybe change the download file button to view file since users may misunderstand that button and believe that they are about to download the file instead of opening it in a new tab

Thread Thread
 
varshithvhegde profile image
Varshith V Hegde

Yes , Thanks for the feedback. About the downloading in the same tab problem with this is my storage and website hosted is diffenrent network or platform thus it impossible to download it on the same tab it will always open in new tab . This is the same problem i got in my previous project too.

Thread Thread
 
vulcanwm profile image
Medea

i don't think it's important to have a download button since if you have a file opened in a tab you can automatically download it

Collapse
 
mdzaiduiux profile image
Mohd Zaid

Good explanation will implement this

Collapse
 
soanvig profile image
Mateusz Koteja • Edited

Check out 'croc'. Your solution sounds similar to Firefox Send (or its nowadays forks). 'croc' approach is far more superior

Collapse
 
varshithvhegde profile image
Varshith V Hegde

Sure!!

Collapse
 
mulugetanigus profile image
Muller_King

Good luck, looks like a very cool project :)

Collapse
 
varshithvhegde profile image
Varshith V Hegde

Thank You !!

Collapse
 
m_hashir147 profile image
Mohamed Hashir

Fantabulous

Collapse
 
varshithvhegde profile image
Varshith V Hegde

Thank You!!

Collapse
 
thepracticaldevgod profile image
The Practical Dev God

Wow it is very great blog . I am new to dev still it is a quality Content . I am gonna use freeshare everyday now.

Collapse
 
varshithvhegde profile image
Varshith V Hegde

Thank You so much I am greatful for your kind words

Collapse
 
nextupweb profile image
nextupweb

Nice Project Dude

Collapse
 
varshithvhegde profile image
Varshith V Hegde

Thank You