FirebaseDB secured connection?

@TIMAI2
That’s genius! :joy: :brain:

Lost me at the Moabite :man_shrugging:

1 Like

Okay, it seems I have some breakthrough.

Since I cannot use user authentications using the FirebaseDB component in AI, I thought of using the Web component to access the database instead using PUT and GET requests. In that way, I could use authentication acquired using the Firebase Authentication V.3.0 extension.

I was working on it when I found this tutorial achieving similar thing!
Here’s the link.

The only issue with the tutorial is that the custom DataChanged procedure is only triggered after the server sends response to a PUT request. In other words, the custom DataChanged method is not globally triggered. So if you change the data in the same database from a different phone running the app, the DataChanged block won’t be triggered on other instances.

EDIT: It seems the only thing needed in the native FirebaseDB component is the feature of dynamically setting the token field.

MIT considers the code they use to access FirebaseDB to be deprecated. Google deprecated the solution MIT uses to access Firebase some time ago. Jeff indicates Google could pull the rug out from under the current solution at any time. MIT decided a while ago they wouldn't continue developing the tool.

...would they be able to do it? I don't know. MIT provided CloudDB as an alternative to Firebase because they expect the way AI2 links presently might not be possible soon. So beware. FB is a nice tool but it might disappear like Fusion tables. or you might get lucky and Google doesn't change anything for a long time.

If Jeff thinks that, then it's serious!

@Taifun Someone might be interested in creating an extension for the task?

Yep, those gems from bygone era.

See also:

1 Like

@TIMAI2 Great tutorial! Thanks! We now just need to add a “DataChanged” event-like functionality. How does the “DataChanged” event achieve that? IMO if it’s achievable through blocks, then we might also be able to implement it using Web / JavaScript etc.

I have worked up the dataChanged scenario using javascript. This works fine in my computer browser, but I have some more work to do on the authentication to get it working in a webview (to feed the data back with a webviewstring). Watch this space…

@TIMAI2 That’s great! Looking forward for your success!

I have also worked up the getTaglist feature.

Here is the completed html which can be used for the dataChanged event. Firebase returns everything, not the individual changed/added/removed item/s, so work needs to be done when the json is received back through the webviewstring. I have the firebase js scripts stored in the assets along with the html file. All the user details and the firebase config, comes through the webviewstring.

<!DOCTYPE html>
<html>
<meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
<meta charset="utf-8">

<head>
	<title>DataChanged</title>
	<script src="firebase-app.js"></script>
	<script src="firebase-auth.js"></script>
	<script src="firebase-database.js"></script>
</head>
<body>
<script>
	
var wvstr = window.AppInventor.getWebViewString();

var email = wvstr.split(",")[0];
var pass = wvstr.split(",")[1];
var setPB = wvstr.split(",")[2];
var uid = wvstr.split(",")[3];

var firebaseConfig = {
  apiKey: wvstr.split(",")[4],
  authDomain: wvstr.split(",")[5],
  databaseURL: wvstr.split(",")[6],
  projectId: wvstr.split(",")[7],
  storageBucket: wvstr.split(",")[8],
};

firebase.initializeApp(firebaseConfig);
var auth = firebase.auth();
auth.signInWithEmailAndPassword(email,pass);
  
auth.onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
    getData();
  } else {
    // No user is signed in. <Use error message here>
  }
});

function getData() {
var dbRefObject = firebase.database().ref().child(setPB +"/"+ uid);
dbRefObject.on('value', snap => { 
     window.AppInventor.setWebViewString(JSON.stringify(snap.val(), null, 3)); 
});	
}
	
</script>
</body>
</html>

Hi Tim,

That's great! Could you please explain me how the getData funtions works? Does that get triggered when the data in the database in changed?

Yes, any changes (made by anyone from anywhere) are picked up by the html file.

See this firecast for the basics (value events)

You may also want to see the followup, Part II (child events)

FireBase is accessible by two methods:
• Through the SDK (which seems to be the method used by the native blocks of the experimental FireBase component of AppInventor), and
• Through the REST API (HTTPS requests, which AppInventor can also manage with the Web component):

In practical terms, the difference seems to be that:

In the first way (in addition to simple requests to read and write to the DB), also allows setting a listener to the data base node: The FireBase1 .DataChanged block automatically receives changes (made by others to the database child node to which the ProjectBucket is aiming), and allows information updating, or even real-time communications between Apps.
But those requests are not authenticated, and (even with the available extensions) either you can’t secure de database with rules that prevent universal access to sensible nodes; or you can’t set up a listener on the protected ones.

The second way allows sending authenticated requests from AppInventor apps to the Realtime Database REST API, as simple as passing the ID token (generated and received when logging in with the authentication extension) as the auth=<ID_TOKEN> query string parameter. This would solve the problem of access to nodes restricted by rules for authorized users only.
But, how can I set up a listener with http rest? (so that the app receives data updates from a protected node).

This is a handicap that I’m facing in a several years old project.
Can anybody help?

I provided the solution a few posts above....

Thanks a lot TIM.

Sorry.
I'm not capable to folow your explanation for setting a listener on a protected node of the database (my only programming skills are using AppInventor blocks).

On the other side, I've been playing arround for months with writing authenticated requests to FireBase RealTime DataBase using HTTP REST (Thanks a lot for your explanation. This one I understand and can follow).

But I found it unreliable, because had a lot of random errors (both when writing messages from app to server through the data base, and when erasing the messages, to clean the database node.

It's probable I'm doing something wrong.
I send my blocks attached, in case you can do me a favour and can take a look at them.

You appear to have an infinite loop of setting a value in firebase, then deleting, or trying to delete....

Please explain what you are looking to achieve.

Thanks Tim.
I’ll try to explain my best (sorry, it will be long):

The idea is that the app sends a message to a certain server.
App writes the message at the project's FireBase Real Time Data Base, at /UID/node/.
The server (currently it's also implemented as another AppInventor app running on a tablet) has Administrator privileges and has a listener set up on this node, so it receives the message.

Once enough time is allowed for the message to be received by the server (some hundred milliseconds), the app cleans the message from DB.
The reason to delete the messages this way, is that the server would be to busy to take care of that (because there will be too many apps accessing a single server).

Everything was working fine with the standard Fire Base App Inventor blocks.

But every day I received an email from FireBase, warning that current rules allow that anyone could read or write on the database. So I tried to secure the data base.

In order to protect the communication between apps and server from possible pirates, I tried that only authenticated apps could write messages to server. So I set up some rules on FirebaseDB:

"$uid" : {
".write" : "$uid === auth.uid",
"node" : {
".read" : false,
},
}

Now, writing on /UID/node/ was prevented, unless app has previously authenticated at FBAuth (I do this using the Gustavo Arango's extension).
Upon authenticating, an IdToken is received by the app, which includes the UID.
This UID, is the same of the path /UID/node/.

When I tried to secure the database, I discovered that the standard AppInventor FireBase blocks doesn't allow to write authenticated requests. So I had to redesign the whole communications part of the app, to write http REST authenticated requests instead.
With the help of your explanations I achieved to send them. And the receipt of those messages by server succeeded most of the times, but not always.
Randomly (let's say once every 7 times) I got an 1103 error reply from FireBase to the app (and, of course, this message was missing and was never received by the server).

I also had problemns deleting the messages:
FB always returned a 200 answer.
But I could see from FireBase console, that some times the message was still there on the data base.

I couldn't find the reason, nor solve the issue. So I surrendered.

I had to think of different FB rules (more relaxed and less secure), and come back to using the standard FB App Inventor blocks, that work so fine, and never fail.

1 Like

??? what is this ? Mirxtrem Apps ?

Yes. Exactly

Are you worried about someone hacking your FB DB or are you just annoyed with the constant warnings?
There is an alternate solution if you are worried about hacking and your current rules setup but you have to get another extension - Carlos Pedrosa's Addon extension - it allows you to place the FB URL into a code block (using obscured text block of course) - in that way, you can hide your URL.