Google Cloud Cloud Function signed url yields 403 SignatureDoesNotMatch - firebase

I'm getting a 403 SignatureDoesNotMatch error when trying to load a url generated through:
file.getSignedUrl({
expires: moment()
.add(10, 'minutes')
.format()
})
I've done all the steps outlined in the example, including adding a service account token creator to the App Engine default service account to allow the creation of signed urls:
As an alternative approach to using admin via firebase-functions I tried downloading service account credentials service-account-credentials.json and creating a gcs storage object as suggested here as such:
const { Storage } = require('#google-cloud/storage');
const storage = new Storage({
keyFilename: 'service-account-credentials.json',
projectId: 'project-id',
});
storage.bucket('bucket-id').getFiles({prefix: 'path/to/dir'}).then(files => files.map(file => [same code as above]));
However this still generates SignatureDoesNotMatch urls.
I've followed the github issue related to the matter but I have not been able to find a viable solution. The solution listed by Firebase dev owner #mcdonamp in the issue references using iam.signBlobRequest but I don't know where iam is defined, I only see it here as a property of bucket, with no signBlobRequest method, and here as an HTTP API endpoint.

Seems that despite the doc's claim of Content-Type headers being optional, they are not. As suggested by this SO post and this github issue, adding contentType to the getSignedUrl options argument fixes the issue:
file.getSignedUrl({
action: 'read',
contentType: 'audio/wav',
expires: moment()
.add(10, 'minutes')
.format()
})
Make sure to also include the header when requesting the resource as well.

Related

Firebase AppCheck POST request is unknown

I'm trying to configure AppCheck in my web app (using SvelteKit).
I've registered my web app with recaptcha and then Added this basic code:
onMount(async () => {
const appCheck = initializeAppCheck(app, {
provider: new ReCaptchaV3Provider('my-key'),
isTokenAutoRefreshEnabled: true
})
})
But it fails with 400 error. Those occur because the POST request has 'unknown' where the Recaptcha (and firebase collection) should be.
POST URL: https://content-firebaseappcheck.googleapis.com/v1/projects/undefined/apps/undefined:exchangeRecaptchaV3Token?key=undefined
Why does it happen? how can I fix it?
*The only similar case is here, but it has no solution, and might not be the same.
SOLVED: The request was malformed due to mistaken firebaseConfig data.

How to upload file in firebase cloud function into firebase storage from url?

I'm using some API, that can give me file with 2 ways:
- I can get FILE in response
- I can get direct URL to the file to download
I decided to make request with first method, get FILE in response. I'm trying to save the file in firebase storage, from firebase cloud function:
exports.test = functions.region('europe-west1').https.onRequest(async (req, res) => {
const axios = require('axios').default
axios({
method: 'get',
url: `https://cloudpbx.beeline.ru/apis/portal/v2/records/06365a27-f8d1-4c51-bba3-a08802429964/9052948777%40mpbx.sip.beeline.ru/download`
}).then((resp) => {
console.log('resp', resp.data)
const bucket = admin.storage().bucket('cardbox-1.appspot.com/mcun/calls')
bucket.upload(resp.data)
})
})
In resp.data i have something like that:
��H�Xing��h $&)+-.179:>ACEGINRTW[_acegjmoqtwz|����������������������������������������������������PLAME3.100(,�$!��h�6���H��V]#mdE�E��"#���}�8kwT��&���>:P�2��>?�����8 ����������*���Z��XVC�(b�k�
D�G��
As i can see its file by itself, but how to handle it, and how upload it into firebase storage? Also, i'm not sure, that i'm correct creating a bucket and using storage api.
Please feel free to make request, you can get response without auth. That file must be mp3 type
Here is the logs with headers about what i'm getting from response:
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Tue, 24 Mar 2020 16:19:55 GMT
Content-Type: application/octet-stream;charset=utf-8
Content-Length: 48744
Connection: close
Content-Disposition: attachment; filename=file.mp3
��H�Xing��h $&)+-.179:>ACEGINRTW[_acegjmoqtwz|����������������������������������������������������PLAME3.100(,�$!��h�6���H��V]#mdE�E��"#���}�8kwT��&���>:P�2��>?�����8 ����������*���Z��XVC�(b�k�
D�G��
C���al�ꝰ�z�KY�Q�]ЪF�8�^���W;,�LUteA�%�u�&��.���
0�q��Cڟ#���6��#�K�h��Itᠠ|[�q�{j'�+ �ʤS<F� Y�5D]?�����nlƦBC�S�Zx'�e�D�Fi_��Vl��4����H��E�z���SMVПQ�P� AT<���(�x�+3�ТB����e�ZC}t��Ї�#֗����2���Kve���.�ԏ�UH���u����ʘfbC��C� ��C�+ġ��̺��R#��|x5hq`Х3�?�N(���.5��� c+��`�Y�F8�d�B&53��¥�L�cx4��3��q�JHԓJ�43Ώ�(к�4r ��a �D
Dɍ0�
Well, it seems that there are a couple of tasks to do here :)
According to the definition of the upload method and their examples, using node js as client library (that makes total sense). You will be able to Upload a file to the bucket. But to be honest, I am not very clear about the usage of the pathString parameter since it points to a local path. Maybe the URL option that you mentioned would be great to test as a feature.
Just pasting the example from docs:
// Imports the Google Cloud client library
const {Storage} = require('#google-cloud/storage');
// Creates a client
const storage = new Storage();
async function uploadFile() {
// Uploads a local file to the bucket
await storage.bucket(bucketName).upload(filename, {
gzip: true,
metadata: {
Content-Type: 'audio/mpeg'
},
});
console.log(`${filename} uploaded to ${bucketName}.`);
}
uploadFile().catch(console.error);
Another way to accomplish this, is to make a POST request with the JSON API to the upload method of Cloud Storage. As I understand, the objects are saved as "RAW" in Cloud Storage.
If you are concerned about the conversion to MP3 file, I think this answer explains very well. Basically, if you want to perform the conversion in the Firebase Function, maybe is not the best scenario according to the size/time of the files.
Good Luck!

Nuxt SPA dynamic routes based on Firebase Firestore data

So I want to have a nuxt site hosted on Netlify where there's a child route whos slug is a firebase firestore document id.
Example:
https://www.example.com/users/steve
(where "steve" is the documentid)
So when the route is hit I would need to query firebase to see if it exists, and if not I would have to return a 404. Is this even possible? I can do it easy in .net or php, but I'm very unsure of a SPA.
Specifically what should I be looking for in the docs, if I can do this?
One solution is to implement an HTTPS Cloud Function that you would call like a REST API, sending an HTTP GET request to the functions endpoint.
As explained in the doc "Used as arguments for onRequest(), the Request object gives you access to the properties of the HTTP request sent by the client".
So you Cloud Function would look like:
exports.getUser = functions.https.onRequest((req, res) => {
// get the value of the user by parsing the url
const baseUrl = req.baseUrl;
//Extract the user from baseUrl
const user = ....
//query the Firestore database
admin.firestore().collection('users').doc(user).get()
.then(doc => {
if (doc.exists) {
res.status(200).end();
} else {
res.status(404).end();
}
});
See the get started page and the video series for more info on Cloud Functions.
Note that you can connect an HTTP function to Firebase Hosting, in such a way that "requests on your Firebase Hosting site can be proxied to specific HTTP functions".

Meteor js requestPermissions not working

Meteor js requestPermissions not working. I want to access google calendar, access token not permission with google calendar. How I can get access google calendar.
there are two things to consider. The right permission you need from google, and the API you use to access your data. You don't provide too many details so I don't know whether you need mobile (Cordova) too.
For your project, in Google Developer Console you need to enable the Calendar API. Once you do that, you have options to see what appId / authorization is relevant for your API so you add it to your Meteor Settings.
Then from the OAuth 2.0 scopes you need to select the exact scope you need (search for "calendar" for instance) and add that scope (the entire url) to your array of scopes.
Then you can do GET or POST with something like the native HTTP API of Meteor
example:
let data = HTTP.call('GET', `https://people.googleapis.com/v1/people/me/connections?pageToken=${res.data.nextPageToken}&personFields=emailAddresses`,
// let data = HTTP.call('GET', `https:https://www.googleapis.com/calendar/v3/calendars/{... your calendarId} `,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: 'application/json'
}
},
(err, res) => { handle these })

Use of Service account credentials when using Cloud Functions Shell

I've just migrated to Cloud Functions 1.0 and am trying out Cloud Functions shell/emulator to run functions locally (using instructions at https://firebase.google.com/docs/functions/local-emulator)
One of the functions is using code below to upload a file to cloud storage and then then generate url for it....but am getting following error:
SigningError: Cannot sign data without client_email.
const bucket = gcs.bucket(bucketName);
bucket.upload(localFilePath, {destination: destinationPath})
.then(data => {
const file = data[0];
return file.getSignedUrl({
action: 'read',
expires: '01-01-2099'
});
I can work around this locally by explicitly setting keyFileName as shown below but seems like this should not be necessary
const gcs = require('#google-cloud/storage')({keyFilename: 'service-account.json'});
The link above mentions that "Cloud Firestore and Realtime Database triggers already have sufficient credentials, and do not require additional setup" (I'm triggering this code from db write). I'm setting GOOGLE_APPLICATION_CREDENTIALS env variable in any case but doesn't look like it's picking it up.

Resources