Cloud Functions for Firebase running into infinite loop - javascript

I have a custom logic to verify the users.
I have written a Cloud Function for Firebase and to verify the custom tokens.
The problem is the cloud function is not getting terminated and is being run into infinite loop, till Firebase kills the function
The cloud function runs into infinite in both matching and non-matching scenario.
Below is the code:
/* CLOUD FUNCTION */
exports.verifyToken = functions.https.onRequest((req, res) => {
var corsFn = cors();
corsFn(req, res, function () {
verifyTheUserToken(req, res);
});
});
function verifyTheUserToken(req, res) {
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.');
res.status(403).send('Unauthorized');
}
const firebaseToken = req.headers.authorization.split('Bearer ')[1];
const userId = req.body.uid;
const receievedToken = req.body.token;
return admin.auth().verifyIdToken(firebaseToken).then(decodedFirebaseToken => {
console.log('ID Token correctly decoded', decodedFirebaseToken);
console.log('req', req.body);
return 'sucess';
}).then(function (receivedValues) {
return admin.database().ref().child('userTokens').child(userId).child('token').once('value');
}).then(function (snapshot) {
if (!snapshot.val()) {
return Promise.reject('token is not set ');
}
if (snapshot.val() != receievedToken) {
return Promise.reject('token doesnt match');
}
return 'verified';
}).then(function (success) {
return admin.database().ref().child('users').child(userId).child('isVerified').set(true);
}).then(function (success) {
console.log('The user is verified');
return;
}).catch(function (error) {
console.log('Error', error);
return;
});
}
Client side I am doing a HTTP request to call the firebase cloud function.
/* CLIENT SIDE */
var currentUser = firebase.auth().currentUser.uid;
var firebaseUserToken = firebase.auth().currentUser.getToken();
firebase.auth().currentUser.getToken(/* forceRefresh */ true).then(function (firebaseUserToken) {
fetch('https://us-central1-MYAPP.cloudfunctions.net/verifyToken', {
'method': 'POST',
'headers': {
'Authorization': 'Bearer ' + firebaseUserToken,
'Content-Type': 'application/json'
},
'body': JSON.stringify({
'uid': currentUser,
'token': 1234,
})
}).then(function (response) {
console.log('successful response');
}).catch(function (error) {
console.error('Error in fetch', error);
});
}).catch(function (error) {
console.error('Error in getting firebase token', error);
});
I am unable to figure out the reason for the infinite loop.
I would really appreciate any help on this.
Thanks!

I had missed res.send() for the success case.
As per documentation:
Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system.
https://firebase.google.com/docs/functions/http-events

Related

How to delete a forge bucket from Autodesk forge

I am successfully creating Bucket and uploadFile successfully using sample.
https://github.com/Autodesk-Forge/forge-extensions
I added the delete function
But when I delete the bucket I get an error.
----oss.js---
router.post('/buckets', async (req, res, next) => {
let payload = new PostBucketsPayload();
payload.bucketKey = config.credentials.client_id.toLowerCase() + '-' + req.body.bucketKey;
payload.policyKey = 'transient'; // expires in 24h
try {
// Create a bucket using [BucketsApi](https://github.com/Autodesk-Forge/forge-api-nodejs-client/blob/master/docs/BucketsApi.md#createBucket).
//Bucket createBucket(postBuckets, opts, oauth2client, credentials)
await new BucketsApi().createBucket(payload, {}, req.oauth_client, req.oauth_token);
res.status(200).end();
} catch(err) {
next(err);
}
});
router.delete('/buckets/delete', async (req, res, next) => {
const encoded_bucketKey = encodeURI(req.bucketKeyID);
try {
// Delete a bucket using
await new BucketsApi().deleteBucket(encoded_bucketKey, req.oauth_client, req.oauth_token);
res.status(200).end();
} catch(err) {
next(err);
}
});
-----------ForgeTree.js -------
function createNewBucket() {
var bucketKey = $('#newBucketKey').val();
var policyKey = $('#newBucketPolicyKey').val();
jQuery.post({
url: '/api/forge/oss/buckets',
contentType: 'application/json',
data: JSON.stringify({ 'bucketKey': bucketKey, 'policyKey': policyKey }),
success: function (res) {
$('#appBuckets').jstree(true).refresh();
$('#createBucketModal').modal('toggle');
},
error: function (err) {
if (err.status == 409)
alert('Bucket already exists - 409: Duplicated')
console.log(err);
}
});
}
function deleteBucket() {
var node = $('#appBuckets').jstree(true).get_selected(true)[0];
switch (node.type) {
case 'bucket':
jQuery.ajax({
url: '/api/forge/oss/buckets/delete',
type:'delete',
contentType: 'application/json',
data: JSON.stringify({ 'bucketKey': node.text , 'bucketKeyID' : node.id}),
success: function (res) {
$('#appBuckets').jstree(true).refresh();
},
error: function (err) {
alert('Bucket delete error:')
console.log(err);
}
});
break;
}
console.log("Delete Bucket=%j", node)
}
I checked the config.js in the sample, it doesn't include bucket:delete scope when acquiring the token by default. Have you added the scope in your code?
Also inside delete route,
const encoded_bucketKey = encodeURI(req.bucketKeyID);
should be
const encoded_bucketKey = encodeURI(req.body.bucketKeyID);
Otherwise, you'll have undefined as encoded_bucketKey.

Callback function with request method to third party API is not working

I am a beginner to callback concept and looking for a solution to my problem.
I calling third party API using request package in node.js here is the code:
In reusable library file: auth.js
let getAuthToken = () => {
let authToken;
var options = {
'method': 'GET',
'url': 'https://<apiURL>/V1/auth_token',
'headers': {
'Authorization': 'Basic <token>'
}
};
request(options, (error, response) => {
if (error) {
throw new Error(error);
} else {
authToken = JSON.parse(response.body);
}
});
return authToken;
}
on my route: http://127.0.0.1:3000/api/v1/musics/authorize-account, I am calling my controller function named "getAuthorizationToken()"
controllerfile: music.controller.js
const auth = require('../middleware/auth');
let getAuthorizationToken = async (req, res, next) => {
let token = await auth.getAuthToken();
console.log(auth.getAuthToken());
res.send(token);
}
Problem is the controller function is getting executed completely and then the third party API is being called event I have added await to the function.
Do explain to me the problem I am facing and any workaround solution will be heartily helpful.
You have to return a promise to be able to await something and have it work as expected:
let getAuthToken = () => {
let authToken;
var options = {
'method': 'GET',
'url': 'https://<apiURL>/V1/auth_token',
'headers': {
'Authorization': 'Basic <token>'
}
};
return new Promise((resolve, reject) => {
request(options, (error, response) => {
if (error) {
reject(error);
} else {
authToken = JSON.parse(response.body);
resolve(authToken);
}
});
})
}
await is only useful on promises. In your case your getAuthToken does not return an promise. But you can change it.
let getAuthToken = () => {
return new Promise((res, rej) => {
let authToken;
var options = {
method: "GET",
url: "https://<apiURL>/V1/auth_token",
headers: {
Authorization: "Basic <token>"
}
};
request(options, (error, response) => {
if (error) {
rej(error);
} else {
authToken = JSON.parse(response.body);
res(authToken);
}
});
});
};
In addition you should also wrap your await in a try / catch
let getAuthorizationToken = async (req, res, next) => {
try {
let token = await auth.getAuthToken();
console.log(token);
return res.send(token);
} catch(err) {
console.log(err);
return res.status(500).send(err);
}
}
Instead of an 500 error you should send an different error code like:
400 Bad request: If there are some missing credentials like the token is missing
401 Unauthorized: If the token is wrong

Promise rejected in POST login using fetch API in reactjs and Nodejs

I am working on a simple login using POST Fetch in Reactjs with NodeJs API. The code is working good and redirect the page when we login using correct username and password but the problem is when using fake username. I got the error in console.log with Promise : "Rejected". And I still can not figure it why
Here is the code in login.js
async SubmitLogin(event){
event.preventDefault();
//debugger;
console.log(this.state)
await fetch(`http://localhost:4000/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(this.state)
})
.then ((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
// then Read the response as json.
else {
let result = response.json();
console.log(result)
if(result === 'Invalid'){
console.log(response)
alert('Invalid User');
//this.props.history.push('/login');
}
else {
alert('Login Sucessfull');
this.props.history.push('/home');
}
}
})
.catch((err) => {
console.error();
})
}
in my server.js, I used express-session like this:
//sales login
app.post('/login', jsonParser, (req, res) => { //jsonParser,
let username = req.body.username;
let password = req.body.password;
console.log("req: ",req.body);
if (username && password) {
dbConn.query(`SELECT * FROM user_tbl WHERE username = ? AND password = ?`, [username, password], (err, results, fields) => {
if (results.length > 0) {
req.session.loggedin = true;
req.session.username = username;
res.redirect('/home');
console.log(results)
console.log("req: ", req.body);
} else {
res.send('Incorrect Username and/or Password!');
}
res.end();
});
} else {
res.send('Please enter Username and Password!');
res.end();
}
});
app.get('/home', (req, res) => {
if (req.session.loggedin) {
res.send('Welcome back, ' + req.session.username + '!');
} else {
res.send('Please login to view this page!');
}
res.end();
});
and this is the result I got in console:
hopefully my question is clear.
I think your response doesnt come json format.You cant parse string to json.
Your response should be like this res.send({success:false , message : "Incorrect Username and/or Password!"})
After many suggestions and anwers, finally I can figure out how to solved this problem. Here is the code in login.js
//submit function
async SubmitLogin(event){
event.preventDefault();
console.log(this.state)
await fetch(`http://localhost:4000/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(this.state)
})
.then ((response) => {
if(response.status === 401) {
throw new Error('Unauthorized');
}
//return response.json();
})
.then((result) => {
console.log(result);
this.props.history.push('/home');
alert('Login Sucessfull');
})
.catch((err) => {
console.log();
})
}
and in the backend, I didn't change anything.

Send back data from node.js to client side javascript

what I´m trying to do is the following I already set a fetch connection from client side JS to the server Node.JS when a person click on a button in HTML which triggers that in the server side looks for an element in the MongoDB database in it find´s it, but my question is how do I send that found element back to the client side JS.
Javascript Code:
var button = document.getElementById("1");
button.addEventListener("click", idss);
function idss() {
var id = this.id;
var data = {
name : id
}
fetch("/clicked", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(function(response) {
if(response.ok) {
console.log('awesome');
return;
}
throw new Error('Request failed.');
})
.catch(function(error) {
console.log(error);
});
}
NODE JS:
app.post("/clicked", (req, res) => {
var pro = (req.body.name);
Number(pro);
Product.findOne({"id": pro}, function(err, foundLList) {
if(err) {
console.log(err);
} else {
console.log(foundLList); //THE ELEMENT IS FOUND
}
}
);
});
What I´m trying to do is to send the found element to Javascript so I can added to another variable.
You have to use res object to send data back to client. Your node code will be:
app.post("/clicked", (req, res) => {
var pro = (req.body.name);
Number(pro);
Product.findOne({
"id": pro
}, function(err, foundLList) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundLList); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundLList
});
}
});
});
and on client side, you can read the data like this:
fetch("/clicked", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(function(response) {
if (response.ok) {
console.log('got data: ', response.data);
}
throw new Error('Request failed.');
})
.catch(function(error) {
console.log(error);
});
}

Using an async function for a route gives me a 404

I'm running an express server trying to use Outlooks API with node,
The routes are now using async and I copied a snippet from the docs:
The handling of the route:
const handle = {};
handle['/mail'] = mail;
and the function is:
async function mail(response, request) {
let token;
try {
token = await getAccessToken(request, response);
} catch (error) {
response.writeHead(200, {
'Content-Type': 'text/html'
});
response.write('<p> No token found in cookie!</p>');
response.end();
return;
}
console.log('Token found in cookie: ', token);
const email = getValueFromCookie(
'node-tutorial-email',
request.headers.cookie
);
console.log('Email found in cookie: ', email);
response.writeHead(200, {
'Content-Type': 'text/html'
});
response.write('<div><h1>Your inbox</h1></div>');
// Create a Graph client
const client = microsoftGraph.Client.init({
authProvider: done => {
// Just return the token
done(null, token);
}
});
try {
// Get the 10 newest messages
const res = await client
.api('/me/mailfolders/inbox/messages')
.header('X-AnchorMailbox', email)
.top(10)
.select('subject,from,receivedDateTime,isRead')
.orderby('receivedDateTime DESC')
.get();
console.log(`getMessages returned ${res.value.length} messages.`);
response.write(
'<table><tr><th>From</th><th>Subject</th><th>Received</th></tr>'
);
res.value.forEach(message => {
console.log(' Subject: ' + message.subject);
const from = message.from ? message.from.emailAddress.name : 'NONE';
response.write(
`<tr><td>${from}` +
`</td><td>${message.isRead ? '' : '<b>'} ${message.subject} ${
message.isRead ? '' : '</b>'
}` +
`</td><td>${message.receivedDateTime.toString()}</td></tr>`
);
});
response.write('</table>');
} catch (err) {
console.log(`getMessages returned an error: ${err}`);
response.write(`<p>ERROR: ${err}</p>`);
}
response.end();
}
It should be working... I don't see any errors there. Why am I getting a 404?

Categories

Resources