From Latin dΔlΔtΕ β "erase, destroy."
Secure credential sharing with client-side AES-256 encryption, zero-knowledge architecture, and automatic self-destruction. Alternative to PasswordPusher, Yopass and Bitwarden Send
DELE.TO is a modern, secure platform for sharing sensitive information like passwords, API keys, and credentials. Built with Next.js 14 and featuring client-side encryption, your data is encrypted in your browser before it ever reaches server.
π https://dele.to β Try it instantly in your browser. No signup required.
- β¨ Features
- πΈ Screenshots
- π Quick Start
- ποΈ Architecture Overview
- π Encryption & Decryption Process
- π Data Flow Example
- π§ͺ Testing
- π οΈ Tech Stack
- π Project Structure
- π§° Development Tips
- π€ Contributing
- π Client-side AES-256-GCM encryption - Data encrypted in your browser
- π Zero-knowledge architecture - Server never sees your encryption keys
- β° Auto-expiration - Set custom expiration times (15m to 7 days)
- ποΈ View limits - Burn-after-reading with configurable view counts
- π Optional password protection - Add extra security layer
- π URL fragment keys - Encryption keys never sent to server
- πΎ Redis storage - Encrypted data with automatic TTL cleanup
- π± Responsive design - Works on all devices
- Node.js 20+ - Download here
- pnpm (recommended) - Install with
npm install -g pnpm - Git - For cloning the repository
Optional for Production:
- Redis - For production scaling (uses local file storage by default)
git clone https://github.com/dele-to/dele-to.git
cd dele-to# Using pnpm (recommended)
pnpm install
# Or using npm
npm install
# Or using yarn
yarn installFor Development: No configuration needed! The app works out of the box using local file storage.
For Production:
Create your environment file for Redis storage:
cp .env.example .envEdit .env with your configuration:
# Redis Configuration (Required for production)
KV_REST_API_URL=your_redis_url_here
KV_REST_API_TOKEN=your_redis_token_here
# Security Salt (Change this in production!)
SALT=your-super-secret-salt-change-me-in-production
π‘ Development Note: The app automatically uses local file storage (
./secure-shares/directory) when Redis is not configured, making it perfect for development and testing without any setup.
pnpm devThe app will be available at http://localhost:3000
- Open http://localhost:3000 in your browser
- Click "Share Securely" to create a test share
- Enter some test data and create a share
- Copy the generated link and test viewing it
docker build -t dele-to .
## This persists the shares data to your host machine (as Redis is not used)
docker run -p 3000:3000 -v "$(pwd)/.secure-shares:/app/.secure-shares" --name dele-to dele-todocker compose up --build -dThe application will be available at http://localhost:3000.
ποΈ Architecture Overview (Click to expand)
DELE.TO uses a zero-knowledge architecture where encryption happens entirely client-side:
π System Architecture Diagram (Click to expand)
graph TB
subgraph "Client Browser"
A[User Input] --> B[Generate AES-256 Key]
B --> C[Generate Random IV]
C --> D[Encrypt Data Client-Side]
D --> E[Base64 Encode]
E --> F[Send to Server]
subgraph "URL Fragment"
G[Encryption Key]
G -.->|Never sent to server| H[URL Hash #key]
end
B --> G
end
subgraph "Server (Zero-Knowledge)"
F --> I[Receive Encrypted Data]
I --> J[Store in Redis/File]
J --> K[Generate Share ID]
K --> L[Return Share URL]
subgraph "Storage"
M[(Redis/File System)]
N[Encrypted Content]
O[IV]
P[Metadata]
J --> M
M --> N
M --> O
M --> P
end
end
subgraph "Recipient Browser"
L --> Q[Access Share URL]
Q --> R[Extract Key from URL Fragment]
R --> S[Fetch Encrypted Data]
S --> T[Decrypt Client-Side]
T --> U[Display Plaintext]
subgraph "Auto-Destruction"
V[View Count Check]
W[TTL Expiration]
X[Delete from Storage]
S --> V
V --> W
W --> X
end
end
subgraph "Security Features"
Y[AES-256-GCM]
Z[Zero-Knowledge]
AA[URL Fragment Keys]
BB[Auto-Expiration]
CC[View Limits]
DD[Optional Password]
end
style A fill:#e1f5fe
style B fill:#f3e5f5
style D fill:#f3e5f5
style G fill:#ffebee
style I fill:#e8f5e8
style M fill:#fff3e0
style R fill:#f3e5f5
style T fill:#f3e5f5
style X fill:#ffebee
π Encryption & Decryption Process (Click to expand)
// AES-256 key
const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"])
// 96-bit IV (12 bytes)
const iv = crypto.getRandomValues(new Uint8Array(12))- Keys never leave the browser. Fresh IV per encryption. IV is not secret.
const encoder = new TextEncoder()
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, encoder.encode(plaintext))- AES-256-GCM provides confidentiality + authentication (integrity).
const encryptedContent = btoa(String.fromCharCode(...new Uint8Array(encrypted)))
const ivString = btoa(String.fromCharCode(...iv))- Base64 makes binary safe for JSON/HTTP.
// fragment contains the raw key material exported earlier (never sent to server)
const keyBytes = /* decode from fragment */
const importedKey = await crypto.subtle.importKey("raw", keyBytes, { name: "AES-GCM" }, true, ["decrypt"])
// iv and encryptedContent come from server response
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, importedKey, encryptedBytes)
const plaintext = new TextDecoder().decode(decrypted)encryptedContent: Base64 ciphertext, meaningless without the key.iv: Base64 12-byte IV. Required for decryption; safe to store alongside ciphertext.
Data Flow Example (Click to expand)
Let's trace what happens when you encrypt "my secret password":Input: "my secret password"
Step 1: Key Generation
π AES-256 Key: [32 random bytes]
Example: 4a7d1ed414474e4033ac29ccb8653d9b...
Step 2: IV Generation
π² IV (12 bytes): [random bytes]
Example: nb4WF+rLL5dokQnO (base64)
Step 3: Encryption
π Plaintext: "my secret password"
π AES-256-GCM Encryption
π¦ Ciphertext: [encrypted bytes]
Example: uJN+TP0nsj2oFPRQOS7+tJIwZko= (base64)
Step 4: What Gets Sent to Server
{
"encryptedContent": "uJN+TP0nsj2oFPRQOS7+tJIwZko=",
"iv": "nb4WF+rLL5dokQnO",
"title": "",
"expirationTime": "1h",
"maxViews": 1,
"requirePassword": false,
"linkType": "standard"
}Step 5: Share URL Creation
π URL: https://dele.to/view/abc123#[base64-encoded-key]
β
This key NEVER goes to server
# Run all tests
pnpm test
# Generate coverage report
pnpm test:coverage
# Test specific encryption functions
pnpm test -- --testPathPattern=crypto.test.tsπ For detailed test status and coverage reports, see TEST_STATUS.md
- β No setup required - works out of the box
- π Location:
./secure-shares/directory (auto-created) - π― Perfect for: Development, testing, and local demos
β οΈ Limitations: Not suitable for production scaling or multiple servers
- π§ Setup: Add Redis URL and token to
.envor Vercel environment variables - βοΈ Provider: Upstash (free tier available)
- π Benefits: Automatic TTL, better performance, horizontally scalable
π§° Development Tips (Click to expand)
- Hot Reload: Changes to code automatically refresh the browser
- TypeScript: Full TypeScript support with type checking
- Tailwind: Use Tailwind classes for styling
- Components: UI components are in
components/ui/ - Crypto: Encryption logic is in
lib/crypto.ts
β’ Module Not Found Errors
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
pnpm installβ’ Build Errors
# Clear Next.js cache
rm -rf .next
pnpm build- Framework: Next.js 14 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS
- UI Components: Radix UI + shadcn/ui
- Database: Redis (Upstash) with file system fallback
- Encryption: Web Crypto API (AES-256-GCM)
- Icons: Lucide React
- Fonts: Geist Sans & Geist Mono
π Project Structure (Click to expand)
secure-share-v2/
βββ __tests__/ # Jest tests
β βββ crypto.test.ts
β βββ share-simple.test.ts
βββ app/ # Next.js app directory
β βββ about/
β βββ actions/
β βββ alternatives/
β βββ create/
β βββ frame/
β βββ miniapp/
β βββ view/[id]/
β βββ vs/
β βββ globals.css
β βββ layout.tsx
β βββ not-found.tsx
β βββ page.tsx
βββ components/ # React components
β βββ ui/ # shadcn/ui components
β βββ access-tips.tsx
β βββ console-message.tsx
β βββ farcaster-debug.tsx
β βββ farcaster-provider.tsx
β βββ farcaster-ready.tsx
β βββ footer.tsx
β βββ inline-tip.tsx
β βββ password-input.tsx
β βββ security-tips.tsx
β βββ theme-provider.tsx
βββ hooks/
β βββ use-farcaster.ts
β βββ use-mobile.tsx
β βββ use-toast.ts
βββ lib/ # Utility libraries
β βββ crypto.ts # Encryption utilities
β βββ farcaster.ts
β βββ utils.ts
βββ public/ # Static assets
β βββ .well-known/
β β βββ farcaster.json
β βββ favicon.ico
β βββ favicon.png
β βββ SEO.png
βββ styles/
β βββ globals.css
βββ README.md
βββ package.json
βββ tailwind.config.ts
We welcome contributions! Here's how to get started:
- Fork the repository on GitHub
- Clone your fork locally
- Create a feature branch
git checkout -b feature/amazing-feature
- Make your changes and test thoroughly
- Commit with conventional commits
git commit -m "feat: add amazing feature" - Push to your fork
git push origin feature/amazing-feature
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Next.js - The React framework
- Tailwind CSS - Utility-first CSS
- Radix UI - Accessible components
- Lucide - Beautiful icons
- Upstash - Serverless Redis
- π§ Email: support@dele.to
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions


