Consider an app that allows users to store photos in Firebase storage, these photos have the user's ID set in a cutom metadata 'owner' field.
The following firebase storage security rule ensures only they can see their photos:
allow read: if resource.metadata.owner == request.auth.uid;
Now imagine the app allows a user to make their photos public if they choose, visible by anyone, even users not logged in (request.auth == null). This could be done with another custom metadata field and a slightly different rule:
allow read: if resource.metadata.owner == request.auth.uid || resource.metadata.public == "true";
This works in theory, but requires all photos to have their metadata altered everytime the user toggles public/private access on/off.
To achieve this the following cloud function could be used to update the metadata of all photos under a given 'folder':
import * as functions from 'firebase-functions';
import * as storage from '@google-cloud/storage';
// 'data' contains 'path' of all photos to update and 'public' which will be set to "true" or "false"
export const updatePublicMetadataField = functions.https.onCall( async (data, context) => {
const s = new storage.Storage();
const bucket = s.bucket("bucket name")
const options = { prefix: data.path }
const md = { metadata: {public: data.public}}
const [files] = await bucket.getFiles(options)
for (const file of files) {
try {
await file.setMetadata(md)
} catch(error) {
return { r: 'Error: ' + error};
}
}
return { r: 'Files processed: ' + files.length};
});
The problem with this approach is that if the user has many hundreds of photos, the cloud function will simply timeout as the calls to setMetadata are not fast.
So is there an alternative approach to allow public access to many files (all within the same 'folder') to be toggled on/off?
Some ideas I had which don't seem to be currently supported by Firebase would be:
- Using a single 'security file' in the same folder, containing the required metadata, which could be read by a get() function similar to how Firestore security rules can read an arbitrary document.
- Access to Firestore from Firebase storage security rules to allow reading the user's desired value of 'public' from Firestore.
- Metadata on Firebase storage 'folders'.
- A single (fast) function to update metadata on all files in a 'folder'. E.g. bucket.setMetadata(prefix, metadata)