Firebase AppCheck when working with Emulator on localhost - node.js

How are developers working with Firebase App Check when developing locally using the emulator on localhost? Are you disabling App Check on localhost entirely? Or are you able to emulating App Check locally?
Firebase has some instructions on using App Check with a debug provider, but the use case for that seems to be when you want to debug locally but use GCP's backend services in the cloud. It doesn't look relevant for developing against the emulator.
Running this in the client fails recaptcha app attestation with a 403 response (PERMISSION_DENIED), presumably because localhost is not listed as an allowed domain:
const appCheck = firebase.appCheck();
appCheck.activate(
process.env.REACT_APP_FIREBASE_APP_CHECK_SITE_KEY,
true,
);
When enforcing app check in callable functions, context.app is undefined when running in the emulator so requests will fail app check.
Disabling App Check locally is certainly an option, but was wondering if there was a way to emulate app check as well.

I've got it set up, but not without lots of trial and error.
Try adding this snippet right above your call to active appCheck. It seems it needs come before activating appCheck. I was getting that same error until I move the debug snippet before the active call. I am using web version 9 though... not sure if that makes a difference.
if (process.env.NODE_ENV !== 'production') {
self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
}
const appCheck = firebase.appCheck();
appCheck.activate(
process.env.REACT_APP_FIREBASE_APP_CHECK_SITE_KEY,
true,
);
This will print a token to the console which will need to be added to you Firebase project settings. Like described in the link you provided.
Did you do those 2 steps and still get the 403 response?

Related

How can you force #google-cloud/datastore to use 'http' when you query your datastore emulator

I have a node + vuejs app from which I'm trying to query my local db (created using datastore emulator).
My code is something like this
const { Datastore } = require('#google-cloud/datastore')
const datastore = new Datastore({
apiEndpoint: "http://localhost:<port>",
projectId: <my_project_name>
})
I then try to run one of the sample queries on Google's documentation
My output shows there is a successful connection but then I get the following error in the console
POST https://localhost:<port>/$rpc/google.datastore.v1.Datastore/RunQuery net::ERR_SSL_PROTOCOL_ERROR
From the error, I see that it has changed http://localhost:<port> to https://localhost:<port> i.e it is forcing a protocol of https for my local host which then obviously fails.
Is there something/option that I have to specify to ensure that it uses http when I'm making local calls or using the datastore emulator?
I found the solution and am posting it in case someone else has the issue.
I started going through the code itself and discovered a reference to this link. The page says
.....By default, the client library will use gRPC, which is a binary tranport based on HTTP/2. It's Node.js implementation, #grpc/grpc-js, uses Node.js http2 module.
If you need to use the client library in non-Node.js environment or when gRPC cannot be used for any reason, you can use the HTTP/1 fallback mode. In this mode, a special browser-compatible transport implementation is used instead of gRPC transport.
In browser context (if the window object is defined) the fallback mode is enabled automatically; set options.fallback to false if you need to override this behavior....
When I added fallback:false to the options, everything worked i.e. it no longer redirected to https and it connected to my data emulator.
I thought about it further and I believe this behavior is because my code was written in the renderer process for a Vuejs App which means there's a windows object. To confirm, I moved the code to the main process and did not include the fallback option and it worked.

Deploying firebase cloud function fails when I initialise firebase with a service account key

so very recently I started using google's firebase cloud functions, and loved it immediately! I very quickly restructured a project I was going to work on, and included firebase in it, so I could use the cool features of firestore, in combination with cloud functions.
Up until today, everything went on smoothly; pretty much, until I decided to play with google's FCM (Firebase Cloud Messaging) to send notifications via node js. Before this, I had created some really dense functions and already deployed to my console which were working seamlessly.
The tricky part is, at the time I created and deployed these functions, I initialised my firebase app in node js with admin.initalizeApp().
With this, everything worked fine(both locally & deployed) until I tried to use admin.messaging().sendToDevice... which resulted in a very nasty error, that basically told me I couldnt send notifications if I wasnt authenticated..
The error
(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. See https://firebase.google.com/docs/admin/setup for setup instructions. Raw server response: "<HTML>
> <HEAD>
> <TITLE>Unauthorized</TITLE>
> </HEAD>
> <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
> <H1>Unauthorized</H1>
> <H2>Error 401</H2>
> </BODY>
> </HTML>
> ". Status code: 401.)
Following the error, I used a few tips from some other users on stack overflow who had faced this error, and most of them suggested that I download a service key from my console, and initialise my firebase app with admin.initializeApp({credential:admin.credential.cert(serviceAccount)})
This solution worked beautifully, as it allowed me to test my notification without seeing the above error ever again.
However, when all my tests were done, and I was ready to deploy, the new function I had just created to work on notification, as well as all my previously deployed functions could not get deployed. All of a sudden, the old working functions in my console had a red exclamation mark beside them, and I had to get rid of them. Even after I cleared out all of my console and tried to redeploy all my functions, it failed, and failed and failed with no errors(context: I wasted the whole day!!! lool!) Every tip on the internet failed for me, until I reverted back to my old way of initialising my firebase app admin.initializeApp(), then booom! all my functions uploaded successfully, and then again, the authentication error appeared again when I tried to retest my notification function.....
I guess my question is: is there anything I don't know about deploying functions to the firebase console with my app initialised with a service account key I downloaded from my console?
Is there something else I need to do to get my functions to deploy properly every time I init my firebase admin app with a service account key?? Because initialising the app with just .initalizeApp() works fine for all other purposes both locally and when deployed, except when using FCM. Can anyone please help with what is happening here??
I think it can be solved by initializing two apps and using them as objects described here. One with credentials that work for other functions and one for messaging.
If you need it only for one function you can do it even inside it. I have tested it like this:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
exports.first_app = functions.https.onRequest(async (req, res) => {
res.json(admin.app().name);
})
exports.other_app = functions.https.onRequest(async (req, res) => {
var otherApp = admin.initializeApp({
credential: **<< different credential here >>**
}, "2nd_app");
res.json(otherApp.name);
})
as already mentioned, you should initialize a second app just for the new function you are creating. You should put the initialization code inside the new function like this
export const saveMap = functions.https.onRequest(async (req, response) => {
const serviceAccount = require("./../serviceAccountKey.json");
admin.initializeApp({
projectId: "serviceAccount.project_id",
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your_project_id_here.firebaseio.com", //update this
storageBucket: "your_bucket_name_here.appspot.com" //update this
}, "2nd_app")
I had the same issue and once I put the second initialization code into the new function, it worked. Note that in this code the serviceAccountKey.json is in the same folder as src and lib.

Firebase Server NodeJS failing to connect with Service Account

I have a pretty simple NodeJS server that I'm using to monitor our Firebase Database. My code is basically identical to the sample on the Firebase documentation:
var firebase = require("firebase");
firebase.initializeApp({
databaseURL: 'https://myurl.firebaseio.com/',
serviceAccount: 'path/to/json.json'
})
Now the issue I'm having is when I run this code from within our network, it doens't seem to be connection as a have a block of code right after to read some data and it never gets ran:
var nodeRef = this.db.ref("node");
nodeRef.on("child_added", function (snapshot, prevChildKey) {
// ...
}, function (error) {
console.log(error);
})
If I give everyone write access to the database, I can take out the serviceAccount setting on the initializeApp call, and everything works perfectly. I've tried running Fiddler to see what it might be making a request to that is failing, but I'm not seeing any requests pop up in Fiddler at all. Any ideas what this might be calling that our proxy would need to allow?
Our IT team found what the problem was, I had asked them to open accounts.google.com in our proxy server. It got set to "allow" instead of "tunnel".
According to them, the HSTS headers were causing the SSL decryption on the proxy unless it was set to tunnel, which was causing the "self signed certificate" error I mentioned above in the comments.
For me, disabling Kaspersky got it to work. You can try that.

How to cache last loaded data on the client in Cordova app?

I'm building an app on Meteor and have been testing my app on my Android device. It works great. I'm publishing my data on the server and subscribing to it in the client.
But when I don't have data or the server is down, the mobile app shows no content. This makes sense as it can't load anything. But it must be possible to cache the last loaded data from the server so there is at least something to display in the mobile app when there is no connection.
I looked into appcache but that seems to be for assets as opposed to database content. Does anybody know how to make the Cordova version of a Meteor app cache the database locally so it will also work offline?
To cache our iPad application configuration we use localStorage. It's super easy to use and really worked out well for use.
localStorage.settings = settings; // data from server
and when the application starts:
var settings = null;
if( navigator.network.connection.type === Connection.NONE ) {
settings = localStorage.settings
} else {
// fetch settings from server
}
We've been running this implementation for over a year now without any issues.

node.js error ECONNREFUSED on localhost url only

I have a node app, hosted on heroku, where I'm trying to hit an API that returns some JSON. That API I'm calling lives with the same app that I'm calling it from (e.g. The node app hosts my web app and has an API that generates JSON from my db).
I'm using the request npm module to make my API call. When deployed to heroku, when I use localhost:8080 as the url in the function I get the error below, but when I use the actual url where my app is hosted on heroku, it works fine. I have dev/staging/prod environments so I don't want to hard code the url.
Thing is, it works fine locally on my machine, so I'm not sure what the issue is - I'm assuming it has something to do with heroku since that's the only difference, but I'm not very familiar with this type of error.
Also - if it helps, I can hit both urls in the browser fine, locally, and on the heroku app.
request('http://localhost:8080/api/pictures', function (error, response, body) {
// this throws error: "connect ECONNREFUSED"
});
request('http://myapp.herokuapp.com/api/pictures', function (error, response, body) {
// this works
});
connect ECONNREFUSED: the two things you want to look at first:
Is the service you're trying to connect to enabled and started?
Is there are firewall between the client and the service host/service port?
In your case:
1) I assume you've started Heroku locally (on a Windows PC?)
2) I also assume it's running on port 8080 (per your notes)
3) Please check your local firewall software, to make sure Heroku and/or port 8080 are enabled. Do you have any antivirus programs (which might introduce their own firewalls)?
4) Also, please look at these links:
http://windows.microsoft.com/en-us/windows/communicate-through-windows-firewall#1TC=windows-7
http://windows.microsoft.com/en-us/windows/open-port-windows-firewall#1TC=windows-7
https://github.com/heroku/heroku/issues/1046
http://www.debian-administration.org/article/120/Application_level_firewalling

Resources