A modern, secure peer-to-peer file sharing application built with Java (backend) and Next.js (frontend). Share files directly between users with PIN-based authentication and enterprise-grade security features.
- Features
- Architecture & Concepts
- Technology Stack
- Security Features
- Getting Started
- How It Works
- Project Structure
- API Documentation
- Contributing
- License
- π PIN-Based Authentication: Each upload generates a unique 6-digit PIN for secure access
- β‘ Real-Time P2P Transfer: Direct file transfer between peers without centralized storage
- π Multiple File Types: Support for documents, images, PDFs, and archives
- π‘οΈ Enterprise Security: Rate limiting, file validation, and timeout protection
- π¨ Modern UI: Clean, responsive interface built with React and Tailwind CSS
- π Fast & Lightweight: Minimal dependencies, optimized for performance
- π File Size Control: 100MB upload limit with streaming validation
- π Thread-Safe: Concurrent request handling with proper synchronization
PeerLink implements a hybrid P2P model:
- Central Coordinator: Backend server manages file metadata and authentication
- Direct Transfer: Actual file data flows directly between peers via TCP sockets
- Dynamic Ports: Each file sharing session uses a unique, randomly assigned port
βββββββββββ ββββββββββββββββ βββββββββββββ
β UploaderββββββββββΊβ Backend ββββββββββΊβDownloader β
β β Metadataβ (Java API) β Metadataβ β
ββββββ¬βββββ ββββββββββββββββ βββββββ¬ββββββ
β β
β Direct P2P Transfer β
βββββββββββββββββββββββββββββββββββββββββββββββ
(TCP Socket)
Defense in Depth Approach:
- Network Layer: Port validation (1024-65535), socket timeouts
- Application Layer: Rate limiting, content-type validation
- Authentication Layer: PIN-based access control
- Data Layer: File size limits, sanitization
- ConcurrentHashMap: Thread-safe storage for file metadata and tokens
- ExecutorService: Thread pool for handling multiple simultaneous requests
- Atomic Operations: Race-condition-free counter updates for rate limiting
Files are processed using streaming rather than loading entirely into memory:
- 8KB buffer for efficient data transfer
- Real-time size validation during upload
- Memory footprint independent of file size
Clean, stateless API endpoints following REST principles:
POST /api/upload- Upload file and receive PINGET /api/download?token={PIN}- Download file with PIN authentication
- Java 17: Modern Java features including records, text blocks, var
- HTTP Server: Built-in
com.sun.net.httpserverfor lightweight HTTP handling - Maven: Dependency management and build automation
- Apache Commons IO: Stream utilities for efficient file handling
- Next.js 14: React framework with server-side rendering
- TypeScript: Type-safe JavaScript for better developer experience
- Tailwind CSS: Utility-first CSS framework for rapid UI development
- Axios: HTTP client for API communication
- React Icons: Modern icon library
- 10 uploads per IP per minute
- Sliding window algorithm with automatic reset
- HTTP 429 (Too Many Requests) response for violations
Allowed Extensions: .txt, .pdf, .jpg, .jpeg, .png, .gif, .zip, .doc, .docx, .csv
Blocked: Executables (.exe, .sh, .bat), scripts (.js, .php, .py)
- Maximum file size: 100MB
- Three-layer validation:
- Content-Length header check
- Streaming size validation
- Post-parse content verification
- 6-digit PIN (100,000 - 999,999 combinations)
- Token required for every download attempt
- HTTP 403 (Forbidden) for invalid tokens
- 30-second socket timeout prevents hanging connections
- Automatic cleanup of temporary files (even on errors)
- Port range restriction (1024-65535) blocks system ports
ConcurrentHashMapfor shared stateAtomicIntegerfor lock-free counters- No race conditions in concurrent operations
- Java 17 or higher
- Node.js 18+ and npm
- Maven 3.9+
-
Clone the repository
git clone https://github.com/yourusername/peerlink.git cd peerlink -
Build the backend
mvn clean package
-
Install frontend dependencies
cd ui npm install
Terminal 1 (Backend):
java -cp target/p2p-1.0-SNAPSHOT.jar org.abhineshjha.AppTerminal 2 (Frontend):
cd ui
npm run devOpen http://localhost:3000 in your browser.
- User selects a file in the UI
- Frontend sends multipart form data to
/api/upload - Backend validates file type, size, and rate limit
- File is saved temporarily with UUID-based filename
- Backend generates:
- Random port (1024-65535)
- 6-digit access PIN
- Background thread starts TCP server on the assigned port
- Frontend displays PIN to user
- User enters 6-digit PIN
- Frontend sends request to
/api/download?token={PIN} - Backend validates PIN and looks up associated port
- Backend connects to uploader's TCP server on that port
- File is streamed through backend to downloader
- Temporary files are cleaned up automatically
// Upload: Generate PIN
String token = generateAccessToken(); // "654321"
accessTokens.put(port, token);
// Download: Validate PIN
Integer port = getPortByToken(token);
if (port == null) {
return 403; // Forbidden
}PeerLink/
βββ src/main/java/org/abhineshjha/
β βββ App.java # Application entry point
β βββ controller/
β β βββ FileController.java # HTTP server & routing
β βββ handler/
β β βββ CORSHandler.java # CORS & 404 handling
β β βββ UploadHandler.java # File upload logic
β β βββ DownloadHandler.java # File download logic
β βββ service/
β β βββ FileSharer.java # P2P server & token management
β βββ utils/
β βββ MultiParser.java # Multipart form parser
β βββ UploadUtils.java # Port generation utility
βββ ui/
β βββ src/
β β βββ app/
β β β βββ page.tsx # Main page component
β β β βββ globals.css # Global styles
β β βββ components/
β β βββ FileUpload.tsx # Upload UI component
β β βββ FileDownload.tsx # Download UI component
β β βββ InviteCode.tsx # PIN display component
β βββ package.json
βββ pom.xml # Maven configuration
βββ README.md
Upload a file and receive access credentials.
Request:
POST /api/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="document.pdf"
Content-Type: application/pdf
[binary data]
------WebKitFormBoundary--Response:
{
"port": 54321,
"token": "654321"
}Status Codes:
200 OK- Upload successful400 Bad Request- Invalid file type or missing data413 Payload Too Large- File exceeds 100MB415 Unsupported Media Type- File type not allowed429 Too Many Requests- Rate limit exceeded
Download a file using the access PIN.
Request:
GET /api/download?token=654321 HTTP/1.1Response:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="document.pdf"
[binary data]Status Codes:
200 OK- Download successful403 Forbidden- Invalid or missing token404 Not Found- File not found500 Internal Server Error- Download error
Advantages:
- β No server storage costs
- β Direct transfer = faster speeds
- β Files never stored permanently
- β Better privacy (no server retention)
Trade-offs:
- β Both peers must be online
- β Single-use transfers
// β NOT Thread-Safe
HashMap<Integer, String> map = new HashMap<>();
map.put(port, file); // Race condition!
// β
Thread-Safe
ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
map.put(port, file); // Atomic operation// β Memory-intensive (loads entire file)
byte[] fileData = Files.readAllBytes(path);
// β
Memory-efficient (8KB chunks)
byte[] buffer = new byte[8192];
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}Multiple security layers ensure that if one fails, others still protect:
User Request
β
[Rate Limiter] β Layer 1: Prevent spam
β
[File Validator] β Layer 2: Block malicious files
β
[Size Checker] β Layer 3: Prevent DoS
β
[PIN Validator] β Layer 4: Authentication
β
File Transfer
Abhinesh Jha
- GitHub: @Abhineshhh
- LinkedIn: Abhinesh Jha
β If you find this project useful, please consider giving it a star!