Cloud function not found from SDK but callable via HTTPS - node.js

I've deployed some cloud functions to my Firebase project. If I call them with a REST client (such as Postman) they work fine. I'm able to execute them and the output is just as expected.
However, I've tried calling them with both de Web SDK and the Android SDK and, in both cases, I'm getting a not-found error. For example, I tried calling my function createRoom with the following code (btw, quite similar to the official docs example):
var firebase = require("firebase/app");
require("firebase/functions");
let firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
};
firebase.initializeApp(firebaseConfig);
var cloudFunctions = firebase.functions();
const createRoom = cloudFunctions.httpsCallable("createRoom");
createRoom()
.then((result) => {
console.log(result);
})
.catch(function (error) {
console.log(error);
});
and I keep getting following error:
HttpsErrorImpl: not-found
at new HttpsErrorImpl (/home/pitazzo/Proyectos/maximiliana/firebase-mock/node_modules/#firebase/functions/dist/index.node.cjs.js:62:28)
at _errorForResponse (/home/pitazzo/Proyectos/maximiliana/firebase-mock/node_modules/#firebase/functions/dist/index.node.cjs.js:157:12)
at Service.<anonymous> (/home/pitazzo/Proyectos/maximiliana/firebase-mock/node_modules/#firebase/functions/dist/index.node.cjs.js:574:33)
at step (/home/pitazzo/Proyectos/maximiliana/firebase-mock/node_modules/tslib/tslib.js:141:27)
at Object.next (/home/pitazzo/Proyectos/maximiliana/firebase-mock/node_modules/tslib/tslib.js:122:57)
at fulfilled (/home/pitazzo/Proyectos/maximiliana/firebase-mock/node_modules/tslib/tslib.js:112:62)
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
code: 'not-found',
details: undefined
}
Using the Android SDK I get an equivalent error, also including the not-found error code. I can't see whats wrong, because calling the function directly works perfectly.
FYI, calls executed with the SDKs are not event registered in the Firebase console logs. Any help will be appreciated.

I found the problem: Cloud Functions are only avaible in those regions where them were deployed.
That means, you have to specify the region where you want to execute the function when calling it. If no region is specified, Firebase looks for it in us-central-1. If it can not be found there, it fails.

Related

Firebase can't find project ID Firebase Admin SDK cloud messaging

I want to my Node.js server to be able to automatically send firebase cloud messages to devices with specific registration tokens. The docs discuss several ways I can authorize my Node.js server, including relying on the default project authorization if I am deploying with Google Cloud (which I am). However, while I'm testing my Node.js server on my local machine, it seems like I need to set an environment variable with the path of a downloaded configuration .json.
I did this with:
export GOOGLE_APPLICATION_CREDENTIALS="/Users/johnsorensen/Documents/Ops Docs/notificationsmrp-firebase-adminsdk-h86ml-cd2d8d8f7a.json"
I can verify that this indeed the correct file path, as I had Mac's finder return it to me.
When I run my app, however, I get this error:
errorInfo: {
code: 'app/invalid-credential',
message: 'Failed to determine project ID: Error while making request: getaddrinfo
ENOTFOUND metadata.google.internal. Error code: ENOTFOUND'
},
codePrefix: 'app'
Node.js code:
const admin = require("firebase-admin")
admin.initializeApp({ credential: admin.credential.applicationDefault(),})
const registrationToken = 'ePdAwFHd_EBJufZC6XQU8l:APA91bEYD5pFKIMuPwO7oAlKWqbENUXXG_TsLf67IS1Lyf-ge9szJ5Eqo0W8GTqgyheXSyNrNY6_QbU5V8nq39hj42cgphRG9PClgKOY8Ugc6aOFMTTY9t5pWrV_suzvzEXH2cprm3Nv';
const message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
admin.messaging().send(message)
.then((response) => {
console.log("Success")
console.log(response)
})
.catch((error) => {
console.log("Error Sending Message", error)
})
After following the docs provided in the comments, it seemed like I was on the right track. But now gcloud is throwing an error about my .json:
(gcloud.auth.application-default.login) Invalid file format. See https://developers.google.com/api-client-library/python/guide/aaa_client_secrets Expected a JSON object with a single property for a "web" or "installed" application
I downloaded the json from the specified source in the docs... what's going wrong now?
I think the docs I was reading was misleading. I can successfully authenticate a node application by simply downloading the private key from firebase, then using the following code:
const admin = require("firebase-admin");
const serviceAccount = require("/filepath/to/private/key");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});

firebase admin node, insufficient permissions

I've checked the other stacks about this but still not sure why i'm getting insufficient permissions error. Probably I'm being insecure.
I'm trying to sync users from 2 different firebase accounts. The first account calls a firebase function on the second account. If a user does not exist, it creates and does some databasing. If user exists, then it creates a custom token and passes it back to the first account to use in an iframe query parameter.
I've created IAM service account, created keys and saved to file, and edited the service token permissions like the other stacks explain but i'm getting the error nonetheless. Here's my function start:
const firebaseConfig = {
credential: admin.credential.applicationDefault(),
apiKey: "xxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "itsli7-87384.firebaseapp.com",
databaseURL: "https://itsli7-87384.firebaseio.com",
projectId: "itsli7-87384",
storageBucket: "itsli7-87384.appspot.com",
messagingSenderId: "503897448704",
appId: "1:503897448704:web:45773bfb231a24bbe213e5"
}
fb.initializeApp(firebaseConfig);
admin.initializeApp(firebaseConfig);
And the function is running this.
return admin.auth().getUser(data.user.uid)
.then(async function () {
return admin.auth().createCustomToken(data.user.uid)
.then(function (customToken) {
res.send(customToken);
})
.catch(function (error) {
console.log('Error creating custom token:', error);
});
The error
code: auth/insufficient-permission
Error creating custom token: FirebaseAuthError: The caller does not
have permission; Please refer to
https://firebase.google.com/docs/auth/admin/create-custom-tokens for
more details on how to use and troubleshoot this feature.
Instead of using the prescribed method of adding cred.json to admin.credential.applicationDefault(), and passing in the same firebase init config object to admin init, it is working with:
var serviceAccount = JSON.parse(fs.readFileSync("cred.json"));
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://itsli7-87384.firebaseio.com"
});
fb.initializeApp(firebaseConfig);

firestore node.js sdk stops responding on write

I am building a CLI app where I want to use firebase as the backend. I am using the firebase node.js sdk for this and I am running into a problem where after successful login, the firestore add / set functions stop responding and do not trigger either the "then" method or the "error" method.
const firebase = require('firebase');
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "<REDACTED>",
authDomain: "<REDACTED>",
databaseURL: "<REDACTED>",
projectId: "<REDACTED>",
storageBucket: "<REDACTED>",
messagingSenderId: "<REDACTED>",
appId: "<REDACTED>"
};
// Initialize Firebase
var app = firebase.initializeApp(firebaseConfig);
function main() {
firebase.auth().signInWithEmailAndPassword('username', 'somepassword').then((cred) => {
console.log('Successful sign in');
firebase.firestore().collection('UserData').doc(cred.user['uid']).collection('ShellCommands').add({'Hello': 'World'}).then(function() {
console.log("Document successfully written!");
terminate();
}).catch(function(error) {
console.log(error);
});
}).catch(function(error) {
console.log(error);
});
}
main();
Now when I run this, I do see the successful sign in console log but after that the app stops and doesn't respond. It seems like its waiting for user input since the keyboard is active.
My firestore rules are open (for testing).
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
Am wondering if I messed up chaining the promise or is there something fundamentally wrong with doing it this way. Note, this will not be a server but a CLI app.
[EDITED]: The CLI app gets passed a string which it writes to firestore and exits. So everytime, the CLI is run, it would login and write the string. However, the CLI would be per user, so the user is only allowed to write to their collection. something like UserData/{UserID}/Data.

Using AWS API Gateway SDK in Node.JS causes issues

So I am trying to follow the AWS API Gateway SDK tutorial on setting up a secure connection between the NodeJS App and API Gateway link here.
My test function looks like something like below:
require('./lib/apigClient');
require('./lib/axios/dist/axios.standalone');
require('./lib/CryptoJS/rollups/hmac-sha256');
require('./lib/CryptoJS/rollups/sha256');
require('./lib/CryptoJS/components/hmac');
require('./lib/CryptoJS/components/enc-base64');
require('./lib/url-template/url-template');
require('./lib/apiGatewayCore/sigV4Client');
require('./lib/apiGatewayCore/apiGatewayClient');
require('./lib/apiGatewayCore/simpleHttpClient');
require('./lib/apiGatewayCore/utils');
var body = {
"type": "the_best_kind",
"status": "processed",
"name": "test123"
};
export function getRatingsTest(req, res) {
var apigClient = apigClientFactory.newClient({
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY',
sessionToken:'SESSION_TOKEn', //OPTIONAL: If you are using temporary credentials you must include the session token
region: 'eu-west-1' // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1
});
console.log('NEW CLIENT =====', apigClient)
apigClient.calcRatingPost(null, body, null)
.then(function(result){
//This is where you would put a success callback
}).catch( function(result){
//This is where you would put an error callback
});
return res.json({test: 123})
}
I keep getting error such a apiGateway is not defined, CryptoJs is not defined and so on. All the 11 javascript files are not modular which is unfortunate.
What is the best approach for getting this to work in NodeJS?
I also tried the aws-api-gateway-client npm package but no luck yet.

Cloud Functions for Firebase: how to issue a request to my Cloud Endpoint

I'm trying to issue a request to my cloud endpoint project when a certain value is written in the firebase database. I can't find any example of how perform a request to Endpoints in Node.js. Here's what I come up with so far:
"use strict";
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const gapi = require('googleapis');
admin.initializeApp(functions.config().firebase);
exports.doCalc = functions.database.ref('/users/{uid}/calc').onWrite(event => {
return gapi.client.init({
'apiKey': 'AIzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'clientId': '1234567890-xxx.apps.googleusercontent.com',
'scope': 'donno what to put here'
}).then(function() {
return gapi.client.request({
'path': 'https://myproj.appspot.com/_ah/api/myApi/v1',
'params': {'query': 'startCalc', uid: event.params.uid }
})
}).then(function(response) {
console.log(response.result);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
});
When triggered, Functions' log spouts: TypeError: Cannot read property 'init' of undefined. i.e. doesn't even recognize gapi.client.
First, what is the right package to use for this request? googleapis? request-promise?
Second, am I setting up the correct path and parameters for a call to an endpoint? Assume the endpoint function is startCalc(int uid).
Update
It seems that Cloud Functions for Firebase blocks requests to their App Engine service - at least on the Spark plan (even though they're both owned by Google - so you'd assume "on the same network"). The request below, works on a local machine running Node.js, but fails on the Functions server, with a getaddrinfo EAI_AGAIN error, as described here. Evidently, it is not considered accessing Google API when you perform a request to your server running on Google's App Engine.
Can't explain why Firebase advocates here steer clear of this question like from fire.
Original Answer
Figured it out - switched to 'request-promise' library:
"use strict";
const functions = require('firebase-functions');
const request = require('request-promise');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.doCalc = functions.database.ref('/users/{uid}/calc').onWrite(event => {
return request({
url: `https://myproj.appspot.com/_ah/api/myApi/v1/startCalc/${event.params.uid}`,
method: 'POST'
}).then(function(resp) {
console.log(resp);
}).catch(function(error) {
console.log(error.message);
});
});

Resources