Skip to content

maximopalopoli/p2pal

Repository files navigation

p2pal

Direct, ephemeral file transfers between peers. No server storage.

p2pal is a CLI tool for sending files directly between machines using WebRTC. The server only coordinates the connection — it never sees, stores, or proxies file contents.


How it works

sender                   server (signaling only)                 receiver
  |                              |                                   |
  |-- POST /api/transfer ------> |                                   |
  |<-- join code --------------- |                                   |
  |                              |<-- POST /api/join (join code) --- |
  |-- WebSocket (offer/ICE) ---> | --- relay --> WebSocket --------> |
  |<- WebSocket (answer/ICE) --- | <-- relay <-- WebSocket --------- |
  |                                                                   |
  |<================ WebRTC DataChannel (direct P2P) ===============>|
  |                    file bytes never touch server                  |

When a direct connection is not possible (restrictive NAT/firewall), traffic is relayed via TURN — still end-to-end, without server-side storage.


Features

  • Peer-to-peer transfers via WebRTC DataChannels
  • Multi-file and directory (-r) transfers in a single session
  • Pause/resume: checkpoint-based recovery after interruption
  • Automatic reconnect after live network drops (signaling + WebRTC renegotiation)
  • SHA-256 integrity verification on every transfer
  • Binary protocol over DataChannel (no JSON+base64 overhead)
  • Short-lived join codes and tokens, auto-expiring via TTL
  • STUN + TURN support for NAT traversal
  • Per-file error handling with optional skip-continue (-skip-errors)
  • Quiet mode (-q) for scripting
  • Progress bar with per-file and transfer-level stats
  • Configurable chunk size (--chunk-size)

Prerequisites

  • Go 1.25+
  • Docker (for Redis and integration tests)
  • TURN server credentials (optional — required for non-P2P fallback)

Getting started

1. Start the server and Redis

make up

This starts both Redis and the backend server via Docker Compose.

2. Build the CLI

make build
# Produces: bin/server  bin/p2pal

3. Send a file

./bin/p2pal send report.pdf

Output:

Sending file: report.pdf (1 file, 2.3 MB) — TTL: 5m
Creating transfer...
  Join code: zebra-luna-47

Waiting for receiver...

4. Receive a file

./bin/p2pal recv zebra-luna-47

Output:

Joining transfer...
Receiving: report.pdf (2.3 MB)
[====================] 100% — SHA-256 verified

CLI reference

Send

./bin/p2pal send [flags] <file> [file2 ...]
./bin/p2pal send -r [flags] <directory>
./bin/p2pal send --resume <transfer-id>
Flag Default Description
-server http://localhost:8080 Backend server URL
-ttl 5m Transfer expiry (e.g. 10m, 1h)
-r false Recursively send a directory
-y false Skip confirmation prompt
-q false Quiet mode: only print join code and errors
-skip-errors false Skip files with errors instead of aborting the batch
-chunk-size 63 Chunk size in KiB (max: 63)
-resume Resume an interrupted transfer by checkpoint ID
-checkpoint-ttl 168h TTL for checkpoint files
-max-retries 3 Connection retry attempts
-retry-backoff 1s Initial retry backoff
-stun stun:stun.l.google.com:19302 STUN server URL
-turn TURN server URL (repeatable)
-turn-user $TURN_USER TURN username
-turn-pass $TURN_PASS TURN password

Receive

./bin/p2pal recv [flags] <join-code>
Flag Default Description
-server http://localhost:8080 Backend server URL
-out current dir Output path or directory
-overwrite false Overwrite existing files
-y false Skip confirmation prompts
-q false Quiet mode: only print errors
-checkpoint-ttl 168h TTL for checkpoint files
-max-retries 3 Connection retry attempts
-retry-backoff 1s Initial retry backoff
-stun stun:stun.l.google.com:19302 STUN server URL
-turn TURN server URL (repeatable)
-turn-user $TURN_USER TURN username
-turn-pass $TURN_PASS TURN password

Checkpoint management

./bin/p2pal checkpoint list        # List resumable transfers
./bin/p2pal checkpoint delete <id> # Delete a specific checkpoint
./bin/p2pal checkpoint clean       # Remove expired checkpoints
./bin/p2pal checkpoint clean-all   # Remove all checkpoints

Checkpoints are stored in ~/.p2pal/checkpoints/ with a default TTL of 7 days.


Resuming an interrupted transfer

If the network drops during a transfer, p2pal automatically reconnects, renegotiates the WebRTC session, and resumes from the last checkpoint.

If a transfer is manually interrupted (Ctrl+C), a checkpoint is saved. Resume it with:

# Check available checkpoints
./bin/p2pal checkpoint list

# Resume from the sender side
./bin/p2pal send --resume <transfer-id>

Running tests

make test                    # Unit tests (with -race)
make test_coverage           # Unit tests + coverage report
make lint                    # go vet

make test_integration        # End-to-end round-trip test (rebuilds Docker images)
make test_integration_quick  # End-to-end round-trip test (skip build)
make test_resume             # Resume-basic integration test (rebuilds Docker images)
make test_resume_quick       # Resume-basic integration test (skip build)
make test_reconnect          # Live network disconnect + auto-reconnect test (rebuilds Docker images)
make test_reconnect_quick    # Live network disconnect + auto-reconnect test (skip build)

Architecture

Components

Component Role
cmd/p2pal CLI — send, recv, checkpoint commands
cmd/server HTTP API + WebSocket signaling server
internal/rtc WebRTC session: ICE, DataChannel, chunked transfer, checkpoints
internal/client HTTP + WebSocket client library
pkg/protocol Shared message types and transfer states
Redis Ephemeral session state, tokens, TTL enforcement

Transfer state machine

pending → ready → active → completed
                         ↘ aborted

Data flow

  • Control plane (server): session creation, join codes, WebRTC signaling relay, TTL
  • Data plane (clients): 64 KiB indexed chunks over WebRTC DataChannel, SHA-256 verification

Security model

  • File bytes never reach the server
  • Join codes and tokens are scoped to a single transfer and expire automatically
  • No user accounts or persistent identity
  • TURN relay is used only when direct P2P fails; server never has plaintext file access

Planned

  • Wildcard file patterns (p2pal send *.pdf)
  • Compression support (zstd)
  • Bandwidth throttling
  • Client config file (~/.p2pal/config.toml)
  • End-to-end encryption (AES-256-GCM on top of DTLS)
  • Shell completion scripts (bash/zsh/fish)

About

CLI tool for direct, ephemeral P2P file transfers over WebRTC. The server only brokers the connection — it never sees your data.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors