Change the HTTP status code with a Google Cloud Function Promise - firebase

My code checks if a user is authorized, if the user is, the proper code is run. If the user is not, it run reject() to reject the promise.
If I run the code authenticated, I get
{"error":{"status":"INVALID_ARGUMENT","message":"Bad Request"}}
I am trying to change the status code to Forbidden (code 403) which you would normally do with res.status(403) however since this is a promise it is different. How can I change the error code returned?
My code is as follows:
const cloudFunction = functions.https.onCall((data, context) => {
return new Promise(function(resolve, reject) {
auth.verifyIdToken(data.userId).then(function(decodedToken) {
if(claims.admin === true) {
// Run code if user has admin role
}
else {
reject()
// Return error code 403 because user does not have admin role
}
}).catch(err => reject(err)) // Return error code 401 because user is not logged in
})
});

You can't change the HTTP status for a callable function. Callable functions essentially take over and hide the HTTP protocol for the request and response. All you do is specify the input and output objects, and the SDKs handle everything else.
If you need to control the HTTP status of a response, you will have to use a regular HTTP type function instead. Then you will have full control over the request and response.

Related

Next JS pages/api; having trouble calling influxdb client from api

I have written a handler function inside my nextjs page/api folder;
handler(req, res) {}
Am using #influxdata/influxDb-client as mentioned in the documentation. Am using
from(queryAPI.rows(query).pipe(....).subscribe(next(value)=> {results.push(value}, complete(console.log(results); res.status(200).json(results)}
Am getting all the query value, once the observable is completed. it works most of the time.
Am pushing the intermediate results in the next part of the subscriber and trying to send the results back to client in the complete part of the subscriber. I want the request handler to wait till i get all my values from influx DB query in the complete part of the subscriber and can send the value back to client..
But the issue "Handler function will not Wait till the observable is completed". Handler function returns, before the observer gets completed. Am getting error: API resolved without sending a response...
I get all the values only when the observer is completed.
I don't know how to handle the scenario.
How can I make the handler function wait until the observable is completed?
I found the solution for the same
I used new Promise() with await, added my observable inside this promise and resolved the promise on Complete of the subscribe.
Code will look like the following :
export async function handler (req, res) {
const results=[];
await new Promise((resolve, reject) => {
from((queryAPIs.rows(query))
.pipe(map(({values, tableMeta}) => tableMeta.toObject(values)))
.subscribe(
{
next(object) => {results.push(object)}
complete() => { resolve (results) }
error(err) => { reject (err) }
});
res.status(200).send(results);
}
}

Get user agent in firebase functions callable

How do I get the user agent in firebase callable function?
I have tried using this:
functions.https.onCall((data, context) => {
console.log("agent", context.rawRequest.agent);
// ....
}
);
This logs the agent to be undefined.
How do I get the user agent in this callable?
When you invoke a callable function, the client SDK doesn't provide a user agent string in the request. It's not part of the protocol.
If you want to receive a user agent string, you're going to have to provide one in the data object that you pass from the client. It won't happen automatically.
It's not written in the doc as mentioned above but then I saw that firebase is sending the user agent in the request header so I decided to dig deeper and found this:
functions.https.onCall((data, context) => {
const { ['user-agent']: userAgent } = context.rawRequest.headers;
console.log('userAgent:', userAgent);
});

why can service worker respondWith() return a fetch object instead of a real response?

I was reading the MDN docs, and got confused why event.respondWith can have a fetch object returned? Isn't the actual request initiator expecting a response instead of a fetch?
addEventListener('fetch', event => {
// Prevent the default, and handle the request ourselves.
event.respondWith(async function() {
// Try to get the response from a cache.
const cachedResponse = await caches.match(event.request);
// Return it if we found one.
if (cachedResponse) return cachedResponse;
// If we didn't find a match in the cache, use the network.
return fetch(event.request);
}());
});
The actual request initiator is not expecting a response. It is expecting a promise that resolves into a response. The MDN docs say exactly that:
The respondWith() method of FetchEvent prevents the browser's default
fetch handling, and allows you to provide a promise for a Response
yourself.
You are not returning a fetch object here when you call fetch(event.request). You are calling the fetch method which returns a promise that resolves into a response.
You can return any promise that resolves to a response here, like so:
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(/* { Fake Response Object } */);
}, 1500);
});

Service Worker - TypeError: Request failed

I used service worker to cache the resource from the other domain. I get this error "TypeError: Request failed serivce-worker.js:12" I don't know why this error is occurring.
service-worker.js
var cacheNames=['v1'];
var urlsToPrefetch=['file from other domain'];
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(cacheNames).then(function(cache) {
console.log('Service Worker: Caching Files');
cache.addAll(urlsToPrefetch.map(function (urlToPrefetch) {
console.log(urlToPrefetch);
return new Request(urlToPrefetch, {mode: 'no-cors'});
})).catch(function(error){
console.log(error);
});
})
);
});
self.addEventListener('fetch', function(event) {
console.log('Service Worker: Fetching');
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
This is a side-effect of dealing with opaque responses (those fetched with mode: 'no-cors'). Here's an excerpt from this longer answer:
One "gotcha" that developer might run into with opaque responses involves using them with the Cache Storage API. Two pieces of background information are relevant:
The status property of an opaque response is always set to 0, regardless of whether the original request succeeded or failed.
The Cache Storage API's add()/addAll() methods will both reject if the responses resulting from any of the requests have a status code that isn't in the 2XX range.
From those two points, it follows that if the request performed as part of the add()/addAll() call results in an opaque response, it will fail to be added to the cache.
You can work around this by explicitly performing a fetch() and then calling the put() method with the opaque response. By doing so, you're effectively opting-in to the risk that the response you're caching might have been an error returned by your server.
const request = new Request('https://third-party-no-cors.com/', {mode: 'no-cors'});
// Assume `cache` is an open instance of the Cache class.
fetch(request).then(response => cache.put(request, response));

Meteor async function for validateLoginAttempt

I wan't to use googles captcha as an security messure in my app.
The process:
Request public response from google on client (Success)
Save public response to an collection (Success)
On server validateLoginAttempt should send my secret and client aclaimed public keys for validation (Success)
If and only if 3 successfull return true otherwise false. (Fails)
The problem I am facing is in 4
I need to execute validateLoginAttempt as async, As soon as I write:
Accounts.validateLoginAttempt(async() => {
await myCallToRemoteValidation
})
However
Accounts.validateLoginAttempt(() => {...})
does process the callback, but too late since node will have already progressed. I already use async await in other parts of the code, and it works but not with accounts. How can I solve this?
Reference: http://docs.meteor.com/api/accounts-multi.html#AccountsServer-validateLoginAttempt

Resources