Skip to content

Compatibilité S3

Utilisez le SDK AWS pour téléverser, télécharger et gérer des fichiers sur IPFS Ninja avec le même code que celui que vous utilisez pour Amazon S3.

Endpoint

https://s3.ipfs.ninja

Identifiants

L'API S3 utilise votre clé API IPFS Ninja pour l'authentification. Votre clé API sert à la fois de clé d'accès et de clé secrète.

Comment obtenir vos identifiants

  1. Allez dans Tableau de bord > Clés API
  2. Cliquez sur Create API key et donnez-lui un nom (par ex. « Accès S3 »)
  3. Copiez la clé complète immédiatement — elle n'est affichée qu'une seule fois et ne peut pas être récupérée ultérieurement

Votre clé ressemble à ceci :

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

Correspondance avec les identifiants AWS

Paramètre AWSValeurExemple
accessKeyIdLes 12 premiers caractères de votre clé APIbws_628bba35
secretAccessKeyLa clé API complète (les 36 caractères)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionToujours us-east-1us-east-1

WARNING

La clé API complète n'est affichée qu'une seule fois lors de sa création. Si vous la perdez, supprimez la clé et créez-en une nouvelle depuis la page Clés API.

Démarrage rapide

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 = Dossiers

Les buckets S3 correspondent à vos dossiers IPFS Ninja. Lorsque vous téléversez un fichier dans un bucket, il est stocké dans le dossier correspondant. Lorsque vous listez les objets d'un bucket, vous voyez les fichiers de ce dossier.

Opération S3Équivalent IPFS Ninja
CreateBucketCréer un nouveau dossier
ListBucketsLister vos dossiers
DeleteBucketSupprimer un dossier et tous les fichiers qu'il contient
PutObject vers un bucketTéléverser un fichier dans le dossier
ListObjectsV2 sur un bucketLister les fichiers du dossier
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

Les dossiers créés via l'API S3 sont les mêmes que ceux visibles dans votre tableau de bord. Vous pouvez organiser vos fichiers depuis l'API S3, l'API REST ou l'interface web — ils partagent tous le même système de dossiers.

INFO

Contrairement à Amazon S3, les dossiers IPFS Ninja sont plats par défaut. Pour créer des structures imbriquées, utilisez les endpoints de dossiers de l'API REST avec parentFolderId. Depuis l'API S3, utilisez des préfixes de clé (par ex. images/photo.png) pour organiser les fichiers au sein d'un dossier.

Les noms de bucket sont uniques au niveau mondial

Les noms de bucket vivent dans un espace de noms global partagé entre tous les clients, comme le fait AWS S3. Cela signifie :

  • Le premier utilisateur à créer un bucket avec un nom donné s'approprie ce nom au niveau mondial.
  • Les appels CreateBucket ultérieurs avec le même nom, depuis n'importe quel compte, renvoient BucketAlreadyExists (409).
  • Si vous essayez de recréer votre propre bucket, vous obtenez BucketAlreadyOwnedByYou (409).
  • Le nom de votre dossier dans le tableau de bord reste propre à votre compte et peut être n'importe quoi — seul le nom de bucket visible via S3 passe par l'espace de noms global.

Si un nom que vous souhaitez est déjà pris, choisissez-en un plus spécifique (myapp-photos-2026, acme-nft-metadata) — la même convention que vous utiliseriez sur Amazon S3.

Opérations prises en charge

PutObject

Téléverse un fichier sur IPFS. Le fichier est épinglé, analysé pour la sécurité, et le CID est renvoyé dans les en-têtes ETag et x-amz-meta-cid.

Pour importer un fichier CAR au lieu d'un fichier classique, ajoutez l'en-tête de métadonnée x-amz-meta-import: car. Voir Import CAR pour plus de détails.

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

Télécharge un fichier par sa clé (nom de fichier) ou son 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

Obtient les métadonnées d'un fichier sans télécharger son contenu.

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

Désépingle un fichier d'IPFS et le supprime de votre compte.

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

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

ListObjectsV2

Liste les fichiers d'un bucket avec filtrage optionnel par préfixe et pagination.

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
}

Téléversement multipart

Téléversez de gros fichiers (jusqu'à 5 Go) à l'aide du téléversement multipart. Le SDK AWS gère cela automatiquement :

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 contrôlez manuellement les parties :

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 }]
  }
}));

Exemple 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())

Exemple 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!")
}

Configurer CORS (accès via SDK navigateur)

Si vous appelez l'API S3 directement depuis du JavaScript navigateur (SPA, application wallet, outil de tableau de bord), vous devez d'abord configurer CORS sur le bucket. Sinon, les navigateurs bloquent le preflight et vos téléversements échouent avec No 'Access-Control-Allow-Origin' header is present.

Même structure que sur AWS S3 — sous-ressources 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" }));

Plafond et valeurs par défaut

  • Jusqu'à 5 règles par bucket (la spécification en autorise 100 ; nous plafonnons à 5 pour garder la réponse de preflight du navigateur compacte).
  • Configuration totale plafonnée à 64 Ko une fois sérialisée.
  • Si aucune configuration CORS n'est définie, les preflights navigateur sont rejetés — comme le comportement par défaut d'AWS S3. Configurez des règles explicites pour les origines depuis lesquelles vous servez réellement du contenu.

Remarque de sécurité concrète

CORS est une couche de confort côté navigateur, pas une frontière de sécurité. Chaque appel à l'API S3 nécessite toujours une signature SigV4 valide calculée à partir de votre clé API — une configuration CORS permissive ne permet à personne d'utiliser votre bucket sans ce justificatif. Ce que CORS empêche réellement : qu'une origine non désirée (par ex. une copie obsolète de votre application sur dev.myapp.com) envoie des requêtes signées depuis un contexte navigateur.

Alternative via le tableau de bord

La page Fichiers propose une entrée S3 CORS dans le menu d'actions de chaque dossier. Même stockage sous-jacent ; si vous ne voulez pas écrire de code PutBucketCors, configurez-le là.

Différences avec Amazon S3

FonctionnalitéAmazon S3IPFS Ninja S3
Modèle de stockageObjets modifiablesAdressage par contenu (CID immuables)
Comportement d'écrasementRemplace l'objet sur placeCrée un nouveau CID, l'ancien CID reste accessible
VersioningPris en chargeNon pris en charge (utilisez les CID pour le versioning)
Chiffrement côté serveurPris en chargeNon pris en charge (le contenu est sur IPFS)
Politiques de cycle de viePrises en chargeNon prises en charge
Politiques de bucket / ACLPrises en chargeUtilisez les modes d'accès du gateway
URL présignéesPrises en chargeUtilisez les tokens de téléversement signés
Taille maximale d'objet5 To5 Go (multipart), 100 Mo (PUT unique)
RégionsMulti-régionus-east-1 uniquement
Valeur ETagHash MD5CID IPFS
En-têtes supplémentairesS3 standardx-amz-meta-cid (CID IPFS)
Format de CIDN/ACIDv1 moderne (bafy…) pour les nouveaux téléversements ; les Qm… hérités restent valides en entrée
Espace de noms de bucketGlobal (à l'échelle AWS)Global (à l'échelle de tous les comptes IPFS Ninja) — même sémantique
CORSPutBucketCors pris en chargePutBucketCors pris en charge (plafond de 5 règles)

Migration depuis Amazon S3

Remplacez la configuration de votre client 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
 });

Vos appels PutObject, GetObject, ListObjectsV2 et DeleteObject existants fonctionnent sans modification.

Migration depuis Filebase

Remplacez l'URL de l'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
 });