diff --git a/src/router.ts b/src/router.ts index 14a4df7..84b056a 100644 --- a/src/router.ts +++ b/src/router.ts @@ -142,6 +142,17 @@ function handleNwFavicon(): Response { }); } +const BITWARDEN_DEFAULT_ICON_SHA256 = 'aaa64871332ad5b7d28fe8874efb19c2d9cc2f1e6de75d52b080b438225a0783'; + +function bytesToHex(bytes: Uint8Array): string { + return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join(''); +} + +async function sha256Hex(buffer: ArrayBuffer): Promise { + const digest = await crypto.subtle.digest('SHA-256', buffer); + return bytesToHex(new Uint8Array(digest)); +} + function isValidIconHostname(hostname: string): boolean { if (!hostname) return false; if (hostname.length > 253) return false; @@ -192,6 +203,9 @@ async function handleGetIcon(request: Request, env: Env, hostname: string): Prom if (resp.ok) { const body = await resp.arrayBuffer(); + if (body.byteLength === 500 && (await sha256Hex(body)) === BITWARDEN_DEFAULT_ICON_SHA256) { + return new Response(null, { status: 204 }); + } const iconResponse = new Response(body, { status: 200, headers: { diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 3e59733..2ea3e93 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { Link, Route, Switch, useLocation } from 'wouter'; import { useQuery } from '@tanstack/react-query'; -import { ArrowUpDown, Cloud, Lock, LogOut, Send as SendIcon, Settings as SettingsIcon, Shield, ShieldUser, Vault } from 'lucide-preact'; +import { ArrowUpDown, Cloud, Clock3, KeyRound, Lock, LogOut, Send as SendIcon, Settings as SettingsIcon, Shield, ShieldUser } from 'lucide-preact'; import AuthViews from '@/components/AuthViews'; import ConfirmDialog from '@/components/ConfirmDialog'; import ToastHost from '@/components/ToastHost'; @@ -15,6 +15,7 @@ import SecurityDevicesPage from '@/components/SecurityDevicesPage'; import AdminPage from '@/components/AdminPage'; import HelpPage from '@/components/HelpPage'; import ImportPage from '@/components/ImportPage'; +import TotpCodesPage from '@/components/TotpCodesPage'; import type { ImportAttachmentFile, ImportResultSummary } from '@/components/ImportPage'; import { changeMasterPassword, @@ -1669,9 +1670,13 @@ export default function App() {