dart_ipfs

A complete, production-ready IPFS (InterPlanetary File System) implementation in Dart, supporting offline, gateway, and full P2P modes.

pub package Dart License: MIT Build Status Tests Ko-Fi

📚 Documentation

Features

✅ Core IPFS Functionality

  • Content-Addressable Storage: CID v0 and v1 support
  • UnixFS: Full file system implementation with chunking
  • DAG-PB: MerkleDAG operations and IPLD traversal
  • CAR Files: Import/export support
  • Pinning: Content persistence management

✅ Networking & Protocols

  • Bitswap 1.2.0: Efficient block exchange
  • Kademlia DHT: Distributed hash table for routing
  • PubSub: Real-time messaging
  • MDNS: Local peer discovery
  • Bootstrap Peers: Network connectivity
  • Web Platform: Full browser support via IPFSWebNode

✅ Services

  • HTTP Gateway: Read-only and writable modes
  • RPC API: Compatible with go-ipfs API
  • IPNS: Mutable naming system
  • DNSLink: Domain-based content resolution
  • Metrics: Prometheus-compatible monitoring

✅ Security

  • Production-Grade Cryptography: secp256k1 + ChaCha20-Poly1305 AEAD
  • Encrypted Key Storage (SEC-001): AES-256-GCM with PBKDF2
  • Content Verification: Automatic CID validation
  • IPNS Signatures (SEC-004): Ed25519 cryptographic verification
  • Memory Security: Key zeroing on lock

Quick Start

Installation

Add to your pubspec.yaml:

dependencies:
  dart_ipfs: ^1.3.0

Or from Git for latest development:

dependencies:
  dart_ipfs:
    git:
      url: https://github.com/jxoesneon/IPFS.git

Then run:

dart pub get

Basic Usage

Offline Mode (Local Storage)

import 'package:dart_ipfs/dart_ipfs.dart';

void main() async {
  // Create node in offline mode
  final node = await IPFSNode.create(
    IPFSConfig(
      dataDir: './ipfs_data',
      offline: true,  // No P2P networking
    ),
  );

  await node.start();

  // Add content
  final content = 'Hello, IPFS!';
  final cid = await node.add(content);
  print('Added with CID: $cid');

  // Retrieve content
  final retrieved = await node.cat(cid);
  print('Retrieved: $retrieved');

  await node.stop();
}

Gateway Mode (HTTP Server)

import 'package:dart_ipfs/dart_ipfs.dart';

void main() async {
  final node = await IPFSNode.create(
    IPFSConfig(
      dataDir: './gateway_data',
      offline: true,
      gateway: GatewayConfig(
        enabled: true,
        port: 8080,
      ),
    ),
  );

  await node.start();
  print('Gateway running at http://localhost:8080');

  // Content accessible at:
  // http://localhost:8080/ipfs/<CID>
}

P2P Network Mode (Full Node)

import 'package:dart_ipfs/dart_ipfs.dart';

void main() async {
  final node = await IPFSNode.create(
    IPFSConfig(
      dataDir: './p2p_data',
      offline: false,  // Enable P2P networking
      network: NetworkConfig(
        bootstrapPeers: [
          '/dnsaddr/bootstrap.libp2p.io/p2p/...',
        ],
      ),
    ),
  );

  await node.start();
  print('P2P Node ID: ${node.peerID}');

  // Node participates in DHT, Bitswap, PubSub
}

Web Platform (Browser)

import 'package:dart_ipfs/src/core/ipfs_node/ipfs_web_node.dart';
import 'dart:typed_data';

void main() async {
  // Use IPFSWebNode for browser environments
  final node = IPFSWebNode(
    // Optional: Connect to secure WebSocket relays
    bootstrapPeers: ['wss://relay.node.address/p2p/...'],
  );
  await node.start();

  // Add content (stores in IndexedDB)
  final cid = await node.add(Uint8List.fromList('Hello Web!'.codeUnits));
  print('Added: $cid');

  // Retrieve content
  final data = await node.get(cid.encode());
  print('Retrieved: ${String.fromCharCodes(data!)}');
}

Gateway Selector (New in 1.2.1)

You can dynamically switch between gateway modes in both the Flutter Dashboard and CLI:

  • Internal: Uses the native Dart P2P node (libp2p).
  • Public: Fetches content via ipfs.io (HTTP).
  • Local: Fetches via local Go-IPFS daemon (localhost:8080).
  • Custom: User-defined gateway URL.

Use Cases

1. Decentralized Storage

// Store files with content addressing
final file = File('document.pdf');
final bytes = await file.readAsBytes();
final cid = await node.addBytes(bytes);

// Content is permanently addressable by CID
print('Document CID: $cid');

2. Content Distribution Network

// Run as HTTP gateway for CDN
final config = IPFSConfig(
  gateway: GatewayConfig(
    enabled: true,
    port: 8080,
    cacheSize: 1024 * 1024 * 1024, // 1GB cache
  ),
);

3. Peer-to-Peer Applications

// Pub/Sub messaging
await node.pubsub.subscribe('my-topic', (message) {
  print('Received: $message');
});

await node.pubsub.publish('my-topic', 'Hello, peers!');

4. Decentralized Websites

// Publish a directory
final websiteDir = Directory('./my-website');
final rootCID = await node.addDirectory(websiteDir);

// Access via: http://gateway/ipfs/<rootCID>/index.html

Configuration

IPFSConfig Options

IPFSConfig(
  // Storage
  dataDir: './ipfs_data',           // Data directory

  // Networking
  offline: false,                    // Disable P2P if true
  network: NetworkConfig(
    bootstrapPeers: [...],           // Bootstrap nodes
    listenAddresses: [               // Bind addresses
      '/ip4/0.0.0.0/tcp/4001',
    ],
  ),

  // Gateway
  gateway: GatewayConfig(
    enabled: true,
    port: 8080,
    writable: false,                 // Read-only by default
  ),

  // RPC API
  rpc: RPCConfig(
    enabled: true,
    port: 5001,
  ),

  // DHT
  dht: DHTConfig(
    mode: DHTMode.server,            // client, server, or auto
    bucketSize: 20,
  ),

  // Logging
  debug: false,
  verboseLogging: false,
)

API Reference

Content Operations

// Add content
final cid = await node.add('content');
final cidBytes = await node.addBytes(bytes);
final cidFile = await node.addFile(file);
final cidDir = await node.addDirectory(dir);

// Retrieve content
final content = await node.cat(cid);
final bytes = await node.getBytes(cid);
final stream = node.catStream(cid);

// Pin management
await node.pin(cid);
await node.unpin(cid);
final pins = await node.listPins();

Networking

// Peer operations
await node.connectToPeer(multiaddr);
final peers = await node.listConnectedPeers();

// DHT operations
final providers = await node.findProviders(cid);
await node.provide(cid);

// PubSub
await node.pubsub.subscribe(topic, callback);
await node.pubsub.publish(topic, data);
final topics = await node.pubsub.listTopics();

IPNS

// Publish mutable name
final ipnsKey = await node.publishIPNS(cid);
print('Published at: /ipns/$ipnsKey');

// Resolve IPNS
final resolved = await node.resolveIPNS(ipnsKey);

Examples

See the example/ directory for full applications:

Other examples:

Run examples:

dart run example/blog_use_case.dart
dart run example/online_test.dart

Deployment Modes

Offline Mode (0 External Dependencies)

Perfect for:

  • Edge computing
  • Embedded systems
  • Local-first applications
  • Testing

Features:

  • ✅ Content storage
  • ✅ CID operations
  • ✅ File system
  • ✅ Pinning
  • ❌ P2P networking (disabled by design)
  • ❌ DHT queries (requires P2P)

Gateway Mode (HTTP + Optional P2P)

Perfect for:

  • Content delivery networks
  • API services
  • Web hosting
  • Public gateways

Features:

  • ✅ HTTP API
  • ✅ Content caching
  • ✅ Compression
  • ✅ P2P networking (optional - can fetch from network)
  • ✅ Content routing (when P2P enabled)

P2P Mode (Full Node)

Perfect for:

  • Public IPFS network
  • DHT participation
  • Content distribution
  • Decentralized apps

Features:

  • ✅ All of the above
  • ✅ P2P networking (fully functional)
  • ✅ DHT server
  • ✅ Bitswap exchange
  • ✅ Provider records
  • ✅ PubSub messaging

Web Mode (Browser)

The IPFSWebNode class provides a browser-compatible implementation that uses IndexedDB for storage and WebSockets for networking.

Capabilities:

  • Storage: Persistent (IndexedDB)
  • Networking: Online (WebSocket connection to bootstrap peers)
  • Protocols: Bitswap (Exchange), PubSub (Gossipsub)
  • IPNS: Not yet supported
  • DHT: Not supported (Client mode only)

Constraints:

  • Requires a compliant WebSocket relay or gateway to join the swarm.
  • No TCP/UDP transport (browser limitation).

Architecture

┌─────────────────────────────────────┐
│         Application Layer            │
│   (Your Dart/Flutter Application)    │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│         dart_ipfs Public API         │
│  (IPFSNode, add, cat, pin, etc.)    │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│         Service Layer                │
│  Gateway │ RPC │ PubSub │ IPNS      │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│        Protocol Layer                │
│  Bitswap │ DHT │ MDNS │ Graphsync  │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│        Transport Layer               │
│    P2P Networking (p2plib-dart)     │
│    Crypto (secp256k1 + ChaCha20)    │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│         Storage Layer                │
│   UnixFS │ DAG-PB │ BlockStore       │
│   Datastore (Hive) │ Pinning         │
└─────────────────────────────────────┘

Comparison with go-ipfs

Feature dart_ipfs go-ipfs (Kubo)
Content Storage
UnixFS
CID v0/v1
Bitswap 1.2.0
Kademlia DHT
HTTP Gateway
RPC API
PubSub
IPNS
P2P Networking
Graphsync
Offline Mode
Language Dart Go
Mobile Support ✅ Flutter
Web Support ✅ Dart Web

Performance

  • Content Hashing: ~50 MB/s (SHA-256)
  • Block Storage: ~1000 ops/sec (Hive)
  • Gateway Latency: <10ms (local cache hit)
  • P2P Handshake: <100ms (secp256k1 ECDH)
  • Memory Usage: ~50MB baseline + content cache

Security Considerations & Guidelines

IMPORTANT: Use in Production requires strict sandboxing. See docker-compose.yml for a secure reference implementation.

To mitigate potential risks, we strictly recommend running dart_ipfs in a sandboxed environment:

  1. Immutable Filesystem: Run with a read-only root.
  2. Non-Root Execution: Use UID > 1000 (e.g., 10001).
  3. Network Isolation: Bind ports to localhost (127.0.0.1) only.
  4. Eclipse/Sybil Protection: RouterL2 enforces IP diversity limits (Max 5 peers/IP) to prevent routing table poisoning.

Production Cryptography

  • Key Exchange: secp256k1 (128-bit security)
  • Encryption: ChaCha20-Poly1305 AEAD
  • Hashing: SHA-256 (Bitcoin-grade)
  • Signatures: IPNS Ed25519 signatures

Content Verification

  • All content is verified via CID
  • Automatic integrity checks
  • Merkle tree validation

Network Security

  • Encrypted P2P connections
  • Peer authentication
  • DHT security hardening

Known Limitations

  1. p2plib Integration: Uses X-coordinate extraction from secp256k1 for 32-byte key compatibility
  2. LZ4 Compression: High-speed compression (via es_compression). Note: Automatically falls back to GZIP on platforms where native LZ4 binaries are unavailable (e.g., Apple Silicon).
  3. COSE Encoding: Stub implementation (catalyst_cose unavailable)

These limitations do not affect core functionality.


Testing

Run the protocol conformance tests:

dart test test/protocol_test.dart

Run all tests:

dart test

Static analysis:

dart analyze

Expected results:

  • ✅ 0 errors
  • ✅ 0 warnings
  • ✅ 510 tests pass (1 skipped)

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for new features
  4. Ensure dart analyze and dart test pass
  5. Submit a pull request

Roadmap

  • Done: Core IPFS protocols
  • Done: Offline mode
  • Done: HTTP Gateway
  • Done: P2P networking
  • Done: Production cryptography
  • Planned: Mobile optimization (Flutter)
  • Done: Web platform support
  • Planned: QUIC transport
  • Planned: Full Ed25519/X25519 support

License

MIT License - see LICENSE file for details


Credits

Built with:

Inspired by:


Support


Ready to build decentralized applications? Get started with dart_ipfs today! 🚀

Libraries

dart_ipfs
Production-ready IPFS (InterPlanetary File System) implementation in Dart.