Skip to content

tonycletus/tendly

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

85 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

πŸ”’ Tendly - Privacy-First Instant File & Text Sharing

Instant, encrypted file & text sharing with zero-knowledge storage. Your data never leaves your device unencrypted.

Deploy with Vercel License: MIT

✨ Features

πŸ” End-to-End Encryption

  • AES-256-GCM encryption for all content before upload
  • Client-side encryption - data is encrypted in your browser
  • Zero-knowledge storage - we cannot read your content
  • PBKDF2 key derivation with 100,000 iterations for security
  • Share code as encryption key - only those with the code can decrypt

πŸš€ Instant Sharing

  • Drag & drop or paste files and text
  • No accounts required
  • Auto-expiring content (5 minutes) with animated expiration effects
  • QR code generation for easy sharing
  • Real-time link previews
  • Share result page for easy code copying and sharing
  • Optimized upload speeds with parallel processing

πŸ“± Mobile-First Design

  • Responsive glass-morphism UI with elegant animations
  • Touch-optimized interactions with haptic feedback
  • Steve Jobs-inspired design - no hiding elements, elegant display on all screen sizes
  • Dark/light mode toggle with sophisticated color schemes
  • Progressive Web App ready
  • Mobile-optimized headers with proper spacing and layout

πŸ›‘οΈ Privacy & Security

  • Client-side encryption using Web Crypto API
  • No server-side decryption - we never see your data
  • Automatic content expiration (5 minutes)
  • View count tracking
  • Secure random key generation
  • Privacy-first rate limiting using hashed IPs
  • Enhanced security indicators with visual encryption badges (see below)

πŸ—οΈ Architecture

Encryption Flow

  1. Content Creation: User uploads file/text
  2. Share Code Generation: Random 8-character identifier (e.g., "ABC123XY") - excludes 0 and O
  3. Key Derivation: Browser derives encryption key from share code using PBKDF2
  4. Encryption: AES-256-GCM encryption with random IV
  5. Storage: Encrypted data and share code stored in Supabase
  6. Sharing: Share code points to encrypted data (server cannot decrypt)
  7. Decryption: Client derives same key and decrypts content

Key Security Point: The server stores share codes but never sees the derived encryption keys. Anyone with the share code can access encrypted data, but only the client can decrypt it.

Security Features

  • AES-256-GCM: Authenticated encryption with Galois/Counter Mode
  • PBKDF2: Password-based key derivation with 100,000 iterations
  • Random IV: Unique initialization vector for each encryption
  • Authentication Tag: Prevents tampering and ensures integrity
  • Secure Random: Cryptographically secure random number generation
  • Hashed IP Rate Limiting: Privacy-first rate limiting without tracking
  • Enhanced Share Codes: Excludes visually similar characters (0, O)

πŸš€ Quick Start

Prerequisites

  • Node.js 18+
  • Supabase account
  • Modern browser with Web Crypto API support

Installation

  1. Clone the repository
git clone https://github.com/tonycletus/tendly.git
cd tendly
  1. Install dependencies
npm install
  1. Set up Supabase

    • Create a new Supabase project
    • Run the migration: supabase/migrations/20250625163805-3fea2b05-9a56-46e5-bce7-7d1eab2afd9a.sql
    • Run the privacy-first security migration: supabase/migrations/20250127000001-true-security.sql
    • Create a storage bucket named shared-files
    • Set up Row Level Security (RLS) policies
  2. Configure environment variables

cp .env.example .env.local

Add your Supabase credentials:

VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
  1. Start development server
npm run dev

πŸ”§ Configuration

Supabase Setup

  1. Database Schema
-- Enable RLS
ALTER TABLE drops ENABLE ROW LEVEL SECURITY;
ALTER TABLE drop_items ENABLE ROW LEVEL SECURITY;

-- Create policies
CREATE POLICY "Allow public read access to drops" ON drops
  FOR SELECT USING (true);

CREATE POLICY "Allow public insert access to drops" ON drops
  FOR INSERT WITH CHECK (true);

CREATE POLICY "Allow public read access to drop_items" ON drop_items
  FOR SELECT USING (true);

CREATE POLICY "Allow public insert access to drop_items" ON drop_items
  FOR INSERT WITH CHECK (true);
  1. Storage Bucket
-- Create storage bucket
INSERT INTO storage.buckets (id, name, public) 
VALUES ('shared-files', 'shared-files', false);

-- Storage policies
CREATE POLICY "Allow public uploads" ON storage.objects
  FOR INSERT WITH CHECK (bucket_id = 'shared-files');

CREATE POLICY "Allow public downloads" ON storage.objects
  FOR SELECT USING (bucket_id = 'shared-files');

Environment Variables

Variable Description Required
VITE_SUPABASE_URL Supabase project URL Yes
VITE_SUPABASE_ANON_KEY Supabase anonymous key Yes

πŸ›‘οΈ Security Features

Encryption Implementation

// Example encryption flow
import { encryptWithPassword, decryptWithPassword } from '@/utils/browserEncryption';

// Encrypt content
const encryptedData = await encryptWithPassword(content, shareCode);

// Decrypt content  
const decryptedContent = await decryptWithPassword(encryptedData, shareCode);

Security Model

For a comprehensive understanding of our security architecture, see our Security Documentation. Key points:

  • Two-Layer Security: Share codes (public) + Encryption keys (client-side derived)
  • Zero-Knowledge: Server stores encrypted data but cannot decrypt it
  • Client-Side Only: All encryption/decryption happens in your browser
  • Privacy-First: No tracking, no analytics, no personal data collection
  • Enhanced Share Codes: Excludes confusing characters for better user experience

Privacy-First Rate Limiting (Hashed IPs)

Tendly implements privacy-first rate limiting by hashing user IP addresses before storing or using them for rate limiting. This ensures:

  • No real IP addresses are ever stored in the database
  • Rate limiting is enforced without tracking or identifying users
  • Hashing uses a salt and SHA-256 for strong privacy

How it works:

  • When a user performs an action (e.g., create drop), their IP is hashed using a server-side function:
    CREATE OR REPLACE FUNCTION hash_ip(p_ip_address INET) RETURNS TEXT AS $$
    BEGIN
        RETURN encode(digest(p_ip_address::TEXT || 'tendly_salt_2025', 'sha256'), 'hex');
    END;
    $$ LANGUAGE plpgsql SECURITY DEFINER;
  • The hashed IP is used for rate limiting and abuse prevention, but cannot be reversed to the original IP.
  • No user agent or fingerprinting is stored, maintaining privacy.

Security Migration

  • The privacy-first security migration (supabase/migrations/20250127000001-true-security.sql) sets up:
    • Hashed IP rate limiting tables and functions
    • Secure session management (no tracking)
    • Content validation and sanitization
    • Secure RPC functions for all drop/item operations
    • Enhanced RLS policies

To apply:

supabase db remote set-branch main
supabase db push

Or run the SQL file directly in the Supabase SQL editor.

Automatic Cleanup of Expired Content

Tendly automatically deletes expired drops, items, and rate limit records to keep your data private and storage clean.

How it works:

  • Expired content is deleted by a scheduled cleanup job (see below)
  • Files in storage are also cleaned up if their drop has expired
  • No user data is retained after expiration

GitHub Actions: Scheduled Cleanup

A GitHub Actions workflow is provided to run the cleanup every 24 hours:

  • File: .github/workflows/cleanup.yml
  • Schedule: Every 24 hours at midnight UTC
  • What it does:
    • Runs a Node.js script to call the Supabase cleanup function and remove expired files

How to set up:

  1. Make sure your Supabase service role key and project ID are set as GitHub secrets:
    • SUPABASE_PROJECT_ID
    • SUPABASE_SERVICE_ROLE_KEY
  2. The workflow will run automatically every 24 hours, or you can trigger it manually from the GitHub Actions tab.

You can adjust the schedule by editing the cron value in .github/workflows/cleanup.yml.

🎨 UI/UX Features

Animated Expiration Effect

  • Visual feedback when content expires
  • Files and text flow into an animated trash can
  • Explosion animation with looping effect
  • Smooth transitions between animation phases

Enhanced Mobile Experience

  • Steve Jobs-inspired design - no hiding elements, elegant display
  • Proper spacing and typography on all screen sizes
  • Touch-optimized interactions with haptic feedback
  • Floating action buttons for mobile convenience
  • Responsive headers with consistent branding

Improved Error Handling

  • Contextual error messages with helpful suggestions
  • Security indicators for privacy reassurance
  • Compact design that matches app aesthetics
  • Proper alignment and visual hierarchy

Performance Optimizations

  • Parallel processing for faster uploads and decryption
  • Optimized animation timings for snappier interactions
  • Efficient content loading with improved caching
  • Mobile performance optimizations

πŸ“± Browser Support

Tendly requires modern browsers with Web Crypto API support:

  • βœ… Chrome 37+
  • βœ… Firefox 34+
  • βœ… Safari 11+
  • βœ… Edge 12+
  • ❌ Internet Explorer (not supported)

πŸš€ Deployment

Vercel (Recommended)

  1. Connect your GitHub repository to Vercel
  2. Add environment variables in Vercel dashboard
  3. Deploy automatically on push to main branch

Manual Deployment

npm run build
npm run preview

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit changes: git commit -m 'Add amazing feature'
  4. Push to branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Guidelines

  • Please ensure your code adheres to the existing style (run npm run lint and npm run format before submitting).
  • Add or update tests as appropriate for your changes.
  • Document any new features or changes in the README.
  • For bug reports or feature requests, open an issue first to discuss what you would like to change.
  • Be respectful and follow the project's Code of Conduct.

Local Development

  • Clone the repo and install dependencies as described above.
  • Run npm run dev to start the development server.
  • Run npm run test to execute tests (if available).

Pull Request Process

  • Ensure your branch is up to date with main before submitting a PR.
  • Provide a clear description of your changes and reference any related issues.
  • One feature/fix per PR is preferred.

Thank you for contributing to Tendly!

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ”’ Privacy Policy

  • No data collection: We don't collect personal information
  • Zero-knowledge: We cannot access your encrypted content
  • Automatic deletion: Content expires after 5 minutes
  • Client-side processing: All encryption happens in your browser
  • No tracking: No analytics or tracking scripts
  • Hashed IPs: All rate limiting and abuse prevention uses hashed IPs only

πŸ“š Documentation

πŸ†˜ Support

πŸ™ Acknowledgments


Made with ❀️ and πŸ”’ for privacy-first file & text sharing

About

A privacy-first file sharing platform built for easy, secure, and temporary file transfers

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors