Skip to content

Συμβατότητα με S3

Χρησιμοποίησε το AWS SDK για να ανεβάσεις, να κατεβάσεις και να διαχειριστείς αρχεία στο IPFS Ninja με τον ίδιο κώδικα που χρησιμοποιείς για το Amazon S3.

Endpoint

https://s3.ipfs.ninja

Διαπιστευτήρια

Το S3 API χρησιμοποιεί το κλειδί API του IPFS Ninja για πιστοποίηση. Το κλειδί API σου λειτουργεί ταυτόχρονα ως access key και ως secret key.

Πώς να αποκτήσεις τα διαπιστευτήριά σου

  1. Πήγαινε στο Dashboard > API Keys
  2. Κάνε κλικ στο Create API key και δώσε του ένα όνομα (π.χ. «S3 access»)
  3. Αντέγραψε ολόκληρο το κλειδί αμέσως — εμφανίζεται μόνο μία φορά και δεν μπορεί να ανακτηθεί αργότερα

Το κλειδί σου μοιάζει έτσι:

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

Αντιστοίχιση σε διαπιστευτήρια AWS

Παράμετρος AWSΤιμήΠαράδειγμα
accessKeyIdΠρώτοι 12 χαρακτήρες του κλειδιού API σουbws_628bba35
secretAccessKeyΤο ολόκληρο κλειδί API (όλοι οι 36 χαρακτήρες)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionΠάντα us-east-1us-east-1

WARNING

Το πλήρες κλειδί API εμφανίζεται μόνο μία φορά όταν το δημιουργείς. Αν το χάσεις, διέγραψε το κλειδί και δημιούργησε ένα νέο από τη σελίδα API Keys.

Γρήγορη Εκκίνηση

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 = Φάκελοι

Τα S3 buckets αντιστοιχούν στους φακέλους σου στο IPFS Ninja. Όταν ανεβάζεις ένα αρχείο σε ένα bucket, αποθηκεύεται στον αντίστοιχο φάκελο. Όταν εμφανίζεις τα αντικείμενα σε ένα bucket, βλέπεις τα αρχεία σε αυτόν τον φάκελο.

Λειτουργία S3Αντιστοιχία στο IPFS Ninja
CreateBucketΔημιουργία νέου φακέλου
ListBucketsΕμφάνιση των φακέλων σου
DeleteBucketΔιαγραφή φακέλου και όλων των αρχείων του
PutObject σε bucketΑνέβασμα αρχείου στον φάκελο
ListObjectsV2 σε bucketΕμφάνιση αρχείων στον φάκελο
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

Οι φάκελοι που δημιουργούνται μέσω του S3 API είναι οι ίδιοι φάκελοι που εμφανίζονται στο Dashboard σου. Μπορείς να οργανώσεις αρχεία είτε από το S3 API, είτε από το REST API, είτε από τη διεπαφή ιστού — όλα μοιράζονται το ίδιο σύστημα φακέλων.

INFO

Σε αντίθεση με το Amazon S3, οι φάκελοι του IPFS Ninja είναι επίπεδοι από προεπιλογή. Για να δημιουργήσεις ένθετες δομές, χρησιμοποίησε τα endpoints φακέλων του REST API με parentFolderId. Από το S3 API, χρησιμοποίησε προθέματα κλειδιών (π.χ. images/photo.png) για οργάνωση εντός ενός φακέλου.

Τα ονόματα buckets είναι καθολικά μοναδικά

Τα ονόματα buckets βρίσκονται σε έναν καθολικό χώρο ονομάτων (global namespace) κοινό για όλους τους πελάτες, αντιστοιχώντας στη σημασιολογία του AWS S3. Αυτό σημαίνει ότι:

  • Ο πρώτος χρήστης που δημιουργεί ένα bucket με συγκεκριμένο όνομα διεκδικεί αυτό το όνομα καθολικά.
  • Μεταγενέστερες κλήσεις CreateBucket με το ίδιο όνομα, από οποιονδήποτε λογαριασμό, επιστρέφουν BucketAlreadyExists (409).
  • Αν προσπαθήσεις να αναδημιουργήσεις το δικό σου bucket, λαμβάνεις BucketAlreadyOwnedByYou (409).
  • Το όνομα του φακέλου σου στο dashboard είναι ανά λογαριασμό και μπορεί να παραμείνει ό,τι θέλεις — μόνο το ορατό στο S3 όνομα bucket περνά μέσα από τον καθολικό χώρο ονομάτων.

Αν κάποιο όνομα που θέλεις είναι ήδη πιασμένο, διάλεξε ένα με διαφορετικό εύρος (myapp-photos-2026, acme-nft-metadata) — την ίδια σύμβαση που θα χρησιμοποιούσες και στο Amazon S3.

Υποστηριζόμενες Λειτουργίες

PutObject

Ανέβασε ένα αρχείο στο IPFS. Το αρχείο γίνεται pin, ελέγχεται για ασφάλεια, και ο CID επιστρέφεται στα headers ETag και x-amz-meta-cid.

Για να εισαγάγεις ένα αρχείο CAR αντί για ένα κανονικό αρχείο, πρόσθεσε το header μεταδεδομένων x-amz-meta-import: car. Δες την Εισαγωγή CAR για λεπτομέρειες.

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

Κατέβασε ένα αρχείο με βάση το κλειδί (όνομα αρχείου) ή τον 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

Λάβε τα μεταδεδομένα ενός αρχείου χωρίς να κατεβάσεις το περιεχόμενο.

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

Αφαίρεσε το pin ενός αρχείου από το IPFS και διέγραψέ το από τον λογαριασμό σου.

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

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

ListObjectsV2

Εμφάνισε τα αρχεία σε ένα bucket με προαιρετικό φιλτράρισμα προθέματος και σελιδοποίηση.

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

Ανέβασε μεγάλα αρχεία (έως 5 GB) χρησιμοποιώντας multipart upload. Το AWS SDK το χειρίζεται αυτόματα:

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

Ή έλεγξε τα μέρη χειροκίνητα:

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

Παράδειγμα 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())

Παράδειγμα 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!")
}

Ρύθμιση CORS (πρόσβαση από SDK σε browser)

Αν καλείς το S3 API απευθείας από JavaScript σε browser (SPA, εφαρμογή πορτοφολιού, εργαλείο dashboard), πρέπει πρώτα να ρυθμίσεις το CORS στο bucket. Διαφορετικά οι browsers μπλοκάρουν το preflight και οι μεταφορτώσεις σου αποτυγχάνουν με No 'Access-Control-Allow-Origin' header is present.

Ίδια δομή με το AWS S3 — subresources 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" }));

Όριο και προεπιλογές

  • Έως 5 κανόνες ανά bucket (η προδιαγραφή επιτρέπει 100· εμείς περιορίζουμε στους 5 ώστε η απάντηση του browser preflight να παραμένει συμπαγής).
  • Η συνολική διαμόρφωση περιορίζεται στα 64 KB σε σειριοποιημένη μορφή.
  • Αν δεν έχει οριστεί διαμόρφωση CORS, τα browser preflights απορρίπτονται — αντιστοιχώντας στην προεπιλεγμένη στάση του AWS S3. Ρύθμισε ρητούς κανόνες για τις origins από τις οποίες όντως εξυπηρετείς.

Σημείωση ασφάλειας στην πράξη

Το CORS είναι ένα επίπεδο διευκόλυνσης στην πλευρά του browser, όχι ένα όριο ασφάλειας. Κάθε κλήση στο S3 API εξακολουθεί να απαιτεί μια έγκυρη υπογραφή SigV4 υπολογισμένη από το κλειδί API σου — μια επιτρεπτική διαμόρφωση CORS δεν επιτρέπει σε κανέναν να χρησιμοποιήσει το bucket σου χωρίς αυτό το διαπιστευτήριο. Αυτό που όντως εμποδίζει το CORS: μια ανεπιθύμητη origin (π.χ. ένα παλιό αντίγραφο της εφαρμογής σου στο dev.myapp.com) να στέλνει υπογεγραμμένα αιτήματα από ένα περιβάλλον browser.

Εναλλακτική μέσω Dashboard

Η σελίδα Files έχει μια καταχώρηση S3 CORS στο μενού ενεργειών κάθε φακέλου. Ίδια υποκείμενη αποθήκευση· αν δεν θέλεις να γράψεις κώδικα PutBucketCors, ρύθμισέ το από εκεί.

Διαφορές από το Amazon S3

ΧαρακτηριστικόAmazon S3IPFS Ninja S3
Μοντέλο αποθήκευσηςΜεταβλητά αντικείμεναΔιευθυνσιοδότηση περιεχομένου (αμετάβλητα CIDs)
Συμπεριφορά αντικατάστασηςΑντικαθιστά το αντικείμενο επιτόπουΔημιουργεί νέο CID, ο παλιός CID παραμένει προσβάσιμος
ΕκδόσειςΥποστηρίζεταιΔεν υποστηρίζεται (χρησιμοποίησε CIDs για εκδόσεις)
Κρυπτογράφηση στον serverΥποστηρίζεταιΔεν υποστηρίζεται (το περιεχόμενο είναι στο IPFS)
Πολιτικές κύκλου ζωήςΥποστηρίζονταιΔεν υποστηρίζονται
Πολιτικές bucket / ACLsΥποστηρίζονταιΧρησιμοποίησε λειτουργίες πρόσβασης gateway
Προϋπογεγραμμένα URLsΥποστηρίζονταιΧρησιμοποίησε υπογεγραμμένα tokens μεταφόρτωσης
Μέγιστο μέγεθος αντικειμένου5 TB5 GB (multipart), 100 MB (μεμονωμένο PUT)
ΠεριοχέςΠολλαπλές περιοχέςΜόνο us-east-1
Τιμή ETagMD5 hashIPFS CID
Επιπλέον headersStandard S3x-amz-meta-cid (IPFS CID)
Μορφή CIDΔ/ΥΣύγχρονο CIDv1 (bafy…) για νέες μεταφορτώσεις· το παλαιότερο Qm… παραμένει έγκυρο ως είσοδος
Χώρος ονομάτων bucketΚαθολικός (σε όλο το AWS)Καθολικός (σε όλους τους λογαριασμούς IPFS Ninja) — ίδια σημασιολογία
CORSΥποστηρίζεται PutBucketCorsΥποστηρίζεται PutBucketCors (όριο 5 κανόνων)

Μετάβαση από το Amazon S3

Αντικατέστησε τη διαμόρφωση του S3 client:

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

Οι υπάρχουσες κλήσεις σου PutObject, GetObject, ListObjectsV2 και DeleteObject λειτουργούν χωρίς αλλαγές.

Μετάβαση από το Filebase

Αντικατέστησε το endpoint URL:

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