ux: clean security warnings modal and overlays

This commit is contained in:
LC mac
2026-01-31 01:58:32 +08:00
parent 2a7ac1cce0
commit a607cd74cf
2 changed files with 81 additions and 90 deletions

View File

@@ -612,62 +612,68 @@ function App() {
{/* Security Modal */} {/* Security Modal */}
{showSecurityModal && ( {showSecurityModal && (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"> <div
<div className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"> className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"
onClick={() => setShowSecurityModal(false)}
>
<div
className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<h3 className="text-lg font-semibold text-white mb-4">Security Limitations</h3> <h3 className="text-lg font-semibold text-white mb-4">Security Limitations</h3>
<div className="text-sm text-slate-300 space-y-2"> <div className="text-sm text-slate-300 space-y-2">
<SecurityWarnings /> <SecurityWarnings />
</div> </div>
<button
className="mt-4 w-full py-2 bg-slate-700 hover:bg-slate-600 rounded-lg"
onClick={() => setShowSecurityModal(false)}
>
Close
</button>
</div> </div>
</div> </div>
)} )}
{/* Storage Modal */} {/* Storage Modal */}
{showStorageModal && ( {showStorageModal && (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"> <div
<div className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"> className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"
onClick={() => setShowStorageModal(false)}
>
<div
className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<h3 className="text-lg font-semibold text-white mb-4">Storage Details</h3> <h3 className="text-lg font-semibold text-white mb-4">Storage Details</h3>
<div className="text-sm text-slate-300 space-y-2"> <div className="text-sm text-slate-300 space-y-2">
<StorageDetails localItems={localItems} sessionItems={sessionItems} /> <StorageDetails localItems={localItems} sessionItems={sessionItems} />
</div> </div>
<button
className="mt-4 w-full py-2 bg-slate-700 hover:bg-slate-600 rounded-lg"
onClick={() => setShowStorageModal(false)}
>
Close
</button>
</div> </div>
</div> </div>
)} )}
{/* Clipboard Modal */} {/* Clipboard Modal */}
{showClipboardModal && ( {showClipboardModal && (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"> <div
<div className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"> className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"
onClick={() => setShowClipboardModal(false)}
>
<div
className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<h3 className="text-lg font-semibold text-white mb-4">Clipboard Activity</h3> <h3 className="text-lg font-semibold text-white mb-4">Clipboard Activity</h3>
<div className="text-sm text-slate-300 space-y-2"> <div className="text-sm text-slate-300 space-y-2">
<ClipboardDetails events={clipboardEvents} onClear={clearClipboard} /> <ClipboardDetails events={clipboardEvents} onClear={clearClipboard} />
</div> </div>
<button
className="mt-4 w-full py-2 bg-slate-700 hover:bg-slate-600 rounded-lg"
onClick={() => setShowClipboardModal(false)}
>
Close
</button>
</div> </div>
</div> </div>
)} )}
{/* Lock Confirmation Modal */} {/* Lock Confirmation Modal */}
{showLockConfirm && ( {showLockConfirm && (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"> <div
<div className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"> className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50"
onClick={() => setShowLockConfirm(false)}
>
<div
className="bg-slate-800 rounded-xl border border-slate-700 p-6 max-w-md w-full mx-4 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
<h3 className="text-lg font-semibold text-white mb-4 flex items-center gap-2"> <h3 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
<Lock className="w-5 h-5 text-amber-500" /> <Lock className="w-5 h-5 text-amber-500" />
Lock Sensitive Data? Lock Sensitive Data?

View File

@@ -1,81 +1,66 @@
import { useState } from 'react'; import React from 'react';
export const SecurityWarnings = () => {
const [isExpanded, setIsExpanded] = useState(false);
export const SecurityWarnings: React.FC = () => {
return ( return (
<div className="fixed top-4 left-4 z-50 max-w-sm"> <div className="space-y-3">
<div className="bg-yellow-50 border-2 border-yellow-400 rounded-lg shadow-lg"> <Warning
icon="🧵"
title="JavaScript Strings are Immutable"
description="Strings cannot be overwritten in memory. Copies persist until garbage collection runs (timing unpredictable)."
/>
{/* Header */} <Warning
<div icon="🗑️"
className="px-4 py-3 cursor-pointer flex items-center justify-between hover:bg-yellow-100 transition-colors rounded-t-lg" title="No Guaranteed Memory Wiping"
onClick={() => setIsExpanded(!isExpanded)} description="JavaScript has no secure memory clearing. Sensitive data may linger in RAM until GC or browser restart."
> />
<div className="flex items-center gap-2">
<span className="text-lg"></span>
<span className="font-semibold text-sm text-yellow-900">Security Limitations</span>
</div>
<span className="text-yellow-600 text-sm">{isExpanded ? '▼' : '▶'}</span>
</div>
{/* Expanded Content */} <Warning
{isExpanded && ( icon="📋"
<div className="px-4 py-3 border-t border-yellow-300 space-y-3 max-h-96 overflow-y-auto"> title="Clipboard Exposure"
description="Copied data is accessible to other tabs/apps. Browser extensions can read clipboard contents."
/>
<Warning <Warning
icon="🧵" icon="💾"
title="JavaScript Strings are Immutable" title="Browser Storage Persistence"
description="Strings cannot be overwritten in memory. Copies persist until garbage collection runs (timing unpredictable)." description="localStorage survives browser restart. sessionStorage survives page refresh. Both readable by any script on this domain."
/> />
<Warning <Warning
icon="🗑️" icon="🔍"
title="No Guaranteed Memory Wiping" title="DevTools Access"
description="JavaScript has no secure memory clearing. Sensitive data may linger in RAM until GC or browser restart." description="All app state, memory, and storage visible in browser DevTools. Never use on untrusted devices."
/> />
<Warning <Warning
icon="📋" icon="🌐"
title="Clipboard Exposure" title="Network Risks (When Online)"
description="Copied data is accessible to other tabs/apps. Browser extensions can read clipboard contents." description="If hosted online: DNS, HTTPS, CDN, and browser can see usage patterns. Use offline/local for maximum security."
/> />
<Warning <div className="pt-3 border-t border-slate-600 text-xs text-slate-400">
icon="💾" <strong className="text-slate-300">Recommendation:</strong>{' '}
title="Browser Storage Persistence" Use this tool on a dedicated offline device. Clear browser data after each use. Never use on shared/public computers.
description="localStorage survives browser restart. sessionStorage survives page refresh. Both readable by any script on this domain."
/>
<Warning
icon="🔍"
title="DevTools Access"
description="All app state, memory, and storage visible in browser DevTools. Never use on untrusted devices."
/>
<Warning
icon="🌐"
title="Network Risks (When Online)"
description="If hosted online: DNS, HTTPS, CDN, and browser can see usage patterns. Use offline/local for maximum security."
/>
<div className="pt-2 border-t border-yellow-300 text-xs text-yellow-800">
<strong>Recommendation:</strong> Use this tool on a dedicated offline device.
Clear browser data after each use. Never use on shared/public computers.
</div>
</div>
)}
</div> </div>
</div> </div>
); );
}; };
const Warning = ({ icon, title, description }: { icon: string; title: string; description: string }) => ( const Warning = ({
<div className="flex gap-2 text-xs"> icon,
<span className="text-base flex-shrink-0">{icon}</span> title,
description,
}: {
icon: string;
title: string;
description: string;
}) => (
<div className="flex gap-2 text-sm">
<span className="text-lg flex-shrink-0">{icon}</span>
<div> <div>
<div className="font-semibold text-yellow-900 mb-0.5">{title}</div> <div className="font-semibold text-slate-200 mb-1">{title}</div>
<div className="text-yellow-800 leading-relaxed">{description}</div> <div className="text-slate-400 leading-relaxed">{description}</div>
</div> </div>
</div> </div>
); );