Issues with mime type #50
-
Hello!
I'm working in a proof of concept, trying to upload to Piñata an encrypted file. I'm using NestJS and I've tried to use both Piñata SDK and Piñata API, and follow the guides in documentation and Youtube.
I don't know if I'm doing something wrong, because after performing the upload, apparently Piñata API changes the mime type of the file that I've uploaded.
This is the code I'm using:
private async uploadToPinata(filePath: string) { const formData = new FormData(); const blob = new Blob ([fs.readFileSync(filePath)]); const fileToPin = new File([blob], "Imagen.txt", {type: "plain/text"}); console.log(fileToPin.type ); formData.append("file", blob); formData.append("network", "public"); //const upload = await pinata.upload.public.file(file); const request = await fetch("https://uploads.pinata.cloud/v3/files", { method: "POST", headers: { Authorization: `Bearer ${process.env.PINATA_JWT}`, }, body: formData, }); const response = await request.json(); console.log("Upload:", response); return response; }
When I log the response, the mime type is incorrect:
Upload: {
data: {
id: '0195965a-7227-7b91-84e5-963b9230c8ad',
user_id: 'e1157ab2-5de5-473c-8502-9447260203b7',
group_id: null,
name: 'blob',
cid: 'bafybeicmsj6vm724ai5ctcur7wgssu33kojlpaqaspsqn5ex5qxz2wfpuy',
created_at: '2025-03-14T20:31:07.169Z',
size: 18408552,
number_of_files: 1,
mime_type: 'application/json',
vectorized: false,
network: 'public'
}
}
Nevertheless, when I pin a txt file with the same content using Piñata web, the file uploads correctly and I can see in the inspector that it maintains the correct mime type.
Has anyone here have a similar problem? Am I doing anything wrong?
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment 11 replies
-
Hey there! I think your approach is really close, but it looks like you're attaching the blob to the formData instead of fileToPin
const fileToPin = new File([blob], "Imagen.txt", {type: "plain/text"}); console.log(fileToPin.type ); formData.append("file", blob); formData.append("network", "public");
Could you try formData.append("file", fileToPin); and see if that works?
Beta Was this translation helpful? Give feedback.
All reactions
-
Oh awesome! Yeah that is our legacy endpoint so that helps us narrow down the issue here, which seems like our new API. I'll have our team look into it. In the meantime the pinFileToIPFS is totally ok to use!
Beta Was this translation helpful? Give feedback.
All reactions
-
Ok, great! Thanks for your answer, I'll continue using pinFileToIPFS then :-)
Beta Was this translation helpful? Give feedback.
All reactions
-
Hey @RipleyCipher! I think we might have implemented some fixes, could you try now and see if it works?
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi! Sorry for the delay, I was busy with other projects. I've just tested without success. In case it's of any help, this is the source code:
import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import * as crypto from 'crypto'; import * as fs from 'fs'; import * as path from 'path'; import { PinataSDK } from "pinata"; import { url } from 'inspector'; import * as mime from 'mime-types'; import { text } from 'stream/consumers'; const pinata = new PinataSDK({ pinataJwt: process.env.PINATA_JWT, pinataGateway: "turquoise-traditional-reindeer-169.mypinata.cloud", }); @Injectable() export class NftService { constructor(private readonly prisma: PrismaService) {} async encryptAndUpload(id: string): Promise<{ piñataLink: string }> { const imagePath = path.join(__dirname, '..', '..', 'uploads', `${id}.jpg`); console.log('Image path:', imagePath); // Verificar si la imagen existe if (!fs.existsSync(imagePath)) { throw new NotFoundException('Imagen no encontrada'); } // Leer la imagen const imageBuffer = fs.readFileSync(imagePath); // Generar clave de encriptación const encryptionKey = crypto.randomBytes(32); const iv = crypto.randomBytes(16); // Vector de inicialización const cipher = crypto.createCipheriv('aes-256-cbc', encryptionKey, iv); console.log("encryptionKey:", encryptionKey.toString('hex')); console.log("iv:", iv.toString('hex')); console.log("cipher:", cipher); // Encriptar la imagen let encryptedData = cipher.update(imageBuffer); encryptedData = Buffer.concat([encryptedData, cipher.final()]); // Guardar la imagen encriptada temporalmente const encryptedPath = `${imagePath}.enc`; fs.writeFileSync(encryptedPath, encryptedData); // Subir a Piñata const pinataResponse = await this.uploadToPinata(encryptedPath); const piñataLink = pinataResponse.cid // Guardar clave en la base de datos await this.prisma.encryptedNFT.create({ data: { nft_id: id, encryption_key_ref: encryptionKey.toString('hex'), iv: iv.toString('hex'), metadata_url: "" }, }); // Eliminar archivo encriptado temporal //fs.unlinkSync(encryptedPath); return { piñataLink }; } private async uploadToPinata(filePath: string) { const formData = new FormData(); const blob = new Blob ([fs.readFileSync(filePath)]); const fileToPin = new File([fs.readFileSync(filePath)], "Imagen.txt", {type: "application/octet-stream"}); console.log(fileToPin.type ); formData.append("file", fileToPin); formData.append("network", "public"); //const upload = await pinata.upload.public.file(file); const request = await fetch("https://uploads.pinata.cloud/v3/files", { //const request = await fetch("https://api.pinata.cloud/pinning/pinFileToIPFS", { method: "POST", headers: { Authorization: `Bearer ${process.env.PINATA_JWT}`, }, body: formData, }); console.log("Request:", request); const response = await request.json(); console.log("Upload:", response); return response; } async getDecryptedImage(id: string, cid: string): Promise<Buffer> { // 1. Buscar en la BD la info asociada al ID const nft = await this.prisma.encryptedNFT.findFirst({ where: { nft_id: id }, }); if (!nft) { throw new NotFoundException('NFT no encontrado'); } const { encryption_key_ref, iv } = nft; console.log("cid:", cid); // 2. Descargar la imagen encriptada desde Piñata const image = await pinata.gateways.public.get(cid); console.log("Imagen:", image); //console.log ("imagen es blob:" , image instanceof Blob); //console.log ("contenido imagen:", image); if (!(image.data instanceof Blob)) { throw new Error('Expected image data to be a Blob'); } const arrayBuffer = await image.data.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); console.log("CID recibido:", cid); console.log("encryption_key_ref desde la BD:", encryption_key_ref); console.log("IV desde la BD:", iv); // 3. Desencriptar la imagen const decipher = crypto.createDecipheriv( 'aes-256-cbc', Buffer.from(encryption_key_ref, 'hex'), Buffer.from(iv, 'hex') ); let decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]); return decrypted; } }
The execution fails when trying to get the file from Piñata to my backend. When I use the legacy API to upload the file, this is an example of what I retrieve from Piñata:
Imagen: {
data: Blob { size: 15532656, type: 'application/octet-stream' },
contentType: 'application/octet-stream'
}
But when I use the v3 API, what I retrieve is:
Imagen: {
data: 'z��\x07�\n' +
'���|�\x7F�G����\x1EQ3��i:�~�\x00�\x1F0�\x07�orD�\x06Ե{��OmR��"gU�l���\x00q�л� �\\��^p;���I\\i%�f�\x13��7\x02hs���E\x0B�*��~���\x12\x03\\=�Qb~?�j�Ώ�\\I\x02\x053����N\x10m\n' +
'\x07���8{�&!... 15292338 more characters,
contentType: 'text/plain'
}
So, I'm not very sure if I have to modify anything to manage the response when I use the v3 API to upload.
Any advice would be more than welcome. Meanwhile, I'll keep using the legacy API.
Thanks a lot for your interest!
Beta Was this translation helpful? Give feedback.
All reactions
-
Ok I think I might have a solution! I confirmed with our engineering team that when uploading with the new endpoint it is going to prioritize the file type through the filename over the type you try to spoof. So by using "Imagen.txt" it will always default to a text file. If you try removing the extension and just use "Imagen" then it should work as an application/octect-stream!
Beta Was this translation helpful? Give feedback.