I'm trying to trigger my function on specific path in storage bucket using:
exports.generateThumbnail = functions.storage.bucket("users").object().onChange(event => {});
When I try to deploy it, console shows:
functions[generateThumbnail]: Deploy Error: Insufficient permissions to (re)configure a trigger (permission denied for bucket users). Please, give owner permissions to the editor role of the bucket and try again.
How can I do that? Do I nedd to setup IAM or bucket permission or maybe something else?
Looks like the issue is that you're trying to reference a bucket named "users" rather than filtering on an object prefix.
What you want is:
exports.generateThumbnail = functions.storage.object().onChange(event => {
if (object.name.match(/users\//)) {
// do whatever you want in the filtered expression!
}
});
Eventually we want to make prefix filtering available so you can do object("users"), but currently you have to filter in your function like above.
Related
This question already has an answer here:
Creating Firebase Storage Security Rules Based on Firebase Database Conditions [duplicate]
(1 answer)
Closed 1 year ago.
I want to allow read permission on a file in Firebase Storage only if the value of a certain node in the Firebase Realtime Database is true. Is it possible to do so? If yes, then how?
That is not possible at this time. You would have to use Cloud functions or your own servers using the Admin SDK to do that.
The Admin SDK essentially has full access to your Firebase project's resources so you can check if the value you are looking for in the Admin SDK exists. If yes, proceed with getting the signed URLs (or the data you are looking for from storage) else return an error.
A simple cloud function for that would be something like:
exports.getStorageData = functions.https.onCall((data, context) => {
const {uid} = context.auth;
const {fileName} = data;
if (!uid) return {error: "User not authorized!"}
// Read for data in realtime database
const dbRef = admin.database().ref("/path/to/data");
if ((await dbRef.once("value")).val()) {
return {error: "Required Value is not true"}
}
//Get signed URL or any data from storage
const storageRef = admin.storage().bucket()
//.....
return {data: "..."}
});
You need to use such secure env such as server or functions as only client side validation is not secure. But is the true value in your database something like a role or anything? You can try adding those in Custom Claims. I'm not totally sure about your use case but if it something like allowing access to specific folders or something then you can add a claim the_folder_id: true. This is not the best solution if a user can have access to a lot of folders. In that case you can assign groups as mentioned in the documentation. But satisfies your needs then you can try the following security rules along with this.
// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
allow read: if resource.metadata.owner == request.auth.token.groupId;
allow write: if request.auth.token.groupId == groupId;
}
I am developing an application, which uses Firestore as a database. I have a collection of admins, where the id of the documents is the email address of the admin. I want to create a security rule, which enables only admins to create new documents. My current solution looks like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{collectionName}/{document=**} {
allow create: if exists(/databases/$(database)/documents/admins/$(request.auth.email));
}
}
}
But when I try to run the admin app, it gives a missing or insufficient permissions error. Furthermore, when I try to test it in the rules playground, it gives the following error:
Error running simulation — Error: simulator.rules line [6], column [24]. Function not found error: Name: [exists].; Error: Invalid argument provided to call. Function: [exists], Argument: ["||invalid_argument||"]
As far as I understand, somehow the exists function is missing and the document id is invalid, but why? It's just a string, isn't it?
If you are trying to get the email associated with the auth request, you have to do it like this:
$(request.auth.token.email).
You can see details on the structure of the Request.auth object here.
There is no option to make a user Admin and give special privileges in realtime database I think it goes the same to the FireStore.
But what you can do is add a field in the user like userType and give it the value Admin whenever an admin Signs up, subsequently you can create rules based on that.
We store user permissions in claims.
Here's how the claim of a enterprise customer looks like:
{"roles": ["enterprise"]}
Then, in the rules of Firebase Storage, we try to check whether a customer is enterprise before they are granted access to some files:
function isEnterprise() {
return (request.auth.token.roles) && ("enterprise" in request.auth.token.roles);
}
Then, when the user attempts to retrieve the Download URL of a file from the web using getDownloadURL, Firebase throw a permissions error.
Could you please provide a solution?
Fixed it with this:
function isEnterprise() {
return request.auth.token.roles.hasAny(['enterprise']);
}
I am working on a school project and have elected to use Firebase as a storage option for uploading/downloading files via an app that I am developing. I would like to be able to display to the user a list of all the files within a specific folder, and also give that user the ability to upload files. However, it seems that the only way to access information within the firebase storage, is to, as the developer, know what the file is rather than find files and display them dynamically. I hope I am making sense with this.
Basically, I would like my app to access the firebase storage, go to a specified folder, and then create a bunch of image-buttons in a viewgroup based off of what is in the folder without having to know before hand what to expect.
Would this be possible via metadata? As in, when ever a new file/folder is created within this parent folder, could I also programmatically update that parent folder's metadata to say, "hey there are these specific files within this folder?"
var storage = firebase.storage();
// Create a storage reference from our storage service
var storageRef = storage.ref();
// Create a child reference
var imagesRef = storageRef.child('yourMainFolder');
// Find all the prefixes and items.
imagesRef.listAll()
.then((res) => {
res.items.forEach((itemRef) => {
itemRef.getDownloadURL().then(function (url) {
console.log(url)
}).catch(function (error) {
// Handle any errors
});
});
res.prefixes.forEach((folderRef) => {
console.log("folder", folderRef._delegate._location.path_.split('/')[1])// In my case:)
});
}).catch((error) => {
// Uh-oh, an error occurred!
});
Currently there is no API in Firebase Storage to list all files in a folder.
What you can do is maintain a database of metadata information (such as file names and folder names) somewhere else.
Firebase Realtime Database would be a good choice for this task.
I started out with an issue simply displaying storage contents. The error message was the same Code 400 "Permission denied. Could not access bucket bucket. Please enable Firebase Storage for your bucket by visiting the Storage tab in the Firebase Console and ensure that you have sufficient permission to properly provision resources."
But the changes I made based on This stackoverflow question made the issue worse, now my upload form is giving the same error now and blocks file uploads, even after rolling back all the changes. I tried creating a brand new project on Firebase, but that has the same error.
I also tried to set my bucket permissions to
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read;
allow write;
}
}
}
since I thought that it could be a rights issue, but I get the same error.
I'm not sure what I was trying to do when I added this bit of code, but I had added
{ provide: StorageBucket, useValue: 'bucket' }
To my providers: on my app.module. I think it was a place holder for something and I forgot to remove it before committing the project.
This led me down and interesting troubleshooting path that finally led me to doing breakpoints and console logs until I found the issue.
const task = this.storage.upload(filePath, file);
I did a console log of task, which gave me a location, that's where I found
bucket: bucket
I then added the same console.log to a working project that showed
bucket: whatever.appspot.com
and I knew I made a mistake somewhere. I just happened across the entry in the app.module.ts file while trying to recreate the issue in stackblitz. The error is resolved.