Can Python SDK Register JS Client for Firebase Events? - javascript

I'm using only the Real-Time Database part of Firebase.
I have a Python Firebase admin on the server, a Javascript Firebase on the web client. No Android or iOS. My web Javascript client receives a token from the Python server for its authentication.
Only the Python server writes to Firebase, the Javascript client never does. But the client registers a "child_added" listener with Firebase to receive database changes in data.
Everything works except for this event listener.
The Firebase docs say:
The Python Admin SDK currently only supports blocking reads. It cannot
be used to add event listeners that receive realtime update
notifications.
But as I understand it, that applies to my server, not the client. Or does getting a custom token from a Python Admin disqualify the Javascript client for these events?
Maybe it's a problem that the server initializes itself with service account credentials, while the client does so with an api key? If so, why doesn't Firebase issue an error?
Here's the relevant Python code (views.py):
import firebase_admin
from firebase_admin import credentials, auth, db
def getFirebaseInstance():
try:
# using fresh download of key from service account for this app
cred = credentials.Certificate('myapp/static/myap/firebase/firebase-adminsdk-4mcup-144fd3c404.json')
firebase = firebase_admin.initialize_app(cred,{'databaseURL': 'https://my-db-url'})
except:
raise
#login_required()
def firebaseClientToken(request):
try:
global __firebase
if __firebase is None:
__firebase = getFirebaseInstance()
token = firebase_admin.auth.create_custom_token('1')
return HttpResponse(token)
except Exception as err:
return HttpResponse("System error:" + str(err), status=406)
def sendToFirebase(request, data):
try:
global __firebase
if not __firebase:
__firebase = getFirebaseInstance()
db = firebase_admin.db
ref = db.reference("messages/")
ref.push(json.dumps(data))
except Exception:
raise
All that works fine as far as the server being able to write to firebase and for generating a custom Token.
The javascript web client receives a token from the Python server (not shown), and registers the event listener with:
(
function authClient2Firebase() {
var waiting;
$.ajax({
url: "firebaseClientToken/",
method: "POST",
success: function(response) { step2(response); },
error: function(xhr) { alert(xhr.responseText); }
});
function step2(customToken) {
try {
firebase.auth().signInWithCustomToken(customToken).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
alert(errorMessage + ' code:' + errorCode);
});
var db = firebase.database();
var fbRef = db.ref("myapp");
fbRef.startAt(loadTransaction.time).on ( "child_added",
function(snapshot) { alert(snapshot.val()); });
}
}
}
)();

It doesn't have to do with tokens or authentication at all, but with a difference between the push(data) command in the Firebase Python and Javascript SDK vs. their documentation.
See the accepted answer at:
Why does Firebase event return empty object on second and subsequent events?

Related

How to verify PayPal Webhooks in node.js?

I found some old answers dealing with PHP and this code example, but I am not sure whether this is outdated now since the repo is archived and I know that generally PayPal moved to an approach that just uses the REST API.
I would love if somebody could give an update here on whats the latest recommendation is and whether the code here from 2015 is outdated now.
/* Copyright 2015-2016 PayPal, Inc. */
"use strict";
var paypal = require('../../../');
require('../../configure');
// Sends the webhook event data to PayPal to verify the webhook event signature is correct and
// the event data came from PayPal.
// Note this sample is only for illustrative purposes. You must have a valid webhook configured with your
// client ID and secret. This sample may not work due to other tests deleting and creating webhooks.
// Normally, you would pass all the HTTP request headers sent in the Webhook Event, but creating a
// JSON object here for the sample.
var certURL = "https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-a5cafa77";
var transmissionId = "103e3700-8b0c-11e6-8695-6b62a8a99ac4";
var transmissionSignature = "t8hlRk64rpEImZMKqgtp5dlWaT1W8ed/mf8Msos341QInVn3BMQubjAhM/cKiSJtW07VwJvSX7X4+YUmHBrm5BQ+CEkClke4Yf4ouhCK6GWsfs0J8cKkmjI0XxfJpPLgjROEWY3MXorwCtbvrEo5vrRI2+TyLkquBKAlM95LbNWG43lxMu0LHzsSRUBDdt5IP1b2CKqbcEJKGrC78iw+fJEQGagkJAiv3Qvpw8F/8q7FCQAZ3c81mzTvP4ZH3Xk2/nNznEA7eMi3u1EjSpTmLfAb423ytX37Ts0QpmPNgxJe8wnMB/+fvt4xjYH6KNe+bIcYU30hUIe9O8c9UFwKuQ==";
var transmissionTimestamp = "2016-10-05T14:57:40Z";
var headers = {
'paypal-auth-algo': 'SHA256withRSA',
'paypal-cert-url': certURL,
'paypal-transmission-id': transmissionId,
'paypal-transmission-sig': transmissionSignature,
'paypal-transmission-time': transmissionTimestamp
};
// The eventBody parameter is the entire webhook event body.
var eventBody = '{"id":"WH-82L71649W50323023-5WC64761VS637831A","event_version":"1.0","create_time":"2016-10-05T14:57:40Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 6.01 USD","resource":{"id":"8RS6210148826604N","state":"completed","amount":{"total":"6.01","currency":"USD","details":{"subtotal":"3.00","tax":"0.01","shipping":"1.00","handling_fee":"2.00","shipping_discount":"3.00"}},"payment_mode":"INSTANT_TRANSFER","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"value":"0.47","currency":"USD"},"invoice_number":"","custom":"Hello World!","parent_payment":"PAY-11X29866PC6848407K72RIQA","create_time":"2016-10-05T14:57:18Z","update_time":"2016-10-05T14:57:26Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/8RS6210148826604N","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/8RS6210148826604N/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-11X29866PC6848407K72RIQA","rel":"parent_payment","method":"GET"}]},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-82L71649W50323023-5WC64761VS637831A","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-82L71649W50323023-5WC64761VS637831A/resend","rel":"resend","method":"POST"}]}';
// The webhookId is the ID of the configured webhook (can find this in the PayPal Developer Dashboard or
// by doing a paypal.webhook.list()
var webhookId = "3TR748995U920805P";
paypal.notification.webhookEvent.verify(headers, eventBody, webhookId, function (error, response) {
if (error) {
console.log(error);
throw error;
} else {
console.log(response);
// Verification status must be SUCCESS
if (response.verification_status === "SUCCESS") {
console.log("It was a success.");
} else {
console.log("It was a failed verification");
}
}
});
Those SDKs are abstractions for the REST API but are no longer being maintained, so it is best not to use them.
There are two possible ways to verify Webhooks
Posting the message back to PayPal with the verify webhook sygnature REST API call. You'll need to use a client_id and secret get an access token first, same as all other REST API calls.
Verifying the cryptographic signature yourself (Java pseudocode here).
For either method, the "webhookId" -- as opposed to each webhook event id -- is 17 alphadigits and for security (anti-spoof) reasons not part of the Webhook message itself (you get it when registering for webhooks or reviewing existing subscribed hooks in the REST app config)
As it can sometimes be a point of confusion, it's worth mentioning that verifying webhooks is for your own information -- to confirm the message did in fact originate from PayPal, and not some other (malicious) actor.
But for PayPal itself to consider the webhook message successfully delivered (and not keep retrying), all that needs to happen is for the listener URL it's posted to to respond with an HTTP 200 OK status. That concludes the webhook message delivery.

How to sync pouchdb with remote Coudant, not able to connect?

How do sync PoucDB to Cloudant by using user login? My Cloudant is set up with IAM and Legacy.
How do I register users and use the credentials to login to use Cloudant and PouchDB
I have not found answers in Cloudant, PouchDB docs. And do not see my answer in Stackoverflow
I am using the PouchDB docs:
var db = new PouchDB('todos');
const remoteUrl = "https://some address"
const remoteOptions = {
'auth': { 'username': user , 'password': pass } }
const remoteDb = new PouchDB(remoteUrl, remoteOptions);
localDB.sync(remoteDB).on('complete', function () {
// yay, we're in sync!
}).on('error', function (err) {
// boo, we hit an error!
});
Replication does work from Cloudant to on-premise Couchdb. Therefore I can connect to Coudant remotely.
As you have Legacy Auth available, I won't worry about IAM authentication. We can simply generate an API key/password for your mobile client and use legacy authentication.
Creating an API key
In the Cloudant Dashboard, choose the "Permissions" menu and click the "Generate API Key" button. You should see a generated Key and Password - these become the Username & Password in the URL you feed to PouchDB.
If you're doing a sync (i.e data is to flow in both directions) then your API key needs both _reader & _writer permissions. If data is to flow from server to mobile only, then _reader & _replicator will suffice.
Client-side code
Your client side code is pretty much correct:
remember that Cloudant only accepts HTTPS connections
the Key from your API Key/Password pair becomes your username
the Password from your API Key/Password pair becomes your password
e.g.
const PouchDB = require('pouchdb')
const db = new PouchDB('todos')
const username = 'KEY'
const password = 'PASSWORD'
const host = 'mycloudservice.cloudant.com'
const databaseName = 'todos'
const remoteDB = `https://${username}:${password}#${host}/${databaseName}`
db.sync(remoteDB).on('complete', async function () {
console.log('done')
}).on('error', function (err) {
console.error(err)
});

firebase googlesignin error in express js

this is the function which is called when user click a button from the html page.
this function is in auth.js which is called in server.js page
auth.js
const firebase = require("firebase");
static googleSignIn(req,res){
firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider()).
then( (result) => {
console.log(result.credential.idToken);
firebase.auth().currentUser.getIdToken(true).then( (token) => {
console.log(token);
});
}).catch((err) => {
console.log(err);
});
}
i get this error
code: 'auth/operation-not-supported-in-this-environment',
message:
'This operation is not supported in the environment this application is
running on. "location.protocol" must be http, https or chrome-extension and
web storage must be enabled
is there any way to send html request and get the token as response ,or any alternative way.please help
That error message is trying to tell you that Firebase Authentication client libraries don't work in a node.js environment. They're only supported for web browser clients.
Read more here.

How to send push notification from angular 6 project to android app

I have an android app in which I send push notification using firebase admin sdk with nodejs.
I was able to send notification from the nodejs raw script when I ran the script.
However, I just built an admin dashboard for sending notification to the app with angular 6 but don't know how to integrate the nodejs script with the new angular app so that I can send notification from the angular app by just a click.
I'd also encourage new ideas on how best to to this.
attached is a screenshot from the nodejs admin script
Setup your node to behave as API server, using Express for example.
Wrap your script as Express module (named send-message.js), basically just make that a function that you export:
const sendMessage = (...params) => {
//your send message logic, I would do copy paste of your code here however it is an image
}
module.exports = sendMessage;
Well and then setup API route that calls the script:
var express = require('express')
var sendMessage = require('./send-message')
var app = express()
app.get('/send-message', function (req, res) {
sendMessage(....);
res.status(200).end();
})
app.listen(3000)
And finally in Angular use HttpClient to call the API.
I finally solved the problem by using firebase cloud functions.
First I set up cloud functions on firebase with this guide
Then I created a cloud function named sendNotification() which is triggered each time new objects are inserted to the firebase realtime database.
Then I placed my existing notification code inside sendNotification() function
Deployed the function to my firebase console
Then hurray, the notification was sent to my device after some db triggers
`
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
//This functions listens to the node '/Food menu/date/Food' for new insert and sends notification to a client
exports.sendNotification = functions.database.ref('/Food menu/date/Food')
.onCreate((snapshot, context) => {
//place your client app registration token here, this is created when a user first opens the app and it is stored in the db.
//You could also retrieve the token from the db but in this case it is hard coded
var registrationToken = "{my-registration-token}";
//This is the payload for notification
var payload = {
data: {
'title': 'Tomorrow\'s Menu',
'message': 'Hello, kindly check the menu available for today',
'is_background': 'true',
'image': 'http://www.allwhitebackground.com/images/3/3430.jpg',
'timestamp': '234'
}
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().sendToDevice(registrationToken, payload)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
//return a promise here since this function is asynchronous
return "Yes";
})
.catch((error) => {
console.log('Error sending message:', error);
});
//return snapshot.ref.parent.child('uppercaseFood').set(uppercase);
});
`
After this, you run firebase deploy --only functionsto deploy the cloud function
Read this guide for more info on cloud functions

Google reCAPTCHA, 405 error and CORS issue

I am using AngularJS and trying to work with Google's reCAPTCHA,
I am using the "Explicitly render the reCAPTCHA widget" method for displaying the reCAPTCHA on my web page,
HTML code -
<script type="text/javascript">
var onloadCallback = function()
{
grecaptcha.render('loginCapcha', {
'sitekey' : 'someSiteKey',
'callback' : verifyCallback,
'theme':'dark'
});
};
var auth='';
var verifyCallback = function(response)
{
//storing the Google response in a Global js variable auth, to be used in the controller
auth = response;
var scope = angular.element(document.getElementById('loginCapcha')).scope();
scope.auth();
};
</script>
<div id="loginCapcha"></div>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
So far, I am able to achieve the needed functionality of whether the user is a Human or a Bot,
As per my code above, I have a Callback function called 'verifyCallback' in my code,
which is storing the response created by Google, in a global variable called 'auth'.
Now, the final part of reCAPCHA is calling the Google API, with "https://www.google.com/recaptcha/api/siteverify" as the URL and using a POST method,And passing it the Secret Key and the Response created by Google, which I've done in the code below.
My Controller -
_myApp.controller('loginController',['$rootScope','$scope','$http',
function($rootScope,$scope,$http){
var verified = '';
$scope.auth = function()
{
//Secret key provided by Google
secret = "someSecretKey";
/*calling the Google API, passing it the Secretkey and Response,
to the specified URL, using POST method*/
var verificationReq = {
method: 'POST',
url: 'https://www.google.com/recaptcha/api/siteverify',
headers: {
'Access-Control-Allow-Origin':'*'
},
params:{
secret: secret,
response: auth
}
}
$http(verificationReq).then(function(response)
{
if(response.data.success==true)
{
console.log("Not a Bot");
verified = true;
}
else
{
console.log("Bot or some problem");
}
}, function() {
// do on response failure
});
}
So, the Problem I am actually facing is that I am unable to hit the Google's URL, Following is the screenshot of the request I am sending and the error.
Request made -
Error Response -
As far as I understand it is related to CORS and Preflight request.So what am I doing wrong? How do I fix this problem?
As stated in google's docs https://developers.google.com/recaptcha/docs/verify
This page explains how to verify a user's response to a reCAPTCHA challenge from your application's backend.
Verification is initiated from the server, not the client.
This is an extra security step for the server to ensure requests coming from clients are legitimate. Otherwise a client could fake a response and the server would be blindly trusting that the client is a verified human.
If you get a cors error when trying to sign in with recaptcha, it could be that your backend server deployment is down.

Categories