Reputation: 121
I´m runnig into CORS
issues. In my functions/index.js
I have:
const cors = require('cors')({
origin: true
});
My endpoint is https://sis-t.redsys.es:25443/sis/realizarPago
. I need to do a POST
to this url with apropiate parameters from the client, and this is outside firebase enviroment. I also have the correct plan to allow external network, but making a request to a different address than the origin one, triggers a CORS
problem:
I have read that you only need to modify the headers, but that only applies if you are making a request to your own server. When you do the http.onRequest()
, you can use a middleware inside the function, but what happens when you make a POST to an external server?
This is the axios
functions that do the POST
:
cardPay: function () {
this.cardProcess = true
axios({
method: 'post',
url: 'https://us-central1-cutre-windrider.cloudfunctions.net/cardPay',
data: {
verifiedUserLogged: this.userLogged.uid,
cart: this.cartItemList,
finalPrice: this.serverPrice,
deliveryInfo: this.userLogged.deliveryAdress,
name: this.userLogged.displayName || false,
email: this.userLogged.email
}
})
.then(response => {
this.requestData = response
this.redsysRedirect(response.data.data)
})
.catch(console.log)
},
redsysRedirect: function (data) {
axios.post('https://sis-t.redsys.es:25443/sis/realizarPago', {
'Ds_SignatureVersion': 'HMAC_SHA256_V1',
'Ds_MerchantParameters': data.merchantParameters,
'Ds_Signature': data.signature
}).then(console.log).catch(console.log)
These are the server side functions:
exports.cardPay = functions.https.onRequest((req, res) => {
return cors(req, res, () => {
const cart = req.body.cart
const user = req.body.verifiedUserLogged
const key = admin.database().ref(`sales/${user}`).push().key
processCart(cart).then(result => {
console.info(createPayment(result, key))
return res.json({ "data": createPayment(result, key) }).end()
}).catch(console.log)
})
})
function processCart(cart) {
return new Promise((resolve, reject) => {
Promise.all(cart.map(i => switcher(i)))
.then(prices => resolve(
prices.reduce(
(finalPrice, price) => price + finalPrice, 0)
)).catch(console.log)
});
}
function switcher(item) {
switch (item.destiny) {
case 'bookedLessons':
return lessonPrice(item.name, item.index)
case 'bookedRentals':
return rentalPrice(item.id, item.index, item.insurancePurchased, item.insuranceId)
case 'bookedLodgins':
return item.reservationData ? roomPriceWithReservation(item.id, item.quantity, item.persons, item.reservationData) : roomPriceNoReservation(item.id, item.quantity, item.persons)
case 'deliveries':
return productPrice(item.id, item.quantity)
case 'bookedCar':
return carPrice(item.id, item.index)
case 'bookedStorage':
return storagePrice(item.index)
case 'bookedTransportation':
return transportationPrice(item.id, item.index, item.persons, item.roundTrip)
case 'bookedDoublePack':
return doublePack(item.id, item.persons)
case 'bookedTriplePack':
return triplePack(item.id, item.persons)
default:
break
}
}
function createPayment(total, orderId) {
let redsys = new Redsys();
let mParams = {
"DS_MERCHANT_AMOUNT":total.toString(),
"DS_MERCHANT_ORDER":orderId,
"DS_MERCHANT_MERCHANTCODE": "025988262",
// "DS_MERCHANT_MERCHANTCODE":tpvInfo.fucCode,
"DS_MERCHANT_CURRENCY":"978",
// "DS_MERCHANT_CURRENCY":tpvInfo.currency,
"DS_MERCHANT_TRANSACTIONTYPE":"0",
// "DS_MERCHANT_TRANSACTIONTYPE":tpvInfo.transaction_type,
"DS_MERCHANT_TERMINAL": "001",
// "DS_MERCHANT_TERMINAL":tpvInfo.terminal,
"DS_MERCHANT_MERCHANTURL":'http://localhost:8080',
"DS_MERCHANT_URLOK":'http://localhost:8080/home?foo=true',
"DS_MERCHANT_URLKO":'http://localhost:8080/home?foo=false'
};
return {signature: redsys.createMerchantSignature(/* tpvInfo.secret */ "sq7HjrUOBfKmC576ILgskD5srU870gJ7", mParams) , merchantParameters: redsys.createMerchantParameters(mParams), raw: mParams};
}
Upvotes: 8
Views: 23099
Reputation: 149
I have also spent 1 entire day on finding the CORS related issue for Firebase functions.
Finally, I found the solution.
By default, firebase-functions are not available to access on internet, we have to create a principle for it & assign to that function.
Go to your GCP console dashboard:
Search "Cloud Functions" in the top Search input, go to "Cloud Functions".
Then, select your cloud function (checkbox).
Click on Permissions on top, after selecting your function.
Click on "Add Principal".
Type "allUsers" as the principal name and select the role "Cloud Function Invoker". You will see a message, "Ability to invoke HTTP functions with restricted access.
"Save"
That's it!
Access is now available to everybody from the internet with the correct config to your Firebase functions without CORS errors.
See the below image here:
Upvotes: 1
Reputation: 3509
For someone who will meet this issue in the future (or my future self):
If you've already configured CORS using cors
package, and you think you configured it correctly, and still have CORS error in the browser console, check this article:
https://haha.world/firebase-cors/
Basically, it's a misleading error returns from Google Cloud Functions, when actually the error is inside your code logic (which is totally not related to CORS at all)
So the first step to fix this bug is to check Google Cloud Functions logs (or Firebase Cloud Functions logs) to see if your function crashed because of any error in your code. Then fix it.
Note: For someone that doesn't have the issue that I described above, you can see other answers, or check these resources:
Upvotes: 25
Reputation: 1035
Check out https://cloud.google.com/functions/docs/writing/http#handling_cors_requests . From that document -
exports.corsEnabledFunction = (req, res) => {
// Set CORS headers
// e.g. allow GETs from any origin with the Content-Type header
// and cache preflight response for an 3600s
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "GET");
res.set("Access-Control-Allow-Headers", "Content-Type");
res.set("Access-Control-Max-Age", "3600");
// Send response to OPTIONS requests and terminate the function execution
if (req.method == 'OPTIONS') {
res.status(204).send('');
}
// Continue with function code
...
}
Upvotes: 9
Reputation: 484
Within your Firebase Function response header you could explicitly allow all origins:
exports.handler = ((req, res) => {
res.set({ 'Access-Control-Allow-Origin': '*' }).sendStatus(200)
})
Or you could modify this to allow only specific origins. This is generally how I have worked around CORS issues with Firebase funcitons in the past.
Upvotes: 9