The palette lived as ~620 hex literals in inline styles plus a few hundred more in
the stylesheets, so there was no single thing to change. It is now 113 custom
properties in src/styles/theme.css, in two blocks.
src/scripts/theme-boot.js decides the theme before first paint — blocking, in <head>,
above the stylesheet, because a deferred script paints dark first and corrects itself.
It stores the mode ('system' | 'light' | 'dark'), never the colour it resolved to, and
stamps data-theme so an explicit choice can beat the media query. The switcher in the
header is a view onto it.
A filled accent stays the brand colour in both themes — the ink on it is near-black
either way — while an accent used as text darkens to clear 4.5:1 on white. A colour
reaches a fill by four routes (a style property, a constant, a helper argument, an SVG
source string), and tests/theme-switching.test.mjs covers all four.
The dark theme is unchanged: every colour declaration the previous build produced comes
out of this one identically once the properties are resolved.
Also: the roadmap drops its status chips on mobile, and Roadmap.jsx no longer splits a
colour with parseInt at runtime, which a var() reference cannot survive.
498 lines
37 KiB
HTML
498 lines
37 KiB
HTML
<!DOCTYPE html>
|
||
<!-- Generated by scripts/build-i18n.js from templates/index.template.html and
|
||
locales/*.json. Edits made here are overwritten by the next build. -->
|
||
<html lang="zh-Hans" dir="ltr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<!-- viewport-fit=cover is what makes env(safe-area-inset-*) resolve to anything
|
||
other than 0 on notched iPhones; the composer already pads for it.
|
||
interactive-widget=resizes-content is honoured by Chrome/Android; iOS
|
||
ignores it, which is why the shell also tracks visualViewport in JS. -->
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content">
|
||
<meta http-equiv="Content-Security-Policy"
|
||
content="default-src 'self';
|
||
script-src 'self';
|
||
style-src 'self' 'unsafe-inline';
|
||
font-src 'self' data:;
|
||
connect-src 'self' stun: stuns: turn: turns:;
|
||
img-src 'self' data:;
|
||
media-src 'self' blob:;
|
||
object-src 'none';
|
||
frame-src 'none';
|
||
worker-src 'self';
|
||
manifest-src 'self';
|
||
form-action 'self';
|
||
base-uri 'none';
|
||
upgrade-insecure-requests;">
|
||
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
||
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
|
||
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
|
||
|
||
<!-- PWA Manifest -->
|
||
<link rel="manifest" href="/zh/manifest.json">
|
||
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1788557187846">
|
||
|
||
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
|
||
from localStorage while the parser is still in <head>, so the page paints in the
|
||
chosen theme on the first frame instead of flashing dark and correcting itself.
|
||
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
|
||
<script src="/src/scripts/theme-boot.js?v=1788557187846"></script>
|
||
|
||
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
|
||
not replayed, so the listener has to exist before Chrome decides the page
|
||
is installable. Deferred/module scripts are already too late. -->
|
||
<script src="/src/scripts/pwa-install-capture.js?v=1788557187846"></script>
|
||
|
||
<!-- PWA Meta Tags -->
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="format-detection" content="telephone=no">
|
||
<!-- "default", not "black-translucent", now that there are two themes.
|
||
black-translucent draws the clock and battery in white and lets the page run under
|
||
them; on a light page that is white on near-white, and the meta is read once at
|
||
launch so no script can correct it. With "default" iOS tints the status bar from
|
||
<meta name="theme-color"> below and picks the glyph colour to contrast with it, so
|
||
it follows the theme on its own. The trade is that the page no longer extends under
|
||
the bar, which makes env(safe-area-inset-top) 0 in standalone — src/styles/pwa.css
|
||
already derives --sb-safe-top from that env(), so it collapses to 0 and the header
|
||
sits where it does in a browser tab. -->
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||
<meta name="apple-mobile-web-app-title" content="SecureBit">
|
||
<meta name="application-name" content="SecureBit">
|
||
<meta name="msapplication-TileColor" content="#ff6b35">
|
||
<meta name="msapplication-config" content="/browserconfig.xml">
|
||
|
||
<!-- iOS Splash Screens - Полная конфигурация с генератора -->
|
||
<!-- Landscape -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 440px) and (device-height: 956px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_17_Pro_Max__iPhone_16_Pro_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 402px) and (device-height: 874px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_17_Pro__iPhone_17__iPhone_16_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_16_Plus__iPhone_15_Pro_Max__iPhone_15_Plus__iPhone_14_Pro_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 420px) and (device-height: 912px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_Air_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_16__iPhone_15_Pro__iPhone_15__iPhone_14_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_16e__iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_11_Pro_Max__iPhone_XS_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_11__iPhone_XR_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_landscape.png">
|
||
|
||
<!-- iPad Landscape -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1032px) and (device-height: 1376px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/13__iPad_Pro_M4_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/12.9__iPad_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1210px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/11__iPad_Pro_M4_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/11__iPad_Pro__10.5__iPad_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/10.9__iPad_Air_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/10.5__iPad_Air_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/10.2__iPad_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/8.3__iPad_Mini_landscape.png">
|
||
|
||
<!-- Portrait -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 440px) and (device-height: 956px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_17_Pro_Max__iPhone_16_Pro_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 402px) and (device-height: 874px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_17_Pro__iPhone_17__iPhone_16_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_16_Plus__iPhone_15_Pro_Max__iPhone_15_Plus__iPhone_14_Pro_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 420px) and (device-height: 912px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_Air_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_16__iPhone_15_Pro__iPhone_15__iPhone_14_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_16e__iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_11_Pro_Max__iPhone_XS_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_11__iPhone_XR_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_portrait.png">
|
||
|
||
<!-- iPad Portrait -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1032px) and (device-height: 1376px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/13__iPad_Pro_M4_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/12.9__iPad_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1210px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/11__iPad_Pro_M4_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/11__iPad_Pro__10.5__iPad_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/10.9__iPad_Air_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/10.5__iPad_Air_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/10.2__iPad_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
|
||
|
||
<!-- Apple Touch Icons -->
|
||
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1788557187846">
|
||
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
|
||
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
|
||
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
|
||
<link rel="apple-touch-icon" sizes="76x76" href="/logo/icon-76x76.png">
|
||
<link rel="apple-touch-icon" sizes="114x114" href="/logo/icon-114x114.png">
|
||
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
|
||
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
|
||
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1788557187846">
|
||
|
||
<!-- Microsoft Tiles -->
|
||
<meta name="msapplication-TileColor" content="#ff6b35">
|
||
<meta name="msapplication-TileImage" content="./logo/icon-144x144.png">
|
||
<meta name="msapplication-config" content="/browserconfig.xml">
|
||
|
||
<!-- Theme colors.
|
||
Two tags with media queries, which is how the browser answers before any script has
|
||
run and how a client with no JavaScript answers permanently. They are the page's
|
||
own ground (--sb-bg in src/styles/theme.css), not the brand orange: this paints the
|
||
Android address bar and the iOS status bar, and a strip in a different colour from
|
||
the page reads as a rendering fault rather than as branding.
|
||
Once theme-boot.js runs it drops the media attributes and writes the resolved
|
||
colour into both, because a media query cannot express "light on a dark system",
|
||
which is exactly what someone who picked a theme by hand has asked for. -->
|
||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0f0f11">
|
||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f6f7f8">
|
||
<meta name="msapplication-navbutton-color" content="#0f0f11">
|
||
|
||
<!-- Security Headers for PWA - CSP is already defined above -->
|
||
|
||
|
||
<!-- SEO -->
|
||
<title>SecureBit.chat - 私密的端到端加密通讯工具</title>
|
||
<meta name="description" content="SecureBit.chat 是一款免费的端到端加密点对点通讯工具,完全在浏览器中运行。无需账号,没有服务器保存你的消息 —— 采用 ECDH P-384、AES-256-GCM 与当面 SAS 校验。">
|
||
<meta name="author" content="Volodymyr">
|
||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1">
|
||
<link rel="canonical" href="https://securebit.chat/zh/">
|
||
<link rel="alternate" hreflang="en" href="https://securebit.chat/">
|
||
<link rel="alternate" hreflang="de" href="https://securebit.chat/de/">
|
||
<link rel="alternate" hreflang="fr" href="https://securebit.chat/fr/">
|
||
<link rel="alternate" hreflang="es" href="https://securebit.chat/es/">
|
||
<link rel="alternate" hreflang="uk" href="https://securebit.chat/uk/">
|
||
<link rel="alternate" hreflang="ru" href="https://securebit.chat/ru/">
|
||
<link rel="alternate" hreflang="zh-Hans" href="https://securebit.chat/zh/">
|
||
<link rel="alternate" hreflang="ko" href="https://securebit.chat/ko/">
|
||
<link rel="alternate" hreflang="hi" href="https://securebit.chat/hi/">
|
||
<link rel="alternate" hreflang="ar" href="https://securebit.chat/ar/">
|
||
<link rel="alternate" hreflang="he" href="https://securebit.chat/he/">
|
||
<link rel="alternate" hreflang="fa" href="https://securebit.chat/fa/">
|
||
<link rel="alternate" hreflang="ur" href="https://securebit.chat/ur/">
|
||
<link rel="alternate" hreflang="x-default" href="https://securebit.chat/">
|
||
|
||
<!-- Open Graph -->
|
||
<meta property="og:site_name" content="SecureBit.chat">
|
||
<meta property="og:title" content="SecureBit.chat - 端到端加密的点对点聊天">
|
||
<meta property="og:description" content="完全在浏览器中运行的安全通讯工具。无需账号,没有服务器保存你的消息。可以接入你自己的 STUN/TURN 服务器 —— 我们不做任何强制。">
|
||
<meta property="og:url" content="https://securebit.chat/zh/">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:locale" content="zh_CN">
|
||
<meta property="og:locale:alternate" content="en_US">
|
||
<meta property="og:locale:alternate" content="de_DE">
|
||
<meta property="og:locale:alternate" content="fr_FR">
|
||
<meta property="og:locale:alternate" content="es_ES">
|
||
<meta property="og:locale:alternate" content="uk_UA">
|
||
<meta property="og:locale:alternate" content="ru_RU">
|
||
<meta property="og:locale:alternate" content="ko_KR">
|
||
<meta property="og:locale:alternate" content="hi_IN">
|
||
<meta property="og:locale:alternate" content="ar_AR">
|
||
<meta property="og:locale:alternate" content="he_IL">
|
||
<meta property="og:locale:alternate" content="fa_IR">
|
||
<meta property="og:locale:alternate" content="ur_PK">
|
||
<meta property="og:image" content="https://securebit.chat/assets/social-card.png">
|
||
<meta property="og:image:secure_url" content="https://securebit.chat/assets/social-card.png">
|
||
<meta property="og:image:type" content="image/png">
|
||
<meta property="og:image:width" content="1200">
|
||
<meta property="og:image:height" content="630">
|
||
<meta property="og:image:alt" content="SecureBit.chat - 端到端加密的点对点聊天">
|
||
|
||
<!-- Twitter Card -->
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:title" content="SecureBit.chat - 端到端加密的点对点聊天">
|
||
<meta name="twitter:description" content="完全在浏览器中运行的安全通讯工具。无需账号,没有服务器保存你的消息。">
|
||
<meta name="twitter:image" content="https://securebit.chat/assets/social-card.png">
|
||
<meta name="twitter:image:alt" content="SecureBit.chat - 端到端加密的点对点聊天">
|
||
|
||
<!-- Structured data (schema.org) -->
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@graph": [
|
||
{
|
||
"@type": "Organization",
|
||
"@id": "https://securebit.chat/#organization",
|
||
"name": "SecureBit.chat",
|
||
"url": "https://securebit.chat/",
|
||
"logo": "https://securebit.chat/logo/icon-512x512.png",
|
||
"sameAs": [
|
||
"https://github.com/SecureBitChat/securebit-chat",
|
||
"https://snapcraft.io/securebit-chat"
|
||
]
|
||
},
|
||
{
|
||
"@type": "WebSite",
|
||
"@id": "https://securebit.chat/#website",
|
||
"name": "SecureBit.chat",
|
||
"url": "https://securebit.chat/",
|
||
"description": "完全在浏览器中运行的端到端加密点对点聊天。",
|
||
"inLanguage": "zh-Hans",
|
||
"publisher": {
|
||
"@id": "https://securebit.chat/#organization"
|
||
}
|
||
},
|
||
{
|
||
"@type": "WebApplication",
|
||
"name": "SecureBit.chat",
|
||
"url": "https://securebit.chat/zh/",
|
||
"applicationCategory": "CommunicationApplication",
|
||
"operatingSystem": "任意系统(现代网页浏览器)",
|
||
"browserRequirements": "需要 WebRTC 与 Web Crypto API",
|
||
"description": "免费的端到端加密点对点通讯工具。无需账号,没有服务器保存消息 —— 采用 ECDH P-384、AES-256-GCM 与当面 SAS 校验。",
|
||
"inLanguage": "zh-Hans",
|
||
"image": "https://securebit.chat/assets/social-card.png",
|
||
"license": "https://opensource.org/licenses/MIT",
|
||
"isAccessibleForFree": true,
|
||
"offers": {
|
||
"@type": "Offer",
|
||
"price": "0",
|
||
"priceCurrency": "USD"
|
||
},
|
||
"featureList": [
|
||
"端到端加密(ECDH P-384、AES-256-GCM)",
|
||
"基于 WebRTC 的点对点连接,不经过消息服务器",
|
||
"当面 SAS 校验,抵御中间人攻击",
|
||
"可使用自有 STUN/TURN 服务器,并提供仅中继的隐私模式",
|
||
"加密文件传输",
|
||
"可安装的渐进式网页应用,支持离线使用"
|
||
],
|
||
"sameAs": [
|
||
"https://github.com/SecureBitChat/securebit-chat"
|
||
]
|
||
}
|
||
]
|
||
}
|
||
</script>
|
||
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
|
||
both execute in document order after parsing, so React still runs before the
|
||
app modules below, but the parser / first paint is no longer blocked. -->
|
||
<script defer src="/config/ice-servers.js?v=1788557187846"></script>
|
||
<script defer src="/libs/react/react.production.min.js"></script>
|
||
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
|
||
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
|
||
it never executes the snippet. Loaded in manual mode (no auto-highlight).
|
||
Its CSS is loaded async via load-async-css.js (not paint-critical). -->
|
||
<script defer src="/libs/prism/prism.js"></script>
|
||
<!-- One render-blocking stylesheet, built by scripts/build-css.js from the Tailwind
|
||
output, the Inter @font-face declarations and the five hand-written sheets, in
|
||
that order — they argue with each other on source order, and concatenation
|
||
preserves it exactly. There used to be eight separate <link> tags here and at
|
||
the end of <body>: 21 KB of CSS in total, but eight round trips before the
|
||
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
|
||
connection. Bytes were never the problem; requests were. -->
|
||
<link rel="stylesheet" href="/assets/app.css?v=1788557187846">
|
||
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1788557187846">
|
||
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
|
||
answers for every weight, so there is one to preload rather than the two of five
|
||
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
|
||
fa-brands are loaded on demand by their CSS, rarely on the first screen. -->
|
||
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
|
||
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
|
||
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
|
||
<script defer src="/src/scripts/load-async-css.js?v=1788557187846"></script>
|
||
<noscript>
|
||
<link rel="stylesheet" href="/libs/prism/prism.css">
|
||
</noscript>
|
||
<script defer src="/src/scripts/fa-check.js?v=1788557187846"></script>
|
||
<!-- This locale's dictionary, registered before anything can ask for a string.
|
||
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
|
||
falls back to it); every other page loads its own here instead of all thirteen
|
||
riding along inside dist/app.js. Absent on the default locale's own page. -->
|
||
<script type="module" src="/src/i18n/dict/zh.js?v=1788557187846"></script>
|
||
<!-- Update Manager - система принудительного обновления -->
|
||
<script defer src="/src/utils/updateManager.js?v=1788557187846"></script>
|
||
<script type="module" src="/src/components/UpdateChecker.jsx?v=1788557187846"></script>
|
||
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
|
||
app has mounted and the browser is idle, so the 142 KB it weighs is off the
|
||
first load. src/components/QRScanner.js used to be here too and registered
|
||
window.QRScanner, which nothing has ever read. -->
|
||
</head>
|
||
<body>
|
||
<div id="root">
|
||
<style>
|
||
.sb-pre{display:none}
|
||
.sb-boot{display:flex;align-items:center;justify-content:center;min-height:100vh;min-height:100svh;margin:0;background:var(--sb-bg)}
|
||
.sb-boot svg{width:62px;height:auto;display:block;animation:sbBootPulse 1.8s ease-in-out infinite}
|
||
@keyframes sbBootPulse{0%,100%{opacity:.32;transform:scale(.97)}50%{opacity:1;transform:scale(1)}}
|
||
@media (prefers-reduced-motion:reduce){.sb-boot svg{animation:none;opacity:.75}}
|
||
</style>
|
||
<noscript><style>
|
||
.sb-pre{display:block}
|
||
.sb-boot{display:none}
|
||
</style></noscript>
|
||
<style>
|
||
.sb-pre{background:var(--sb-bg);color:var(--sb-text-2);font-family:Inter,system-ui,-apple-system,"Segoe UI",sans-serif;line-height:1.6;padding:56px 24px 72px;margin:0}
|
||
.sb-pre .sb-pre-in{max-width:940px;margin:0 auto;display:flex;flex-direction:column;gap:56px}
|
||
.sb-pre .sb-pre-brand{font-size:13px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--sb-orange);margin:0 0 18px}
|
||
.sb-pre h1{font-size:clamp(28px,5vw,40px);font-weight:800;letter-spacing:-1.1px;line-height:1.12;color:var(--sb-text-1);margin:0 0 14px}
|
||
.sb-pre h2{font-size:23px;font-weight:700;letter-spacing:-.5px;color:var(--sb-text-1);margin:0 0 8px}
|
||
.sb-pre h3{font-size:17px;font-weight:700;letter-spacing:-.2px;color:var(--sb-text-2);margin:0 0 6px}
|
||
.sb-pre p{margin:0 0 10px;color:var(--sb-text-7);font-size:15px;max-width:62ch}
|
||
.sb-pre .sb-pre-lead{font-size:16px;color:var(--sb-text-5);max-width:52ch}
|
||
.sb-pre .sb-pre-eyebrow{font-size:11px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--sb-text-9);margin:0 0 6px}
|
||
.sb-pre .sb-pre-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;margin-top:22px;padding:0;list-style:none}
|
||
.sb-pre .sb-pre-card{background:var(--sb-surface);border:1px solid rgba(var(--sb-ink),.07);border-radius:10px;padding:18px 20px}
|
||
.sb-pre .sb-pre-tags{margin:10px 0 0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:6px}
|
||
.sb-pre .sb-pre-tags li{font-size:11.5px;color:var(--sb-green);background:rgba(var(--sb-green-rgb),.09);border:1px solid rgba(var(--sb-green-rgb),.18);border-radius:4px;padding:2px 7px}
|
||
.sb-pre .sb-pre-steps{margin:22px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:2px}
|
||
.sb-pre .sb-pre-steps li{border-top:1px solid rgba(var(--sb-ink),.06);padding:13px 0;display:flex;flex-wrap:wrap;gap:2px 14px;align-items:baseline}
|
||
.sb-pre .sb-pre-steps h3{margin:0;font-size:15.5px}
|
||
.sb-pre .sb-pre-steps .sb-pre-when{font-size:12px;color:var(--sb-text-9);margin-inline-start:auto;white-space:nowrap}
|
||
.sb-pre .sb-pre-steps p{flex:1 1 100%;margin:2px 0 0;font-size:14px}
|
||
.sb-pre .sb-pre-docs{margin:14px 0 0;padding:0;list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:2px 24px}
|
||
.sb-pre .sb-pre-docs li{padding:8px 0;border-top:1px solid rgba(var(--sb-ink),.06);font-size:14.5px}
|
||
.sb-pre a{color:var(--sb-orange);text-underline-offset:2px}
|
||
@media (prefers-reduced-motion:reduce){.sb-pre *{animation:none!important;transition:none!important}}
|
||
</style>
|
||
<div class="sb-boot" aria-hidden="true">
|
||
<svg viewBox="276 240 700 760" xmlns="http://www.w3.org/2000/svg" focusable="false">
|
||
<defs>
|
||
<linearGradient id="sbBootSilver" x1="0" y1="0" x2="0.35" y2="1"><stop offset="0" stop-color="#fdfdff"/><stop offset="0.20" stop-color="#e7e7ec"/><stop offset="0.46" stop-color="#c4c4cb"/><stop offset="0.72" stop-color="#a4a4ac"/><stop offset="1" stop-color="#86868d"/></linearGradient>
|
||
<linearGradient id="sbBootOrange" x1="0" y1="0" x2="0.25" y2="1"><stop offset="0" stop-color="#ffb84d"/><stop offset="0.27" stop-color="#ff9a33"/><stop offset="0.58" stop-color="#fb7d16"/><stop offset="1" stop-color="#db5d04"/></linearGradient>
|
||
</defs>
|
||
<path fill="url(#sbBootSilver)" fill-rule="nonzero" d="m 835.26446,352.56633 102.39051,-103.90366 -418.64101,1.00877 c 0,0 -171.69323,1.22309 -222.43455,167.96079 -52.34251,171.99925 77.67556,253.20215 77.67556,253.20215 0,0 35.54922,23.82856 79.77792,31.68982 15.73869,2.39372 79.16695,1.09532 79.16695,1.09532 54.47377,-10.08773 41.40629,-81.22528 -10.65516,-77.67557 C 492.06451,630.5166 372.5156,615.45079 386.86464,469.07968 415.02639,353.31661 520.52712,353.57511 520.52712,353.57511 Z"/>
|
||
<path fill="url(#sbBootOrange)" fill-rule="nonzero" d="m 289.24744,881.29522 95.22696,-95.94027 369.13823,1.06997 C 873.15229,774.31964 863.51011,647.63259 863.51011,647.63259 846.7608,546.1216 749.51871,545.49427 749.51871,545.49427 l -232.01791,0.25219 c -37.80546,-8.91638 -37.85435,-49.4299 -37.85435,-49.4299 0,0 -1.56131,-38.07813 40.52401,-46.63785 l 260.62023,-0.7745 c 170.83788,24.60922 185.61432,187.63187 185.61432,187.63187 0,0 18.85523,117.07655 -90.63794,200.89054 l -0.62454,154.4184 -144.79052,-110.68137 z"/>
|
||
<path fill="url(#sbBootOrange)" d="m 658.38568,658.74237 a 27.462458,27.462458 0 0 1 -27.43073,27.46244 27.462458,27.462458 0 0 1 -27.49412,-27.39898 27.462458,27.462458 0 0 1 27.36719,-27.52575 27.462458,27.462458 0 0 1 27.55736,27.33536 z"/>
|
||
<path fill="url(#sbBootOrange)" d="m 748.42871,659.07971 a 27.462458,27.462458 0 0 1 -27.43073,27.46244 27.462458,27.462458 0 0 1 -27.49412,-27.39898 27.462458,27.462458 0 0 1 27.36719,-27.52575 27.462458,27.462458 0 0 1 27.55736,27.33537 z"/>
|
||
</svg>
|
||
</div>
|
||
<div class="sb-pre">
|
||
<div class="sb-pre-in">
|
||
<header>
|
||
<p class="sb-pre-brand">SecureBit.chat</p>
|
||
<h1>一条只有你们两人<br>才能读懂的直连线路。</h1>
|
||
<p class="sb-pre-lead">密钥在你的设备上生成,并在两端之间直接交换。无需账号,没有服务器保存你的消息。</p>
|
||
</header>
|
||
<section>
|
||
<p class="sb-pre-eyebrow">我们的不同之处</p>
|
||
<h2>SecureBit 为何与众不同</h2>
|
||
<ul class="sb-pre-grid">
|
||
<li class="sb-pre-card">
|
||
<h3>分层的 加密内核</h3>
|
||
<p>ECDH P-384 密钥交换、AES-256-GCM 载荷、ECDSA 签名与完整的 ASN.1 校验,汇成一条加固的流水线。</p>
|
||
<ul class="sb-pre-tags"><li>ECDH P-384</li><li>AES-256-GCM</li><li>ECDSA</li><li>ASN.1</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>纯粹的 P2P 基于 WebRTC</h3>
|
||
<p>消息通过 WebRTC 在设备之间直接传递。没有中继保存你的数据 —— 服务器只帮两端彼此找到对方。</p>
|
||
<ul class="sb-pre-tags"><li>DTLS 1.3</li><li>无中继</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>完美的 前向保密</h3>
|
||
<p>会话密钥持续轮换,用后即弃,因此单个泄露的密钥永远打不开此前的对话。</p>
|
||
<ul class="sb-pre-tags"><li>临时密钥</li><li>自动轮换</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>流量 混淆</h3>
|
||
<p>数据包的大小与时间间隔会被填充并随机化,即使有人盯着线路,也看不出元数据的规律。</p>
|
||
<ul class="sb-pre-tags"><li>数据包填充</li><li>时间抖动</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>零数据 收集</h3>
|
||
<p>没有账号,没有日志,不保存消息。服务器上没有任何可以泄露、被调取或被出售的东西。</p>
|
||
<ul class="sb-pre-tags"><li>无需账号</li><li>没有日志</li></ul>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
<section>
|
||
<p class="sb-pre-eyebrow">开发路线图</p>
|
||
<h2>SecureBit 的演进</h2>
|
||
<p>从第一个原型走向抗量子的去中心化网络,每一层都有完整的 ASN.1 校验。</p>
|
||
<ol class="sb-pre-steps">
|
||
<li>
|
||
<h3>开发启动</h3>
|
||
<span class="sb-pre-when">2025 年初</span>
|
||
<p>构想、原型与基础设施搭建</p>
|
||
</li>
|
||
<li>
|
||
<h3>Alpha 版本</h3>
|
||
<span class="sb-pre-when">2025 年春</span>
|
||
<p>首个公开 Alpha:基础聊天与密钥交换</p>
|
||
</li>
|
||
<li>
|
||
<h3>安全加固</h3>
|
||
<span class="sb-pre-when">2025 年夏</span>
|
||
<p>强化安全并发布稳定分支</p>
|
||
</li>
|
||
<li>
|
||
<h3>扩展与稳定</h3>
|
||
<span class="sb-pre-when">2025 年秋</span>
|
||
<p>网络扩展与稳定性改进</p>
|
||
</li>
|
||
<li>
|
||
<h3>隐私优先版本</h3>
|
||
<span class="sb-pre-when">2025 年冬</span>
|
||
<p>聚焦隐私:尽量减少元数据</p>
|
||
</li>
|
||
<li>
|
||
<h3>Enhanced Security Edition</h3>
|
||
<span class="sb-pre-when">2025 年末</span>
|
||
<p>18 层军用级密码学,配合完整的 ASN.1 校验</p>
|
||
</li>
|
||
<li>
|
||
<h3>Desktop Edition</h3>
|
||
<span class="sb-pre-when">2026 年初</span>
|
||
<p>面向 Windows、macOS 与 Linux 的原生桌面应用</p>
|
||
</li>
|
||
<li>
|
||
<h3>安全语音与通话</h3>
|
||
<span class="sb-pre-when">2026 年初</span>
|
||
<p>加密语音消息、语音通话与视频通话</p>
|
||
</li>
|
||
<li>
|
||
<h3>群组通讯</h3>
|
||
<span class="sb-pre-when">当前</span>
|
||
<p>在不牺牲隐私的前提下进行群聊</p>
|
||
</li>
|
||
<li>
|
||
<h3>Mobile Edition</h3>
|
||
<span class="sb-pre-when">2027 年第二季度</span>
|
||
<p>面向 iOS 与 Android 的原生移动应用</p>
|
||
</li>
|
||
<li>
|
||
<h3>抗量子版本</h3>
|
||
<span class="sb-pre-when">2027 年第四季度</span>
|
||
<p>抵御量子计算机</p>
|
||
</li>
|
||
<li>
|
||
<h3>去中心化网络</h3>
|
||
<span class="sb-pre-when">2028 年</span>
|
||
<p>完全去中心化的网络</p>
|
||
</li>
|
||
<li>
|
||
<h3>AI 隐私助手</h3>
|
||
<span class="sb-pre-when">2028 年以后</span>
|
||
<p>用人工智能守护隐私与安全</p>
|
||
</li>
|
||
</ol>
|
||
</section>
|
||
<section lang="en" dir="ltr">
|
||
<p class="sb-pre-eyebrow">Documentation</p>
|
||
<ul class="sb-pre-docs">
|
||
<li><a href="/docs/" hreflang="en">Documentation</a></li>
|
||
<li><a href="/docs/faq/" hreflang="en">Frequently asked questions</a></li>
|
||
<li><a href="/docs/architecture/" hreflang="en">Architecture</a></li>
|
||
<li><a href="/docs/cryptography/" hreflang="en">Cryptography</a></li>
|
||
<li><a href="/docs/descriptor-sbq2/" hreflang="en">SBQ2 — connection descriptor v2</a></li>
|
||
<li><a href="/docs/configuration/" hreflang="en">Configuration</a></li>
|
||
<li><a href="/docs/calls/" hreflang="en">Voice and video calls</a></li>
|
||
<li><a href="/docs/api/" hreflang="en">API Notes</a></li>
|
||
<li><a href="/docs/contributing/" hreflang="en">Contributing</a></li>
|
||
<li><a href="/docs/use-policy/" hreflang="en">Use policy and limitations</a></li>
|
||
</ul>
|
||
</section>
|
||
<section>
|
||
<h2>一起构筑隐私的未来</h2>
|
||
<p>SecureBit 因社区而成长。你的想法与反馈塑造着安全通讯的未来 —— 开放开发,全程完整的 ASN.1 校验。</p>
|
||
<p><a href="https://github.com/SecureBitChat/securebit-chat" rel="noopener">GitHub 仓库</a></p>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script type="module" src="/dist/app-boot.js?v=1788557187846"></script>
|
||
<script type="module" src="/dist/app.js?v=1788557187846"></script>
|
||
|
||
<script defer src="/src/scripts/pwa-register.js?v=1788557187846"></script>
|
||
<script src="/src/pwa/install-prompt.js?v=1788557187846" type="module"></script>
|
||
<script src="/src/pwa/pwa-manager.js?v=1788557187846" type="module"></script>
|
||
<script defer src="/src/scripts/pwa-offline-test.js?v=1788557187846"></script>
|
||
</body>
|
||
</html> |