I am running a problem with my app. I want to check in the backend if the photo which has been uploaded has the allowed dimensions (1024px * 1024px or 1024px * 1980 px, for example), and also that the image is lower than 30MB (for all dimensions).
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /photos/{photo} {
function hasValidSize() {
// Max. photo size = 30MB (For all dimensions)
return request.resource.size < 30 * 1024 * 1024;
}
allow read;
allow write: if request.auth != null && hasValidSize();
}
}
}
Is it possible to check the photo dimensions as a security rule too?
Pd: I have already implemented a photo cropper that has 3 possible dimensions, but what if a hacker downloads the client code and modifies it?...
Thanks.
It's not possible to check image dimensions in security rules. The only thing you can check is the total size of the file, which is what request.resource.size is used for.
In fact, Cloud Storage is used for any type of content at all. It's not limited to images, and doesn't have any special considerations for images. To Cloud Storage, everything is just a sequence of bytes.
If you need to place limits on the contents of the file, you'll need to write some backend code for that, and make sure all your clients are using that backend for the upload. Either that, or use Cloud Functions to write a trigger that deletes invalid files after they've been uploaded.
Related
I'm creating a blog with Firestore. I have two collections called users and blogPosts. Each document in blogPosts contains name, createdAt, createdBy and password (plain string) field.
I want to create a security rule so clients can access a document only if they provide the correct document password.
According to an idea in this link, I wrote a rule like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /blogPosts/{postUid} {
allow write: if
request.resource.data.createdBy == request.auth.uid &&
request.resource.data.name is string &&
request.resource.data.name.size() > 2 &&
request.resource.data.name.size() < 32 &&
request.resource.data.password is string &&
request.resource.data.password.size() > 5 &&
request.resource.data.password.size() < 32
allow read: if
request.auth != null &&
request.resource.data.password == resource.data.password // <---- THIS LINE IS NOT WORKING
}
}
}
I get this error in playground with the rule above: Error: simulator.rules line [16], column [8]. Property resource is undefined on object. So it means we don't have resource.data on read queries.
How can I achieve my goal with Firebase security rules, so only clients that has blogPosts password can access to documents?
What you're trying to do isn't possible with security rules (and also isn't really "secure" at all). A client app can't simply pass along some password in a query. The only time input is checked is for document fields in a write operation, not document reads.
If you want to check a password, you will have to make some sort of API endpoint and require that the caller provide the password to that endpoint. Again, bear in mind that this is only as secure as your ability to keep that password a secret, because once it becomes known (perhaps by simply reverse engineering your app), anyone will be able to use it.
In my application, my user documents have an avatar image associated with them which is kept in cloud storage. Currently I have a field in the user object that references the download URL of its image. Just wondering if this is the correct/best way to do it.
There isn't really a best way to materialize the link between an avatar image that you store in Cloud Storage and a specific user of your Firebase project.
You can very well do the way you do (having a "field in the user object that references the download URL").
Another approach would be to store the avatar images in a public "folder" under your default bucket using the user UID to name the avatar image (see at the bottom the note on "folders").
Then you you can use a link with the following structure to directly download the image (or include it in a img src HTML tag)
https://firebasestorage.googleapis.com/v0/b/<yourprojectname>.appspot.com/o/users%2F38r174prM9aTx4JAdcm50r3V0Hq2.png?alt=media
where users is the name of the "folder" dedicated to public avatar images
and 38r174prM9aTx4JAdcm50r3V0Hq2.png is the image file name for a specific user (i.e. user UId + png extension).
Note that the / is encoded as %2F (standard URL encoding).
You would then set your Cloud Storage security rules like the following:
service firebase.storage {
match /b/{bucket}/o {
match /privateFiles { //All other files that are not under users
match /{allprivateFiles=**} {
allow read: if false;
allow write: .....
}
}
match /users/{userId} { //Public "folder"
allow read;
}
}
}
Note: Actually Google Cloud Storage does not have true "folders", but by using a "/" delimiter character in the file path it will behave similarly to folders. In particular the Firebase console will display the files organised in folders.
After i execute my Firestore-Test-App made with Flutter i look at the Firestore analytics to see how many request my Test-App made. It shows me that i make a minimum of 20 up to 60 document reads with 1 start of the Test. The problem is, the test should result in a maximum of ~1-3 reads as i understand it.
I've read https://firebase.google.com/docs/firestore/pricing. It did help to understand the billing logic of firestore, but following that logic in the article i should be making a maximum of ~5 reads.
This thread: Firestore - unexpected reads also suggests that maybe, the document reads come from the opened Firebase console, viewing the documents. So i closed it before the test and opened it 30 min after. This did not change the result. I also set breakpoints and the code did only execute once.
I opened a completly new Flutter Project to test it.
This is the only part making read requests:
CollectionReference dbUsers = dbInstance.collection("Users");
var user = dbUsers
.where("docId", isEqualTo: fireAppUser.user.uid)
.limit(1)
.snapshots();
var _userSub = user.listen((value) {
if (value.documents.isNotEmpty && value.documents.first.data != null)
print(value.documents.first.data);
});
_userSub.cancel()
Below my firestore rule, which is on default settings for now.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
I have exactly 5 documents in my Database.
I expect to have a maximum of ~5 document reads. Please help me to undestand why this Snippet causes an unexpected number of reads. What could cause it?
Edit: forgot to append the cancel() to the snippet
That code can make a nearly unlimited number of reads, since it's adding a listener to the document. It will cost 1 read the first time you run it, and continue to incur reads as the listener remains added, as the document changes over time.
If the accounting doesn't make sense to you, contact Firebase support with your exact reproduction instructions.
I am successfully uploading images using AngularFire2 to Firebase Storage.
I have the following upload code.
this.AfStorage.ref(`images/${userId}/${timeStamp}`).putString(base64Image,'data_url');
There are a few issues that I want to solve.
How can I set a limit on the file size? Meaning I want the user to be able to upload files which are less than 10mb.
How can I limit the file number? Meaning I want one user to be able to upload only 3 files.
If there are no firebase server size solutions do suggest some client size solutions.
Thanks
To limit the size of uploads, see this example from the documentation:
service firebase.storage {
match /b/{bucket}/o {
match /images {
// Cascade read to any image type at any path
match /{allImages=**} {
allow read;
}
// Allow write files to the path "images/*", subject to the constraints:
// 1) File is less than 5MB
// 2) Content type is an image
// 3) Uploaded content type matches existing content type
// 4) File name (stored in imageId wildcard variable) is less than 32 characters
match /{imageId} {
allow write: if request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches('image/.*')
&& request.resource.contentType == resource.contentType
&& imageId.size() < 32
}
}
}
}
There is no way to limit the number of files with security rules, so you'll have to look at workarounds such as shown here:
https://groups.google.com/forum/#!topic/firebase-talk/ZtJPcEJr0Mc (seems to hint this is possible, but I've never tried it)
limit number of children with storage rules
Limit number of files in a firebase storage path
I want to create a FireStore rule that grantes read privilages to documents after the current date has surpassed a timestamp value in the document.
This is for a blog web application.
E.G a blogger sets a blog post to be available to the public on a certain date.
From reading the documentation this should work, but It dosn't.
service cloud.firestore {
match /databases/{database}/documents {
match /Articles/{article}{
allow read: if request.time.date() < resource.data.date
}
}
}
What I am i missing ??
firebaser here
I tried the same thing a while ago, and found out it isn't currently possible.
It is possible to allow/deny read to a specific document based on a property of that document.
It is possible to allow a query that filters documents based on a property in that document, but currently that is only possible based on request.auth.
This means that unfortunately your filter currently can't be implemented with security rules. I recommend you file a feature request to chime in.
Update (2018-04-24): this might now be possible with request.time, but I haven't had a chance to test yet. Have a look here.
NOTE: As this is my first answer on Stack Overflow, I wasn't allowed to comment on Frank van Pueffelen's answer, so just as a heads-up, the credits for this solution are his!
The request has a request.time which is a timestamp, and Firestore allows for basic math operators on timestamp <> timestamp operations, so your request.time < resource.data.date will work ;)
service cloud.firestore {
match /databases/{database}/documents {
match /Articles/{article}{
allow read: if request.time < resource.data.date
}
}
}
This is based on my personal testing on 2018.09.29
trying switching the < to >.
request.time will be the time of accessing the document while resource.data.date should be the creation timestamp of the document.
try using this for your security rules:
allow read: if request.time > (resource.data.timestampPropertyName + duration.time(1, 0, 0, 0));
duration.time(4, 3, 2, 1) will create a four hour, three minute, two second, one nanosecond duration.
More information can be found at:
https://firebase.google.com/docs/firestore/reference/security/#timestamp
Do remember to wait for sometime after saving your security rules for it to take effect!
Answer of #user776914 is nice but what if there are diff timezones
Lets add +- 27 hours to be sure it was e.g. created in that day +- 1
duration.abs(request.time - request.resource.data.created) < duration.value(27, 'h')
What's max timezone offset
I wanted to do a similar thing for a game. I wanted to activate and deactivate a game object only after a particular date. I used google's cloud functions to do it. I deployed a function that runs every day to check the firestore documents and changes values according to the script.