How to use batch notifications API with Cloud Functions for Firebase? - javascript

I'm just trying to have my app send a notification to the users when someone likes there event.
I have tried to do it this way:
exports.likeAddedNotification = functions.database.ref('/eventLikes/{eventID}/{userWhoLikedID}').onWrite(event => {
const userWhoLikedID = event.params.userWhoLikedID;
console.log("User has liked a post " + userWhoLikedID);
admin.database().ref('events/' + event.params.eventID).once('value').then(function(snapshot) {
var usersID = snapshot.val().userId;
console.log("The person who made the post is " + usersID);
//Send notification to that user
var payload = {
"group_id": "batch_push_sender",
"push_time": "now",
"message": {
"body": usersID + " liked your event"
},
"recipients": {
"custom_ids": [usersID]
},
"sandbox": true, // Only for iOS
};
notificationRequest.write(JSON.stringify(payload));
notificationRequest.end();
console.log("Sent a notification to " + usersID);
});
});
(Sorry for including so much code, but I feel it may all be relevant)
If I use this code and remove the
var payload = ...
and
notificationRequest.write(JSON.stringify(payload));
notificationRequest.end();
it works exactly how I'd expect. It will write to the console saying which post is liked and who liked that post.
I'm really not sure if the issue is coming from doing to much in a closure, or if I'm just doing something plain wrong, or if it's the Batch API that is causing errors.
If you know of a better site for push notifications that allows using a UDID as a custom identifier so that I don't have to manually deal with tokens for each device, please let me know!

First, make sure to return your Promises, that's the only way to guarantee that the Cloud Functions worker will keep things going. Since Firebase Cloud Notifications are sync, it's very likely your request is getting aborted.
You should also check out the Firebase Admin SDK's messaging components. We've built in some nice APIs for FCM.
We have an example on how to use these in Cloud Functions for Firebase on GitHub https://github.com/firebase/functions-samples/tree/master/fcm-notifications

Related

"redirect_uri_mismatch" when sending authentication code to GoogleAPI

I am having trouble with the authentication process for the GoogleAPI. In the end I want to be able to read the users steps using the GoogleFit API and then store that value in a database. Currently I'm using restdb.io and executing javascript in codehooks.
The documentation from Google that I am following can be found here, clicking on the HTTP/REST option in the code examples. At the moment I am at step 5: I have gotten the users authentication code and stored it in the database. Now I have to POST the code along with some other parameters and get the access and refresh tokens.
If the POST is successful (from what I understand) I should get back a 200-OK message that the request was valid. Google will then POST a JSON body with the access and refresh token to the redirect_uri that I have specified in my GoogleAPI credentials page and the initial request. At redirect_uri I have to handle the request and save the two values.
The problem is that I receive a redirect_uri_mismatch - Bad Request message from Google as a response when executing the request. I get it at the log.debug("ERROR HERE: " + [...]); in the code below:
async function mainFunction(){
const authCode = THIS_IS_MY_AUTHENTICATION_CODE;
try {
var answer = await postRequestToGoogle(authCode);
//do stuff with response from Google
} catch (error) {
//do stuff
}
}
async function postRequestToGoogle(authCode){
//body for the request
const params = "code=" + authCode + "&" +
"client_id=THIS_IS_MY_CLIENT_ID" + "&" +
"client_secret=THIS_IS_MY_CLIENT_SECRET" + "&" +
"redirect_uri=THIS_IS_MY_REDIRECT_URI" + "&" +
"grant_type=authorization_code";
try{
const result = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: params})
.then(res => {
log.debug("ERROR HERE: " + JSON.stringify(res.json()));
return res.json();
})
//return JSON back main function
return result;
}catch(error){
//do stuff
}
}
I looked up the error message and tried some things:
Copy and pasted multiple different Authorized redirect URI from the GoogleAPI credentials page into the code to make sure that there is no problem with
http/https
www/no www
trailing slashes
typos or capitalization
Waited for changes to be processed by Google (read that it can more than 30min)
Changed all the other parameters to see if the redirect_uri is actually the problem
If code is changed the message is invalid_grant - Bad Request
If client_id is changed the message is invalid_client - The OAuth client was not found
If client_secret is changed the message is invalid_client - Unauthorized
If the grant_type is changed the message is unsupported_grant_type - Invalid grant_type
That's why I think the issue is the redirect_uri, but it's unclear to me how since I copy&pasted it. Something that came to mind was that maybe the value of redirect_uri gets changed when it's read by Google? Or maybe when the request is being put together? Do some characters have to be replaced?
I tried to analyze the request with Wireshark but didn't think about the fact that it's HTTPS so I would have I would have to decrypt it.. Is that something I should look into?
Thank you for taking the time to read all of this! If you have any advice please let me know :)
Update 16.11.20:
I have created a new OAuth 2.0 Client ID and used the new id/secret in my request. The resulting message the same as before. I will wait and try again tomorrow to see if maybe Google needs some more time. Then I'll try to delete all current IDs and start with a fresh GoogleAPI project.
Update 19.11.20:
Creating a new OAuth 2.0 Client ID did not resolve my problem, neither did creating a whole new GoogleAPI project and adding those credentials into the request. I am in contact with the developers of restdb.io and have asked them to add the Google Auth Library: Node.js Client to the list of supported Node.js packages. Hopefully that will help, I will give it a try as soon as it can be used :)
Update 02.12.20:
No progress so far, but I'm optimistic that the developers will add the package soon. I will post a final update as soon as I am done with this project.

Use git credential manager to fetch azure devops api instead of personal access token

I am trying to fetch git azure devops api to get information about repositories and branches in js.
In order to achieve that, I made a little application with the following code :
$(document).ready(function() {
var personalToken = btoa(':'+'<personnalAccessToken>');
fetch('https://dev.azure.com/<company>/<project>/_apis/git/repositories?api-version=5.1', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
'Authorization': 'Basic '+ personalToken
}
}).then(function(response) {
return response.json();
}).then(function(repositories) {
console.log("There are "+repositories.count+" repositories");
}).catch(function(error) {
console.log('Fetch error: ' + error.message);
});
This code is working great but as you can see there is my personnalAccessToken writen directly inside the code... which is really bad...
When I am using git in command line, I don't have to specify any credential information because I use git credential manager for windows. Which means my personnalAccessToken is already stored, cached and automatically used everytime I use a git command, like clone, etc.
So, I would like my js code to use the same thing, I would like it to use my stored credentials automatically to fetch the api without being required to set my personnalAccessToken in code.
I have already searched for hours but can't find out if it is possible.
I have already searched for hours but can't find out if it is
possible.
Sorry but as I know it's impossible. The way you're calling the Rest API is similar to use Invoke-RestMethod to call rest api in Powershell.
In both these two scenarios, the process will try to fetch PAT for authentication in current session/context and it won't even try to search the cache in Git Credential Manager.
You should distinguish the difference between accessing Azure Devops service via Rest API and by Code:
Rest API:
POST https://dev.azure.com/{organization}/{project}/{team}/_apis/wit/wiql?api-version=5.1
Request Body:
{
"query": "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] = 'Task' AND [State] <> 'Closed' AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc"
}
Corresponding Code in C#:
VssConnection connection = new VssConnection(new Uri(azureDevOpsOrganizationUrl), new VssClientCredentials());
//create http client and query for resutls
WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
Wiql query = new Wiql() { Query = "SELECT [Id], [Title], [State] FROM workitems WHERE [Work Item Type] = 'Bug' AND [Assigned To] = #Me" };
WorkItemQueryResult queryResults = witClient.QueryByWiqlAsync(query).Result;
Maybe you can consider using a limited PAT, limit its scope to Code only:
I know there exists other Authentication mechanism
:
For Interactive JavaScript project: ADALJS and Microsoft-supported Client Libraries.
You can give it a try but I'm not sure if it works for you since you're not using real Code way to access the Azure Devops Service... Hope it makes some help :)
If you have the script set up in an Azure Runbook you can set it as an encrypted variable there and have it pull it from there before running rather than having it directly written into the code.
$encryptedPatVarName = "ADO_PAT"
$adoPat = Get-AutomationVariable -Name $encryptedPatVarName
$adoPatToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($adoPat)"))
$adoHeader = #{authorization = "Basic $adoPatToken"}
The above is the Powershell version of it. I have seen some people do it with other

AWS Cognito Missing required key 'DeviceKey' in params

Hi doing my user management using the so useful Amazon web service Cognito.
I would remember my users devices on login but when I'm calling the
cognitoUser.setDeviceStatusRemembered()
I have this error message :
Missing required key 'DeviceKey' in params
This is how I have implement it:
AuthService.login($scope.username.toLowerCase(), $scope.password)
.then(function(res) {
if ($scope.rememberMe == true)
AuthService.setRememberedDevice($scope.username);
})
My login function is well working for a long time.
I have read on this question :
AWS Cognito Identity JS: Forget/Remember/Do Not Remember Device
...that a call to the getCachedDeviceKeyAndPassword() could solve this problem but I can not figure out where to find an implementation of this method or how to use it.
I think #Ionut Trestian could know the right answer
Which enviornment are you running? If you run it in a browser, the tokens and device keys are stored in local storage, and if you run it in a server side enviornment, they are stored in memory.
I'm not sure which SDK/library you are using. With the current Amplify library, you can get the device key through the user object:
Auth.currentAuthenticatedUser({
}).then(user => {
user.getCachedDeviceKeyAndPassword(); // without this line, the deviceKey is null
console.log(user.deviceKey);
});

How to implement push notification support in Cordova app using Quickblox?

Apologies for such a basic question, but I really can't find any information on the subject.
The Quickblox Javascript SDK has some classes related to push notifications, and I have enabled them using chat_history and the alerting tab in chat. However what I don't understand is how to receive these notifications on the front end UI?
I don't have any code to share as I don't know where to start!
Any help would be truly appreciated, thank you.
There are modules to work with pushes:
QB.messages.tokens
QB.messages.subscriptions
QB.messages.events
To subscribe for pushes you have to do 2 things:
Create a push token using QB.messages.tokens
Create a subscription using QB.messages.subscriptions
Additional info can be found in REST API page http://quickblox.com/developers/Messages#Typical_use_.D1.81ases
Also you have to upload APNS and Google API key to QuickBlox admin panel.
This all needs if you are going to build Cordova app for iOS/Android
You need encode the message.
You need to make sure your mobile app would know to understand the decoded message.
For example,
sending push notification to android qb_user_id: 20290
(and from me - my qb_user_id: 12121):
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function send_push() {
var params = {
notification_type: 'push',
push_type: 'gcm',
user: {ids: [20290]},
environment: "production",
message: b64EncodeUnicode('{"message":"HELLO WORLD","user_id":12121,"device_type":"WEB","message_qb_id":"563a55a44cedaa83885724cf","message_type":"Text","send_status":"BeingProcessed","send_time":1446663588607}')
};
QB.messages.events.create(params, function(err, response) {
if (err) {
console.log("QB.messages.events.create::error:" +err);
} else {
console.log("QB.messages.events.create::response:" + response);
}
});
}
In this example, the mobile app is looking for a message in this format:
{"message","user_id","device_type","message_qb_id","message_type","send_status","send_time"}

Google Cloud Storage Javascript anonymous upload

I want to use GCS to store pictures taken by users in my Cordova app. I have a first major issue : I can't figure out how to use GCS properly for that purpose. Every usable example in the documentation ( here or there for the auth process alone ) needs to give credentials from a Google account on the client side to be able to use the JSON API. I don't want that. Basically I want every people connected to my app to be able to upload freely to the wanted bucket. I thought about issuing tokens for every user of my app, etc... But first I need to be able to upload something anyhow, right ?
My current status is this :
function init() {
gapi.client.setApiKey(apiKey);
gapi.auth.authorize({
client_id: clientId,
scope: 'https://www.googleapis.com/auth/devstorage.full_control',
immediate: true
}, initializeApi);
}
function initializeApi() {
gapi.client.load('storage', 'v1').then(makeRequest);
}
function makeRequest() {
var request = gapi.client.storage.buckets.list({
'project': PROJECT
});
request.then(function(response) {
console.log(response);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
}
And well, the log just gives me the error : "Error: Login Required" along with a 401 unauthorized on
https://content.googleapis.com/storage/v1/b?project=PROJECT&key=apiKey
Well, since I provided everything I had, I guess I need some sort of authentication token. I simply didn't find anywhere how to do that.
The only lead I have would be this : service accounts and it absolutely doesn't sound like something fit for client side code.
Thanks ahead !

Categories

Resources