I don't understand how can I set a limit of files upload in a day. I want users to publish a maximum of 10 photos per day. On the database side I put a increment counter. If it reaches a certain size it does not allow a user to post other contents. but by the storage side this is impossible. An attacker can publish all files that he want without limits. Is there a solution to prevent this situation? Thanks in advance. At moment my security rules are:
service firebase.storage {
match /b/projectid/o {
match /Photo/{user}/{photo}/image.jpg {
allow write: if request.auth != null &&
request.auth.uid == user && (
request.resource.size < 5 * 1024 * 1024 && photo.size() < 32 ||
request.resource == null);
allow read: if request.auth != null &&
request.auth.uid == user
}
}
}
Well, there's a very simple way of doing this, and there's the right way of doing this.
The hacky way of only allowing a certain number of files to be uploaded in a certain time period is to name the files with some numerical property: say users/{userid}/0.jpg
through users/{userid}/9.jpg
(for 10 photos).
You can write a rule to check that as follows:
// Match all filenames like 0.jpg
match /users/{userId}/{photoId} {
allow write: if photoId.matches('^\d\.jpg$')
}
If you need more granularity than order of magnitude, you can do something like:
// Match all filenames like YYY.jpg where YYY is a number less than XXX
match /users/{userId}/{photoId} {
allow write: if int(photoId.split('\.')[0]) < XXX
}
That only solves half our problem though: we can restrict the number of files, but what if a user just wants to upload over them? Luckily, we can write a rule that prevents an end user from overwriting their file ever (though we've got to carve out deletions), or within a given time period. Let's explore:
// Allow files to be overwritten once a day, written if there's nothing there, or deleted as often as desired
match /users/{userId}/{photoId} {
allow write: if request.time > resource.timeCreated + duration.value(1, "d") || resource.size == 0 || request.resource.size == 0
}
These can be combined into function:
function isAllowedPhotoId(photoId) {
return int(photoId.split('\.')[0]) < XXX
}
function canOverwritePhoto() {
return request.time > resource.timeCreated + duration.value(1, "d") || resource.size == 0 || request.resource.size == 0
}
match /users/{userId}/{photoId} {
allow write: if isAllowedPhotoId(photoId) && canOverwritePhoto()
}
Long term, the solution is being able to reference Database data from within Storage, and vice-versa. Unfortunately, that world isn't here yet, but we're working towards it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With