I'm trying to generate and upload an image for each vendor that is created in my project, then update that vendor's document with the url of that image. But it continues failing with an error:
SigningError: Permission 'iam.serviceAccounts.signBlob' denied on resource (or it may not exist).
The generation and upload work fine. It's getting the url from that file is what fails. The weird thing is that it worked fine when I did this with a script I ran manually while using almost the exact same code. Not sure why it worked then, but not within my onCreate function. Here is a snippet of the code:
const db = admin.firestore()
const stg = new storage.Storage()
const bucket = stg.bucket('my_bucket')
try {
// Generate OG image - returns a Buffer
const buffer = await generateOgImage(vendor)
// Upload image to Storage
const imagePath = `vendors/${vendorId}/og.jpg`
const file = bucket.file(imagePath)
await file.save(buffer, {contentType: 'image/jpeg'})
// Get url from uploaded image
// ! Fails here
const url = await file.getSignedUrl({
action: 'read',
expires: '03-09-2491'
}).then(res => res[0])
// Add ogImageUrl property and update vendor doc
vendor.ogImageUrl = url
await db.collection('vendors').doc(vendorId).update(vendor)
} catch (e) {
console.error(e)
}
I've tried using the different storage objects provided by Firebase/GCP but neither work. And I also made sure to initialize with a credential.
// index.ts
import * as admin from 'firebase-admin'
admin.initializeApp({credential: admin.credential.cert('cert_key_path')})
// onCreateVendor.ts
import * as storage from '@google-cloud/storage'
import * as admin from 'firebase-admin'
const stg = new storage.Storage()
const stg = admin.storage()
Here is the full code:
// onCreateVendor.ts
import axios from 'axios'
import * as functions from 'firebase-functions'
import * as storage from '@google-cloud/storage'
import * as admin from 'firebase-admin'
const db = admin.firestore()
const stg = new storage.Storage()
interface Vendor {
id: string
ogImageUrl: string
// Other props ...
}
export const onCreateVendor = functions.firestore
.document('vendors/{vendorId}')
.onCreate(async (snapshot, context) => {
const vendor = snapshot.data() as Vendor
const vendorId = vendor.id
const bucket = stg.bucket('my_bucket')
try {
// Generate OG image
const buffer = await generateOgImage(vendor)
// Upload image to Storage
const imagePath = `vendors/${vendorId}/og.jpg`
const file = bucket.file(imagePath)
await file.save(buffer, {contentType: 'image/jpeg'})
// Get url from uploaded image
// ! Fails here
const url = await file.getSignedUrl({
action: 'read',
expires: '03-09-2491'
}).then(res => res[0])
// Add ogImageUrl property and update vendor doc
vendor.ogImageUrl = url
await db.collection('vendors').doc(vendorId).update(vendor)
} catch (e) {
console.error(e)
}
})
async function generateOgImage(vendor: Vendor): Promise<Buffer> {
let response = await axios({
// ... Axios stuff
})
return Buffer.from(response.data, 'binary')
}