Reputation: 850
I'm trying to achieve the following behavior using Firebase:
This is what I've been trying so far:
uid
in the Real-Time Database.uid
and store it in the file's metadata.auth.uid
matches the uid
stored in the file metadata.This should work well, but what do I do if the user account does not yet exist?
I could create a new account after the user enters the recipient's email address. If I do that though, I have to specify a password. I could specify a random password and use the password reset email, but that isn't a good user experience, also because you can't fully customize the reset email.
If I don't create the new account right away, how can I make sure that only the user with this email address can access the file? Storing the email address in the file's metadata doesn't work since it could change later.
I have a feeling I'm thinking way too complicated here. Is there an easier way to achieve this, or am I overlooking something?
EDIT: I've investigated a bit more and I think one way to do this would be by using a custom auth token, which is suggested by the Firebase Storage guide here. That would require me to setup my own auth server though, which kind of defeats the purpose of using Firebase Authentication in the first place. Is there an easier way to achieve this?
Upvotes: 4
Views: 2616
Reputation: 535
Hey to accomplish what you want to do you'll have to add the uid of the users allowed to read the file in the file's metadata then check if the token's uid is contained in the metadata.
Something like this:
match /internal/{imageId} {
allow read: if resource.metadata[request.auth.uid] != null;
}
resource.metadata is a map so to keep things organized you can have all of the uid with permission to read under a canRead parameter so it'll look like this:
match /internal/{imageId} {
allow read: if resource.metadata.canRead[request.auth.uid] != null;
}
To manage the metadata read through firebase's documentation under "Use File Metadata" https://firebase.google.com/docs/storage/
Read more about security here: https://firebase.google.com/docs/storage/security/user-security, https://firebase.google.com/docs/reference/security/storage
Also I am not sure if filling your metadata with uids is a good practice. I'm not sure if there is a limit to how much data you save there. Hope this helps!
Upvotes: 1
Reputation: 35648
This should be fairly straightforward:
files
file_id_0
file_name: My File
read_write: uid_0
read_only:
uid_1: true
uid_2: true
and of course you have users
users
uid_0
name: Larry
email: [email protected]
uid_1
name: Curly
email: [email protected]
uid_2
name: Moe
email: [email protected]
and some spiffy conceptual rules
rules
.read: false
.writ: false
files
$file_id
//give the person that uploaded the file read access to this node as well as
// any user id that exists in the read_only node
.read: root.child('files').child($file_id).child('read_write').val = auth.uid ||
root.child('files').child($file_id).child("read_only').child(auth.uid) = true
//write access only to the user that created it
.write: root.child('files').child($file_id).child('read_write').val = auth.uid
That's pretty close.
So when uid_0 uploads a file, My File, it is stored in file_id_0. That user then 'invites' another user via their email (assume they exist) to that file. In this case uid_0 invites uid_1 and uid_2 and those user ids are written to the file_id_0 node. Those would be obtained by querying the /users node for those two users.
The sticking point is inviting another user that doesn't already exist.
I think they play there is to have an email watch list node.
watch_list
uid_0
[email protected]: file_id_0
each user observers the users node and if a newly added user email exists in their watch list (uid_0 is watching for [email protected]). Then add them to the file_id_0 /read_only node and remove it from the watch list.
Looking at what I just wrote, it's a bit unelegant so there's probably a better way.
Upvotes: 2