I want to have a collection with all the users and I want to store their current location.
I will have a function that is calculating the distance from the current user location to the location of each user that is in the collection and I want to receive only the users that are X kilometers away from the current users.
I can get all the users and filter them on the front-end but wont that be a lot of document reads if there are a lot of users ?
Is there a way to pass the current user location to firebase and do the filtering on the server side ? Or the only way is to get all the users and filter them on the front-end ?
If you want to avoid doing large amounts of work in your client app, you can use Cloud Functions for Firebase to create a backend API endpoint and push that work to a hosted backend. A full discussion of a possible implementation is too long for a Stack Overflow answer, but you will want to read that documentation to get started building a backend. One easy approach is to write a callable function that you can invoke directly from the client. The function can then use the Firebase Admin SDK to query the database, perform some computations, and return the results to the app.
Related
I'm making a little Snapchat clone, and a part of this app I'm trying to build is the ability to add a friend and start a conversation with them. I'm using Firebase to manage my users and I'm a little stuck now trying to figure out what works and why I'm getting problems trying to use some methods or functions.
What I want is this simple line of code to work:
var userByEmail = await _admin.app().auth().getUserByEmail("b#gmail.com");
print(userByEmail.toString());
However this has been giving my some problems, most recently, the following error message:
Unhandled Exception: FirebaseAuthError(auth/invalid-credential): Must initialize app with a cert credential or set your Firebase project ID as the GOOGLE_CLOUD_PROJECT environment variable to call verifyIdToken().
Getting to this point made me want to first ask a question about FirebaseAdmin and Auth before continuing and potentially screwing up my app settings.
Is there a simple way to do what I'm trying to do?
I have a Firebase.instance.initializeApp() in my Main function, do I only ever call that once or should I start initilizeApp in the initState of each Stateful Widget where needed?
What does this error message actually mean?
You are trying to use the Firebase Admin SDK in your Flutter code, which is not possible. The Admin SDKs give full administrative access to your Firebase project, which would be a serious security concern if you allow that in your Flutter app.
If you want to allow certain administrative functionality in your application, you will have to make that functionality available yourself. For example, to look up a user by their email address, there are two common approaches:
Store the minimal information about each user in a cloud-accessible database (such as Firebase's Realtime Database or Cloud Firestore) when each user registers with your app, and then look it up from there.
Wrap the getUserByEmail from the Admin SDK in a custom API that you make for yourself, on a server you control or in Cloud Functions. In that API you validate that the user making the call is authorized to do so, then call Firebase through the API you were trying to use, and return the minimal result back to the caller.
Both of these are feasible and can work to solve a variety of use-cases. But if you've never built backend code before, you might find the first approach easier to get started with.
Also see:
How to get Firebase UID knowing email user?
Flutter get User Data from Firebase
The right way to do what you want is using Firebase auth, authenticating your user and using a collection to store and retrieve users information. That auth information provided by firebase should only be used for authentication and security purposes.
The Firebase admin must have a user logged in to work properly, but its purpose is to provide a more administration environment and should not be used inside a clients app, unless its an admin app.
With all that said, lets go for the rescue:
Authenticate your user (using firebase auth);
After auth, save all the user information you want to share with other user inside its own collection (you will need to create one);
When an authenticated user (this is important) 'request any other users data, you query for the data in the previous created collection.
I am looking to use the https.onCall to accept some input from a user (such as data about another user). I'd then like to do some advanced processing on that data including retrieving sensitive data from other entries on my firestore that should not be exposed. Depending on the outcome of that analysis, I will update other locations in the database. However, I am concerned about the security of the original call and its source. I know that I have the context parameter on the onCall to verify the source was logged in, but I'd like to apply security rules to the final write based on the context.auth provided to the cloud function.
The security rules are straight forward for normal database operations but not if I'm doing an operation (seeded by a normal user) routed through the Admin SDK.
Thoughts?
but I'd like to apply security rules to the final write based on the context.auth provided to the cloud function
As you are aware that you can identify which user made a call to functions as well as that Admin SDK has super-access to database, the general flow should be to write functions in a way that they only edit documents that should be editable by the user.
If you had still like to narrow down access, you can do that for firebase database by passing databaseAuthVariableOverride when initializing admin app.
Read more on authenticating with limited privileges
When you use the admin SDK, or any of the server SDKs, it always bypasses all security rules. Rules only apply to access coming directly from web and mobile clients using the client SDKs.
If you need to apply some sort or restricts to data written from your backend, you will need to code that into the logic of your backend code. Security rules will be of no help.
my app is fetching data from a Firestore database but this data should only be accessible to users who are currently subscribed to In-App-Purchases.
What is the best way to protect this data?
My first thought was routing everything through a Firebase Function, so the user has to send their subscription ID to the function, the function checks it and returns the data, but this would require way too many function calls for just a few users.
If you are not using any server client libraries then you can create a rule on firestore to restrict the reads on the table.
firestore rules docs..
You could simply check if the requesting user has subscribed to In-App-Purchases (assuming there is a flag in the user's data to confirm the same).
This question already has answers here:
Continue execution after sending response (Cloud Functions for Firebase)
(3 answers)
Closed 3 years ago.
I'm currently looking to take in a request (using Express/Firebase Cloud Functions)and do some calculations/make some requests, send a response, but then respond to a user before updating my database or doing some extra calculations.
Use case example: Occasionally, a user will follow another user. This means that I want to update all over my database so that my data is in the right place later on. I don't need my user to wait for me to do this, this is something I can do long after the server knows the user wishes to follow them.
Can I receive the user request, perform a server action, respond to the user, then continue on with my cloud function? I have read inn places that a function terminates on responses, but it's not clear how else you go about this or if it only terminates on specific responses.
The way to explain is not possible to achieve, I mean, after you return from a function the process is done.
However, there are several patterns you can implement, it just matters of playing with triggers, take a look.
You can save a state on a firestore collection and trigger a background function which fetches this state and do whatever you need.
If you don't feel like saving this on collection, you have PubSub available as well.
This should give you a good starting point to investigate what is the best solution for your use case.
Hope this helps!
There are two kinds of cloud Functions for Firebase: the ones that you can call directly (HTTPS Callable functions, HTTPS "simple" functions and scheduled functions) and the one that respond to events generated by some of the Firebase services or Google Cloud features like for example Firestore, Authentication events or Cloud Storage (see https://firebase.google.com/docs/functions for a full list)
Classically, when you want to send a response to a user after he/she initiated a Cloud Function, you would choose an HTTPS Callable functions or an HTTPS "simple" functions. But this is not the only way to do it: you can very well send a feedback to the user with a background triggered Cloud Function, mainly by writing something in Firestore (or the Realtime database) to a location the front-end is listening to.
With this second way, you can very well "respond to the user, then continue on with [the] cloud function". While with a callable Cloud Function when you send back the response to the user the Function is terminated.
So let's describe this method in a bit more details for Firestore:
You trigger the background function, for example by writing to a Firestore document/collection from your front-end
At the same time, from the front-end, you set a listener to a specific document (not necessarily the same document than above). See here for setting a listener.
The Cloud Function starts to do some work and at one moment writes to this specific document in Firestore
In the front-end, the user is informed of the write through the listener
In the background the Cloud Function can continue its other tasks.
The key point is that you have to correctly chain all the asynchronous tasks of the Cloud Function by chaining the promises.
Say I have data fetching code like this
firestore().collection("USERS").get(userId1)
And say my app uses this user in multiple places. Normally with a rest API I would build some sort of data persistence layer, where I map id => users and let my app reuses the in memory data.
In the case of firebase though is it efficient to just call
firestore().collection("USERS").get(userId1)
Whenever I need that user model and just let the firebase sdk figure out if networking needs to happen.