Files
TransferTribe/src/app/page.tsx
T
twotalesanimation 0b56ec31ed Address remaining audit findings
Multiple files per transfer
- The UI accepted several files but only files[0] was ever uploaded, so
  recipients saw a list and received one file. Chunks now carry a
  fileIndex, the upload session tracks each file separately, and finalize
  assembles one encrypted payload and one File row per file.
- The download page lists real files with per-file download buttons; the
  previously unused isFileDownloading/isFileDownloaded helpers now drive
  that state. /api/file/[id] accepts a fileId, scoped to the transfer so
  an id from another transfer cannot be fetched.

Large downloads
- Replace res.blob() with a helper that streams the response body to disk
  via the File System Access API where available, keeping peak memory at
  roughly one chunk instead of the whole file. Falls back to the blob
  path elsewhere.

Password brute force
- Rate limit /api/verify and /api/file/[id] to 10 attempts per transfer,
  per client, per 15 minutes; a correct password clears the counter.
  Per-process state, matching the existing local-disk storage model.

Disk reclamation
- Nothing ever deleted payloads, so every transfer stayed on disk
  regardless of expiresAt. Add a cleanup routine that marks lapsed
  transfers EXPIRED, deletes payloads for expired and soft-deleted
  transfers, and sweeps abandoned chunk directories. It refuses to unlink
  anything outside UPLOAD_DIR. Exposed as POST /api/cron/cleanup behind
  CRON_SECRET, failing closed when that is unset.

Build hygiene
- Stop ignoring ESLint during builds and fix all 70 resulting violations:
  unused imports and state, unescaped JSX entities, explicit any, and a
  missing useEffect dependency. Seven catch blocks discarded their error
  silently and now log it.
- Delete dead code: two unused send components, the two legacy upload
  endpoints they called, the unused whole-file WebCrypto helpers, and a
  duplicate separator component differing only by a typo.

Add .env.example documenting configuration, including CRON_SECRET.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 09:32:37 +02:00

273 lines
13 KiB
TypeScript

'use client';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
import { Header } from '@/components/header';
import { HeroSection } from '@/components/hero-section';
import { Stats } from '@/components/stats';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import {
ArrowRight,
Shield,
Zap,
Mail,
Star
} from 'lucide-react';
import Link from 'next/link';
export default function Home() {
const { data: session, status } = useSession();
const router = useRouter();
useEffect(() => {
// Redirect logged-in users to dashboard
if (session) {
router.push('/send');
}
}, [session, router]);
if (status === 'loading') {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:from-slate-900 dark:via-slate-800 dark:to-slate-900 flex items-center justify-center">
<div className="text-center">
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full flex items-center justify-center mx-auto mb-4 animate-pulse">
<Mail className="w-8 h-8 text-white" />
</div>
<p className="text-slate-600 dark:text-slate-400">Loading...</p>
</div>
</div>
);
}
if (session) {
return null; // Will redirect to dashboard
}
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:from-slate-900 dark:via-slate-800 dark:to-slate-900">
<Header />
<main className="container mx-auto px-4 py-8">
<HeroSection />
<div className="max-w-6xl mx-auto space-y-16">
<Stats />
{/* Features Section */}
<section id="features" className="space-y-12">
<div className="text-center">
<h2 className="text-3xl md:text-4xl font-bold text-slate-900 dark:text-slate-100 mb-4">
Why Choose Transfer Tribe?
</h2>
<p className="text-xl text-slate-600 dark:text-slate-400 max-w-2xl mx-auto">
Built for security, designed for simplicity. Share files with confidence.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<Card className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-white/20 dark:border-slate-700/20 hover:bg-white/90 dark:hover:bg-slate-800/90 transition-all">
<CardContent className="p-8 text-center">
<div className="w-16 h-16 bg-gradient-to-br from-green-400 to-emerald-600 rounded-full flex items-center justify-center mx-auto mb-6">
<Shield className="w-8 h-8 text-white" />
</div>
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-4">
Enterprise Security
</h3>
<p className="text-slate-600 dark:text-slate-400 leading-relaxed">
Bank-level encryption, password protection, and automatic expiration ensure your files stay secure.
</p>
</CardContent>
</Card>
<Card className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-white/20 dark:border-slate-700/20 hover:bg-white/90 dark:hover:bg-slate-800/90 transition-all">
<CardContent className="p-8 text-center">
<div className="w-16 h-16 bg-gradient-to-br from-blue-400 to-blue-600 rounded-full flex items-center justify-center mx-auto mb-6">
<Zap className="w-8 h-8 text-white" />
</div>
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-4">
Lightning Fast
</h3>
<p className="text-slate-600 dark:text-slate-400 leading-relaxed">
Powered by Google Cloud Storage for maximum speed and reliability. Upload and share in seconds.
</p>
</CardContent>
</Card>
<Card className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-white/20 dark:border-slate-700/20 hover:bg-white/90 dark:hover:bg-slate-800/90 transition-all">
<CardContent className="p-8 text-center">
<div className="w-16 h-16 bg-gradient-to-br from-purple-400 to-purple-600 rounded-full flex items-center justify-center mx-auto mb-6">
<Mail className="w-8 h-8 text-white" />
</div>
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-4">
Email Integration
</h3>
<p className="text-slate-600 dark:text-slate-400 leading-relaxed">
Recipients get secure download links directly in their inbox. No accounts required to download.
</p>
</CardContent>
</Card>
</div>
</section>
{/* How It Works */}
<section className="space-y-12">
<div className="text-center">
<h2 className="text-3xl md:text-4xl font-bold text-slate-900 dark:text-slate-100 mb-4">
How It Works
</h2>
<p className="text-xl text-slate-600 dark:text-slate-400 max-w-2xl mx-auto">
Share files in three simple steps
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="text-center space-y-4">
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full flex items-center justify-center mx-auto text-white font-bold text-xl">
1
</div>
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100">
Upload Files
</h3>
<p className="text-slate-600 dark:text-slate-400">
Drag and drop your files or click to select. Files up to 2GB are supported on the free plan.
</p>
</div>
<div className="text-center space-y-4">
<div className="w-16 h-16 bg-gradient-to-br from-green-500 to-emerald-600 rounded-full flex items-center justify-center mx-auto text-white font-bold text-xl">
2
</div>
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100">
Add Recipients
</h3>
<p className="text-slate-600 dark:text-slate-400">
Enter recipient email addresses and add an optional personal message.
</p>
</div>
<div className="text-center space-y-4">
<div className="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-600 rounded-full flex items-center justify-center mx-auto text-white font-bold text-xl">
3
</div>
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100">
Send Securely
</h3>
<p className="text-slate-600 dark:text-slate-400">
Recipients receive an email with a secure download link and password.
</p>
</div>
</div>
</section>
{/* Testimonials */}
<section className="space-y-12">
<div className="text-center">
<h2 className="text-3xl md:text-4xl font-bold text-slate-900 dark:text-slate-100 mb-4">
Trusted by Thousands
</h2>
<p className="text-xl text-slate-600 dark:text-slate-400 max-w-2xl mx-auto">
See what our users are saying about Transfer Tribe
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<Card className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-white/20 dark:border-slate-700/20">
<CardContent className="p-6">
<div className="flex items-center space-x-1 mb-4">
{[...Array(5)].map((_, i) => (
<Star key={i} className="w-4 h-4 fill-yellow-400 text-yellow-400" />
))}
</div>
<p className="text-slate-600 dark:text-slate-400 mb-4">
&ldquo;Transfer Tribe has revolutionized how we share large design files with clients. The security features give us peace of mind.&rdquo;
</p>
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full flex items-center justify-center text-white font-semibold">
S
</div>
<div>
<p className="font-semibold text-slate-900 dark:text-slate-100">Sarah Chen</p>
<p className="text-sm text-slate-500 dark:text-slate-400">Creative Director</p>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-white/20 dark:border-slate-700/20">
<CardContent className="p-6">
<div className="flex items-center space-x-1 mb-4">
{[...Array(5)].map((_, i) => (
<Star key={i} className="w-4 h-4 fill-yellow-400 text-yellow-400" />
))}
</div>
<p className="text-slate-600 dark:text-slate-400 mb-4">
&ldquo;Simple, fast, and secure. Exactly what we needed for sharing confidential documents with our legal team.&rdquo;
</p>
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-br from-green-500 to-emerald-600 rounded-full flex items-center justify-center text-white font-semibold">
M
</div>
<div>
<p className="font-semibold text-slate-900 dark:text-slate-100">Michael Rodriguez</p>
<p className="text-sm text-slate-500 dark:text-slate-400">Business Owner</p>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-white/20 dark:border-slate-700/20">
<CardContent className="p-6">
<div className="flex items-center space-x-1 mb-4">
{[...Array(5)].map((_, i) => (
<Star key={i} className="w-4 h-4 fill-yellow-400 text-yellow-400" />
))}
</div>
<p className="text-slate-600 dark:text-slate-400 mb-4">
&ldquo;The email integration is brilliant. Our clients love how easy it is to receive and download files.&rdquo;
</p>
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-br from-purple-500 to-pink-600 rounded-full flex items-center justify-center text-white font-semibold">
A
</div>
<div>
<p className="font-semibold text-slate-900 dark:text-slate-100">Alex Thompson</p>
<p className="text-sm text-slate-500 dark:text-slate-400">Freelancer</p>
</div>
</div>
</CardContent>
</Card>
</div>
</section>
{/* CTA Section */}
<section className="text-center space-y-8">
<div className="bg-gradient-to-r from-blue-500 to-indigo-600 rounded-2xl p-12 text-white">
<h2 className="text-3xl md:text-4xl font-bold mb-4">
Ready to Start Sharing?
</h2>
<p className="text-xl text-blue-100 mb-8 max-w-2xl mx-auto">
Join thousands of users who trust Transfer Tribe for secure file sharing.
Get started with our free plan today.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link href="/auth/signup">
<Button size="lg" className="bg-white text-blue-600 hover:bg-blue-50 px-8 py-3 rounded-full shadow-lg hover:shadow-xl transition-all">
Get Started Free
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
</Link>
<Link href="/pricing">
<Button variant="outline" size="lg" className="border-white text-white hover:bg-white/10 px-8 py-3 rounded-full">
View Pricing
</Button>
</Link>
</div>
</div>
</section>
</div>
</main>
</div>
);
}