Help!
I'm trying to create an endpoint that anyone can call to register the start of a trial. But I only want to allow new trials to be recorded, no edits or deletes on existing trials.
I'm using a realtime database and cloud functions. I mostly have this working.
- I made a node in my database to keep track of when trials start: { trials: { emailHash: timestamp } }
- I made a cloud function with an express app so I can do a POST with fetch to record when a trial starts (region-project.cloudfunctions.net/function/emailHash)
- This function correctly records the trial start date.
- I then made security rules on my database to only allow a write to { trials } if !data.exists() && newData.exists() to ensure the trial start time is never updated or deleted.
The problem is, the security rule isn't blocking calls to my function.
I think that it is because my Cloud Function is using the Admin SDK and not a service account and the admin can write to the database regardless of the rules? I even tried changing the rules to { "trials": ".write": false } and the writes still went through.
But as soon as I get into the pit of service accounts, I get lost really quick. I think Firebase auto-created some service accounts when I setup my project. Do I lock those service accounts down? Or maybe I need to call admin.initializeApp() with a config to use that service account? Or do I need to create a new service account? Or is the problem elsewhere entirely?
I'm not trying to get help with my code, but in case it better explains what I'm doing, here is a summary:
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const express = require("express");
admin.initializeApp();
const app = express();
const database = admin.database();
const emailHash = req.body?.hash;
const now = Date.now();
if (emailHash) {
database.ref(`trials/${emailHash}`).set(now).then(() => {
res.status(200).send("Successfully initialized trial");
});
}
});
exports.externalCall = functions.https.onRequest(app);