Skip to content

Compatibilidade S3

Utiliza o AWS SDK para carregar, transferir e gerir ficheiros no IPFS Ninja com o mesmo código que utilizas para o Amazon S3.

Endpoint

https://s3.ipfs.ninja

Credenciais

A API S3 utiliza a tua chave de API do IPFS Ninja para autenticação. A tua chave de API serve tanto como access key como secret key.

Como obter as tuas credenciais

  1. Vai a Dashboard > API Keys
  2. Clica em Create API key e dá-lhe um nome (ex.: "S3 access")
  3. Copia a chave completa imediatamente — só é apresentada uma vez e não pode ser recuperada depois

A tua chave tem este formato:

bws_628bba35e9e0079d9ff9c392b1b55a7b
├──────────┘└──────────────────────────┘
 prefix (12 chars)    rest of key

Mapeamento para credenciais AWS

Parâmetro AWSValorExemplo
accessKeyIdOs primeiros 12 caracteres da tua chave de APIbws_628bba35
secretAccessKeyA chave de API completa (todos os 36 caracteres)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionSempre us-east-1us-east-1

WARNING

A chave de API completa só é apresentada uma vez, quando a crias. Se a perderes, elimina a chave e cria uma nova na página de API Keys.

Início Rápido

javascript
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: "https://s3.ipfs.ninja",
  credentials: {
    accessKeyId: "bws_628bba35",
    secretAccessKey: "bws_628bba35e9e0079d9ff9c392b1b55a7b"
  },
  region: "us-east-1",
  forcePathStyle: true
});

// Upload a file
const put = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "hello.json",
  Body: JSON.stringify({ hello: "IPFS" }),
  ContentType: "application/json"
}));

console.log("CID:", put.Metadata?.cid);
// CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

Buckets = Pastas

Os buckets S3 correspondem às tuas pastas no IPFS Ninja. Quando carregas um ficheiro para um bucket, este é guardado na pasta correspondente. Quando listas objetos num bucket, vês os ficheiros dessa pasta.

Operação S3Equivalente no IPFS Ninja
CreateBucketCriar uma nova pasta
ListBucketsListar as tuas pastas
DeleteBucketEliminar uma pasta e todos os ficheiros nela
PutObject no bucketCarregar ficheiro para a pasta
ListObjectsV2 no bucketListar ficheiros na pasta
javascript
import { ListBucketsCommand, CreateBucketCommand, PutObjectCommand } from "@aws-sdk/client-s3";

// Create a bucket (= create a folder)
await s3.send(new CreateBucketCommand({ Bucket: "nft-metadata" }));

// Upload a file into the folder
await s3.send(new PutObjectCommand({
  Bucket: "nft-metadata",      // ← folder name
  Key: "token-42.json",        // ← filename within the folder
  Body: JSON.stringify({ name: "My NFT #42" })
}));

// List buckets (= list your folders)
const { Buckets } = await s3.send(new ListBucketsCommand({}));
console.log(Buckets);
// [{ Name: "nft-metadata", CreationDate: "2026-04-13T..." }]

TIP

As pastas criadas através da API S3 são as mesmas pastas visíveis no teu Dashboard. Podes organizar ficheiros tanto pela API S3, como pela API REST, ou pela interface web — todas partilham o mesmo sistema de pastas.

INFO

Ao contrário do Amazon S3, as pastas do IPFS Ninja são planas por predefinição. Para criar estruturas aninhadas, utiliza os endpoints de pastas da API REST com parentFolderId. A partir da API S3, utiliza prefixos nas chaves (ex.: images/photo.png) para organizar dentro de uma pasta.

Os nomes de bucket são globalmente únicos

Os nomes de bucket vivem num espaço de nomes global partilhado por todos os clientes, tal como acontece no Amazon S3. Isto significa que:

  • O primeiro utilizador a criar um bucket com determinado nome reserva esse nome globalmente.
  • Chamadas CreateBucket posteriores com o mesmo nome, de qualquer conta, devolvem BucketAlreadyExists (409).
  • Se tentares recriar o teu próprio bucket, recebes BucketAlreadyOwnedByYou (409).
  • O nome da tua pasta no painel é por conta e pode continuar a ser o que quiseres — só o nome do bucket visível pela API S3 passa pelo espaço de nomes global.

Se o nome que queres já estiver ocupado, escolhe um nome com um âmbito diferente (myapp-photos-2026, acme-nft-metadata) — a mesma convenção que usarias no Amazon S3.

Operações Suportadas

PutObject

Carrega um ficheiro para o IPFS. O ficheiro é fixado, verificado quanto à segurança, e o CID é devolvido nos cabeçalhos ETag e x-amz-meta-cid.

Para importar um ficheiro CAR em vez de um ficheiro normal, adiciona o cabeçalho de metadados x-amz-meta-import: car. Consulta Importação CAR para detalhes.

javascript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import fs from "fs";

const result = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "photo.png",
  Body: fs.readFileSync("photo.png"),
  ContentType: "image/png"
}));

console.log("CID:", result.ETag);
bash
# curl equivalent
curl -X PUT "https://s3.ipfs.ninja/my-project/photo.png" \
  --data-binary @photo.png \
  -H "Content-Type: image/png" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  --user "bws_628bba35:bws_628bba35e9e0079d9ff9c392b1b55a7b"

GetObject

Transfere um ficheiro pela sua chave (nome do ficheiro) ou CID.

javascript
import { GetObjectCommand } from "@aws-sdk/client-s3";

const result = await s3.send(new GetObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

const body = await result.Body.transformToByteArray();
console.log("Size:", body.length);
console.log("CID:", result.Metadata?.cid);

HeadObject

Obtém os metadados do ficheiro sem transferir o conteúdo.

javascript
import { HeadObjectCommand } from "@aws-sdk/client-s3";

const head = await s3.send(new HeadObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

console.log("Size:", head.ContentLength);
console.log("Type:", head.ContentType);
console.log("CID:", head.Metadata?.cid);

DeleteObject

Desfixa um ficheiro do IPFS e elimina-o da tua conta.

javascript
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

ListObjectsV2

Lista ficheiros num bucket com filtragem opcional por prefixo e paginação.

javascript
import { ListObjectsV2Command } from "@aws-sdk/client-s3";

const list = await s3.send(new ListObjectsV2Command({
  Bucket: "my-project",
  Prefix: "images/",
  MaxKeys: 100
}));

for (const obj of list.Contents ?? []) {
  console.log(obj.Key, obj.Size, obj.ETag); // ETag = CID
}

Multipart Upload

Carrega ficheiros grandes (até 5 GB) utilizando o carregamento multiparte. O AWS SDK trata disto automaticamente:

javascript
import { Upload } from "@aws-sdk/lib-storage";
import fs from "fs";

const upload = new Upload({
  client: s3,
  params: {
    Bucket: "my-project",
    Key: "large-dataset.tar.gz",
    Body: fs.createReadStream("large-dataset.tar.gz"),
    ContentType: "application/gzip"
  },
  partSize: 10 * 1024 * 1024, // 10 MB per part
});

upload.on("httpUploadProgress", (progress) => {
  console.log(`Uploaded ${progress.loaded} of ${progress.total} bytes`);
});

const result = await upload.done();
console.log("CID:", result.ETag);

Ou controla as partes manualmente:

javascript
import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand
} from "@aws-sdk/client-s3";

// 1. Start
const { UploadId } = await s3.send(new CreateMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin"
}));

// 2. Upload parts
const part1 = await s3.send(new UploadPartCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  PartNumber: 1,
  Body: chunk1
}));

// 3. Complete
const result = await s3.send(new CompleteMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  MultipartUpload: {
    Parts: [{ PartNumber: 1, ETag: part1.ETag }]
  }
}));

Exemplo em Python

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.ipfs.ninja",
    aws_access_key_id="bws_628bba35",
    aws_secret_access_key="bws_628bba35e9e0079d9ff9c392b1b55a7b",
    region_name="us-east-1"
)

# Upload
s3.put_object(
    Bucket="my-project",
    Key="data.json",
    Body=b'{"hello": "IPFS"}',
    ContentType="application/json"
)

# List files
response = s3.list_objects_v2(Bucket="my-project")
for obj in response.get("Contents", []):
    print(obj["Key"], obj["Size"])

# Download
result = s3.get_object(Bucket="my-project", Key="data.json")
print(result["Body"].read())

Exemplo em Go

go
package main

import (
    "context"
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    client := s3.New(s3.Options{
        BaseEndpoint: aws.String("https://s3.ipfs.ninja"),
        Region:       "us-east-1",
        Credentials:  credentials.NewStaticCredentialsProvider("bws_628bba35", "bws_628bba35e9e0...", ""),
        UsePathStyle: true,
    })

    _, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket:      aws.String("my-project"),
        Key:         aws.String("hello.txt"),
        Body:        strings.NewReader("Hello, IPFS!"),
        ContentType: aws.String("text/plain"),
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Uploaded!")
}

Configurar CORS (acesso via SDK no browser)

Se estás a chamar a API S3 diretamente a partir de JavaScript no browser (SPA, aplicação de carteira, ferramenta do painel), tens de configurar CORS no bucket primeiro. Caso contrário, os browsers bloqueiam o preflight e os teus carregamentos falham com No 'Access-Control-Allow-Origin' header is present.

Mesma estrutura que no AWS S3 — subrecursos PutBucketCors / GetBucketCors / DeleteBucketCors:

PutBucketCors

javascript
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new PutBucketCorsCommand({
  Bucket: "my-bucket",
  CORSConfiguration: {
    CORSRules: [{
      AllowedOrigins: ["http://localhost:3000", "https://myapp.com"],
      AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE"],
      AllowedHeaders: ["*"],
      ExposeHeaders: ["ETag", "x-amz-meta-cid", "x-amz-request-id"],
      MaxAgeSeconds: 3600,
    }],
  },
}));

GetBucketCors

javascript
import { GetBucketCorsCommand } from "@aws-sdk/client-s3";

const { CORSRules } = await s3.send(new GetBucketCorsCommand({ Bucket: "my-bucket" }));
console.log(CORSRules);

DeleteBucketCors

javascript
import { DeleteBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteBucketCorsCommand({ Bucket: "my-bucket" }));

Limite e valores predefinidos

  • Até 5 regras por bucket (a especificação permite 100; limitamos a 5 para manter a resposta de preflight do browser compacta).
  • Configuração total limitada a 64 KB serializados.
  • Se não houver configuração de CORS definida, os preflights do browser são rejeitados — tal como no comportamento predefinido do AWS S3. Configura regras explícitas para as origens a partir das quais realmente serves conteúdo.

Nota de segurança do mundo real

CORS é uma camada de conveniência do lado do browser, não uma fronteira de segurança. Todos os pedidos à API S3 continuam a exigir uma assinatura SigV4 válida calculada a partir da tua chave de API — uma configuração de CORS permissiva não permite que alguém utilize o teu bucket sem essa credencial. O que o CORS efetivamente evita: que uma origem não pretendida (ex.: uma cópia desatualizada da tua aplicação em dev.myapp.com) envie pedidos assinados a partir de um contexto de browser.

Alternativa: painel

A página Ficheiros tem uma opção S3 CORS no menu de ações de cada pasta. Mesmo armazenamento subjacente; se não quiseres escrever código para PutBucketCors, configura-o por ali.

Diferenças em relação ao Amazon S3

FuncionalidadeAmazon S3IPFS Ninja S3
Modelo de armazenamentoObjetos mutáveisEndereçamento por conteúdo (CIDs imutáveis)
Comportamento de sobrescritaSubstitui o objeto no localCria novo CID, o CID antigo continua acessível
VersionamentoSuportadoNão suportado (utiliza CIDs para versionamento)
Encriptação no servidorSuportadaNão suportada (o conteúdo está no IPFS)
Políticas de ciclo de vidaSuportadasNão suportadas
Políticas de bucket / ACLsSuportadasUtiliza os modos de acesso do gateway
URLs pré-assinadosSuportadosUtiliza os tokens de carregamento assinados
Tamanho máximo do objeto5 TB5 GB (multiparte), 100 MB (PUT único)
RegiõesMulti-regiãoApenas us-east-1
Valor do ETagHash MD5CID IPFS
Cabeçalhos extraS3 padrãox-amz-meta-cid (CID IPFS)
Formato do CIDN/ACIDv1 moderno (bafy…) para novos carregamentos; o Qm… legado continua válido como entrada
Espaço de nomes do bucketGlobal (em toda a AWS)Global (em todas as contas IPFS Ninja) — mesma semântica
CORSPutBucketCors suportadoPutBucketCors suportado (limite de 5 regras)

Migrar do Amazon S3

Substitui a configuração do teu cliente S3:

diff
 const s3 = new S3Client({
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "AKIA...",
-    secretAccessKey: "wJalrX..."
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
+  forcePathStyle: true
 });

As tuas chamadas existentes de PutObject, GetObject, ListObjectsV2 e DeleteObject funcionam sem alterações.

Migrar do Filebase

Substitui o URL do endpoint:

diff
 const s3 = new S3Client({
-  endpoint: "https://s3.filebase.com",
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "FILEBASE_KEY",
-    secretAccessKey: "FILEBASE_SECRET"
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
   forcePathStyle: true
 });