Skip to content

Commit 8899fbc

Browse files
author
teycir
committed
feat: Increase file size limit to 5MB
- Update validation from 750KB to 5MB - Update UI messages and tooltips - Update request size limit to 7MB
1 parent cb77d19 commit 8899fbc

7 files changed

Lines changed: 177 additions & 61 deletions

File tree

app/admin/canary/page.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
'use client';
22

33
import { useState } from 'react';
4-
import { Card } from '@/components/ui/card';
5-
import { Button } from '@/components/ui/button';
64
import { Shield, Calendar, AlertTriangle } from 'lucide-react';
75
import { toast } from 'sonner';
86

@@ -40,7 +38,7 @@ export default function AdminCanaryPage() {
4038
<h1 className="text-3xl font-bold text-neon-green">WARRANT CANARY</h1>
4139
</div>
4240

43-
<Card className="p-6 mb-6">
41+
<div className="cyber-card p-6 mb-6">
4442
<h2 className="text-xl font-bold text-neon-green mb-4">Monthly Update</h2>
4543

4644
<div className="space-y-4 mb-6">
@@ -76,16 +74,20 @@ export default function AdminCanaryPage() {
7674
</div>
7775
</div>
7876

79-
<Button onClick={updateCanary} disabled={updating} className="w-full">
77+
<button
78+
onClick={updateCanary}
79+
disabled={updating}
80+
className="cyber-button w-full"
81+
>
8082
{updating ? 'UPDATING...' : 'UPDATE CANARY'}
81-
</Button>
82-
</Card>
83+
</button>
84+
</div>
8385

84-
<Card className="p-6">
85-
<a href="/canary.txt" target="_blank" className="text-neon-green hover:underline">
86+
<div className="cyber-card p-6">
87+
<a href="/canary" target="_blank" className="text-neon-green hover:underline">
8688
View Current Canary →
8789
</a>
88-
</Card>
90+
</div>
8991
</div>
9092
</div>
9193
);

app/api/seal/[id]/route.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export async function GET(
5858
isLocked: true,
5959
unlockTime: metadata.unlockTime,
6060
timeRemaining: metadata.unlockTime - Date.now(),
61+
isDMS: metadata.isDMS,
62+
pulseToken: metadata.isDMS ? (await container.db.getSeal(sealId))?.pulseToken : undefined,
6163
});
6264
}
6365

@@ -72,6 +74,7 @@ export async function GET(
7274
keyB: metadata.keyB,
7375
iv: metadata.iv,
7476
encryptedBlob: blobBase64,
77+
isDMS: metadata.isDMS,
7578
});
7679
} finally {
7780
concurrentTracker.release(ip);

app/page.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,13 @@ export default function HomePage() {
143143
const onDrop = useCallback((acceptedFiles: File[]) => {
144144
if (acceptedFiles?.length > 0) {
145145
const selectedFile = acceptedFiles[0];
146-
const maxSize = 750 * 1024;
146+
const maxSize = 5 * 1024 * 1024; // 5MB
147147
if (selectedFile.size > maxSize) {
148-
toast.error(`File too large: ${formatFileSize(selectedFile.size)} (max 750KB)`);
148+
toast.error(`File too large: ${formatFileSize(selectedFile.size)} (max 5MB)`);
149149
return;
150150
}
151151
if (selectedFile.size > maxSize * 0.9) {
152-
toast.warning(`File size: ${formatFileSize(selectedFile.size)} (approaching 750KB limit)`);
152+
toast.warning(`File size: ${formatFileSize(selectedFile.size)} (approaching 5MB limit)`);
153153
}
154154
setFile(selectedFile);
155155
setMessage('');
@@ -260,9 +260,9 @@ export default function HomePage() {
260260
return;
261261
}
262262

263-
// Validate message length (D1 limit: 750KB)
264-
if (message.trim() && message.length > 750000) {
265-
toast.error('Message too large (max 750KB)');
263+
// Validate message length (D1 limit: 5MB)
264+
if (message.trim() && message.length > 5000000) {
265+
toast.error('Message too large (max 5MB)');
266266
const textarea = document.getElementById('message-input');
267267
if (textarea) {
268268
textarea.classList.add('input-error');
@@ -271,9 +271,9 @@ export default function HomePage() {
271271
return;
272272
}
273273

274-
// Validate file size (D1 limit: 750KB)
275-
if (file && file.size > 750 * 1024) {
276-
toast.error('File too large (max 750KB)');
274+
// Validate file size (D1 limit: 5MB)
275+
if (file && file.size > 5 * 1024 * 1024) {
276+
toast.error('File too large (max 5MB)');
277277
return;
278278
}
279279

@@ -635,7 +635,7 @@ export default function HomePage() {
635635
{/* Text Area */}
636636
<label htmlFor="message-input" className="block text-sm mb-2 text-neon-green/80 tooltip">
637637
MESSAGE OR FILE
638-
<span className="tooltip-text">Enter text message or upload a file (max 750KB). Only one can be used at a time.</span>
638+
<span className="tooltip-text">Enter text message or upload a file (max 5MB). Only one can be used at a time.</span>
639639
</label>
640640
<textarea
641641
id="message-input"
@@ -685,7 +685,7 @@ export default function HomePage() {
685685
<p className="text-xs text-neon-green/40">OR CLICK TO SELECT</p>
686686
<div className="flex items-center justify-center gap-1 mt-2">
687687
<AlertTriangle className="w-3 h-3 text-neon-green/30" />
688-
<p className="text-xs text-neon-green/30">Max size: 750KB</p>
688+
<p className="text-xs text-neon-green/30">Max size: 5MB</p>
689689
</div>
690690
</>
691691
)}

app/pulse/[token]/page.tsx

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -208,18 +208,18 @@ function PulsePageClient() {
208208
}
209209

210210
return (
211-
<div className="min-h-screen flex items-center justify-center p-4 relative w-full overflow-hidden">
211+
<div className="min-h-screen flex items-center justify-center p-4 relative w-full overflow-x-hidden pb-20">
212212
<BackgroundBeams className="absolute top-0 left-0 w-full h-full z-0" />
213213
<div className="max-w-md w-full relative z-10 text-center">
214-
<Heart className={`w-16 h-16 mx-auto mb-4 ${isUrgent ? 'text-red-500 animate-pulse' : 'text-neon-green'}`} />
215-
<h1 className="text-2xl sm:text-3xl font-bold glow-text mb-6 px-2">
214+
<Heart className={`w-12 h-12 mx-auto mb-3 ${isUrgent ? 'text-red-500 animate-pulse' : 'text-neon-green'}`} />
215+
<h1 className="text-2xl sm:text-3xl font-bold glow-text mb-4 px-2">
216216
<DecryptedText text="DEAD MAN'S SWITCH" animateOn="view" className="text-neon-green" />
217217
</h1>
218218

219219
{timeRemaining > 0 && (
220-
<Card className={`mb-8 ${isUrgent ? 'border-red-500/50 shadow-[0_0_20px_rgba(255,0,0,0.2)]' : ''}`}>
220+
<Card className={`mb-6 p-4 ${isUrgent ? 'border-red-500/50 shadow-[0_0_20px_rgba(255,0,0,0.2)]' : ''}`}>
221221
<p className="text-xs text-neon-green/50 mb-2 uppercase tracking-widest">TIME UNTIL AUTO-UNLOCK</p>
222-
<div className={`text-3xl sm:text-4xl md:text-5xl font-mono mb-2 ${isUrgent ? 'text-red-500 pulse-glow' : 'text-neon-green pulse-glow'}`}>
222+
<div className={`text-3xl sm:text-4xl font-mono mb-2 ${isUrgent ? 'text-red-500 pulse-glow' : 'text-neon-green pulse-glow'}`}>
223223
{formatTimeShort(timeRemaining)}
224224
</div>
225225
{isUrgent && (
@@ -231,27 +231,29 @@ function PulsePageClient() {
231231
</Card>
232232
)}
233233

234-
<p className="text-neon-green/70 mb-8 text-sm">
234+
<p className="text-neon-green/70 mb-6 text-sm px-4">
235235
Click below to confirm you are active and reset the countdown timer.
236236
</p>
237237

238-
<Button
239-
onClick={handlePulse}
240-
disabled={isPulsing}
241-
className="w-full text-xl py-6 mb-4 shadow-[0_0_20px_rgba(0,255,65,0.3)] hover:shadow-[0_0_40px_rgba(0,255,65,0.5)] flex items-center justify-center gap-2"
242-
>
243-
<Heart className="w-5 h-5" />
244-
{isPulsing ? 'PULSING...' : 'SEND PULSE'}
245-
</Button>
238+
<div className="space-y-3">
239+
<Button
240+
onClick={handlePulse}
241+
disabled={isPulsing}
242+
className="w-full text-lg py-4 shadow-[0_0_20px_rgba(0,255,65,0.3)] hover:shadow-[0_0_40px_rgba(0,255,65,0.5)] flex items-center justify-center gap-2"
243+
>
244+
<Heart className="w-5 h-5" />
245+
{isPulsing ? 'PULSING...' : 'SEND PULSE'}
246+
</Button>
246247

247-
<Button
248-
onClick={() => setShowBurnConfirm(true)}
249-
variant="danger"
250-
className="w-full text-sm opacity-80 hover:opacity-100 flex items-center justify-center gap-2"
251-
>
252-
<Flame className="w-4 h-4" />
253-
BURN SEAL (PERMANENT)
254-
</Button>
248+
<Button
249+
onClick={() => setShowBurnConfirm(true)}
250+
variant="danger"
251+
className="w-full text-sm opacity-80 hover:opacity-100 flex items-center justify-center gap-2"
252+
>
253+
<Flame className="w-4 h-4" />
254+
BURN SEAL (PERMANENT)
255+
</Button>
256+
</div>
255257

256258
{error && <ErrorMessage message={error} />}
257259
</div>

app/v/[id]/page.tsx

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ interface SealStatus {
1717
timeRemaining?: number;
1818
keyB?: string;
1919
iv?: string;
20+
isDMS?: boolean;
21+
pulseToken?: string;
2022
}
2123

2224
export default function VaultPage({ params }: { params: { id: string } }) {
@@ -257,7 +259,7 @@ function VaultPageClient({ id }: { id: string }) {
257259

258260
// Locked state with countdown
259261
return (
260-
<div className="min-h-screen flex items-center justify-center p-4 relative w-full overflow-hidden">
262+
<div className="min-h-screen flex items-center justify-center p-4 relative w-full overflow-x-hidden pb-20">
261263
<BackgroundBeams className="absolute top-0 left-0 w-full h-full z-0" />
262264
<div className="max-w-md w-full text-center relative z-10">
263265
<motion.div
@@ -269,30 +271,46 @@ function VaultPageClient({ id }: { id: string }) {
269271
repeat: Infinity,
270272
repeatType: "reverse"
271273
}}
272-
className="mb-6 flex justify-center"
274+
className="mb-4 flex justify-center"
273275
>
274-
<Lock className="w-16 h-16 text-neon-green" />
276+
<Lock className="w-12 h-12 text-neon-green" />
275277
</motion.div>
276278

277-
<h1 className="text-3xl sm:text-4xl font-bold glow-text mb-3 px-2">
278-
<DecryptedText text="VAULT SEALED" animateOn="view" className="text-neon-green" />
279+
<h1 className="text-2xl sm:text-3xl font-bold glow-text mb-3 px-2">
280+
<DecryptedText text={status.isDMS ? "DEAD MAN'S SWITCH ACTIVE" : "VAULT SEALED"} animateOn="view" className="text-neon-green" />
279281
</h1>
280-
<p className="text-neon-green/70 mb-6 text-sm sm:text-base px-4">
281-
This message is cryptographically locked until:
282+
283+
{status.isDMS && status.pulseToken && (
284+
<div className="mb-4 p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg">
285+
<p className="text-yellow-500 text-sm font-bold mb-2">⚠️ PULSE REQUIRED</p>
286+
<p className="text-yellow-400/80 text-xs mb-3">
287+
This seal will auto-unlock if not pulsed. Click below to keep it locked.
288+
</p>
289+
<a
290+
href={`/pulse/${status.pulseToken}`}
291+
className="cyber-button inline-flex items-center justify-center gap-2 bg-yellow-500/20 hover:bg-yellow-500/30 border-yellow-500/50 text-yellow-500 w-full text-sm"
292+
>
293+
SEND PULSE NOW →
294+
</a>
295+
</div>
296+
)}
297+
298+
<p className="text-neon-green/70 mb-4 text-sm px-4">
299+
{status.isDMS ? 'Will auto-unlock if pulse not received by:' : 'This message is cryptographically locked until:'}
282300
</p>
283301

284-
<Card className="p-4 sm:p-6 mb-6 border-neon-green/40 shadow-[0_0_30px_rgba(0,255,65,0.1)]">
285-
<div className="text-base sm:text-lg md:text-xl font-bold mb-4 text-neon-green/80 uppercase tracking-widest border-b border-neon-green/20 pb-2">
302+
<Card className="p-4 mb-4 border-neon-green/40 shadow-[0_0_30px_rgba(0,255,65,0.1)]">
303+
<div className="text-sm font-bold mb-3 text-neon-green/80 uppercase tracking-widest border-b border-neon-green/20 pb-2">
286304
Protocol Unlock Time
287305
</div>
288-
<div className="text-lg sm:text-xl md:text-2xl font-bold mb-6 text-white font-mono break-words">
306+
<div className="text-lg sm:text-xl font-bold mb-4 text-white font-mono break-words">
289307
{new Date(status.unlockTime).toLocaleString()}
290308
</div>
291309

292-
<div className="text-xs text-neon-green/50 mb-2 uppercase tracking-abovet">Time Remaining</div>
310+
<div className="text-xs text-neon-green/50 mb-2 uppercase tracking-widest">Time Remaining</div>
293311
{timeLeft > 0 ? (
294312
<>
295-
<div className="text-2xl sm:text-3xl md:text-4xl font-mono pulse-glow text-neon-green tabular-nums mb-4">
313+
<div className="text-2xl sm:text-3xl font-mono pulse-glow text-neon-green tabular-nums mb-3">
296314
<DecryptedText
297315
text={formatTimeLeft(timeLeft)}
298316
speed={0}
@@ -316,16 +334,16 @@ function VaultPageClient({ id }: { id: string }) {
316334
)}
317335
</Card>
318336

319-
<div className="space-y-4">
337+
<div className="space-y-3">
320338
<button
321339
onClick={copyVaultLink}
322-
className="cyber-button inline-flex items-center justify-center gap-2 bg-neon-green/10 hover:bg-neon-green/20"
340+
className="cyber-button inline-flex items-center justify-center gap-2 bg-neon-green/10 hover:bg-neon-green/20 w-full"
323341
>
324342
<Copy className="w-4 h-4" />
325343
COPY VAULT LINK
326344
</button>
327345

328-
<p className="text-xs text-neon-green/40 max-w-xs mx-auto leading-relaxed">
346+
<p className="text-xs text-neon-green/40 max-w-xs mx-auto leading-relaxed px-2">
329347
<span className="block mb-1">SECURITY LEVEL: MAXIMUM</span>
330348
This vault uses split-key encryption and WORM storage.
331349
It cannot be opened early, even by the creator.
@@ -338,4 +356,4 @@ function VaultPageClient({ id }: { id: string }) {
338356
</div>
339357
</div>
340358
);
341-
}
359+
}

docs/INNOVATION-ANALYSIS.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Innovation Analysis: What's Worth Building?
2+
3+
## TL;DR
4+
5+
**Build Now:** Post-Quantum Cryptography (PQC)
6+
**Maybe Later:** Decentralized Storage
7+
**Skip:** SSI and ZKPs (wrong problems)
8+
9+
## Quick Evaluation
10+
11+
### 1. Self-Sovereign Identity (SSI) 🔴 SKIP
12+
13+
**Problem it solves:** Lost vault links
14+
**Why skip:**
15+
- Breaks "anyone with link = access" model (kills whistleblower use case)
16+
- Adds authentication layer (contradicts zero-trust design)
17+
- Requires wallet (huge UX barrier)
18+
- Massive complexity for small benefit
19+
20+
**Better solution:** Optional password-encrypted link backup in localStorage
21+
22+
### 2. Zero-Knowledge Proofs (ZKPs) 🟡 SKIP (FOR NOW)
23+
24+
**Problem it solves:** Key A visible in URL
25+
**Why skip:**
26+
- Key A already never sent to server (problem doesn't exist)
27+
- 1-5 second proof generation = terrible UX
28+
- Still need to distribute Key A somehow (defeats purpose)
29+
- You already have memory obfuscation (v0.6.0)
30+
31+
**When to revisit:** If ZK tech gets 100x faster (2027+)
32+
33+
### 3. Post-Quantum Cryptography (PQC) 🟢 BUILD THIS
34+
35+
**Problem it solves:** Quantum computers will break AES-256 (2030-2035)
36+
**Why build:**
37+
- Seals can be locked for decades (quantum threat is real)
38+
- NIST-approved algorithms ready now (CRYSTALS-Kyber)
39+
- Only 5x slower, +50KB bundle (acceptable)
40+
- Huge marketing value ("quantum-resistant vaults")
41+
42+
**Implementation:**
43+
```typescript
44+
// Hybrid mode: AES + Kyber
45+
import { kyber1024 } from '@noble/post-quantum/kyber';
46+
47+
// 1. Encrypt with AES (fast)
48+
const aesEncrypted = await aesEncrypt(data, aesKey);
49+
50+
// 2. Protect AES key with Kyber (quantum-safe)
51+
const { ciphertext, sharedSecret } = kyber1024.encapsulate(publicKey);
52+
const protectedKey = xor(aesKey, sharedSecret);
53+
```
54+
55+
**Timeline:** 2-3 months to production
56+
57+
### 4. Decentralized Storage + MPC 🟡 MAYBE LATER
58+
59+
**Problem it solves:** Cloudflare single point of failure
60+
**Why wait:**
61+
- 10x slower (500ms vs 50ms)
62+
- 100x more expensive ($500/mo vs $5/mo)
63+
- Massive operational complexity (5 servers, consensus, Byzantine failures)
64+
- IPFS is slow (2-5 seconds per fetch)
65+
66+
**When to build:**
67+
- Enterprise tier (customers pay for censorship resistance)
68+
- Self-hosting guide (let others run MPC networks)
69+
- 2026+ when you have revenue to support infrastructure
70+
71+
## What to Build
72+
73+
**Now (Q1 2025):** Post-Quantum Cryptography
74+
- 2-3 months effort
75+
- Use `@noble/post-quantum/kyber`
76+
- Hybrid mode (AES + Kyber)
77+
- Huge marketing win
78+
79+
**Later (2026+):** MPC for enterprise tier
80+
- Only if you have paying customers
81+
- Document self-hosting approach
82+
- Let others run their own networks
83+
84+
**Never:** SSI and ZKPs
85+
- Wrong problems
86+
- Too much complexity
87+
- Conflicts with design
88+
89+
---
90+
91+
**Bottom line:** Build PQC. Skip the rest.

0 commit comments

Comments
 (0)