From 9af5c63f1711f744fe0d4eef352b9ca9582eae75 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 18:40:21 +0000 Subject: [PATCH] feat: implement comprehensive suite of hash algorithms with explorer UI - Created a centralized algorithm registry detailing categories, descriptions, security levels, recommendations, and citations. - Added and compiled Rust dependencies and incremental WASM bindings for SHA-2, SHA-3, SHAKE, BLAKE2, RIPEMD-160, Whirlpool, SM3, and checksums. - Updated the background Web Worker to support dynamic and streaming updates. - Redesigned the React app interface with search, filters, modals, and localized security guidelines. Co-authored-by: erikraft <139592038+erikraft@users.noreply.github.com> --- frontend/src/App.tsx | 458 ++++++++++++--- frontend/src/hash.worker.ts | 154 +++-- frontend/src/hashRegistry.ts | 1037 ++++++++++++++++++++++++++++++++++ frontend/src/styles.css | 98 +++- rust/Cargo.lock | 130 +++++ rust/Cargo.toml | 12 + rust/src/lib.rs | 700 ++++++++++++++++++++++- 7 files changed, 2463 insertions(+), 126 deletions(-) create mode 100644 frontend/src/hashRegistry.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6db7e59..42480e7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useRef } from 'react'; +import { hashAlgorithms, HashAlgorithmInfo } from './hashRegistry'; export default function App() { // Original Hashing States @@ -8,12 +9,9 @@ export default function App() { const [progress, setProgress] = useState(null); const [progressBytes, setProgressBytes] = useState<{ read: number; total: number } | null>(null); - const [hashes, setHashes] = useState<{ - sha256: string; - sha512: string; - md5: string; - blake3: string; - } | null>(null); + + // Dynamic hashes map supporting all algorithms + const [hashes, setHashes] = useState | null>(null); const [isComputing, setIsComputing] = useState(false); const [error, setError] = useState(null); const [copiedAlgo, setCopiedAlgo] = useState(null); @@ -22,6 +20,13 @@ export default function App() { // Hash Comparison State const [compareHash, setCompareHash] = useState(''); + // UI Search and Filter States for Algorithms + const [searchQuery, setSearchQuery] = useState(''); + const [selectedCategory, setSelectedCategory] = useState('Todos'); + + // Selected Algorithm detail modal/tooltip state + const [activeInfoAlgo, setActiveInfoAlgo] = useState(null); + // Terminal Booting States for Site Loader const [isBooting, setIsBooting] = useState(true); const [bootCommand, setBootCommand] = useState(''); @@ -61,7 +66,6 @@ export default function App() { const commandText = "init --rust-hash"; let cmdIndex = 0; - // Phase 1: Type Command const typingInterval = setInterval(() => { if (cmdIndex < commandText.length) { setBootCommand(prev => prev + commandText[cmdIndex]); @@ -69,15 +73,13 @@ export default function App() { } else { clearInterval(typingInterval); - // Phase 2: Start sequentially outputting log steps setTimeout(() => { - setLogSteps(1); // Show first log + setLogSteps(1); setTimeout(() => { - setLogSteps(2); // Show second log + setLogSteps(2); setTimeout(() => { - setLogSteps(3); // Show third log + setLogSteps(3); - // Phase 3: Increment progress bar let prog = 0; const progressInterval = setInterval(() => { if (prog < 100) { @@ -86,7 +88,6 @@ export default function App() { } else { clearInterval(progressInterval); - // Phase 4: Final line and close loader setLogSteps(4); setTimeout(() => { setShowFinalPrompt(true); @@ -112,10 +113,10 @@ export default function App() { if (isBooting) return; const phrases = [ - 'Privacy-first local hashing', - 'Built with Rust + WebAssembly', - 'Asynchronous Web Worker processing', - 'Drag & Drop modern visual interface' + 'Privacidade em primeiro lugar: processamento local', + 'Construído com Rust + WebAssembly ultra-rápido', + 'Execução paralela assíncrona via Web Workers', + 'Interface moderna com Drag & Drop de arquivos' ]; let timer: NodeJS.Timeout; @@ -155,13 +156,11 @@ export default function App() { setProgressBytes(null); setHashes(null); - // Terminate any previous worker running to cancel current operation immediately if (workerRef.current) { console.log("Terminating existing worker"); workerRef.current.terminate(); } - // Spin up a new worker console.log("Instantiating new Worker..."); const worker = new Worker( new URL('./hash.worker.ts', import.meta.url), @@ -170,13 +169,12 @@ export default function App() { worker.onmessage = (event) => { const { type: responseType, progress: resProgress, bytesRead, totalBytes, results, error: responseError } = event.data; - console.log("Received worker message:", responseType, { resProgress, bytesRead, totalBytes, results, responseError }); if (responseType === 'HASH_PROGRESS') { setProgress(resProgress); setProgressBytes({ read: bytesRead, total: totalBytes }); } else if (responseType === 'HASH_SUCCESS') { - console.log("Hashing SUCCESS! Results:", results); + console.log("Hashing SUCCESS!"); setHashes(results); setIsComputing(false); setProgress(null); @@ -199,7 +197,7 @@ export default function App() { if (activeTab === 'text') { const timer = setTimeout(() => { startHashing('HASH_TEXT', text); - }, 250); // 250ms debounce + }, 250); return () => clearTimeout(timer); } }, [text, activeTab]); @@ -256,14 +254,33 @@ export default function App() { }, 1500); }; - // Render booting progress bar text helper - const getProgressBarText = (percent: number) => { - const totalBlocks = 20; - const filledBlocks = Math.round((percent / 100) * totalBlocks); - const emptyBlocks = totalBlocks - filledBlocks; - return "[" + "█".repeat(filledBlocks) + "░".repeat(emptyBlocks) + "]"; + // Get Security Color helper + const getSecurityBadgeInfo = (level: HashAlgorithmInfo['securityLevel']) => { + switch (level) { + case 'Seguro': + return { text: 'SEGURO', className: 'badge-secure' }; + case 'Fraco/Inseguro': + return { text: 'FRACASSO/VULNERÁVEL', className: 'badge-weak' }; + case 'Obsoleto': + return { text: 'OBSOLETO/EVITAR', className: 'badge-obsolete' }; + case 'Não Criptográfico (Integridade)': + return { text: 'NÃO-CRIPTOGRÁFICO', className: 'badge-checksum' }; + default: + return { text: 'N/A', className: 'badge-na' }; + } }; + // Filter categories + const categories = ['Todos', 'Criptográfico', 'Integridade (Checksum)', 'Fast/Non-Cryptographic', 'Segurança de Senha', 'Fuzzy/Similaridade', 'Outros Especializados']; + + // Filter & Search Logic + const filteredAlgorithms = hashAlgorithms.filter(algo => { + const matchesSearch = algo.name.toLowerCase().includes(searchQuery.toLowerCase()) || + algo.description.toLowerCase().includes(searchQuery.toLowerCase()); + const matchesCategory = selectedCategory === 'Todos' || algo.category === selectedCategory; + return matchesSearch && matchesCategory; + }); + return ( <> {/* Premium Loader Overlay */} @@ -279,31 +296,33 @@ export default function App() { {logSteps >= 1 && (
[ OK ] - Resolving WebAssembly compilation targets... + Resolvendo alvos de compilação WebAssembly...
)} {logSteps >= 2 && (
[ OK ] - Wasm bindgen bindings verified. + Bindings do wasm-bindgen verificados com sucesso.
)} {logSteps >= 3 && (
[ OK ] - Instantiating background Web Worker context... + Instanciando contexto assíncrono do Web Worker...
)} {bootProgress > 0 && (
- {getProgressBarText(bootProgress)} + + {"[" + "█".repeat(Math.round(bootProgress / 5)) + "░".repeat(20 - Math.round(bootProgress / 5)) + "]"} + {bootProgress}%
)} {logSteps >= 4 && (
[ OK ] - Bootstrap process completed successfully. + Processo de inicialização concluído com sucesso.
)} {showFinalPrompt && ( @@ -346,7 +365,7 @@ export default function App() { setHashes(null); }} > - ✍️ Text Input + ✍️ Entrada de Texto @@ -366,11 +385,11 @@ export default function App() {
{activeTab === 'text' && (
-

✍️ Input String

+

✍️ String de Entrada