I'm building a chat application for Android using a Node.js server..
When a user wants to open a new Topic/chat group, few things need to be done:
1. Create the Topic using Amazon's (AWS) SNS SDK.
2. Subscribe each one of the requested users to this Topic, using their AWS Endpoint ARN.
My question is on the Node.js AWS SDK, but corresponds to the AWS Android API as well as they currently work the same in this matter.
Question 1:
How do I subscribe multiple Endpoint ARNs in one call?
Currently I have to wait after each "subscription request" to make sure it is successful before I submit the next one. It takes too much time and effort.
Question 2:
In case a user wants to unsubscribe from the entire app, I delete his/her Endpoint from AWS-SNS.
BUT, their subscriptions to the various topics remain! So effectively, they still receive all the data/messages (and there is no app to receive it of course).
Please let me know if any code is needed.
* I thought maybe I would just put a json'd List with all the ARNs, but it did not work.
Currently AWS SDK does not accept the array of Arns.
AWS-SDK/sns.subscribe
The possible solution is to use a bulk array of requests but this action is throttled at 100 transactions per second (TPS) according to the AWS documentation.
Here is an example of Node.js API calls.
const subscribe = async (TopicArn, arns) => {
try {
const promises = []
arns.forEach((Endpoint) => {
promises.push(sns.subscribe({
Protocol: 'application',
TopicArn,
Endpoint,
}).promise())
})
await Promise.all(promises)
} catch (e) {
console.error(e)
}
}
Related
I am trying to implement SafetyNet in my app. I also, don't have a server, and I am using Firebase Firestore and Firebase Functions.
My knowledge about Firebase Functions is very limited. And I was wondering if I could somehow use the functions to help me with the SafetyNet attestation. As I see, I should be producing a nonce on the cloud, send this nonce to the app, use it to attest, and send it back to the cloud to verify the integrity correct?
But I can't seem to find anywhere on how to do this. Can anyone point me in the right direction?
YES
Sorry for the excitement there, but this is possible since a few weeks ago through a new feature called Firebase App Check.
With App Check, you always end up with a two-step process:
Use an attestation provider (such as SafetyNet) in your application, so that information about the app is attached to each request it makes to Firebase.
Then at some point in time, when enough of your app requests have this information attached, check for the app information in Cloud Functions, or enable the check in one of the other supported services.
If you check the documentation on enabling App Check enforcement for Cloud Functions, you'll see that it mostly boils down to this check in the code:
exports.yourCallableFunction = functions.https.onCall((data, context) => {
// context.app will be undefined if the request doesn't include a valid
// App Check token.
if (context.app == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called from an App Check verified app.')
}
// Your function logic follows.
});
I'm building an Android App that searches for nearby locations. I use Firebase login system (Login with email and password, and login with Google, Facebook, etc), therefore I would also like to build an API with Firebase. (also because I need the app to be more complicated) I have built a serverless API with Firebase Cloud Functions and I can make GET/PUT requests with Postman. However, I would like to secure these endpoints, similar to how JWT secure a RESTAPI, so that only users who logged in the App can make requests. How do I achieve this? I have looked at "authorized-https-endpoint" but it seems like it only allow Google-Sign-In.
Or is there a way that I can still use Node and Mongodb RestAPI, and secure it using the accounts logged into Firebase?
Here is a piece of the backend code
app.get('/api/read/:item_id', (req, res) => {
(async () => {
try {
const document = db.collection('items').doc(req.params.item_id);
let item = await document.get();
let response = item.data();
return res.status(200).send(response);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
})();
});
exports.app = functions.https.onRequest(app);
Thank you guys so much in advance.
Use Firebase Callable Functions. They fulfill your requirement.
Refer: https://firebase.google.com/docs/functions/callable
In the case where there are issues with the function calls, please refer to this: firebase.google.com/docs/functions/callable-reference.
As mentioned here this is to be used only if the SDKs don't work for you
The authorized-https-endpoint example supports all forms of auth on the client, as long as it's going through the Firebase Auth SDK. In all cases, the client can send an auth token to the function, and the function code can use the Firebase Admin SDK to verify the token. It doesn't matter how the user authenticated - any Firebase user account will work.
You can also use a callable function, which will automatically perform the validation for you in the exact same way. Your code must then check to see if a user was authenticated using the calling context before continuing.
Brief information: I am working on a quiz application for Android. The database is on Firebase and the users login via anonymously. When the user opened the application, it will be automatically signed-in.
My question is about firebase. I could not build the intelligence for firebase requests.
When the application is opened;
1) signInAnonymously (which firebase function) should be called first.
2) Then i check that the signed user has a saved point or not on firebase database.
3) If the user does not have point, it is generated.
4) Then i send a request to get the point of user.
In all steps, i send a request to firebase via async firebase methods. The sequence is important because the output of any step can be an input for the next step.
I handle this via callback. But i do not know that it is the best way.
screenshots of callbacks for these steps
Can you give me advice for these? If i do not use callbacks, problems are occured because of asynchronous firebase methods. The reason of that i open this issue is undetermined problems. I can learn and build any other algorithm to make it better. Thank you.
It looks like you are using nested callbacks and I am not a Java programmer, but you may want to take it easy on yourself and not go that route.
If my signing in anonymously you mean a One-Time-Password authentication flow such as just providing a phone number, that would definitely be a good approach.
You can use Google Cloud Functions, but the functions would have to be written in Nodejs, Python or Go.
Either way take a look at this flow below:
User requests OTP
Acknowledge the request
Generate code, save the code on backend (GCF)
Text user the code
User sends you the correct code
Compare codes on the server
Send user some kind of token or as you say a "point" to identify them.
I do believe Java does have support for JSON Web Tokens.
So after your setup GCF project, you are going to get some folder and files like so:
.firebaserc: a hidden file that helps you quickly switch between projects with firebase use.
firebase.json: describes properties for your project.
functions/: this folder contains all the code for your functions.
functions/package.json: an NPM package file describing your Cloud Functions.
functions/index.js: the main source for your Cloud Functions code.
functions/node_modules/: the folder where all your NPM dependencies are installed.
You want to import the needed modules and initialize the app:
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const serviceAccount = require("./service_account.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://my-project.firebaseio.com"
});
That service_account.json is something you need to create, its not a library.
It will have a bunch of private and public keys that you get from your Firebase console. Ensure you also place that file inside your .gitignore files as well.
So I am skipping some crucial details here that you will have to figure out so as to get to your main question.
First, you need the idea of a user, so you need to create a user inside GCF so that in itself is going to be a function and as you mentioned Firebase is asynchronous so it would look something like this:
const admin = require("firebase-admin");
module.exports = function(req, res) {
// Verify the user provided a phone
if (!req.body.phone) {
return res.status(422).send({ error: "Bad Input" });
}
// Format the phone number to remove dashes and parens
const phone = String(req.body.phone).replace(/[^\d]/g, "");
// Create a new user account using that phone number
admin
.auth()
.createUser({ uid: phone })
.then(user => res.send(user))
.catch(err => res.status(422).send({ error: err }));
// Respond to user request saying account was made
};
So the code above I grabbed from a previous project of mine, except the whole thing was in JavaScript. For you this part will be in JavaScript or Nodejs specifically as well since again, Nodejs, Go or Python are the only languages supported by GCF.
So the comments are self-explanatory but I feel compelled to explain that the first thing I had to resolve is how to pass in information to this function in a request.
To do that I had to reference the req.body object as you see above. req.body contains all the different data that was passed to this function when the user called it. I was not sure if you knew that. So before you go and copy paste what I have above, do a res.send(req.body);. So nothing else inside that module.exports = function(req, res) {} except res.send(req.body);, so you can get a good sense of how this all works.
For every function you create you need to run a firebase deploy name-of-project.
After you feel you have a handle on this and its all working successfully, you can create your Android Studio project and add the database dependency like so:
compile 'com.google.firebase:firebase-database:10.2.1'
And then you will probably want to create your User model, maybe like this:
public class User {
public String phone;
public User() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public User(String phone) {
this.phone = phone;
}
}
And so on, anyway I hope that kind of gives you a good enough idea that it gets you going. Best of luck. I know I failed to take time out to explain that the regex in my code is to sanitize the phone number and probably some other stuff. So again, don't just copy paste what I offered, study it.
I'm developing a chat application using Firebase Database in Android.
I've already done the core (chat and user's list activities), but I have yet to do the notification system.
What I want is that when a user is added to a conversation (single or group) and another user writes a new message to the conversation, the first user has to receive a notification that if clicked opens the conversation activity.
My big dilemma is how to structure the service that runs in background to receive the push notification or to listen to the firebase database node I need to look at to know if there are any messages.
I figured out two different approaches:
Approach 1) Use the firebase notification
With this approach I simply send a data notification from the sender client to all the other clients in the conversation when the sender sends a message, and so the receiver will decide to show the notification (if the chat activity it's not opened) and handle the click action.
With this approach I think I will save CPU consumption and then battery.
What I don't understand is how to register a user to receive a group notification (topic notification) because as I understood, I have to subscribe that client to the topic, but if the application is in background or close, how does it knows that a new group, with its user inside, has been created and so it has to subscribe to the topic?
For the two-users conversation scenario this is not a problem as I can send the notification directly to the destination user without needing him to be subscribed to any topic.
Approach 2) Listen to a firebase database data node with a background service
With this approach I just need to create a bootable service that listen to a specific node of the database (with ValueEventListener) and show a notification when data shows that a new message/conversation is coming.
An example of the node to listen to, can be the data about the unseen messages as following:
conversation_user_unseen_messages
$conversationId1
$user1: 3
$conversationId2
$user2: 1
Then, if the data shows new messages/conversations the android app client will decide to show a system notification.
I think that with this approach there will be more energy consumption as it has to constantly check if there are any new message on the db.
Final consideration
I have found a very useful guide written by the mythical Frank van Puffelen,that explains how to set up the system I need, with using an additional server side component (node.js server).
My last question is: do I need to set up a server? Is a better solution than handling everything by the clients (using for example http requests)?
What solution do you think is the best?
Many thanks.
EDIT
I'm still figuring it out, but here it is some consideration.
I have to requesting and using a InstanceID
Instance ID provides a unique ID per instance of your apps.
So i have to request an InstanceID when user is connected and the InstanceId it is avalaible.
And then don't use topics.
Topic messages are optimized for throughput rather than latency. For
fast, secure delivery to single devices or small groups of devices,
target messages to tokens, not topics.
as said in the topic messagin guide that instead suggests to target message to tokens .
To do so I have to collect the user token in my user database reference:
users: {
$userId1: {
name: "John",
email: "john#gmail.com",
token: "Ax8HiP3Edf7....",
}
}
and then when my app client send a new message it has to also has to send a notification for all users involved in the chat, thing that I already can do with my current db structure.
How do I handle and collect the requests?
I implement a node.js server app that connect to Firebase Database and listens for the notification requests made by the app and then sends the notification request by http call to every destination app.
When do I have to register the user token?
When a app client starts for the first time or when the InstanceID expire (onTokenRefresh).
Is this the right way to do it?
EDIT 2
I found a big hole in the FCM implementation. It seems that I can not handle at all notifications delivered to iOs apps that are not in foreground.
As found in the Data notification documentation
On iOS, FCM stores the message and delivers it only when the app is in the foreground and has established a FCM connection. On Android, a client app receives a data message in onMessageReceived() and can handle the key-value pairs accordingly.
And I need to catch the data notification even when the app is in background, I need that specifically because I want to update my badge counter on the app icon to let the user know how many unread messages he has.
I'm now tryng the OneSignal solution can receive notification even when in background, it's free and interfaces with GCM. I'm sad to not stay with Google but if I can't update the badge count using FCM I have to look to an other side.
Any consideration will be appreciated.
Approach 1 is the one that you should use. Frank's guide is using the first approach, so you need to set up a server.
Is it a better solution than handling everything by the clients (using for example http requests)?
Yes. If you send the notification in the client (the app), your API Key will be exposed (via network sniffing or reverse engineering) and you definitely would want to avoid that.
how to subscribe a user to a new group topic if the app is closed or in the background?
Looks like you have to create relation mapping on the server, by calling https://iid.googleapis.com/iid/v1/IID_TOKEN/rel/topics/TOPIC_NAME with Authorization: key=YOUR_API_KEY as the header, the full description is here. Follow this guide to get the Instance ID token.
I hope my answer answers your questions. Cheers :)
Now you can simply achieve this using firebase functions ...
Here's mine
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendFollowerNotification =
functions.database.ref('/whatever/{groupUID}/{userUID}/{todoUID}')
.onWrite(async (change, context) => {
const useruuid = context.params.userUID;
const thisdata = change.after.val();
console.log('sendto:'+useruuid);
var ref = admin.database().ref(`userdatas/${useruuid}/phonetkn`);
return ref.once("value", function(snapshot){
const payload = {
notification: {
image: "default",
sound:"default",
vibrate:"true" ,
title: 'New Mission !',
body: thisdata.titre ,
color: '#22c064',
icon: "notification_icon"
}
};
admin.messaging().sendToDevice(snapshot.val(), payload)
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
});
//
Hello all i am making an android app in whiich i have multiple account login at a time now my question is that i for multiple logins i should use sessions to verify every account user that is logged in. Now i am using express on the server side i have read a lot of documentation on storing sessions in node.js
Express-session (Though it is only good for development but not for production but not for my app)
Cookie-session
connect-Redis
connect-mongo
I have also heard about json web tokens where i can generate unique tokens and then i can pass the tokens to the client using res.json({user_id:"user1", token: "generated_token here"})
I have also heard about passport but dont know how it is going to do this also as in passport i use express-session by default will it be good for production or not ??
Now my first question is i have read all of there docs and nowhere it is mentioned where i am creating unique tokens for every user that is signing up.
Second question as i am using my server for android app there will be no use of cookie i will be sending user token as in parameter req.body.token now how to cmpare this with current user_id.
Actually i dont get the flow of control i mean how everything is going on in session in node.js. Also what is this secret is this thing generating unique tokens or what. Also i mean about 100000 of users are registered for my app now please tell me accordingly which way should i use for my app.
I have asked this question previously but there i did not mention that as i am not making a website how to do this(As in my case there will be no use of tokens)
I know this question i am asking is very vague but please bear with me i just want to understand how sessions are used in node.js
Thanks Anways
I'll try to answer this, but it is vague (as you pointed out). I'm going to make an assumption that your Android app is a native Android app and is going to be connecting to some sort of NodeJS backend in the cloud that is based on ExpressJS. If that's not the case, please clarify your thoughts in an update to your question.
The best idea for this specific scenario is to look to the cloud provide. Azure App Service Mobile Apps, for example, allows you to implement authentication - it eventually returns a JSON Web Token (http://jwt.io) to authenticate each request.
If you don't want to be beholden to a cloud provider, but want to run it yourself, you are going to have to implement the token generation and checking yourself. This generally follows the form:
Set up a WebAPI endpoint (maybe /signin) which takes whatever token the identity provider gives you, verifies the information and returns a JWT - there is an NPM module (jsonwebtoken) for producing the JWT. Ensure the JWT includes the identity of your user. I tend to use email address for the identity.
Your Android application will do a WebAPI request to your backend with an Authorization header, the value of which is "Bearer "
Your NodeJS API will use JWT authorization to validate the JWT and extract the user identity so you can use it in your API logic.
The important thing to note in this specific scenario is that your backend code is implementing a WebAPI - there are no cookies nor sessions in the API. The only thing that is linking the user from the client code to the backend code is the JWT.
As a short piece of code, here is how you verify a JWT:
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var jwtCheck = jwt({
secret: new Buffer('your-jwt-secret', 'base64'),
audience: 'your-jwt-audience'
});
app.get('/api/protected', jwtCheck, (req, res) => {
// Your code here
});
app.listen(process.env.PORT || 3000);