Ad

How To Securely Connect Firestore Document With Storage File

So I need to save documents to my Firestore, and each document has a link to a file (download link).

In order to achieve this, I:

  1. Upload the file to Firebase storage
  2. Get the download link to the file once the upload has succeeded.
  3. Upload the document with a download_url field linking to the storage file.

You can see this in the code.

This has the following issues:

  • My javascript is all client sided (I work with Github Pages), so someone can simply change the download link and put that in the document upload.
    I can add firestore rules that check whether the download link starts with https://firebasestorage.googleapis.com/v0/b/my_application.appspot.com/o/info, but is this really the best way to go?
  • If the file to upload is legit, but the document isn't, the file will be saved to my storage, but the document will be denied. With no reference to the file, It'll always stay in my storage unless I manually remove it.
function uploadFile(my_file) {
    // Create a root reference
    var storageRef = firebase.storage().ref();
    var uploadTask = storageRef.child('info/' + my_file.name).put(my_file);

    uploadTask.on('state_changed', function (snapshot) {
    }, function (error) {
        console.error("Error uploading file: ", error);
    }, function () {
        // Handle successful uploads on complete
        uploadTask.snapshot.ref.getDownloadURL().then(function (downloadURL) {
            uploadDocument(downloadURL);
        });
    });
}

function uploadDocument(downloadUrl) {
    var name = document.forms["infoForm"]["name"].value;
    var author = document.forms["infoForm"]["author"].value;

    var documentObject = {
        name: name,
        author: author,
        download_url: downloadUrl
    };

    db.collection("info").add(documentObject)
        .then(function (docRef) {
            console.log("Document written with ID: ", docRef.id);
        })
        .catch(function (error) {
            console.error("Error adding document: ", error);
        });
}

I don't know what's the best way of handling this. Any help will be very appreciated :)

Ad

Answer

With Firebase security rules you can enforce certain requirements for both Cloud Storage and Cloud Firestore. But you can't enforce a dependency between them in security rules, so there's no way to validate that the download URL the user puts in the database is the same as the file they just uploaded.

I see a few options:

  1. Implement the entire operation of uploading-a-file-and-writing-the-document in Cloud Functions. So you'd implement a Cloud Function that takes all the required data from the user, and then writes both the file and the document. This way you can be sure that it's always your code doing the writing, and the users can't work around that by writing their own code.

  2. Change what you write to the database. For example, if you write the document's path instead of the download URL you can be sure the file must exist in Cloud Storage. You can even verify that it's in a user-specific folder by checking if the path starts with their UID, and then in Storage rules implementing user-case security.

Ad
source: stackoverflow.com
Ad