Local Firebase Cloud Functions issue with Firebase Cloud Messaging - firebase

When I start the functions locally (firebase serve --only functions), it can read & write the Firestore data but when it comes to send the push notification it fails with the following error. It was working since yesterday. Today i updated my MacOS to Big Sur and then it stopped working.
Unauthorized Error 401 An error occurred when trying to authenticate
to the FCM servers. Make sure the credential used to authenticate
this SDK has the proper permissions. See
https://firebase.google.com/docs/admin/setup for setup instructions.
Following is the function that tries to send the notification:
exports.test = functions.https.onRequest(async (req, response) => {
var data = {};
const token = await util.getTokenByEmail('demouser#gmail.com');
let payload = {}, notiData = {}, notification = {}
notification.title = notiData.title = `Test msg`;
notification.body = `Test msg`;
notiData.message = `Test msg`;
payload.notification = notification;
payload.data = notiData;
try {
await admin.messaging().sendToDevice(token, payload);
} catch (e) {
console.log(`Error: ${e}`); // Unauthorized Error 401
data.error = e;
}
response.status(200).json({ data: data });
});
I followed the steps given here and also set the GOOGLE_APPLICATION_CREDENTIALS.
export GOOGLE_APPLICATION_CREDENTIALS="Volumes/demo/Firebase/key.json"
I am downloading the key.json from the Firebase -> Settings -> Service Accounts.

It turned out that, I was setting the GOOGLE_APPLICATION_CREDENTIALS only for that terminal session. Once I set the path to $HOME/.zshrc, it started working. Thanks for your time and help.

Related

How to solve problem Firebase Cloud Messaging error in Firebase Cloud function?

I have some problem about using Firebase Cloud Messaging from Firebase Cloud Functions.
The error message is below. It is from my Firebase Cloud Functions Log console.
Error: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions.
At first, I follow Firebase Cloud Functions CodeLabs.
https://firebase.google.com/codelabs/firebase-cloud-functions
And at last lab "New Message Notifications", when I insert new message at Web "FriendlyChat" app, there is not display notification message. Then I checked log in Firebase Cloud Functions Log console, there was an error message which I had told.
How to solve problem Firebase Cloud Messaging error in Firebase Cloud function?
Or ... How can I check about cloud functions credential before call FCM?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.firestore.document('messages/{messageId}').onCreate(
async (snapshot) => {
// Notification details.
const text = snapshot.data().text;
const payload = {
notification: {
title: `${snapshot.data().name} posted ${text ? 'a message' : 'an image'}`,
body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
icon: snapshot.data().profilePicUrl || '/images/profile_placeholder.png',
click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
}
};
// Get the list of device tokens.
const allTokens = await admin.firestore().collection('fcmTokens').get();
const tokens = [];
allTokens.forEach((tokenDoc) => {
tokens.push(tokenDoc.id);
});
if (tokens.length > 0) {
// Send notifications to all tokens.
const response = await admin.messaging().sendToDevice(tokens, payload);
await cleanupTokens(response, tokens);
functions.logger.log('Notifications have been sent and tokens cleaned up.');
}
});
Thank you in advance.
I solve this problem by set "Enabled" at "Cloud Messaging API (Legacy)" at Project Settings.

FirebaseMessagingError: Invalid registration token provided

I am trying to send push notifications to another iOS device using firebase cloud functions but I receive the following error below when attempting to do so:
'FirebaseMessagingError: Invalid registration token provided. Make sure it matches the registration token the client app receives from registering with FCM.'
This is the registration token I am trying to send to 6e04bb35f06e2d981d5603bbd229eeab5ee5649f6af7b4ecc3894be6ad1574d7 which is the same token I have saved in my realtime database:
Below is my onCreate function:
exports.onMessageCreate = functions.database.ref('/messages/{chatId}/{messageId}').onCreate((snapshot, context) => {
const chatId = context.params.chatId;
const receiverId = chatId.replace(context.auth.uid, '');
const root = snapshot.ref.root;
return admin.database().ref(`/users/${receiverId}/regToken`).once('value').then(tokenSnap => {
var regTokenRef = tokenSnap.val();
const payload = {
notification: {
title: 'title',
body: snapshot.val().text,
}
};
const options = { priority: "high" };
return admin.messaging().sendToDevice(regTokenRef, payload, options).then(function(response){
console.log("Successfully sent message: ", response);
console.log(response.results[0].error);
}).catch(function(error) {
console.log("Error sending message: ", error);
});
});
});
Do you know what may be causing this error? I am not too sure what I need to check here. Is the format wrong here? Does it need to be in quotes? I have looked at other links but they haven't really helped.
I am importing '#react-native-community/push-notification-ios' to generate the token. I think this may be the problem. I was having issues to use the messaging from firebase. Is this the issue?
Please see below the didFinishLaunchingWithOptions method updated in my AppDelegate.m file. Have I placed the below code correctly? When this is added it is causing my app to appear blank when launching the simulator with the FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).? However, when removed my app launches but with still has the FirebaseError.
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
#react-native-community/push-notification-ios is not able to generate an FCM token, only APN token: https://github.com/react-native-push-notification-ios/push-notification-ios/issues/117
If you want to use firebase, you need to generate the token from the messaging package of firebase to have a FCM one.

Firebase functions run in one firebase project but giving internal error in the other

I have two firebase accounts one used for development(D) and the other for production(P). My development(D) firestore and functions run on us-central1. On production(P) firestore location is asia-south1 and functions run on us-central1
My firebase functions run properly in development (D) but are giving me the following error in production. Further, when I check the logs on the firebase functions console, there does not seem to be any activity. It appears as if the function has not been called.
Error returned by firebase function is :
Function call error Fri Apr 09 2021 09:25:32 GMT+0530 (India Standard Time)with{"code":"internal"}
Further the client is also displaying this message :
Access to fetch at 'https://us-central1-xxx.cloudfunctions.net/gpublish' from origin 'https://setmytest.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. zone-evergreen.js:1052 POST https://us-central1-xxx.cloudfunctions.net/gpublish net::ERR_FAILED
Here is the code from my angular app calling the function -
const process = this.fns.httpsCallable("gpublish");
process(data).subscribe(
(result) => {
console.log("function responded with result: " + JSON.stringify(result));
},
(err) => {
const date1 = new Date();
console.log("Function call error " + date1.toString() + "with" + JSON.stringify(err));
});
Here are the functions -
index.ts
import { gpublish } from "./gpublish/gpublish";
import { sendEmail } from "./sendEmail";
export {gpublish,sendEmail };
gpublish.ts
import * as functions from "firebase-functions";
const fs = require("fs");
const { google } = require("googleapis");
const script = google.script("v1");
const scriptId = "SCRIPT_ID";
const googleAuth = require("google-auth-library");
import { admin } from "../admin";
const db = admin.firestore();
export const gpublish = functions.https.onCall(async (data: any, res: any) => {
try {
const googleTest = data.test;
console.log("Publishing to google test of name " + googleTest.testName);
// read the credentials and construct the oauth client
const content = await fs.readFileSync("gapi_credentials.json");
const credentials = JSON.parse(content); // load the credentials
const { client_secret, client_id, redirect_uris } = credentials.web;
const functionsOauth2Client = new googleAuth.OAuth2Client(client_id,client_secret, redirect_uris); // Constuct an auth client
functionsOauth2Client.setCredentials({refresh_token: credentials.refresh_token}); // Authorize a client with credentials
// run the script
return runScript(functionsOauth2Client,scriptId,JSON.stringify(googleTest)
).then((scriptData: any) => {
console.log("Script data is" + JSON.stringify(scriptData));
sendEmail(googleTest, scriptData);
return JSON.stringify(scriptData);
});
} catch (err) {
return JSON.stringify(err);
}
});
function runScript(auth: any, scriptid: string, test: any) {
return new Promise(function (resolve, reject) {
script.scripts
.run({auth: auth,scriptId: scriptid, resource: {function: "doGet", devMode: true,parameters: test }
})
.then((respons: any) => { resolve(respons.data);})
.catch((error: any) => {reject(error);});
});
}
I have changed the service account key and google credentials correctly when deploying the functions in development and in production.
I have tried many things including the following:
Enabling CORS in Cloud Functions for Firebase
Google Cloud Functions enable CORS?
The function is running perfectly in Development firebase project but not in Production firebase project. Please help!
You need to check that your function has been deployed correctly.
A function that doesn't exist (404 Not Found) or a function that can't be accessed (403 Forbidden) will both give that error as the Firebase Function is never executed, which means the correct CORS headers are never sent back to the client.

Firebase functions with nodemailer POST request: Error: Process exited with code 16

I'm running a Firebase cloud function whose purpose is to handle the backend of a "contact me" form. The Express framework is being used for middleware functions. When the submit button is clicked, a POST request is made to the /submit endpoint.
index.js in the functions folder is as below:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const bodyParser = require("body-parser");
const express = require("express");
const emailRoute = require("./routes/email");
// Initialize Firebase in order to access its services.
admin.initializeApp();
const app = express();
// Automatically allow cross-origin requests.
app.use(cors({ origin: true }));
app.use(bodyParser.urlencoded({extended: false}));
app.use(emailRoute);
// Expose Express API as a single Cloud Function.
exports.app = functions.https.onRequest(app);
The imported router from email.js is as follows:
const nodemailer = require("nodemailer");
const express = require("express");
const router = express.Router();
router.post("/submit", (req, res) => {
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: "email#gmail.com",
pass: "password",
},
});
const myEmail = {
to: "myemail#gmail.com",
subject: `A new message from ${req.body.name}`,
text: `${req.body.name} sent the following message:
\n\n ${req.body.message}
\n\n Senders email: ${req.body.email}`,
};
const sendersEmail = {
to: req.body.email,
subject: "A copy of your message to me",
text: `You just sent me the following message:\n\n${req.body.message}`,
};
console.log("SUBMIT REQUEST PROCESSING");
transporter.sendMail(myEmail);
transporter.sendMail(sendersEmail);
res.redirect("/#contact");
console.log("PROCESSING COMPLETE");
});
module.exports = router;
There is no issue when running this in the local environment - the email gets sent to both parties. However, when run in the hosted environment as a Firebase function the following error is thrown: Error: Process exited with code 16 (as displayed in the function logs section of the Firebase console). A previous SO answer indicates an uncaughtException or unhandledRejection.
Before the error, both console.log() statements are logged. Then the function finishes with a 302 status code (as it does when run locally and successfully). After that, there is the unhandled rejection followed by Error: Invalid login and a link to my Google account and a statement "Please log in via your web browser and then try again".
Could this be a Firebase security measure against automated mailing that nodemailer is attempting to execute?
I needed to both enable less secure apps and display unlock captcha on the gmail account, only the former of which I had previously done.
I also needed to set the gmail.email and gmail.password Google cloud environment variables. This can be done with the following shell command: firebase functions:config:set gmail.email="myusername#gmail.com" gmail.password="secretpassword"
A great resource I found on this is an official Firebase function sample that utilises Nodemailer, where the above is covered.
The issue is in logging to your Google account. Have you enabled less secure apps in your Google account? Or better I would recommend to use some other authentication, as described here:
https://support.google.com/a/answer/176600?hl=en

Firebase Node SDK ref.on and ref.once not working

I've been using firebase for a couple years now and I've not run into this - I believe it is Google Account/Firebase Account related.
This basic code will not get into the ref.on() or ref.once() function - either the success or error callbacks. What is the deal?
var firebase = require('firebase');
var admin = require('firebase-admin');
const serviceAccount = require('../firebase-security.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://swc-shockball3.firebaseio.com/'
});
var db = admin.database();
console.log('trying to get ref .once')
var itemsRef = db.ref('items');
itemsRef.once('value', function(snapshot) {
// never gets here
console.log(snapshot)
}, function(error) {
// doesn't get here either
console.log('error is')
console.log(error)
})
I've found if I console.log the itemsRef itself it will return a largish firebase-y object. I also can log itemsRef.once.toString() and it will log the function signature, but CALLING it doesn't actually work correctly.
I ensured my permissions for the database are read/write as true (boolean). I've ensured that the json for my serviceAccount is correct- I even blew away my firebase project altogether and created a new one.
What gives?
I turned on admin.database.enableLogging(true) and could then see the error message was Googal OAuth token invalid grant error. I created a new service account, no change.
But then I simply changed my local machine (Windows 10) time settings to be automatic time/automatic date. That fixed it!

Resources