Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Issues with mime type #50

Unanswered
RipleyCypher asked this question in Q&A
Mar 14, 2025 · 1 comments · 11 replies
Discussion options

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?

You must be logged in to vote

Replies: 1 comment 11 replies

Comment options

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?

You must be logged in to vote
11 replies
Comment options

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!

Comment options

Ok, great! Thanks for your answer, I'll continue using pinFileToIPFS then :-)

Comment options

Hey @RipleyCipher! I think we might have implemented some fixes, could you try now and see if it works?

Comment options

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!

Comment options

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /